Skip to content

docs: define the agent change process and in-repo design records - #225

Open
lan17 wants to merge 8 commits into
mainfrom
claude/design-records
Open

lan17 wants to merge 8 commits into
mainfrom
claude/design-records

Conversation

@lan17

@lan17 lan17 commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Problem

Agents open most DialCache pull requests, and the process they follow is spread across AGENTS.md convention bullets, AUTHORING.md, VALIDATION.md, docs/authoring.md and docs/maintainers.md. Design reasoning lives in rewritten issue bodies, a folder on one laptop and Claude memory. Recent cost:

This grew out of an evaluation of OpenSpec. Its specs/ tree would restate what Quint and CONTRACTS.md already define, so this adopts only a change-record convention plus an explicit process, with no CLI.

The review comment on the first draft asked whether every behavior change needs the 2.5 h full run. It does not: 136 of those minutes are the model-fault campaign, which reads only the Quint models, the challenge catalog and the Quint toolchain, so port changes cannot alter its result. The last month had 115 full runs, 63 of them green on commits later superseded, while #190 and #198 broke main with no run at all.

Change

Type: Docs, plus Tooling (the formal workflow and the docs link checker). No design record is needed.

  • AGENTS.md is organized around "Make a change":

    • Classify the change: nine types, each setting the record, the steps and the validation required before the PR leaves draft.
    • Stop at five maintainer gates: design, changed decision, unsettled scope (including requests the repo contradicts), missing validation, irreversible actions.
    • Follow the type's path.
    • Review a PR without approving it.
    • Refresh pinned ledgers, validate the head commit, open the PR as a draft from the template, and finish against a checklist.

    Critical behavior and the conventions stay. The directory tree goes, and the stale claims it carried are corrected.

  • design/README.md and design/TEMPLATE.md set out when a change needs a design record, how to find earlier decisions (searches include PRs), and the lifecycle:

    • Decisions stay Open until the maintainer confirms them.
    • Implementation waits for Accepted.
    • A changed decision keeps its old choice under Rejected.
    • Departures go to Deviations.
  • .github/pull_request_template.md is the description shape AGENTS.md tells agents to fill with --body-file. GitHub never applies templates to gh pr create --body.

  • formal/catalogs/README.md gains "Refresh after an edit": what each ledger pins and the order to refresh them, using the --refresh and --refresh-inputs commands feat(formal): add in-repo ledger refresh commands #228 added. The branch is merged with main through feat(formal): add where.mjs, the contract lookup command #236; each merge's ledger conflict was resolved by taking main's copy and re-keying the three edited guides, three hash lines each time. AGENTS.md and DEVELOPMENT_PROCESS.md point at feat(formal): add where.mjs, the contract lookup command #236's node formal/tools/where.mjs <ID>, which prints where a contract is stated, tested, challenged and mapped: the step the Bug fix path had agents assembling by hand.

  • DEVELOPMENT_PROCESS.md explains the workflow to human readers, with four Mermaid diagrams: how behavior is defined, the life of a change, the design-record lifecycle, and a portable feature from start to finish. It also covers the change types, validation levels, ledgers, what only the maintainer decides, and releasing. It links to AGENTS.md for exact steps, and AGENTS.md requires both to change together. It is not named CONTRIBUTING.md because GitHub shows that file to outside contributors, which would imply a policy for them.

  • CLAUDE.md imports AGENTS.md for Claude Code builds older than v2.1.277, which read only CLAUDE.md.

  • scripts/check-docs.mjs link-checks AGENTS.md, DEVELOPMENT_PROCESS.md and design/README.md.

  • formal-full.yaml gets a mode input, and each mode adds to the one before:

    • replay: generate the corpus and replay it in all four ports. About 8 minutes when the corpus is cached, 17 on a miss.
    • mutations: plus the TypeScript, Go and Rust mutation campaigns. About 50 minutes.
    • full: plus the model checks and the model-fault campaign. About 2.5 hours. The default, and the weekly schedule.

    Lanes a mode does not select are skipped, and the aggregate requires them to be skipped, so a dispatch cannot pass as a stronger mode than it ran. The concurrency group is keyed by ref and mode, so a replay never queues behind a full run.

  • The corpus is cached by an exact hash of every generation input: the models, formal/replay/, formal/tools/, formal/generated/, the catalogs other than the three review ledgers, the committed witness fixtures, the Quint pin, the Makefile and the package manifests. Generation is deterministic in content, so a hit equals a regenerated corpus; no partial key may restore. A branch that adds Quint regressions misses the cache and regenerates, so its histories enter the corpus every port must pass. The weekly run regenerates even on a hit. Committing the corpus was rejected: it is 35 MiB and changes on every model edit, and the 17 smoke histories are already the committed subset.

  • The tiers in the documents: Replay for port, driver and regression-only changes; Mutations when a file a catalogued mutant rewrites, or a mutant catalog, is edited; Full for Quint transitions, invariants or challenges, the kernel library or the Quint toolchain; Full with exploration for a layout move. Exploration is otherwise weekly only. A green run on an earlier commit covers a head whose difference is Markdown files or ledger pins, with PR CI green on the head. VALIDATION.md, AUTHORING.md and maintainers.md say the same, with their ledger pins refreshed.

Open questions

  1. Agent: prefix. Agent-posted issues, comments and reviews begin with Agent:, so approval means "your words, without the prefix". Recommended: keep.
  2. Strict design gate. Implementation waits until the record is Accepted; an agent whose design needs a decision stops after pushing the record. The alternative is implementing in draft at the risk of rework. Recommended: keep the strict gate.
  3. PRs opened before records existed. Unmerged ones, such as feat: add exact-key deletion across all ports #219, get a record, and only their Open decisions stop at the design gate. The alternative is to exempt them. Recommended: records.
  4. No agent signatures in PR descriptions. The rule includes Codex's "— Levicus 🤖", since the description becomes the squash commit body. This follows your recorded rule against the Claude footer. Recommended: keep.
  5. Every bug fix requires a full run. Resolved by the tiers: a bug fix needs Replay (about 8 minutes), Mutations if it edits a mutant's file, Full only if it changes a Quint transition, invariant or challenge.
  6. Length. AGENTS.md is 290 lines and 19 KB, about 5k tokens per session. That is under Codex's 32 KiB budget and Claude's large-file warning, but over the 200-line guideline. The alternative is moving the per-type paths to a separate file, which the design panel scored lower because agents may never open it. Recommended: keep it in one file.

Validation

Head: 788142a (merges of main at 71d44d4 and 5030320, plus the where.mjs pointers)

  • node --test scripts/check-docs.test.mjs at 6490055: 5/5 pass.
  • node scripts/check-docs.mjs at 6490055: 30 pages link-checked; every anchor AGENTS.md, DEVELOPMENT_PROCESS.md and design/README.md link to resolves.
  • corepack pnpm --dir typescript exec vitest run test/formal-validation.test.ts at 6490055: 34/34 pass. The new test pins the mode options, the lane conditions, the exact cache key and restore step id, and the gate line for line; flipping one gate expectation fails it (checked).
  • make audit at 6490055: passes with the refreshed source-audit.json and go-parity.json pins for VALIDATION.md, AUTHORING.md and maintainers.md; after the merge the same three files are re-keyed with check-source-audit.mjs --refresh, and go-parity.json is unchanged because it now binds dispositions.
  • Formal replay 38612947384 (mode replay) at 296eede: green in 17 min 14 s; cache miss, corpus generated and saved; check-models and every mutation lane skipped.
  • Formal replay 38613028985 (mode replay) at 296eede: green in 8 min 16 s from start; cache hit, generate 71 s.
  • Formal replay 38617177083 (mode replay) at 6490055: green in 6 min 11 s; cache hit, generate 36 s; the per-mode concurrency group and the schedule condition parse and run.
  • Formal replay 38651601005 (mode replay) at 8667553: green in 15 min from start; cache miss, because main's kernel header rewrite and tool changes are in the key; the new corpus was saved. It queued behind an earlier replay in the same per-mode group, as designed.
  • Formal replay 38702974816 (mode replay) at 788142a: green in 19 min; cache miss, because main's tool and catalog changes are in the key; the new corpus was saved.
  • make audit (now including feat(formal): measure Quint style and enforce two caps #234's Quint style caps), node scripts/check-docs.mjs (35 pages) and the formal-validation, formal-source-audit, formal-go-parity and formal-style test files at 788142a: 79/79 pass.
  • make audit, node scripts/check-docs.mjs and the formal-validation, formal-source-audit and formal-go-parity test files at 8667553: pass. Two prerequisite-probe tests timed out once at the 5-second default under a load average of 31 from another session and pass with a longer budget; they are unchanged by this PR.
  • Reviews, simulation only: three competing AGENTS.md shapes judged against a rule inventory and a study of agent failures in test(formal): parse the witness corpus once in the completion gates #176–docs: define the agent change process and in-repo design records #225; six simulated agents walked the result through real tasks; a fact-checker verified every claim against the repo and the ruleset; three reviewers checked DEVELOPMENT_PROCESS.md; four reviewers checked the mode and cache change (Actions semantics, cache-key completeness against everything generation reads, policy coherence, test adequacy). Their fixes are in this head.

Not run: mutations and full modes on this branch. This PR changes no port source, model or mutant input, so replay is its tier; the full path is unchanged apart from the per-mode concurrency group and the schedule condition, both exercised by the replay run's parse of the same file.

Follow-ups

Design rationale for DialCache changes has lived in GitHub issue bodies
that are rewritten in place, in a design folder on one laptop, and in
Claude memory. Codex agents, which open about half of recent pull
requests, can see none of the last two, and the edit history of a
rewritten issue is not searchable. Recent examples: #132 shipped the
compression design that #60 had closed as not planned without linking
it; #117's body was rewritten six times; #219 exported
CacheUseCaseOptions against #218's design while #218's decision
checklist stayed unticked.

Add design/ with a README and a template. A record is required before a
new or changed portable contract, a new conformance profile, a redesign
of the conformance machinery, a cross-port or reshaping public API
change, or a reversal of an earlier decision. Decisions stay Open until
a maintainer confirms them, the implementing pull request stays in
draft until then, a changed decision keeps its earlier choice under
Rejected, and departures from the record go to its Deviations section
in the same pull request. Records explain decisions; Quint and the
formal guides remain the definition of behavior.

AGENTS.md gains a structure entry and one convention bullet, since it is
the only instruction every agent reads. design/README.md joins the
relative-link check because it links into formal/guides/; records
themselves are unchecked. No source-audit or go-parity pin changes:
neither ledger covers AGENTS.md, design/ or scripts/.
@codecov-commenter

codecov-commenter commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.73%. Comparing base (5030320) to head (788142a).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #225   +/-   ##
=======================================
  Coverage   93.73%   93.73%           
=======================================
  Files          78       78           
  Lines       11357    11357           
  Branches      656      656           
=======================================
  Hits        10645    10645           
  Misses        642      642           
  Partials       70       70           
Flag Coverage Δ
go 91.12% <ø> (ø)
python 92.08% <ø> (ø)
rust 94.29% <ø> (ø)
typescript 96.56% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Process rules were scattered across AGENTS.md convention bullets,
AUTHORING.md, VALIDATION.md, docs/authoring.md and docs/maintainers.md,
and recent PRs show the cost: #190, #197, #198 and #213 merged without a
full run on their head; Python was left out of guides and checks after
#200; #219 exported a type its design kept private; an agent merged PRs
and agent reviews read like approvals.

Rewrite AGENTS.md around one section, "Make a change": classify the
change by type (each type sets the record, the steps and the validation
required before a PR leaves draft), stop at five maintainer gates, follow
the type's path, refresh pinned ledgers, validate the head commit, open
the PR as a draft from the template, and finish against a checklist.
Agents never submit approving reviews, and agent-posted GitHub text
begins with "Agent:". Critical behavior and the conventions stay; the
directory tree goes, and the stale claims it carried are corrected.

Supporting changes:
- CLAUDE.md imports AGENTS.md for Claude Code builds that do not read
  AGENTS.md natively.
- .github/pull_request_template.md is the description shape AGENTS.md
  tells agents to fill, with Open questions, a port table and per-run
  commits.
- formal/catalogs/README.md gains "Refresh after an edit": what each
  ledger pins and the order to refresh them.
- design/README.md and TEMPLATE.md align with the gates: implementation
  waits for an Accepted record, searches include pull requests, unmerged
  pre-record PRs get records, and confirmations link or quote the
  approval.
- AGENTS.md joins the relative-link check.

None of these files is pinned by a ledger; make audit passes unchanged.
@lan17 lan17 changed the title docs: keep design decisions in in-repo design records docs: define the agent change process and in-repo design records Oct 13, 2026
@lan17
lan17 marked this pull request as draft October 13, 2026 23:45
Comment thread AGENTS.md Outdated
lan17 added 6 commits October 13, 2026 17:03
AGENTS.md is written for agents: exact steps, gates and commands. Add
DEVELOPMENT_PROCESS.md for people who want to understand the workflow
itself: how behavior is defined once in contracts and Quint and replayed
by every port, the life of a change, the three validation levels and why
ledgers exist, the change types, the design-record lifecycle, what only
the maintainer decides, a portable feature end to end, and releasing.
Four Mermaid diagrams render on GitHub; each was checked under Mermaid
11.

The guide links to AGENTS.md as the authoritative rule set instead of
restating commands, and AGENTS.md now says a change to "Make a change"
updates the guide in the same PR. The file is named for its purpose
rather than CONTRIBUTING.md, which GitHub shows to outside contributors
and would imply a policy for them. It joins the relative-link check.
The full formal run takes about two and a half hours, and 136 of those
minutes are the model-fault campaign, which reads only the Quint models,
the challenge catalog and the Quint toolchain. Port changes cannot alter
its result, yet the process asked for the whole run on every behavior
change, so it was skipped (#190, #198 merged with no run) or re-run on
intermediate pushes (63 green runs on superseded commits since September).

Give formal-full.yaml a mode input. replay generates the corpus and
completes every port replay, about 15 minutes. mutations adds the three
port mutation campaigns, about 50 minutes. full, the default and the
weekly schedule, adds check-models with the campaign. Lanes a mode does
not select are skipped, and the aggregate requires them to be skipped,
so a dispatch cannot pass as a stronger mode than it ran. The run name
carries the mode.

The generate job restores .formal-traces from a cache keyed on every
input generation reads: the models, formal/replay, formal/tools,
formal/generated, the catalogs other than the three review ledgers, the
committed witness fixtures, the Quint pin, the Makefile and the lockfile.
Generation is deterministic in content, so an exact key stands for a
regenerated corpus; no partial key may restore. A branch that adds Quint
regressions misses the cache and regenerates, so its histories enter the
corpus that every port must pass.

AGENTS.md, DEVELOPMENT_PROCESS.md, VALIDATION.md and maintainers.md
state the tiers and when each applies: Replay for port, driver and
regression-only changes; Mutations when a catalogued mutant's file is
edited; Full when a transition, invariant, the kernel library or the
Quint toolchain changes. A green run on an earlier commit still covers
a head whose difference is prose, design records or ledger pins. The
workflow-shape test pins the mode options, the lane conditions, the
cache key inputs and each mode's gate; a flipped gate expectation fails
it. The two pinned guides' ledger entries are refreshed.
Review of the mode change found these gaps.

The concurrency group was keyed on the ref alone, so a replay dispatched
while a full run was in progress on the same branch waited for it, up to
two and a half hours. The group now includes the mode; same-mode
dispatches still queue.

The weekly scheduled run regenerates even on a cache hit, so a freshly
installed toolchain re-exports the committed fixtures and vectors once a
week; the save stays skipped when the entry already exists.

A new challenge is measured only by the model-fault campaign, so the Bug
fix row sends a changed challenge to Full. A layout move keeps Full with
exploration, because exploration snapshots the source tree. The mutant
rule reads the same in every document: a file a catalogued mutant
rewrites, or a mutant catalog. The carry-over rule names Markdown files
and ledger pins instead of "prose". maintainers.md, VALIDATION.md and
AUTHORING.md no longer require full validation for every behavior change.

The workflow-shape test pins the cache key and the restore step id
exactly, and the gate line for line, so an added exclusion, a
non-hashFiles key component or a loosened arm fails it.
# Conflicts:
#	formal/catalogs/go-parity.json
#	formal/catalogs/source-audit.json
# Conflicts:
#	formal/catalogs/source-audit.json
#236 added formal/tools/where.mjs, which prints where one contract is
stated, tested, challenged and mapped. That is the navigation the Bug
fix path and the formal convention in AGENTS.md asked agents to assemble
by hand, so both name the command, and DEVELOPMENT_PROCESS.md lists it
under Where to look.
@lan17
lan17 marked this pull request as ready for review October 15, 2026 08:10

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants