Conversation
…o refund-as-payment)
statusClass() used a greedy substring regex that rendered any status containing
settl/releas/complet/done/paid/funded/success/approved/active as a green "settled"
pill. So a REFUND ("refunded" contains "funded"), an UNRELEASED/INCOMPLETE/UNSUCCESSFUL/
NOT_APPROVED/INACTIVE/UNDERFUNDED, and every *_ALLOCATED (decided, not final) rendered as
a completed PAYMENT. A refund shown as a payment is the read-route contract's forbidden-
asserter CRITICAL, live in the shipped on-ramp kit.
Replace it with an EXACT normalized-status map keyed off the sec-A conformance table
(V-next finalState/unitState, the 10-state machine) plus the legacy EscrowSummaryDTO enum:
- SETTLED_RELEASED / COMPLETED -> st-settled (operator distribution discharged)
- SETTLED_REFUNDED / REFUNDED -> new non-green st-refunded ("payer refunded - operator NOT paid")
- RELEASE_ALLOCATED / REFUND_ALLOCATED / in-flight (0-5) / FUNDED / CREATED -> st-waiting
- unmapped / unknown -> new neutral st-unknown, NEVER green (fail closed)
No substring inference for money state. Add honest sec-A direction labels on the settlement
rail, and drop the dishonest rail fallback that inferred 'settled' from releasedCount
(contract rule 12: never key settlement off count/receipt existence).
Adversarial conformance test extracts the shipped <status-map v1> region verbatim (tests the
real bytes, not a copy) and asserts the sec-A table, the never-green invariant, normalization
(casing/whitespace/separators), generic-state tones, and that the old regex is gone. 7/7 green.
Refs: genui-read-route-contract sec-A + rules 1/12; genui conformance matrix v1.4.
Cross-family (sol/GPT-5.6) verdict: the one-line /refund/ guard is insufficient; this is the
exact-map it prescribed. gen-UI owns the fix (defect is in gen-UI's shipped kit + contract).
…d/dispute as green) EscrowPage.tsx rendered the escrow status GlowBadge with `... : "green"` as the ternary DEFAULT, so any status other than active/funded -- refunded, disputed, created, unknown -- rendered GREEN: a refunded or disputed escrow shown as a completed payment. Same false-green money-display bug as the ui-kit statusClass fix, in a parallel formatter (the blast radius sol predicted: "fixing one helper doesn't help if dashboards independently infer status"). Replace with an exact map defaulting to gray: completed -> green, disputed -> red, active -> gold, everything else (funded/created/refunded/unknown) -> gray. Matches the already-honest MilestoneTimeline statusColors + read-route contract rule 1. Type-correct by inspection (all branches return valid GlowBadge colors: green|gold|red|gray); a full dashboard typecheck/build is Spark-offload territory and was NOT run here.
Bring PR #313 current with master before extending it (dry-run merge-tree was clean; no conflicts). No force-push: the PR history is preserved. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…state table
Master had five competing escrow-status vocabularies (EscrowStatus,
Escrow.status, the dashboard DTO, the V-next UnitState, the context-pack
summary) and every surface re-inferred them; the shipped kit's substring regex
rendered a REFUND as a green completed payment (read-route contract rule 1).
MONEY_STATUS_MAP is the ONE exact table: normalized key -> semantic tone +
honest, direction-explicit label. Green ('settled') is reserved for the three
documented FINAL releases to the operator (SETTLED_RELEASED, COMPLETED,
RELEASED). Refunds are 'refunded' (final, operator NOT paid); allocated-not-
final states are 'waiting'; unknown fails closed. Bare SETTLED is deliberately
unmapped: SettlementResultDTO uses it for operator-paid but the V-next phase
vocabulary uses it for BOTH released and refunded.
Frozen at every level; compile-time coverage records make tsc fail if
EscrowStatus / Escrow.status gains a value with no entry. Browser-safe.
8 tests (sec-A table, never-green invariant, unknown fail-closed,
normalization, full vocabulary coverage, immutability).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…ifier - <status-map v2> mirrors @pcc/spec MONEY_STATUS_MAP verbatim (the vanilla kit cannot import it) and now covers every documented escrow vocabulary, so canonical states like released/slashed/releasing/expired no longer render 'unknown'. - New moneyStatusClass for MONEY surfaces (the receipt window): money table only. An off-schema 'success'/'done'/'ok' on a money response is NOT a settlement state and never renders paid (it still tones a generic run/list surface via statusClass). - Conformance test moved into CI: #313's node --test file lived under apps/dashboard/public/ (served publicly) and no CI job ran it. The new vitest file (a) extracts the shipped region verbatim and proves it equals the spec map key for key and agrees with classifyMoneyStatus over an adversarial battery, and (b) boots the WHOLE kit in jsdom and asserts the rendered receipt pill: refund / allocation / off-schema success / missing status (rule 12) are never settled-green. 19 tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
EscrowPage's escrow badge had its own inline ternary (a sixth formatter). It now calls moneyBadgeColor(), which takes the semantic tone from @pcc/spec classifyMoneyStatus and only maps tone -> GlowBadge color: green is reserved for a documented FINAL release; refunded / allocated / unknown are never green. GlowBadge itself defaults to green, so money badges must pass an explicit color. A compile-time record lists every value of the dashboard's EscrowStatus type (tsc fails if the type gains one) and the test asserts each is a KNOWN state in the canonical map, so no real escrow status renders 'unknown'. 3 tests; dashboard tsc --noEmit clean; full dashboard suite 223/223. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
This was referenced Sep 24, 2026
Open
…id; route data surfaces by data First part of the #313 review fixes (astra via coord-watch #2465, product-qa #2594, reviewer-bravo): - Normalization rejects rather than erases: only a plain status string ([A-Za-z0-9 _-]) is classified. "RELEASED?", "❌RELEASED", "releaſed", ["RELEASED"] and objects whose toString returns a green word are now unknown. Spec and kit mirror are changed together. - COMPLETED is no longer green. It ends many non-money DTOs (jobs, A2A, steps, batch claims where paid != completed), so it now reads "completed - settlement not confirmed". - List rows and run status pick their table from the DATA: money unless the binding is a known non-money read and the row carries no money field. So an escrow row's "success" or "done" is never green, while a completed job still is. Generic surfaces check generic states first. - The EscrowPage milestone badge now comes from the canonical map (no dead "fulfilled" green). Tests: money-status 35/35 (+8); full spec 832/832; dashboard 223/223; the 7 gateway kit suites 95/95; tsc (spec, dashboard) clean. More #313 fixes follow (source-schema receipt adapter). agent: pcc-genui (4df1e691) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…el; no bare-word green Second part of the #313 review fixes: steward rulings #2490/#2688, astra (coord-watch #2465), escrow #2580, product-qa #2594. - Classify by SOURCE SCHEMA: classifySettlementRecord (spec) / settlementRecordClass (kit mirror): - V-next /lifecycle: unitState is an ordinal 1..9, pinned to VNextSettlementLib.sol's `enum UnitState`; 0 is a read error. finalState, isAllocated and isTerminal must agree, and a final state needs all three present. - V-next /receipt: finalState counts only when terminal with isAllocated true. `null` + allocated reads "decided, not yet paid out". - A legacy escrow record goes through the flat table on its status. - Anything else (a job, an A2A task) is "not a settlement record". - The flat word table has NO green entry: bare SETTLED_RELEASED, RELEASED and COMPLETED are not settlement reads. The only green is a consistent V-next state 8. AWAITING_FUNDING is unknown. Labels are fixed per escrow F4-F6: "not final", "payer not yet refunded", "payout distribution discharged", "payees NOT paid". - Receipt: state by schema; nothing invented (no default "USDC", "payer"/"payee" or "escrow-milestone"; missing values read "not reported"). - Run window: a read model by its schema; a full snapshot with no status reads unknown (an earlier green is never kept). List/run money rows that are read models use the schema. - The kit tables are frozen. Compile-time coverage now constrains the real map (`satisfies`). - EscrowPage: the "Total Locked" and selected-escrow panels no longer glow green. Tests: money-status 18 + conformance 37 = 55. They cover wire fixtures for states 0-9, every cross-check disagreement, missing corroboration, receipt shapes, job/A2A records, the kit==spec adapter over the battery, the ordinal table re-read from the Solidity enum, frozen tables, no-invention, run null snapshot, and money rows. Full spec 852/852; dashboard 223/223 (after a spec build); gateway kit suites 95/95; tsc spec + dashboard clean. agent: pcc-genui (4df1e691) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…rrency Pins the no-invention rule for the currency line (the earlier test used a receipt with no amount, so the currency branch never ran; mutation M8 survived). M8 is now red. agent: pcc-genui (4df1e691) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
…els-job-execution Brings PX-1's fixed money-status map into PX-6 (steward #2688, genui #2743): bare status words are never green, 'completed' is never paid, and settlement tone comes only from classifySettlementRecord. The merge applies cleanly. Under the new map a milestone record's 'released' is no longer a settled tone, so the next commit adapts the payout axis (5 settlement-axis tests fail at this merge commit alone). agent: pcc-readmodels (c255d7dc)
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
…_released, never paid #313's fixed map (merged in the previous commit) makes every bare status word a non-green tone, following steward ruling #2490: settlement tone comes only from authoritative money state. A milestone record's "released" is now a waiting tone, so reconciling by tone would have reported a recorded release as "not_paid": a false statement. The payout now reads the gateway's escrow words exactly (their source schema is the escrow_milestones and escrows tables): - a released milestone (released, settled_released) that the escrow record does not contradict is the new payout state reported_released, with payoutConfirmation record_only. It is gray and says it is not confirmed. On a V-next escrow "released" can mean the outcome was allocated, not paid out. - "paid" is reserved for an authoritative settlement read model (a V-next lifecycle or receipt that classifySettlementRecord shows as released). The gateway's escrow records never produce it; a test sweeps every word pair of the money map to prove that. - a milestone saying "completed" is ambiguous (completion is not release): unknown. - conflicts are unchanged: released vs a refunded, disputed or slashed escrow, and refunded or unreleased vs an escrow saying everything was released, are unknown. This also answers coord-watch's open question on #353 (can payout be "paid" when this job's money was not released?): no gateway record can make it "paid" now. Gateway 3042 passed / 6 skipped / 0 failed; spec 861; dashboard 249, tsc -b clean. Mutation check on the new rule: 5/5 killed. agent: pcc-readmodels (c255d7dc)
This was referenced Sep 24, 2026
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
…sign #3013) A job row can literally say "settled" with nothing paid (#353's notice job_row_reports_settled), so the Run card could read "Status: settled", and a job list badge or a status metric likewise. Colour was already neutral; the text was not. Any value read from a field named `status` (status, job.status, kernel.status) whose word is a money state now carries PCC's fixed qualifier "- reported by the record, not confirmed by a settlement read" (the #313 wording), in every sink: metric (bindScalar), run card (bindSchemaCard), list badge and list meta (bindListRows). The money-state word list is narrower than the prose CLAIM_RE ("verified"/"approved" are not money states); lookalikes, zero-width, fullwidth and camel/snake/kebab joins are folded first. The kit is rebuilt (check:ir-kit). Tests: 4 new, including the shipped kit end to end (review344 19/19). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…ocated/phase semantics #313's classifier assumed isAllocated was true for every allocated-or-final state (6-9). The read routes say otherwise: gateway unit-state-mapper isAllocatedState is true for 6/7 ONLY ("outcome decided, money NOT fully moved"), so a settled /lifecycle or /receipt body carries isAllocated:false. A genuinely settled unit therefore rendered "settlement fields disagree" and was never shown as settled -- fail-closed, but wrong, and the hand-written test fixtures encoded the same assumption (one even pinned the real settled receipt as unknown). Now, in the spec classifier and the kit mirror alike: - lifecycle: allocated = state 6 or 7; `phase` must match VNEXT_PHASE (the mapper's PHASE_BY_STATE) when present, and a final state needs finalState, isAllocated, isTerminal AND phase; - receipt (finalState, phase, isAllocated): final only with isAllocated:false and phase:"settled" (both present); isTerminal, if present, must agree; "allocated" and "in flight" cross-check phase too. A new gateway suite takes its fixtures from the routes themselves (Fastify inject over a fake reader) for states 1-9 and classifies every body with the spec AND the shipped kit: only state 8 is green, from either route, and each tampered field is unknown. Tests: money-status 18 + conformance 39; spec 854/854; dashboard 223/223; new gateway suite 3/3. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
…the v1.5 design contract The preserved v1.5 contract describes the design DTO, but master's routes were built to it through escrow's DTO mapping (#667), which differs: finalState is null (never *_ALLOCATED) for states 1-7, isAllocated is true for 6/7 only (a settled body says false), phase is emitted, receipts answer 200 for states 1-5, state 0 is a 503, and several design fields are not emitted yet. Nothing said so, and #313's classifier was built on the wrong assumption (settled units never went green; fixed in #313 @7061730a). Adds an "Implemented on master" section (verified against settlement-read.ts and unit-state-mapper.ts at ac86a40) with the consumer rule for settled-green, and a pointer on the golden matrix. The design text is unchanged; the golden-vs-implementation choice is left to the route owners. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
…lay sum
The receipt window fell back to economics.amount and formatted it with fmtUsd. On the
real /receipt route that field is a raw integer in the token's BASE units (read-surface
contract rule 14) and the route sends no tokenDecimals, so a 1 USDC settlement
("1000000") would have rendered as 1,000,000.00.
Now economics.amount becomes a display amount only with the record's own tokenDecimals
(exact string arithmetic, no float); otherwise it is shown as "N base units (decimals
not reported)", with no invented currency. A malformed value is "amount not reported".
Top-level amount/totalAmount (legacy escrow records, already display units) are unchanged.
Tests: 3 new (conformance 42/42) using the route's exact EconomicsRecord shape.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
Genui #3113 / #3151. 7061730 classifies settlement reads by the routes' own isAllocated / phase semantics (isAllocated is true for states 6/7 only, so a settled unit no longer reads as "fields disagree"), and de3a973 stops the ui-kit receipt window formatting economics.amount (base units) as a sum. No conflicts. JobExecutionDTO shows no economics.amount: its milestone.amount and escrowTotal.amount are the escrow record's decimal strings, labelled as recorded. agent: pcc-readmodels (c255d7dc)
… it (escrow ruling #3163) Escrow ruled that master's settlement routes are the target and asked gateway to ADD the staticcall-authoritative unitState to /receipt (additive), so a receipt consumer can tell 6 (release decided) from 7 (refund decided); genui keys that direction off unitState, never off finalState. A receipt with unitState enters the unitState branch, which required isTerminal for a final state, and /receipt carries no isTerminal, so settled receipts would have classified "incomplete" the day the field lands. A final state now needs unitState, finalState, isAllocated and phase (every present field still cross-checked, isTerminal included when present). Spec and kit alike. Tests: the route-derived suite classifies each state's real /receipt plus the lifecycle's unitState (states 1-9: same tones as /lifecycle, green only at 8, 6 vs 7 named) and four tampers of it (4/4); money-status 60/60. Requiring isTerminal again turns it red. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
… ruling #3163) Escrow, the money-semantics owner for /receipt and /lifecycle, ruled that the target is master's routes. §A of the conformance matrix now says so, row by row: - 200 for states 1-9; 503 for state 0; 404 only for an unknown (or foreign) unit; - finalState only for 8/9; isAllocated true for 6/7 only; - #313's presentation labels, with 8 the only green. The superseded #667 rows (404 for 1-5, finalState *_ALLOCATED for 6/7) are named as such. The contract's open question is marked resolved, with the one additive gateway change (unitState on /receipt) and the consumer rule (6 vs 7 from unitState, never finalState). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
Genui #3217: per escrow ruling #3163 the gateway will add unitState to /receipt; classifySettlementRecord accepts that shape and names state 6 vs 7 from unitState. Today's bodies classify as before. No conflicts. agent: pcc-readmodels (c255d7dc)
LamaSu
added a commit
that referenced
this pull request
Sep 24, 2026
#353 now carries #313 @8f946499 (settlement-read classification by the routes' isAllocated/phase semantics; base-unit receipts; unitState on /receipt) and scopes JobExecutionDTO's evidence through the job instead of the never-written evidence_bundles.tenant_id. The one adaptation: loadLegacySettlement stops passing the removed `tenant` load option (it still refuses a job outside the caller's tenant before any read). agent: pcc-readmodels (c255d7dc)
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
product-steward asked for this (#3378): #352 and #313 conflicted in EscrowPage.tsx, and #408 and #380 inherited the conflict. Resolved with the recipe from #3124: - The one conflicting hunk is the stats grid. It takes #352's side: the Total Locked panel stays removed, since it was a TVL sum with no read model. #313's only edit there was dropping that panel's glow. - Everything else auto-merges, including #313's moneyBadgeColor on both escrow badges. tsc is clean. The dashboard passes 284/284, @pcc/ui 17/17. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…shell-route-model #354 now stacks on #352 (and so on #313), which answers astra's pack-19 finding 2. At #354's own head, App.tsx still passed kernelsOnline={2}, activeJobs={3} and networkStatus="connected". With #352, the dashboard shell renders <LiveStatusBar /> instead. The RC2 merge order already puts #352 before #354. Clean merge. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…hat-held-actions This brings #354's round-3 fixes (astra pack 19) into #413. The spatial and agent workspaces now own only their own address, and every sign-in and sign-out empties the query cache. It also brings #352's round-3 honesty fixes and #313, which #354 now stacks on. Conflict resolved: #354's new user-switch test in routing.test.tsx set the key with useAuthStore.setState({ apiKey }). #368's store, which #413 carries, keeps the key out of state, so the test uses adoptApiKey(). That still flips isAuthenticated, which is what App.tsx's cache-clearing subscription watches. tsc is clean and the dashboard passes 387/387. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…/shell-product-home #419 lands after #352, so this brings in #352's round-3 honesty fixes (astra pack 18) and #313. It carries #352's count-freshness rule over to #419's ProductHome-based StatusBar. Conflicts resolved: - LiveStatusBar: keeps #419's ProductHomeDTO read. It adds #352's re-read on recovery, so ProductHome is re-read at once when the gateway answers again after a failed health check. - lib/live-status.ts: the freshness rule is now one exported isCurrent(), used by both deriveLiveStatus and deriveHomeStatus. A read counts as current only if the gateway is reachable, the read succeeded, it came after the last failed health check, and it is at most COUNT_MAX_AGE_MS old. Before this, deriveHomeStatus showed any successful ProductHome read, so a read cached before an outage came back as current on recovery. - live-status.test.ts: #419's deriveHomeStatus fixtures carry read timestamps now. Two new cases: ProductHome read before an outage stays hidden until it is re-read, and a read older than COUNT_MAX_AGE_MS is not current. Both fail without isCurrent. - live-pages-honesty.test.tsx: in #419 the Command Center's Active Jobs KPI is ProductHome's exact count, a separate read. So the malformed-/api/jobs case now asserts that the job list is unavailable and not shown in part, instead of asserting that the KPI is missing. tsc is clean and the dashboard passes 328/328. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…rdening product-steward #3377: so the operator can merge #313 and then #342 without a conflict. The one conflict is adjacent pill CSS in pcc-ui.js: #313 adds .pcc-pill.st-refunded and .pcc-pill.st-unknown after st-running, #342 adds .pcc-pill.st-ack there; all three kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…-truth Shell #3746: #352 now carries astra's round-3 honesty fixes and #313 @8f946499, with the EscrowPage conflict resolved. No conflicts with #380, and no product code of #380 changes. Verified on the merged tree: typecheck clean, dashboard vitest 344/344 (15 files). No force-push (board rule 3). agent: pcc-operator-ux (f0734fab) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 29, 2026
…st (PX-3) Product review of #425 (product steward #4050); both notes were reproduced with failing tests first. 1. flushOutcome answered any successful flush with "Settled epoch N". A flush hands the epoch's operations to the bundler as UserOperations, and its answer carries their hashes, not an on-chain receipt (#313: accepted is not settled). The page now says "The gateway reports epoch N flushed: X operations in Y batch(es)." The epoch history is the same record, so its labels now read "Epochs Flushed" and "No epoch has been flushed since the gateway last started." 2. Manual Flush, an operational money action, ran on one click. It now asks first. The confirmation names the pending count, what a flush does (batched ERC-4337 UserOperations that act on escrow), and that it cannot be recalled. agent: pcc-readmodels (c255d7dc)
… route (astra r2 on #313) astra (gpt-5.6-sol) round 2 at 8f94649: DO-NOT-SHIP. Each finding was reproduced FIRST with a failing test against 8f94649's kit (verify-before-fix), then fixed: - F1 HIGH, shape is not provenance: a settled-SHAPED body bound to /api/jobs/j1 rendered green, and so did a baked (unsigned) snapshot. New classifySettlementRead(record, {path, live}) in the spec and settlementReadClass in the kit: a FINAL V-next state (settled 8, refunded 9) is shown only for a LIVE read of an exact per-unit settlement route (SETTLEMENT_READ_ROUTE = /api/settlement/units/0x<64 hex>/(receipt|lifecycle), the route's own UNIT_ID_RE). Snapshots, fallbacks, stream events and other routes read "final state not shown - not a live read of a settlement route". Receipt, list and run windows pass their liveness. - F2 HIGH: the generic table painted success/done/completed/ok green, so money data the routing heuristic missed (nested economics) turned green. Green means money finally reached the payee and nothing else is ever green: generic success words are now a NEUTRAL st-ack. - F3 MEDIUM: a failed poll kept an earlier green. It now reads "unknown · read failed". - F4 LOW: classifySettlementRecord's doc comment described the old /receipt rule; rewritten to the implemented semantics, and it now says display must go through classifySettlementRead. Eight earlier expectations encoded exactly what F1/F2 flagged (green from snapshots and from generic "completed"); they now assert the fixed behavior. New: live-mode checks (exact route, ?asOf, invalid unit id, other leaves, the direction label), kit == spec parity for the gate over records x sources, and the gateway suite runs the gate on the routes' real bodies. Tests: spec 864/864; gateway settlement suites 32/32; dashboard 223/223. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 30, 2026
…erdict Verify-before-fix pass against 29b-doc-350-r2-runner-ed229845.astra.verdict.md. All 4 MEDIUM findings reproduced and fixed in the two docs only (no route/mapper/ sol files touched): - D1: Route 3 text + rule 17 table + design-DTO finalState still contradicted the doc's own "Implemented on master" section (states 1-5 return 200/null, never invisible/no-receipt; finalState is terminal-only). Rewrote both, marked superseded-by-#3163, fixed matrix §B fixture 1's refundReason NONE -> null (RefundReason has no NONE member). - D2: finalizedBlock definition only covered the deferred (dischargeClaim) path. Confirmed via VNextSettlementEscrow.sol (_allocateRelease/_allocateRefund set SETTLED_* directly when remainingClaimCount hits 0 inline, no ClaimDischarged emitted) and a live route trace (fake reader, state 8, complete index, no zeroing-discharge block -> /receipt returned finalizedBlock: null). Documented both inline/deferred shapes, added inline+deferred matrix fixtures (1a/1b), and an explicit implementation-gap note (gateway-owned, SettlementUnitReader needs an allocation-block-aware read). - D3: doc presented classifySettlementRecord and settlement-read-money-status.test.ts as implemented/shipped; neither exists at ed22984 (git cat-file -e fails; zero grep hits) or anywhere on this branch -- both live only on unmerged PR #313. Reworded to explicit pending/unmerged language in both docs. - D4: doc specified TENANT_FORBIDDEN -> 403 while requiring it be indistinguishable from unknown-unit's 404 -- self-contradictory, and master always maps both to an identical 404 UNKNOWN_UNIT (settlement-read.ts:163-176,275-288). Removed the external 403 from the error union; TENANT_FORBIDDEN is internal-only. Evidence, per-finding confirmation questions, and the temp-test trace log are in /mnt/sparkbulk/pcc-reconciliation/returns/pcc-genui-work/triage-350-r2.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Sep 30, 2026
…he consumer rule Review of docwriter-alpha's 14fd55a (D1-D4, accepted as is). Two factual syncs: - the pending-code notes named #313 @8f946499, which has since moved; they now name the PR (still unmerged) without a SHA; - the consumer rule now states #313's round-3 rule: a final presentation needs a LIVE read of the exact per-unit settlement route (never a snapshot or another route). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LamaSu
added a commit
that referenced
this pull request
Oct 1, 2026
Finding: any 2xx flush body lacking the expected fields returned
{ ok: true, message: "The gateway accepted the flush." }, asserting an
acceptance the gateway's answer never established. Repro at 58a888b:
flushOutcome(200, {}) returned ok:true (2 tests failing, see below).
Fix: flushOutcome now requires the full flush contract on a 2xx — epoch,
totalIntents and batches as safe non-negative integers, and (when present)
a batchDetails array whose length matches `batches` and whose entries each
have a real UserOp hash (0x + 64 hex), a safe operationCount and a trigger
in {manual,size,age,value}. Anything else is ok:false with the same shape
message a malformed status/epochs read already uses. isCount now uses
Number.isSafeInteger (not isInteger) throughout the module. The success
wording still never says "settled" (#313 kept green).
Updated the old test that had permitted {} and null success bodies to
assert ok:false instead, and fixed an unrealistic "0xab" placeholder hash
in the #313 fixture to a real 64-hex value.
agent: implementer-charlie for pcc-readmodels (c255d7dc)
This branch has not been 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.
Problem
Money/settlement status was rendered by inference, so a REFUND rendered as a PAYMENT (read-route contract rule 1, the forbidden-asserter CRITICAL):
pcc-ui.jsstatusClass(): the greedy substring regex/(settl|releas|complet|done|paid|funded|success|approved|active)/greenedrefunded(contains "funded"),UNRELEASED,INCOMPLETE,UNDERFUNDED, and every*_ALLOCATED(decided, not final);EscrowPage.tsx: the escrow badge defaulted to green;EscrowStatus,Escrow.status, the dashboard DTO, the V-nextUnitState, the context-pack summary), and every surface re-infers them.GlowBadgealso defaults to green.Fix (scope updated 2026-09-24 for the PCC reconciliation, STATUS-BOARD PX-1)
@pcc/spec(packages/spec/src/money/money-status.ts:MONEY_STATUS_MAP,classifyMoneyStatus,normalizeMoneyStatus). It maps each exact normalized key to a semantic tone plus an honest, direction-explicit label, and it covers every documented vocabulary on master.SETTLED_RELEASED,COMPLETED,RELEASED.refunded(final; the operator is NOT paid). Allocated-but-not-final states arewaiting. Unknown values fail closed.SETTLEDis deliberately unmapped. It means operator-paid inSettlementResultDTO, but in the V-next phase vocabulary it covers BOTH released and refunded.tscif a spec vocabulary gains an unmapped value.pcc-ui.js<status-map v2>). This vanilla asset cannot import from the spec, so it keeps a verbatim copy. It also addsmoneyStatusClassfor money surfaces, so the receipt window no longer greens an off-schema"success"/"done"/"ok". fix(ui-kit,dashboard,spec): one canonical money-status map - no refund/allocated/unknown as settled-green #313's originalreleasedCountfix (contract rule 12) is kept.moneyBadgeColor(), with compile-time coverage of the dashboard'sEscrowStatustype.Tests (all of them now run in CI)
packages/spec/src/__tests__/money-status.test.ts: 8 tests (the sec-A table; the green set is exactly the 3 final releases; a never-green battery; unknown fails closed; normalization; full vocabulary coverage; immutability).packages/spec/src/__tests__/money-status.conformance.test.ts(jsdom): 19 tests. It proves the shipped kit's table equals the spec map key for key and agrees with it across an adversarial battery. It also boots the whole kit and checks the rendered receipt pill: a refund, an allocated state, an off-schema success, or a missing status never renders green.apps/dashboard/src/lib/__tests__/money-badge.test.ts: 3 tests.The original
node --testfile lived underapps/dashboard/public/, so it was served publicly, and no CI job ran it. Its 7 cases are now in the vitest suite and the file is removed.Results (DGX Spark, branch @
506f437e):@pcc/spec824/824,@pcc/dashboard223/223, dashboardtsc --noEmitclean, spectscbuild clean.Mutation proof. Each mutation must turn the suite red:
REFUNDEDchanged to settledWith every mutation restored, the suite is green again.
Scope notes
SWFDashboardPage's greenactivebadge renders a mock epoch table, not escrow state. Retiring mocks is the product-shell lane's job, so it is deliberately untouched.fulfilled) with an honest gray default, so it is also untouched.Review ask
Cross-family review requested. gateway / readmodels: please check the vocabulary semantics, especially
RELEASEDrendering green and bareSETTLEDrendering unknown.Follow-ups (not in this PR)
SettlementResultDTO.statusshould carry an unambiguous state (itssettledcollides with the V-next phase word).EscrowStatustype with@pcc/spec(readmodels).#307 toPlanCardshould consumeclassifyMoneyStatus.75e013bf.Supersedes
feat/agent-console(a41e6f46). Ledger row 37 / STATUS-BOARD PX-1.🤖 Generated with Claude Code
https://claude.ai/code/session_01P7daTDp5o3mAwxYNYyRCVy