Skip to content

DRAFT: feat(compose): per-leg escrow settlement wire for executeComposition (Lane 2) - #237

Draft
LamaSu wants to merge 1 commit into
masterfrom
feat/compose-perleg-escrow
Draft

DRAFT: feat(compose): per-leg escrow settlement wire for executeComposition (Lane 2)#237
LamaSu wants to merge 1 commit into
masterfrom
feat/compose-perleg-escrow

Conversation

@LamaSu

@LamaSu LamaSu commented Jul 10, 2026

Copy link
Copy Markdown
Owner

DO NOT MERGE — needs owner sign-off on the escrow-shape decision

This wires money movement into compose execution. The escrow-shape ADR (local: ai/research/industry-pain-points/lane2-escrow-shape-ADR.md — ai/ is gitignored by repo convention) must be signed off first.

The gap this closes

executeComposition walks the composed DAG and records per-step reputation but creates ZERO settlement objects — a 3-operator composition settles nobody (the code's own comment names the missing piece: "paid-job-flow + Lane 2 settlement").

ADR decision (PROPOSED): Option A

One MilestoneEscrowV3 per composition, one milestone per composed leg, each leg released independently on ITS OWN evidence (oracle-attested Mode-B; Mode-A is removed per settlement-decisions.md D1-D3).

Why not Option B (single milestone + Payout[] map, all-or-nothing):

  • MAX_SINGLE_BPS = 5000 makes any leg worth >50% of the composition inexpressible.
  • The payout map is bps-of-post-fee-distributable with operator-residual semantics — built for intra-leg role attribution (ADR-11 contributor economics), not inter-leg operator payment.
  • One milestone = one evidence hash + one attestation: per-leg verifiability and the per-leg dispute/reclaim surface collapse to all-or-nothing, contradicting executeComposition's short-circuit semantics (completed legs stay credited).
  • NOTE: the splitPayout primitive is already on master (V1/V2/V3) — no cherry-pick from feat/contributor-economics needed; it composes WITH Option A (any single leg may carry a map).

What's in the draft

  • packages/gateway/src/services/compose-settlement.ts (new): planCompositionLegs (pure leg→milestone mapping; per-leg stepId = keccak256("{compositionId}:{stepIndex}")" + per-leg jobId → C2b + jobIdHash cross-leg replay guards; skips graph-search ""operators + zero-price legs with reasons),createCompositionEscrow(mock + real V3: createEscrowV3 → addMilestone per leg with the LEG's operator as payout recipient → approve → fund upfront; mirrors createJobFromSession's ceremony incl. withSignerLock + receipt-confirmed writes),settleCompositionLeg` (per-leg submitEvidenceV3; attestation + release ride the existing oracle path with the leg's milestoneIndex).
  • packages/gateway/src/routes/compose.ts: PCC_COMPOSE_SETTLEMENT-gated pre-loop escrow phase in executeCompositionfail-closed (escrow create failure ⇒ zero steps run); settlement summary on CompositionExecutionResult (HTTP response + spec shapes untouched).
  • packages/contracts/test/MilestoneEscrowV3.composition.t.sol (new, 6 tests): per-leg independent release; C2b cross-leg stepId revert; per-leg jobId binding revert; C1 UID replay across legs revert; short-circuit → reclaimAfterDeadline refunds only the stranded leg; intra-leg splitPayout distribution inside a composition escrow.
  • packages/gateway/src/__tests__/compose-settlement.test.ts (new, 8 tests): planner mapping/skips/clamps, mock escrow row (version: "v3"), integration, fail-closed, flag-off regression guard.

Test evidence (run on DGX Spark)

  • forge: composition suite 6/6, existing MilestoneEscrowV3Test 22/22 (no regression)
  • gateway: tsc clean; vitest 36/36 (8 new + 28 existing compose tests)

Flagged dependencies

  1. Completion signal: "credit at completion not ack" (__pccStep = {compositionId, stepIndex} job tagging + async completion settle) lives on feat/composition-preflight-gate, NOT master. This draft wires against that intended signal; until it lands, settleCompositionLeg is the exported integration point and nothing auto-invokes per-leg release.
  2. Owner sign-off on the escrow shape (this PR must not merge before that).
  3. Follow-ons noted in the ADR: extend driveSettlement crank to V3 dispatch; async escrow-create ceremony (compose-execute becomes chain-latency-bound when enabled); requester-identity wiring for the escrow row's payer field; operator resolution for graph-search legs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ti8XbczbzSquGXzquvAgjp

…ition (Lane 2)

DRAFT + PROPOSE — do not merge without owner sign-off on the escrow-shape
ADR (ai/research/industry-pain-points/lane2-escrow-shape-ADR.md): this
wires money movement.

Option A per the ADR: ONE MilestoneEscrowV3 per composition, ONE milestone
per composed leg (the leg's operator is that milestone's payout recipient),
each leg released independently on ITS OWN evidence via the oracle-attested
Mode-B path. Fail-closed: if the composition's pay cannot be escrowed, no
step executes.

- services/compose-settlement.ts: planCompositionLegs (pure leg->milestone
  mapping w/ per-leg stepId/jobId replay-guard bindings; skips
  graph-search '' operators + zero-price legs), createCompositionEscrow
  (mock + real V3 create/addMilestone-per-leg/approve/fund, mirroring
  createJobFromSession's ceremony), settleCompositionLeg (per-leg evidence
  submit; attestation+release ride the existing oracle machinery).
- routes/compose.ts: executeComposition gains a PCC_COMPOSE_SETTLEMENT-gated
  pre-loop escrow phase + settlement summary on CompositionExecutionResult.
  HTTP response shape untouched.
- __tests__/compose-settlement.test.ts: planner mapping/skips, mock escrow
  row (version v3), fail-closed integration, flag-off regression guard.
- contracts/test/MilestoneEscrowV3.composition.t.sol: composition-shaped
  forge tests — per-leg independent release, C2b cross-leg stepId, per-leg
  jobId binding, C1 UID replay across legs, short-circuit reclaim of
  stranded legs, intra-leg splitPayout attribution.

FLAGGED deps: completion signal (__pccStep) lives on
feat/composition-preflight-gate (not master); splitPayout primitive already
ON master (no cherry-pick needed); owner sign-off on ADR required.

Agent: implementer-perleg-escrow
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ti8XbczbzSquGXzquvAgjp
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.

1 participant