Skip to content

docs: ledger checkpoint after #770 — terminal CI, #768 review, status-mark repair - #771

Closed
NewWorldVenture wants to merge 131 commits into
mainfrom
claude/final-audit-ledger770-checkpoint-20261001
Closed

NewWorldVenture wants to merge 131 commits into
mainfrom
claude/final-audit-ledger770-checkpoint-20261001

Conversation

@NewWorldVenture

@NewWorldVenture NewWorldVenture commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

This is the documentation-only checkpoint for task JIMMY-NWV-LEDGER770-20261001, written by NWV as the sole finalaudit.md writer while the Codex coordinator is stopped.

Ancestry

What it records (each source is listed separately)

Checks on this exact head (Node 24.21.0)

  • Document checks: 602 / 602 (migration-reference 589, tally 3, page register 6, migration-version safety 4).
  • Generated finding index: docs/audit/finding-index.py output matches the generated block exactly.
  • Whitespace: git diff --check is clean.
  • Status marks: no ?? marks remain.

Not included

🤖 Generated with Claude Code

https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

NewWorldVenture and others added 3 commits October 1, 2026 06:10
…r checkpoint)

Documentation only, on top of frozen #770 95b785e (unchanged), for
task JIMMY-NWV-LEDGER770-20261001 while the Codex coordinator is stopped.

- main 01b2c38 post-merge CI36846986553: terminal all-four success,
  1,909 clean E2E.
- #768 59b4c98: all-four CI36845154127 plus Support's independent
  review; the original photo-flake cause/fix stays unestablished.
- #769 71e8f88: all-four CI36846162597; Daniel's review not yet posted.
- #770 95b785e: all-four CI36847694663; 602 document checks
  reproduced and SHA256 matched.
- Three #770 Register B rows read `?? IN PROGRESS`; the mark is
  restored to the IN PROGRESS mark they were already counted under.
  No ID, order, status, count or evidence text changes; no new PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
@vercel

vercel Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
bubaly Ignored Ignored Oct 2, 2026 7:02pm UTC

Request Review

claude added 2 commits October 1, 2026 11:01
…d to the checkpoint

Owner review 5378367970. #772 07602d4 is recorded as author-reported
local evidence (18 new / 54 repeat / 87 combined synthetic browser
cases, 11 mutants), with its hosted CI still running and its two
reported, unfixed residuals. No one-card-per-child policy, no Register B
row, no PASS. #768 promotion/merge awaits the owner's explicit approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
…ledger checkpoint)

Owner review 5378577116. #773 2526ec2 is recorded as author-reported,
test-only synthetic evidence with its hosted CI still running: R1
remount duplicate issuance, R4 provider-success/mirror-failure orphan
plus duplicate retry, R5 concurrent cardholder unique race. Multiple
cards per child stay legitimate; no one-card policy. Support owns
repairs A and C; R4 stays unresolved with no cancel/adopt/schema
authorization. Open workflow gaps, not a live incident; no Register B
row, no PASS. #768 approval still pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

Terminal receipts for review 5378948260. These are recorded here only; the head is held at 499326dc0c740af77d428c567bcc451b850deef5 for review, with no ledger push. I checked each against GitHub's check runs.

Head Run Database Mobile Web (types/lint/unit/build) E2E
#771 499326dc0 (this PR) CI36855143099 success success success 11:48:45 success 11:53:54 UTC
#772 07602d49c CI36852467778 success success success 11:23:15 success 11:24:29 UTC
#773 2526ec2ca CI36854822850 success success success 11:44:14 success 11:50:35 UTC

Supabase Preview was skipped on all three.

How to read this

Unchanged:

These receipts, and anything that follows, will go into the next batched ledger commit, not a push for routine status changes.


Generated by Claude Code

…l CI and the A+C execution blocker

Owner review 5379042101. The Last Updated line and section heading said
10:55 UTC but included #772 (10:58), #773 (11:21) and the A+C assignment
(11:23); those additions now carry their own times. Records the terminal
all-four CI for #771/#772/#773 (receipt 5930953854) and Support's A+C
source-edit permission blocker (#712 comment 5930951363). Ownership is
not execution clearance; no workaround, no PASS, R4 unresolved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

Review 5379042101 received, with thanks for the independent tally. The timestamp finding is correct.

The batched correction is prepared and committed locally, and it is not pushed. This PR's head stays at 499326dc0, as you asked.

I'll push it when you tell me the current head no longer needs to stay fixed. Otherwise I'll push it together with the next material update, such as Daniel's #769 review, so that CI restarts only once.


Generated by Claude Code

claude added 2 commits October 1, 2026 12:26
…ate evidence

Owner review 5379179166. #774 c582d96 (12:13 UTC) is new fail-closed
entitlement work, not a #729 duplicate, but based on 84fe103 (174
behind main); its local /pricing and 22,707-test evidence is from that
stale checkout, not current-main acceptance. Hosted CI36860293995 was
running; Blackstone's retest relay ACK pending. No row, PASS or merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
Owner review 5379348558. #774's original c582d96 stays recorded as the
abort-only, stale-base baseline (not the repaired candidate). Current
af53da9 normally merges main 01b2c38 and bounds the whole feature-tier
read; author-reported 10 fail/6 control on the predecessor, 16/16 after,
23,947 tests + 2 expected failures, 89 focused checks. Hosted final-head
CI36863502780 and independent review pending. Blackstone's relay is
verified automatic. No row, PASS, promotion or merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

The batched documentation checkpoint for review 5379348558 is pushed. The new head is ccdb3b91511f696a93ca8f9c48c78e1938927347, and the audit SHA256 is 5c1fb16518980cacfd208fde2aeb9a7832cdb6d5b72affb7ea73cf2b1c39fd1d.

History is preserved. The earlier head 499326dc0 and #770's 95b785e03 are both ancestors of the new head, and there was no force push. The PR stays a draft.

Three commits on top of 499326dc0:

Checks on this exact head:

  • the 602 document checks pass;
  • the generated finding index matches;
  • git diff --check is clean;
  • Register B is unchanged, with no ?? marks.

Not done: no new PASS, production credit or Register B rows; #768's approval hold and Daniel's #769 review are still pending; no promotion or merge.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

E2E failed on ccdb3b915, and it is not this PR's failure. It is a date-triggered failure in an existing spec. It will now fail on every PR and on main.

What failed. In CI36863717027: 1 failed, 1,908 passed. The failure is tests/e2e/social-publish-consumers.spec.ts:269, "a saved schedule links to its existing record and does not schedule or publish a second copy". It failed on both attempts with Expected: 1, Received: 0 from resultCount.

Root cause (not intermittent):

  • The test fills the schedule with a fixed wall time, '2026-10-01T12:00' (line 271).
  • Both the client (resolveScheduleTime) and the server action (validateScheduleInstant) refuse an instant at or before now, with socialSchedule.pastTime, "Choose a time in the future".
  • The browser clock isn't pinned. The sibling social-scheduling-ui.spec.ts pins it with page.clock.setFixedTime.
  • So from 2026-10-01 12:00 UTC onward the schedule is refused and no result is recorded.
  • That fits the history. Main 01b2c380's run (E2E finished 10:35 UTC) and this PR's previous head 499326dc0 (11:53 UTC) both passed with 1,909. This run started after 12:42 UTC.

Why it isn't this PR's:

Reproduced locally on main 01b2c380 (detached checkout, Chromium):

  • As written, the spec is 11 passed, 1 failed, the same test.
  • Pinning only the browser clock is not enough. The client then accepts the time, but the server action, running in Node on the real clock, still answers "Choose a time in the future".
  • Proposed patch (test-only, 3 lines): use a far-future fixed time. With it, the spec is 12/12.
-  await page.locator('input[type="datetime-local"]').fill('2026-10-01T12:00');
+  // Both the form and the server action refuse a time that is not in the future,
+  // against the real clock, so this must stay ahead of any date the suite runs on.
+  await page.locator('input[type="datetime-local"]').fill('2099-10-01T12:00');

The patch is saved locally with SHA256 eac86ec3…6428b.

Not done:

  • I haven't pushed this. It is outside this documentation-only checkpoint task, and the owner decides who lands it.
  • I haven't re-run CI either: the failure is deterministic, so a re-run would fail the same way.

#771's head stays ccdb3b915, and its other three jobs are unaffected by this.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

This updates my previous comment, following review 5379752489.

Failure on #771. This PR's E2E failure, CI36863717027, is the same expired fixture:

Fix and dependency. The repair is the fixture-only draft #775, which computes a future browser-local schedule. #771's green E2E now depends on #775 reaching main. My 2099 patch above was only a proposal and is superseded by #775; I'm not pushing it.

Unchanged:


Generated by Claude Code

@NewWorldVenture NewWorldVenture left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed exact-head terminal evidence: ccdb3b9 CI36863717027 failed at13:14:34UTC only in the same social-publish-consumers.spec.ts:269 expired fixed-date fixture; both attempts expected1/received0 at helper172, 1failed/1908passed. Web, Database and Mobile passed. Record as current CI blocked, not a successful full gate. Independent review finds only finalaudit changed and Register B preserved. #775 fixture-only046bc33b8ac8e1ea70a09495eee1815374de9a81 is now under review/CI36867423592; #774 carries the identical fix at ecb626b with CI36867472286. Do not add another copy to your docs-only branch while those are pending; preserve the current head. Minor next-batch wording correction: Last Updated summary still says #772 hosted CI pending, while the timestamped terminal paragraph correctly records success. No new PASS or promotion/merge.

… CI wording

Owner review 5379767360. #771's exact head CI36863717027 failed only E2E
on the expired fixed-date fixture social-publish-consumers.spec.ts:269
(1 failed / 1,908 passed); recorded as blocked, not a full gate. Same
on #774 af53da9. Fixture-only #775 046bc33 and #774 ecb626b carry
the repair with CI running; #771's green E2E depends on #775. Last
Updated no longer calls #772's hosted CI pending. No PASS, no fixture
copy in this docs-only branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

@NewWorldVenture NewWorldVenture left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependency update: fixture-only #775 at046bc33b8ac8e1ea70a09495eee1815374de9a81 now has all-four successful CI36867423592, including1909 clean E2E passes. Combined #774ecb626 CI36867472286 also finished all-four success. Neither is merged yet. Keep current docs head preserved and record these terminal receipts in comments until a substantive next batch. #771's own ccdb run remains failed on the pre-fix fixture; do not borrow the dependency's green status. Parent is obtaining explicit ready/merge approval for the eligible drafts.

Copy link
Copy Markdown
Owner Author

Dependency receipts for review 5380159701. These are recorded here only; the head stays ccdb3b915, with no ledger push. I checked each against GitHub's check runs.

Head Run Database Mobile Web E2E
#775 046bc33b8 (fixture-only) CI36867423592 success success success 13:39:58 success 13:48:20 UTC
#774 ecb626b93 (carries the same fix) CI36867472286 success success success 13:40:56 success 13:48:37 UTC

Neither is merged.

#771's own run is not green. CI36863717027 on ccdb3b915 stays failed, on the fixture as it was before the fix. I'm not borrowing #775's or #774's green status for #771. #771 can only get a green E2E on a run against a base that contains #775.

The next batch, already committed locally and not pushed, records these receipts and the dependency. It awards no PASS and no promotion or merge.


Generated by Claude Code

@NewWorldVenture

Copy link
Copy Markdown
Owner Author

Independent reviewer checkpoint: current evidence and separate remaining holds

Main 01b2c380dc819aab3d4d5110899eb047f5f40a08 is still authoritative (3e3e0b). Trusted-TLS public build-info returned HTTP200 with exact01b2 at2026-10-01 15:47:30.167Z (37e5f1). Recorded main CI 36846986553 is terminal success in all four jobs (962767), completed10:35:53Z. This proves that recorded run and served source identity, not all later clock-dependent tests or production readiness.

PR771 current ccdb3b91511f696a93ca8f9c48c78e1938927347 remains E2E FAILURE in 36863717027, with its other three CI jobs successful (07ca5e). The owner already reports the expired fixed-date fixture and keeps it separate from775/774. Independently read CI 36867472286 is terminal success in all four jobs on 774ecb626b9, which includes the775 fixture; it is not this ledger head or served main. The authored controlled-time diagnosis of main's date expiry is reported here; this reviewer did not rerun that browser matrix.

New published scoped evidence:

  • 767 receipt finalization:7new canonical-executor/SDK scenarios,59 assertions; older namespace-parent countercontrol reproduces late output overwrite. Combined8characterizations/64 assertions. Clears acquired-attempt finalization in those cases, not atomic service effects or durable reconciliation.
  • 769 investment admission:56candidate cases pass; inverse single-guard control has12desired refusals fail/44controls pass. Two-parent retries and generic approved requests do not authorize settlement. No usable approval-to-settlement workflow, SQL/RLS/provider/financial SDK or actual money operation proved. Publication body verified exact after an ambiguous CLI response (c6be5c); no duplicate post.
  • 774 existing admin-write concurrency hold: actual settings helpers/entitlement/SDK show simultaneous successful Calendar-off and Chores-plus updates discard the off setting in both main/candidate. Three healthy/serialized/failed-read controls pass. This strengthens Sep5 documentation, not a new774regression or request to expand its read-deadline scope. Existing atomic/versioned write obligation remains.

Canonical tally (d7b880):

  • Main ledger e9b908fa5c0742cbd3623f65d3afbc13ad713151:14,360unique RegisterB IDs;11,877NS /2,132IP /185PASS /157FIXED_PASS /9BLOCKED.342recorded closures=2.3816%,zero blocked credit.
  • Candidate771 ledger 5fd503cf:14,364IDs;11,877NS /2,136IP /185PASS /157FIXED_PASS /9BLOCKED. Four new file obligations; none removed/no existing status changes.342closures=2.3810%.
  • SessionA841overlapping status rows stay separate (127NS/697IP/17PASS); do not add them toB.
  • The three literal ?? IN PROGRESS marks from770 are repaired without credit. Existing timestamp/header feedback has an owner-prepared follow-up; no newly borrowed-green claim found.

Mechanical counts are not an endorsement of every PASS. The existing ROLE-B6B2EC5BB4A0 broad assurance claim remains atmain11511/candidate11596, while its current source remains the previously reviewed guard; owner reconciliation is still required. The old routine-export ceiling and failed-upload cleanup sources are likewise unchanged on current main; this is source carry only, with no fresh production/security reproduction. Do not award their closure from unrelated green CI.

All three reviewers and root preserved the clean reference b87faba0,unpublished0/0. No shared-ledger/source/branch edits, SQL, real provider, production configuration or money movement. Existing IDs retained; no new status credit. PRODUCTION READY: NO remains supported.

claude added 2 commits October 1, 2026 16:20
…ence

#771 comment 5935613991: main 01b2c38 served/CI identity, #771's E2E
failure kept, #767/#769 scoped characterizations, the existing #774
admin-write concurrency obligation, canonical Register B tallies, and
owner reconciliation items. No PASS, no closure from unrelated CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
#775 dependency

Owner review 5383057905. DISPLAY-TZ-01: the display-ownership harness
mocked date-fns parseISO as new Date(value), shifting date-only values
west of UTC (from baf9090, TIME-003); #776 069d508 uses real
date-fns with 9 timezone controls and is all-four green (E2E 1,918).
Its parent's failure was only the expired social fixture and stays
separate. E2E-DATES found no other expired fixed-date fixtures.
#771's E2E depends on #775's fixture. No production defect, row, PASS,
promotion or merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

The batched documentation checkpoint for review 5383057905 is pushed. The new head is 15a54e2582d7251a172e17b2e41e614b056f230f, and the audit SHA256 is 411223c95cf63b4cd3f575335e9ac588f5425bd27a47726bd62d3abe6d2903ed.

History is preserved. ccdb3b915, 499326dc0 and #770's 95b785e03 are all ancestors, and there was no force push.

Three commits on top of ccdb3b915:

Checks on this exact head:

  • the 602 document checks pass;
  • the generated finding index matches;
  • git diff --check is clean;
  • Register B is unchanged, with no ?? marks.

What to expect from this head's CI. It runs on a base without #775, so I expect E2E to fail again on the same fixture until #775 is on main. If it does, I'll record that the same way, with no new PASS.

Not done: no promotion or merge, and the #768 approval hold and Daniel's #769 review are still pending.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Hosted CI on 15a54e2 has finished. E2E failed, with the same single cause as ccdb3b9.

Results (run 36900349399):

Check Result
Typecheck · Lint · Test · Build ✅
Database ✅
Mobile (Expo) ✅
E2E ❌ 1907 passed, 1 failed, 1 flaky

The failure: tests/e2e/social-publish-consumers.spec.ts:269, "a saved schedule links to its existing record…".

The flaky test: tests/e2e/rewards-readback-review.spec.ts:206 timed out on its first attempt (Points Leaderboard was not visible within 5 s) and passed on retry. It is unrelated to this diff, and I haven't diagnosed or claimed it. I'll record it in the ledger as observed-flaky, with no root cause.

Recording: I'll record this result, together with Blackstone's JIMMY-BLK-SELF-CHECK claim, in the next substantive docs batch. No new PASS. No promotion or merge.


Generated by Claude Code

@NewWorldVenture NewWorldVenture left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head terminal CI36900349399 needs both qualifications recorded: Web/Database/Mobile passed; E2E1907passed +1flaky +1failed. The persistent failure is the known expired social fixture lacking775. Separately, rewards-readback-review.spec.ts:206 failed initially at ready helper193/call214 because 'Points Leaderboard' did not appear within5s, then passed its retry. Cause and reproducibility of that flake are unestablished; do not describe this run as1908clean passes or solely the expired fixture. Job110497659466. Preserve the logs and current head; no blind rerun of the unchanged baseline and no weakened timeouts/retries. Include this qualification in the next substantive ledger batch, without new PASS credit.

…ackstone self-check claim

E2E on CI36900349399: 1,907 passed, 1 failed (expired social fixture,
base lacks #775), 1 flaky (rewards-readback-review.spec.ts:206, cause
unestablished). Records JIMMY-BLK-SELF-CHECK-20261001 scope and NWV's
no-conflict check. No Register B change, no new PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

Docs batch pushed at 3b9c01a07, following review 5383409531. It changes only finalaudit.md (sha256 865a817c…8469). Its parents are 15a54e258 and 95b785e03.

What it records:

  • CI36900349399 / job 110497659466, both qualifications. Web, Database and Mobile passed. E2E had 1,907 passed, 1 failed (the expired social fixture; base 01b2c380 lacks E2E: schedule the social post a week ahead, not on a fixed date #775) and 1 flaky. The flaky case is rewards-readback-review.spec.ts:206: on the first attempt it failed at the ready helper (line 193, called from line 214) because Points Leaderboard was not visible within 5 s, then it passed on retry. Its cause is unestablished. The entry says explicitly that this run is neither 1,908 clean passes nor a failure due solely to the fixture. Logs and the old head are preserved, with no blind re-run and no weakened timeouts or retries.
  • Blackstone's JIMMY-BLK-SELF-CHECK-20261001 claim, with its exact paths, its exclusions, NWV's no-conflict check and the rule that synthetic coverage is not device or screen-reader acceptance.

Checks: 602/602 document checks pass, the finding-index generator runs cleanly, and the Register B row tally is identical to 15a54e258.

Expected CI: this head's E2E will still fail on the expired fixture until #775 is on main. No new PASS. No promotion or merge.


Generated by Claude Code

claude added 3 commits October 1, 2026 18:38
…I-WF-024

Exact ee988ce, CI36904951459 all four green (owner-verified E2E 1,920
clean). Records the aria-disabled + in-flight guard focus repair and keeps
physical endurance, real fullscreen/connectivity, unanswered APIs and
screen-reader acceptance outside proved coverage. No PASS, no Register B
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
…nd NWV's overlap check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP
… case)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KRUgA6hD6QgzmtpSP6TUmP

Copy link
Copy Markdown
Owner Author

Support: claim 6101058890 is done, now reconciled with main. Unchecked-grocery counts and lists skip archived shopping lists. Branch only, no PR.

  • Branch claude/data-lifecycle-7q6vtf, head adfe982a2fb4ff538dc520372e845260e7f98ee4, merged with main 9e898cf0a7acf584a1eb6b33a7d9d31393502966. git merge-tree against current main aca5c9cba is clean.
  • PR Support fixes, batch 1: referral credit once, deleted and archived data, child wallet ownership, server-action census #1022 already shipped this branch's first six commits, so main's copies stay and the branch no longer carries them. The only thing left vs main (16 files) is the archived-list fix (readOnOpenGroceryLists + 11 readers), its test, and fixture updates. The home-asset cleanup is not part of the diff.
  • Conflict in lib/assistant/tools.ts: kept main's manager gate on chore sign-offs in list_pending_decisions. Only the grocery count changes, and it now reads open lists only.
  • One new fixture update: main's tests/pending-decisions-keep-money-for-the-managers.test.ts SDK fetch fake now allows grocery_lists. Before this, 3 of its cases failed with "Could not load pending decisions."
  • Mutant: putting back main's unscoped grocery count in tools.ts fails 2 cases of an-archived-shopping-list-is-not-counted.
  • Gates: 94 test files that touch the changed modules, plus 18 guard/ratchet/contract tests, all pass. eslint is clean on the 16 files, and the full tsc run is clean.
  • Left for the owner: app/api/ai/insights/route.ts:337 (the grocery/shopping case) still reads unchecked items across every list. The source guard misses it because it goes through the eq(sb, 'grocery_items', …) helper.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Bring claude/sending-crons-7q6vtf up to current main, and settle claim 6126421805. Code only, no migration; branch claude/sending-crons-7q6vtf; no PR.

  • Claim 6126421805 (automation emails ignore unsubscribes, bounces and complaints, and carry no unsubscribe link) was not yet committed. Current main already fixes it in lib/marketing/automation-steps.ts (an opt-out read before every send, the unsubscribe footer and one-click headers), so that work is dropped as superseded by main.
  • Merge main (not rebase) into the branch. Conflicts in lib/marketing/automation-{events,runner,steps}.ts and tests/an-unconfirmed-write-outside-actions-ratchet.test.ts are resolved on main's code, keeping only the branch's earlier fixes that main lacks: a retried automation run does not resend an email it already delivered, and a step that throws keeps the run's send log.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6133966729 is done. claude/sending-crons-7q6vtf is merged with current main; claim 6126421805 is superseded by main. Branch only, no PR.

  • Branch claude/sending-crons-7q6vtf, head 1dc14bac33396d1c03116667daa227d2c97bdde2, merging main aca5c9cba2777e64de2d1eca2452c8a4b7996e2f. git merge-tree --write-tree origin/main HEAD exits 0; the net diff against main is the branch's 18 earlier files (checkout-abandoned nudge, closed-family crons, notification email stamping, push receipts, automation retry) and nothing else.
  • Superseded by main: claim 6126421805. Main's lib/marketing/automation-steps.ts reads marketing_suppressions before every automation send, records send_email:suppressed (a run that settles), treats an unreadable list as a failure, and adds the unsubscribe footer and one-click headers. That claim's uncommitted test passes on main for unsubscribe, bounce, complaint, address case, footer and headers, and the unreadable-list retry, so nothing from it is kept.
  • For the owner: that dropped work also exempted payment_failed and payment_completed workflows from the opt-out, because the unsubscribe page says transactional email is unaffected. Main suppresses every automation trigger. That is left to the owner to decide.
  • Conflicts resolved on main's runSteps(steps, recipient, fallback, supabase, admit?). The branch's previous is a new trailing parameter, so a send an earlier attempt delivered is not repeated on retry. A step that throws is still logged <action>:failed. The ratchet keeps both decrements and now totals 48. The retried-automation test's email mock gains APP_URL.
  • Mutants, all killed on the merged code: no carry-over in runSteps (6 tests fail), runner drops previous (4 fail), event path drops previous (2 fail), a throwing step escapes (3 fail).
  • Gates: 58 focused test files (marketing automation, opt-out, checkout-abandoned, push, notification email, cron dispatch) plus the guard and ratchet tests, including an-unconfirmed-write-outside-actions-ratchet, a-route-write-is-confirmed, ordering-guards-fail-on-absence and i18n-ungated-surface-ratchet, all pass. eslint is clean and the full tsc passes.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim and number request, posted before editing. A marketplace order is returned or completed by its seller, in the database too. Requesting 0518 as a held source and probe reservation. Held source only under supabase/reserved/, applied nowhere; branch claude/marketplace-order-status-guard-7q6vtf, cut from claude/marketplace-transactions-7q6vtf at 965cf8752 so the app rule and the database rule ship together; no PR.

  • Finding: on claude/marketplace-transactions-7q6vtf, setOrderStatusAction refuses a buyer marking an order returned or completed (only its seller_member may). But marketplace_orders_update (0483) still lets either party write status through PostgREST. So a borrower can PATCH their own order to returned while still holding the item, which also ends its overdue reminders. A buyer can also complete a sale that was never handed over. returned_at counts as returned in lib/marketplace/returns.ts, and either party can write it the same way.
  • Number: 0518, the first number above the held 0517. 0515 is requested in 6109587749 and not released, and it is left alone, not filled. Nothing in this thread or on Owner decisions: kid logins, marketplace, health, tax, guests, notes, medications, social, money, location, records (held 0504–0514, 0516–0517) #999 names 0518.
  • Intended rule: a BEFORE UPDATE trigger on marketplace_orders, SECURITY INVOKER and keyed on current_user in ('authenticated','anon') as 0458 and 0482 are. It refuses (42501) a change of status to returned or completed, or any change of returned_at, unless the caller is the order's seller_member (the app's own test). The seller check is a SECURITY DEFINER helper with search_path = ''. Unchanged: the service role, cascades, and SECURITY DEFINER RPCs, including marketplace_complete_handoff, the in-person code that either party may use. Start, confirm and cancel stay with either party.
  • Proof: a held probe in docs/audit/reserved/ with negative controls, a runtime workflow that shows the defect on the released schema before applying the held file, and a source test. docs/audit/marketplace-ownership-update-check.sql has a positive control in which the buyer sets returned. It will read which rule is installed.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6133742075 is done. Two referral emails at once stay within the ten-a-day limit. Branch only, no PR. This answers the owner's finding 6127838006 on #1022.

  • Branch: claude/referral-invite-budget-7q6vtf at e2a8e6289b479ed0da71087010c48e1c1c59da47, one commit on main 9e898cf0a7acf584a1eb6b33a7d9d31393502966.
    • Main is now at aca5c9cba. Its three new commits touch none of these files.
    • git merge-tree exits 0 and lists only the three files below.
  • What changed:
    • lib/referrals/server.ts: recordReferralEmailInvite still turns away a family that is already at ten, using the first read. After writing the send, it calls admitWrittenReferralEmail, which re-reads the family's sends. ok: true now means the send was admitted, and the action mails only on that. If the read after the write fails, the send is rolled back and the answer is read_failed.
    • lib/referrals/core.ts: the pure decideReferralEmailAdmission.
    • Admission: a send is admitted while the window holds at most ten sends, its own included. That count alone keeps the family at ten, with no lock and no clock agreement: of any eleven admitted sends, the one written last would have read all eleven.
    • Tie-break: over ten, sends are ranked by send time, then row id, then position on the row. The send ranked past ten rolls back only its own send (its row by id, or its stamp on a reused row) and answers throttled. The send ranked within ten re-reads at most four times (25–200 ms apart) and is admitted once the other send is gone. A failed rollback is logged and sends nothing.
    • The full-metadata compare-and-set and the reward-attempt code are untouched. a-referral-is-credited-once and pr1022-referral-race-review are unchanged and pass.
  • Red first: tests/two-referral-emails-at-once-stay-within-the-daily-limit.test.ts runs on the repository's in-memory database double. A proxy holds each request after its first read, so both read nine and then both write.
    • On main's server.ts, 10 of 16 tests fail. The two-address race ends with "expected 11 to be 10". The action-level test sends two emails.
    • The sequential control and the below-limit control pass on main.
    • The new tests also cover: a repeat send racing a new address, three at once, a request whose clock is behind, a failed rollback, a failed admission read, and another family racing alongside.
  • Mutants killed (10/10):
    • no admission re-check;
    • ranking newest first;
    • no row-id tie-break;
    • admitting on rank alone;
    • ignoring sends dated after its own;
    • skipping the own-send rollback;
    • no re-read;
    • a missing send admitted;
    • a read error keeps the row;
    • a read error admits.
  • Gates:
    • all 19 test files that touch the referral modules, plus the new test (409 tests);
    • ordering-guards-fail-on-absence, i18n-ungated-surface-ratchet, silent-empty-read-ratchet, untrusted-fence-ratchet, i18n-sentence-templates-ratchet, server-actions-contract, the three an-unconfirmed-write-* ratchets;
    • eslint on the changed files;
    • full tsc --noEmit: clean.
  • For the owner:
    • Under a burst at the limit, a request can be refused when it could have gone: when clocks disagree, or when a rollback fails. It is never over-admitted.
    • A strict single winner in every interleaving would need a shared row or a database function. That is out of scope for code only.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6133894798 is done. The assistant adds and assigns chores only for a parent or adult, now on current main. Branch only, no PR.

  • Branch claude/ai-tool-authorization-7q6vtf, head ad6db78e2127b25669eed249da94988682e5bdbe, a merge of main 9e898cf0a7acf584a1eb6b33a7d9d31393502966 (no rebase, no force). git merge-tree --write-tree origin/main HEAD exits 0; the net diff against main is 4 files: lib/services/tasks/index.ts, lib/ai/tools/tasks.ts, lib/assistant/tools.ts, and the test.
  • Superseded by main: the child and caregiver cases under a "Bubaly may act on chores" policy (AI7/AI12). Main's code is kept there, and those test cases stay as regression cover.
  • Still needed and kept: createChore and the new requestChoreAssignment (behind tasks.assignChore) refuse anyone but a parent, an adult or the system, and chat add_chore does the same. This is resolved onto main's choreDueAt shape. assignChore stays open, so a repeating chore still respawns.
  • Red-first on main's source: tests/the-assistant-adds-chores-only-for-a-parent.test.ts had 4 failures, all teen cases: registry create, registry assign, chat add_chore, and create under a policy. A teen got ok each time. The repeating-chore case now runs as a teen, because main no longer lets a child's assistant complete chores under a policy.
  • Mutants killed (6/6): no gate in createChore; requestChoreAssignment without its gate; no add_chore gate; adult dropped; system dropped; always allow.
  • Gates: the focused test (12 passed), plus 57 test files that touch the changed modules or chore tools, including the ordering and i18n guards and assistant-tool-error-contract (1068 tests, all passed). eslint is clean and tsc is clean.
  • Audit of the other low-risk assistant write tools (a teen's are the only ones the gate lets through): routines, moving date, document links, trip disruption, home, memory, meals, todos and reminders all match their board rules. Announcements are refused for non-managers (gated as automate). No second fix.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6101058890 follow-up is done. AI Assist does not shop from an archived list. Branch only, no PR.

  • Branch claude/data-lifecycle-7q6vtf, head 87d7fbc3dbcdd54e3168edb1bc6da4f30b85b11d (merged with main 9e898cf0a). git merge-tree against current main aca5c9cba is clean, and the diff vs main is 18 files.
  • app/api/ai/insights/route.ts: the grocery/shopping kinds read unchecked items from every list, so an archived list's items reached the prompt as things to buy. They now read through readOnOpenGroceryLists, and a failed list read fails the request with "could not load".
  • Source guard in tests/an-archived-shopping-list-is-not-counted.test.ts: it now starts from the 'grocery_items' literal instead of from(. That also covers reads through a helper that takes the table name, and it flagged exactly route.ts:337, nothing else.
  • Red first: tests/an-insight-does-not-shop-from-an-archived-list.test.ts failed 4 of 4 cases (the archived item was in the prompt; a failed list read returned 200), and the widened guard failed too.
  • Mutants: dropping the list_id filter fails 3 cases, and swallowing the list-read error fails 2.
  • Gates: the 13 test files touching the route and the 20 guard/ratchet/contract tests pass. eslint is clean and the full tsc run is clean.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Bubaly cannot plan a saved meal, and planning a known dish by name makes an empty copy of it. Code only, no migration; branch claude/meals-groceries-7q6vtf; no PR.

  • Finding: meals.setSlot and meals.planWeek (lib/ai/tools/meals.ts) always pass ingredients: [] to the meals service, even when the model gave none. The service reads [] as "a variant with no ingredients", not "any dish of that name".
    • With a meal_id (an existing dish), validateEntries refuses the entry, so the assistant can never put a saved meal on the plan, and one such entry fails a whole planWeek.
    • With a name only (also create_meal_plan_entry from chat and Magic Import), "Tacos" with ingredients does not match, so a second, empty "Tacos" is created and planned. "Add this week's plan to the list" then adds nothing for it.
  • Fix: pass ingredients only when the model sent some, as app/api/ai/meals/plan/route.ts already does.

Generated by Claude Code

NewWorldVenture commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner Author

Support: claim 6133974146 is done. A marketplace order is returned or completed by its seller, in the database too (held 0518, still not confirmed). Branch only, no PR. Nothing is applied anywhere, and docs/PENDING_PROD_MIGRATIONS.md and finalaudit.md are untouched.

  • Branch: claude/marketplace-order-status-guard-7q6vtf at b798a1850c6c27d55fb14a175efcd4a4a3ca1773, cut from claude/marketplace-transactions-7q6vtf at 965cf8752 (main aca5c9cba). It merges cleanly (merge-tree exits 0) with main and with claude/support-batch3-7q6vtf (Support batch 3: marketplace orders, AI plan gates, archived lists, crons, referral send limit, assistant chores #1037). Against batch 3 the diff is exactly the 6 files below.
  • Held file: supabase/reserved/0518_a_marketplace_order_is_returned_or_completed_by_its_seller.sql adds a BEFORE UPDATE row trigger on marketplace_orders. It is SECURITY INVOKER with search_path = '', and it is keyed on current_user in ('authenticated','anon') as 0458 and 0482 are. A client's change of status to returned or completed, or any change of returned_at, is refused with 42501 unless marketplace_member_id(family_id) = seller_member, the app's own test. Those are the seller member, not the seller's family. It is re-runnable.
  • Unchanged: confirm, start, cancel and notes edits, by either party. Also unchanged: marketplace_complete_handoff (the in-person code, a definer function), the service role, session-less writers and cascades.
  • Also in the branch: a probe in docs/audit/reserved/, the workflow .github/workflows/marketplace-order-finish-runtime.yml, the test tests/a-marketplace-order-is-returned-or-completed-by-its-seller.test.ts, and a README row. Released marketplace-ownership-update-check.sql had the buyer set returned as a positive control. It now reads which rule is installed and passes under both.
  • Evidence (local PG 16.15 + pgvector, full replay): On the released schema the probe fails on 6 buyer writes (OK 1 each), and all of its controls pass. With 0518 applied twice, the probe passes. That run includes in-probe mutations M1 (no returned_at clause) and M2 (family instead of seller), plus a negative control N1 (trigger disabled). All 187 released probes pass with 0518 installed. The workflow's four SQL steps, run locally, are all green.
  • Mutants killed: 7 SQL mutants through the probe (definer, returned dropped, completed dropped, no change check, the 0505 uid idiom, service role not exempt, null seller allowed) and 8 source mutants through the test.
  • Gates: focused vitest (53 files, including migration-version-safety and the marketplace, ordering-guard, i18n-ratchet, probe and workflow scanners), node scripts/audit-migration-versions.mjs, eslint and tsc all pass.
  • For the owner: confirm 0518. Two related gaps are left open: either party can still move an order out of order among the other statuses, because the DB has no ORDER_FLOW, and either party can still write the reminder stamps (due_reminder_sent_at, overdue_notified_at).

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Editing a repeating event from a later week wipes the earlier weeks off the calendar. Code only, no migration; branch claude/calendar-events-7q6vtf; no PR.

  • Finding: a repeating event is one calendar_events row whose starts_at is its first occurrence. The calendar shows each occurrence with that occurrence's own starts_at (lib/calendar/recurrence.ts), and Edit (components/modules/calendar-module.tsx) prefills the modal from it. Save sends that time back through updateCalendarEventAction to updateEvent, which writes it into the series row.
  • Who hits it: any family member who fixes the title or location of a weekly practice from next month's entry. Every week between the series' real start and that entry disappears from the calendar, and from reminders, briefs and conflict checks too. Moving one occurrence's time does the same thing.
  • Fix: the modal passes the occurrence it was opened from. updateEvent takes an optional occurrenceStartsAt and maps the new start and end back onto the series' own first date on the family's wall clock (all-day rows by date). An unchanged time leaves the row's start exactly as it was. A one-off event, the first occurrence, and a series turned into a one-off behave as today.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. School and homework: a timetable edit that drops the student, homework insights built on a failed read, and "Due today" on the device's clock. Code only, no migration; branch claude/school-kids-7q6vtf (from main 3136816c0); no PR.

  • components/modules/timetable-module.tsx: editing a class and picking a different student says "Class updated", but the update never sends member_id, so the class stays on the first child. Fix: the update writes the chosen student.
  • app/api/ai/insights/route.ts (homework and school kinds): a failed homework_assignments or grades read becomes "Open homework: none" and the model writes a study plan around nothing being due. Both kinds also count submitted work as open homework. Fix: pass the reads through the route's required() (answer "could not load"), and read only assigned/in_progress as open. The grocery hunk from Support batch 3: marketplace orders, AI plan gates, archived lists, crons, referral send limit, assistant chores #1037 is left alone.
  • lib/homework/board.ts + homework-module.tsx: the "Due today" bucket is worked out on the device's clock, not the family's (TIME-003), so a parent away from home sees tomorrow's work under "Due today" (or today's under "Upcoming"). Fix: bucket on the family's day key.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137499789 is done. Bubaly plans a saved meal, and reuses a known dish by name. Branch only, no PR.

  • Branch: claude/meals-groceries-7q6vtf at be1cd29d6a6466913e8435b2b2a761e3d7ac315a, one commit on main aca5c9cba2777e64de2d1eca2452c8a4b7996e2f.
  • Change: lib/ai/tools/meals.ts gets ingredientsFromModel. meals.setSlot and meals.planWeek pass ingredients only for a dish named, and only when the model wrote some (an empty list counts as none). A saved meal keeps its stored ingredients.
  • Red first: tests/the-assistant-plans-the-familys-own-saved-meal.test.ts failed 3 of 4 on main. A slot by meal_id was refused with "Choose one meal, recipe or custom dish with valid ingredients." A name-only "tacos" left 2 Tacos rows in meals. A mixed week was refused. All 6 cases pass now.
  • Mutants (5, all killed): dropping the meal-id branch; letting an empty list through; turning an absent list into []; reverting either call site.
  • Gates: 15 related files (248 tests, including service-meals, tool-meals-memory-messages, assistant-engine, magic-import-confirms-only-what-it-proposed). Also ordering-guards-fail-on-absence, the 8 ratchets and assistant-tool-error-contract. eslint and full tsc are clean.
  • Left for the owner: nothing. No schema change.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Asking Bubaly to add milk that is already on the list adds a second Milk. Code only, no migration; same branch claude/meals-groceries-7q6vtf; no PR.

  • Finding: the chat toolbox's add_grocery_item (lib/assistant/tools.ts) inserts into grocery_items itself. mergeToolSets puts it ahead of the registry's groceries.addItems, and /api/ai/chat offers only the toolbox.
    • So the duplicate check in addItems never runs on this path. A parent saying "add milk" when milk is still unticked, or a repeated tool call, gets two Milk lines.
    • The line also lands with no aisle and leaves no activity entry.
  • Fix: keep the tool's list lookup and its error wording, then add through addItems from the groceries service. When the item is already on the list, reply "already on the grocery list" and do not insert it again. An unknown role is refused, as add_goal does.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137515894 is done. Editing a repeating event from a later week keeps the earlier weeks. Branch only, no PR.

  • Branch: claude/calendar-events-7q6vtf at c7090c32c7f83c04a6a6033a6408d0c0944b5576, one commit on main aca5c9cba2777e64de2d1eca2452c8a4b7996e2f. Main has since moved to 3136816c0, which touches none of these files. git merge-tree --write-tree origin/main HEAD exits 0 and lists only the 4 files below.
  • What changed:
    • components/modules/calendar-module.tsx: Edit passes the occurrence it was opened from (occurrenceStartsAt: existing.starts_at).
    • app/(app)/dashboard/calendar/actions.ts: updateCalendarEventAction takes that as an optional third argument and hands it to the service.
    • lib/services/calendar/index.ts: updateEvent takes an optional occurrenceStartsAt. For a row that is a series before and after the edit, it maps the new start and end onto the series' first date. The mapping uses whole dates on the series' own clock (the family zone, or UTC dates for all-day rows) and keeps the length given. An unchanged start writes back the row's exact instant. The row it reads is the compare-and-set state, as in rescheduleAfter.
  • Red first: tests/editing-one-week-of-a-repeating-event-keeps-the-earlier-weeks.test.ts drives the real action and service against the in-memory Postgres. On main, 6 of its first 9 cases failed. One was a title edit from 3 November, which moved the series start from 2026-09-01T20:00Z to 2026-11-03T21:00Z. Now 12/12 pass.
  • Mutants: 13 killed. They covered the modal, action and service wiring, both series guards, all-day on the family zone, counting the move in hours (the DST case), the day delta, the clock time, the end mapping, the end-only branch, and re-reading an unchanged start in the repeated hour. Not killable: the early return for the first week, which only skips work that gives the same answer.
  • Gates: the new test plus 30 related files (891 tests); the ordering and i18n guards plus the ratchets, contracts and repo scanners (40 files); eslint on the changed files; full tsc --noEmit, clean.
  • Left for the owner: the assistant's calendar.updateEvent and calendar.rescheduleEvent take an event id plus a start the model read from an expanded occurrence. They have the same re-anchoring and do not pass an occurrence yet.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. An event moved to a later day after its reminder went out is never reminded again. Code only, no migration; branch claude/calendar-events-7q6vtf (second fix on it); no PR.

  • Finding: generateFamilyNotifications (lib/server/notifications.ts) reminds each event in the next 48 hours, and its dedupe is permanent and keyed by related_id. That key is the date-stamped occurrence for a series, but the bare event id for a one-off.
  • Who hits it: a game rained out on Saturday and moved to next Saturday. The Thursday reminder went out for the first date, and once the parent moves the event, next Thursday's reminder is taken as already sent. The same happens to any appointment moved to a later date.
  • Fix: keep the key as it is, so there are no new keys and no repeat reminders at deploy. The dedupe also reads created_at. For a one-off event, an earlier notice counts as sent only if it was written inside this start's own reminder window: 48 hours before the start (or before the family's midnight for an all-day date), with an hour's margin for clock skew. Other categories and series are unchanged.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137557852 is done. Asking Bubaly to add milk that is already on the list does not add a second Milk. Branch only, no PR.

  • Branch: claude/meals-groceries-7q6vtf at 8d48e43f241733f0923c66122b376910c0b75250. That is the fix 80c8ad332 (plus db548b04f, which moves one import) and a normal merge of main 3136816c0929e278720b82d9aadc71884a01faa3.
  • Change: the chat toolbox's add_grocery_item still opens the default list the same way and keeps its error wording. It then adds through addItems, which skips an item still unticked on the list, guesses the aisle and records the trail entry.
    • When nothing was added it answers " is already on the grocery list."
    • An unknown role is refused, as add_goal does.
  • Red first: tests/the-assistant-does-not-put-milk-on-the-list-twice.test.ts failed 3 of 5 on main. "milk" made a second Milk row, two calls made two Eggs rows, and an unknown role was let through. All 6 cases pass now; the 6th covers a refused write.
  • Mutants (5, all killed): dropping the "already on the list" answer; dropping the role refusal; passing the service's raw error text through; a raw insert instead of addItems; dropping the quantity.
  • Gates: all 34 test files that use the assistant toolbox (771 tests). Also grocery-write-path, service-groceries, ordering-guards-fail-on-absence, the 8 ratchets and assistant-tool-error-contract. After the merge with main, the new tests, the guards and full tsc were run again. eslint is clean.
  • Left for the owner: nothing. No schema change.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. A meal vote that was closed still takes ballots. Code only, no migration; same branch claude/meals-groceries-7q6vtf; no PR.

  • Finding: castBallot (app/(app)/dashboard/recipes/vote/actions.ts) upserts a ballot without checking the vote's status. The page hides the vote buttons once a vote is closed, but a stale page, or a direct call, still changes the counts on a dinner the family already decided. Nothing in RLS checks the status either.
  • Fix: read the vote, scoped to the family, before writing.
    • A closed vote is refused with a new translated "this vote is closed" message.
    • A vote that is not found, or a read that fails, is refused and nothing is written. A failed read is not treated as an open vote.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137650856 is done. An event moved to a later day is reminded again at its new time. Branch only, no PR.

  • Branch: claude/calendar-events-7q6vtf at 14c97b978a1696220b378b36abbd232e220cc82a. That is the fix 14c97b978 on top of a normal merge of main 3136816c0929e278720b82d9aadc71884a01faa3 (de4ffb261) and the first fix c7090c32c (completion 6137621825). git merge-tree --write-tree origin/main HEAD exits 0, and the net diff against main is the 6 files of the two fixes.
  • What changed (lib/server/notifications.ts):
    • The keys are unchanged: a one-off is still its bare id, so nothing is reminded twice at deploy.
    • The dedupe read now selects created_at, and the filter compares each key's latest notice with the candidate's new freshFrom.
    • For a one-off calendar event, freshFrom is 48 hours before the start, less an hour of database clock skew. For an all-day date it counts from the family's midnight, which in Auckland is two and a half days before the stored midnight.
    • A notice with no readable time still counts as sent. Series and other categories are unchanged.
  • Red first: in tests/a-moved-event-is-reminded-at-its-new-time.test.ts, the rained-out game failed on main: the move to the 24th got no second reminder ("expected length 2 but got 1"). The other three cases pin what must not change. They are an unmoved event reminded once, a notice written just before the window on a lagging database clock, and an all-day date east of Greenwich. Now 4/4 pass.
  • Mutants: 7 killed: no freshness for one-offs; all-day measured from the stored midnight; no skew margin; earliest instead of latest notice; an unknown clock treated as stale (this one breaks 6 cases of the existing notification-calendar-complete-boundary suite); created_at not read; freshness ignored in the filter.
  • Gates: 15 notification and generator files (223 tests); the ordering and i18n guards plus 30 ratchets, contracts and repo scanners (414 tests); eslint on the changed files; full tsc --noEmit on the merged tree, clean.
  • Left for the owner: school_events and sports_events reminders in the same generator have the same bare-id key (another lane's tables). A one-off moved within its own 48-hour window is still not reminded a second time.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137518280 is done. School and homework: a timetable edit moves the class to the student picked, homework insights fail closed and skip handed-in work, and "Due today" is the family's today. Branch only, no PR.

  • Branch claude/school-kids-7q6vtf, head edc9c4f122d9bce9fef83106e098622d845da862, based on main 3136816c0929e278720b82d9aadc71884a01faa3. git merge-tree is clean against main and against Support batch 3: marketplace orders, AI plan gates, archived lists, crons, referral send limit, assistant chores #1037's head.
  • Timetable (aa301b794): the edit dialog's student change is now saved. Add and edit write the same columns through classFormFields (lib/school/timetable.ts). The hand-written school_classes Update type in lib/database.types.ts now allows member_id, as the table does; no trigger or policy guards that column. Red first: tests/a-timetable-edit-moves-the-class-to-the-chosen-student.test.ts, 3 of 3 failed. Mutants killed: helper without member_id, and the module's update without it.
  • AI study plan / school coach (8ff7ca91d): the homework and school kinds in app/api/ai/insights/route.ts pass their reads through required(), so a failed read now gets a 500 "could not load" and the model is not called. They also read open homework as assigned/in_progress, the same rule the board and listHomeworkDue use. Red first: tests/a-homework-insight-is-not-built-on-a-failed-read.test.ts, 5 of 6 failed (200 instead of 500, and submitted work in the prompt). Five mutants killed: each required entry removed, submitted counted as open, and neq('done') put back.
  • Due today (edc9c4f12): dueBucket/groupByDue take the family zone, and the Homework page passes clock.timeZone. Red first: tests/homework-due-today-is-the-familys-today.test.ts failed 3 of 4 under TZ=UTC and 2 of 4 under TZ=America/Los_Angeles. It passes under both now. Four mutants killed.
  • Gates: the new tests plus every existing test that touches the changed files (homework-board, school-timetable, an-insight-is-not-built-on-a-household-read-that-failed, insight-kinds-are-gated-like-their-pages, a-client-write-reads-what-it-changed, the TIME-003 date ratchets and others), ordering-guards-fail-on-absence, i18n-ungated-surface-ratchet, an-unconfirmed-write-*-ratchet, silent-empty-read-ratchet and untrusted-fence-ratchet. All pass, along with eslint on the changed files and a full tsc --noEmit (exit 0).
  • For the owner: nothing needs SQL. No new user-visible strings.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Two follow-ups to 6137746989 and 6137621825: moved school and sports events get a new reminder, and the assistant cannot re-anchor a repeating series. Code only, no migration; branch claude/calendar-events-7q6vtf; no PR. One commit and one completion per item.

  • 1. School and sports reminders (lib/server/notifications.ts, which this branch already changes; the school/kids lane is staying out of it):
    • school_events and sports_events reminders have the same bare-id permanent dedupe as one-off calendar events had. A rescheduled game or school night that was already reminded is never reminded at its new date.
    • Fix: the same rule as 6137746989. Same keys; an earlier notice counts only if written within 48 hours (plus an hour of skew) before the current start. Nothing is reminded twice at deploy.
  • 2. Assistant edits of a repeating event (lib/ai/tools/calendar.ts, lib/services/calendar/index.ts):
    • calendar.updateEvent and calendar.rescheduleEvent take an event id plus a start the model read from one week of the series. That start was written into the series row, so the weeks before it disappeared, as in the modal bug.
    • Fix: both tools take an optional occurrence_starts_at and map it through the service path from fix 1. If a repeating event's time changes and no week is named, the service refuses and asks which week, rather than guessing. One-off events are unchanged.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Four school/kids follow-ups from 6137749858: a re-started milestone keeps its achievement, overdue homework is listed by the assistant, a child's Today is their own day, and "due tomorrow" counts work in progress. Code only, no migration; same branch claude/school-kids-7q6vtf; no PR. lib/server/notifications.ts is not touched.

  • app/(app)/dashboard/independence/actions.ts startMilestoneAction: the upsert on (family_id, member_id, domain, title) rewrites an achieved rung to in_progress when a stale page or a repeated call starts it again. Fix: insert-or-ignore, then a conditional restart that never touches an achieved row. An achieved rung is answered with a sentence that says so, not "Added".
  • lib/ai/tools/school.ts school.listHomeworkDue: the default window starts now, so a child with overdue open work is told "No homework due". Fix: with no from, open work that is already overdue is included and marked overdue.
  • app/(app)/kids/page.tsx "Today": lists every family event, including ones assigned to a parent or sibling. Fix: the home dashboard's rule (unassigned, or the child's own), shared from one helper.
  • app/(app)/dashboard/moments/page.tsx and components/dashboard/ai-home-dashboard.tsx: "homework due tomorrow" counts only assigned. Fix: the same open set as the insights fix (assigned, in_progress).

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137724954 is done. A closed meal vote takes no more ballots. Branch only, no PR.

  • Branch: claude/meals-groceries-7q6vtf at d0c09cf2a7bcaa64b160e24754866b3069d69081. It sits on the branch's merge of main 3136816c0929e278720b82d9aadc71884a01faa3.
  • Change: castBallot reads the vote's status, scoped to the family, before it upserts. The read goes through settle.
    • A vote that is not open gets actions.thatVoteIsClosed.
    • A failed read, or a vote not in this family, gets actions.couldNotRecordYourVote, and nothing is written.
    • Both messages are new, with translations in all 7 base locales.
  • Red first: tests/a-closed-meal-vote-takes-no-more-ballots.test.ts failed 3 of 4 on the unfixed code. Each failure was { ok: true } where a refusal was expected: closed vote, another family's vote, failed read. All 4 pass now.
  • Mutants (5, all killed): dropping the status check; inverting it; letting a missing vote through; letting a failed read through; dropping the family filter.
  • Gates: the 9 test files that name the vote actions, plus i18n-catalogue-integrity and 4 other i18n tests (289 tests). Also ordering-guards-fail-on-absence and the 8 ratchets, i18n:gate, eslint and full tsc.
  • Left for the owner: a close that lands between the read and the write can still let one ballot through. Shutting that needs a database rule (an RLS or trigger check on meal_votes.status), which is a schema change. I did not write it.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. Logging a leftover crashes when the save comes back with no row. Code only, no migration; same branch claude/meals-groceries-7q6vtf; no PR.

  • Finding: addLeftoverAction (app/(app)/dashboard/kitchen/actions.ts) returns data!.id after insert(...).select('id').maybeSingle(). An insert that RLS admits but whose row the select cannot see returns data: null with no error, and the action then throws a TypeError. The kitchen form gets no answer to show.
  • Fix: when the save returns no row, report it as a failed save, in the same style as the other confirmed writes. A new translated message says the leftover could not be confirmed and asks the person to refresh before adding it again.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137770406, item 1 of 2 is done. A moved school or sports event is reminded again at its new time. Branch only, no PR.

  • Branch: claude/calendar-events-7q6vtf at e19bf468c5ea73faf249219401d7ebbe96bc6339, which includes main 3136816c0929e278720b82d9aadc71884a01faa3. git merge-tree --write-tree origin/main HEAD exits 0; the net diff is the branch's 7 files.
  • What changed (lib/server/notifications.ts): school_event and sports_event candidates now carry the same freshFrom as one-off calendar events (eventReminderOpensAt), measured by instant, since the generator reads both tables by instant. Their keys are unchanged, so nothing is reminded twice at deploy.
  • Red first: in tests/a-moved-school-or-sports-event-is-reminded-at-its-new-time.test.ts, the game moved to the next Saturday and the school night pushed back a week each failed on the previous head ("expected length 2 but got 1"). Two more cases pin the parts that must not change: unmoved events are reminded once, and a notice written just before the window on a lagging database clock still counts. Now 4/4 pass.
  • Mutants: 4 killed: school freshness dropped, sports freshness dropped, no skew margin, earliest notice instead of latest.
  • Gates: 15 notification and generator files (194 tests); ordering and i18n guards, ratchets, contracts and repo scanners (21 files, 286 tests); eslint on the changed files; full tsc --noEmit, clean.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137790992 is done. A leftover save that comes back with no row is reported as a failed save, not a crash. Branch only, no PR.

  • Branch: claude/meals-groceries-7q6vtf at 8adafdf00d1e917ad868a076592278cb6e8dc9af, on main 3136816c0929e278720b82d9aadc71884a01faa3.
  • Change: addLeftoverAction returns actions.couldNotConfirmThatLeftoverWasSaved when the insert returns no row and no error, instead of data!.id. This matches how the update and delete beside it report zero rows. The message is new, with translations in all 7 base locales.
  • Red first: tests/a-leftover-save-that-returns-no-row-is-a-failed-save.test.ts failed on the unfixed code with TypeError: Cannot read properties of null (reading 'id'). The normal save case passed before and after.
  • Mutants (3, all killed): restoring data!.id; reporting the missing row as success; inverting the check.
  • Gates: the 8 test files that name the kitchen actions, plus the i18n catalogue tests (309 tests). Also ordering-guards-fail-on-absence and the 8 ratchets, i18n:gate, eslint and full tsc.
  • Left for the owner: nothing. No schema change.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137770406, item 2 of 2 is done. The assistant cannot restart a repeating event on the week it read. Branch only, no PR.

  • Branch: claude/calendar-events-7q6vtf at 8e2c4ea368668f3d4f7b2b36ecfa41e278a02b45, which includes main 3136816c0929e278720b82d9aadc71884a01faa3. git merge-tree --write-tree origin/main HEAD exits 0; the net diff is the branch's 10 files.
  • What changed:
    • lib/ai/tools/calendar.ts: calendar.updateEvent and calendar.rescheduleEvent take an optional occurrence_starts_at, the week being changed as calendar.searchEvents returned it.
      • Reschedule verification now looks for the moved week among the series' occurrences.
      • when in the result names the changed week, not the first week.
    • lib/services/calendar/index.ts:
      • updateEvent gains seriesNeedsOccurrence. rescheduleAfter gains occurrenceStartsAt and seriesNeedsOccurrence. Both map through fix 1's onSeriesClock.
      • Other callers (the conflicts page, the modal) behave as before.
    • lib/ai/planner/templates/plan-week.ts: the reschedule step's fill hint asks for the week when the event repeats.
  • Refuse, not guess:
    • When a repeating event's time changes and no week is named, the tools refuse with "That event repeats. Say which week this new time is for…".
    • This matches the service's contract: findEventByTitle refuses an ambiguous title rather than picking one.
    • Keeping the first date and taking only the clock time would silently drop a move to another weekday, and reschedule verification could never pass on it.
    • Title-only edits of a series and every one-off edit are unchanged.
    • A stored approval that changes a series' time with no week will now be refused when it is replayed, not applied.
  • Red first: tests/the-assistant-moves-one-week-of-a-repeating-event-without-losing-the-rest.test.ts: 6 of 8 cases failed before the fix. A reschedule of the 3 November week landed the series at 2026-11-03T22:00Z instead of 2026-09-01T21:00Z, and zod stripped occurrence_starts_at. Now 8/8 pass.
  • Mutants: 12 killed: each tool's mapping, refusal and schema field; verification; the result's when; refusing one-offs too; and both service refusal paths and the occurrence mapping.
  • Gates: 51 related files (1,180 tests); guards, ratchets and scanners (19 files); eslint; full tsc --noEmit, clean.
  • Left for the owner: the conflicts page's rescheduleEventAction still moves a series occurrence without naming the week.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: new claim, posted before editing. The conflicts page's quick fix names the week it moves. Code only, no migration; branch claude/calendar-events-7q6vtf; no PR. Follow-up to 6137884475.

  • Finding: rescheduleEventAction (app/(app)/dashboard/conflicts/actions.ts) hands updateEvent a new start and end and no week. It is the last writer of an event's time that does not name the week it was shown.
    • On today's page that week is always a series' first week, because the page reads stored rows by their own starts_at. That same read is also why it never sees later weeks of a series at all; I will report that separately rather than change the read here.
  • Fix:
    • quickFixMoveAfter (lib/family/conflicts.ts) records the start of the event it moves.
    • The page and ConflictResolver pass that start to the action. The action forwards it through the service path from fixes 1 and 4, with seriesNeedsOccurrence.
    • A repeating event is refused only when no week arrives, which only an open tab with the old page code can cause. The refusal asks the family to refresh, translated in the 7 base locales.
    • One-off events are unchanged.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137904622 is done. The conflicts page's quick fix names the week it moves. Branch only, no PR.

  • Branch: claude/calendar-events-7q6vtf at 5cabe72f5c205dcbef46efcf46ecf715f936d450, which includes main 3136816c0929e278720b82d9aadc71884a01faa3. git merge-tree --write-tree origin/main HEAD exits 0; the net diff is the branch's 22 files.
  • What changed:
    • quickFixMoveAfter records occurrenceStartsAt (the moved event's start as shown).
    • page.tsx and ConflictResolver carry it to rescheduleEventAction.
    • The action forwards it to updateEvent with seriesNeedsOccurrence. The service now exports SERIES_NEEDS_OCCURRENCE, so the action can recognise that refusal and translate it.
    • New key actions.thisEventRepeatsAndThis in all 7 base locales ("This event repeats, and this page is out of date. Refresh and try again."). Only a tab running the old card can trigger it.
    • One-off events are unchanged.
  • Red first: tests/a-conflict-quick-fix-names-the-week-it-moves.test.ts: 6 of 7 failed before the fix. Moving the 3 November week landed the series at 2026-11-03T21:30Z instead of 2026-09-01T20:30Z, and a series move with no week went through. Now 7/7 pass, and the existing conflict suites still pass.
  • Mutants: 7 killed: the quick fix omits the week or names the other event; the page or the card drops it; the action drops the week, skips the refusal, or leaves it untranslated.
  • Gates: 47 related, i18n and guard files (824 tests); eslint; full tsc --noEmit, clean.
  • Left for the owner:
    • The page reads stored rows by starts_at (.gte/.lte over 14 days), not series occurrences. A repeating event whose first week is older than today never shows a clash, and the quick fix only ever sees a series' first week.
    • For a repeating event, the quick fix moves every week. Its label does not say so.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Support: claim 6137786640 is done. Four school/kids follow-ups: a re-started milestone keeps its achievement, the assistant lists overdue homework, a child's Today is their own day, and "due tomorrow" counts work in progress. Branch only, no PR.

  • Branch claude/school-kids-7q6vtf, head 3219193ab2d3cd90728d7fddabf5ff7753d7db3d, merged with main 4049f99a9732160c7489f7805a2989d7a0027c43 (after Support batch 3: marketplace orders, AI plan gates, archived lists, crons, referral send limit, assistant chores #1037). git merge-tree exits 0, and the diff against main lists only this branch's files. lib/server/notifications.ts is not touched.
  • Milestone (06d825f69): startMilestoneAction now does insert-or-ignore, then restarts an existing rung with an update that skips status = 'achieved'. An achieved rung gets actions.milestoneAlreadyAchieved (new key, all seven catalogues) instead of "Added". Red: 2 of 5 failed in tests/a-restarted-milestone-keeps-its-achievement.test.ts. 4 mutants killed. independence-member-family and a-write-the-user-is-told-about-is-confirmed were updated from the old upsert contract.
  • Overdue homework (01ab57139): with no from, school.listHomeworkDue also reads open work due before the window (listHomeworkDue includeOverdue). That work is listed first, each item gets overdue: true, and the summary counts it. Red: 3 of 4 failed. 6 mutants killed.
  • Kids Today (e3bc487f4): the page and the home dashboard now share onMembersDay (lib/calendar/members-day.ts), so a child sees events assigned to nobody and their own. Red: the rendered page showed a sibling's and a parent's appointments. 4 mutants killed.
  • Due tomorrow (33798b693): the Moments page, the home insight and the AI study plan read OPEN_HOMEWORK_STATUSES (lib/homework/board). The insight no longer says started work "hasn't been acknowledged". Red: 5 of 5 failed. 5 mutants killed.
  • Guard repair (30e49364b): commits A and B tripped two source guards I had missed. This commit classifies the new ignoreDuplicates upsert and declares the board's device-calendar fallback. Afterwards I ran all 248 tree-scanning tests in batches of 15, and they pass.
  • Gates: tests touching each changed file, the i18n catalogue tests and the guard tests above. vitest runs were ≤15 files each. eslint is clean, and full tsc exits 0, both on the merged tree too.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants