diff --git a/docs/okf-ingestion/plan.md b/docs/okf-ingestion/plan.md index fcdae9a..2abbed8 100644 --- a/docs/okf-ingestion/plan.md +++ b/docs/okf-ingestion/plan.md @@ -121,10 +121,22 @@ specifics-bank) all independently converged on `sha256(...)[:12]`; the pattern i **R5 (phase 4, Node half) — contract parity details.** Stable string error codes on the error object (the Python half's `exc.code` discipline, mirrored so Node consumers assert on `err.code`, never on message -text); zero runtime dependencies; ESM with `node:` prefixes; LF-only output with exactly one trailing -newline; and the golden-fixture set shared across both halves so byte-identity is the test, not the -promise. Our packages already meet the zero-dep/ESM/LF conventions (sole exception: `scripts/analytics` -depends on `csv-parse`), so parity is cheap on our side. +text); zero runtime dependencies; ESM with `node:` prefixes; and the golden-fixture set shared across both +halves so byte-identity is the test, not the promise. + +> **Correction, 2026-07-20 (trinn D-review).** An earlier revision of this section claimed we "already meet +> the zero-dep/ESM/LF conventions". Verified against the code, two parts of that were false: +> +> - **We have no stable error codes.** None of the four CLIs set a machine-readable code; every failure is a +> free-text `Error` plus a numeric `process.exit` (`scripts/brain/src/ingest.ts:99,:113`, +> `scripts/trends/src/cli.ts:125,:255`). `err.code` is an ask *of* the library, not a discipline we mirror. +> - **"Exactly one trailing newline" is not our invariant, and must not become the library's.** Nothing +> asserts it here, and `serializePublishedRecord` deliberately omits it (`scripts/brain/src/ingest.ts:71`) +> because the record must end on the verbatim body or the byte-exact round-trip (SC2, §5) breaks. A shared +> fixture corpus therefore has to carry a *verbatim, non-normalized* case; a corpus where every valid +> output ends in one newline encodes normalization as contract and tests byte-identity away. +> +> Zero-dep/ESM does hold (sole exception: `scripts/analytics` depends on `csv-parse`). ## 5. What must never move here