Context
One morning (2026-06-12, the v13 publish-hold window) produced three completeness-gate frictions, each costing real review cycles. This ticket absorbs all three into the substrate that should have prevented them — the friction → gold unit for the day.
(a) Reviewer-prescribed close-target downgrades are mechanically un-greenable. Cycle-1 reviews on PR #12971 and PR #12979 prescribed downgrading Resolves #N → Refs #N (close-target hygiene: the PRs didn't deliver every AC). But agent-pr-body-lint enforces the operator rule (#12367): Resolves #N is the mandatory closing keyword — Refs/Related alone can never pass. Both PRs went red; the reviewer parked blocked; diagnosis was non-obvious (a stale event-payload twin run passed, making a rerun look like the fix — actions/github-script lints the frozen context.payload.pull_request.body snapshot, so the failing run was the truthful one). Resolution took 2 extra author cycles: ticket re-scopes/splits + Resolves restoration. The linter's own comment block names the sanctioned shape ("a ticket that needs N PRs… must become an epic + subs or be split") — but the pr-review payload never tells the reviewer side, so reviewers keep prescribing the forbidden shape.
(b) Consumed-surface tickets are born Ledger-less; every one costs a yield round-trip. Four intake yields in one morning — #12951, #12957, #12884, #12931 — all "blocked until the ticket carries a Contract Ledger", plus a REQUEST_CHANGES cycle (PR #12979 cycle-3 → #12969 Ledger backfill, then instant approval). ticket-create-workflow.md §5 lists the Contract Ledger Matrix as "(when applicable)" with no applicability test — the trigger is too weak to fire at authoring time, so the cost lands downstream at intake/review instead.
(c) The gitlab-pat healthcheck seam is charted nowhere canonical. The first deployment ever to run NEO_AUTH_MODE=gitlab-pat (a private remote stack, 2026-06-12) discovered: setupGitlabPat installs app.use(requireBearerAuth(...)) app-wide with no exemption (ai/mcp/server/shared/services/AuthService.mjs:230), and the in-container healthchecks send no bearer unless NEO_MCP_HEALTHCHECK_TOKEN is set (ai/scripts/diagnostics/mcpHealthcheck.mjs:39,50,69-70) → every probe 401s → kb/mc never reach service_healthy → orchestrator depends_on conditions never satisfy → a fresh docker compose up structurally never completes. Found at review time (fix: a 2-line env passthrough), but only because the reviewer traced the full chain — ai/deploy/docker-compose.yml never sets NEO_AUTH_MODE, so the canonical compose silently doesn't chart the seam for the next bearer-mode deployment.
The Architectural Reality
.github/workflows/agent-pr-body-lint.yml:71-92 — the Resolves mandate + the split prescription (authoritative, already correct; NOT touched here).
.agents/skills/pr-review/references/pr-review-guide.md — the close-target / Contract-Completeness audit sections; read-on-demand payload (not turn-loaded).
.agents/skills/ticket-create/references/ticket-create-workflow.md §5 — the Contract Ledger Matrix bullet; same payload tier.
ai/deploy/docker-compose.yml:75-80,133-138 — the kb/mc healthcheck blocks (no auth-mode seam note).
learn/agentos/process/contract-ledger.md — the Ledger discipline doc the trigger should point at.
The Fix
Three line-level additions, one PR:
- pr-review-guide.md (close-target section, ≤4 lines): when a PR over-claims its close target, the reviewer prescription is "split/re-scope the ticket so
Resolves stays honest" — never "downgrade to bare Refs", which agent-pr-body-lint mechanically rejects (rule #12367). Include the stale-snapshot note: a passing duplicate lint run on an edited body may be linting the pre-edit event payload; the fix is a body/ticket fix, not a rerun.
- ticket-create-workflow.md §5 (≤3 lines): replace the bare "(when applicable)" with the applicability test — "if the ticket introduces, modifies, or removes ANY surface another human, agent, or system consumes (tool answer shapes, configs/env, lifecycle scripts, public methods, docs flows), the Ledger is REQUIRED at creation; a consumed-surface ticket filed without one will be intake-yielded back" — citing the 2026-06-12 four-yield day as the empirical anchor.
- ai/deploy/docker-compose.yml (≤4-line comment on each of the two healthcheck blocks): if this deployment enables
NEO_AUTH_MODE=gitlab-pat, the self-probes must authenticate — set NEO_MCP_HEALTHCHECK_TOKEN (consumed by mcpHealthcheck.mjs) or the container never reaches service_healthy and dependent services never start.
Contract Ledger
| # |
Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
| 1 |
pr-review-guide.md close-target audit (agent-consumed review payload) |
agent-pr-body-lint.yml:71-92 (rule #12367) |
reviewers prescribe split/re-scope, never bare-Refs |
none needed — additive guidance |
the payload IS the doc |
PR #12971 + PR #12979 cycle history, 2026-06-12 |
| 2 |
ticket-create-workflow.md §5 Ledger bullet (agent-consumed creation payload) |
learn/agentos/process/contract-ledger.md + intake-gate practice |
"(when applicable)" → explicit consumed-surface applicability test |
none — additive |
same |
yields on #12951/#12957/#12884/#12931 + #12969 backfill cycle |
| 3 |
ai/deploy/docker-compose.yml healthcheck blocks (operator-consumed deploy reference) |
AuthService.mjs:230 + mcpHealthcheck.mjs:39,50 |
comment charts the bearer-gate/self-probe seam + the token env |
none — comment only |
compose comment |
the 2026-06-12 remote-deployment review finding (fix verified: token passthrough + docker compose config exit 0) |
Decision Record impact
none (read-on-demand payload prose + compose comments; no gates, no loaded-byte growth, no behavior change).
Substrate Accretion Defense
All three additions live in read-on-demand surfaces (no turn-loaded growth; lint-skill-manifest byte budgets unaffected — no SKILL.md router edits). Decay dispositions: row 1 retires if the linter ever grows an explicit no-close exemption anchor; row 2 retires if Ledger validation becomes a mechanical create-time lint; row 3 retires if requireBearerAuth gains a loopback/health exemption upstream. Implementer note: per the compaction taxonomy gate, read learn/agentos/decisions/0007-agents-md-compaction-taxonomy.md before editing the skill payloads.
Acceptance Criteria
Out of Scope
- Changing
agent-pr-body-lint.yml itself (it is correct; this charts it for reviewers).
- New mechanical gates (create-time Ledger linting is a possible successor, deliberately not this ticket).
- An
AuthService loopback/health exemption (weakens the gate; the token route is the supported shape).
- The private deployment's own repo (fixed there already at review time).
Related
#12367 (the Resolves operator rule), #12969/PR #12979 + #12970/PR #12971 (the collision pair), #12951/#12957/#12884/#12931 (the yield quartet), #12983 (sibling ai/deploy compose wiring lane), PR #12960 (the freshness-gate substrate precedent for payload-tier additions).
Release classification: post-release (process/doc substrate; nothing release-blocking).
Live latest-open sweep: checked latest 20 open issues at 2026-06-12T11:35Z + re-checked latest 10 at 11:39Z; no equivalent found. A2A in-flight sweep (last 60 min, all read-states): no competing claim on this scope.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "close-target split Refs downgrade lint collision Contract Ledger trigger healthcheck bearer gate seam"
Context
One morning (2026-06-12, the v13 publish-hold window) produced three completeness-gate frictions, each costing real review cycles. This ticket absorbs all three into the substrate that should have prevented them — the friction → gold unit for the day.
(a) Reviewer-prescribed close-target downgrades are mechanically un-greenable. Cycle-1 reviews on PR #12971 and PR #12979 prescribed downgrading
Resolves #N→Refs #N(close-target hygiene: the PRs didn't deliver every AC). Butagent-pr-body-lintenforces the operator rule (#12367):Resolves #Nis the mandatory closing keyword —Refs/Relatedalone can never pass. Both PRs went red; the reviewer parked blocked; diagnosis was non-obvious (a stale event-payload twin run passed, making a rerun look like the fix —actions/github-scriptlints the frozencontext.payload.pull_request.bodysnapshot, so the failing run was the truthful one). Resolution took 2 extra author cycles: ticket re-scopes/splits +Resolvesrestoration. The linter's own comment block names the sanctioned shape ("a ticket that needs N PRs… must become an epic + subs or be split") — but the pr-review payload never tells the reviewer side, so reviewers keep prescribing the forbidden shape.(b) Consumed-surface tickets are born Ledger-less; every one costs a yield round-trip. Four intake yields in one morning —
#12951,#12957,#12884,#12931— all "blocked until the ticket carries a Contract Ledger", plus a REQUEST_CHANGES cycle (PR #12979 cycle-3 →#12969Ledger backfill, then instant approval).ticket-create-workflow.md§5 lists the Contract Ledger Matrix as "(when applicable)" with no applicability test — the trigger is too weak to fire at authoring time, so the cost lands downstream at intake/review instead.(c) The gitlab-pat healthcheck seam is charted nowhere canonical. The first deployment ever to run
NEO_AUTH_MODE=gitlab-pat(a private remote stack, 2026-06-12) discovered:setupGitlabPatinstallsapp.use(requireBearerAuth(...))app-wide with no exemption (ai/mcp/server/shared/services/AuthService.mjs:230), and the in-container healthchecks send no bearer unlessNEO_MCP_HEALTHCHECK_TOKENis set (ai/scripts/diagnostics/mcpHealthcheck.mjs:39,50,69-70) → every probe 401s → kb/mc never reachservice_healthy→ orchestratordepends_onconditions never satisfy → a freshdocker compose upstructurally never completes. Found at review time (fix: a 2-line env passthrough), but only because the reviewer traced the full chain —ai/deploy/docker-compose.ymlnever setsNEO_AUTH_MODE, so the canonical compose silently doesn't chart the seam for the next bearer-mode deployment.The Architectural Reality
.github/workflows/agent-pr-body-lint.yml:71-92— theResolvesmandate + the split prescription (authoritative, already correct; NOT touched here)..agents/skills/pr-review/references/pr-review-guide.md— the close-target / Contract-Completeness audit sections; read-on-demand payload (not turn-loaded)..agents/skills/ticket-create/references/ticket-create-workflow.md§5 — the Contract Ledger Matrix bullet; same payload tier.ai/deploy/docker-compose.yml:75-80,133-138— the kb/mc healthcheck blocks (no auth-mode seam note).learn/agentos/process/contract-ledger.md— the Ledger discipline doc the trigger should point at.The Fix
Three line-level additions, one PR:
Resolvesstays honest" — never "downgrade to bareRefs", whichagent-pr-body-lintmechanically rejects (rule#12367). Include the stale-snapshot note: a passing duplicate lint run on an edited body may be linting the pre-edit event payload; the fix is a body/ticket fix, not a rerun.NEO_AUTH_MODE=gitlab-pat, the self-probes must authenticate — setNEO_MCP_HEALTHCHECK_TOKEN(consumed bymcpHealthcheck.mjs) or the container never reachesservice_healthyand dependent services never start.Contract Ledger
pr-review-guide.mdclose-target audit (agent-consumed review payload)agent-pr-body-lint.yml:71-92(rule#12367)ticket-create-workflow.md§5 Ledger bullet (agent-consumed creation payload)learn/agentos/process/contract-ledger.md+ intake-gate practice#12951/#12957/#12884/#12931+#12969backfill cycleai/deploy/docker-compose.ymlhealthcheck blocks (operator-consumed deploy reference)AuthService.mjs:230+mcpHealthcheck.mjs:39,50docker compose configexit 0)Decision Record impact
none (read-on-demand payload prose + compose comments; no gates, no loaded-byte growth, no behavior change).
Substrate Accretion Defense
All three additions live in read-on-demand surfaces (no turn-loaded growth;
lint-skill-manifestbyte budgets unaffected — no SKILL.md router edits). Decay dispositions: row 1 retires if the linter ever grows an explicit no-close exemption anchor; row 2 retires if Ledger validation becomes a mechanical create-time lint; row 3 retires ifrequireBearerAuthgains a loopback/health exemption upstream. Implementer note: per the compaction taxonomy gate, readlearn/agentos/decisions/0007-agents-md-compaction-taxonomy.mdbefore editing the skill payloads.Acceptance Criteria
NEO_MCP_HEALTHCHECK_TOKENseam comment (both kb + mc).lint-skill-manifest+lint-pr-bodygreen on the PR.Out of Scope
agent-pr-body-lint.ymlitself (it is correct; this charts it for reviewers).AuthServiceloopback/health exemption (weakens the gate; the token route is the supported shape).Related
#12367(the Resolves operator rule),#12969/PR #12979 +#12970/PR #12971 (the collision pair),#12951/#12957/#12884/#12931(the yield quartet),#12983(sibling ai/deploy compose wiring lane), PR #12960 (the freshness-gate substrate precedent for payload-tier additions).Release classification:post-release (process/doc substrate; nothing release-blocking).Live latest-open sweep: checked latest 20 open issues at 2026-06-12T11:35Z + re-checked latest 10 at 11:39Z; no equivalent found. A2A in-flight sweep (last 60 min, all read-states): no competing claim on this scope.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "close-target split Refs downgrade lint collision Contract Ledger trigger healthcheck bearer gate seam"