Skip to content

Report pins a branch drops and modules it leaves unsealed, without refusing either - #436

Merged
lamemustafa merged 2 commits into
masterfrom
surface/416-coverage-report
Sep 16, 2026
Merged

lamemustafa merged 2 commits into
masterfrom
surface/416-coverage-report

Conversation

@lamemustafa

@lamemustafa lamemustafa commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Implements #416's second decision — report, don't refuse. Now a single commit on master (after #434's squash and #437); nothing stacked.

What it reports

scripts/surface_coverage_report.py runs after every successful reseal.sh (not --verify) and always exits 0. Against the merge-base with origin/master it lists:

  • a dropped pin — a surface conflict resolved by taking the base side loses entries and the gate passes;
  • a module declared directly by a pinned module and newly left unpinned — a new file, a newly attached file, or one pinned at the base.

What it does not check — stated where it is read

In its all-clear line, docstring, docs/release-process.md and the reseal.sh comment: code moved between existing files; a new module under an unpinned parent, even one carved out of a pinned file; deeper descendants; a pinned file that stops being compiled; a test-only or feature-gated module becoming production; a new crate root. A clean report is not evidence nothing left the seal. The all-clear line says so.

(The previous version named only the first blind spot, which implied it was the only one. Review found the rest.)

Module resolution

Follows rustc, walked from crate roots: a bare mod resolves beside a file that owns its directory (crate root, mod.rs, #[path]-loaded) and under <stem>/ otherwise; #[path] resolves beside the declaring file. Review compared file sets — not only counts — with rustc's dep-info for every crate in the repo and found them identical. The docstring lists forms it does not handle (cfg_attr path, r# names, include!, macro-generated modules, …); none occurs here.

Tests: 32, against 34 mutations — all caught

The 19 from the first version plus 15 more, including every survivor review found. Six needed the tests strengthened before they failed:

  • #[path] in an ordinary file — the shape agent.rs uses for nearly every agent_*.rs;
  • test-only and feature-gate inheritance through a file, not just an inline block;
  • pub(crate)/pub(in …) with a cfg;
  • the new-file and pinned-at-base report clauses;
  • a relative --surface from a subdirectory;
  • an escaped quote in a char literal ('\"'), which would otherwise open a string to end of file.

Writing that last test exposed a real bug, fixed: on macOS /tmp and /var are symlinks, and a surface under a symlinked root was reported as outside the repository.

Verified locally

surface_coverage_report.test.py 32/32 · reseal.sh --verify exit 0 · reseal.test.mjs 3 pass, 0 skipped · check-ci-workflow-consistency.mjs exit 0 · hook's first real run: clean.

Doesn't touch MAX_SURFACE_FILES or the pin guard, so against #438 only the surface/matrix hashes need resealing, whichever lands second.

🤖 Generated with Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Base automatically changed from surface/416-pin-admission-and-egress to master September 16, 2026 09:01
@lamemustafa
lamemustafa force-pushed the surface/416-coverage-report branch from 69ccd46 to 1e4b776 Compare September 16, 2026 09:21
@lamemustafa lamemustafa changed the title Report pins a branch drops and modules it unseals, without refusing either Report pins a branch drops and modules it leaves unsealed, without refusing either Sep 16, 2026
lamemustafa and others added 2 commits September 16, 2026 15:00
…ither

bridge#416's second decision: report, and let a person decide. Rebuilt on
master after #434's squash, and after two reviews.

scripts/surface_coverage_report.py runs after every successful reseal.sh
(not --verify) and never fails it. Against the merge-base with
origin/master it lists a dropped pin, and a module declared directly by a
pinned module and newly left unpinned -- a new file, a newly attached
file, or one pinned at the base.

What it does not check is stated where it will be read: in its all-clear
line, its docstring, docs/release-process.md and the reseal.sh comment.
Review showed the first wording ("code moved between existing files")
named one blind spot and implied it was the only one. It also misses a
new module under an unpinned parent even when carved out of a pinned
file, deeper descendants, a pinned file that stops being compiled, a
test-only or feature-gated module becoming production, and a new crate
root.

Module resolution follows rustc, walked from crate roots: a bare `mod`
resolves beside a file that owns its directory (crate root, mod.rs, or
declaring file. Review compared file sets, not just counts, with rustc's
dep-info for every crate here and found them identical. The docstring
lists the forms it does not handle, none of which occurs in the repo.

Relative --surface paths now resolve against the caller's directory, and
paths are compared as real paths: on macOS /tmp and /var are symlinks, and
the first version reported a surface under a symlinked root as outside the
repository.

32 tests, run against 34 mutations -- the 19 from the first version, and
15 more including every survivor review found -- and all 34 fail a test.
Six needed the tests strengthened first: #[path] in an ordinary file
(the shape agent.rs uses for nearly every agent_*.rs), inheritance of
test-only and feature gates through a file, restricted visibility with a
cfg, the new-file and pinned-at-base report clauses, a relative surface
from a subdirectory, and an escaped quote in a char literal.

docs/module-decomposition.md now points at the report and says what it
does not catch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Inner #![cfg] does occur here, in five test files; none of them declares a
module, which is the case the resolver does not handle. And the test file
now says file sets, matching what the review compared, not counts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lamemustafa
lamemustafa force-pushed the surface/416-coverage-report branch from 8d2df85 to ab5bde0 Compare September 16, 2026 09:30
@lamemustafa
lamemustafa merged commit cacbc7b into master Sep 16, 2026
13 checks passed
@lamemustafa
lamemustafa deleted the surface/416-coverage-report branch September 16, 2026 09:40
lamemustafa added a commit that referenced this pull request Sep 16, 2026
docs/proposed-rust-module-conventions.md item 2: extract inline test
modules first -- mechanical, no production change. These were the two
largest remaining inline test blocks among pinned production files: 1,951
lines in runtime.rs and 1,848 in connection.rs. Production lines are
unchanged; the files drop to 3,490 and 2,024 lines.

Each block moves to <stem>_tests.rs beside its parent, kept as the same
child module (`#[cfg(test)] #[path = "..."] mod tests;`), so private access
and test paths are unchanged, and relative include_str!/include_bytes!
paths still resolve from the same directory.

Checked, not asserted:
- The moved bodies differ from the removed blocks only by four columns of
  indentation, compared against HEAD line by line. The eight multi-line
  string literals were left byte-identical rather than dedented, since
  their whitespace can be test data.
- rustfmt then re-wrapped lines using the freed columns. Its only
  non-whitespace changes are four trailing commas; all 1,057 string
  literals are identical before and after.
- Test names are identical before and after: 99 under default features,
  110 with voucher-scan, which gates 11 of them. All pass under both.
- cargo clippy --lib --tests -D warnings is clean.
- Resealing changed exactly two pinned hashes, and the #436 coverage
  report counts exactly two newly unsealed test-only modules, listing
  nothing else. Unpinned test modules are the repository norm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lamemustafa added a commit that referenced this pull request Sep 16, 2026
…ot by name

#440, #441 and #442 moved inline `#[cfg(test)] mod tests { ... }` blocks
into sibling files loaded by `#[cfg(test)] #[path = "..."] mod tests;`.
check-tally-request-builder-hazards.mjs skipped only the inline form, so it
began reading those files as production code. Results did not change, but
a test that builds a hazard-shaped string as an expectation would have
raised a false alarm.

Skipping any file named *_tests.rs was rejected: a safety scanner must not
exempt production code for its file name. Instead a file is skipped only
when it is actually loaded as a test module:

- Edges: a brace-depth-0 out-of-line `mod name;` whose attribute group has
  a cfg implying test (cfg(test), or test as an argument of cfg(all(...))),
  with #[path] or bare in a crate root or mod.rs; plus any such declaration
  made by a file already test-only, iterated to a fixed point.
- Vetoes, from every .rs file in the repository and matched by basename
  case-insensitively: any other `mod name;` at any depth (including macro
  bodies and inline modules), any `path = "..."` or include!-family string
  not part of an edge (covering cfg_attr), and every Cargo crate root.
- Files whose braces underflow or do not end balanced contribute no edges.
- Everything unhandled -- cfg(any(...)), #[path] inside an inline module,
  r#name -- leaves the file scanned, so an error is a false alarm, never a
  missed hazard.

The design was critiqued before implementation. The critique found four
ways the first draft could skip a production file -- a non-test
declaration it did not recognise, a Cargo target, a declaration outside the
scan roots, case variants -- and that it would still have scanned 24 of the
74 extracted files: 22 declared by other test files, one under
cfg(all(test, ...)), one bare in a mod.rs. The veto set, the fixed point and
those two cfg/bare shapes are the response.

Checked, not asserted: on this repository the skipped set is exactly the
74 files the rustc-validated module graph from #436 marks test-only, path
for path; the 10 pinned violations are unchanged. The skipped count is now
pinned too, so a lexer regression that quarantines too much fails the gate.

Main now runs under `import.meta.main` so the functions can be imported;
a test runs the real script as a child process so a main that silently
does nothing cannot pass. 15 fixture tests; 15 mutations of the scanner
(trust file names, accept any cfg mentioning test, drop each veto, trust
unbalanced files, accept nested declarations, drop propagation, drop the
crate-root veto, case-sensitive veto, #[path] under the stem, main never
running, no bare-mod detection, strings or comments not skipped, only the
first attribute, no raw-string path) each fail a named test. One of those
first survived because a fixture's production declaration masked the
lexer; the fixture was fixed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant