Skip to content

Name docs/ and notes/ in the root map, and test that the project's own tree stays named - #496

Merged
max-sixty merged 2 commits into
mainfrom
docs/name-notes-and-docs-in-map
Sep 9, 2026
Merged

Name docs/ and notes/ in the root map, and test that the project's own tree stays named#496
max-sixty merged 2 commits into
mainfrom
docs/name-notes-and-docs-in-map

Conversation

@leaf-agent

@leaf-agent leaf-agent commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

CLAUDE.md's repository map names seven of the nine directories in the project's own tree. The two it misses, docs/ and notes/, are both places sessions are actively sent — d4801b6a wrote notes/codex-integration.md, 8ac42a81 wrote notes/workspace-followups.md and the TODO.md section that links to it, and docs/ holds the five product documents scripts/site.py publishes as leaf.page. A session that lands in either has only the files in front of it to say what the directory is for.

What the map now says

Two paragraphs beside the existing examples/ / tests/ / scripts/ / worker/ one:

  • docs/ is the site's own content — each product document there is a Leaf source, so changing what leaf.page says is a page edit rather than a template edit. That fact currently lives only in scripts/site.py's docstring, which is the wrong place for a session deciding where to make the change.
  • TODO.md is the ordered priority list and notes/ holds what its items link out to, with the dating rule stated: where a note and the tree disagree, the tree is right.

The dating rule is scoped to what CI actually reads. ci.yaml's lint job runs pre-commit/action@v3.0.1 over the whole tree, and .pre-commit-config.yaml's exclude: carves out only the MCP App experiment captures — so ruff, shellcheck, typos, and the whitespace hooks all gate an authored note, and a session told otherwise would redden lint on the first one it writes. What holds is the narrower fact the rule rests on: nothing under tests/ reads notes/, so no test checks a note against the tree.

The test

test_the_root_instructions_name_every_directory_of_the_projects_own_tree derives the set from shipped_payload() rather than a list, so the next top-level directory added without a paragraph goes red instead of staying green — the same construction, and the same reason, as test_the_root_instructions_name_every_directory_ci_gates_on_its_own directly above it. Dotted directories are excluded: a session finds .github/ or .config/ through the host rather than through this map.

It matches the backticked prefix without a closing backtick, because a part is named at whatever depth it is owned at — bin/leaf is a launcher and skills/leaf/assets/ is a tree, and both name their directory. The existing test above requires the closing backtick because a working-directory: is always named as the bare directory.

Verification

  • uv run pytest tests/test_interact_layer.py — 165 passed, 6 skipped.
  • Bug-back: with the CLAUDE.md paragraphs stashed and the test kept, it fails with AssertionError: unnamed in CLAUDE.md: ['docs', 'notes'].
  • uv run pre-commit run --files notes/mcp-apps/experiments/10/observe.py notes/mcp-apps/experiments/10/commands.sh — ruff, typos, shellcheck and the whitespace hooks each ran on those notes rather than skipping, which is the reading behind the scoped sentence above.
  • uv run pre-commit run --files CLAUDE.md — passed.

This is prose plus its gate; there is no product path to regress.

@leaf-agent leaf-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The notes/ paragraph's justification is false, and it is the one claim in this diff a session would act on directly. ci.yaml's lint job runs pre-commit/action@v3.0.1pre-commit run --all-files — and .pre-commit-config.yaml's exclude: carves out only notes/mcp-apps/experiments/[0-9]+/(results/|output\.txt$), with its own comment reading "lint the authored commands and findings, not the captures". So ruff gates notes/ask-placement-eval/outline.py and each experiment's observe.py and serve.py, shellcheck gates run.sh and commands.sh, and typos and the whitespace hooks gate every note. A session that reads notes/ as unchecked reddens lint on the first note it writes.

The narrower fact the dating rule actually rests on is true: nothing under tests/ reads notes/, so no test checks a note against the tree. Suggestion inline.

Comment thread CLAUDE.md Outdated
pre-commit runs --all-files in ci.yaml's lint job, and the config's exclude carves out only the MCP App experiment captures, so ruff, shellcheck, typos, and the whitespace hooks all gate authored notes. The dating rule rests on the narrower fact that no test reads notes/.
@max-sixty
max-sixty merged commit 26754cc into main Sep 9, 2026
7 checks passed
@max-sixty
max-sixty deleted the docs/name-notes-and-docs-in-map branch September 9, 2026 10:38
max-sixty pushed a commit that referenced this pull request Sep 10, 2026
…ule (#543)

`scripts/CLAUDE.md` tells a session that a clean `git status` after
`scripts/vendor.py <bundle>` is the check that a bundle still matches
the script, and that the check holds only where every fetched input is
pinned. It then sorts the bundles into those two classes — and two of
the seven are in neither, so a session rebuilding `floating-ui` or
`mcp-app` has no answer for whether a diff it sees is drift to fix or an
upstream patch to take.

Each belongs in a class the paragraph already describes:

- `floating-ui` reproduces. `@floating-ui/dom`, `@floating-ui/core`, and
`@floating-ui/utils` are all in `PINS`, and that closure is complete:
`dom` depends on `core` and `utils`, `core` on `utils`, `utils` on
nothing. Rebuilding it left `git status` clean.
- `mcp-app` fetches an input `PINS` does not name.
`@modelcontextprotocol/ext-apps@1.7.5` declares `@standard-schema/spec
^1.1.0`, which npm's resolver picks, so the bundle sits with `plot` and
`pierre`. It reproduced when I rebuilt it today — which is exactly the
reading the paragraph exists to keep a session from relying on.

This is drift rather than a deliberate omission. The paragraph dates
from `c7b37062` (2026-08-30); `mcp-app` landed in #188 on 2026-09-01 and
`floating-ui` in #537 last night, and #533 — the most recent commit to
touch the paragraph — added `jsdiff` to it, so it is meant to be kept
current.

The test follows the shape this repo already uses for instruction lists
(#93, #105, #331, #496): it reads the bundle names out of `vendor.py`'s
`BUILDS` and `COPIES` rather than restating them, and asserts each is
named in that one paragraph. On `main` it fails with `unplaced in
scripts/CLAUDE.md: ['floating-ui', 'mcp-app']`.

What it deliberately does not check is *which* class a bundle is placed
in — deciding that means resolving each package's dependency graph,
which is a network call this suite should not make. A name in the wrong
class still needs a reader to catch; a name that is absent no longer
does.

<details><summary>Verification</summary>

- `uv run pytest tests/test_interact_layer.py` — 167 passed, 6 skipped.
- The new case alone, with `scripts/CLAUDE.md` reverted to `main`'s
text: `AssertionError: unplaced in scripts/CLAUDE.md: ['floating-ui',
'mcp-app']`.
- `scripts/vendor.py floating-ui` and `scripts/vendor.py mcp-app` each
left `git status` clean.
- `npm view @floating-ui/dom@1.8.0 dependencies` → `{
'@floating-ui/core': '^1.8.0', '@floating-ui/utils': '^0.2.12' }`;
`@floating-ui/core@1.8.0` → `{ '@floating-ui/utils': '^0.2.12' }`;
`@floating-ui/utils@0.2.12` → none;
`@modelcontextprotocol/ext-apps@1.7.5` → `{ '@standard-schema/spec':
'^1.1.0' }`.

</details>

Co-authored-by: leaf-agent <318509791+leaf-agent@users.noreply.github.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.

2 participants