Skip to content

Phase 2 follow-ups from Codex gate round 49 (#443) #464

Description

@Clarion1631

Follow-up to #443 (Phase 2: review queue + signed memos). Filed under the Option B stop rule: the PR's last Codex gate verdict (round 49, 2026-09-03 19:40Z on 9ac7a463) has no P0, so it merges after Phase 1 once its apply script has run; the remaining P1 findings are tracked here. Round 48's Critical items (split-identity manifest failing open, quarantine store failing open, delivery reservation committing on a lost CAS) were fixed in that push.

From round 49

  1. [P1] Quarantine persistence failures still return success and lose the retry. When persistQuarantine() fails, src/app/api/cron/bank-register-pull/route.ts:966 records only quarantineStateReason; summary.ok stays true, so the continuation marker at :1014 is not set and :1032 returns HTTP 200. A transient quarantine read/write failure withholds freshness while every continuation slot reports nothing-in-progress, suppressing that day's receipt cards. Fix: treat !quarantine.ok as a failed run, persist a continuation obligation, return non-2xx; test with an injected write failure and assert the next slot retries.

  2. [P1] Database failures reading the split manifest bypass the recovery path. The findUnique at route.ts:702 sits outside the conversion to SplitManifestUnreadableError; only JSON/schema failures get that type. A transient DB error is rethrown past the handler at :484, so no continuation or blocked reason is recorded, and with completed window state every scheduled continuation skips until the next nightly full run. Fix: route the read failure through the same recoverable path (or persist a retry obligation before rethrowing); test with an injected DB error.

Also open

  1. No operator path to accept a quarantine. The acceptance mechanism is versioned, but an operator would have to hand-write the AutomationSetting row. Add a manager-page action (or MCP tool) that records an acceptance bound to the current quarantine version.
  2. The apply-script e2e driver has only ever run in CI. Docker Desktop does not start on the dev box and there is no local Postgres, so seed → apply → re-apply → parity was never run locally; both driver failures this PR (a pre-Phase-2 column, a text param bound into a timestamp) would have been caught locally. Worth a local Postgres recipe before the next apply-script change.

Not a code item

  • Before merge, the Beverly bridge (gtr-books) must send n and request_id with every signed-memo answer, or answers are refused as association-incomplete.

Companion work on the Apps Script side (found 2026-09-04, blocks the chat-signing feature, not the merge)

The contract ProBuild enforces: POST /api/automation/receipt-requests/answers (auth RECEIPT_BRIDGE_SECRET) requires thread, integer n, and request_id (requestId also accepted) and matches all three against the posted card's stored record; GET /api/automation/receipt-requests/threads emits {owner, owner_user, message_name, request_id, items:[{n, fingerprint, ...}]} with request_id = receipt-req-<owner>-<date>.

What exists today in C:\Users\jat00\workspaces\golden-touch (clasp folders, no git):

  • beverly-chat-app/chatAffidavitApp.js — PREPARED (not pushed): signAffidavitCore_ now writes n and request_id into each signed answer record, read from affidavit-threads.json by thread + fingerprint; 6 new tests in beverly-chat-app/test/signAffidavit.test.js (15/15 green, mutation-checked). Deploy = clasp push from that folder (HEAD deployment is live immediately; script id in .clasp.json).
  • qbo-clasp/sweepChatReceipts.js — unchanged; none of its answer writers are signatures, so ProBuild ignores them.

What does NOT exist and must be built before a signed memo can reach ProBuild:

  1. Threads mirror (Phase 2 spec §4 item 2, mirrorReceiptRequestThreads()): poll the threads endpoint and merge into affidavit-threads.json by thread key without clobbering Beverly's own entries; needs the bridge secret in Script Properties and a post-07:45 trigger.
  2. Answers forwarder: nothing POSTs chat-job-answers.json records to the answers endpoint.
  3. Product call: a signature with no card association still produces a PDF and an unusable answer (logged, not refused), because Beverly's non-ProBuild affidavits legitimately have no thread entry.

Until 1 and 2 ship, ProBuild refuses every chat answer as association-incomplete and the chase stays open; the existing Beverly flow (chat signing → PDF → email/archive) is unaffected.
4. Possible fourth writer. Beverly's Python runner (affidavit_chat_request.py, runs on Justin's PC, not in any repo here) may also append signed:true records to chat-job-answers.json; it was not found on disk to check. Recommended durable shape: have the (new) answers forwarder back-fill n and request_id from affidavit-threads.json at forward time, which covers every writer at once, instead of patching each producer.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions