Skip to content

Commit a0879ba

Browse files
Align read-first prose with the contract's agent_read_order
The runtime contract (contract --json → agent_read_order), llms.txt, AGENTS.md, .well-known, and docs/agent-contract-current.md § Two read entry points all name agent-handoff.json as the first artifact a coding agent reads after verify — but README told agents "read verifier.json first" in two places (the Verify-first quickstart and the copy-into- your-agent block) while telling them "read agent-handoff.json.gate. merge_verdict first" a few lines later, and the "What it produces" list claimed "in read order" with verifier.json ahead of the handoff. The /shipgate slash command carried the same stale sentence. Fix the three README spots and the slash command to lead with agent-handoff.json (gate.merge_verdict, then controller) and present verifier.json as the authoritative controller substrate, matching the contract doc's language. No field or artifact semantics change. Guard: new test_read_first_instructions_match_contract_agent_read_order in tests/test_public_surface_contract.py pins every "Read `<artifact>` first" instruction on README.md, AGENTS.md, llms.txt, and .claude/commands/shipgate.md to the runtime contract's agent_read_order[0], so the two orderings cannot ship simultaneously again. Verified to fail on the old verifier-first phrasing. (.well-known's machine-readable agent_read_order and primary_commands were already contract-validated by existing tests in this file.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 3fe7bd2 commit a0879ba

3 files changed

Lines changed: 64 additions & 13 deletions

File tree

.claude/commands/shipgate.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,10 @@ permissions, policies, CI gates, or `shipgate.yaml`, run the verifier:
7070
agents-shipgate verify --base origin/main --head HEAD --json
7171
```
7272

73-
Read `agents-shipgate-reports/verifier.json` first and lead with `merge_verdict`
74-
(a deterministic projection of `release_decision.decision`, which remains the
75-
gate in `report.json`), then `capability_changes[]`. Do not claim completion when
73+
Read `agents-shipgate-reports/agent-handoff.json` first and lead with
74+
`gate.merge_verdict` (a deterministic projection of `release_decision.decision`,
75+
which remains the gate in `report.json`), then the authoritative substrate
76+
`agents-shipgate-reports/verifier.json` and `capability_changes[]`. Do not claim completion when
7677
`merge_verdict` is `blocked`, `insufficient_evidence`, or
7778
`human_review_required` unless the user accepted the human-review requirement, and
7879
never weaken `shipgate.yaml`, Shipgate CI, `AGENTS.md`, policies, baselines, or

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,11 @@ The release gate is `agents-shipgate-reports/report.json` →
189189
The PR/controller surface is `agents-shipgate-reports/verifier.json`
190190
`merge_verdict` (`mergeable | human_review_required | insufficient_evidence |
191191
blocked | unknown`), a deterministic projection of the release decision. Read
192-
`verifier.json` first for `merge_verdict`, `applicability`,
193-
`agent_controller`, `can_merge_without_human`, `first_next_action`, and
194-
`fix_task`. `capability_review.top_changes` is supporting/provisional reviewer
195-
context.
192+
`agent-handoff.json` first (`gate.merge_verdict`, then `controller`), then the
193+
authoritative controller substrate `verifier.json` for `merge_verdict`,
194+
`applicability`, `agent_controller`, `can_merge_without_human`,
195+
`first_next_action`, and `fix_task`. `capability_review.top_changes` is
196+
supporting/provisional reviewer context.
196197

197198
Zero-setup demos of both verdicts are in
198199
[60 seconds](#60-seconds-watch-it-block-two-prs) above; `uvx` runs them with no
@@ -278,10 +279,11 @@ For local control, parse the `shipgate check` stdout JSON
278279
`repair`, and `policy`. For local uncommitted verify work,
279280
omit `--base`/`--head`. For committed PR/CI refs,
280281
make the base ref available first because `verify` never fetches. Read
281-
`agents-shipgate-reports/verifier.json` first and lead with `merge_verdict`,
282-
`applicability`, `agent_controller`, `can_merge_without_human`,
283-
`first_next_action`, and `fix_task`, then read supporting/provisional
284-
`capability_review.top_changes` and
282+
`agents-shipgate-reports/agent-handoff.json` first and lead with
283+
`gate.merge_verdict` and `controller`, then read the authoritative substrate
284+
`agents-shipgate-reports/verifier.json` (`merge_verdict`, `applicability`,
285+
`agent_controller`, `can_merge_without_human`, `first_next_action`,
286+
`fix_task`), then supporting/provisional `capability_review.top_changes` and
285287
`agents-shipgate-reports/report.json` for `release_decision.decision`. Do not
286288
claim completion when `merge_verdict` is `blocked`, `insufficient_evidence`, or
287289
`human_review_required` unless the user explicitly accepts human review. Do not auto-assert approval. Do not auto-assert confirmation, idempotency,
@@ -486,8 +488,8 @@ and pre-commit equivalents.
486488
When a PR changes what your agent can do, the verify loop writes these
487489
artifacts — in read order:
488490

489-
- **`agents-shipgate-reports/verifier.json`** — the **primary PR/controller evidence artifact**. A coding agent reads `merge_verdict` (`mergeable | human_review_required | insufficient_evidence | blocked | unknown`), `can_merge_without_human`, `agent_controller`, `first_next_action`, and `fix_task` when producing reviewer evidence for an agent-capability PR. Local control comes from `shipgate check --format codex-boundary-json` and `shipgate.codex_boundary_result/v1`. See [`docs/agent-contract-current.md`](docs/agent-contract-current.md) for the field contract.
490-
- **`agents-shipgate-reports/agent-handoff.json`** — the compact `shipgate.agent_handoff/v1` object for coding agents. It projects `gate`, `controller`, `blocked_by[]`, `remediation_plan[]`, and verify-run reproducibility from existing artifacts; it does not introduce a second verdict.
491+
- **`agents-shipgate-reports/agent-handoff.json`** — the **first artifact a coding agent reads**: the compact `shipgate.agent_handoff/v1` object. Lead with `gate.merge_verdict`, then `controller`; it also projects `blocked_by[]`, `remediation_plan[]`, and verify-run reproducibility from existing artifacts, and it does not introduce a second verdict.
492+
- **`agents-shipgate-reports/verifier.json`** — the **authoritative PR/controller evidence substrate**. A coding agent reads `merge_verdict` (`mergeable | human_review_required | insufficient_evidence | blocked | unknown`), `can_merge_without_human`, `agent_controller`, `first_next_action`, and `fix_task` when producing reviewer evidence for an agent-capability PR. Local control comes from `shipgate check --format codex-boundary-json` and `shipgate.codex_boundary_result/v1`. See [`docs/agent-contract-current.md`](docs/agent-contract-current.md) for the field contract.
491493
- **`agents-shipgate-reports/verify-run.json`** — the deterministic verify-run reproducibility artifact. It records stable subject/input hashes, policy-pack hashes, outcome, artifact paths, and `run_id` without wall-clock timestamps.
492494
- **`agents-shipgate-reports/attestation.json`** + **`agents-shipgate-reports/org-evidence-bundle.json`** — optional organization-governance projections over the same verifier/report artifacts. They are ledger inputs for platform teams, not release gates; `report.json.release_decision.decision` remains the decision engine.
493495
- **`agents-shipgate-reports/host-grants.json`** + **`agents-shipgate-reports/org-status.json`** — optional fleet-governance artifacts from `audit --host --out` and `org status --json`, useful for host-grant drift, policy-pack pin state, and exception hygiene.

tests/test_public_surface_contract.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,3 +2348,51 @@ def test_no_singular_underscore_module_name(relpath):
23482348
f"{relpath}:{line} uses singular `agent_shipgate`; the "
23492349
f"correct Python module is `agents_shipgate` (plural)."
23502350
)
2351+
2352+
2353+
# ---------------------------------------------------------------------------
2354+
# Read-first artifact vs the runtime contract's agent_read_order
2355+
# ---------------------------------------------------------------------------
2356+
2357+
READ_FIRST_PATTERN = re.compile(r"[Rr]ead\s+`([^`]+)`\s+first")
2358+
# Prose surfaces that tell a coding agent which verify artifact to read
2359+
# first. .well-known/agents-shipgate.json carries the machine-readable
2360+
# agent_read_order (validated against the contract elsewhere in this
2361+
# file); these are the human/agent prose mirrors of that order.
2362+
READ_FIRST_SURFACES = (
2363+
"README.md",
2364+
"AGENTS.md",
2365+
"llms.txt",
2366+
".claude/commands/shipgate.md",
2367+
)
2368+
2369+
2370+
@pytest.mark.parametrize("relpath", READ_FIRST_SURFACES)
2371+
def test_read_first_instructions_match_contract_agent_read_order(relpath):
2372+
"""Every 'Read `<artifact>` first' instruction must name the first
2373+
artifact in the runtime contract's agent_read_order (agent-handoff.json
2374+
since contract v7), optionally with a reports-dir prefix or a field
2375+
path suffix. README shipped both 'read verifier.json first' and
2376+
'read agent-handoff.json first' simultaneously until v0.14.x; this
2377+
pins the prose surfaces to the contract so the contradiction cannot
2378+
return. verifier.json stays the authoritative controller substrate —
2379+
mentioning it is fine, telling an agent to read it *first* is not."""
2380+
contract = build_contract_payload().model_dump(mode="json")
2381+
first_artifact = contract["agent_read_order"][0]
2382+
assert first_artifact == "agent-handoff.json", (
2383+
"contract agent_read_order[0] changed; sweep the read-first "
2384+
"prose on READ_FIRST_SURFACES, then update this pin."
2385+
)
2386+
text = _read(relpath)
2387+
matches = READ_FIRST_PATTERN.findall(text)
2388+
assert matches, (
2389+
f"{relpath} no longer contains a 'Read `<artifact>` first' "
2390+
"instruction. Either restore one naming "
2391+
f"{first_artifact} or drop the surface from READ_FIRST_SURFACES."
2392+
)
2393+
for artifact in matches:
2394+
assert first_artifact in artifact, (
2395+
f"{relpath} tells an agent to read {artifact!r} first; the "
2396+
f"contract's agent_read_order starts with {first_artifact!r} "
2397+
"(see docs/agent-contract-current.md § Two read entry points)."
2398+
)

0 commit comments

Comments
 (0)