Skip to content

docs(agents): record §5 of the conventions spec, and the markdown line-width call - #388

Merged
derek73 merged 5 commits into
masterfrom
docs/conventions-gap
Aug 17, 2026
Merged

docs(agents): record §5 of the conventions spec, and the markdown line-width call#388
derek73 merged 5 commits into
masterfrom
docs/conventions-gap

Conversation

@derek73

@derek73 derek73 commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Documentation only — AGENTS.md, docs/design/, and a new
.git-blame-ignore-revs. Five commits, the last two of which correct
claims the first three made.

§5 — stage contract docstrings

The 2026-07-11 v2 implementation-conventions spec fixed nine sections
before the first line of the rewrite. Its own header attests:

the durable subset … gets distilled into AGENTS.md … (Done
2026-07-12 … as a "2.0 API modules" section covering §1–§4,
§6–§9
)

That range reads as exhaustive unless you notice §5 is missing from
the middle of it
. It is the one section that never reached a
committed home, and #381's spec-residue sweep didn't catch it —
plausibly for the same reason, since a sweep reading that header ticks
the spec off as distilled. A false attestation defeats an audit more
thoroughly than no attestation, because it turns the audit into a
lookup.

The convention was followed anyway — all eight pipeline stages carry
the Consumes: / Produces: / Reads: docstring, and _pipeline/
modules that are not stages say so in their first line instead. So it
was load-bearing and unenforceable at once.

Corrected in review (thanks — all three were wrong):

  • It cited rules.md as naming the stages. rules.md forbids exactly
    that in its own preamble: "Statements are implementation-free: no
    stage names, no function names, no regexes."
  • It leaned on implemented:, which names modules honoring a rule —
    many-to-many, and carries no stage naming.
  • It said "all nine stages". There are eight; the ninth module is
    _assemble, which the same sentence called not-a-stage.

The real authority is _pipeline/__init__.py's STAGES plus the
field-ownership map in ParseState's docstring, pinned by
tests/v2/pipeline/test_state.py. §5 originally pointed at the core
API spec, which is gitignored — so the distillation needed a new
anchor and I reached for the nearest normative-sounding document
rather than the correct one.

Markdown line width, and the rewrap

Measured: wrapped and unwrapped render identically, docs/design/ is
not in the Sphinx build, and unwrapping is byte-identical
(newline→space is 1:1). No rendering, build, size or token difference
exists. The cost is one-sided — 74% of the deleted words in #386's
decisions.md diff were reflow, not change.

All five documents are now unwrapped in one whitespace-only commit:

AGENTS.md                          531 → 375 lines
docs/design/decisions.md          1457 → 513
docs/design/mechanisms.md          575 → 154
docs/design/rules.md               828 → 675
docs/design/nameparser-2.0-rfc.md  305 → 160

Content verified identical after whitespace collapse, checked against
HEAD rather than trusting the rewrapper's own claim.

rules.md's rule bodies stay wrapped. A rule block is a record
format — 4-space statement prose above 6-space example lines that
align into a scannable unit — so it sits with tables and code fences,
which the rewrapper skips. Its example and pointer lines are parsed
per line and could not have been joined regardless; the 233 doc tests
pass on the result.

Two claims the rewrap falsified

Both were in the justification I wrote for advising against a bulk
rewrap, and both were assumptions:

  • "It resets git blame." Measured: 43 lines of 1717 (~2.5%).
    Git's diff maps most joined lines back to whichever commit wrote
    their opening text.
  • ".git-blame-ignore-revs fixes that." It recovers none of
    the 43. Misconfiguration ruled out — file well-formed, correct full
    SHA, identical counts with and without. --ignore-revs-file
    re-attributes a line by finding it in the parent, and a line made by
    merging five lines has no counterpart there.

The file is kept as the right home for future format-only commits that
map 1:1, and its header says plainly that it does nothing for this one.

Verification

uv run --frozen pytest — 3459 passed, 20 skipped, 11 xfailed, green
at every commit.

🤖 Generated with Claude Code

Two conventions that were live but unwritten.

**Stage contract docstrings (§5).** The 2026-07-11 v2 implementation
conventions spec fixed nine sections before the first line of code.
Its own header attests to distilling "§1–§4, §6–§9" into this file on
2026-07-12 — a range that reads as exhaustive unless you notice §5
missing from the middle of it. §5 is the one section that never
reached a committed home, and the 2026-08-16 spec-residue sweep
(#381) did not catch it, most likely for the same reason.

It has been followed anyway: all nine pipeline stages carry the
Consumes:/Produces:/Reads: docstring, and the two _pipeline/ modules
that are not stages say so in their first line instead. So the
convention was load-bearing and unenforceable at once — a new stage
could have omitted it and no reviewer would have had grounds. Now
recorded, including that the absence of the three lines is itself a
claim about the module.

**Markdown line width.** Measured rather than argued: wrapped and
unwrapped markdown render identically, docs/design/ is not in the
Sphinx build, and unwrapping is byte-identical since newline→space is
1:1 — so no rendering, build, size or token difference exists. The
cost is one-sided, at 74% of the deleted words in #386's
decisions.md diff being reflow rather than change. New prose goes
unwrapped; existing paragraphs stay until rewritten, because a bulk
rewrap resets git blame across 31 and 43 authoring commits in
rules.md and decisions.md, and that provenance is what dates a stale
claim.

The exception is enforced, not stylistic: rules.md's example lines
and pointer lines are parsed per line, and a wrapped example is a
hard error. Statement prose is free because the citation check
normalizes whitespace first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73 derek73 added the docs Documentation fixes and updates label Aug 17, 2026
@derek73 derek73 self-assigned this Aug 17, 2026
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.51%. Comparing base (81c0be2) to head (28ed18f).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #388   +/-   ##
=======================================
  Coverage   98.51%   98.51%           
=======================================
  Files          44       44           
  Lines        2895     2895           
=======================================
  Hits         2852     2852           
  Misses         43       43           

☔ 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.

The note telling you not to hard-wrap prose was hard-wrapped across
two paragraphs and 19 lines, having been offered as one. Now one
unwrapped line, which is both the convention it states and the length
it promised.

Dropped in the trim: the per-medium enumeration of what makes no
difference (rendering, build, size, tokens), the blame-commit counts,
the .git-blame-ignore-revs escape hatch, and the exception's field
list. The measurements stay in this PR's description and #386's
history; a convention needs the rule and the one number that justifies
it, not the workings.

Note the section it sits in was already wrapped while "2.0 API
modules" below is not, so the file was mixed before either note
existed -- which is why the §5 bullet in the previous commit is
unwrapped and correct without anyone deciding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73
derek73 force-pushed the docs/conventions-gap branch from d710e49 to ca6cec2 Compare August 17, 2026 03:23
derek73 and others added 3 commits August 16, 2026 20:31
Three errors in the §5 bullet, all found in review.

It said stages are "named exactly as rules.md and the specs name the
stage". rules.md cannot be that authority and says so in its own
preamble -- "Statements are implementation-free: no stage names, no
function names, no regexes" -- so the bullet asked rules.md to do the
one thing it forbids itself. Nor does `implemented:` supply it: that
field names the modules honoring a rule, and a rule can list several
while a module honors several, so it carries no stage naming at all.
The committed authority is `_pipeline/__init__.py`'s STAGES for the
set and ParseState's docstring for the field-ownership map, pinned by
tests/v2/pipeline/test_state.py. The original §5 pointed at the v2
core API spec, which is gitignored -- which is why the distillation
needed a different anchor rather than a transcribed one.

It said "all nine stages carry it". There are eight; STAGES calls
itself the eight-stage fold. The ninth module is _assemble, which the
same sentence describes as not a stage -- the count contradicted its
own clause.

Trimmed with it: the spec-header attestation story, which is why this
section was missing rather than what the convention is, and belongs in
#388's description.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mechanical reformat, no words added, removed or reordered. Verified
by collapsing all whitespace in each file before and after and
comparing digests -- identical for all five -- independently of the
rewrapper's own claim, since a script asserting its own correctness
is the shape this project keeps getting caught by.

  AGENTS.md                          531 -> 375 lines
  docs/design/decisions.md          1457 -> 513
  docs/design/mechanisms.md          575 -> 154
  docs/design/rules.md               828 -> 675
  docs/design/nameparser-2.0-rfc.md  305 -> 160

Left wrapped, deliberately: rules.md's rule BODIES. A rule block is a
record format, not a paragraph -- 4-space statement prose above
6-space example lines that align into a scannable unit -- so it sits
with tables and code fences, which the rewrapper also skips. Only
rules.md's preamble and section Backgrounds moved, which is why its
reduction is the smallest of the five. Its example lines and pointer
lines are parsed per line and could not have been joined regardless;
tests/v2/test_rules_doc.py and test_doc_citations.py pass, 233 of
them.

Blame cost, measured rather than assumed: 43 lines of 1717 end up
attributed to this commit -- 13 in AGENTS.md, 24 in decisions.md, 3
each in mechanisms.md and rules.md. Git's diff already maps most
joined lines back to whichever commit wrote their opening text, so
the reformat is far cheaper for `git blame` than the wholesale reset
an earlier note in this branch predicted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds .git-blame-ignore-revs and updates the line-width note now that
the bulk rewrap has happened -- the note previously said "don't
bulk-rewrap", which the previous commit contradicts.

Both halves of the justification I gave for that advice turned out
wrong, and measuring rather than re-reading is what caught them.

The blame damage is 43 lines of 1717, not wholesale. Git's diff
already maps most joined lines back to whichever commit wrote their
opening text, so a reflow costs far less attribution than predicted.

And .git-blame-ignore-revs recovers NONE of those 43 -- verified with
the file well-formed and carrying the correct full SHA, identical
counts with and without. --ignore-revs-file re-attributes a line by
finding it in the parent, and a line produced by MERGING five lines
has no counterpart there, so there is nothing to hand the blame back
to. The entry is kept because it is the right home for future
format-only commits that map 1:1, and the file says in its own header
that it does nothing for this one -- inert machinery is fine when it
is labelled inert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@derek73
derek73 merged commit e319a6c into master Aug 17, 2026
11 checks passed
@derek73
derek73 deleted the docs/conventions-gap branch August 17, 2026 03:45
derek73 added a commit that referenced this pull request Aug 17, 2026
#388's §5 bullet asserted that rules.md names the pipeline stages,
which its preamble forbids in as many words. Axis 4 as written would
not have caught it: it pointed inward, from a rule to the decision
entry it cites, while that error pointed outward, from AGENTS.md at
rules.md. Same class, opposite direction, so the axis now names both
rather than the list growing a tenth item -- the note's own warning is
that a checklist asking for meaningless things teaches skimming.

Checked while writing it, and worth recording: rules.md IS compliant
with its preamble. A first detector flagged seven candidates and all
seven were false positives -- "group" three times as the ordinary
English word, which P2 legitimately uses for groups of words, and four
regex-shaped hits that were my own pattern matching markdown bold. The
one that survived inspection, matches()/comparison_key(), sits in "Not
in scope", and _statements() in test_doc_citations.py defines a
statement as rule-block text up to the first example -- so Backgrounds
and Not-in-scope may name functions, and do.

That caveat is in the axis for a reason: without it the check produces
confident false positives, and someone acts on one. A constitution's
terms of art are defined somewhere executable in this repo, and that
definition outranks the intuitive reading of the word.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation fixes and updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant