llm-ingestion-okf/src/llm_ingestion_okf
Kjell Tore Guttormsen c1d0ba237d feat(propose): --table-grid selects Arm E, absent is off [skip-docs]
The flag threads through `run` and `main` and takes no argument. Arm D's gate
is a run LENGTH where 0 means off; Arm E has no numeric parameter, so a boolean
is the honest shape and an integer would only manufacture a sweepable knob that
means nothing. `run` therefore adds no numeric validation, and the help says
why.

Both prose sites that enumerate the arms `okf build` does not expose are
updated: `src/llm_ingestion_okf/cli.py` and `CLAUDE.md`. The second was found
by review, not by grep of the first -- the same claim lives in two files and
only one of them is code.

The generalised attribution test earned itself in this commit. The first draft
of the Arm E help contained "byte-identical to Arm D -- Arm D rather than Arm
B", and argparse's rendering plus the test's ` --` chunk split meant the
attribution fell OUTSIDE the `table-grid` chunk. The test went red with the
truncated chunk printed, which is exactly the failure it exists to catch: a
whole-output grep would have been satisfied and the attribution would have been
unfindable in the option it belongs to. The clause is now parenthesised.

Arm C's marker check in `tests/test_cli_build.py` gains `rule:table-grid` and
is renamed to speak of all three arms, measured on the artifact rather than on
the flag: a flag `okf build` never passes is not evidence about what it emits.

[skip-docs] is the MEASURED precedent, not a convenience. `grep -c` for
"outline-run", "max-segment-chars", "Arm C" and "Arm D" returns 0 in both
README.md and CHANGELOG.md: an arm flag is documented in its constant's `#:`
comment, in `--help`, and in the round's measurement report, and it is off by
default so it makes no promise to a consumer. `--path-prefix`, which is a real
interface change, does have a CHANGELOG entry. The rule this follows is stated
at docs/2026-09-07-k3-arm-d.md: "interface and behaviour changes yes, arm flags
no." Arm E's report is docs/2026-09-07-k3-arm-e.md, later in this round.

Tests first: 3 red, then green (a fourth, the no-argument test, is honest in
its docstring that it is green before the flag exists too, because argparse
rejects an unknown option with the same code; it becomes evidence only once
the flag is real). 1248 -> 1251.
ruff check: exit 0. ruff format --check: exit 0. mypy --strict src/ tools/:
27 files, Success. pytest -q: exit 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:53:59 +02:00
..
__init__.py feat(inbox): walk the drop directory recursively 2026-09-07 04:11:00 +02:00
_pandoc.py feat(extract): resolve the vendored converter and refuse an unpinned version 2026-09-02 14:07:20 +02:00
cli.py feat(propose): --table-grid selects Arm E, absent is off [skip-docs] 2026-09-07 10:53:59 +02:00
connectors.py fix(errors): type the NUL-byte path failure as SourceError 2026-07-20 10:30:42 +02:00
corpus.py feat(cli): okf build, one installed command for folder in, bundle out 2026-09-07 05:06:33 +02:00
errors.py feat(materialize): sources takes a list and renders N flow mappings 2026-09-02 16:12:19 +02:00
extract.py feat(profiles): a profile may name a per-suffix renderer 2026-09-02 14:19:18 +02:00
guard_adapter.py feat(guard): bump the pin to >=0.3,<0.4 and pin Door C's allow_reserved=False 2026-08-02 21:08:53 +02:00
importer.py feat(index): one ordering helper, called by both doors 2026-09-01 19:54:45 +02:00
inbox.py feat(cli): okf build, one installed command for folder in, bundle out 2026-09-07 05:06:33 +02:00
manifest.py feat(profiles): materialize_bundle takes a keyword-only profile (req 6) 2026-07-31 15:37:17 +02:00
materialize.py feat(materialize): sources takes a list and renders N flow mappings 2026-09-02 16:12:19 +02:00
profiles.py feat(inbox): surface adjudication state and its dwell time 2026-09-02 14:49:45 +02:00
propose.py feat(propose): --table-grid selects Arm E, absent is off [skip-docs] 2026-09-07 10:53:59 +02:00
py.typed feat(typing): ship the PEP 561 py.typed marker 2026-07-17 03:46:51 +02:00
render.py feat(errors): stable machine-readable codes on IngestError 2026-07-17 04:01:04 +02:00
segmentation.py feat(segmentation): parse the adjudication state a plan already carries 2026-09-02 14:44:06 +02:00
structure.py fix(frontmatter): a nested key must not substitute for a top-level one 2026-08-31 23:31:53 +02:00