# O5: one command from a folder to a bundle you can ask a question of 2026-09-08. Session 113, order `20260908T184152Z-1340419920`, on top of `efa92ce` (K3 round 3). This is the session that made the reading direction installable. Everything here already worked from a clone; none of it worked for anyone else. ## 1. The red measurement The consumption skill generator was run against a bundle and the result grepped for paths: ```sh python3 tools/okf_skill.py ~/okf-test/v1-bundle --out /tmp/o5-red/skill grep -c "^/" /tmp/o5-red/skill/SKILL.md # absolute paths ``` **4 lines**, of which two are the commands the skill tells a reader to run: ``` 17: The contract this skill is held to is `/repos/llm-ingestion-okf/docs/consumption-contract.md`. 25: python3 /repos/llm-ingestion-okf/tools/okf_consume.py \ 26: /okf-test/v1-bundle \ 40: python3 /repos/llm-ingestion-okf/tools/okf_contract_check.py \ ``` Line 26 is the caller's own data and belongs there. The other three name a checkout. A skill carrying them cannot be moved, shared, or run by anyone without that clone at that exact path — which is every reader except the one who generated it. ## 2. Step 0: the default moved again, because the number behind it moved Round 3 set `okf build`'s flagless default to `--outline-run 3 --unit-fold` (Arm D plus Arm F) on Arm F's published "5 of 12". That figure had been measured with `--table-grid` ON. Without Arm E, Arm F's table clause — fold a table back into the heading that introduces it — has no joined table to fold, because a grid table is then not one block but one block per rule line. Arm E therefore joined the default, with `--no-table-grid` as its opt-out. Measured here on the operator's five-document folder, at the same stamp: | build | `.md` files | of which concepts | `index.md` | `log.md` | |---|---|---|---|---| | new default (D+E+F) | 30 | **15** | 14 | 1 | | `--no-table-grid` (D+F, round 3's) | 43 | **28** | 14 | 1 | The `.md` totals reproduce the PM measurement exactly (43 and 30). The concept counts differ from the 29 and 16 it reported by exactly one each, and the decomposition says why: `md` files minus `index.md` counts `log.md` as a concept. The index walk does not, and neither does the pre-pass. `--keep-table-heading` did NOT join the default: measured on two K2 bundles in round 3 it buys 35 bytes and zero rank positions. The red test is `test_the_build_default_is_now_arm_d_plus_arm_e_plus_arm_f` on a grid-table fixture, where the arm's effect is visible in the TITLES: with it off the sheet lands as `7 Romskjema` plus `Tabell linje 6`, `Tabell linje 8` and `Tabell linje 10` — concepts named after a line number. Its opt-out half asserts those four titles come back under `--no-table-grid`. ## 3. The move Three modules moved from `tools/` into `src/llm_ingestion_okf/`: | was | is | reached as | |---|---|---| | `tools/okf_consume.py` | `consume.py` | `okf consume` | | `tools/okf_contract_check.py` | `contract_check.py` | `okf check` | | `tools/okf_skill.py` | `skill.py` | `okf skill` | and one is new: `project.py`, reached as `okf project`. The `tools/` files stay, because published reproduction blocks name them and a measurement whose command no longer runs is a measurement nobody can repeat. They are **aliases, not re-exports**: `sys.modules[__name__] = _impl`. A re-export binds copies of the names into a second module object, so a caller patching one patches a binding the implementation never reads — measured, two tests that `monkeypatch` `okf_consume` went green again only under the alias. **Two authored files had to learn to travel.** `okf skill` instantiates `skills/okf-consume-template/SKILL.md`, and `okf consume` measures `docs/consumption-contract.md` as its § 7.4 known-positive and refuses without it. Neither is under `src/`. Both are force-included into the wheel from the file they are authored in, and both resolvers prefer the packaged copy and fall back to the source tree — one authored copy, no committed duplicate, because a duplicate is the drift the generator exists to prevent. **The generated skill names commands, not paths.** `okf consume` and `okf check`, resolved by the shell. The two attribution lines that named `tools/okf_skill.py` now name `okf skill`. ## 4. What `okf project` does, and what it refuses to decide `okf project ` runs `okf build` with **this package's default** into `/.okf//`, generates the skill into `/.claude/skills/-consume/`, and prints a summary. `` defaults to the current directory, `` to the folder's name NFC-normalised and reduced to `[a-z0-9-]`. It owns no flag that changes a bundle's bytes. A test holds the project bundle byte-equal to the `okf build` bundle of the same folder at the same stamp: two build paths would mean every measurement report is pinned to a bundle nobody produces. The summary reports two things a concept count cannot: - documents in the folder that **no concept names** — nothing can quote them; - documents that landed **whole**, as one flat concept at the bundle root (measured on the artefact: a concept id with no `/`) — reachable, but a question returns the entire document as one excerpt, which the budget often refuses and which often does not carry the answer where it was asked. Both are `[sourced-not-sufficient]` cases, and the summary names the documents. ## 5. The install measurement From a fresh `uv tool install` into an isolated tool directory, run from an empty folder with this repository nowhere on `PYTHONPATH` and `PATH` reduced to the install plus `/usr/bin:/bin`: ``` Read 5 document(s) from /okf-test/dokumenter. Wrote 15 concept(s) to /private/tmp/o5-user/.okf/dokumenter. Wrote the skill to /private/tmp/o5-user/.claude/skills/dokumenter-consume/SKILL.md. 0 of 5 document(s) were left out of the bundle. [...] 1 of 5 document(s) landed WHOLE [...] Expect `[sourced-not-sufficient]` there: - Del II Bilag 6 - Teknisk oppsett.pdf NEXT: start claude again in /private/tmp/o5-user and ask your question. ``` Exit 0. The generated skill carries **0** references to `tools/` or to any checkout. `okf consume` on that bundle exits 0, and `okf check` on the pair is **conformant: 15 rules over 8 excerpts and 7 withheld entries, 0 findings**. **The first install measurement was wrong and is recorded here rather than dropped.** `uv tool install` from the unchanged local path returned a cached build of the previous version, and `okf project` failed with `invalid choice: 'project'`. The version bump was already required; without it the measurement would have reported the old wheel as the new one. ## 6. What was NOT done - **`docs/consumption-contract.md` was not edited.** Its § "What is mechanically checked" still names `tools/okf_contract_check.py`, which is true — the alias exists. Its bytes are the pre-pass's known-positive (`KNOWN_POSITIVE_EXPECTED = 12563`), so editing it makes the pre-pass refuse until the literal is updated. That coupling is deliberate and this was not the session to spend it. - **`skills/okf-consume/` was not regenerated**, only its four command and attribution lines were updated in place. Regenerating needs the K2 bundle, which is never copied into this repository. - **No push, and the tag is local.** The order and the operator own that. - **`tests/test_okf_consume.py` was not left untouched, and the order asked that it be.** Two assertions in it read a PATH, which is the one thing this work exists to change: one read the pre-pass's source text at `tools/okf_consume.py`, the other required the README recipe to invoke `python3 tools/