Skip to content

Commit 451bac3

Browse files
committed
feat: add claim aggregation service spec requirements
1 parent 55822a8 commit 451bac3

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"specId": "ee68c70d-ee1c-4764-b4a9-96c5676223ad", "workflowType": "requirements-first", "specType": "feature"}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Requirements Document
2+
3+
## Introduction
4+
5+
The Claim Aggregation Service centralizes governance math for the claims board. It pre-computes quorum progress percentages, votes-needed counts, and human-readable deadline estimates from indexed vote rows, eligible voter totals, and the contract's `quorum_bps` configuration. Results are cached in Redis and exposed on the existing `GET /claims/:id` response DTO, so the frontend can render a quorum progress bar and deadline display without implementing any governance formula itself.
6+
7+
## Glossary
8+
9+
- **ClaimAggregationService**: The NestJS service responsible for computing and caching aggregated governance fields for a claim.
10+
- **quorum_bps**: Basis-points quorum threshold read from the on-chain deployment registry (e.g. 5100 = 51%). Determines the minimum fraction of eligible voters required for quorum.
11+
- **quorum_progress_pct**: Integer percentage (0–100) representing how far the current approve-vote count has advanced toward the quorum threshold.
12+
- **votes_needed**: The number of additional approve votes required to reach quorum, given the current tally and eligible voter count.
13+
- **deadline_estimate_utc**: An approximate UTC ISO-8601 timestamp for when the voting window closes, derived from `createdAtLedger + VOTE_WINDOW_LEDGERS` and the average seconds-per-ledger constant. Approximate because Stellar ledger close times vary.
14+
- **eligible_voter_count**: The total number of wallets eligible to vote on a claim, sourced from the on-chain policy membership snapshot stored in the database.
15+
- **VOTE_WINDOW_LEDGERS**: The fixed ledger count defining the voting window (currently 120,960 ledgers).
16+
- **SECONDS_PER_LEDGER**: The average ledger close time constant used for deadline estimation (currently 5 seconds).
17+
- **AggregatedClaimDto**: The response DTO shape returned by `GET /claims/:id`, extended with the three new aggregated fields.
18+
- **Deployment_Registry**: The on-chain contract registry from which `quorum_bps` is read at service startup and cached.
19+
- **Redis_Cache**: The existing Redis instance used to cache aggregated results with a short TTL.
20+
21+
---
22+
23+
## Requirements
24+
25+
### Requirement 1: Quorum Progress Computation
26+
27+
**User Story:** As a frontend developer, I want the API to return a pre-computed quorum progress percentage, so that I can render a quorum progress bar without implementing governance math in the client.
28+
29+
#### Acceptance Criteria
30+
31+
1. THE ClaimAggregationService SHALL compute `quorum_progress_pct` as `floor((approve_vote_count / quorum_threshold_votes) * 100)`, clamped to the range [0, 100].
32+
2. THE ClaimAggregationService SHALL derive `quorum_threshold_votes` as `ceil((quorum_bps / 10000) * eligible_voter_count)`.
33+
3. THE ClaimAggregationService SHALL read `quorum_bps` from the Deployment_Registry and document the source in code comments.
34+
4. THE ClaimAggregationService SHALL document the source of `eligible_voter_count` (policy membership snapshot) in code comments.
35+
5. WHEN `eligible_voter_count` is zero, THE ClaimAggregationService SHALL return `quorum_progress_pct` of 0 and `votes_needed` of 0 without dividing by zero.
36+
37+
### Requirement 2: Votes-Needed Computation
38+
39+
**User Story:** As a frontend developer, I want the API to return the number of additional approve votes needed, so that I can display actionable voting progress to users.
40+
41+
#### Acceptance Criteria
42+
43+
1. THE ClaimAggregationService SHALL compute `votes_needed` as `max(0, quorum_threshold_votes - approve_vote_count)`.
44+
2. WHEN quorum has already been reached, THE ClaimAggregationService SHALL return `votes_needed` of 0.
45+
3. THE ClaimAggregationService SHALL use the same `quorum_threshold_votes` value as used in `quorum_progress_pct` computation to ensure consistency between the two fields.
46+
47+
### Requirement 3: Deadline Estimate Computation
48+
49+
**User Story:** As a frontend developer, I want the API to return a human-readable UTC deadline estimate, so that I can display the voting window close time without computing ledger arithmetic on the client.
50+
51+
#### Acceptance Criteria
52+
53+
1. THE ClaimAggregationService SHALL compute `deadline_estimate_utc` as the ISO-8601 UTC timestamp of `claim.createdAt + (VOTE_WINDOW_LEDGERS * SECONDS_PER_LEDGER * 1000 ms)`.
54+
2. THE ClaimAggregationService SHALL include a code comment and API documentation note stating that `deadline_estimate_utc` is approximate due to variable Stellar ledger close times.
55+
3. WHEN a claim's voting window has already closed, THE ClaimAggregationService SHALL still return the historical `deadline_estimate_utc` value.
56+
57+
### Requirement 4: Contract Formula Alignment
58+
59+
**User Story:** As a protocol engineer, I want the backend quorum formula to match the on-chain contract formula, so that the UI and contract always agree on quorum status.
60+
61+
#### Acceptance Criteria
62+
63+
1. THE ClaimAggregationService SHALL use `quorum_bps` sourced from the Deployment_Registry rather than a hardcoded constant.
64+
2. THE ClaimAggregationService SHALL include a code comment referencing the contract function or registry key from which `quorum_bps` is read.
65+
3. WHEN `quorum_bps` changes in the Deployment_Registry, THE ClaimAggregationService SHALL reflect the updated value within one cache TTL cycle without requiring a service restart.
66+
67+
### Requirement 5: Redis Caching with Invalidation
68+
69+
**User Story:** As a backend engineer, I want aggregated results cached in Redis with a short TTL, so that repeated reads are fast and cache entries are invalidated when new votes arrive.
70+
71+
#### Acceptance Criteria
72+
73+
1. THE ClaimAggregationService SHALL store aggregated results in Redis_Cache under the key pattern `claims:aggregated:{claimId}` with a TTL of 30 seconds or less.
74+
2. WHEN a new Vote row is written to the database for a given claim, THE ClaimAggregationService SHALL delete the Redis_Cache entry for that claim's aggregated key.
75+
3. IF Redis_Cache is unavailable, THEN THE ClaimAggregationService SHALL compute and return aggregated results directly from the database without throwing an error.
76+
4. THE ClaimAggregationService SHALL not cache results that contain stale `quorum_bps` values older than the configured TTL.
77+
78+
### Requirement 6: DTO Extension for GET /claims/:id
79+
80+
**User Story:** As a frontend developer, I want the `GET /claims/:id` response to include the three aggregated fields, so that a single API call provides everything needed to render the claim detail view.
81+
82+
#### Acceptance Criteria
83+
84+
1. THE ClaimsController SHALL include `quorum_progress_pct`, `votes_needed`, and `deadline_estimate_utc` in the `GET /claims/:id` response DTO.
85+
2. THE AggregatedClaimDto SHALL expose `quorum_progress_pct` as an integer in [0, 100].
86+
3. THE AggregatedClaimDto SHALL expose `votes_needed` as a non-negative integer.
87+
4. THE AggregatedClaimDto SHALL expose `deadline_estimate_utc` as an ISO-8601 UTC string.
88+
5. THE ClaimsController SHALL document `deadline_estimate_utc` in the OpenAPI schema with a note that the value is approximate.
89+
90+
### Requirement 7: Unit Tests with Fixed Fixtures
91+
92+
**User Story:** As a backend engineer, I want unit tests with fixed vote/voter fixtures that verify formula correctness, so that any formula change requires an intentional test vector update.
93+
94+
#### Acceptance Criteria
95+
96+
1. THE ClaimAggregationService test suite SHALL include at least one test fixture with known `approve_vote_count`, `eligible_voter_count`, and `quorum_bps` values and assert the exact expected `quorum_progress_pct` and `votes_needed` outputs.
97+
2. THE ClaimAggregationService test suite SHALL include a fixture where quorum is exactly met (boundary condition) and assert `quorum_progress_pct` of 100 and `votes_needed` of 0.
98+
3. THE ClaimAggregationService test suite SHALL include a fixture where `eligible_voter_count` is zero and assert no division-by-zero error occurs.
99+
4. THE ClaimAggregationService test suite SHALL include a fixture verifying `deadline_estimate_utc` matches the expected UTC timestamp for a known `createdAt` and `createdAtLedger` input.
100+
5. WHEN the quorum formula is changed, THE ClaimAggregationService test suite SHALL fail on existing fixtures, requiring explicit test vector updates to pass.

0 commit comments

Comments
 (0)