ledger
1 file changed,
+6
−0
.superpowers/sdd/2026-08-23-idear/progress.md+6 −0
diff --git a/.superpowers/sdd/2026-08-23-idear/progress.md b/.superpowers/sdd/2026-08-23-idear/progress.md| index c5efa01..347fd0e 100644 |
| --- a/.superpowers/sdd/2026-08-23-idear/progress.md |
| +++ b/.superpowers/sdd/2026-08-23-idear/progress.md |
| @@ -67,3 +67,9 @@ Task 3: Ruling (frozen checksum re-recorded): ACCEPT. Task 2 declared timestamps |
| Task 3: Ruling: the REAL defect is that Task 2's schema test passed a write-only schema. Requiring the reviewer to judge whether a round-trip read test is now present; if not it becomes a finding. A migration test that never reads back proves only that CREATE TABLE parses. |
| Task 3: Ruling (ErrInvalidRole beyond the brief's four sentinels): ACCEPT. A malformed role is 400 and an authority refusal is 403; folding them loses a distinction handlers need. |
| Task 3: cross-task note for Tasks 4-6: emails are normalised (trim + lowercase) in the store, so the admission adapters and handlers MUST normalise the submitted address identically or an invitation will never match. ErrLastOwner renders 403, not 400. |
| +Task 3: review — spec ✅, quality Needs work: 4 Important, 3 Minor. Reviewer ran a 24-mutation battery and found the implementer's own "Caught" table contained TWO FALSE ENTRIES (target-active check and the CAS both survive single-layer removal). Frozen-checksum re-record independently reproduced and accepted. |
| +Task 3: Ruling: fix all four Importants. (1) correct the false coverage claims in the report — a false coverage claim in the ledger is worse than the gap, because Task 6 reads it and trusts it. (2) TestConcurrentClaimYieldsOneOwner catches its own mutation only 21/25 runs; loop 20 fresh rosters so it is deterministic. (3) ErrLastOwner must wrap ErrForbidden — as a bare errors.New, the natural handler taxonomy renders the package's most security-relevant refusal as a 500. (4) Invite's blank-email returns a bare errors.New — the exact 400/500 hole ErrInvalidRole was invented to close, on the sibling field of the same form. |
| +Task 3: Ruling: ALSO fix the UTC exposure the reviewer found while checking the checksum justification. Expiry comparison is string comparison on time.Time.String(); a non-UTC ExpiresAt renders "+0100 CET" and breaks it far worse than a monotonic reading. Store UTC and assert it. This is a latent correctness bug, not a style point. |
| +Task 3: Ruling: ALSO do Minor 1 (Claim's atomic INSERT ... SELECT WHERE NOT EXISTS) and Minor 2 (a NAMED round-trip test in schema_test.go). Claim is currently correct only because db.Open caps the writer pool at one connection — correctness that depends on an unrelated config elsewhere is what breaks two releases later. Minor 2 is the lesson of the whole TEXT/DATETIME episode: Task 2's schema test proved only that CREATE TABLE parses. |
| +Task 3: cross-task note for Task 6: checkInviteRole is strictly-below, so an Admin may grant only Member. The role selector must not offer Admin to an Admin or every such submit 403s. |
| +Task 3: fix round 1 dispatched (resume original implementer, opus), FIX_BASE efd00f8 |