Repository navigation
feat(gateway): MC 9 bounded child authority — a composite operator carves a child reservation from one sealed unit (503 until the sealed deal is stored) - #415
Draft
LamaSu wants to merge 8 commits into
Conversation
…erator carves a child reservation from a sealed unit POST /api/settlement/reservations/:parentId/children lets the operator of ONE unit of a SEALED parent deal subcontract part of it (#2301). The store (#402) enforces every bound in one immediate transaction; the route answers first where that closes an oracle. - Only the parent unit's operator may carve a child. Anyone else gets the byte-identical missing-parent 404, BEFORE any other answer. A test caught an earlier version that leaked request-not-found for a real parent. - The child is funded by the operator's own wallet, never the parent payer's. All children of a unit fit its net n and none outlives its reclaimAt. The floor is max(parent's, own). The child's own request must be the operator's, in the reservation's currency. An unsealed parent is 409. - The parent unit's terms come from an injected ParentUnitResolver. Nothing persists the sealed deal today, so production answers 503. The proposed consumed_deal_json amendment to #2240 is in the PR body. Tests: 3 new (7 in the file), including end to end on one durable store: payer's deal sealed, the operator carves a child, a subcontracted child plan is accepted against it. Full gateway suite: 3061 passed, 6 skipped; only the known capture suites fail to load. 6 mutation checks, all killed. 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
…rable store (PCC_HTTP_TRACE_OUT) When PCC_HTTP_TRACE_OUT is set, the MC 9 end-to-end test writes the whole exchange as JSON: 1. the payer issues; 2. the parent deal is sealed; 3. the operator carves a child; 4. the child plan is accepted (digest, payer, obligation, deal bindings, seal, presentation state); 5. both reservations are read back. The composition return cites it as the HTTP-level end-to-end trace, next to the pure-level one. Nothing changes when the variable is unset. 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
…l (amendment #3231) services/sealed-deal-parent-units.ts derives a parent unit's terms from the bytes the R13 store keeps. Those bytes are the accepted deal's canonical preimage, which hash to the sealed digest. The terms are the job's operator, the unit's exact net n and its reclaimAt. Nothing comes from the caller: the reservation id and unit reference are lookup keys. An unknown unit, an unsealed parent, unreadable bytes or a non-canonical amount are null (fail closed; BigInt alone would accept hex and padded digits). The MC 9 tests now use this REAL resolver instead of a stand-in. An unsealed parent therefore has no sealed deal and gets the same 404 as a missing one; the store's own not-consumed check remains as defence in depth. Tests: route file 8/8 (1 new resolver test). Full gateway suite: 3062 passed, 6 skipped; only the known capture suites fail to load. db 208/208. 4 mutation checks: 3 killed, 1 equivalent (reading an unsealed reservation's absent bytes as an empty deal is still null; the store's state filter is what guards it, and the db tests pin that). 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
…mc9-child-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
…h the child route on the new store API (H1) This merge carries the R13 round-2 store (45d0cde) and issue route (bbe03e3). The store's API changed, so the MC 9 child route changes with it, here in the merge. That change is the ChatGPT review's H1 over HTTP. - The route names only `{ reservationId, unit }`. The STORE derives the unit's operator, n and reclaimAt from the parent's sealed deal, inside its immediate transaction, after checking the stored bytes against the sealed digest. - The route-side resolver (services/sealed-deal-parent-units.ts) is deleted, and so is its `parentUnits` option. Production's 503 now depends only on the issue wiring. - No oracle. - The whole not-found family is the SAME 404: no parent, parent not sealed, no such unit, not the unit's operator, and a corrupt stored deal (which is also logged as an integrity fault). - An unsealed parent was a 409; it is now that same 404. - The caller's OWN request is checked first. It says nothing about the parent. - The child's own request terms apply: its ceiling (it was 0) and its floor. The child's floor is max(request's, body's, parent's). - The conflict resolution in reservations-route.test.ts: the request table takes the new terms shape (ceiling and floor), with the operator's subcontract requests; the wiring keeps the operator's own payer wallet. Tests: gateway R13 139/139, reservations-route 10/10. There are new tests for: another operator's unit; forged body terms ignored; the child's own ceiling; the child's floor; a corrupt stored deal giving the same 404. 5 route mutation checks, all killed: a corrupt deal answers 500; an unsealed parent is 409; the child ceiling is 0; the child skips its own ceiling; the child floor comes from the body only. pcc-composition 8a0f4de0, goal pcc-reconciliation. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 29, 2026
Draft
…nto feat/mc9-child-reservations Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…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
LamaSu
had a problem deploying
to
trusted-checks
October 7, 2026 00:22 — with
GitHub Actions
Failure
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.
Round 3 (2026-09-29): merges #402's fixes for astra's pack-45 findings
This head merges #402 @638bc3dc (A, B, C, D, each reproduced first). The R13 delta pack is
92-composition-r13-r3-6dadaf8b.md, and the full tests pass at #415's head 6dadaf8.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 merge carries #410's round-2 route (bbe03e3) into this branch and updates the child route for #402's changed store API — that's H1 over HTTP:{ reservationId, unit }. The STORE derives the unit's operator,nandreclaimAtfrom the parent's sealed deal, inside its own immediate transaction, after checking the stored bytes against the sealed digest.services/sealed-deal-parent-units.ts) is deleted, and so is itsparentUnitsoption. Production's 503 now depends only on the issue wiring (feat(gateway): R13 reservation ISSUE + READ routes — server terms only, exact money; 503 until store, exact ceiling and payer binding exist #410).reservations-route.test.ts: the request table takes the new terms shape (ceiling and floor), with the operator's subcontract requests; the wiring keeps the operator's own payer wallet.Tests: gateway R13 139/139, reservations-route 10/10. New tests cover: another operator's unit; forged body terms ignored; the child's own ceiling; the child's floor; a corrupt stored deal giving the same 404. 5 route mutation checks, all killed: a corrupt deal answers 500; an unsealed parent is 409; the child ceiling is 0; the child skips its own ceiling; the child floor comes from the body only.
Round-2 pack:
45-composition-r13-402-410-415-r2-ac3db658.md(covers #402, #410 and #415).Draft, stacked on #410 (R13 issue and read routes) → #402 (the R13 store). MUST-CLOSE 9: bounded child authority (#2301), over HTTP.
What it does
POST /api/settlement/reservations/:parentId/childrenlets a composite operator subcontract part of a unit it was paid for. The child reservation is carved from ONE unit of a SEALED parent deal. The body is{unit: "<jobId>#<milestoneIndex>", requestId, currency, maxAmountBaseUnits, purpose, expiresInSec, minTier?}.Authority, all enforced by the store in one immediate transaction (#402), with the route answering first where that avoids an oracle:
request-not-foundfor a real parent.payerFor), never the parent payer's.A failed child cannot mark the parent fulfilled. The parent unit releases only on its own tier evidence, and VCR's
requires(#2674, emitted by #391) gates release order.Where the sealed deal lives (resolved in round 2)
The store keeps the sealed deal.
budget_reservations.consumed_deal_jsonholds the compiled plan asacceptedDealDigest's own canonical preimage, written in the same consume transaction (amendment #3231, #402 450b575/@af14e2ad; steward condition #3235). The route-sideParentUnitResolverthis section used to describe is gone:services/sealed-deal-parent-units.tsand itsparentUnitsoption are deleted, in this PR (ac3db65). The STORE itself now derives the parent unit's terms — operator,n,reclaimAt— from that stored deal, inside its own immediate transaction, after checking the stored bytes against the sealed digest (#402 @45d0cde3, H1). Production's 503 now depends only on the issue wiring (#410), not on any resolver here.Tests (
reservations-route.test.ts, +3; 7 in total)End to end on one durable store:
Bounds: n exact to one base unit, across children; reclaimAt exact (at it is fine, one second over is 422); the parent payer's wallet is refused; an unsealed parent is the same 404 as a missing one (round 2; was 409 before ac3db65); the child request must be the operator's own and in the reservation's currency.
No oracle: another principal, a missing parent and an unknown unit give the byte-identical 404. Malformed unit references are 400. Production is 503.
Mutation checks, 6: all killed. The C8 survivor led to the request-currency case.
(Round 1 counts. Round 2's own numbers — gateway R13 139/139, reservations-route 10/10, 5 mutation checks all killed — are in the Round 2 section above.)
pcc-composition 8a0f4de0, goal pcc-reconciliation.
🤖 Generated with Claude Code
https://claude.ai/code/session_0171FftEAfqjwbJHowVTqAbz