Skip to content

Cite NZ spec sources by symbol, not line number - #1141

Closed
MaxGhenis wants to merge 1 commit into
mainfrom
nz-spec-symbol-citations
Closed

MaxGhenis wants to merge 1 commit into
mainfrom
nz-spec-symbol-citations

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Invariant

No NZ spec resource cites a line number of a Python source unless the same resource pins that source at a commit. In practice:

  • This repository's sources are cited by symbol, because their line numbers move under unrelated edits.
  • Another repository's source may be cited by line only when the resource also pins it, through a mapping whose path names the .py file and whose commit is 7–40 hex digits.

The check is unpinned_python_line_citations in test_nz_spec_package.py. It scans every string, mapping keys included, in every NZ package resource (the JSON files and spec/*.yaml).

Scope:

  • Pins match by file name.
  • The recognized line locators are x.py:N, x.py:N-M, x.py:N,M, x.py#LN, x.py LN, x.py line N, x.py, lines N-M, x.py (lines N-M), and the reverse forms lines N-M of x.py and line N in x.py.
  • A line locator that names no .py file is out of scope, for example harness_lines or "lines 1695-1790 of the same file at 302e43b…". Those already sit beside a commit.

Why

benefit_unit_rule.json cited concepts.py:880-919 (the relationship pointer block) and concepts.py lines 892-901 (the "always parent 1" sentence). fe698c9 wrote them against the file at that commit.

The same file also cited executor.py lines 636-643 and lines 1550-1573. Those were exact when this branch was cut from 0daf83c, but #888 has since merged and moved the two functions to lines 638 and 1531. scenarios.json cited the conformance harness as ops main run.py:168, which moves whenever ops main does.

Changes

Resource Was Now
benefit_unit_rule.json pointer_concepts.citation concepts.py:880-919 concepts.py, the "# --- Relationships" block: _pointer("partner_person_id") through _pointer("reference_person_id")
benefit_unit_rule.json dependent-child rule concepts.py lines 892-901 concepts.py _pointer("parent_1_person_id")
benefit_unit_rule.json description (…_structural_columns, executor.py lines 636-643), (_validate_population_declaration, executor.py lines 1550-1573) (microcosm.graph.executor._structural_columns), (microcosm.graph.executor._validate_population_declaration)
scenarios.json MC12 annualisation note (ops main run.py:168) (WEEKS_IN_MODEL_YEAR in TheAxiomFoundation/ops nz-lane/emtr_reproduction/run.py at ba6e7d6e)

as_rate_bridge.json's run.py:N citations are unchanged. Its source block pins nz-lane/emtr_reproduction/run.py at ba6e7d6e4f488fdb2762dfb9d91c90f3238b719c, and the new test asserts that they are scanned and covered by that pin, so the exemption is not vacuous.

Each cited claim was re-read for this PR:

  • At ops ba6e7d6e, run.py:168 is WEEKS_IN_MODEL_YEAR = D365 / D7. That commit is still ops main's head.
  • _pointer("parent_1_person_id")'s definition says "When only one parent is co-resident it is always parent 1."
  • _check_pointers emits parent_order for parent_2 without parent_1.
  • _validate_population_declaration raises when a non-structural node owns an entity id or person membership column.

Tests (engine-free, TestSourceCitations)

  • Committed resources: no unpinned Python line citation in any NZ resource. The harness citations are found, and they are pinned at a 40-hex commit.
  • Regression vectors: each of the five citations this PR replaces is refused.
  • Hypothesis, one property per branch:
    • an unpinned line citation in any locator spelling, at any depth, as a value or as a mapping key, is refused;
    • a commit pin at 7–40 hex for that file covers it;
    • a pin of another file, or a pin at a branch name such as main, HEAD or a 6-hex prefix, does not;
    • symbol citations are not line citations.
  • Differential (spec against source):
    • The pointer names in benefit_unit_rule.json equal the _pointer(...) calls in concepts.py's Relationships block, in order.
    • The citation names that block's first and last pointer.
    • The parent-1 concept definition still says "always parent 1".
    • _check_pointers exists.
    • Every dotted microcosm.* symbol named anywhere in the package resolves through import plus getattr. A missing attribute and a missing shard both raise.

Mutation check. Each of these mutants fails one of the new tests, and each was reverted:

  • dropping "always" from the parent-1 definition;
  • renaming _check_pointers;
  • renaming executor._structural_columns;
  • renaming parent_2_person_id in the block.

On origin/main's JSON, the validator flags all five old citations (2× concepts.py, 2× executor.py, 1× run.py). On this branch it flags none.

Robustness to #1134: with #1134's microcosm-frame/src diff applied on top of this branch, TestSourceCitations and the three country goldens pass (18 passed).

Re-pins

packages/microcosm-build/tests/golden/nz_country_spec.json, regenerated from the loaded spec (3 lines):

  • benefit_unit_rule.json: 9e507e78… → 2dcc3a89…
  • scenarios.json: 5dbf2b96… → 1ca42272…
  • fingerprint: df8850d5… → b7a6622b…

Downstream search:

  • The spec-engine package_fingerprint for NZ moves from d7ef7887… to 45566f35…. No file in this repo pins it, by full hash or by 8-character prefix, and neither does Chronicle at 0f2cd96 or a PolicyEngine-wide code search.
  • spec_sha256 and documentation_sha256 are unchanged, because the legacy JSON is in neither surface.
  • No other file pins the old resource hashes. The sources.yaml contract receipts pin only source_stages.json and geography_spine.json, which are untouched.

Verification

Commands:

  • ruff check .: clean.
  • ruff format --check on the test file: clean.
  • pytest test_nz_spec_package.py test_country_spec.py test_spec_engine_country_bundles.py test_spec_engine_loader.py -p no:cacheprovider --basetemp=.hub-scratch/pytest -o tmp_path_retention_policy=failed: 251 passed.

Only the targeted files were run, not the full suite.

Out of scope

The US spec has the same defect. us/ecps_parity_known_gaps.json cites packages/microcosm-build/src/microcosm/build/us_runtime/asec_pool.py lines 61… and lines 397…, which are in-repo and unpinned. That is filed as a separate follow-up, not changed here.

axiom: n/a: spec citation text and an engine-free test; no policy or rule change.

🤖 Generated with Claude Code

benefit_unit_rule.json cited concepts.py:880-919 and concepts.py lines
892-901 for the relationship pointers. #1120 shifted both ranges by one
line on main, and #1134 (open) adds seven more lines above them: at its
head, lines 892-901 are the partner pointer's text rather than the
"always parent 1" sentence, and 880-919 stops before reference_person_id.
The file also cited executor.py by line, and scenarios.json cited the
harness as "ops main run.py:168", which moves with ops main.

Cite the Relationships block, _pointer("parent_1_person_id"), the
executor functions, and WEEKS_IN_MODEL_YEAR at ops ba6e7d6e instead.
Add unpinned_python_line_citations: no NZ spec resource may cite a line
of a Python source unless it pins that source at a commit (as
as_rate_bridge.json pins the harness), with Hypothesis cases per refusal
branch, plus checks that the cited pointers match the concepts source
and that every dotted microcosm symbol the package names resolves.
Re-pin the two resource hashes and the NZ spec fingerprint in the golden.

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

Copy link
Copy Markdown
Contributor Author

Closing as superseded by #1282 (NZ hub; this PR's owner session is gone).

#1282 rebuilds this PR's guard, unpinned_python_line_citations / TestSourceCitations, on current main without merging this branch. That avoids the conflicts this branch has with main, which is 430 commits ahead.

#1141's tests, mutants and five regression vectors are ported into #1282.

@MaxGhenis MaxGhenis closed this Oct 15, 2026
MaxGhenis added a commit that referenced this pull request Oct 15, 2026
…line (#1282)

* fix(nz): replace drifting spec line citations with stable locators

Invariant: No resource in the NZ spec package
(packages/microcosm-build/src/microcosm/build/nz/, JSON and spec/*.yaml)
cites a line number of a file in this repository. Another repository's
file may be cited by line only when the same resource pins that file at
a commit, in a mapping whose path names the file and whose commit is
7–40 lowercase hex.

Rebuild #1141 on current main without merging its branch. Replace all
local Python/JSON/Markdown line locators with symbols, exact JSON
records, or a documentation heading. Preserve resource meanings and
field shapes. Guard all extensions, nested values/keys, foreign pins,
symbol resolution and JSON pointers; add properties and differentials.

Regenerate only changed NZ golden resource hashes and fingerprint:
benefit_unit_rule.json: 5c1cf16daaae482ea3ec53495f4c2e4ae452d928c6240a5284dbbf30cd2dfe37 -> a9e8cbfd38a64d2f8db0002fe8c31bb5a18fb34dbe59fa943336487ce95e2ca8
reporting_classifiers.json: b5af9e4737af4717d86aedfe651df8b3c18c3875763726e7a6a0b9b1168ed133 -> 789a07acd1b6724a12bbd9584ab9fa05bb01d0b675cc3a0fbc837b066dbec49e
scenarios.json: 30f96f3063773d77e3c70119c8f5d99d3528eca87428903da00ca071ab34cfaf -> 9c70241a6203b3a66dc09587c8b955d9d421bbe32f018ea1542e7639f4c7507c
country_fingerprint: 3208901a27e6f09885e5990517c80e2d418425d937aa33fb0f6dacbbf290dd23 -> 5e97ffb44bc37ebd3809e7f6cf2ad253ef4308339338b96b4bd78746a9c1888d
package_fingerprint: 07ab080d68771a207290c83a9040b294f0775c96b74022938c9da13aa713ba20 -> bba0d1ac41b972314bfa5f95adb9884c462296713af50f68d3969246a0c6f112
No other repository pins moved; searched full hashes and 8-char prefixes.
package_fingerprint is derived; no file pins it.
spec_sha256 and documentation_sha256 are unchanged.

Validation: 542 passed, 1 skipped across eight final targeted
test-file runs; all four required mutants fail their intended tests and
are restored. Ruff check/format and git diff --check pass.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

* Select cited JSON records by key, not array index

Extend NZ JSON citations with exactly-one keyed record selectors, conjunctions,
RFC 6901 escaping and pointer suffixes. Refuse record-array index traversal in
both citation scanning and resolution; retain scalar-array indexing.

Use unique input identities in the closure and canonical_input in Axiom
bindings (engine_input is not unique). Change only the three evidence strings.

Regenerate the NZ golden; only reporting_classifiers.json and fingerprint move:
reporting_classifiers.json: 789a07acd1b6724a12bbd9584ab9fa05bb01d0b675cc3a0fbc837b066dbec49e -> d1a5011e2163a4ceec5f030e155a02f7bc4a3bc0ad59f06fb7a406993319512f
country_fingerprint: 5e97ffb44bc37ebd3809e7f6cf2ad253ef4308339338b96b4bd78746a9c1888d -> 9259333d5b7c212209654cebabc06122a8bc2dbe2cb1c776af17c6d02f1200fe
Full hashes and 8-character prefixes checked; no stale tracked pins remain.

Tests: test_nz_spec_package.py 279 passed; test_country_spec.py 135 passed;
test_nz_axiom_input_closure.py 17 passed, 1 skipped. Total: 431 passed,
1 skipped. Initial regressions: 20 failed on the original resolver/resources.
All four required mutants fail their intended tests and are restored byte for
byte (1 index, 1 wrong-record, 3 scratch duplicate, 1 exactly-one failures).
Ruff check/format, CI test-layout and graph-burndown verification, and
git diff --check pass.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

* Refuse backtick-wrapped and L-prefixed line citations

Share the file-line locator grammar between regular and extensionless files.
Recognize Markdown and quote wrappers, forward/reverse L locators,
punctuation, and range/list spellings. Document recognized forms and scope.

Add deep mapping-key/value regressions and extend Hypothesis generation
across wrappers and dash variants. Preserve symbol, JSON-pointer and keyed
record citations, with explicit negative controls.

Validation: NZ spec 619 passed; country spec 135 passed; NZ closure 17 passed,
1 skipped. Physical control and three restored mutants fail as intended.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

* Attribute Markdown-link line citations to their destination

Attribute link locators to the destination and every filename in the label.
Exempt a citation only when all attributed files are pinned foreign sources.
Keep JSON pointer and keyed-selector fragments opaque to the line scanner.

Document the prose-citation threat model and exercise its in-scope examples,
deep key/value regressions, and generated link attribution and exemptions.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

* Attribute URL link destinations in the line-citation guard

Parse HTTP(S) file URLs in Markdown destinations and bare prose, including
GitHub blob/raw forms, raw.githubusercontent.com, and line/column fragments.
Retain repository identity so microcosm URLs are always local and foreign
URLs require the existing same-resource path and commit pin.

Leave unparseable links available for full-text scanning. Extend deep key
and value regressions and the link attribution property across URL forms.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

* Match URL pins by exact path and parse URL fragments by grammar

Keep basename pin matching for prose while requiring exact paths for URL
citations. Parse line fragments by their positive grammar and preserve raw
fallback scanning when a fragment is not understood.

Cover punctuation, common URL wrappers, encoded paths, lowercase and short
ranges, commit permalinks, and tree/blame routes with regressions and properties.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>

---------

Co-authored-by: GPT-6.1 Sol <noreply@openai.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