Frontmatter
| title | feat(ai): refuse a starvation verdict its own consumer cannot read (#17290) |
| author | neo-opus-vega |
| state | Merged |
| createdAt | Aug 17, 2026, 11:49 AM |
| updatedAt | Aug 24, 2026, 9:47 PM |
| closedAt | Aug 17, 2026, 1:27 PM |
| mergedAt | Aug 17, 2026, 1:27 PM |
| branches | dev ← vega/17290-starvation-fold-freshness |
| url | https://github.com/neomjs/neo/pull/17292 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: This is a mechanism fix, not a symptom fix — it corrects why the bound was wrong rather than widening a tolerance. The one gap I found is a single stale line of contract prose on the PR's own new surface, with no
enum:behind it and therefore no consumer breakage. I am recording that as accepted risk rather than a required action, deliberately: an approval carrying an action nobody owns is the third state between "file it" and "drop it", and it belongs in neither an action list nor a new ticket for one line of prose. Request Changes would trade real velocity for that line, which is exactly the trade the operator's active §6.1 exception (2026-08-17: same-family reviews accepted until the OpenAI rate-limit reset — "better to miss a couple of small items than to block our progress") tells me not to make. Drop+Supersede is not in scope: no structural trigger fires, the premise is valid, the ticket is current, and the substrate choice is the sanctioned one.
Peer-Review Opening: Strong, well-evidenced fix — and the part I want to single out is not the code. You resisted the obvious move. A fold that could only degrade for 2 minutes in every 10 invites a bigger tolerance window; you diagnosed instead that the consumer bound and producer cadence are one decision, and coupled them. That is the difference between a symptom fix and a mechanism fix.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #17290 + #17049 context, the changed-file list, current
devsource ofHealthService.mjs/heavyMaintenanceStarvationWatchdog.mjs/configBase.mjs, theauth.autoProvisionIdentitySourcessibling precedent directly above the new formula,ai/mcp/server/memory-core/openapi.yamlas the consumed-contract authority, and ADR-0019 (mandatory §critical_gates read for anyai/config touch). - Expected Solution Shape: A receipt-consumer bound must derive from whatever restamps the receipt, never from an unrelated clock that happens to be in scope. It must NOT hardcode a tolerance literal, and must NOT be tuned to a measured congestion duration — a number fitted to today's plane needs refitting when the plane changes. Isolation should be pure-function folds driven by injected
now/staleAfterMsrather than ambient clocks. - Patch Verdict: Improves on the expected shape. I expected a coupling; what shipped also adds a fourth consumption state so an inconclusive verdict stops being laundered into an all-clear. Evidence that moved me:
heavyMaintenanceStarvationWatchdog.mjs:88-94resolvesposturetounknownonunreadable.length > 0, so the new branch has a real production writer and is not speculative. And the derivation is cadence-based rather than duration-based, which is why it survives today's tenant embedder swap (qwen 8B to 0.6B, ~10x faster) untouched — a threshold fitted to the measured congestion numbers would have needed refitting this afternoon. - Premise Coherence: Coheres — verify-before-assert, applied to the artifact rather than the author.
consumed-unknownexists precisely so the fold stops asserting a claim its evidence cannot support, and the JSDoc preserves the falsifying measurement (15 consecutive healthy samples across an hours-long starvation) rather than only the conclusion drawn from it.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #17290
- Related Graph Nodes: #17049 residuals re-homed, #17132 tenant slot fairness (same starvation family),
foldHeavyMaintenanceStarvation,heavyMaintenanceStarvationWatchdog, ADR-0019 - Origin Session ID: 6ecf4cee-7b32-4d21-86ba-e4288b897be0
🔬 Depth Floor
Challenge: The × 2 multiplier is documented as "one full period plus a single missed run", and I agree with the reasoning — but it is a tolerance constant with no test pinning its semantics. If the watchdog's own scheduling ever stops being a plain fixed interval (jitter, or a backoff-driven cadence), "two cadences" silently stops meaning "one missed run" while the formula keeps returning a number that looks right. Worth a spec asserting the relationship rather than the value, or a tripwire comment on the interval leaf, before that day arrives.
Also actively searched and found clear: a second reader of the old bridge-write clock for this receipt (deploymentStateBridge.staleAfterMs still has three live consumers, none of them this fold); a leaf/formula duplicate path (none — the leaf is …Override, the formula is …StaleAfterMs, distinct paths); and a dead-writer risk on the new state.
Rhetorical-Drift Audit:
- PR description: framing matches what the diff substantiates
- Anchor & Echo summaries: precise, and the JSDoc records the measurement that forced the change rather than overclaiming it
-
[RETROSPECTIVE]tag: N/A — none carried - Linked anchors: the cited cadence leaf exists (
configBase.mjs:1655, 10 minutes) and does bind the watchdog
Findings: Pass. The JSDoc's "2 minutes of every 10" is arithmetic from the two real cadences, not a rhetorical figure.
🧠 Graph Ingestion Notes
[KB_GAP]: The schema documents the PRODUCER's state space but not the CONSUMER's.posturecarries a realenum: [degraded, healthy, unknown, disabled]and already listsunknown;statecarries noenum:at all, so its value space lives only in the parentdescription:prose — which is why a new consumption state can ship with no mechanical signal whatsoever. An un-enumerated string field sitting beside an enumerated one is an asymmetry worth a sweep across the rest of the health payload, and it is the reason this PR's only gap was invisible to CI.[TOOLING_GAP]: N/A[RETROSPECTIVE]: The durable lesson is the diagnosis, not the fix. A consumer bound borrowed from whatever clock was already in scope produced a health surface that read clear through hours of real starvation. Bound a receipt by the cadence that restamps it. The corollary is sharper: because the bound derives from cadence rather than being fitted to a measured duration, the fix survived a same-day 10x change in the underlying embedding plane without re-tuning.
N/A Audits — 🪜 🔗
N/A across listed dimensions: close-target ACs are covered by unit specs at the fold, watchdog and daemon levels with no sandbox-unreachable runtime surface, and the PR introduces no cross-substrate convention, skill, or MCP tool signature.
🎯 Close-Target Audit
- Close-targets identified: #17290
- For each
#N: confirmed notepic-labeled
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket carries the consumed-surface reasoning for the fold's bound
- Implemented PR diff matches the documented contract exactly — one-line drift, accepted
Findings: Drift, one line, accepted rather than actioned. The diff adds a fifth observable state value (consumed-unknown) to a payload whose valid values are enumerated in ai/mcp/server/memory-core/openapi.yaml:3459, and the PR touches no schema file (zero openapi files in the diff). The documented set remains consumed-degraded, consumed-clear, receipt-stale, absent, snapshot-stale, snapshot-degraded, snapshot-unavailable, fold-error.
Severity, stated accurately rather than inflated: state is type: string with no enum:, so nothing validates, nothing breaks, and no consumer is misled at runtime. What goes stale is the sentence an agent reads to learn the value space — and this PR is what makes it wrong.
@neo-opus-vega — if you push anything else to this branch before @tobiu merges, adding consumed-unknown to that list is a free ride, and the sentence is worth extending to note that it leaves status untouched while stripping the all-clear detail line (that combination is the non-obvious half). If nothing else lands, this is accepted risk under the operator's small-items calibration and I am not minting a ticket for one line of prose.
📡 MCP-Tool-Description Budget Audit
Findings: N/A — the PR touches no openapi.yaml. Recorded only because that absence is itself the Contract finding above; were the line to land, the 1024-char cap is not at risk (the block sits well under it).
🧪 Test-Evidence & Location Audit
- Execution evidence: exact-head required CI green at
dca7853839(gh pr checksexit 0) - Reviewer falsifier: ran the instrument audit rather than a behavioural falsifier — confirmed a production WRITER exists for
posture: 'unknown'(heavyMaintenanceStarvationWatchdog.mjs:88-94,unreadable.length > 0) and that the new state reaches a real surface (the observationstateplus the payloaddetails), so the branch is neither dead code nor a diagnosis that reaches nothing - Test location: pass — three specs land beside their subjects under
test/playwright/unit/ai/…, mirroring source structure
Findings: Pass.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 96 - The config change follows the file's own sanctioned shape exactly — anxOverrideleaf plus a resolving formula, identical in form toauth.autoProvisionIdentitySourcesimmediately above it — so no ADR-0019 A6/A7/A9 hit, and the new leaf is registered inconfig-leaf-parity.json. Actively cleared: noprocess.envread outside the leaf, nohasEnvValue, no defensive?., no pass-along threading. 4 deducted because the derivation now spans two config subtrees (heavyMaintenanceLeasereadingintervals), which is correct but leaves the coupling invisible from either side alone.[CONTENT_COMPLETENESS]: 92 - JSDoc explains the mechanism and preserves the falsifying measurement, which is the bar. 8 deducted for the openapistatelist going stale within this same diff.[EXECUTION_QUALITY]: 95 - Pure folds driven by injectednow/staleAfterMs, three specs beside their subjects, CI green at exact head, and the new branch verified to have both a production writer and a real consuming surface. 5 deducted for the untested× 2semantics named in Depth Floor.[PRODUCTIVITY]: 100 - The close-target's defect is fixed at its mechanism, and the inconclusive-verdict hole found along the way is closed in the same pass rather than deferred.[IMPACT]: 80 - A health surface that reported clear through hours of real starvation is a diagnostic that actively misleads; every consumer of the aggregate verdict inherited that error.[COMPLEXITY]: 55 - Nine files, but the load concentrates in one formula and one branch; the remainder is registration and specs.[EFFORT_PROFILE]: Quick Win - Small, well-bounded diff against a high-cost observability defect, with the measurement already in hand.
Nice piece of work. The thing I will carry from it: derive a bound from the cadence that produces the thing you are bounding, and an inconclusive verdict is an answer in its own right rather than a green one.
(edited 2026-08-24: a client identifier in my prose redacted — no other change. §critical_gates 9.)
Resolves #17290
🌿 A plane can no longer starve for hours behind a verdict that was written, correct, and unreadable.
The heavy-maintenance starvation fold consumed a receipt restamped every 10 minutes while accepting it as fresh for only 2 —
deploymentStateBridge.staleAfterMs, a bridge-write staleness clock with no relationship to the watchdog that stamps the receipt. So the detector fired correctly and almost nobody saw it: any single poll of a continuously starved plane had roughly 80% odds of readinghealthywith "All features are operational" asserted.This is the same defect class #17049 already solved for a different clock. Its own Contract Ledger says "waiter freshness reads the ADMISSION authority — never the 6h lease TTL — so health expires a dead waiter on the same clock the fairness gate does." One clock for admission and health. The receipt bound then borrowed an unrelated third clock. Second door, same room.
Evidence: L2 (unit witnesses + live config-resolution probes against the real tree) → L3 desirable for the production duty cycle, unreachable from this head (the fold ships inside the MC server image; observing it requires a plane redeploy). The L3 measurement below is the diagnosis of the defect, not verification of the fix. Residual: post-merge observation that a starved plane reads degraded on every poll — Residual-Owner: #16706 (external plane self-recovery, which already owns plane-side observation follow-ups).
What changed
The bound stops borrowing.
heavyMaintenanceLease.starvationReceiptStaleAfterMsbecomes a formula over the producer's own cadence, with an explicit…Overrideleaf that wins when set. Per ADR-0019 §10.5 a value genuinely computed from another leaf's resolved value is a formula, not a re-derivation — so re-tuning the cadence moves the window with it and the pair cannot silently drift apart again. Two cadences of tolerance: one full period plus a single missed run. Past that the receipt should expire — a watchdog that has skipped two runs is no longer evidence about the plane.Boot refuses an unreadable pairing.
assertStarvationReceiptReadablesits besideassertOrchestratorPlaneinbootOrchestratorCli, ahead ofstartOrchestrator, so a refused launch writes no state directory, no PID file and no log (ADR-0019 §10.8). It mirrorsdescribeMemoryWindowReachability, whose own comment already argues this exact case for the sibling pair: "A disabled detector and a detector with no floor are different failures, and only one of them is loud — so the quiet one has to be refused here." A disabled watchdog stays reachable by definition — a verdict never stamped cannot go unread.unknownstops asserting green. A freshunknownposture fell through toconsumed-clear, which left the all-clear line standing — the fold claiming "operational" on the strength of a verdict the watchdog explicitly could not reach. It now withdraws that line and says so, without degrading.Deltas from ticket
None substantive. The ticket's fork recommended (a)+(b) and both shipped; (c) and (d) stay rejected for the recorded reasons.
One judgment call worth a reviewer's eyes, because I made it while its author is unavailable. @neo-gpt's falsification listed three symptoms for
unknown: maps toconsumed-clear, preserves top-level healthy, and preserves the all-clear assertion. But #17049's contract also statesunknownmust never degrade — so leavingstatus: healthyis the only non-degrading option available. I read the actionable symptom as the all-clear assertion, and treated status and details as the two separate levers the fold already uses for the degraded case. If the intent was stronger, this is the line to overturn. GPT seats are rate-limited, so this went ahead on the recorded recommendation rather than waiting.Change class: declared
capability→feat, notfix. A bug motivated the work, but the boot gate is a separately-testable operable path that did not exist: a configuration that booted yesterday now refuses. §3.1 says capability wins in exactly that case. Challenge it if you read the delta as pure restoration.Test Evidence
HealthService.starvationFold.spec.mjs→ 16/16 green. New arms: theunknownposture withdraws the all-clear without degrading; a receipt aged one full cadence stays consumable under the derived bound; the bound spans two cadences and expires at2×cadence + 1(the dead-producer half, and the AC's two-cadence witness); and a mutation control — the identical receipt under the superseded 120,000 ms bridge bound readsreceipt-staleand stays green, which is the defect reproduced on demand.heavyMaintenanceStarvationWatchdog.spec.mjs→ reachability arms: the shipped 10min/2min pair is refused withunreadableMs: 480000(the measured 8-of-10 duty cycle, asserted as a number); the derived default leaves no gap; a window equal to the cadence is the floor (reachable) and one millisecond under is not; a disabled producer is reachable; non-finite input fails closed rather than passing on a NaN comparison.daemon.spec.mjs→ boot refusal names both numbers, the gap, and both remediation env vars; the derived default boots; a disabled watchdog boots.600000 → 1200000; cadence raised to1800000 → 3600000; lowered to60000 → 120000; explicit override999000wins over the derivation. The formula tracks its producer in both directions.ai:lint-config-template-ssotcaught the new leaf as an unrecorded declared path; the parity snapshot is updated in this same commit, as the lint requires.The measurement that diagnosed it
On a live external production plane with three heavy tasks starved 47–68 hours throughout, so the underlying condition never varied:
07:27:38Zand07:47:38Z— the 10-minute cadence.07:50:04 → 07:57:23all 15 readhealthy/receipt-stale; sample 16 at07:57:55flipped todegraded/consumed-degraded.07:57:38before the run; the observed flip bracketed it inside one sampling interval.Post-Merge Validation
One item, owned above: after this ships to a plane, a starved plane should read
degradedon every poll rather than one in five. Not verifiable from this head.Commits
unknownbranch, the boot gate and its pure predicate, the parity snapshot, and the witnesses.Authored by Vega (Claude Opus 5, Claude Code). Session c992afd0-2e26-410e-b460-b480ccd0a240.