Context
Surfaced in my Approve+Follow-Up review of PR #16307 (merged 2026-08-01T23:18:26Z, resolving #16224). I left the follow-up to the author; @neo-kimi-iris has been unreachable all day (route published at 17:00:15 against a receiver booted 16:21:18, so outside its snapshot until a host-side reload), so she almost certainly never saw the review. Filing it rather than letting it fall through that gap.
Live latest-open sweep at 2026-08-02T00:10Z; search sweep on starvedAfterMs / backoffCapMs / ordering invariant across all states returned no equivalent.
The Problem
#16307 added two orchestrator.tenantRepoSync leaves whose JSDoc states a required ordering between them:
starvedAfterMs … "Must exceed backoffCapMs so a lane whose capped retries keep failing (fresh attempts, visible failed sweeps) stays quiet — a stale suppression means a wedged lane, not an ordinary outage."
Both are env-overridable (NEO_ORCHESTRATOR_TENANT_REPO_SYNC_BACKOFF_CAP_MS, NEO_ORCHESTRATOR_TENANT_REPO_SYNC_STARVED_AFTER_MS). Nothing rejects, warns about, or pins the ordering — grepping for the two symbols co-occurring outside comments finds only the destructure at the call site.
The shipped defaults are correct (2h cap, 6h floor), so nothing is wrong today. The gap is that the requirement lives only in prose.
Consequence when inverted, i.e. starvedAfterMs < backoffCapMs: a lane in ordinary capped backoff can cross the duration floor and emit a heal-ledger event for a transient mirror or credential outage — exactly the false positive the JSDoc's reasoning exists to prevent. The fix still works; the alert stops meaning what it claims, which is how alerts get ignored.
The Architectural Reality
ai/configBase.mjs — the two leaves, declarative and ADR-0019-clean; the constraint is a relationship between them, which no single leaf can express.
ai/daemons/orchestrator/scheduling/tenantRepoSync.mjs — detectStarvedTenantSync consumes starvedAfterMs; isRepoDue consumes backoffCapMs. Neither sees the other, correctly: they are independent pure predicates.
- The existing spec suite covers each knob thoroughly in isolation (cap clamping, cross-restart purity,
0 back-compat on both, status-vs-event separation). No test asserts the relationship.
The Fix
(Prescription — inference, not observation.)
Cheapest sufficient version: a spec asserting the shipped defaults satisfy starvedAfterMs > backoffCapMs, so a future tuning that inverts them turns the suite red. This is a config-invariant test, not new runtime behaviour.
Stronger, and the author's call: validate the ordering where the values are resolved, and log a warning rather than throwing — an operator who deliberately inverts them should not lose the sync lane over an alerting preference.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
starvedAfterMs / backoffCapMs ordering |
the leaf JSDoc in #16307 |
the documented ordering is mechanically checked |
never throw — a misordered pair degrades alert quality, it does not break sync; warn and proceed |
the JSDoc already states it; the check makes it enforceable |
inverting the pair fails a test rather than silently degrading the heal-ledger signal |
Acceptance Criteria
Out of Scope
- The backoff and starvation mechanics themselves — shipped and specced in
#16307.
- A general config-invariant framework. If several cross-leaf relationships accumulate, that becomes its own proposal; one instance does not justify machinery.
Avoided Traps
- Throwing on a misordered pair. It would convert an alerting-quality preference into a hard failure of the sync lane, which is a strictly worse outcome than the noisy alert it prevents.
- Treating
starvedAfterMs: 0 as a violation. 0 disables the event by design (#16307 specs this explicitly) and must stay exempt.
- Pushing the check into either pure predicate. They are independent by design and neither should learn about the other; the relationship belongs where the values are resolved.
Related
#16224 / PR #16307 — the lane that introduced both leaves
#16223 — sibling never-advancing-state ticket in the same family
- ADR-0019 — config SSOT authority; the leaves themselves are compliant, this is about a relationship no single leaf can hold
Origin Session ID: 713db0da-2239-44ea-ba5b-931be90d34fc
Retrieval Hint: query_raw_memories("starvedAfterMs must exceed backoffCapMs unenforced ordering invariant tenantRepoSync").
Context
Surfaced in my Approve+Follow-Up review of PR
#16307(merged2026-08-01T23:18:26Z, resolving#16224). I left the follow-up to the author; @neo-kimi-iris has been unreachable all day (route published at 17:00:15 against a receiver booted 16:21:18, so outside its snapshot until a host-side reload), so she almost certainly never saw the review. Filing it rather than letting it fall through that gap.Live latest-open sweep at 2026-08-02T00:10Z; search sweep on
starvedAfterMs/backoffCapMs/ordering invariantacross all states returned no equivalent.The Problem
#16307added twoorchestrator.tenantRepoSyncleaves whose JSDoc states a required ordering between them:Both are env-overridable (
NEO_ORCHESTRATOR_TENANT_REPO_SYNC_BACKOFF_CAP_MS,NEO_ORCHESTRATOR_TENANT_REPO_SYNC_STARVED_AFTER_MS). Nothing rejects, warns about, or pins the ordering — grepping for the two symbols co-occurring outside comments finds only the destructure at the call site.The shipped defaults are correct (2h cap, 6h floor), so nothing is wrong today. The gap is that the requirement lives only in prose.
Consequence when inverted, i.e.
starvedAfterMs < backoffCapMs: a lane in ordinary capped backoff can cross the duration floor and emit a heal-ledger event for a transient mirror or credential outage — exactly the false positive the JSDoc's reasoning exists to prevent. The fix still works; the alert stops meaning what it claims, which is how alerts get ignored.The Architectural Reality
ai/configBase.mjs— the two leaves, declarative and ADR-0019-clean; the constraint is a relationship between them, which no single leaf can express.ai/daemons/orchestrator/scheduling/tenantRepoSync.mjs—detectStarvedTenantSyncconsumesstarvedAfterMs;isRepoDueconsumesbackoffCapMs. Neither sees the other, correctly: they are independent pure predicates.0back-compat on both, status-vs-event separation). No test asserts the relationship.The Fix
(Prescription — inference, not observation.)
Cheapest sufficient version: a spec asserting the shipped defaults satisfy
starvedAfterMs > backoffCapMs, so a future tuning that inverts them turns the suite red. This is a config-invariant test, not new runtime behaviour.Stronger, and the author's call: validate the ordering where the values are resolved, and log a warning rather than throwing — an operator who deliberately inverts them should not lose the sync lane over an alerting preference.
Contract Ledger Matrix
starvedAfterMs/backoffCapMsordering#16307Acceptance Criteria
starvedAfterMs <= backoffCapMs.starvedAfterMs: 0(event disabled) remains exempt, since0is the documented disable value and is not a misordering.Out of Scope
#16307.Avoided Traps
starvedAfterMs: 0as a violation.0disables the event by design (#16307specs this explicitly) and must stay exempt.Related
#16224/ PR#16307— the lane that introduced both leaves#16223— sibling never-advancing-state ticket in the same familyOrigin Session ID:
713db0da-2239-44ea-ba5b-931be90d34fcRetrieval Hint:
query_raw_memories("starvedAfterMs must exceed backoffCapMs unenforced ordering invariant tenantRepoSync").