Skip to content

Pay down static text witness batch A#657

Merged
flyingrobots merged 3 commits into
mainfrom
static-text-witness-burndown-02
Jun 13, 2026
Merged

Pay down static text witness batch A#657
flyingrobots merged 3 commits into
mainfrom
static-text-witness-burndown-02

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Batch A for the next static-text witness burndown.

This PR replaces brittle source/prose assertions with deterministic witnesses:

  • Adds npm run issue:dead-exports backed by scripts/dead-export-report.ts for Static text assertions in test/unit/scripts/dead-code-cleanup-shape.test.ts #296.
  • Adds canonical fixture corpus coverage for the dead-export report.
  • Adds test/helpers/MarkdownDocument.ts for structured heading/link/table/task-row checks.
  • Converts Batch A tests away from direct static prose checks toward AST, JSON-schema, runtime, Markdown-structure, and fixture-backed evidence.

Issues

Refs #296, #298, #299, #300, #301, #302, #304, #305, #306, #307.

No issue is auto-closed by this PR body. After merge, each issue should be closed only with concrete evidence anchored to merged paths, line numbers, and commit SHA.

Evidence

Command Result
npm exec vitest run test/unit/scripts/dead-export-report.test.ts test/unit/scripts/documentation-corpus-shape.test.ts test/unit/domain/trust/domainPurity.test.ts test/unit/scripts/factory-functions-in-tests-shape.test.ts test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts test/unit/scripts/glossary-shape.test.ts test/conformance/hygieneQuarantineGraduation.test.ts test/conformance/immutableSnapshotBuilder.test.ts test/unit/scripts/incremental-index-updater-closeout-shape.test.ts test/unit/scripts/index-builder-on-git-cas-shape.test.ts Passed: 10 files, 71 tests.
npm run issue:dead-exports -- test/fixtures/dead-export-report/src Passed; reports fixture candidates deterministically.
npm run issue:dead-exports -- src Passed; scanned 671 files / 2297 exports / 168 candidates.
npm run lint Passed.
npm run typecheck Passed.
npm run lint:md Passed.
npm run lint:links Passed: 1982 total, 1503 OK, 0 errors, 479 excluded.
npm run test:local Passed.
Pre-push IRONCLAD M9 gate Passed twice on this branch.

Notes

The dead-export scanner is deliberately a candidate report, not a release-blocking ratchet. It gives deterministic reachability evidence for #296 without pretending every zero-reference export is safe to delete.

Summary by CodeRabbit

  • New Features

    • Added an npm command to scan and report unused/“dead” exports and emit a Markdown report.
  • Tests

    • Added unit tests for the dead-export report and a markdown parsing helper for structured assertions.
    • Refactored many tests to use AST inspection and structured markdown helpers instead of fragile regex/string checks.
    • Removed an old source-code compliance check in favor of contract-focused tests.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d01eae47-6a55-40f9-a60f-10937635cc73

📥 Commits

Reviewing files that changed from the base of the PR and between 73799cd and 99ca11a.

📒 Files selected for processing (6)
  • scripts/dead-export-report.ts
  • test/helpers/MarkdownDocument.ts
  • test/unit/domain/trust/domainPurity.test.ts
  • test/unit/scripts/dead-export-report.test.ts
  • test/unit/scripts/documentation-corpus-shape.test.ts
  • test/unit/scripts/index-builder-on-git-cas-shape.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/unit/scripts/dead-export-report.test.ts
  • test/helpers/MarkdownDocument.ts
  • test/unit/domain/trust/domainPurity.test.ts
  • test/unit/scripts/documentation-corpus-shape.test.ts
  • test/unit/scripts/index-builder-on-git-cas-shape.test.ts
  • scripts/dead-export-report.ts

📝 Walkthrough

Walkthrough

Adds a dead-export CLI (scan, TS parse, export extraction, reference counting, Markdown report) with fixtures/tests; introduces MarkdownDocument test helper; refactors tests to use structured markdown queries and TypeScript AST checks; adds Zod manifest validation and removes one source-pattern conformance test.

Changes

Dead Export Detection Tool

Layer / File(s) Summary
Dead export report script implementation
scripts/dead-export-report.ts
Implements source discovery, TypeScript parsing, exported-declaration extraction, global identifier reference counting, findings sorting, and Markdown formatting. Exports buildDeadExportReport() and formatDeadExportReport() and supports direct CLI execution.
Dead export fixtures, npm script registration, and tests
package.json, test/fixtures/dead-export-report/src/*, test/unit/scripts/dead-export-report.test.ts
Adds issue:dead-exports npm script, fixture modules (UsedValue, UnusedValue, renamedUnusedFunction) and a consumer, plus Vitest tests that assert deterministic scan metrics and stable markdown output.

Test Infrastructure Improvements

Layer / File(s) Summary
MarkdownDocument parser helper
test/helpers/MarkdownDocument.ts
Adds an immutable MarkdownDocument class with typed result shapes and parsing/query helpers: headings, links, table rows, list items, task rows, plus fromFile and convenience predicates.
Test migrations to structured markdown queries
test/unit/scripts/documentation-corpus-shape.test.ts, test/unit/scripts/factory-functions-in-tests-shape.test.ts, test/unit/scripts/glossary-shape.test.ts, test/unit/scripts/incremental-index-updater-closeout-shape.test.ts, test/unit/scripts/index-builder-on-git-cas-shape.test.ts
Refactors multiple tests from raw file/string assertions to use MarkdownDocument structured queries and task/table lookup helpers.
AST-based test inspection improvements
test/unit/domain/trust/domainPurity.test.ts, test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts
Replaces regex/string-based checks with TypeScript AST parsing/traversal for module-specifier extraction, process.env detection, and console usage; expands GitGraphAdapter tests with deterministic stream plumbing and executeStream recording.
Schema validation and source conformance simplification
test/conformance/hygieneQuarantineGraduation.test.ts, test/conformance/immutableSnapshotBuilder.test.ts
Adds Zod-based hygiene manifest schema parsing and removes the ImmutableSnapshot.ts forbidden-pattern source scan test.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A parser born to parse, fixtures built to test,
Dead exports found, the tool knows best.
Markdown queries, cleaner than before,
ASTs traversed—no regex anymore!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: this PR delivers Batch A of static text witness burndown, replacing brittle assertions with deterministic witnesses.
Description check ✅ Passed The PR description includes all required template sections: a clear summary of the change, explicit issue references, a detailed evidence table showing verification outcomes, and helpful context about the dead-export scanner's purpose.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch static-text-witness-burndown-02

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.0.0
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If you tag this commit as v18.0.0, release workflow will publish.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts (1)

26-38: ⚡ Quick win

Make ByteCollectableStream.collect honor the CollectableStream options contract.

The test double currently ignores optional collect options, which can make stream-path tests less representative of the adapter contract.

Suggested patch
 class ByteCollectableStream implements CollectableStream {
   constructor(private readonly chunks: readonly Uint8Array[]) {}

   async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {
     for (const chunk of this.chunks) {
       yield chunk;
     }
   }

-  async collect(): Promise<Buffer | string> {
-    return Buffer.concat(this.chunks.map((chunk) => Buffer.from(chunk)));
+  async collect(opts?: { asString?: boolean; maxBytes?: number }): Promise<Buffer | string> {
+    const buffer = Buffer.concat(this.chunks.map((chunk) => Buffer.from(chunk)));
+    if (typeof opts?.maxBytes === 'number' && buffer.byteLength > opts.maxBytes) {
+      throw new Error('stream exceeds maxBytes');
+    }
+    return opts?.asString ? buffer.toString('utf8') : buffer;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts`
around lines 26 - 38, The test stub ByteCollectableStream currently implements
collect() but ignores the CollectableStream options contract; update
ByteCollectableStream.collect to accept the optional options parameter (matching
the CollectableStream signature) and return a string when an encoding option is
provided or a Buffer otherwise. Specifically, change the collect signature on
ByteCollectableStream to accept options (e.g., collect(options?: { encoding?:
string })), use Buffer.concat(this.chunks.map(...)) to build the result, and if
options?.encoding is set return result.toString(options.encoding) else return
the Buffer; ensure the async iterator and other behavior remain unchanged so
tests that pass collect options exercise the same contract as the real adapter.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/unit/domain/trust/domainPurity.test.ts`:
- Around line 36-43: moduleSpecifiers currently only extracts module specifiers
from ImportDeclaration nodes, so export statements like `export ... from
'.../infrastructure/'` are missed; update moduleSpecifiers to also handle
ExportDeclaration by checking ts.isExportDeclaration(statement) and
ts.isStringLiteral(statement.moduleSpecifier) and include
statement.moduleSpecifier.text in the returned array (preserve the existing
ImportDeclaration handling in the same function so both import and export-from
specifiers are collected for the boundary checks).

---

Nitpick comments:
In `@test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts`:
- Around line 26-38: The test stub ByteCollectableStream currently implements
collect() but ignores the CollectableStream options contract; update
ByteCollectableStream.collect to accept the optional options parameter (matching
the CollectableStream signature) and return a string when an encoding option is
provided or a Buffer otherwise. Specifically, change the collect signature on
ByteCollectableStream to accept options (e.g., collect(options?: { encoding?:
string })), use Buffer.concat(this.chunks.map(...)) to build the result, and if
options?.encoding is set return result.toString(options.encoding) else return
the Buffer; ensure the async iterator and other behavior remain unchanged so
tests that pass collect options exercise the same contract as the real adapter.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b8860d5-e471-4b58-b912-169e85c88203

📥 Commits

Reviewing files that changed from the base of the PR and between e4bb016 and 73799cd.

📒 Files selected for processing (18)
  • package.json
  • scripts/dead-export-report.ts
  • test/conformance/hygieneQuarantineGraduation.test.ts
  • test/conformance/immutableSnapshotBuilder.test.ts
  • test/fixtures/dead-export-report/src/consumer.ts
  • test/fixtures/dead-export-report/src/index.ts
  • test/fixtures/dead-export-report/src/renamed-unused-function.ts
  • test/fixtures/dead-export-report/src/unused-value.ts
  • test/fixtures/dead-export-report/src/used-value.ts
  • test/helpers/MarkdownDocument.ts
  • test/unit/domain/trust/domainPurity.test.ts
  • test/unit/infrastructure/adapters/GitGraphAdapter.gitCasPersistence.test.ts
  • test/unit/scripts/dead-export-report.test.ts
  • test/unit/scripts/documentation-corpus-shape.test.ts
  • test/unit/scripts/factory-functions-in-tests-shape.test.ts
  • test/unit/scripts/glossary-shape.test.ts
  • test/unit/scripts/incremental-index-updater-closeout-shape.test.ts
  • test/unit/scripts/index-builder-on-git-cas-shape.test.ts
💤 Files with no reviewable changes (1)
  • test/conformance/immutableSnapshotBuilder.test.ts

Comment thread test/unit/domain/trust/domainPurity.test.ts
@flyingrobots

Copy link
Copy Markdown
Member Author

@codex self-review found issues that should be resolved before merge. Evidence below is deterministic and reproducible against origin/main...HEAD on branch static-text-witness-burndown-02.

Severity File Lines Infraction Deterministic evidence Recommended mitigation prompt
P1 Major test/unit/domain/trust/domainPurity.test.ts 36-42, 99-106 Architecture firewall regression: the AST refactor only collects ImportDeclaration module specifiers, so export ... from, dynamic import(), and require() can leak infrastructure/ or adapters/ through the trust domain without failing this test. nl -ba test/unit/domain/trust/domainPurity.test.ts | sed -n '36,106p' shows moduleSpecifiers() only accepts ts.isImportDeclaration(...); assertions depend exclusively on that list. Update domainPurity to collect forbidden module specifiers from ImportDeclaration, ExportDeclaration with moduleSpecifier, dynamic import() calls, and require() calls. Add deterministic inline/fixture regression cases proving each forbidden form fails while comments remain ignored.
P2 Major scripts/dead-export-report.ts; test/fixtures/dead-export-report/src/index.ts; test/unit/scripts/dead-export-report.test.ts 176-189; fixture 1-3; test 14-19 Dead-export witness reports re-export aliases by local implementation name instead of public exported API name. The fixture encodes the bug: renamedUnusedFunction as PublicUnusedFunction is reported as renamedUnusedFunction. npm run issue:dead-exports -- test/fixtures/dead-export-report/src | rg 'index.ts|renamedUnusedFunction|PublicUnusedFunction' outputs index.ts / renamedUnusedFunction; nl -ba test/fixtures/dead-export-report/src/index.ts | sed -n '1,3p' shows the public export is PublicUnusedFunction. Track export declarations with separate exportedName and referenceName. Report element.name.text for the public export while counting references through element.propertyName?.text ?? element.name.text. Update the canonical fixture assertion to expect index.ts:PublicUnusedFunction:re-export.
P3 Medium test/unit/scripts/index-builder-on-git-cas-shape.test.ts 5-18 Refactor weakens the original docs contract: the test no longer asserts the design mentions whole-blob reads, and no longer guards the v17 release ledger against INFRA_index-builder-on-git-cas ← god file-size theater. git diff origin/main...HEAD -- test/unit/scripts/index-builder-on-git-cas-shape.test.ts shows removal of both assertions; current lines 8-17 only check heading/list rows/task status. Extend MarkdownDocument with a precise containsText() or paragraph helper, then restore the semantic assertions for whole-blob reads and the negative release-ledger file-size-theater marker.
P4 Low test/unit/scripts/documentation-corpus-shape.test.ts 87-91 Archive-index test no longer proves the archive is explicitly non-canonical. The removed phrase was the behavioral reason this archive index exists; link presence alone is weaker. git diff origin/main...HEAD -- test/unit/scripts/documentation-corpus-shape.test.ts shows removal of should not be treated as the canonical current docs set; current lines 87-91 only check heading and links. Add a text/paragraph assertion through MarkdownDocument so the archive index must still state that archived docs are not the canonical current docs set.
P4 Low scripts/dead-export-report.ts 137-174 Strict style-policy violation: pushExportedStatement is 36 nonblank lines, over the repository’s 35-line function/method limit. awk 'NR>=137 && NR<=174 && NF { count++ } END { print count }' scripts/dead-export-report.ts returns 36. Split pushExportedStatement into smaller concept helpers, for example declaration-kind dispatch and exported-variable handling, without adding generic helper sludge.

Current checks observed during review:

  • git status --porcelain: clean before review.
  • git fetch origin --prune: completed.
  • git diff --check origin/main...HEAD: clean.
  • gh pr checks 657 --watch=false: all listed checks passing, including CodeRabbit.

@flyingrobots

Copy link
Copy Markdown
Member Author

@codex review-fix update pushed in 99ca11a6.

Prior finding Resolution Evidence
P1 domain-purity scanner missed export ... from, dynamic import(), and require() domainPurity now walks the AST for import declarations, export declarations, dynamic import calls, and require calls, with deterministic fixture cases including commented import text. WARP_TEST_MIN_FREE_MB=0 npm run test:local -- test/unit/domain/trust/domainPurity.test.ts passed as part of targeted suite.
P2 dead-export report used local alias name instead of public export name Dead-export declarations now carry separate exportedName and referenceName; report output uses the public exported name while counting references by the local name. npm run issue:dead-exports -- test/fixtures/dead-export-report/src reports PublicUnusedFunction.
P3 index-builder-on-git-cas docs-shape contract weakened Restored assertions for whole-blob reads and the negative INFRA_index-builder-on-git-cas ← god ledger marker. Targeted docs-shape tests passed.
P4 archive index no longer proved non-canonical status Restored exact text assertion through MarkdownDocument.containsText(...). Targeted docs-shape tests passed.
P4 pushExportedStatement exceeded 35-line limit Split direct-export dispatch into pushDirectExportedStatement; measured functions are now 14 and 29 nonblank lines. awk line-count check returned pushExportedStatement 14 and pushDirectExportedStatement 29.

Local validation completed before push:

  • git diff --check
  • npm run issue:dead-exports -- test/fixtures/dead-export-report/src
  • npm run issue:dead-exports -- src
  • WARP_TEST_MIN_FREE_MB=0 npm run test:local -- test/unit/domain/trust/domainPurity.test.ts test/unit/scripts/dead-export-report.test.ts test/unit/scripts/index-builder-on-git-cas-shape.test.ts test/unit/scripts/documentation-corpus-shape.test.ts
  • npm run lint
  • npm run typecheck
  • npm run lint:md
  • npm run lint:links
  • WARP_TEST_MIN_FREE_MB=0 npm run test:local
  • pre-push IRONCLAD M9 gate, including link check, lint/typecheck/policy/surface/markdown gates, and full stable unit-test shards

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.0.0
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If you tag this commit as v18.0.0, release workflow will publish.

@flyingrobots flyingrobots merged commit 2ad3900 into main Jun 13, 2026
18 checks passed
@flyingrobots flyingrobots deleted the static-text-witness-burndown-02 branch June 13, 2026 04:23
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