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
…-sepolia
The StatusBar defaulted kernelsOnline and activeJobs to 0, networkStatus to
"connected", and always printed "base-sepolia". A caller with no data
therefore rendered plausible values instead of saying it had none.
- Counts are number | null | undefined; unknown renders as a dash.
- networkStatus gains "unknown" and defaults to it ("Checking gateway...").
- The network label is an optional prop with no default.
Tests: 7 in StatusBar.test.ts; 5 fail against the previous component.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
…ccount state
StatusBar: App.tsx passed kernelsOnline={2} activeJobs={3}
networkStatus="connected" on every page. LiveStatusBar now derives them from
the same react-query reads the Command Center uses:
- /api/health, re-checked every 30s;
- /api/kernels: online only with a fresh heartbeat (isStale);
- /api/jobs: active = the gateway's in-flight set in /api/agent/me
(pending, queued, in_progress, paused).
A failed or pending read shows as unknown, not 0.
Settings showed wallet 0x1234...5678, "Base Sepolia", "1,000.00 USDC",
"Tier 1" and "Auto-fund Escrow: Enabled", all hard-coded. It now shows:
- the account behind the API key (GET /api/agent/me: operator, key, scopes,
and how many keys hold the * scope);
- the wallet wagmi reports as connected, and its chain.
Balance and preferences are removed until something serves them.
Tests: live-status.test.ts (8), including a source check that App.tsx passes
no literal counts to a status bar.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
Every live page read its data as `const { data = [] } = useX()`, so during
an outage it showed "No jobs yet", "0/0 kernels", "$0.00 locked" or
"Welcome to PCC, ready": plausible values in place of "couldn't load".
Each page now has four states:
- loading;
- unavailable: the read failed and nothing was read before;
- stale: the refresh failed, so earlier data is shown with its time;
- data, where empty means the read succeeded and returned nothing.
Also removed, because each showed a value no source serves:
- Command Center: "Evidence Events 0 / last 24 hours" (hard-coded);
"Recent Activity: No activity yet" (a static claim); job.amount and name
(not in JobDTO, so every job showed $0.00).
- Total Value Locked (Command Center and Escrow) summed every escrow's
totalAmount, counting refunded and released escrows as locked. Removed
until #313's exact map or a read model serves funds held.
- Escrow: "Challenge Windows 0" (hard-coded); milestones read a field the
DTO doesn't have (now milestoneCount).
- Revenue: summed job.amount over completed jobs, which presents completion
as payment. Removed until settled income is served. Success rate now uses
finished jobs, not all jobs.
- Kernels: capability count read a missing field (now capabilityCount).
Crashes fixed:
- DiscoverPage and KernelLeaderboardPage called useMemo after the loading
early-return. React threw "Rendered more hooks than during the previous
render" on every first load.
- KernelsPage rendered kernel.location, a {lat, lng} object, as a React
child. It now shows physicalAddress, the label, or the coordinates.
Active and online counts use lib/live-status.ts, the same definitions as the
StatusBar. Job status chips map the canonical StepStatus values; pending,
in_progress and paused previously rendered as "offline".
Tests: live-pages-honesty.test.tsx (18) renders the real pages with the real
hooks and a stubbed fetch, in outage / partial / empty / data cases.
15 of the 18 fail against master's pages.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
… phase table Product pack section 7 / PX-6. A product surface needs to PROJECT a job, not infer it. The DTO has four independent axes, each with an explicit enum, the source it was read from, and that source's own timestamps: - execution: what the executor reported. ONE exact table maps every job-row status PCC writes or documents (gateway JOB_STATUSES, KernelJobStatus, StepStatus, and the paid-job pipeline's active / evidence_stored / evidence_submitted / settled) to a phase. Anything else is `unknown`, never a success phase. `settled` in a job row is an execution fact only: mock settlement writes it with no money moving. - evidence: received, counted, and fabricated-by-design events counted with the canonical isFabricated. Received is never verified. - verification: outcome verification is `not_available` (no public verdict read exists); capture checks are counted as capture checks. - settlement: the linked escrow record, classified by the canonical money map (#313 classifyMoneyStatus); payout is paid / refunded / not_paid / simulated / unknown, never derived from completion. asOf is READ time (render-provenance contract, #2222/#2232). Browser-safe. Compile-time coverage of KernelJobStatus and StepStatus; 8 tests (exact table, fail-closed input including prototype keys, frozen table, terminal set). agent: pcc-readmodels (c255d7dc)
…s not settled
PX-6: the live Jobs list drilled into a mock detail page, and the legacy job
DTO inferred payment from completion. This adds the product read model and
stops the inference.
- New GET /api/jobs/:jobId/execution -> JobExecutionDTO (@pcc/spec). One
synchronous read pass over the store; each source (capability, kernel,
evidence + events, capture verdicts, settlement) is read separately, and a
failed read becomes `unavailable` with a generic error (details go to the
log), never an empty list or a default. Same gate as GET /api/jobs/:jobId;
under TENANT_ENFORCE a job of another tenant is a 404. cache-control:
no-store.
- Settlement link follows the paid-job flow (negotiation session -> cwmId ->
escrow), then the job's own cwmId, then the session's escrow address; more
than one candidate is `ambiguous` and nothing is chosen. The payout reads the
job's OWN milestone (by stepId). The whole-escrow status is used only when
the escrow records no milestones; when milestones exist but none is this
step, payout is unknown, so a sibling step's release never pays this job. A
mock-settlement escrow (mock-escrow-*) is `simulated`, never paid.
- Legacy JobDetailDTO timeline: status `completed` now emits a `completed`
event instead of `settled` (completed is not payment). A row that itself
says `settled` is still echoed.
- JobDTO rows carry executionPhase (server-read, exact table), so no surface
re-derives it from status.
- GET /api/jobs keeps { jobs } and adds collection-v1 `items` (the closed
render IR list shape, #2231), total (ALL matching jobs, not the page
length), offset/limit/hasMore and asOf (read time, #2222).
Tests: 34 in readmodels/job-execution.test.ts (builder, loader, route, list
envelope), including negatives: completed without a record is not paid; a
job row saying settled is not paid; funded+completed is not_paid; refund is
never paid; an unknown money status is never paid; a mock escrow is never
paid; sibling releases never pay this job; ambiguous links/milestones choose
nothing; evidence is never verification; failed reads are unavailable with
no internal detail; missing timestamps stay null; tenant isolation. Plus 2
populator tests. Full gateway suite: 3016 passed, 6 skipped, 0 failed.
agent: pcc-readmodels (c255d7dc)
…no mock data
PX-6, the continuity break: JobsPage (live) opened JobDetailPage, which read
only mockJobs/jobMeta/mockEscrows (emptied, so every real job said "Job not
found"), a hard-coded mockEvidence array, hard-coded DID / IPFS CID / Base and
Solana tx hashes, and a "Load demo trace" fixture.
JobDetailPage now renders GET /api/jobs/:jobId/execution only:
- four independent panels (Work, Payment, Evidence, Verification), each
naming its source. "Work reported complete" is never payment; evidence is
"received, not verified"; capture checks are explained as capture checks.
- Payment: only a gateway-classified `paid` is green (GlowBadge defaults to
green, so every badge passes an explicit color); recorded amounts are
labeled recorded, never paid; not-linked / ambiguous / unavailable read as
what they are.
- 404 ("Job not found") is told apart from unavailable ("Job details are
unavailable right now", with retry). A failed refresh keeps the last read
and says it is stale. Polls every 15s until the phase is terminal.
- Notices from the DTO (job row says settled, fabricated evidence, simulated
escrow, unknown status) are shown as-is.
- An "Inspect raw record" section keeps ids, raw statuses and the contract
address available without forcing them into the main view.
Support: gateway.ts ApiError keeps the HTTP status (message unchanged);
getJobExecution; useJobExecution (no retry on 404); useJobs now throws on a
response without a jobs array instead of returning [] (absence is not
evidence); dto.ts JobDTO.executionPhase and the `completed` timeline event.
Presentation rules live in lib/job-execution-view.ts (exhaustive over the spec
unions). JobsPage is the shell lane's (PX-3) and is untouched here.
Tests: 10 view tests + 5 page-source tests (no fixture imports, no hard-coded
hashes/CIDs/DIDs, 404 vs unavailable, stale marker). Dashboard suite 238/238;
tsc -b && vite build clean.
agent: pcc-readmodels (c255d7dc)
…ate escrows Two escrow records under the job's cwm must read `ambiguous` with no record and payout unknown; picking the first would show one escrow's money state for a job that may belong to the other. Mutation-checked: making the loader take the first candidate turns this test red (16/16 mutations of the PX-6 rules are caught by the suite). agent: pcc-readmodels (c255d7dc)
… not a total Product-steward review of #352 (bus #2409): MEDIUM. GET /api/jobs returns at most 50 rows when no limit is sent (job.facade.ts) and reports no total. The StatusBar, Command Center, Jobs and Revenue pages counted page 1 and showed the result as exact. Now a full page makes every count over it a lower bound, rendered "N+": - StatusBar: activeJobsAtLeast - lib/live-status.ts: JOBS_PAGE_SIZE, mayBeTruncated, formatCount - the pages note "there may be more" - Revenue's success rate shows "--" instead of a rate from a partial sample ProductHomeDTO / a /api/jobs total (readmodels #2289, #2290) will replace the lower bound with the exact count. LOW. useKernels and useEscrows mapped an unexpected response shape to [], which reads as "0 kernels online". They now throw, like readmodels' useJobs (absence is not evidence). /api/kernels and /api/escrow return full lists, so they need no lower bound. Tests: - live-status +3, StatusBar +1, live-pages-honesty +2. - live-pages-honesty's settle wait is now condition-based (up to 2 s), not a fixed 50 ms that flaked under load. - dashboard 251/251, ui 17/17. Against master's pages, 17 of the 20 honesty tests fail. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
Found while answering coord-watch's review question (#2497): can any surface still show a fabricated, default or last-known value when a read failed or came back off-schema? - Command Center: after a failed refresh, the KPIs kept their last-known figures while the banner said failed figures show as "—". A summary now shows only what its latest read returned. The list pages keep earlier data under a timestamped StaleNotice. - useJobs mapped an off-schema /api/jobs to [], which reads as "0 active jobs". It now throws. The lines are byte-identical to readmodels' feat/readmodels-job-execution, so the two branches merge in either order. - useAgentMe: an answer without the identity block is a failed read. Before, Settings crashed. Tests: +3 in live-pages-honesty; all 3 fail on the previous head (753ab25). Dashboard 254/254. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
… confirmation Response to the cross-family review of #353 (DO-NOT-SHIP, coord-watch #2477). The types now carry what the gateway must prove before claiming any money: - SettlementLink gains `conflicting`: the job's recorded identifiers point at different escrow records, or the record found contradicts one of them. - SettlementAxis.linkMatches lists every identifier that points at the linked record; payoutBasis is only ever this job's own milestone (no whole-escrow fallback); payoutConfirmation `record_only` qualifies a paid/refunded claim that no chain receipt confirms. - SettlementRecordView.statusObservedAt: null. The escrow record stores no time for its statuses, so a fresh asOf dates the read, not the settlement. - PayoutState documents the reconciliation: paid needs this job's milestone to say released AND the escrow not to contradict it; any disagreement is unknown. no_milestones is unknown. - New notices: settlement_records_conflict, settlement_link_conflict. agent: pcc-readmodels (c255d7dc)
…ze the reader Addresses the cross-family review of #353 (coord-watch #2477, astra), which showed the read model could report a job as PAID with the wrong money. P1-1 link: resolveSettlement now looks up EVERY recorded identifier in full (the session's escrow address and CWM, the job's CWM), with row cardinality checked (the address lookup no longer hides duplicates). One identifier matching several escrows is ambiguous; identifiers matching different escrows are conflicting; the one escrow found must match every identifier the session recorded; a session that records no escrow cannot be linked through the job's CWM. The job's CWM alone links only jobs with no negotiation session. P1-2: an escrow with no milestone rows no longer yields a payout (several jobs can share an escrow): unknown. P1-3: the payout reads this job's milestone reconciled with the escrow's own status (reconcilePayout); released + refunded/disputed/slashed/expired/ unrecognized escrow, and unreleased/refunded + an all-released escrow, are conflicts -> unknown with a notice. paid/refunded are marked record_only. P1-5: GET /api/jobs/:jobId/execution is object-authorized before any axis is read (authorizeJobRead), whatever TENANT_ENFORCE says: a valid X-Admin-Key (constant-time, no dev bypass when PCC_ADMIN_KEY is unset), the job's kernel operator (kernel.operatorAddress), or its recorded buyer (the negotiation session's userAgentId). Anonymous -> 401; anyone else -> 404 (no existence oracle). Stated limits: the principal is the API key's operatorId (proven identity is board N2, gateway); the buyer is only recorded as the session's userAgentId. Tests: 56 in readmodels/job-execution.test.ts, including the reviewer's counterexample (unrelated completed escrow on the job's CWM), address duplicates, session address vs job CWM naming different escrows, a session address with no row, a session CWM contradicting the found escrow, zero milestones for every escrow status, the full milestone x escrow table, and the authorization matrix (anonymous, stranger, operator, buyer, admin, wrong admin key) under both TENANT_ENFORCE settings. Mutation-checked: 17/17 red. agent: pcc-readmodels (c255d7dc)
…b row The job row can say the work finished; it cannot prove payment. Mock settlement writes `settled` into the row with no money moving, so every "work finished" row status (completed, settled, evidence_stored, evidence_submitted, verified, awaiting_verification) now becomes a `completed` timeline event and the legacy JobDetailDTO timeline never emits `settled`. Payment lives on the escrow record (JobExecutionDTO settlement axis). Raised by the #353 cross-family review as a remaining legacy lie. agent: pcc-readmodels (c255d7dc)
…shing Addresses the #353 cross-family review (P1-4, P2) and the design lane's note (#2510). - P1-4: the recorded escrow and milestone statuses are neutral record text (recordStatusBadge: always gray, labeled from the DTO's own classification, prefixed "Simulated:" on a mock escrow). The page no longer re-classifies raw money strings, so a simulated or conflicting record can never show a green "payment sent to operator" beside a payout that says otherwise. - P2: the job keeps refreshing after the work finishes (60s instead of 15s), because finishing the work never makes the money final; a read older than two intervals is marked stale by age, as is a failed refresh. - Design #2510: no work phase uses a success or animated-online chip; only "executing" (amber) and "failed" (red) carry color. - Wording for the new states: link conflicts, records that disagree, no milestones, and "Not confirmed on chain" on a record-only paid claim. A 401 says to sign in instead of "not found". Tests: 18 view tests (every canonical money status x simulated renders neutral; freshness; new wording) and 7 page-source tests (no raw money re-classification, polling never turns off). Dashboard 248/248; tsc -b && vite build clean. agent: pcc-readmodels (c255d7dc)
…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
…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)
…_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)
…irmed reachable Operator-ux's real-state trace (#2800): about 2 s after the gateway stopped, the bar still read "Gateway online | 2 kernels online", and it kept that until its next 30 s health poll. The counts came from reads that succeeded before the outage, presented as current. - deriveLiveStatus shows kernel and job counts only while /api/health confirms the gateway is reachable. While liveness is unknown or down they are "—". - recheckHealthOnReadFailure: any failed gateway read (other than health itself, so there is no loop) invalidates the health query, so the bar flips to "Gateway unreachable" on the next failed read instead of the next poll. Tests: live-status +2; LiveStatusBar.test.ts (3, jsdom). Dashboard 259/259. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
The contract for operator-ux's Work Inbox (PX-7, fields from operator-ux #2562), so the UI projects instead of inferring: - OperatorWorkItem across four sources (job_offer, skill_job, kernel_job, approval): phase plus phaseSource (server, operator_reported or verifier), the source's own status, pay with its funding (escrowed, declared_unfunded, simulated, unknown) and basis, location, evidence requirements, actions with the route to call and the reason when not allowed, refs, changedAt. - Exact phase maps for job-offer statuses and kernel-job execution phases. Completion is reported_done by the operator, never verified; a "settled" offer is work reported done, not a payment; anything unmapped is unknown. - OperatorIncomeDTO: rows from escrow records, totals that are sums of rows only, historyAvailable false with the reason. - toBaseUnits converts an amount to base units exactly or returns null (no rounding, no guessed decimals); currencyDecimals knows only recorded currencies. Tests: 9 (maps fail closed and never say verified; exact conversion; no rounding). agent: pcc-readmodels (c255d7dc)
…odels OperatorWorkDTO and OperatorIncomeDTO for operator-ux's Work Inbox (PX-7), scoped to the caller's kernels (operatorAddress is the caller, compared case-insensitively, as authorizeJobRead does). Anonymous callers get 401; a failed kernel read is 503; a caller with no kernels gets an empty, fully described read. cache-control no-store. - Kernel jobs: phase from the job's execution phase. Pay only from this job's milestone in its escrow record, through #353's resolver and payout rule (buildSettlementAxis, now exported): escrowed, or simulated for a mock escrow, else unknown with no amount. A pending approval folds into its job (awaiting_me, approve/reject), so no work is listed twice. - Approvals without a job row are their own items (no invented pay). - Job offers: the caller's claimed offers, plus open offers for capability types the caller's kernels offer, each with a claim action naming those kernels. Declared prices are declared_unfunded, never escrowed. The location is rounded to about 1 km until the offer is the caller's. A missing location is unknown, not remote. A lapsed offer cannot be claimed, and the action says why. If either offers read fails, no offer is listed (a partial list would look complete). - Skill jobs are not_attributable: they are keyed by a self-asserted humanDid that no key is bound to yet. The source says so instead of an empty list. - Income: rows for the caller's linked kernel jobs; totals per payout status and currency, summed in BigInt from rows with exact base units only (the rest are counted in uncountedRows); historyAvailable false with the reason; never paid. - job-offers store: listClaimedBy(kernelIds) (read-only) and an exported extractRequirementsCoords. Tests: operator-work.test.ts (29: kernel jobs, approvals, offers, sources, ordering and truncation, income, both routes on a real store including cross-operator scoping). Gateway 3071 passed / 6 skipped / 0 failed (a first full run had the known 5000ms flake in completion-real-tier.test.ts, untouched, 3/3 alone). Mutation check: 12/12 killed. agent: pcc-readmodels (c255d7dc)
CLAUDE.md and docs/AGENT_INTEGRATION.md gain an Operator Work section; the context pack and the capability list (agent-introspection) list GET /api/operator/work and GET /api/operator/income, with what their fields can and cannot claim. agent: pcc-readmodels (c255d7dc)
… amount
The shared money primitive turned any missing or unparseable amount into
"$0.00 USDC" (parseFloat -> NaN -> "0.00"). It also painted every amount
the "green" tone, which the dashboard theme compiles to blue, whether or
not anything was paid.
- amount?: string | number | bigint | null. Missing or unreadable input
renders an em dash with a visually hidden "amount unavailable" label,
never 0.
- Exact reading and printing (parseAmountExact / formatAmountExact in
utils): no float and no rounding. 0.004 stays 0.004, grouped thousands
("1,234.56") are read in full, and an optional `decimals` reads base
units (USDC: 6).
- Neutral ink: no payment-state colour or glow. `glow` is accepted and
ignored; the money badge (MONEY_STATUS_MAP) shows whether it was paid.
- Tabular numerals.
- Removes the unused utils.formatAmount (the same NaN -> $0.00 trap).
The strict-parsing cases are adapted from pcc-shell's 7f66a20, so one
formatter serves both lanes. Approved as a Wave-0 PX-3/PX-15 primitive
fix by product-steward (#2573).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X3Lva1DrcsKRjJdrzu27zJ
…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
…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
pcc.product-home/v1: the platform-wide facts a home page shows, each
from a named gateway source, for the shell's StatusBar and Command Center
(shell #2007, product-steward #2170).
- kernels: online / stale / other with the kernel read model's rule
- jobs: counts by execution phase and `active` (known, not finished)
- settlementNetwork: the CONFIGURED network (basis gateway_config), with
the chain id of known network names; not proof an escrow lives there
- escrowHeld: sums of milestone amounts in held states per currency, in
base units, mock escrows excluded; confirmation record_only
- a section that could not be read is {state: "unavailable", reason}
HELD_MILESTONE_STATUSES and NOT_HELD_MILESTONE_STATUSES are disjoint and
in normalized form; every EscrowStatus word and every milestone word the
gateway writes (PENDING, EVIDENCE_SUBMITTED) is in one of them, checked
at compile time for EscrowStatus.
agent: pcc-readmodels (c255d7dc)
One read per section; a section whose read fails is unavailable with a reason, never a zero. Held funds are summed from escrow_milestones rows in held states (never escrow totals: an active escrow can hold released milestones), exactly in base units or counted as uncounted; unknown status words are counted as unclassified, never guessed. Under TENANT_ENFORCE the job counts are the caller's tenant's, a caller with no tenant gets them withheld (no cross-tenant read happens), and the held total is withheld because escrow records carry no tenant. The route states each withheld reason at the source. cache-control: no-store. Tests: 13 gateway (pure builders + the route on a seeded store) and 5 spec. Mutation check: 17/17 killed. agent: pcc-readmodels (c255d7dc)
agent: pcc-readmodels (c255d7dc)
…ine kernels The charter's ProductHome is a health / jobs / capabilities summary, so the DTO gains `capabilities`: capability rows, and how many sit on a kernel that is online by the kernels section's own rule (a capability on a stale, offline or missing kernel is listed but never counted as on an online kernel), per type, with a null type for a row that has none. A listing is not a promise of capacity. Built from the same read as the kernels section, so it is unavailable exactly when that read fails. Tests: gateway product-home 15 (was 13). Mutation check: 22/22 killed. Suites: gateway 3086/6/0, spec 875. 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
…duct-home consumer branch EscrowPage: #352's stats grid (no Total Locked sum) kept; #313's moneyBadgeColor badges merge as is (the RC2 resolution sent to product-steward, #3124). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
…xactly) into the product-home consumer branch
Readmodels' ProductHomeDTO (#409; #3192, #3213) counts kernels, jobs, capabilities and held escrow over the gateway's own records. The shell consumes it: - StatusBar: kernels online and active jobs are the gateway's exact counts, no longer "50+" lower bounds over one page of /api/jobs. The network label is the settlement network the gateway is configured for, shown as "<name> (configured)". The counts still show only while /api/health confirms the gateway is reachable (#352's rule, now gatewayConnectivity()). - Command Center KPIs: - active jobs of total; - kernels online/total, with stale and not-online counts; - capabilities listed, with how many are on an online kernel ("a listing is not a promise of capacity"); - escrow held per currency, formatted exactly from base units by design's AmountDisplay (#393). It is labelled "From escrow records; no chain read confirms it", with uncounted, unrecognised and simulated escrows called out. A section the gateway couldn't read shows "—" and its reason, never 0. - lib/product-home.ts checks the answer's shape. Any other schema, a missing count, a negative count, a display string for a base-unit amount, or a missing network block is a failed read. Tests: - product-home.test.ts (8). - deriveHomeStatus (3). - The Command Center honesty tests, rewritten around the DTO (27 in the file). 5 fail against #352's list-based page. - Dashboard 303/303; tsc clean. Stacked on #352, readmodels #409 and design #393. It lands after them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
The settle loop stopped at the first tick with no fetch in flight, and a query can read as idle for one tick between retries. Under load on the Spark (load average 16-21) this file failed 3 of 23 once (the Kernel leaderboard, Revenue and Settings cases; reported by implementer-echo). It now waits for two idle ticks in a row, within 2 s: the same fix #408 applies to its own tests. Test-only. Dashboard 259/259 on three consecutive runs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
…y reports it Readmodels confirmed (#3325) that the build SHA stays on /api/health (N5, #369). #369 adds commit and commitSource there. The StatusBar now shows "build <sha7>" beside the configured network, but only for a full 40-hex commit whose source is "image_build". A runtime-only, unknown or malformed commit shows nothing, as does any gateway without #369 (today's master). This has no code dependency on #369. @pcc/ui StatusBar gains an optional `build` prop. Tests: StatusBar (+1), deriveHomeStatus build cases (+1). ui 9/9, dashboard 304/304, tsc clean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ
…rmed (PX-3, astra r2) astra's round-2 review of #352 (DO-NOT-SHIP at 459c616) found that the query-to-view boundary treated data presence and a shallow envelope check as proof of current, valid state. The list hooks now reject a response with a malformed row, not just one without the array: - jobs need an id and a status; - kernels need an id, a status and the isStale flag the populator always sets; - escrows need an id and a status; - capabilities need an id and a kernelId; - templates must be an array. /api/agent/me must carry a complete identity: operator, key_id, key_name and scopes. Settings reads the key section through keyCounts(). That treats { active: null, wildcard_keys: 0, unavailable } as unavailable, not as zero wildcard keys. The StatusBar shows a count only if it was read after the gateway's last failed health check and is at most 75 s old. A recovered health check no longer certifies counts cached before the outage. The bar re-reads its counts every 30 s, and at once on recovery. isKernelOnline now requires isStale === false. Pages: - Discover, the leaderboard and Revenue label data kept after a failed refresh (StaleNotice). - Discover says when site names couldn't be read, and no longer turns missing templates into an empty list. - The leaderboard reads every capability page at limit 200, the route's maximum; it had asked for 500. If paging stops early, it says the ranking covers only what was read. - The Command Center and Jobs say "in the first 50" when only one page was read. - Kernels' capability total and the leaderboard's queue depth show as unknown, not zero-filled, when a row doesn't report them. - The leaderboard's online pulse uses the fresh-heartbeat rule. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…A-H) Covers astra r2's #352 findings: malformed-row rejection (jobs/kernels/ escrows/templates/capabilities), stale-refresh labelling on Discover/ Kernel-leaderboard/Revenue, Discover's "site names couldn't load" notice, truncated-page wording on Command Center and Jobs, the kernel capability total going unavailable (not zero-filled) when one kernel omits it, useAllCapabilities paging through every page of /api/capabilities (250 rows/2 pages, and a short second page marking the ranking partial), and three Settings account-section honesty cases (missing key_id, keys. unavailable with reason, missing keys section entirely) -- two of which crash on the pre-fix source (identity.key_id.slice on undefined; keys. active on an undefined keys object). Also adds two kernel-leaderboard-logic.ts unit cases: buildLeaderboard's `online` field reflects isKernelOnline (isStale-gated), and `queueDepth` is null when any capability omits it rather than treating it as zero. 19 new cases total (17 in live-pages-honesty.test.tsx, 2 in KernelLeaderboardPage.test.ts). Full dashboard suite: 281/281 passing. tsc --noEmit: clean. Stretch case (LiveStatusBar recovery timing) skipped per spec -- already covered by lib/__tests__/live-status.test.ts's "counts are current, not just cached" describe block. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… not any digit-plus Review of test-writer-alpha's 58bbfab: /\d\+/ would match any lower bound on the page. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
…/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>
…l at eaedeb4) Appends an R4 describe block to live-pages-honesty.test.tsx with 18 tests (R1a-R5b) covering every finding in the 18b astra verdict for eaedeb4: escrow currency/amount fabrication (Dashboard, Escrow, Revenue), Discover presenting templates as live capabilities, off-schema rows (bogus job/kernel/ escrow status, capability missing type, negative queue depth, negative/ fractional key counts) still reaching displayed numbers, the capabilities pager certifying a shrunk-total or duplicated-page read as complete, and two categorical empty-state claims over a partial read. All 18 fail at eaedeb4 as designed (verified via `pnpm exec vitest run`); the 40 pre-existing tests in the file still pass. No source file was modified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ail closed, Discover lists live capabilities (astra 18b) Each finding was first reproduced at eaedeb4 by 3a87d0b (18 cases, R1a-R5b, all failing there). All 18 pass now. F1 (HIGH, money): an ETH escrow showed as "$10.00 USDC", and "not-money" showed as "$0.00 USDC". - useEscrows now requires a canonical decimal totalAmount (no sign, exponent, grouping or leading zeros) and a currency the escrows table allows (USDC, ETH, DAI). Milestone counts, when present, are counts, and the released and disputed milestones are among the escrow's milestones. - Dashboard, Escrow and Revenue pass the escrow's currency to a new EscrowAmount. It shows the amount digit for digit, never through a float, with a "$" only for USDC, and shows unavailable rather than a value. The shared AmountDisplay is design's (#393), and EscrowAmount follows its new rules, so @pcc/ui is untouched here. F2 (MEDIUM): Discover listed the static template catalog as "capabilities found". It now reads the capabilities operators list (GET /api/capabilities, every page, each row validated). A read the pager capped is counted "N+", with a note. F3 (MEDIUM): statuses such as "bogus" were counted. - Job, kernel and escrow statuses must be ones the gateway defines. The sets in api/wire-vocabulary.ts are what the gateway really writes, with a source for each value. That is wider than its advertised JOB_STATUSES: executing, evidence_submitted and settled are stored too, and a narrower set would turn working pages into outages. - Capability rows need a type. queueDepth, assuranceScore and reputation must be in range when present. - keyCounts needs non-negative integers, with the wildcard keys no more than the active ones. F4 (MEDIUM): useAllCapabilities fails the read, and its retry starts over, when: - the total changes between pages; - a page answers for another offset; - hasMore disagrees with the page's offset, limit and total; - an id repeats; - more rows arrive than the total. F5 (MEDIUM): - The leaderboard says "Nothing to rank yet" when kernels are registered but list no capabilities. "No kernels" is kept for when none are registered. - Revenue says "No completed jobs in the first 50" on a full page. Changes to the tests: - bravo's titles now state requirements. - Its varying stub answers for the offset asked, so R4a and R4b test the total and duplicate checks rather than an offset mismatch. - R3g checks the Active keys row: the key id "key-1234" itself contains "-1". - The round-2 fixture's "mystery" job status is now a known inactive one, because an unknown status fails the read (R3a, R3b). - New tests cover: - every status the gateway writes being accepted; - USDC keeping its "$", with every digit of a large amount; - DAI showing no "$"; - malformed amounts; - each pager check, including a total change the other checks miss; - out-of-range scores; - more wildcard keys than active keys. - Mutation controls: 11 mutations, each reverting one check, and every one fails at least one test (returns/pcc-shell-work/px3-r4-controls/). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-home Brings astra 18b's fixes (escrow currency and exact amounts, known statuses, pager consistency, live Discover, scoped empty states). Textually clean, but two fixes: - DashboardPage keeps AmountDisplay. #352 dropped the import because its escrow rows now use EscrowAmount, and this branch still uses AmountDisplay for the Held in Escrow KPI. - The TTL-sweeper test checks the Kernels page for the kernel counts. Here the Command Center's kernel ratio comes from /api/product/home. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Draft: the shell side of ProductHomeDTO. Stacked on #352, readmodels #409 (ProductHomeDTO) and design #393 (exact AmountDisplay). Base: master. It lands after all three.
Why
The StatusBar and Command Center counted over one page of
/api/jobs(at most 50 rows), so a busy gateway read "50+". The network label had no source. #409 serves the platform-wide facts, counted by the gateway over its own records.What changes
StatusBar:
<name> (configured), because configuration is not proof that escrow lives there;/api/healthconfirms the gateway is reachable (fix(dashboard,ui): live StatusBar, honest Settings, and a failed read is not an empty result #352's rule, nowgatewayConnectivity()).Command Center KPIs:
AmountDisplay. It is labelled "From escrow records; no chain read confirms it", and it calls out uncounted, unrecognised and simulated escrows.A section the gateway couldn't read shows "—" and its reason, never 0.
Served build (N5): the StatusBar shows "build " when
/api/healthreports an image-baked commit (feat(gateway): /api/health reports the served commit (N5) #369'scommitwithcommitSource: "image_build"). Otherwise it shows nothing. There is no code dependency on feat(gateway): /api/health reports the served commit (N5) #369.lib/product-home.tschecks the answer. Any of these is a failed read:The job and escrow lists below the KPIs still read their list routes. The "first 50" note stays on the list only.
Conflict note
Readmodels' chain carries #313, so this branch includes the same EscrowPage resolution sent to product-steward for RC2 (#3124): #352's stats grid, and #313's
moneyBadgeColorbadges.Tests
product-home.test.ts(8) andderiveHomeStatus(3).@pcc/uiStatusBar 9/9;tscis clean.Browser trace against #409's real gateway: 8/8 (
returns/pcc-shell-work/e2e-home-20260924/)Setup: this branch's gateway (#409's
/api/product/home) withNODE_ENV=production, a fresh DB and no seed. A kernel, a capability and a job were created through the API.GET /api/product/homereturned.🤖 Generated with Claude Code
https://claude.ai/code/session_01VU6exGFC7uLukeDF2GBUpQ