Skip to content

Check and suggest the axiom line on country-model PRs; plan the pe-parity drain - #9

Open
MaxGhenis wants to merge 18 commits into
mainfrom
axiom-parity-check
Open

MaxGhenis wants to merge 18 commits into
mainfrom
axiom-parity-check

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

This makes the PolicyEngine→Axiom parity rule (CONTRIBUTING, "Mirror policy changes in Axiom") checked and assisted rather than manual, for every country model.

What's in it

1. A reusable PR check (.github/workflows/axiom-parity.yml, package axiom-parity/). Country repos call it on pull_request.

  • It applies only when a PR changes <package>/parameters/, variables/ or reforms/. Markdown under those paths doesn't count.
  • Each claim on the axiom: line is resolved against GitHub:
    • queued: the issue exists in a TheAxiomFoundation/rulespec-* repo, carries pe-parity, is open (or closed as completed), and passes a dispatch-ready lint over its body and comments. The lint needs six things: module path, corpus citation (not a corpus release file), verbatim law, required outputs, a pasteable review_finding, and companion tests.
    • encoded: a rulespec PR that is open or merged. It warns when the PR carries no encoder manifest.
    • encoded-correct: every module named exists on rulespec main, and so does any #rule cited. For each module, a cited companion case or file exists and outputs a rule of that module.
    • n/a: an allowed category (below), as the PR's only claim. For metadata and docs-tests, no changed policy file may change a parameter value or formula; every file is checked. Parameter YAML is compared with descriptive keys removed, and Python by AST with docstrings and class-level labels removed.
    • needed: never passes.
  • Several claims are allowed (;, |, several lines, or a bullet list after a colon). Every claim must pass.
  • A status is claimed only in the canonical shape: right after the reference or citation it is claimed for, or opening its clause, with nothing before it that denies it. "rulespec-us#1416 is not [yet] queued" claims nothing, whatever its punctuation.
  • It verifies the claims a PR makes. It can't tell that every changed provision has a claim; the finder comment lists every referenced citation so a reviewer can compare.
  • mode: warn reports in the job summary and annotations without failing. mode: enforce fails the job.

2. A parity finder (axiom-parity suggest). It runs in the same workflow and keeps one comment on the PR while the check fails.

  • It reads the reference URLs on the changed parameters and variables and maps them to corpus citation paths. The mapping covers:
    • legislation.gov.uk and gov.uk;
    • the US Code via Cornell, uscode.house.gov and govinfo;
    • the CFR via eCFR, Cornell and govinfo;
    • CA, MD and OH codes and 14 more state code sites, IRS revenue procedures, plus a section-number match for about 50 other state hosts.
  • It looks the citations up in a shallow, sparse clone of the rulespec repo and in the open pe-parity issues.
  • It suggests encoded-correct candidates together with the companion cases that output each module.
  • When a citation's source document already has an open issue, it suggests extending that issue. When nothing covers a document, it drafts one issue for it. A draft's TODOs fail the lint until a person fills them in.

3. A drain design (axiom-parity/docs/drain.md), with two tools:

  • corpus-pin lists the citations the encoder could read in the corpus release a rulespec clone pins: rows with an operative body. Rows marked repealed are listed apart, because the encoder refuses them. It reads axiom-corpus with git, using the encoder owner's procedure.
  • drain-plan extracts each issue's target citations and review_finding (every finding block, body first, then comments), files each target under its source document, and prices a wave from measured run costs.
    • A batch is one document, so no run mixes jurisdictions, which the encoder refuses.
    • A module a finding names is requested work unless the words around it mark an import, a deferral, a precedent or a description. When the issue gives no citation for requested work, the issue is held.
    • It applies the encoder owner's lists as data: blocked modules (declared, named in a finding, or owning the target citation on rulespec main), held citations and its dispatch-preparation verdicts, source patterns, and assembled pipelines, where the change an issue asks for is a hand edit that a signed run does not make.

CONTRIBUTING now lists the n/a categories and the issue headings, and names the check.

Allowed n/a categories (please check this list)

The rule names infra, data, ui, microsim-only and emulator-mapping. Three more cover policy-path PRs that change no provision of law:

  • docs-tests: documentation and tests;
  • metadata: labels, references and units;
  • not-law: contributed reforms, proposals, and announcements not yet legislated.

The replay below shows these three accounted for most n/a PRs. A reason saying "Axiom doesn't encode this yet" is rejected unless an explicit category is given, because that is what queued is for. Three US PRs used exactly that reason: policyengine-us#9667, #9656 and #9588.

Evidence

Replay over every PR merged since 2026-09-26 (scripts/replay_history.py, diffing each merge commit locally):

Repo Merged Change policy files Would pass Main failures
policyengine-uk 98 81 60 no line 13, issue not dispatch-ready 4, needed 3, n/a mixed with other claims 2, n/a category 2
policyengine-us 203 173 87 no line 44, issue not dispatch-ready 26, queued with no issue 6, n/a category 5
  • I read each failure class and fixed every parser false positive the replay surfaced:
    • lines inside code fences;
    • a bullet list continuing a line;
    • dict(title=, href=) references;
    • 0000-01-01 parameter dates;
    • references moved under a dated value's metadata;
    • prose lines that start with "Axiom:".
  • Rulespec lookups use main today, so a few old claims pass only because a module landed later.

Finder on the three open UK PRs the earlier replay session checked by hand (#2240–#2242). It reproduces those findings exactly:

  • FA 2004 s.190 is encoded: uk:statutes/ukpga/2004/12/190, with cases earnings_above_basic_amount and earnings_below_basic_amount.
  • ss.188, 189, 227, 227ZA, 228A and 233 have no module. The finder drafts one issue for FA 2004.
  • FA 2003 Sch 4ZA has no module, so it drafts an SDLT issue.
  • UC Act 2025 s.1 is queued in rulespec-uk#367, which is dispatch-ready.

The check passes on #2240's merge ref: s.190 is verified against its module and both cases, and rulespec-uk#444 is dispatch-ready.

Backlog (axiom-parity backlog):

  • rulespec-uk: 79 of 83 open pe-parity issues are dispatch-ready.
  • rulespec-us: 84 of 175.
    • 85 US issues lack a pasteable review_finding; 60 of them are among the 71 filed on 2026-10-09.
    • 21 name no module.
  • By the plan's own checks (corpus pin, the encoder owner's blocked modules and citations, manual paths paused), 16 source documents pass: 17 citations, 16 signed runs, completing 11 issues. Without the citation holds and the manual-path pause it is 26 documents and 29 citations.
  • Passing the plan is necessary, not sufficient. The encoder owner prepared all 16 documents for dispatch on 2026-10-10:
    • 4 were dispatched that day (Colorado 39-22-2003 and three New Mexico sections) and wait on the signing approval;
    • 5 wait on an encoder fix (axiom-encode#1819);
    • 3 rely on a source that isn't in the pinned corpus;
    • the 4 UK documents cannot be encoded: rulespec-uk has no working signed route. The signed workflow reads .axiom/workflow-toolchain.toml, which rulespec-uk lacks, and rulespec-uk's layout test allows no encoding manifest. The encoder owner has queued that route question for Max.
  • drain-plan reads those verdicts back as holds. With them and the UK hold applied, it lists no document that is ready and not already dispatched.
  • Some lint-ready issues are held for the work they ask for: 10 ask for a change to an assembled pipeline, and 13 ask for work on a module and give no citation for it (2 are in both groups).
  • Two earlier versions of this description overcounted: 25 documents (31 issues, 45 provisions), then 16 documents completing 15 issues.
    • The first plan grouped an issue under its first citation's document only, so a run could mix jurisdictions, and it read targets from an issue's last comment only.
    • The second read a module as a target only when its own sentence had a verb such as "encode", so a numbered list of modules went unread.
    • Review rounds 3 and 4 caught these.

Encoder costs (axiom-parity/docs/drain.md), from the 453 targeted-signed-reencode runs between 2026-09-01 and 10-10:

  • The 121 runs since 2026-09-25 (GPT-6 Luna, escalating to Sol) cost $7.08 in model spend; 11 succeeded. Mean $0.058 a run, p90 $0.150, most $0.496.
  • Four citations from the 453 runs have a manifest on rulespec-us main. One is a GPT-6 Sol encode from 2026-10-01. An earlier version of the drain document said two citations and no fresh model encode; it had read only the top-level record of each manifest file.

Invariants (property-tested with Hypothesis)

  • The parser never raises, is deterministic, and finds no lines in text without an axiom: prefix.
  • Rendered claims, legal ids and rulespec refs round-trip through the parser.
  • Lint: for every subset of sections removed, the missing elements are exactly that subset; found and missing partition the six elements; a draft the finder writes is never dispatch-ready.
  • Behaviour: descriptive edits never count as a change; value edits and changed formula locals always do; a file compared with itself never changes.
  • Check: a policy PR passes if and only if it has at least one claim and every claim is good; adding a good claim never breaks a passing PR; the check is deterministic.
  • Differential: warn and enforce block on exactly the same findings, and warn shows no errors.
  • Differential: anything the drain can paste as a review_finding, the lint counts.
  • Differential: the URL mapper never contradicts 427 URL-to-citation pairs that an independent pass checked against the corpus.
  • Drain: a batch is ready if and only if every issue is lint-ready and every target is in the pin.
  • Drain: every batch holds one source document and one jurisdiction; each target sits in exactly one batch; a batch needs its citations over 16, rounded up, runs.
  • Parser: an aside never cancels a negation ("is not (…) queued", "is not, …, queued" claim nothing).
  • Lint: an input is never an expected outcome, however many are listed, and a named input is never a required output.
  • Parser: emphasis never turns a denial into a claim.
  • Neighbourhood grids (tests/test_neighbourhoods.py): each free-text rule is tried over every combination of the markers, wrappers and wordings near the ones it was written for. Examples are 14 negations × 12 asides × 49 emphasis pairs for a denied status, and 8 list markers × 6 separators for a module-and-citation line.

There are 268 tests in all, run by .github/workflows/axiom-parity-tool.yml. actionlint is clean.

Review

Independent GPT-6.1 Sol reviews, each with reproductions:

  • Round 1 (505822f) requested changes: 4 P1 and 9 P2 findings.
  • Round 2 (b94b1bc) requested changes: 2 P1 and 10 P2 findings, plus 5 false positives in a 30-PR sample.
  • Round 3 (9f04a68) requested changes: 6 P1 findings, 8 P2 and 1 P3. It reproduced the replay, lint, pin and cost figures, and found the five earlier false positives fixed.
  • Round 4 (f858521) requested changes: 5 P1 findings and 6 P2. It reproduced every figure and found no misjudged PR in a fresh 20-PR sample.
  • Round 5 (d787a40) requested changes: 8 P1 findings and 1 P2. It reproduced every figure and found no misjudged PR in a fresh 20-PR sample.
  • Round 6 (6269fb0) requested changes: 8 P1 findings and 2 P2, most of them again in how status words were read.
  • At d09c652 the parser stops guessing at negations. A status counts only in the canonical shape: right after its reference or citation (only separators, closing marks and a few words like "is" between), or opening its clause, with no denying word before it. A phrasing the grammar doesn't know is not a claim. A property test checks that for any words between a reference and a status, a claim is made exactly when every one is allowed.
  • Every finding from the six rounds is fixed at d09c652 with a regression test.
  • Round 7 is reviewing d09c652.

Rollout

  1. Merge this.
  2. Merge the caller PRs, which use mode: warn: Run the Axiom parity check on pull requests (warn-only) policyengine-uk#2249, Run the Axiom parity check on pull requests (warn-only) policyengine-us#10048, Run the Axiom parity check on pull requests (warn-only) policyengine-canada#558, Run the Axiom parity check on pull requests (warn-only) policyengine-il#12 and Run the Axiom parity check on pull requests (warn-only) policyengine-ng#28. They also update or add the PR templates' axiom line. The uk and us callers point at this branch, so their runs exercised the workflow end to end; both ran green.
  3. After about two weeks of warn-only runs, switch them to mode: enforce.
  4. Then make "Axiom parity" a required check in branch protection. That is a settings change for a repo admin.

policyengine-nz isn't listed in the rule. Its hub can opt in with the same five-line caller.

axiom: n/a: infra: CI tooling for the parity rule; no country-model policy changes

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 10, 2026 07:14
A reusable workflow (axiom-parity.yml) checks the axiom: line on every PR
that changes parameters, variables or reforms: queued issues must exist,
carry pe-parity and be dispatch-ready; encoded PRs must exist and be open
or merged; encoded-correct must name a module on rulespec main and a
companion test that outputs it; n/a needs an allowed category, and
metadata/docs-tests claims are checked against the diff.

The finder maps changed files' reference URLs to corpus citations, looks
up RuleSpec modules and open pe-parity issues, and drafts a dispatch-ready
issue per source document when nothing covers a provision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
drain-plan groups dispatch-ready pe-parity issues by source document,
extracts each issue's target citations and pasteable review_finding, and
prices a weekly wave from measured encoder run costs. corpus-pin lists the
citations with an operative body in the release a rulespec clone pins,
read from axiom-corpus with git. docs/drain.md is the drain design.

Calibration against every policy PR merged since 2026-09-26 fixed: fenced
axiom lines, bullet continuations, n/a notes on queued lines, dict()
references, year-0000 parameter dates, and moved or misspelled references
inside dated values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 16 commits October 10, 2026 07:39
…t's open issue

A citation with no module and no issue of its own, in a source document that
already has an open pe-parity issue, now suggests extending that issue
instead of drafting a duplicate (seen on policyengine-us#10040, where
rulespec-us#1626 covers 20 CFR 416.1202 and the PR also cites 416.1160).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dling

The PR and the tool are checked out into separate directories, so files in a
PR can't stand in for the tool. In warn mode a tooling failure is a warning,
not a failed job; in enforce mode it exits 2, distinct from a rule failure.
The finder writes nothing for PRs that change no policy files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A differential property test found the drain could extract a YAML-form
review_finding (review_finding: |-) that the lint missed. The lint now uses
the drain's extractor as a fallback, so anything the drain would paste counts
as present, and a batch is ready only if every issue has pasteable text.
The extractor also reads a cue after a bold step label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…int and drain

Check
- A formula local named label/reference is code, not metadata; only class
  attributes are descriptive. Inert bare dict() expressions and date-keyed
  bracket values are normalized.
- Every changed policy file is checked for an n/a metadata claim (no cap).
- encoded-correct needs a companion test for every module it names, and an
  unresolved relative module (/22) blocks.
- n/a is a claim wherever it sits, so it can't share a line with others.
- Modal and future status words (might be queued, to be queued) are prose.

Lint and drain
- An element with a TODO is missing, companion tests need expected values,
  and a prose back-reference isn't the element: finder drafts never pass.
- One extractor decides the review_finding for both the lint and the drain.
- Every citation a finding names is a target; a batch needs pasteable text.
- corpus-pin skips repealed rows and reads rulespec-uk's real corpus pin.

Finder
- Issues are read with their comments (one GraphQL query per 50 issues).
- Dated-value references are read; dashes are normalized; the comment is
  only updated when a bot wrote it.
- URL mapping gains legislation.gov.uk /id/ and nested schedules, IRS rev
  procs, eCFR part URLs, govinfo and 14 state code sites, and is tested
  against 427 corpus-checked URL vectors.

Workflow: pull_request only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A shell guard on the maintainers' machines blocks any command line that
contains find run from a broad directory, so axiom-parity find could not be
run by the agents who need it. The workflow and docs use suggest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…approvals

drain-plan --blocked-modules takes modules that must not be a target or an
import. Its first use is the 17 rulespec-us modules that carry the obsolete
module.source_verification.values field and the modules that reference
them: a target importing one fails to compile.

The scarce resource is the production-signing approval, and one signed run
can carry up to 16 citations (MAX_SOURCE_BUNDLE_CITATIONS), so the plan
counts runs per source document and the doc budgets approvals per week.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Check and parser
- Any module reference that resolves to nothing fails an encoded-correct
  claim, however it is written (corpus path, legal id, path or sibling).
- A companion named later on the same axiom line counts; a bare test file
  name is searched beside every cited module.
- Negation stops at its clause ("is not encoded but is queued"); a status
  used as an adjective ("the queued rule") is not a claim; n/a after
  "and" or a full stop is still a claim; a reference-less status joins the
  next only when the statuses agree.

Lint and drain
- Placeholders are matched in any case; a companion case needs a stated
  outcome, not a digit; negative judgments count.
- A review_finding cue must introduce the finding in its own sentence; a
  fence tagged review_finding is one. Outputs named in the finding count.
- Targets are the labelled citation plus everything the finding names.

Finder and behaviour
- Sibling issues are found from every open issue's own citations.
- Comments past 100 are read; the REST fallback reads comments too.
- dict(...) is inert only when the module leaves the builtin alone.
- Dashes are normalized in URLs, claims and cited test paths.

docs/drain.md states the taxonomy's populations exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encoder owner asked to pause manual paths until axiom-encode#1821
merges, so drain-plan takes --blocked-citation-pattern (repeatable).
docs/drain.md records that Max approved the standing approval (d1262).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
drain-plan --blocked-citations reads {blocked: [{citation, match, kind,
reason}]}, where match is exact or exact-or-descendant, and blocks an issue
whose target matches. It complements the module list and the pattern block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wnership

Lint (issue_lint.py)
- Input facts are not expected outcomes: an `input:` block and an
  "input x: 0" clause are dropped before outcomes are looked for.
- A required output named in a finding must be declared as an output and
  tied to the identifier. "Add an input named a_b_c" declares an input.
- A finding cue must hand the finding over now. Deferred, unavailable and
  empty cues hand over nothing, and an inline cue takes only the block
  right below it.
- review_findings() returns every finding in a text once. Braced paths
  (a/b/{1,2}.yaml) are expanded before modules and citations are read.

Axiom line (axiom_line.py, check.py)
- A negation left hanging before an aside governs the status after it:
  "is not (yet) queued", "is not, in fact, queued", "(not yet) queued".
- Bold n/a after a claim, and "the already queued rule", parse correctly.
- A companion test named right after a negation is not evidence.

Drain (drain.py, corpus_pin.py, cli.py)
- A batch is one source document, so no run mixes jurisdictions (the
  encoder refuses such a bundle). An issue spanning documents is in each.
- The blocked-module filter checks the declared module, modules a finding
  uses, the target's path and the modules above it, and, with
  --rulespec-dir, the modules on main that own the target citation.
- Findings in comments add to the body's. Modules a finding asks for work
  on become targets; imports, deferrals and precedents do not.
- A pin file marks repealed rows; a repealed target is not in the pin.

Finder (finder/cli.py, finder/propose.py)
- The finder updates only a comment its own account wrote that opens with
  the marker. Issue text is dash-normalized before citations are matched.

Behaviour (behaviour.py)
- A star import may rebind dict, except the PolicyEngine model_api preamble.

docs/drain.md
- Four citations from the measured runs have a manifest on rulespec-us
  main, not two; one is a GPT-6 Sol encode. The "no fresh model encode has
  landed" claim is withdrawn.
- With every hold applied, 16 documents (20 citations, 16 runs) are ready,
  not 25.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 4 found new phrasings that the rules misread. Rather than add a rule
per phrasing, the rules now guess towards the safe side where they have to
guess, and the README says what they cannot tell.

Drain (drain.py)
- A module a finding names is requested work unless the words around it
  mark an import, a deferral, a precedent or a description. Each marker
  covers its own clause. A numbered list of modules under one "Encode
  these:" line is now read (rulespec-uk#429).
- A line that only pairs a module with a citation declares both
  (rulespec-us#1618).
- A requested module resolves to the citation the issue gives for it or
  for the provision above it, else to the one its path spells (federal US
  and UK). With neither, the issue is held and the plan names the module.
- A precedent or a described module is not at stake for the block list.
- Backticked sibling names, several brace groups and incomplete paths are
  handled. A pin row may hold spaces.

Lint (issue_lint.py)
- A list of input facts is not an outcome: only an announced result ends
  an input clause, and a bare "key: 0" or "x is 0" never counts. A result
  after a colon counts after a described case.
- A YAML case counts whatever the order of its keys; a comment inside a
  code block is not a heading.
- "Add an input rule a_b_c" declares no output.
- Headings and bold labels obey the same negation and deferral rules as
  inline cues. Back-to-back finding labels keep both findings.

Axiom line (axiom_line.py, check.py)
- Emphasis is stripped before parsing. A hanging negation skips its aside,
  and its reach ends at a hard break, another status word, or a reference
  after the aside.
- A test ruled out inside brackets is not evidence.

docs
- With every hold applied, 16 documents (17 citations, 16 runs) are ready,
  completing 11 issues, not 15. 13 lint-ready issues are held because a
  requested module has no citation.
- README: a Limits section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encoder owner prepared the 12 US documents that passed the plan for
dispatch and found 2 dispatchable that day, 2 runnable after an issue
update, 5 waiting on axiom-encode#1819, 1 needing a ruling and 2 whose
finding relies on a form outside the pin.

- --blocked-citations is repeatable and reads the owner's verdict file
  ({documents: [{citation, verdict, reason, until}]}); every row holds
  its citation.
- docs/drain.md says plainly that passing the plan is necessary, not
  sufficient, with the verdict table. With the verdicts applied the plan
  lists 4 UK documents.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The encoder owner keeps a list of assembled pipelines: modules composed
from other modules, where the change an issue asks for is a reviewed hand
edit, not an encode (axiom-encode#1723 for rulespec-us; an ordinary PR in
rulespec-uk).

- --work-holds reads {rule, modules: [{module, evidence}]}. An issue is
  held when a finding, or a line pairing a module with a citation, asks
  for work on a listed module. Importing from one is not held.
- The hold names the module and the owner's evidence, and the plan prints
  the owner's rule once. It replaces the missing-citation reason for those
  modules: naming a citation would not make them dispatchable.

On the backlog of 2026-10-10 it holds 9 lint-ready issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 5 found phrasings one step from fixed ones. Each is fixed, and a
new test module builds phrasings from their parts so a rule is tried
against every combination of markers, wrappers and wordings near the ones
it was written for. Those tests found three more gaps before review did.

Axiom line
- Emphasis is removed completely, however nested: "is not ***queued***".
- A bullet that says anything about a status never inherits one.
- A negation can hang before an aside after an auxiliary ("cannot be
  (yet) queued") and before a dash aside ("is not — for now — queued").

Check
- A negation rules out every companion test in its reach: its own bracket
  group, nested groups included, up to a colon, semicolon, sentence end
  or status word.

Lint
- A name made an input by the words after it is not an output: "Add a
  rule a_b_c as a new input", "Add `x` to the inputs".
- A label's remainder is checked for deferral whatever its length, and a
  finding that starts on the label's line does not take a quote below it.
- A result table needs a filled-in result cell.

Drain
- A request in a module's own clause makes it work whatever describes it:
  "encode the deferred X", "add it to the guarantee that X composes",
  "encode X as a module". Description verbs are listed, not guessed.
- "1. module — citation" pairs are read like bulleted ones.
- programs/ modules are recognised; work on one with no citation is held.

docs
- Missing or repealed corpus text explains 8 failures, not 10.
- The backlog table and held-issue counts follow the new rules and the
  encoder owner's assembled-pipelines list.
- README Limits lists the evidence and finding-label rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s no signed route

The encoder owner prepared all 16 documents that pass the plan. Four were
dispatched (Colorado and three New Mexico sections). Five wait on
axiom-encode#1819, three rely on a source outside the pin, and the four
UK documents cannot be encoded: the signed workflow reads
.axiom/workflow-toolchain.toml, which rulespec-uk lacks, and rulespec-uk's
layout test allows no encoding manifest.

The document now carries that table and the UK finding, and the plan
command holds every uk citation until the route is decided.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Six rounds found phrasings one step from fixed ones, most of them in how a
status word is read. The parser no longer guesses at negations.

Axiom line
- A status is claimed only when it follows its reference or legal
  citation directly (separators, closing marks and is/are/now/already and
  a few such words may stand between), or opens its clause, and nothing
  before it in its piece denies or conditions it. "is not [yet] queued",
  "isn’t queued" and "Not in Axiom yet, rulespec-us#1416 queued" claim
  nothing, whatever their punctuation. Each status is judged in its own
  piece, so a denied claim keeps its references to itself.
- A bullet list inherits "The rest is queued:" only when nothing in the
  lead denies it.
- A status in prose with a reference after it is noted, not claimed.
- Curly apostrophes, Markdown links and comma citations ("43-1041(A),(H)")
  are read before a status.

Check
- Test references are read whole, so "file.test.yaml::case" doesn't end a
  negation's reach.

Lint
- An output named in a finding counts only in a closed set of declared
  shapes; a name followed by any input designation ("as a scoped input")
  is not one.
- A finding on its label's line is none when its first sentence defers
  it, however long.
- Cells under an input column are inputs. "(1)" and "(a)" are list
  markers.

Drain
- Root-first program paths, emphasis around paths, "repair the existing
  X" and "add the import to X" read as work on X.

Tests: grids over the words between a reference and its status, denials
before it, input designations, deferred label lengths, input columns,
module layouts, wrappers and modifiers, list numbering, repeated
references and Markdown links. 268 tests.

Replay: UK 60 of 81, US 87 of 173 policy PRs pass (was 58 and 87).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant