Repository navigation
Conversation
…atomic consume (DRAFT: awaiting operator decision #2240) This is the Gate B keystone (MUST-CLOSE 7 and 8). The schema is operator decision #2240, as amended by #2301 (payer, parent binding, currency check, app-level digest recompute, exact ceiling) and #2302 (min_tier). It must not merge before the operator decides queue item 26. Once merged and deployed, the table is created by the runtime migration. @pcc/store BudgetReservationStore is self-contained over the raw SQLite handle: - Amounts are canonical decimal TEXT compared as BigInt, never a float and never in SQL. - issue runs in ONE BEGIN IMMEDIATE transaction. Issued and consumed top-level reservations must fit the request's ceiling. For MC 9 children: the parent must be consumed, in the same currency, and issued to the parent unit's operator; all children of a unit fit its net n and none outlives its reclaimAt; the child's floor is max(parent's, its own). - consume runs in ONE BEGIN IMMEDIATE transaction. It re-checks principal, request, currency, every payer, issued and unexpired, the maximum and the floor, then seals the digest. The UPDATE is conditional on state = 'issued', and exactly one row must change. - SQL CHECKs cover canonical digits, the known states, consumed <=> digest, min_tier in 0..3, and both halves of a parent binding or neither. The gateway's services/reservation-store.ts is the trace stand-in's consume protocol, made durable. Before the store it refuses wrong-binding, digest-mismatch (the digest is RECOMPUTED from content) and obligation-mismatch. A resealed plan is still refused by the store's authority checks. Tests: db 11 (the db package suite passes with the new migration) and gateway 5, including the whole route on the durable store with exactly one of two concurrent accepts sealed. Full gateway suite: 3049 passed, 6 skipped; only the known capture suites fail to load. Mutation checks: 20 in all, 18 killed. The 2 store survivors are layered concurrency defenses single-threaded tests cannot separate: IMMEDIATE vs deferred, and the conditional UPDATE guard. Each is kept as defence in depth. pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz
…he parent payer (self-review of #402) Two flaws found in a self-review before the cross-family round: - An issued reservation past its expiry kept its share of the request ceiling, and a child kept its share of the parent unit, until housekeeping marked it expired. No housekeeping runs, so the share was held forever, although consume already refuses it. Money is now held by consumed reservations and by issued ones that are unexpired at the moment of issue. - A child reservation could name the parent's payer. #2301: a child never uses the parent payer's credentials. The operator funds its subcontract from its own wallet, so this is now refused as child-payer-is-parent-payer. Tests: db 13/13 (2 new) and gateway 5/5. 4 mutation checks, all killed: expired still holding, the child payer check, consumed not counting, and the expiry boundary. pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz
This was referenced Sep 24, 2026
…nt #3231, steward conditions #3235) budget_reservations gains consumed_deal_json, which the consume writes in the same transaction as the digest. - (a) The stored bytes are acceptedDealDigest's canonical PREIMAGE, and the consume refuses unless sha256(bytes) == the digest (deal-preimage-mismatch). A table CHECK makes consumed <=> bytes present. - (b) The bytes are never part of the reservation object. Only sealedDealPreimage(id), server-side, reads them (for MC 9's parent terms, funding and VCR delivery). - (c) At most 1 MiB, enforced by the store and by a table CHECK. The gateway adapter passes the preimage in the next commit, once #351 exports acceptedDealPreimage. Tests: db 16/16 (3 new; the helpers now use real preimage/digest pairs). pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz
…reservations (for the stored sealed deal)
…mage (amendment #3231) The consume protocol recomputes the digest as sha256 of #351's acceptedDealPreimage(plan). The carried digest must equal it (digest-mismatch otherwise). The store receives both the recomputed digest and the preimage bytes, re-checks that they hash to each other, and keeps the bytes as the sealed deal (steward condition (a), #3235). Tests: gateway reservation-store 5/5; after a real accept, the stored bytes hash to exactly the sealed digest and parse as the deal. Route tests 17/17. 4 mutation checks on the store's amendment logic, all killed: the hash unchecked, the bytes not stored, no size bound in the store, the bytes exposed on the reservation object. pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz
…et-reservations pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz
… deal (ChatGPT review of 0b8adda) The operator's cross-family review (ChatGPT, 2026-09-28) of #402/#410/#415 at 0b8adda was DO-NOT-SHIP. This commit fixes the store side of every finding. The routes follow in #410 and #415. - H1: child terms come from the sealed deal, never the caller. - `issue` takes `parent: { reservationId, unit }` only. Inside its IMMEDIATE transaction it: 1. reads the consumed parent; 2. re-checks sha256(stored deal) == stored digest; 3. parses the deal strictly and requires it to be that reservation's deal; 4. finds the exact unit and derives its operator, net n and reclaimAt. - The identity checks come first, so a non-operator only ever sees the not-found family. - A child also fits its own request's ceiling. - H2: durable expiry, and the store's own clock. - The clock is injected at construction and read inside each transaction; no caller passes `now`. - Before an issue frees an expired reservation's share, it moves that reservation issued -> expired in the same transaction, in both the request scope and the sibling scope. - A consume that finds an expiry records it. Consume requires 'issued'. - So a skewed clock cannot consume a share that was already re-issued. This is tested on two connections, in both orders and for siblings. - H3: 0004_budget_reservations.sql is BUDGET_RESERVATIONS_DDL, statement for statement (test-asserted). - migrateDatabase runs ensureBudgetReservationsSchema. That rebuilds an EMPTY table of another shape and refuses to boot on one that holds rows. - Test: 0004, then the runtime migration, then a real consume. - M5: the table refuses what its invariants forbid. - CHECKs: amount > 0 and <= uint256; a canonical digest; consumed <=> digest <=> deal <=> consumed_at; created < expires; integer times and tier. - Triggers: inserts only as issued, and a child only under a consumed parent; updates only issued -> consumed | expired | released, with no term changed; no DELETE. - SQL has no sha256, so the trusted readers re-check the hash, parse, and check the reservation. - M6: the consume seals only a real deal, for this reservation. - New @pcc/spec `parseSealedDeal` checks: canonical bytes; the domain; exact keys; lowercase hex; at most 64 units, 16 per job, 16 legs per unit and 16 KiB per unit; the f/n arithmetic; legs == n; total == sum of g; jobId = planId:operator; milestones; stepId = keccak(node); a bijective binding; planHash == canonicalPlanHash. - The consume takes the request, currency, payers, obligation and lowest tier FROM THE DEAL. The input is now { reservationId, principal, dealDigest, dealPreimage }. - The gateway adapter throws when the store refuses the server's own compiled deal: a generic 500, never a 409. Tests: spec 909/909, db 222/222, and gateway R13 129/129. The new files typecheck. New tests cover every finding, including the reviewer's exact inputs: a MiB of 'y' with its hash, an invented unit with a forged operator/net/reclaim, 0004 then migrate then consume, and the skewed-clock interleaving. 39 mutation checks: 38 killed. The one survivor is EQUIVALENT: SD14 (the parser's one-job-per-operator check). Two jobs with one operator share a jobId, so their unit refs collide and the bijective binding check refuses the deal. The check is kept for its clearer diagnosis. A first-run survivor, ST6 (the sibling expiry sweep), was a TEST GAP: every sibling test shared a request. Siblings under two requests now kill it. pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… one transaction, refuses a reused id, and the parser enforces assurance structure (astra, round 2 of R13) astra's review of ac3db65 (pack 45) returned DO-NOT-SHIP. Every finding was REPRODUCED first at 45d0cde (the review loop): 12 new tests fail there and pass here. A (HIGH): issue() re-read the caller's maxAmountBaseUnits for validation, both ceilings and the insert, so astra's getter (1n three times, then 100n) passed with 1 and inserted 100 USDC. consume() also re-read reservationId through its final UPDATE: checks on the caller's reservation consumed SOMEONE ELSE'S (reproduced), and the stored bytes could differ from those hashed. Every field, the nested parent reference included, is now read ONCE into an owned, frozen copy. B (HIGH): ensureBudgetReservationsSchema inspected, counted, dropped and created with no transaction. A committed row landing between the count and the drop was lost (reproduced by interleaving a second connection). It now runs as ONE immediate transaction. Compatibility is a RECORDED version (pcc_schema_versions, written by the DDL itself), never SQL text, which had refused a correct, differently written table (reproduced). C (MEDIUM): with recursive triggers off, INSERT OR REPLACE reopened a consumed reservation, and a NULL id was accepted. Both were reproduced. The insert guard now refuses a reused id, and id is NOT NULL (schema version 2). D (MEDIUM): parseSealedDeal accepted tier 2 with no program, tier 0 with a program, and two distinct programs. The store then honoured a forged tier-2 deal under a floor-2 reservation (reproduced). The parser now refuses all three as "bad-assurance", mirroring the compiler (v2: at most one program; per job from accepted-deal v3). Migration 0004 is regenerated from the runtime DDL, statement for statement. Not in this commit: the compiler accepts reclaimAt above uint64, which the parser refuses (reproduced). The fix belongs to #351, which has a queued pack; today the mismatch is fail-closed at consume. Tests: db 231, spec 912, gateway 3056 passed. The capture suites do not load without a built @pcc/verifier dist. Mutations: 10 of 10 killed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…3-issue-route Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…nto feat/mc9-child-reservations Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
) #351 (59ee4ae, on master) holds an omitted quote to the gross floor: under an economics split, the legs to a node's own payout address must carry at least the net of its quote, and no quote means the whole gross. The three sealed-deal fixtures that use a split stated no quote, so on master they no longer compile (operator-below-quote). The lane's merge-order fold build found it: #402's own head passes 14/14, the fold fails 3. Each fixture now quotes exactly what its operator keeps: 9 of 10 USDC under the 10% royalty split (its net equals the operator's leg), and gross minus 15 under the 16-leg split. The assertions are unchanged; 14/14 both on this branch and on the fold with master's floor. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSBxBEX3sn9DPSqihyjuZE
…creates the table (#402, pack 92 MEDIUM) The exported BUDGET_RESERVATIONS_DDL (and migrations/0004, statement for statement) ran CREATE TABLE IF NOT EXISTS and then stamped version 2 unconditionally. Run directly against an existing older table, it left the table as it was but certified it as v2, and ensureBudgetReservationsSchema then trusted the false record (reproduced: the reviewer's 4 steps, and a v1 table with the same column names re-stamped from 1 to 2). The stamp now runs BEFORE the CREATE, and only when no budget_reservations table exists yet, so it is written only by the run that creates the table. An existing table, of any age, is never certified by the DDL; the guarded path alone decides about it. No table, column, index or trigger changes. Tests: both reproductions (the DDL and the 0004 file), the v1 re-stamp, and the record surviving a second run. db 235/235; 2/2 mutants killed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSBxBEX3sn9DPSqihyjuZE
#402, pack 252 MEDIUM) astra 252 (SHIP-WITH-FIXES; the fixture quotes are closed): the presence checks compared sqlite_master.name = 'budget_reservations' case-sensitively, while SQLite resolves table names case-insensitively. Reproduced first at 698de5b: a v1 table named Budget_Reservations, recorded as v1, was re-stamped to 2 by the DDL and by migration 0004, and ensureBudgetReservationsSchema neither refused nor rebuilt it. Every sqlite_master name check now uses COLLATE NOCASE: the DDL's guard, the same guard in 0004, and both lookups in the guarded path (the table and the version table). NOCASE folds ASCII letters, as SQLite's identifier resolution does. No table, column, index or trigger change. Tests: the case-variant re-stamp through both DDL forms, the guarded path refusing (rows) and rebuilding (empty) a case-variant table, and a case-variant version table read correctly. db 238/238; 4/4 mutants killed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSBxBEX3sn9DPSqihyjuZE
…/r13-budget-reservations (plain merge, no edits; retarget to master; fresh CI) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZpG7S6AyDzTEJBQH8up44
LamaSu
marked this pull request as ready for review
October 7, 2026 00:16
LamaSu
had a problem deploying
to
trusted-checks
October 7, 2026 00:17 — with
GitHub Actions
Failure
LamaSu
added a commit
that referenced
this pull request
Oct 7, 2026
…sue-route (plain merge, no edits) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZpG7S6AyDzTEJBQH8up44
LamaSu
added a commit
that referenced
this pull request
Oct 7, 2026
…at/mc9-child-reservations (plain merge, no edits) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZpG7S6AyDzTEJBQH8up44
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Current state (2026-10-06, pcc-composition)
feat/agent-plans-route), merged at ff71067.git merge-treeof the two (8cc5e013).COLLATE NOCASE.budget_reservationsDDL is approved (operator-queue item 26).scripts/ci/secret-scan.mjs: OK on--treeand on--range 2f5b21dc..head;pnpm build --concurrency=1,pnpm -r --no-bail test,pnpm -r exec tsc --noEmitand gateway'stypecheck:browser. The test step ran 54 packages with 0 failures: spec 3479/3479, store (db) 240/240, and gateway 5848 passed, 13 skipped, 3 todo.Round 3 (2026-09-29): astra's pack-45 findings (DO-NOT-SHIP on ac3db65), each REPRODUCED first, then fixed at 638bc3d
Under the review loop, the new tests were run at 45d0cde (byte-identical store and parser to ac3db65) BEFORE any change: store 9 failed, parser 3 failed.
pcc_schema_versions, v2), never SQL text.idis NOT NULL.INSERT OR REPLACEreopened a consumed row, and a NULL id was accepted.parseSealedDealenforces the compiler's assurance structure (bad-assurance).reclaimAtabove uint64 (reproduced) goes to feat(spec): accepted-plan compiler — composition half of MS-01 (R12) #351's next round. It is fail-closed at consume today.92-composition-r13-r3-6dadaf8b.md. Migration 0004 is regenerated from the runtime DDL.Schema change: approved under operator-queue item 26
(Historical note, kept as written before the approval:)
This PR adds the table
budget_reservations. Once merged and deployed, the gateway's runtime migration (migrateDatabase) creates it at startup. The design is operator decision #2240, amended by #2301 (payer, parent binding, a currency check on consume, the app-level digest recompute, an exact ceiling) and #2302 (min_tier). The steward recommends approve as amended. Nothing is applied until you merge and deploy. If you change the design, this draft changes with it.Round 2 (the operator's cross-family review, 2026-09-28)
The operator's ChatGPT review of #402/#410/#415 at
0b8adda9was DO-NOT-SHIP (H1, H2, H3, M4, M5, M6). This PR fixes the store side of every finding except M4 (that one's #410's); the routes follow in #410 and #415.issuenow takesparent: { reservationId, unit }only. Inside itsBEGIN IMMEDIATEtransaction it reads the consumed parent, re-checkssha256(stored deal) == stored digest, parses the deal strictly and requires it to be that reservation's deal, then finds the exact unit and derives its operator, netnandreclaimAt. The identity checks come first, so a non-operator only ever sees the not-found family. A child also fits its own request's ceiling.now. Before an issue frees an expired reservation's share, it moves that reservation issued → expired in the same transaction, in both the request scope and the sibling scope. A consume that finds an expiry records it; consume requiresissued. Tested on two connections, in both orders, and for siblings.0004_budget_reservations.sqlisBUDGET_RESERVATIONS_DDL, statement for statement (test-asserted).migrateDatabaserunsensureBudgetReservationsSchema, which rebuilds an EMPTY table of another shape and refuses to boot on one that holds rows. Test: 0004, then the runtime migration, then a real consume.consumed ⇔ digest ⇔ deal ⇔ consumed_at;created < expires; integer times and tier. Triggers: inserts only as issued, and a child only under a consumed parent; updates only issued → consumed | expired | released, with no term changed; no DELETE. SQL has no sha256, so the trusted readers re-check the hash, parse, and check the reservation.@pcc/specparseSealedDealchecks: canonical bytes; the domain; exact keys; lowercase hex; at most 64 units, 16 per job, 16 legs per unit and 16 KiB per unit; the f/n arithmetic; legs == n; total == sum of g;jobId = planId:operator; milestones;stepId = keccak(node); a bijective binding;planHash == canonicalPlanHash. The consume takes the request, currency, payers, obligation and lowest tier FROM THE DEAL — the input is now{ reservationId, principal, dealDigest, dealPreimage }. The gateway adapter throws when the store refuses the server's own compiled deal: a generic 500, never a 409.The sealed deal itself (amendment #3231, steward condition #3235).
budget_reservationsgainsconsumed_deal_json, written in the same transaction as the digest (450b575). The stored bytes areacceptedDealDigest's own canonical PREIMAGE, and consume refuses unlesssha256(bytes) == digest(deal-preimage-mismatch). SQL has no sha256, so the table cannot check the hash itself; its CHECKs hold presence and size. The bytes are never on the reservation object — only server-sidesealedDealPreimage(id)reads them, for MC 9's parent terms, funding and VCR delivery — and are capped at 1 MiB, enforced by both the store and a table CHECK. The gateway adapter (af14e2a) recomputes the digest assha256of #351'sacceptedDealPreimage(plan)and hands the store both the digest and the preimage bytes; the store re-checks that they hash to each other before keeping the bytes as the sealed deal.Tests: spec 909/909, db 222/222, gateway R13 129/129. The new files typecheck. New tests cover every finding, including the reviewer's exact inputs: a MiB of
ywith its hash, an invented unit with a forged operator/net/reclaim,0004then migrate then consume, and the skewed-clock interleaving. 39 mutation checks: 38 killed. The one survivor is EQUIVALENT — SD14, the parser's one-job-per-operator check: two jobs with one operator share a jobId, so their unit refs collide and the bijective binding check refuses the deal; it's kept for its clearer diagnosis. A first-run survivor, ST6 (the sibling expiry sweep), was a TEST GAP: every sibling test shared a request; siblings under two requests now kill it.Round-2 pack:
45-composition-r13-402-410-415-r2-ac3db658.md(covers #402, #410 and #415).Known cost of the stack: until #351 → #355 → #356 → #357 → #391 merges up, #402's diff against #391 temporarily includes #351's 9d7686a.
Was stacked on #391 (the R9 route) → #357 → #356 → #355 → #351; all of them are on master now. Reconciliation row R13 (Gate B keystone; MUST-CLOSE 7 and 8). Retarget the stack to master before merge (rule 4).
What it does
@pcc/store:BudgetReservationStore(packages/db/src/repositories/budget-reservations.ts). It is self-contained over the raw SQLite handle; the sharedIRepositoriesaggregate is untouched.numeric(78,0), so amounts are canonical decimal TEXT and compared asBigIntin code, never in SQL and never as a float. A test with values around 2^200 would fail under float rounding.issue, in ONEBEGIN IMMEDIATEtransaction:issuetakesparent: { reservationId, unit }only — never caller-supplied terms. Inside the transaction it re-reads the consumed parent, re-checks its sealed-deal digest, and derives the unit's operator, netnandreclaimAtfrom THAT deal. The parent must be consumed and in the same currency. All children of one unit fit its net n, none outlives its reclaimAt, and the child inherits max(parent's floor, its own) — and now also fits its own request's ceiling.consume, in ONEBEGIN IMMEDIATEtransaction (round 2, M6): takes{ reservationId, principal, dealDigest, dealPreimage }— never a caller-supplied payer or obligation.parseSealedDeal(new@pcc/spec, a strict total parser of the accepted-deal preimage) checks the deal's canonical bytes, domain, exact keys, and unit/leg/size bounds, and the request, currency, every job's payer, the obligation and the lowest tier all come FROM THE DEAL. The store still re-checks principal, issued-and-unexpired and floor against the stored row, then seals the deal digest: the UPDATE is conditional onstate = 'issued', and exactly one row must change.CHECK): canonical digits only (1–78, no leading zero), the known states,consumed ⇔ digest present,min_tierin 0..3, and both halves of a parent binding or neither — extended in round 2 (M5) withcreated < expires, integer times/tier, and insert/update/no-DELETE triggers (see above).Gateway:
services/reservation-store.tsimplements the trace stand-in's consume PROTOCOL, made durable.loadReservationfeeds the seam.consumeReservationfeeds the route. Before touching the store it refuses a plan it did not compile:wrong-binding);acceptedDealPreimage(digest-mismatch, the feat(spec): accepted-plan compiler — composition half of MS-01 (R12) #351 consumer contract);obligation-mismatch).invalid-deal,wrong-reservation, a preimage mismatch or invalid input), the adapter throws. That is a generic 500, never a client-facing 409.Tests
@pcc/store: 13 tests against real SQLite.createStoreruns the DDL idempotently.The db package's full suite passes with the new migration.
Gateway: 5 tests.
loadReservationmapping.Mutation checks, 20: 18 killed, 2 survivors explained.
Store (14): 12 killed.
The 2 survivors are layered concurrency defenses that single-threaded tests cannot tell apart:
BEGIN IMMEDIATEvs deferred. Under a deferred transaction, SQLite's snapshot isolation makes a racing read-then-write fail with SQLITE_BUSY rather than double-consume.state = 'issued'guard, which is redundant under the immediate lock.Each is kept as defence in depth.
Adapter (6): all killed. The per-job payer survivor led to the one-job-of-several test.
(These are round-1 counts, scoped to what round 1 added. Round 2's own numbers — spec 909/909, db 222/222, gateway R13 129/129, 39 mutation checks/38 killed — are in the Round 2 section above and supersede these as the head's totals.)
Self-review fixes (e6975e4), before the cross-family round
Issue and read routes: #410, stacked on this PR.
Cross-family status: round 1 was DO-NOT-SHIP at
0b8adda9(see Round 2 above, which fixes it). Round 2 goes through the operator's ChatGPT review as pack45-composition-r13-402-410-415-r2-ac3db658.md.Not in this PR
pcc-composition 8a0f4de0, goal pcc-reconciliation.
🤖 Generated with Claude Code
https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz