Skip to content

S2 — Rewrite the physical-architecture standard's directory tree (closes C-84) - #253

Merged
Polichinel merged 4 commits into
developmentfrom
docs/s2-physical-arch-tree
Aug 17, 2026
Merged

S2 — Rewrite the physical-architecture standard's directory tree (closes C-84)#253
Polichinel merged 4 commits into
developmentfrom
docs/s2-physical-arch-tree

Conversation

@Polichinel

Copy link
Copy Markdown
Contributor

S2 of epic #240. Closes #242 and register C-84. Documentation only — src/ untouched, no public API change, CONFORMANCE_FLOOR stays 1.0.0.

Depended on #252 (S1), which corrected the layering paragraph in this same file. That is why these were separate stories: S1 owned :48-49 and :67, S2 owns the tree those lines sit under.

The problem

docs/standards/physical_architecture_standard.md §2 held the repository's authoritative directory tree — the document a contributor is pointed at to answer "where does this file go?", and one ADR-007 expects agents to read. It was a pre-implementation design sketch that was never revised after the package was built:

Claimed Reality
weight_frame.py "(anticipated)" never shipped
mask_frame.py "(anticipated)" never shipped
target_frame.py "(anticipated)" shipped in v1.0.0, has its own CIC
metadata.py missing from the tree
_typing.py missing — and it has the highest fan-in in the leaf (8)
conformance/ missing — the one surface whose primary caller is another repository
views_frames_summarize/ absent entirely
views_frames_reconcile/ absent entirely

Eight of thirteen leaf modules, one of three packages, two phantom files. The document was also undated, so its staleness was invisible — every CIC carries a Last reviewed line and all eight are current; this standard had nothing.

What changed

  • §2 rewritten to all three shipped packages and all 36 modules, ordered by the ADR-002 layering S1 corrected, with the ADR-001 category annotated on each file that has one.
  • _typing.py and conformance/ marked as having no category, and why — one is a typing helper (C-19), the other verifies the ontology rather than belonging to it (ADR-016). Inventing category numbers for them would have been worse than saying so.
  • A Last reviewed date and a perishability note at the top: the tree is authoritative and therefore perishable; update it in the same change that moves a module.
  • The phantom frames are replaced by a sentence recording the actual rule — new frame types are additive MINOR (ADR-018) and belong in the tree the day they ship, not before — plus what carrying them cost.

Verification

Per the refinement S1 added to C-77, the check matches the shape of the claim rather than a fixed phrase, and was mutation-tested in both directions before being trusted. It parses the fenced tree and diffs it against src/**/*.py:

$ python3 treecheck.py
source modules: 36
missing from tree: none
in tree but absent from src/: none
packages absent from tree: none
exit=0

$ # mutation 1 — reinstate a phantom module in the tree
in tree but absent from src/: ['weight_frame.py']          exit=1

$ # mutation 2 — hide a real module from the tree
missing from tree: ['views_frames/metadata.py']            exit=1

Both failure directions are caught, which is what makes the green run mean anything. This is the lesson from S1, where C-82's first verification pasted real output from a real command and still missed two surviving occurrences because the command could not have found them.

$ bash docs/validate_docs.sh   → PASSED
$ uv run ruff check .          → All checks passed
$ uv run ruff format --check . → 77 files already formatted
$ uv run mypy src/             → no issues in 36 source files
$ uv run lint-imports          → 2 kept, 0 broken
$ uv run pytest --cov --cov-fail-under=100 → 100.00%, green

Two contradictions the rewrite surfaced, fixed here

Extending the tree to three packages made two existing sections wrong. Both were created by this change, so both are fixed in it rather than deferred:

  • §3 forbids utils/helpers/common dumping grounds — while the newly-visible views_frames_summarize/_common.py and views_frames/_typing.py carry exactly such names. §3 now states why each is a focused module (two functions with one responsibility; two array aliases) and that a third unrelated concern is the signal to split, not to widen the exception.
  • §5 said compliance would be audited "once the leaf is stood up" — it has been released for months. It now names the two rules that are machine-enforced (test_one_concept_per_file for §1; the import-linter contracts and test_package_dependency_dag for §4) and states plainly that the tree is not machine-checked — it is kept current by the review note at the top.

Deliberately not done

The tree check is not folded into docs/validate_docs.sh. It is a natural fourth assertion alongside S6's three (#246), but that script is bash-and-grep by design — the docs CI job installs no Python on purpose — and parsing a fenced tree is the one candidate of the four that plausibly cannot be done in bash. Recorded on #246 for S6 to decide rather than pre-empted here.

Section 1's rules, the naming convention, and the Category taxonomy are untouched. They are accurate and test-enforced. This story fixed the tree, the date, and the two contradictions the tree created.

Register

C-84 closed and moved to Resolved: open 17 → 16, resolved 65 → 66.

🤖 Generated with Claude Code

Polichinel and others added 4 commits August 17, 2026 21:38
…oses C-84)

S2 of epic #240, closing register C-84. Documentation only.

The §2 directory tree was a pre-implementation sketch that was never revised
after the package was built. It showed one of three packages, omitted
`metadata.py`, `_typing.py` and the whole `conformance/` subpackage, listed two
files that never shipped (`weight_frame.py`, `mask_frame.py`), and still marked
`target_frame.py` as "(anticipated)" — it shipped in v1.0.0 with its own CIC.
The document was also undated, so its staleness could not be seen by looking.

The tree now covers all three shipped packages and all 36 modules, ordered by
the ADR-002 layering S1 corrected, with the ADR-001 category on each file that
has one. `_typing.py` and `conformance/` are marked as having no category and
why — one is a typing helper, the other verifies the ontology rather than
belonging to it. The document carries a `Last reviewed` date and a note saying
the tree is authoritative and therefore perishable.

Verified with a check written to match the shape of the claim rather than a
fixed phrase, and mutation-tested in both directions before being trusted —
per the refinement S1 added to C-77. It parses the fenced tree and diffs it
against `src/**/*.py`: clean at exit 0; reinstating a phantom module gives exit
1 naming `weight_frame.py`; hiding a real one gives exit 1 naming
`views_frames/metadata.py`.

Extending the tree to three packages surfaced two contradictions in the sections
below it, fixed here rather than left:

- §3 forbids `utils`/`helpers`/`common` dumping grounds, while the newly-visible
  `_common.py` and `_typing.py` carry exactly such names. §3 now says why each
  is a focused module — two functions with one responsibility, two type aliases
  — and that a third unrelated concern is the signal to split rather than to
  widen the exception.
- §5 said compliance would be audited "once the leaf is stood up". It now names
  the two rules that are machine-enforced and states plainly that the tree
  itself is not — it is kept current by the review note at the top.

Not done here: folding the tree check into `validate_docs.sh`. That script is
bash-and-grep by design and parsing a fenced tree is the one candidate check
that plausibly cannot be. Recorded on #246 for S6 to decide.

Closes #242.

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

Four findings from /review-diff on this branch.

The perishability note said the tree "showed one of three packages and eight of
thirteen modules". Placed next to "one of three packages", a reader takes
thirteen as the repository total — and it is not: this PR's own verification
reports 36 source modules. Thirteen was a count of views_frames modules-as-named-
concepts, and even that is arguable (14 files, 11 excluding `__init__.py`).

This is S1's "Ten modules" defect recurring one story later, in a note whose
subject is documents that fall out of step with reality. Same fix as S1: delete
the number rather than correct it, and say the specific thing instead — one of
the three shipped packages, the three omitted modules by name, two files never
written. Nothing left to drift.

Also:

- The `_typing.py` entry closed its parenthetical on an em-dash and padding —
  "(private; no category —      )" — with the completing clause on the next
  line, outside the parentheses. It read as unfinished text in the one document
  whose stated purpose is that a reader infers every responsibility from the
  tree without reading bodies.
- Realigned the comment column across all three package blocks. Category
  annotations had landed at four different columns where the original tree was
  aligned; in a screaming-architecture document the tree's legibility is the
  deliverable. Re-verified after the rewrite: 36 modules, no ghosts, all three
  packages.
- The C-84 resolution now says the tree-check script is deliberately not
  committed and why — it would be the only Python under a `docs/` tree whose CI
  job installs none, and whether the logic belongs in `validate_docs.sh` is
  S6's call (#246). A reader was otherwise left hunting for a file that is not
  in the repository.

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

Five findings, and one of them says I was too conservative in the last commit.

**The check is now committed** as `scripts/check_arch_tree.py`. The previous
commit argued it should stay out of the repository because `docs/` has no
Python. That was the wrong boundary: `scripts/` already holds exactly this kind
of standalone tool (`verify_reconcile_parity.py`, the fixture generators), all
unwired from CI. Pasting a transcript of a script nobody can re-run is the
pattern C-77 exists to flag, and the register entry was doing it. The script
parses the fenced §2 tree and diffs it against `src/**/*.py` in both directions;
mutation-tested again after committing. Whether it belongs in
`validate_docs.sh` is still S6's call (#246) and the module docstring says so.

**§1 contradicted the tree §2 now makes visible.** It required every non-trivial
class to live in a file named after it, and named "bundling unrelated frames in
a frames.py" as the incorrect example. The reconcile block exposes `module.py`
(ReconciliationModule), `result.py` (ReconciliationResult) and `frames.py` —
which under a literal reading violates both. It does not: module names are read
package-qualified, so `views_frames_reconcile/module.py` reads as
`reconcile.module` and `reconciliation_module.py` would stutter; and
`frames.py` holds the package's array→frame adapter *functions*, not a bundle
of frame classes. §1 now says this, and separates the mechanically-checked half
(`test_one_concept_per_file`) from the review-judgement half.

**Three register/CHANGELOG inconsistencies**, all created or exposed by this
epic:

- The Status-section prose read "At 17 open concerns — 13 of them Tier 3" three
  lines under a header this branch changed to 16. Both numbers described
  2026-07-31, when the Status class was introduced. It now says so, and points
  at the header as the current count.
- The `doc↔code topology drift` cluster still read as pending work, in
  present tense, though both members are now resolved — and Register
  Conventions declare that list the single authority on clustering. Marked
  CLOSED by S1+S2, matching the form the other closed clusters use.
- The `[Unreleased]` CHANGELOG recorded C-84 as registered but never as
  resolved, while giving S1's C-82 correction a full entry. S2 now has one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two stories, two refinements, both learned by getting it wrong.

S1 taught that a check has to be capable of failing: C-82's grep matched four
fixed phrases and missed two occurrences inside its own search path.

S2 taught the next part. The C-84 resolution pasted output from a script that
had been mutation-tested in both directions — which satisfies S1's lesson — but
the script lived in a scratchpad and was never committed. The only artifact
proving the tree was correct was a transcript nobody else could execute. A claim
backed by an unreproducible transcript is the same shape as a claim backed by
nothing.

So the rule has three parts, and S10 (#250) should write all three somewhere
durable: demonstrate rather than describe; use a check that could actually have
failed; leave the check where the next person can run it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Polichinel
Polichinel merged commit d35ea5d into development Aug 17, 2026
10 checks passed
@Polichinel
Polichinel deleted the docs/s2-physical-arch-tree branch August 17, 2026 19:56
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.

S2 — Rewrite the physical-architecture standard's directory tree (closes C-84) (Epic #240)

1 participant