Skip to content

Import-strip hygiene: dissolve the homonym bucket (152 → 0) and remeasure the stripped residual - #8067

Merged
briansrls merged 27 commits into
mainfrom
session/calm-ram-435
Aug 9, 2026
Merged

briansrls merged 27 commits into
mainfrom
session/calm-ram-435

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes the corpus-hygiene bucket and re-measures the stripped residual on the head that carries the repair. This does not close import deletion, and nothing here is progress toward it.

Before / after — both measured on this head

actionable corpus_hygiene diagnostics
before 152
after 0

The disposition is absent from the ledger, not reduced. Reconciliation is checked by the classifier, not asserted:

stripped_hard (3,100) = control_hard (22) + attributable (3,078)
attributable (3,078)  = Σ ledger rows (3,078)      [reconciliation: OK]

Remaining residual by hard disposition

disposition rows
unique_decl_unresolved_mechanism_unobserved 1,885
variant_mechanism_unobserved 600
variant_owner_unindexed 249
cascade 138
field_on_unresolved_or_wrong_type 71
method_on_unresolved_receiver 66
ordinary_callee_unindexed 45
record_shape_cascade 12
per_module_convention_population 8
intentional_ambiguity_fixture 3
unindexed_symbol_candidate 1

What was done

Consolidated onto one authority: declaration_ref_eq + declaration_ref_in_list (44 rows) → std.roster_frontier; Milliwatt/milliwatt/milliwatt_count → std.measure; srv3_nbd_proxy_local_port → its cited extdeps row; decl_facts_matching_qualified_name → v2.std.decl_facts_skeleton; gnu_bash_subject_ref → the derived row in gunbc.language_target_registry.

Renamed as genuine homonyms: PublicationSubject → RoadmapPublicationSubject / PublicProjectionSubject (31 rows); NetworkInterface → DockerContainerNetworkInterfaceStats; ampere → ampere_vendor; shape_from_catalog → cpu_/gpu_; ChangeClassification → Bootstrap…/ChangeRealization…; path_has_prefix → rust_source_path_has_prefix; note → instrument_note/motion_note.

Fixture-locals: five nid helpers, authored, site_artifact_digest, fixture_repository (git/hg/pijul), decl_facts_reflection_fixture_facts.

Reclassified out of the debt count with named dispositions: per_module_convention_population (derived from a threshold in the gap between fork counts 2–6 and convention counts 94/497, so new convention rows self-classify), intentional_ambiguity_fixture (SharedBareArm, CensusProbeSubject — renaming them deletes the test subject), and duplicate-named fields/methods routed to their cascade dispositions.

cell/row are #8056's (landed 0ee2d85de2a); I measured the same repair under different names before finding that PR and withdrew the competing edit.

Two findings, not cleanups

  • runner_slot_unit_name and RunnerReplacementCause have divergent bodies — two systemd unit-name constructions, two cause vocabularies — as does current_walk_attempt_id (none vs empty string). Renaming per your instruction makes the fork visible, not fixed; that latent defect is recorded in §15.6.
  • Renaming the git fixture made another module's bare fixture_repository bind to an unrelated declaration, producing five spurious "no field on type Repository" errors: pool coincidence on the unstripped tree, the same mechanism as the largest residual class.

Numbers that moved for reasons that are not this repair

Control 12 → 22 (compiling origin/main alone reproduces 22 — the hygiene batch adds zero); corpus grew to 16,375 imports / 2,579 files; unique_decl… rose to 1,885. All follow main landing #8062, #8061, #8068 mid-work. §15.1–15.5 now carry an explicit pointer that their numbers are the pre-repair reading.

Fixes review 50740

The receipts pinned a pre-repair commit while the diff consolidated forks the ledger listed as open. Everything is regenerated on this head and the hash names it. The regeneration also caught a defect of my own: corpus_hygiene: 2 turned out to be my rename colliding with an existing import_resolution_facts_live in v2.lens.module_graph — named for its return type when the distinguishing fact is its source; now reference_derived_import_resolution_facts_live.

Verification

Unstripped whole-tree compile green at baseline (22, identical to origin/main); strip reproduces byte-identically from tracked content; classifier reproduces the committed ledger; .gitignore allowlist entries survive a heal round-trip (regen fixed point).

What remains

The ordinary compiler must produce accepted occurrence bindings, project provider-file dependencies from them, and load the same closure independently of ambient pool membership.

The permanent closing contract still reports all six capabilities unavailable (§15.0). The corpus excuse is gone; the integration vertical is what is left.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 4 commits August 9, 2026 01:54
…onyms that carry half of it

Whole-corpus strip measurement (docs section 15 of the cascade diagnosis, the
DESIGN-linked authority for this lane rather than a new orphan doc), plus the
part of the residue that is corpus hygiene rather than a compiler deficit.

Measurement: gunbc rebuilt from main at 1eadad4 (a stale binary would have
measured a substrate that #7924 replaced), two scratch trees, a brace-depth-aware
strip of 16,315 import declarations across 2,574 files with zero residue.
Control 12 hard diagnostics, stripped 5,827 -> 5,815 strip-attributable over 801
files and 486 names; 69% of stripped files compile clean. Joining every failing
name against a corpus declaration index splits the residue: 50% homonyms (32
names), 28% the documented Class B population, 10% variant tags, 11% cascade.
The classes are indistinguishable by diagnostic text, so the join is what ranks
the work.

Fix, for the homonym half only: `cell`, `row` and `note` were each declared
twice with unrelated return types (a MarkdownTableCell/Row table helper in
gunbc.plans.md_helpers, a markup Fragment helper in the instrument pages). Two
concepts sharing a short name is a homonym, not a section 3 fork, so the
correction is disambiguation and not consolidation: the instrument-local
declarations become instrument_cell / instrument_row / instrument_note, names
derived from the instrument_cell_class / instrument_row_class /
instrument_note_class they already build. All three names are now corpus-unique,
which removes 2,765 of the 5,815 (48%) at the authoring layer.

This does not unblock the strip. Classes B and C are unchanged and remain the
blocker, and section 13's wave rule stands. Verified by execution: whole-tree
`gunbc compile --target dag` on the renamed tree produces the same 12 baseline
diagnostics as before the rename.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Section 15.5 predicted 2,765 removed diagnostics from the classification
arithmetic. Re-ran the strip against the renamed tree with the same binary and
the same brace-depth-aware pass: 5,815 -> 3,047, measured removal 2,768 (47.6%),
three more than predicted because cascade diagnostics went with them. Zero
cell/row/note failures remain, so the class is closed rather than reduced.

Also records why the ~150-diagnostic Class A tail is not uniformly mechanical
(half genuine forks needing an authority decision, half cross-domain homonyms),
and notes that consolidating a fork temporarily adds the import edge this lane
deletes -- an ordering artifact, since a corpus-unique name resolves bare.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… Class C label

Three corrections to the measurement, and one withdrawal.

WITHDRAWN: the cell/row rename. Open #8056 authored it first (fragment_cell /
fragment_row, same two files) after independently observing explicit imports
losing to pool coincidence. This session measured the same repair under different
names without checking for an existing fix PR. Both instrument files are restored
to main, so #8056 owns that repair and one defect is not repaired twice. `note`
(declared twice across the sandbox and motion modules) is NOT covered by #8056
and is recorded as the uncovered sibling rather than edited here, since its
declarations sit adjacent to #8056's lines.

CENSUS: the published four classes summed to 5,803 against a stated 5,815. The
missing 12 are diagnostics carrying no quoted name for the join to key on (eight
indexing, four if-branch mismatches). They are now an explicit unclassified row
and the ledger identity is stated, so the residual reconciles exactly. Their
count coinciding with the control's 12 is a coincidence, called out as one; one
of the four is the Product(<anon>) fabrication shape, so part of that row is
Class-B damage in disguise.

CLASS C: the label is withdrawn. The section described the 599 rows as the
arity-zero/variant-tag population that section 3 predicts -- a hypothesis THIS
DOCUMENT's section 5 refutes by execution. Re-asserting it while citing the
refuted section is the stale-citation class in the document that recorded the
refutation. The rows now carry a named re-proof procedure and are explicitly not
evidence for a language feature.

Also: Class A is split four ways, since global textual uniqueness is not the
namespace model's rule -- it preserves distinct same-spelled declarations and
feeds candidates to the ambiguity fold; the 69%-clean reading is qualified
against the measurement-only discriminator and the fabrication arm; the framing
no longer implies a countdown, and states the closing frontier as 2 with E and F
unavailable.

Adds docs/plans/import-strip-residual-ledger.tsv: the exact 3,047-row residual
worklist, dispositions summing to the row count, with provider_in_loaded_closure
carried as unobserved (it needs loader instrumentation, and guessing it would
fabricate the E/F measurement) and no_declaration_found documented as an index
limitation rather than a fifth class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Re-measure the repo-wide import strip; disambiguate the three homonyms carrying half the residue Import-deletion measurement: whole-corpus strip census, reconciled, with the exact residual ledger Aug 9, 2026
…-measure on the current base

Six required changes from review, each verified against the carriers rather than
taken on the reviewer's word.

FRONTIER 2 IS WITHDRAWN. The roadmap prose was ahead of its own executable
closing authority. gunbc.namespace_reference_derived_closure_contract
namespace_reference_derived_closure_acceptance_admissions returns SIX
ReferenceDerivedClosureUnavailable rows -- including the four A-D capabilities,
trigger P2aStructuralCandidateProducer7515 -- and
reference_derived_closure_closing_contract_holds is false above frontier zero.
Section 15.0 replaces the single frontier with a three-level maturity matrix
(A-D parser-fixture evidence; E/F carrier/fixture evidence; permanent
ordinary-path contract all six unavailable), citing the carriers that say so
themselves: namespace_clause_e_projection_law_note excludes
OrdinaryLoadedCompilationClosure, module_path_file_row_dissolution_note carries
its row as a scaffold until B2, and roadmap_authority's
namespace_cross_file_provenance_lane_integration_note states outright that B1
fixture carriers do not close the lane. The missing work is an integration
vertical, not two algebra arms.

CLASS B IS NOT E. The prior revision dispositioned 1,656 rows as clause E while
every row recorded provider_in_loaded_closure=unobserved; both cannot stand. The
disposition is now unique_decl_unresolved_mechanism_unobserved, and the doc
enumerates the five mechanisms the evidence cannot distinguish. The
live_tree.dag lead (943 rows, 31% of the residual) survives as a strong lead,
labelled as one.

EXACT WORKLIST IS WITHDRAWN: 1,109 rows are explicitly unclassified or
downstream and 1,656 carry an unobserved mechanism; only 152 are hygiene.

THE 505-ROW BUCKET IS SPLIT six ways -- variant_owner_unindexed 249,
ordinary_callee_unindexed 133, field_on_unresolved_or_wrong_type 88,
method_on_unresolved_receiver 22, record_shape_cascade 12,
unindexed_symbol_candidate 1 -- because count/first/split/ends_with are methods
on unresolved receivers and steps/kind/qualified_name are fields downstream of a
missing parent type, not index gaps.

CLASS C PROVIDERS ARE CANDIDATES. The single provider_module column laundered a
same-leaf index hit into a binding fact; the ledger now carries
candidate_provider_modules, candidate_count, intended_provider=unobserved and
accepted_binding=unobserved.

REPRODUCIBILITY. docs/plans/import-strip-measurement/ commits the brace-aware
stripper (now emitting a per-file manifest), the classifier, raw control and
stripped diagnostics, the duplicate-declaration census, summary totals, corpus
hash, measured commit, tool identity, and the deterministic command sequence.
The stripper was verified to reproduce the measured tree byte-identically, and
the classifier reproduces the committed ledger. Registered as a scaffold with a
dissolution trigger: when B2 lands, the ledger becomes a projection of the
loader's accepted-binding output and these scripts delete.

RE-MEASURED ON THE CURRENT BASE, post-#8056: control 12, stripped 3,062,
attributable 3,050, reconciliation checked by the classifier rather than
asserted. Supersedes the 5,815 reading taken at 1eadad4; the two are not a
trend.

Also fixes a fabricated citation this section introduced -- DESIGN.md has no
"Current state - stale binary phantom breakage" heading (that is this session's
memory index, not DESIGN), and "known-positive" is this document's term, not
DESIGN's. Caught in review; it is the same stale-citation class the section
lectures about.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title Import-deletion measurement: whole-corpus strip census, reconciled, with the exact residual ledger Import-strip measurement: reproducible residual ledger, with the maturity matrix corrected Aug 9, 2026
gunbc-ci-auto-heal and others added 2 commits August 9, 2026 03:01
…ore silently dropped them)

review 50719 is correct: the README documented a reproducer invoking
strip_imports.py and classify_residual.py, and neither file was in the tree. The
cause was .gitignore:113 `*.py`, a deliberate repo-wide rule -- `git add -A`
skipped both silently, and the explicit `git add` that followed had its
"ignored file" error suppressed by a 2>/dev/null I should not have written.
So the PR asserted regenerability while shipping only the receipts: the exact
specification-without-execution gap DESIGN section 5 names, in a PR whose
subject is measurement honesty.

Fixed by following the convention already in .gitignore rather than force-adding:
two negation entries beside the existing
!docs/plans/witness-subject-execution-audit.py and
!docs/probes/dissolution_census_a_ci_layer_roots_project.py exemptions. There is
established precedent for committed measurement scripts under docs/ --
docs/probes/namespace_census_2026-07-31/ is an entire directory of them -- and
the ignore rule's own comment scopes itself to the .dag/.rs substrate, which
docs/ is not. A negation entry records the exemption where a reader will find
it; `git add -f` would have hidden it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README asserted regenerability; now it carries the execution that
establishes it. Running the committed scripts against a `git archive HEAD`
export -- only what a fresh clone receives -- reproduces the manifest and the
3,050-row ledger byte-identically, with the classifier printing its own
reconciliation. Also records why the scripts were missing, so the next author
meets the *.py rule with an explanation instead of the same silent drop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

review 50719 is correct and is fixed in 0e0cfe9d445 + 68caa7e2edf.

Cause. .gitignore:113 carries a repo-wide *.py rule. git add -A skipped both scripts silently, and the explicit git add I ran afterwards had its "ignored file" error swallowed by a 2>/dev/null I should not have written. So the PR asserted regenerability while shipping only the receipts — specification-without-execution, in a PR whose whole subject is measurement honesty. The reviewer's framing is exactly right.

Fix. Two negation entries beside the exemptions .gitignore already carries (!docs/plans/witness-subject-execution-audit.py, !docs/probes/dissolution_census_a_ci_layer_roots_project.py), rather than git add -f. There is precedent for committed measurement scripts under docs/ — docs/probes/namespace_census_2026-07-31/ is an entire directory of them — and the ignore rule's own comment scopes itself to the .dag/.rs substrate, which docs/ is not. A negation entry records the exemption where the next author will find it; a force-add hides it.

Verified by execution, not asserted again. From a git archive HEAD export containing only tracked content:

stripped 16315 import declarations across 2574 files
MANIFEST REPRODUCED
reconciliation: stripped_hard=3062 = control_hard=12 + attributable=3050
ledger rows 3050 vs attributable 3050: OK
LEDGER REPRODUCED FROM TRACKED CONTENT ONLY

The manifest and the 3,050-row ledger reproduce byte-identically from a clean checkout. The README now carries that verification rather than the bare claim.

— sent from calm-ram-435

gunbc-ci-auto-heal and others added 8 commits August 9, 2026 03:09
… the artifact

review 50727 is correct, and identifies the durable fix I had missed. My
previous commit hand-edited .gitignore -- a GENERATED artifact emitted from
gunbc.gitignore_authority -- so CI auto-heal regenerated it from the authority
and removed both entries in 1505281, leaving the README describing
exemptions the tree did not carry. Editing a projection instead of its authority
is the DESIGN section 3 single-authority violation, and the artifact winning is
the mechanism working correctly, not a race.

The entries now exist where they are derived from:
  gitignore_model.dag        two GitignoreArtifact variants
  gitignore_authority.dag    both added to the PythonLocalDevScript group
  gitignore_emit.dag         render arms for the two paths
then regenerated via the documented actuator
(dag/tools/generated_artifact_gate.dag main_wet), which is what auto-heal itself
runs -- so the next heal reproduces these lines instead of deleting them.

Proven by execution rather than by reasoning about it: a second consecutive heal
run reproduces .gitignore byte-identically (regen fixed point), and the compiler
refused the intermediate state where the variants were referenced from the
authority/emit import lists before being declared in the model -- which is how
the third module was found.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rities

declaration_ref_eq + declaration_ref_in_list (44 of the 152 hygiene rows):
gunbc.commit_workflow carried a semantically identical copy of std.roster_frontier's
DeclarationRef equality. Deleted; the std authority is imported. Two consequences
that had to move with it: declaration_field_eq became dead once its only caller
went, so it is deleted rather than left as a dead scaffold, and the std authority
names its list parameter `refs` where the local copy said `declarations`, so all
four call sites moved.

Milliwatt / milliwatt / milliwatt_count (2 rows): product.hardware_selection
redeclared std.measure's SI unit family verbatim. Deleted and imported; three
witness call sites that named product.hardware_selection.milliwatt repointed.

srv3_nbd_proxy_local_port (5 rows): extdeps.bmc.webui.nbd_proxy_serve holds the
cited upstream port fact and gunbc.srv3_os_install_diagnostic held a copy. The
copy is deleted and the extdeps authority imported -- the direction the external
upstream decomposition rule requires.

Verified: whole-tree `gunbc compile --target dag` produces the same 12 baseline
diagnostics as before the change.

The imports added here are transitional. They dissolve with the ordinary-loader
changeover, when a corpus-unique name resolves bare; they must not be scored as
import growth against the deletion lane.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Consolidated onto one authority: decl_facts_matching_qualified_name (identical
bodies, both in v2 std) onto v2.std.decl_facts_skeleton; gnu_bash_subject_ref
onto the DERIVED row in gunbc.language_target_registry, deleting the hardcoded
DeclarationRef literal that duplicated it.

Renamed as genuine homonyms -- different concepts that shared a leaf:
PublicationSubject splits into RoadmapPublicationSubject (a roadmap publication
attempt: node, branch, head) and PublicProjectionSubject (a content projection:
subject/content identity, path), 31 rows and the largest single family;
NetworkInterface -> DockerContainerNetworkInterfaceStats with the product
topology keeping the name; ampere -> ampere_vendor with the SI unit constructor
keeping it; shape_from_catalog -> cpu_/gpu_; ChangeClassification ->
Bootstrap.../ChangeRealization...; path_has_prefix -> rust_source_path_has_prefix;
note -> instrument_note / motion_note; reference_resolution_facts_live ->
import_resolution_facts_live on the module_graph side, where the name now
follows the ImportResolutionFact it returns.

Renamed as fixture-locals: five witness-local nid helpers, authored ->
authored_status_fixture, site_artifact_digest -> fixture_site_artifact_digest,
fixture_repository -> git_/mercurial_/pijul_, decl_facts_reflection_fixture_facts
-> decl_facts_reflection_witness_support_facts.

Renamed BOTH sides where the bodies actually diverge, so the fork is visible
rather than latent: runner_slot_unit_name and RunnerReplacementCause (the
recovery module's copies build a different unit name and enumerate different
causes than gunbc.runner_lifecycle, which carries Disposition = SingleAuthority),
and current_walk_attempt_id (env_var/none vs optional_env/empty-string). These
are named, not fixed; two functions still compute a systemd unit name
differently and that is a latent defect this PR surfaces rather than resolves.

Per-spec w3c tokens are named for the spec that owns them: accelerometer.dag
keeps accelerometer_permission_name, and the DeviceMotion spec's copy becomes
device_motion_accelerometer_permission_name; interfaces_are_secure_context_only
gains an API-family prefix on each side. Each upstream spec module owns its own
facts, so a shared token is not consolidated across specs.

One specimen worth keeping, found by execution during the consumer sweep:
renaming the git fixture made another module's bare `fixture_repository` bind to
an unrelated declaration in a different witness file, producing five bogus
"no field on type Repository" errors. That is pool coincidence reproduced on the
UNSTRIPPED tree -- the same mechanism as the Class B residual, and an argument
for these renames rather than against them.

All 30 families are now corpus-unique.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…is head

Fixes review 50740: the committed receipts pinned a pre-repair commit while the
diff consolidated the very forks the ledger listed as open, so the measurement
authority and the fix disagreed inside one PR. Everything is now regenerated on
the head that carries the repair, and sections 15.1-15.5 carry an explicit
pointer saying their numbers are the pre-repair reading.

MEASURED, not predicted: corpus_hygiene 152 -> 0. The disposition is absent from
the ledger rather than reduced. Reconciliation checked by the classifier:
stripped 3,100 = control 22 + attributable 3,078 = sum of ledger rows.

Also fixes a defect the regeneration caught in my own work. The first run
reported corpus_hygiene: 2, which was a rename of mine colliding with an
existing import_resolution_facts_live in v2.lens.module_graph -- I had named it
for its return type when the distinguishing fact is its source. It is now
reference_derived_import_resolution_facts_live, and both are unique.

Three numbers moved for reasons that are NOT this repair, stated so the tables
are not read as a scoreboard: the unstripped control rose 12 -> 22, and
compiling origin/main alone reproduces 22, so the hygiene batch adds zero
diagnostics; the corpus grew to 16,375 imports across 2,579 files; and
unique_decl_unresolved_mechanism_unobserved rose to 1,885. All three follow main
landing #8062, #8061 and #8068 during the work.

The section states plainly that this does not close import deletion. What it
buys is that no one can point at a miscellaneous naming tail to justify a
workaround; the remaining residual is one integration vertical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The corpus hash covers dag/ and src/v2/ .dag files only, so it is stable across
this docs-only commit; the commit line now names the head that carries the
hygiene close rather than the one before it.
@gunbai-bot gunbai-bot Bot changed the title Import-strip measurement: reproducible residual ledger, with the maturity matrix corrected Import-strip hygiene: dissolve the homonym bucket (152 → 0) and remeasure the stripped residual Aug 9, 2026
gunbc-ci-auto-heal and others added 3 commits August 9, 2026 04:58
review 50749 found a semantic bug in production lens code, introduced by my own
rename. The blunt pass over reference_resolution_facts_live rewrote four sites in
v2.lens.module_graph -- the declaration, the CALL SITE inside
dependency_resolution_facts_live, and two prose rows -- and when I later fixed
the name collision I repaired only the declaration. That left reference_edges:
sourced from import_resolution_facts_live, the same producer already feeding
import_edges:, so bare-reference dependency edges were silently dropped from the
module graph that feeds affected-set selection, import closure and compile-clean
scope.

Repaired: the call site takes reference_derived_import_resolution_facts_live, and
both prose rows are reconstructed from main so they differ by exactly the rename.
Audited the whole file against origin/main -- all four changed lines are the
intended rename and nothing else.

WHY NOTHING CAUGHT IT, which matters more than the fix. Both helpers have the
identical signature (List<String>, List<String>, List<String>) ->
List<ImportResolutionFact>, so the substitution is type-correct and the
whole-tree compile stayed green at baseline THROUGH the regression -- the check I
was relying on cannot see this class. And no witness in the corpus references
dependency_resolution_facts_live or union_import_resolution_fact_lists at all, so
the two-source union has no discriminating control and a wrong producer there is
invisible to the executing corpus.

The coverage gap is recorded in section 15.7 rather than closed here: a real
control needs a fixture where a module is reachable by bare reference but NOT by
import, which is the same fixture shape the ordinary-loader vertical needs and
belongs with it rather than bolted onto a naming PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Residual is unchanged (3,078 rows, reconciliation OK) because the repair changed
a call site inside a lens, not the corpus name structure -- but the receipts now
name the head that carries the fix rather than the one before it.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

review 50749 is correct, and it is the most serious defect in this PR — a semantic regression in production lens code, introduced by me. Fixed in 1b6f149ec9f.

What happened. My blunt rename of reference_resolution_facts_live hit four sites in v2.lens.module_graph: the declaration, the call site inside dependency_resolution_facts_live, and two prose rows. When I later fixed the name collision, I repaired only the declaration — leaving reference_edges: sourced from import_resolution_facts_live, the producer already feeding import_edges:. Bare-reference dependency edges were silently dropped from the module graph that feeds affected-set selection, import closure and compile-clean scope. Exactly as the review states.

Fix. The call site now takes reference_derived_import_resolution_facts_live, and both prose rows are reconstructed from origin/main so they differ by exactly the rename. I audited the entire file against main: all four changed lines are the intended rename and nothing else.

Why nothing caught it — the part worth keeping. Both helpers have the identical signature (List<String>, List<String>, List<String>) -> List<ImportResolutionFact>, so the substitution is type-correct and my whole-tree compile stayed green at baseline through the regression. The check I was relying on cannot see this class. Worse, the corpus contains no witness referencing dependency_resolution_facts_live or union_import_resolution_fact_lists at all — the two-source union has no discriminating control, so a wrong producer at that seam is invisible to the executing corpus.

I did not add a witness, deliberately. A real control needs a fixture where a module is reachable by bare reference but NOT by import, so the two arms provably disagree — the same fixture shape the ordinary-loader vertical needs. Bolting a live-tree census witness onto a naming PR is the scope creep this PR was told to avoid, so the gap is recorded in §15.7 as an obligation. Say the word if you want it here instead.

Receipts regenerated on the repaired head (9325d299349 + 9885cfc5f66), since leaving them one commit stale is what review 50740 flagged: residual unchanged at 3,078 rows, reconciliation 3,100 = 22 + 3,078 OK, and the reproducer re-verified from a git archive HEAD export containing only tracked content — manifest and ledger both byte-identical.

— sent from calm-ram-435

… number

review 50759, both findings, with one correction to the first.

WITNESS IMPORT: dag/test/claim/scaffold_disposition_census_fixture_witness_test
imported decl_facts_matching_qualified_name from v2.std.decl_ref_resolution,
which this PR stopped declaring. The single-authority half is right and is
fixed -- it now imports from the declaring module v2.std.decl_facts_skeleton.
The COMPILE-BREAK half does not reproduce: v2.std.decl_ref_resolution imports
the symbol, so the re-export resolves, and the witness ran green (returns true)
BEFORE the repoint as well as after. Recorded because "verify each item against
the current code" cuts both ways; the fix is worth making on single-authority
grounds, not because the tree was broken.

README: the two flagged lines were a sample, not the population. Swept the file
and corrected five stale claims -- the 3,050-row figure, the strip expectation
(16,315/2,574 -> 16,375/2,579), the verification reconciliation
(3,062 = 12 + 3,050 -> 3,100 = 22 + 3,078), the manifest row count, and the
--control-count/expect lines the review named.

The tool-identity section was not merely stale, it was FALSE, and that is the
one worth reading. It claimed no .rs changed between 1eadad4 and the
measured base so the original binary stayed current. Main then landed #8062,
which changes src/v1 binding behaviour, and the binary was rebuilt. The section
now records what that cost: the heal entry passed locally under the old binary
while failing in CI under the new one, so a binary older than the substrate it
judges reports a compiler that no longer exists. Rebuild whenever src/v1 moves.

Verified by execution, not by reading: the README recipe was run and its stated
numbers reproduce (16,375 across 2,579; 3,100 = 22 + 3,078; rows 3,078 OK), and
the repointed witness still returns true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

review 50759 — both findings addressed in 08a253b8c66, with one correction to the first.

Witness import. The single-authority half is right and is fixed: scaffold_disposition_census_fixture_witness_test now imports decl_facts_matching_qualified_name from the declaring module v2.std.decl_facts_skeleton rather than from v2.std.decl_ref_resolution.

The compile-break half does not reproduce, and I checked rather than assumed: v2.std.decl_ref_resolution imports the symbol, so the re-export resolves. The witness ran green (returns true) before the repoint as well as after, and the whole-tree compile was at baseline throughout. Worth stating plainly since "verify each item against the current code" cuts both ways — the fix is right on single-authority grounds, not because the tree was broken.

README counts. The two flagged lines were a sample, not the population. I swept the file and corrected five stale claims: the 3,050-row figure, the strip expectation (16,315/2,574 → 16,375/2,579), the verification reconciliation (3,062 = 12 + 3,050 → 3,100 = 22 + 3,078), the manifest row count, and the --control-count / expect lines named in the review.

One of them was worse than stale — it was false, and it's the one worth reading. The tool-identity section claimed no .rs changed between 1eadad4af25 and the measured base, so the original binary stayed current. Main then landed #8062, which changes src/v1 binding behaviour, and I rebuilt. The section now records what that cost instead of hiding it: the heal entry passed locally under the old binary while failing in CI under the new one, because a binary older than the substrate it judges reports a compiler that no longer exists. Rebuild whenever src/v1 moves.

Verified by execution, not by reading: I ran the README recipe and its stated numbers reproduce — 16,375 imports across 2,579 files, 3,100 = 22 + 3,078, ledger rows 3078 ... OK — and the repointed witness still returns true.

— sent from calm-ram-435

gunbc-ci-auto-heal and others added 3 commits August 9, 2026 05:43
…han assume it

review 50765: the stamp pinned 9325d29 while HEAD carried a later corpus edit
(the witness import repoint), so the hash no longer described the tree the
receipt claims to cover -- the same stale-receipt class section 15.6 names, in
the receipt that documents it.

The review suggested the ledger and diagnostics were "likely unchanged". Both
halves are now established instead of assumed, and they needed different
arguments:

STRIPPED half, by construction: the only post-measurement edit was an import
line, and the strip deletes every import line, so the stripped tree at HEAD is
BYTE-IDENTICAL to the one measured (verified with diff -rq over both source
roots, and the manifest matches). The stripped diagnostics therefore cannot
differ -- no recompile can change that.

CONTROL half, by measurement: the control retains the changed import, so it was
recompiled at HEAD. 22 diagnostics, and the log differs from the committed
receipt ONLY in wall-clock lines. That is now documented rather than papered
over: the README records which receipt content is not byte-reproducible and
gives the filtered diff used to check it, so a future comparison does not read a
timing delta as a measurement change. Nothing derives from the durations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mit id

A stamp written into a tracked file names an ancestor by construction -- the
commit cannot contain its own id -- so re-stamping to catch HEAD is a loop that
never closes and always reads one commit stale. The hash is the real anchor: it
covers dag/ and src/v2/ .dag files, so docs-only commits do not move it. The
receipt now says so and gives the one-line command that decides whether it
describes the reader's tree, which is checkable at any commit rather than
requiring trust in either line.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

review 50765 — fixed in 88c2ff2385b + 7e5b046dcf8, with each half established rather than assumed.

The review suggested the ledger and diagnostics were "likely unchanged". Both are now settled, and they needed different arguments:

Stripped half — by construction, no recompile needed. The only post-measurement edit was an import line, and the strip deletes every import line, so the stripped tree at HEAD is byte-identical to the one measured (diff -rq over both source roots; manifest matches). The stripped diagnostics therefore cannot differ.

Control half — by measurement. The control retains the changed import, so I recompiled at HEAD: 22 diagnostics, and the log differs from the committed receipt only in wall-clock lines. That's now documented rather than papered over — the README records which receipt content is not byte-reproducible and gives the filtered diff (grep -v 'done in') used to check it, so a future comparison doesn't read a timing delta as a measurement change. Nothing derives from the durations.

One structural fix beyond the finding. Re-stamping to catch HEAD is a loop that never closes: a commit cannot contain its own id, so any stamp written into a tracked file names an ancestor by construction and always reads one commit stale — which is what this review caught, and what it would catch again next time. The receipt now says the hash is the anchor, not the commit line, and carries the one-line command that decides it:

find dag src/v2 -name '*.dag' -print0 | sort -z | xargs -0 sha256sum | sha256sum

Equal to the stamped hash means the receipts describe your tree, whatever the commit line says. Verified at the current head: they match.

review 50770 is an APPROVE with no findings; nothing to change there.

— sent from calm-ram-435

…urce control

1. THE `note` RENAME CHANGED A WIRE VALUE, NOT ONLY A SYMBOL. In
   "instrument-note" the token sits between a hyphen and a quote, neither of
   which is a word character, so a word-boundary rename matched inside the
   string literal: the sandbox emitted "instrument-instrument_note" and motion
   emitted "instrument-motion_note", and the motion page's notes silently
   stopped matching the stylesheet rule that styles them. Nothing in the
   repository could refuse it — a class name is resolved by the browser against
   CSS text.

   Repaired by CONSOLIDATION rather than by two corrected copies: motion already
   imported from the sandbox, so it now imports instrument_note and its
   duplicate helper is deleted. One helper cannot drift from itself.

   The whole corpus was then audited for the same class, not just this site: the
   multiset of every string literal in every .dag file was compared against the
   merge base. Exactly three literal changes are mine — this one, and two prose
   annotations that correctly re-cite renamed symbols — plus the gnu_bash_subject_ref
   consolidation. No other wire value moved.

   Witness: witness_note_class_wire_matches_stylesheet_selector, green, and red
   under either exact corrupted spelling.

2. THE CLASSIFIER'S TWO EXCUSING RULES WERE THRESHOLDS, AND THEY FAILED OPEN AT
   THE ONE NUMBER UNDER TEST. "Ten or more declarations is a convention" and
   "every candidate path contains .fixture. is an intentional collision" both
   remove rows from the hygiene bucket by shape, and that bucket is asserted at
   ZERO. Each subject is now NAMED and its defining property CHECKED against the
   tree — conventions must be one-per-module under a declared prefix, fixtures
   must match an exact pinned module set — and a subject that stops satisfying
   its property lands in `duplicate_unclassified`, which is loud and counted,
   never silently excused.

   Six controls in classifier_controls.py, all holding: a planted ten-declaration
   accidental fork stays hygiene, an unknown duplicate across two fixture modules
   stays hygiene, a convention name declared twice in one module is not excused,
   an ambiguity name with a third declaration is not excused, and both named
   subjects keep their dispositions.

3. NOTHING EXECUTED THE TWO-SOURCE UNION. dependency_resolution_facts_live unions
   two producers that share a signature, so the call site that passed the import
   producer into both arms compiled clean and returned well-formed edges while
   dropping every reference-only dependency. A unit test of the fold would not
   have caught it; the defect is in which producers the production function calls.

   So the production function is pointed at a four-module fixture and asserted at
   identity grain in both directions. Restoring the doubled arm reds two of the
   five witnesses.

   The fixture's shape is DERIVED from the seam rather than invented: the two
   producers are disjoint by file — reference_resolution_facts emits nothing for
   a file carrying imports — so the reference-only dependency must live in an
   import-less consumer, and a same-path duplicate is unconstructible. The
   witness says so instead of asserting a dedup that cannot arise.

classifier_controls.py is registered in the gitignore authority; the repo-wide
*.py rule dropped this lane's scripts silently once already (review 50719).
gunbc-ci-auto-heal added 2 commits August 9, 2026 06:42
…dge-source repairs

Control 22 -> 10 (main's #8072 healed part of the annotation-grain class), corpus
16,382 imports / 2,583 files, stripped 3,098 = control 10 + attributable 3,088,
reconciliation OK. corpus_hygiene is absent from the ledger at ZERO, and so is
duplicate_unclassified - so the two remaining excusing dispositions did not
absorb anything: each was checked against the tree and both held.

All 10 control diagnostics sit in host_phase_status_witness_test.dag, which this
branch does not touch, so the hygiene batch still adds zero diagnostics - now
evidenced by the located diagnostics themselves rather than by a separate run of
main. The four new fixture modules contribute zero, measured, not assumed.

Also retires the doc's claim that the convention rule is 'derived, not a list'.
That was the fail-open threshold, and the section that says so is the section
asserting zero.
@gunbai-bot

gunbai-bot Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

All three P1 blockers are repaired on c69e32211bb, receipts regenerated on that exact head, and the 152→0 close is intact and unsplit.

1. The note rename changed a wire value — and the audit was widened past the reported site.

You were right about the mechanism, and it is worse than a missed site: in "instrument-note" the token sits between a hyphen and a quote, neither of which is a word character, so the word-boundary guard did not protect string literals at all. The rename was free to edit any wire value in the corpus.

So rather than fix the one site you found, I compared the multiset of every string literal in every .dag file against the merge base. Exactly four literal changes are mine: this one, two prose annotations that correctly re-cite renamed symbols, and the gnu_bash_subject_ref consolidation. No other wire value moved anywhere in the corpus. That is the part I could not have concluded from the report alone.

Repaired by consolidation as you specified — motion already imported from the sandbox, so it imports instrument_note and its duplicate helper is deleted. witness_note_class_wire_matches_stylesheet_selector is green, and reds under either exact corrupted spelling.

2. The classifier's two rules were thresholds, and they failed open into the one number under test.

Accepted without reservation. "Ten or more is a convention" and "every candidate path contains .fixture." both remove rows from the bucket I am asserting at zero, which makes them the absorbing fallback pointed at this measurement's load-bearing claim.

Each subject is now named and its defining property checked against the tree: a convention must be one declaration per module under a declared prefix, an intentional ambiguity must match an exact pinned module set. A subject that stops satisfying its property lands in duplicate_unclassified — loud, counted, not zero. Six controls in classifier_controls.py, all holding, including your two: a planted ten-declaration accidental fork stays hygiene, and an unknown duplicate across two fixture modules stays hygiene.

On the regenerated run both corpus_hygiene and duplicate_unclassified are absent at zero, so the two remaining excusing dispositions did not absorb anything — each was checked, and both held.

3. The two-source union now executes on the production path.

A fixture tree, with dependency_resolution_facts_live itself pointed at it — not a hand-built call to the fold. Restoring the doubled import arm reds two of the five witnesses.

One correction to the fixture you sketched: the optional shared-duplicate edge is unconstructible through this seam, and finding out why improved the test. reference_resolution_facts emits nothing for a file that still carries imports, precisely so the reference producer cannot over-connect the un-stripped tree — so the two producers are disjoint by file, the reference-only dependency has to live in an import-less consumer, and one path can never appear in both. Asserting that dedup would have been a tautological control. The witness asserts the union at identity grain in both directions instead, and says in its note why the dedup control is absent.

Receipts regenerated on c69e32211bb. Control fell 22 → 10 (main's #8072 healed part of the annotation-grain class); corpus 16,382 imports / 2,583 files; 3,098 = 10 + 3,088, reconciliation OK. All 10 control diagnostics sit in host_phase_status_witness_test.dag, a file this branch does not touch — so "the hygiene batch adds zero diagnostics" is now evidenced by the located diagnostics themselves rather than by a separate run of main. The four new fixture modules contribute zero, measured. The corpus-hash anchor re-verifies against the current tree.

I also retired the doc sentence claiming the convention rule was "derived, not a list" — that sentence was the fail-open threshold, sitting in the section that asserts zero.

CI is running on the exact head; I will report the completed run rather than infer it.

— sent from calm-ram-435

gunbc-ci-auto-heal added 2 commits August 9, 2026 07:11
One conflict, in dag/tools/module_impact_query_front_door.dag. Main (#8054)
deleted the scale-probe block; this branch had only RENAMED a callee inside it
(reference_resolution_facts_live -> reference_derived_import_resolution_facts_live,
the module_graph homonym). Deleted code cannot carry a rename, so main's deletion
is taken whole.

The import line survives the deletion on both sides and must carry the NEW name:
main still spells it reference_resolution_facts_live, and that declaration no
longer exists in v2.lens.module_graph. Taking main's spelling verbatim would have
produced an unresolvable import — the clean-side take that a stat-only reading of
this merge would have missed.

The same-named function in v2.lens.reference_deps is untouched and keeps its name:
it is the other half of the original homonym pair, with a different signature
(Outcome<List<ReferenceResolutionFact>>), and only the module_graph one was renamed.
Main advanced (#8054, #8069), so the corpus hash moved and the receipts no longer
described the tree. Re-measured rather than left stale: control 10 (unchanged,
same annotation-grain file this branch does not touch), corpus 16,388 imports
across 2,583 files, 3,160 = 10 + 3,150, reconciliation OK.

corpus_hygiene remains ABSENT AT ZERO through a main advance that added 62
residual rows - which is the more informative reading than the first zero was:
the close survives the corpus moving underneath it, because it removed forks
rather than pinning a snapshot. duplicate_unclassified is also zero, so both
named excusing dispositions still satisfy their checked properties on a corpus
neither was authored against.

All witnesses re-run green on this head, and the anchor re-verifies.
@briansrls
briansrls merged commit 32887d3 into main Aug 9, 2026
5 checks passed
@briansrls
briansrls deleted the session/calm-ram-435 branch August 9, 2026 09:07
gunbai-bot Bot pushed a commit that referenced this pull request Aug 9, 2026
…uling)

The three scripts under docs/plans/import-strip-measurement/ are deleted, and
their .gitignore negation entries are removed at the gunbc.gitignore_authority
single authority with .gitignore regenerated from it — not hand-edited.

WHAT THIS COSTS, STATED RATHER THAN LEFT STANDING. #8067's README claimed the
measurement regenerates byte-identically from a clean checkout, and shipped the
scripts to make that claim true. With them untracked the claim is FALSE, so it is
withdrawn: the receipts cannot be regenerated from a fresh clone, the recipe is
retitled as a record of what was executed rather than as runnable instructions,
and the one citation of the controls in the cascade diagnosis now says the harness
is untracked instead of pointing at a path that no longer resolves. A stale
pointer to a deleted file is the positional-citation rot DESIGN §3 names; leaving
the reproducibility sentence would have been worse, because it is a claim about
evidence rather than a pointer.

What survives is what a reader can still check: the committed receipts, and the
corpus-hash anchor that decides whether they describe the tree in front of them.

This does not change any measured figure. The hygiene close (152 -> 0) and the
merged reconciliation (3,160 = 10 + 3,150) were established by execution before
the harness was deleted; deleting the instrument does not retract the reading.
The classifier's dissolution trigger has not moved either — it was always due to
delete when B2 lands OrdinaryLoadedCompilationClosure production. This just pays
that cost now, and loses re-runnability in exchange for not carrying a parallel
text-scanning classifier in the tree.
briansrls pushed a commit that referenced this pull request Aug 9, 2026
…nd harness removal (#8079)

* Repair the classifier's raw-population check, and the control that missed it

THE DEFECT. `classify_rows` built `candidates` as a SET of modules and passed it
into `convention_holds`, whose whole job is to decide whether a convention name
is declared at most once per module. The set had already made that true by
construction, so two declarations of a convention name in one module would have
been silently excused as a convention instead of landing in
`duplicate_unclassified`. Raw population and display population are two different
facts; the repair separates them rather than swapping one for the other, so the
ledger's candidate columns stay distinct-module.

THE CONTROL THAT MISSED IT IS THE MORE IMPORTANT HALF. #8067 shipped a control
named "convention name violating one-per-module is not excused" and it PASSED
against the defective code, because it called `disposition()` directly with a
duplicated list — bypassing the deduplication the production path performs before
`disposition()` is ever reached. That is the same class the same PR had just
repaired one layer down: a test of the predicate is not a test of the behaviour.

So the loop is extracted from `main()` into `classify_rows()` — not for tidiness,
but because the production seam was unreachable, which is why no control could
have caught this. Four new controls go through it. The gap is demonstrated rather
than asserted: with the repair reverted, the direct-call control still reports ok
while the production-path control fails.

NOT A CORRECTION TO THE MERGED MEASUREMENT, and this is checked rather than
argued: regenerating the ledger from the merged receipts with the repaired
classifier reproduces `docs/plans/import-strip-residual-ledger.tsv`
BYTE-IDENTICALLY (3,160 = 10 + 3,150). At the measured tree the two named
convention populations really are one-per-module — 497 and 94 declarations across
497 and 94 distinct modules — so the collapsed check happened to agree. The 152→0
close stands unchanged.

Commit 1 of the import-deletion lane, per operator direction: this classifier is
scheduled to delete when production closure lands, so it does not get its own PR.

* Remove the Python measurement harness from the repository (operator ruling)

The three scripts under docs/plans/import-strip-measurement/ are deleted, and
their .gitignore negation entries are removed at the gunbc.gitignore_authority
single authority with .gitignore regenerated from it — not hand-edited.

WHAT THIS COSTS, STATED RATHER THAN LEFT STANDING. #8067's README claimed the
measurement regenerates byte-identically from a clean checkout, and shipped the
scripts to make that claim true. With them untracked the claim is FALSE, so it is
withdrawn: the receipts cannot be regenerated from a fresh clone, the recipe is
retitled as a record of what was executed rather than as runnable instructions,
and the one citation of the controls in the cascade diagnosis now says the harness
is untracked instead of pointing at a path that no longer resolves. A stale
pointer to a deleted file is the positional-citation rot DESIGN §3 names; leaving
the reproducibility sentence would have been worse, because it is a claim about
evidence rather than a pointer.

What survives is what a reader can still check: the committed receipts, and the
corpus-hash anchor that decides whether they describe the tree in front of them.

This does not change any measured figure. The hygiene close (152 -> 0) and the
merged reconciliation (3,160 = 10 + 3,150) were established by execution before
the harness was deleted; deleting the instrument does not retract the reading.
The classifier's dissolution trigger has not moved either — it was always due to
delete when B2 lands OrdinaryLoadedCompilationClosure production. This just pays
that cost now, and loses re-runnability in exchange for not carrying a parallel
text-scanning classifier in the tree.

* Reconcile the README's head and byte-reproducibility line with the withdrawal

review 50839 (REQUEST_CHANGES) found the document contradicting itself: I added a
withdrawal section saying the receipts cannot be regenerated from a clean
checkout, and left three earlier passages asserting the opposite — the title
("reproducer"), the head paragraph ("Everything below regenerates from a named
tree"), the scaffold block describing the scripts in the present tense as though
still tracked, and the closing line "everything the measurement asserts is
byte-reproducible". A reader met the regenerability claim BEFORE the withdrawal.

That is the same defect class this PR exists to fix, one level up: an appended
correction is not a correction if the original claim survives above it. It is
also the rung-honesty failure DESIGN §5 names — the document reported a stronger
standing than the tree supports.

Reconciled rather than annotated:

- title is "retained execution record", not "reproducer";
- the head now states the frozen-record fact FIRST, before the recipe, so the
  ordering the review objected to is inverted;
- the scaffold block is past tense and says the scripts were removed EARLY, with
  the declared dissolution trigger (B2 landing OrdinaryLoadedCompilationClosure
  production) explicitly recorded as NOT yet fired — an honest early removal, not
  a trigger silently treated as satisfied;
- the byte-reproducibility passage is scoped to what it established at the time
  and followed by what a reader can check now without the harness: the
  corpus-hash anchor.

Swept the whole file for the class rather than fixing the three cited lines: no
present-tense regenerability claim remains.

* Reconcile the cascade diagnosis §15.1 with the withdrawn reproducer claim

review 50840 (REQUEST_CHANGES): §15.1 still called the measurement a "full
reproducer" with scripts "committed" and "the deterministic command sequence that
regenerates every number below", so the two authorities disagreed about whether
the measurement is regenerable — the README said no, the diagnosis said yes.

This is the SECOND time in this PR I fixed the cited location and left the class
alive elsewhere: c8710bf swept the README and patched exactly one line of the
diagnosis. Sweeping one authority is not sweeping the claim, and a §15 reader got
the old standing from the canonical design-linked document. Recorded plainly
because the pattern, not the line, is the defect.

§15.1 now states that the directory is a retained execution record, that the
numbers cannot be regenerated from a clean checkout, and — the part the review did
not ask for but honesty does — that the harness was removed EARLY, before its
declared dissolution trigger fired. The trigger (B2 landing
OrdinaryLoadedCompilationClosure production) is named as NOT fired, so nobody can
read the deletion as evidence that B2 landed. What remains checkable without the
harness is named: the corpus-hash anchor.

Swept the whole tree this time rather than the cited file: the only two documents
referencing the measurement are this one and the measurement README, and they now
agree.

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 9, 2026
…lan, fix a homonym

Commit A. Three defects, each found by execution and each mine.

1. THE SERVICE DEPENDENCY IS GONE, so the emission-model gap is no longer hit.
   filesystem_read requires the Filesystem service, and a service in the v1
   emission closure emits an unmodelled `dry_run.rs`. Both sources are now
   embedded, exactly as the sibling parser-walk witness does. This REDUCES the
   witness and the file says so: the provider is an authored copy of
   v2.std.live_tree's type declaration rather than the real module, so it no
   longer witnesses the live corpus or catches drift — it proves the binding
   mechanism only. Dissolve-on: the stage0 plan accounts for service-support
   files (or classifies them via v2.compiler.self_host.frontier), after which
   both sides return to reading the real files. The parser finding does not
   depend on this and is unaffected: it came from a structural census of
   02_parse's minting sites, not from reading the corpus.

2. THE PLAN ROW IS DERIVED, NOT REGISTERED. Re-running the generated-artifact
   gate produced the witness's row from the emission model itself, which is the
   sanctioned path the refusal names — unlike the CI auto-heal's hand-added rows,
   which I reset rather than built on.

3. A HOMONYM I INTRODUCED BROKE AN UNRELATED MODULE. `data subject_name` in the
   flat namespace collided with a same-named parameter in
   v1_tests_claim_v1_annotation_round_trip_test, whose emitted Rust then called a
   String as a function — four E0618s in a file this branch never touched. Every
   declaration here is now `idb_`-prefixed, matching the sibling witness's own
   convention. That this is the exact corpus-hygiene class #8067 closed,
   reintroduced by me two PRs later, is worth recording rather than quietly
   fixing.

AND THE VERIFY THAT CAUGHT IT WAS ITSELF NEARLY A FALSE GREEN. The first
post-rename verify reported regen_divergence_count=0 while the rebuild had FAILED
with those four errors — the old binary verifying its own stale output, the exact
trap the two-pass rule exists for. The build result has to be checked before the
verify result means anything. It now rebuilds clean and verifies at divergence 0.

Standing: build/regen green, two controls green, exactly one named expected
semantic red (witness_import_less_reference_reaches_the_real_provider) carried in
the declared roster.
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