feat: implement the Repository Hygiene and Layout Policy (design 2026-07-28) - #672
Conversation
Red evidence for the Repository Hygiene and Layout Policy implementation (Engineering/designs/2026-07-28-repository-hygiene-design.md). Defines the contract for scripts/check_repo_hygiene.py (static and working-tree modes over fixture git trees: root allowlist, forbidden suffixes, merge remnants, local settings, retired paths, binary magic/size, personal absolute paths, generated-file exception metadata, archive manifest checksums, experiment metadata and review expiry, rustfmt uniqueness, version drift, and post-suite tree cleanliness) plus structural guards for the scripts/build_windows_installer.ps1 packaging entry point. Run: python3 -m unittest discover -s tests/tooling Result at this commit: 32 tests, 30 failures, 2 errors (checker and entry point intentionally absent). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
Implements the enforcement layer of the approved design (Engineering/designs/2026-07-28-repository-hygiene-design.md): - REPOSITORY_HYGIENE.md: binding Repository Hygiene and Layout Policy (placement rules, tracked/ephemeral rules, output roots, archive manifest schema, single sources of truth, exceptions process). - .repo-hygiene.toml: machine-readable profile (root allowlist, forbidden suffixes/names, retired paths, binary/size declarations, personal-path placeholders, generated-file exceptions, version sources, approved output roots). Transitional version mirrors (src/version.rs, .build_meta.json, wix.toml) and the installer-consumed pinned VSIX are declared exceptions pending the packaging consolidation. - scripts/check_repo_hygiene.py: dependency-free checker with static and working-tree modes. Green evidence: the 27 checker unit tests from the preceding Red commit now pass (python3 -m unittest discover -s tests/tooling); the 5 installer placement guards stay red until the migration commit. Static mode against this commit reports 118 violations - the migration worklist the following commits burn down, including 16 tracked AST dumps that embed a personal Windows home directory and a real package-lock.json version drift (26.7.46 vs 26.7.59). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
… homes
Applies the initial migration from the approved design
(Engineering/designs/2026-07-28-repository-hygiene-design.md). Static
hygiene mode is clean at this commit (118 violations -> 0) and all 32
tooling tests pass, including the installer placement guards.
Deleted reproducible/unsafe debris: compare_search_full_clean, every
tracked *.ast.txt / *.lex.txt dump (16 embedded a personal Windows home
directory), docs_code_blocks_report.json, validation_report.json, the
mutable docs validation cache and timestamp report, linter .orig/.rej
merge remnants, the raw clippy log, generated test_rust_files/,
google_index.html, Nexus/.claude/settings.local.json, dead
crates/wfl_core, LabsTest/email.wfl (personal identifier, not archived),
and .rustfmt.toml (rustfmt.toml is now the sole config, edition 2024).
Reclassified legacy WFL programs per the design's disposition table:
fixtures to tests/fixtures/{modules,diagnostics,tooling}/, 15 converted
asserted TestPrograms under modules/ constants/ nexus/ (describe/expect,
all passing; load_container pins load-module scope isolation as a
negative test), examples/web/{blog_server,html_server}.wfl (personalized
wording removed, analyzer-validated), experiments/{nexus,syntax}/ with
required metadata (issues #668/#669), and the remaining probes archived.
New tests/diagnostics_fixtures_test.rs asserts diagnostics and exit
status for the intentionally invalid fixtures (analyzer add-report gap
pinned as >=4, tracked in #671).
Split Tools/: rust_loc_counter.py -> scripts/metrics/, wfl_md_combiner.py
-> scripts/docs/, WFL ports -> examples/tools/ (validated; output moved
under target/reports/), spec -> Engineering/components/, MSI plan and its
harnesses -> Archive/implementation-plans/windows-installer/, config
checker and MSI launcher retired. build_msi.ps1 ->
scripts/build_windows_installer.ps1 (+ -BumpVersion from the retired
launcher).
Moved records: Dev diary -> History/dev-diary/2026/ (+ README),
Docs/development -> Docs/contributing, active designs/plans/evidence ->
Engineering/, Docs/Archive + superpowers plans + TODO + rust_loc_report +
root bug.md + WFLHASH reviews -> categorized Archive/ paths indexed by
Archive/manifest.json (sha256 per entry, 47 entries, all non-normative).
Promoted .jules/bolt.md lessons to History/perf-lessons.md; .jules and
.cursor files are now thin adapters to root policy.
Also: fixed .gitignore (Icon? case rule, .vscode negations, recursive
.claude/settings.local.json, dump/report ignores), repointed
rust_loc_counter_test.wfl at target/test-artifacts/, docs validation
report now writes to target/reports/docs-validation/, bump_version.py now
updates both package-lock.json version fields (fixing the live 26.7.46 vs
26.7.59 drift), and working-tree mode correctly parses -z rename records.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
…layout - GOVERNANCE.md: new §3.8 makes REPOSITORY_HYGIENE.md a binding technical policy; related-documents table updated; Dev Diary and wflpkg paths fixed. - CONTRIBUTING.md / README.md / Docs/README.md / Docs/contributing/index.md: reference the hygiene policy and checker; Docs/development links now point at Docs/contributing/; moved design docs now referenced in Engineering/. - AGENTS.md and CLAUDE.md: project-structure sections describe the canonical layout (Engineering/, History/, Archive/, experiments/, tests/fixtures/), Dev Diary path updated to History/dev-diary/<year>/, and a Repository Hygiene critical rule added; .cursor/.jules noted as thin adapters. - Archived the generated DOC_CODE_AUDIT.md snapshot (manifest entry added); Docs/README.md now tells readers to regenerate it under target/reports/. - generate_rust_loc_report.py writes to target/reports/metrics/ instead of Docs/. - Dev Diary entry for this change (History/dev-diary/2026/). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
… runner - New early repo-hygiene matrix job (Linux + Windows) runs the checker's fixture-tree unit tests and static mode over the tracked tree; bump-version now depends on it. - integration-tests and run-wfl-programs end with a working-tree hygiene check on both OSes, proving the suites leave the checkout clean outside the approved output roots. - Workflows that write directly to the repository (ci.yml bump-version, versioning.yml, auto-fmt.yml) run the static check immediately before their push; update-security-doc.yml opens a PR and is covered by PR CI. - run_integration_tests.sh/.ps1 now execute TestPrograms feature subdirectories (modules/, constants/, nexus/) recursively, excluding docs_examples/ (validated separately) and the execute_pages/ and test_data/ fixture trees, and treat error_examples/ programs as expected-fail — so a converted test that regresses actually gates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
…nk fixes - CHANGELOG.md: Unreleased Added/Changed entries for the hygiene policy, checker, CI gate, and layout migration. - examples/web/README.md: document the two validated web examples. - run_integration_tests.sh: replace mapfile -d with a while-read loop (macOS ships bash 3.2, which lacks mapfile -d). - Fix relative links in design docs moved to Engineering/ so they resolve from their new location. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
…ample
Findings from running the new working-tree hygiene gate over the full
suite chain (integration, web, docs validation):
- wfl --lex/--parse dumps now write under target/reports/dumps/ with a
flattened name instead of beside the source file — the exact mechanism
that produced the formerly tracked AST/lex dumps (which embedded
absolute personal paths). CLI docs in AGENTS.md/CLAUDE.md updated.
- Repo and TestPrograms .wflcfg set debug_report_enabled = false and
execution_logging = false (config discovery is closest-wins, so both
files need the switches). Intentional-error programs no longer drop
*_debug.txt next to themselves on every run; the packaged installer
config still enables debug reports for end users.
- File I/O and middleware TestPrograms write under
target/test-artifacts/{file_io,web}/ instead of the repository root
(flush_test_*, test_output.txt, test.log, test_append.log,
middleware logs, google_index.html).
- tests/file_io_error_handling_test.rs: the write-after-close test also
cleans the stray 'file1' the rejected write currently creates.
- error_examples/type_error.wfl used '42 plus "hello"', which is legal
string-coercing concatenation today and exited 0 — the example was
asserting an error that no longer exists. It now uses 'minus', which
genuinely fails (docs must be honest; error examples too).
- Profile: python __pycache__ directories allowed as ignored output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
|
Important Review skippedToo many files! This PR contains 270 files, which is 170 over the limit of 100. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (270)
You can disable this status message by setting the 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. Comment |
| # The macOS Finder icon file is literally "Icon\r". The old `Icon?` glob also | ||
| # swallowed the tracked `icons/` directory on case-insensitive filesystems. | ||
| Icon[\r] |
There was a problem hiding this comment.
🟡 macOS Finder icon files are no longer ignored and will show up as uncommitted changes
The rule meant to hide the macOS Finder icon file was rewritten to Icon[\r] (.gitignore:84), which Git reads as the plain name "Iconr" instead of the carriage-return name the Finder actually creates, so the icon file stops being ignored.
Impact: On macOS the Finder-created icon file appears as an untracked change, which now fails the new post-test cleanliness check and can be committed by accident.
Why the bracket form does not match the carriage-return name
Git's wildmatch treats a backslash inside [...] as an escape of the next literal character, not as a C-style escape sequence; \r therefore means the letter r, so Icon[\r] is equivalent to Iconr.
Verified locally:
$ printf 'Icon[\\r]\n' > .gitignore
$ git status --porcelain --ignored | cat -A
?? "Icon\r" <- macOS icon file NOT ignored
!! Iconr <- unrelated name ignored instead
The working-tree gate added in this PR (.github/workflows/ci.yml:304-310) fails on any untracked file outside target/, so a developer on macOS running the suite locally would now hit this. The conventional fix is a literal carriage return after Icon (as in GitHub's macOS.gitignore).
Prompt for agents
The `.gitignore` entry `Icon[\r]` does not do what its comment claims. Git's wildmatch treats a backslash inside a bracket expression as an escape of the following literal character, so `[\r]` is the single character `r` — the pattern matches a file literally named `Iconr` and does NOT match the macOS Finder icon file, whose name is `Icon` followed by a carriage return (0x0D). The goal of the change (avoid the old `Icon?` glob swallowing the tracked `icons/` directory on case-insensitive filesystems) is still valid, but the replacement must contain an actual carriage-return byte after `Icon`, the way GitHub's canonical macOS.gitignore does it. Update the rule so the byte sequence `Icon\x0D` is written literally into the file (and keep a comment noting the trailing CR is significant so future edits/editors do not strip it).
Was this helpful? React with 👍 or 👎 to provide feedback.
| review_by = datetime.date.fromisoformat(m.group(1)) | ||
| if review_by < today: | ||
| report.add("experiment-expired", readme_rel, | ||
| f"Review-by {review_by} has passed: promote, archive, " | ||
| "or remove the experiment") |
There was a problem hiding this comment.
🔍 Experiment Review-by dates become a hard CI failure on a fixed calendar date
Both experiment READMEs pin Review-by: 2026-10-30 (experiments/nexus/README.md:14, experiments/syntax/README.md:14) and check_experiments fails the blocking repo-hygiene job as soon as that date passes. That is the intended policy behaviour, but it means unrelated PRs will start failing CI on a date with no other trigger, and the only recovery is a policy-touching commit. Worth having issues #668/#669 scheduled well before the expiry so main does not go red unexpectedly.
Was this helpful? React with 👍 or 👎 to provide feedback.
| - name: Static hygiene check before push | ||
| run: python3 scripts/check_repo_hygiene.py --mode static |
There was a problem hiding this comment.
🔍 auto-fmt workflow calls the checker without setting up Python
The new step runs python3 scripts/check_repo_hygiene.py, but this job has no actions/setup-python step (unlike the repo-hygiene and bump-version jobs), so it depends on the runner image's default python3 being ≥ 3.11 — the checker exits 2 with HYGIENE-ERROR: Python 3.11+ with tomllib is required on anything older (confirmed locally on 3.10). The blacksmith-2vcpu-ubuntu-2404-arm image should ship 3.12, so this is likely fine, but it is an undeclared dependency that would turn into an opaque exit-2 failure blocking the auto-format push if the image ever changes.
Was this helpful? React with 👍 or 👎 to provide feedback.
`tests/diagnostics_fixtures_test.rs::constant_mutation_is_rejected_for_every_mutation_form` landed with #672 pinning `>= 4` reports and a comment pointing at #671. With the analyzer gap closed the fixture reports all five, so the assertion is now an exact `== 5`. Also updates the dev diary for the new repository layout: the file moved to `History/dev-diary/2026/`, and the prose now points at `tests/fixtures/diagnostics/constant_immutability.wfl` rather than the retired `syntax_test/` tree. Refs #671 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR
…675) * fix(ci): repair post-merge gate failures on main Three follow-ups from the first run of the hygiene gates on main: - vscode-extension/package-lock.json: sync both version fields to 26.7.60. A 'Bump version to 26.7.60' commit landed on main between this branch's base and its merge, made with the pre-fix bump script that skipped the lock file; the merged tree therefore tripped the new version-drift rule (CI repo-hygiene job and auto-fmt pre-push check). Future bumps update the lock via the fixed scripts/bump_version.py already on main. - ci.yml: set up Python 3.12 in the integration-tests and run-wfl-programs jobs. The Windows runner's default python lacks tomllib, so the new post-suite working-tree hygiene steps failed with HYGIENE-ERROR even though every test in both suites passed. - rustfmt.toml: newline_style Unix -> Auto. The removed duplicate .rustfmt.toml (no newline_style) was rustfmt's effective config; with it gone, Unix style made the nightly Windows build's fmt check reject the autocrlf CRLF checkout. Auto restores the long-standing behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ * fix: hash archive blobs from the git index, not working-tree bytes The Windows repo-hygiene leg (previously cancelled by fail-fast, so never observed) failed the archive-manifest fixture test: autocrlf materializes text files with CRLF on Windows, so hashing working-tree bytes makes every archived text file's sha256 drift from the manifest. The checker now hashes the staged blob (git show :path) — canonical LF on every platform — and the test fixture writes with newline='\n' so fixture bytes are deterministic. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ --------- Co-authored-by: Claude <noreply@anthropic.com>
) * test: red coverage for dropped `add ... to CONST` analyzer report (#671) `add <value> to <name>` parses to `AddToListStatement`, which the analyzer never checked for constness, so a program mutating a constant five ways got only four `Cannot modify constant` reports. The same hole covers `remove ... from CONST` and `clear CONST`. Red evidence: `add_to_constant_is_rejected_on_its_own` (0 reports, expected 1), `every_mutation_form_of_a_constant_is_reported` (4, expected 5) and `list_mutation_statements_reject_constant_targets` (0, expected 3) all fail; `mutable_targets_are_still_accepted` already passes and guards the fix against over-reporting. Refs #671 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * fix(analyzer): report constant mutation for add/remove/clear (#671) `add <value> to <name>` parses to `AddToListStatement` rather than `Assignment` — the target's type is unknown at parse time, so the interpreter decides between arithmetic and list-append at runtime. The analyzer's `AddToListStatement` arm only checked that the target name was defined, never that it was writable, so `add 10 to MAX_SIZE` on a constant produced no report. A program mutating one constant five ways got four reports instead of five; the `add` line was the silent one. `remove ... from` and `clear` had the same hole. The analyzer now tracks constants explicitly in a `constant_bindings` set of `SymbolBindingKey`s, populated when a `store new constant` declaration is defined, and `report_constant_mutation` consults it from all three bare-name mutation statements. Keying by binding rather than name keeps an inner-scope shadow from being mistaken for the constant. `SymbolKind::Variable { mutable: false }` deliberately is NOT the test: action parameters, container-method parameters, loop variables, try/when error bindings, predefined globals, and REPL parent-scope variables are all registered immutable without being constants, and appending to a list parameter has always been legal. This also closes a runtime hole for constant lists. A constant number was already rejected at runtime via `Environment::assign`, but `add`/`remove`/ `clear` on a constant list mutated the `Rc<RefCell<Vec<Value>>>` in place without ever reassigning the binding, so the constant check was bypassed. Docs: `Docs/03-language-basics/variables-and-types.md` claimed constants were "planned for future versions" and `Docs/06-best-practices/naming-conventions.md` that "true immutability is limited today" — both false since `store new constant` shipped. Both now document the real syntax and the rejected mutation forms, with two validated examples registered in the docs-examples manifest. Verified: `cargo test --all --no-fail-fast` (150 suites, 0 failures), clippy `-D warnings`, `cargo fmt --check`, 111 `TestPrograms/` programs against the release binary, and `scripts/validate_docs_examples.py` (21/21). Fixes #671 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * test: tighten the constant-mutation fixture pin to all 5 forms (#671) `tests/diagnostics_fixtures_test.rs::constant_mutation_is_rejected_for_every_mutation_form` landed with #672 pinning `>= 4` reports and a comment pointing at #671. With the analyzer gap closed the fixture reports all five, so the assertion is now an exact `== 5`. Also updates the dev diary for the new repository layout: the file moved to `History/dev-diary/2026/`, and the prose now points at `tests/fixtures/diagnostics/constant_immutability.wfl` rather than the retired `syntax_test/` tree. Refs #671 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * fix(analyzer): carry constants across branch merges; honest docs (#671) Addresses three review findings on #674. Constant markers survive a branch merge. `IfStatement`/`SingleLineIf` re-define a binding created on both arms into the parent scope under a new binding key, and `pop_scope_promoting_except` does the same for promoted scopes — neither moved the `constant_bindings` entry. The symbol keeps `mutable: false`, so `change` still reported while `add`/`remove`/`clear` went silent: the #671 defect again, one scope up. Both paths now carry the marker, mirroring the existing `mutable: then && else` merge (constant on either arm means constant after). Before the fix, `add 1 to LIMIT` after such a branch escaped analysis entirely and was caught only at runtime; for a constant list it would not have been caught at all. Docs no longer overclaim. "WFL refuses to modify it" / "every mutation form is rejected" is false while `push with <list> and <value>` is unchecked. Both pages now enumerate the forms that are actually checked and carry an explicit known-gap callout pointing at #673, plus a note that a constant fixes the binding rather than the contents reached through an alias. The loop-variable negative test now tests its claim. It previously used `add entry to gathered`, where the loop variable is the value and `gathered` is the target. Rewritten so the loop variable is the mutation target, scoped to the bare-name statements this change touches: `subtract`/`multiply` on a loop variable do report, via the `Assignment` path's long-standing `mutable: false` check, which is pre-existing and out of scope. Also adds a `// CI-SKIP:` directive to `constants_immutable_01.wfl`. The CI "Run WFL Programs" sweep covers `TestPrograms/docs_examples/` (unlike run_integration_tests.sh) and expects exit 0, so the intentional error example failed it. The docs validator still checks it statically and asserts it fails semantic analysis. Refs #671, #673 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * fix(ci): unbreak the Windows hygiene gate and the version-drift check Three failures that predate this branch and reproduce on main's own run for 438780a. They are unrelated to #671 but block this PR from going green. 1. Windows jobs had no Python. `integration-tests` and `run-wfl-programs` call scripts/check_repo_hygiene.py as their final step but never ran actions/setup-python, so on Windows they got the runner's bundled `python` (pre-3.11) and died with "HYGIENE-ERROR: Python 3.11+ with tomllib is required" regardless of what the job actually tested — the WFL sweep (141 passed, 0 failed), the docs-example validation (21/21) and the web tests (3/3) had all passed by then. Both jobs now set up Python 3.x, as `repo-hygiene` and `bump-version` already did. Switching Windows to `python3` was the other option and was rejected: on Windows that name can resolve to the Microsoft Store app-execution alias. `nightly.yml` also runs Python on Windows without setup-python, but only calls bump_version.py, which is stdlib-only and needs no tomllib — left alone. 2. Fixture writes were not byte-exact. FixtureTree.write used Path.write_text, which applies the platform newline translation, so on Windows every "\n" landed as "\r\n". test_archive_valid_manifest_passes computes its expected sha256 from the LF form, so it could never match the file the checker hashed — green on Linux, red on Windows. It now writes the caller's exact UTF-8 bytes (which also stops the locale encoding leaking in), with test_fixture_write_is_byte_exact pinning the behaviour. 3. The extension lockfile was stale. vscode-extension/package-lock.json still read 26.7.59 against Cargo.toml's 26.7.60, failing the static gate with "version-drift". bump_version.py already knows to update both mirrors; the 26.7.60 bump landed without it. Set to the values that script would write. Verified: `python3 -m unittest discover -s tests/tooling` 33 passed; `check_repo_hygiene.py --mode static` now exits 0 (was 1 on a clean origin/main worktree). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * fix(ci): check archived content out verbatim so its sha256 pins hold The Windows Repository Hygiene job failed with sha256 drift on all 48 archived files at once. The manifest hashes are computed from the committed (LF) bytes, but check_repo_hygiene.py hashes the file as it sits in the working tree, and the Windows runner checks out with core.autocrlf=true — so every LF became CRLF and every hash missed. Confirmed rather than assumed: re-hashing each file's CRLF-converted bytes reproduces the exact "actual" digests from the CI log. This was latent, not new. The job previously died earlier, at the checker's unit tests; fixing those in the parent commit let it reach the static check and surface the next Windows-only failure behind it. Archived files are immutable blobs pinned by hash, so a root .gitattributes marks Archive/** as `-text`: no end-of-line translation on any platform, making the working tree byte-identical to the commit. Fixing the checkout rather than the checker keeps the hash a pin on repository content instead of on whatever the local platform happened to write, and leaves the checker's semantics alone. `.gitattributes` is added to the root allowlist in .repo-hygiene.toml. It is a legitimate root-level Git config file alongside the already-allowed .gitignore, and root is the only place it applies from — this is a gap in the allowlist, not an exception carved out to silence a violation. Verified by simulating the Windows checkout on Linux — clone with core.autocrlf=true, then run the checker: before: 48 archive-manifest drift violations, exit 1 after: clean, exit 0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR * test: cover the reachable promotion path; correct the risk class (#671) Round 2 of review. Three of four findings were valid. Test comment was wrong and coverage was thin. The branch test named `pop_scope_promoting_except`, but a `check` merge goes through `promote_constant_marker` — different function. Corrected, and the test now also covers a constant *list* through `add`/`remove`/`clear`, the two forms with no `Assignment` fallback behind them. The other migration site is unreachable, and now says so. The reviewer asked for a try/when regression exercising `pop_scope_promoting_except`. That test cannot be written: a binding declared inside a try statement does not survive it at all — even when declared on every path, a later reference reports `Variable '<name>' is not defined` rather than resolving to a promoted key. Rather than write a test that does not exercise what it claims, this pins the premise (`try_scoped_declarations_do_not_escape_the_statement`) so the migration gets real coverage the day try-scoping changes, and documents at the call site why the code is kept: `constant_bindings` should not silently diverge from the four alias maps migrated for the same keys beside it. `outer_constants_survive_an_intervening_try` covers what a program can actually observe. Risk class R1 was wrong; it is R3. testing.md §5 puts backward compatibility in R3 outright and forbids lowering the class, and this change does alter behavior (`add`/`remove`/`clear` on a constant list: silently allowed → rejected at analysis). The diary now records R3, notes that §11.3 does not apply (no concurrency, lifecycle, streaming, untrusted input, or crypto), and lists the failure-path and negative coverage that does. Also bumps the two remaining `actions/setup-python@v4` uses to v5, matching the jobs fixed in the previous commit and clearing the Node 20 deprecation warning. Not taken: running the static hygiene check inside the bump-version push-retry loop. That job is pre-existing code this branch does not touch, and the concern (a concurrent merge racing the retry) is real but belongs in its own change rather than riding along with an analyzer fix. Verified: 151 test binaries, clippy -D warnings, fmt --check, tooling tests 33 passed, static hygiene exit 0, CI program sweep 142/0/49, docs examples 21/21. Refs #671 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H9AnrAH4d8sTni73GWgkjR --------- Co-authored-by: Claude <noreply@anthropic.com>
Implements the approved Repository Hygiene and Layout design (
Engineering/designs/2026-07-28-repository-hygiene-design.md) end to end: binding root policy, machine-readable enforcement profile, dependency-free checker, the full initial migration of legacy content, reference updates across governance/contributor/agent docs, and a blocking CI gate.What this PR does
Policy & authority
REPOSITORY_HYGIENE.md(binding; incorporated asGOVERNANCE.md§3.8) and.repo-hygiene.toml(root allowlist, forbidden/retired paths, binary and size declarations, personal-path placeholders,[[generated]]exceptions, version sources, approved output roots).CONTRIBUTING.md,README.md,Docs/README.md,Docs/contributing/index.md,AGENTS.md,CLAUDE.md;.cursor/.julesfiles become thin adapters to root policy (perf lessons promoted toHistory/perf-lessons.md).Enforcement
scripts/check_repo_hygiene.py— static mode (tracked-tree rules incl. archive sha256 verification, experimentReview-byexpiry, and product-version drift across Cargo/npm/wix/lock mirrors) and working-tree mode (post-suite cleanliness outside approved output roots).repo-hygieneCI matrix job (Linux + Windows);bump-versiondepends on it;integration-testsandrun-wfl-programsend with working-tree checks; workflows that push directly (bump-version,versioning.yml,auto-fmt.yml) run the static check immediately before pushing.Migration (118 static violations → 0)
*.ast.txt/*.lex.txtdump (16 embedded a personal Windows home directory), an accidentally tracked 3.9 MB ELF binary, generated reports and the mutable docs-validation cache,.orig/.rejmerge remnants, the raw clippy log, generatedtest_rust_files/,google_index.html, a trackedsettings.local.json, deadcrates/wfl_core,LabsTest/email.wfl(personal identifier — deliberately not archived),.rustfmt.toml(sole config is nowrustfmt.toml, edition 2024).TestPrograms/{modules,constants,nexus}/programs (describe/expect, all passing) and 5tests/fixtures/fixtures with a newtests/diagnostics_fixtures_test.rsasserting diagnostics + exit codes. Notable:load_container.wflpinsload modulescope isolation as a negative test (the legacy probe asserted a sharing behavior that was never implemented —include fromis the sharing mechanism), andeven_inline_precedence.wflpins exact division semantics the old probes misunderstood.History/dev-diary/2026/;Docs/development/→Docs/contributing/; active designs/plans/evidence →Engineering/;Tools/split intoscripts/metrics/,scripts/docs/,examples/tools/,Engineering/components/, archive;build_msi.ps1→scripts/build_windows_installer.ps1(with the retired MSI launcher's-BumpVersionoption); web examples →examples/web/(personalized wording removed, analyzer-validated); prototypes →experiments/{nexus,syntax}/with checker-enforced metadata (Experiment: Nexus prototype program (experiments/nexus/) #668, Experiment: pattern kitchen sink (experiments/syntax/) #669).Archive/manifest.json(path, original path, source commit, sha256, kind, status, reason,normative: false, security classification). WFLHASH review snapshots triaged: already public in-tree, classifiedpublic-historical.run_integration_tests.sh/.ps1now executeTestPrograms/feature subdirectories (excludingdocs_examples/,execute_pages/,test_data/;error_examples/= expected-fail), so converted tests actually gate.Producers fixed so gated suites leave the checkout clean (found by running the new working-tree gate over the full suite chain)
wfl --lex/--parsedumps now write undertarget/reports/dumps/instead of beside the source file — the exact mechanism that produced the formerly tracked dumps..wflcfgdisable in-repo debug reports and execution logs (closest-wins config discovery required both); the packaged installer config still enables debug reports for end users.target/test-artifacts/;rust_loc_counter_test.wfllikewise; docs-validation report moved undertarget/reports/; the write-after-close Rust test cleans the strayfile1it currently creates.error_examples/type_error.wflused42 plus "hello", which is legal string-coercing concatenation today and exited 0 — replaced withminus, which genuinely fails.vscode-extension/package-lock.jsonhad drifted to 26.7.46 vs 26.7.59 everywhere else — fixed, andbump_version.pynow updates both lock version fields;.gitignoreIcon?rule could swallowicons/on case-insensitive filesystems;.vscode/negations were dead;settings.local.jsonnow ignored recursively.Deferred (tracked, declared as transitional
[[generated]]exceptions)Cargo.toml(retiresrc/version.rs,.build_meta.json,wix.tomlversion line) and VSIX staging attarget/package/windows/— requires Windows MSI evidence (R3). Until then the checker's version-drift rule keeps every mirror in agreement.add ... to CONSTreport when combined with other constant mutations #671: analyzer drops theadd ... to CONSTreport when combined with other constant mutations (found during fixture conversion; test pins>= 4of 5 reports).Test evidence (testing.md §15)
tests/tooling/test_check_repo_hygiene.py(27 fixture-tree cases: clean pass + one per violation class, both modes),tests/tooling/test_windows_installer_script.py(placement/retirement guards),tests/diagnostics_fixtures_test.rs(diagnostic + exit-status assertions), 15 asserted WFL end-to-end programs, checker static+working-tree runs over the real tree.6ae52ff(test: add failing repo-hygiene checker and installer placement tests) — 32 tests, 30 failures + 2 errors, each for the intended reason; ancestor of the Green commits.cargo fmt --all -- --checkclean;cargo clippy --all-targets --all-features -- -D warningsclean;cargo test --allexit 0 (150 suites, 0 failures); release-build integration gatescripts/run_integration_tests.shexit 0 (130 passed, 0 failed, 24 skipped — including the recursive TestPrograms sweep);scripts/run_web_tests.sh3/3;python3 scripts/validate_docs_examples.py --ci --force19/19; static hygiene mode exit 0; working-tree mode exit 0 after all suites.windows-2025in this PR's CI). MSI build/install evidence deferred with Consolidate product version onto Cargo.toml and stage the VSIX during packaging #670.testing.md).scripts/test_bump_version.pymock harness was broken before this change (MagicMock/JSON serialization) — the new lock-update logic was verified functionally instead; Windows runner recursion not executed locally (CI exercises it); packaging consolidation deferred (Consolidate product version onto Cargo.toml and stage the VSIX during packaging #670).🤖 Generated with Claude Code
https://claude.ai/code/session_01QVvQraMbMgEWU9dPSTaqqJ
Generated by Claude Code