Skip to content

Commit cd0928a

Browse files
committed
docs: land grounded corpus baseline and preserved closeout receipts
1 parent d09a476 commit cd0928a

13 files changed

Lines changed: 664 additions & 101 deletions

docs/BASELINE-narrativegoldmine.md

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,15 @@ One command compiles the corpus into every served artefact:
7070
python -m pipeline.build ontology/pages dist
7171
```
7272

73-
`pipeline/build.py` runs seven stages in a fixed order — parse → validate →
74-
Turtle → WebVOWL → Page API → search index → graph tiers (NGG1) — then writes
75-
`api/schema/context.jsonld` and `api/validation-report.json`. Only `main()`
76-
exits non-zero on validation errors; the build itself treats them as
77-
non-blocking (`pipeline/build.py`). Dependency surface is `rdflib>=7.0.0`
78-
(plus `pytest`). The run is **deterministic within a day** (the only wall-clock
79-
input is `date.today()`, the only RNG a seeded force layout) — every binary and
80-
JSON artefact reproduces byte-for-byte. The **one exception** is
81-
`dist/data/ontology.ttl`: rdflib mints fresh blank-node ids for the existential
82-
restrictions on every run, so it is isomorphic and equal-length but reorders.
83-
Compare it by triple set, never by hash.
84-
85-
### The `is_public` gate
86-
87-
`vc:public` on the Page block is the **sole** publication gate, and it is
88-
checked independently in every output stage rather than filtered once, so no
89-
stage can inherit a stale list: `pipeline/jsonld_to_turtle.py:244` and `:331`,
90-
`pipeline/jsonld_to_webvowl.py:48`, `pipeline/jsonld_to_page_api.py:21`,
91-
`pipeline/jsonld_to_search.py:18`, `pipeline/emit_graph_tiers.py:538`. The one
92-
place it is deliberately **not** applied is `build_backlink_index`, which runs
93-
over the full page list (documented in `docs/architecture/pipeline.md`).
73+
`pipeline/build.py` performs input census/preflight, public projection and validation before exporting Turtle, WebVOWL, Page API/Markdown, search and graph tiers, then a generation manifest. Malformed or ambiguous input and validation errors refuse publication in both strict and non-strict calls. Outputs are staged; promotion backs up the prior generated trees and rolls back on failure. An additional rollback failure retains the recovery directory for repair. This is not atomic activation across live readers or consumers.
74+
75+
Graph payloads use stable ordering where implemented, but the complete bundle is not byte-deterministic: `pipeline/manifest.py` records a fresh UUID and UTC timestamp, and Turtle blank-node identities can vary. Compare RDF by isomorphism/triple semantics, and verify each generation against its own manifest rather than claiming equal bytes across builds.
76+
77+
### The public projection boundary
78+
79+
`vc:public` must be a literal JSON boolean. `pipeline/public_projection.py` rejects malformed, missing or ambiguous declarations and conflicts with other public flags. The canonical builder projects only public pages before inference and export. It drops or redacts references to known private identities, including body text and title-form Markdown; unresolved concepts remain available as intentional dangling references. This is not a general secret detector.
80+
81+
Exporter-local visibility checks in `pipeline/visibility.py` remain defensive boundaries. The canonical public graph and Markdown are derived from the same protected projection; no workflow copies raw authored Markdown over it. Public census/validation diagnostics are aggregate-only. Authoring-directory exclusions and exact corpus identity/count gates remain separate from the privacy flag.
9482

9583
### The NGG1 binary tier contract
9684

@@ -137,19 +125,19 @@ CI glue are **AGPL-3.0-or-later** (`LICENSE`); the `ontology/` corpus is
137125

138126
## Known divergences & open items
139127

140-
- **`ADR-NG-001` is cited pervasively but is absent from this tree.** Over
141-
thirty code and doc files cite `ADR-NG-001 §2/§3/§4/§5/§7/§9` as the authority
142-
for the explorer overhaul, and `explorer/FORMAT-NGG1.md:3` links it by the
143-
exact path `../../docs/adr/ADR-NG-001-explorer-architecture.md` — which does
144-
not exist here (it lived in the upstream publishing repo). The load-bearing
145-
design is real and implemented; only the cited document is missing. This
146-
baseline plus `docs/architecture/explorer.md` are its de-facto reconstruction.
147-
Reconstructing `ADR-NG-001` into `docs/adr/` is an open item. Note the
148-
`FORMAT-NGG1.md:3` link is **doubly broken**: `../../docs/adr/` from
149-
`explorer/FORMAT-NGG1.md` normalises to *above* the repo root (one `../` too
150-
many — the correct depth is `../docs/adr/…`). Whoever reconstructs `ADR-NG-001`
151-
must fix the relative depth too, or the link still will not resolve once the
152-
target exists.
128+
- **`ADR-NG-001` is classified `historical-absent`, not open** (resolved
129+
2026-09-05, ADR-2001). 33 files cite `ADR-NG-001 §2/§3/§4/§5/§7/§9`; the
130+
document itself never existed in this tree and lived in the upstream
131+
publishing repo. It is **not** reconstructed — writing a decision record for a
132+
decision this repo did not take would fabricate authority. Instead each cited
133+
section is mapped to the in-tree surface that carries its content today
134+
(ADR-2001 "ADR-NG-001 resolution"), so a reader following a citation reaches
135+
a real document. `explorer/FORMAT-NGG1.md:3` links the absent record by the
136+
path `../../docs/adr/ADR-NG-001-explorer-architecture.md`, which is **doubly
137+
broken**: from `explorer/` that normalises to *above* the repo root (the
138+
correct depth would be `../docs/adr/…`). Since the target is classified
139+
absent, the link is recorded as a dangling historical citation rather than
140+
repaired to point at nothing.
153141
- **The `7,874` figure is stale corpus-wide.** `docs/architecture/pipeline.md`
154142
and `docs/architecture/explorer.md` are written against a 7,874-page corpus,
155143
but the corpus is now **8,138** pages (`EXPECTED_CLASSES: '8138'`,
@@ -167,42 +155,111 @@ CI glue are **AGPL-3.0-or-later** (`LICENSE`); the `ontology/` corpus is
167155
- **`ontology.ttl` is not byte-reproducible** (blank-node reshuffle, above).
168156
- **`EXPECTED_CLASSES` is a hand-typed pin** that duplicates a figure the
169157
pipeline already computes and drifts the moment the corpus does; it must move
170-
in the same commit as any corpus change.
158+
in the same commit as any corpus change. That independence is deliberate
159+
(ADR-2003) and is preserved. Since 2026-09-05 it is no longer the only
160+
membership check: `pipeline/contracts/class-identity.txt` commits the sorted
161+
class-IRI **set**, so an equal-count identity substitution — delete one class,
162+
add another — fails the release gate as a diff even though the count agrees.
163+
Count and set must move in the same commit; the gate fails if they disagree.
171164
- **Three classes resolve to no category** (`electric-vehicle`,
172165
`ethan-mollick`, `urban-planning`) — a corpus ancestry gap, not a resolver
173166
fault.
174167
- **4,383+ object-property targets are referenced but never declared** as pages
175-
and ship as `skos:Concept` stubs with slug-derived labels.
168+
and ship as `skos:Concept` stubs with slug-derived labels. The visibility
169+
policy deliberately does **not** redact these: they resolve to no page, so they
170+
name no private entity, and redacting them would rewrite the published
171+
semantics of the whole corpus for no privacy benefit.
172+
- **The explorer cannot consume `ontology.json` directly.** The classic WebVOWL
173+
split shape keeps `domain`/`range` in `propertyAttribute[]`, and the consumer's
174+
`StandardParser::parse_property` raises `Missing domain for property` without
175+
them on the `property[]` entry itself. `pipeline/explorer_compat.py` emits a
176+
merged `ontology-explorer.json` that satisfies it. **One divergence remains
177+
unresolvable from this side**: the Rust parser requires `domain`/`range` as
178+
strings while `modern/src/stores/useGraphStore.ts` indexes them with `[0]`, and
179+
a JSON value cannot be both. It is recorded, tested and owned by WasmVOWL
180+
(`EXPLORER_DIVERGENCES`, `pipeline/tests/test_explorer_compat.py`).
176181

177182
## Invariants (must not silently change)
178183

179-
1. `vc:public` is the only publication gate, and it is re-checked in every
180-
output stage. No stage may filter once and let another inherit the list.
184+
1. Public input must have a strictly boolean `vc:public`. The canonical builder
185+
applies the protected public projection before inference/export; exporter-local
186+
checks must not be bypassed by raw Markdown copying or diagnostic disclosure.
181187
2. The NGG1 node record is **24 bytes** with **one** `u16 category`. Writer and
182188
both readers stay pinned to the 183-byte golden fixture; changing the stride
183189
or the category cardinality breaks all six builders at once.
184190
3. Bridged (multi-category / multi-domain) membership is recoverable **only**
185191
from `bridges.json`. The binary `category` field is the nearest category, not
186192
the membership set.
187-
4. The pipeline is deterministic within a day for every artefact **except**
188-
`ontology.ttl`; that exception is compared by triple set, not by hash.
193+
4. Verify every bundle against its own generation manifest. Manifest UUID/time
194+
and Turtle blank-node identities prevent a blanket byte-determinism claim.
189195
5. The corpus is synthetic-AI-generated-under-human-direction and must be
190196
surfaced as such from data (`ATTRIBUTED_TO`, `CORPUS_NATURE`,
191197
`corpusNature`), never rebranded as human-authored or authoritative.
192198
6. `EXPECTED_CLASSES` in `build.yml` must equal the true class count and move in
193199
lockstep with any corpus change.
194200
7. The SharedArrayBuffer transport stays disabled until re-enabled behind a
195201
double-buffered SAB with an Atomics-gated generation flip.
202+
8. **Every input file is accounted for.** `input_files == parsed + rejected +
203+
excluded`, and a release contains zero `rejected` entries. A file that
204+
produces no page must produce a coded reason, never silence.
205+
9. **No public artefact contains a private identifier.** Whole-page filtering is
206+
the floor, not the ceiling: derived references are filtered through
207+
`pipeline/visibility.py` at every output, and the release gate re-derives the
208+
private set from source and scans the built tree for it.
209+
10. **Count and identity move together.** `EXPECTED_CLASSES` and
210+
`pipeline/contracts/class-identity.txt` must agree and change in the same
211+
commit; the count keeps its independent-tripwire property, the set adds
212+
membership the count cannot see.
213+
11. **Every export carries a generation manifest** naming the source revision,
214+
the generation id, the counts and a SHA-256 for each artefact. An artefact
215+
without a matching manifest entry is not a release.
196216

197217
## Change process
198218

199219
Any change to a fact in this baseline requires: (1) updating the affected
200220
section with the new `file:line`; (2) confirming the relevant invariant still
201221
holds (especially the `is_public` re-check and the NGG1 stride); (3) if the
202-
corpus size changes, updating `EXPECTED_CLASSES` and the stale `7,874` figures
203-
in `docs/architecture/*.md` **in the same commit**; (4) bumping `version` and
222+
corpus size changes, updating `EXPECTED_CLASSES`, regenerating the identity set
223+
(`python -m pipeline.release_gate <dist> --pages ontology/pages --regenerate`)
224+
and the stale `7,874` figures in `docs/architecture/*.md` **in the same
225+
commit**; (4) bumping `version` and
204226
re-recording `verified_commit` from `git rev-parse --short HEAD`. New decisions
205227
are recorded in `docs/adr/` from `docs/adr/TEMPLATE.md` and the index
206228
regenerated (`node scripts/adr-index-gen.js docs/adr`). Legacy prose — including
207229
the absent `ADR-NG-001` and the `ADR-008`/`ADR-012` corpus pages — is evidence,
208230
not authority: cite it, do not defer to it.
231+
232+
## Estate closeout qualification — 2026-09-04
233+
234+
The [knowledge-production review](../../VisionFlow/docs/estate-review/knowledge-production.md) and [current-vault trace](../../VisionFlow/docs/estate-review/authored-vault-transition.md) distinguish this extracted publisher from the active visionGraph corpus. ADR-2001–2004 now carry explicit identity, publication and consumer acceptance conditions. The count tripwire and separate CI validator remain implemented safeguards; pipeline/build.py itself only logs validation errors. Equal counts cannot prove equal identities or intended visibility. Parser input census, strict publication flags, immutable export generations and actual explorer-schema compatibility remain open. ADR-008/012 under ontology/pages are corpus content, not operative decisions.
235+
236+
## Estate closeout progress — 2026-09-05
237+
238+
The four qualifications recorded on 2026-09-04 are closed against this working
239+
tree, with the count tripwire preserved rather than replaced.
240+
241+
- **Parser input census**`pipeline/census.py`. Every `*.md` is parsed,
242+
rejected with a code, or excluded; the totals must balance and a strict build
243+
refuses a corpus containing a rejected file. Real corpus: 8,138 / 8,138,
244+
balanced, 0 rejected.
245+
- **Strict publication flags** — only a literal JSON `true` publishes; a
246+
non-boolean or absent flag is a validation error and publishes nothing.
247+
- **Inference visibility**`pipeline/visibility.py`, consulted by every
248+
exporter, with per-format tests over a public-child / private-parent /
249+
private-grandparent fixture.
250+
- **Immutable export generations**`pipeline/manifest.py` writes a versioned
251+
manifest (generation id, source revision + dirty flag, counts, SHA-256 per
252+
artefact) with every export; CI re-verifies it.
253+
- **Explorer-schema compatibility**`pipeline/explorer_compat.py` emits the
254+
merged shape the WasmVOWL consumer actually parses, pinned to a fixture.
255+
- **Validation blocks**`pipeline/build.py --strict` stops before writing any
256+
artefact; the non-strict build still exits non-zero.
257+
- **Identity beside the count**`pipeline/contracts/class-identity.txt`; an
258+
equal-count substitution fails the release gate while the count still passes.
259+
260+
Local verification at this revision: 85 pipeline tests pass; the full CI gate
261+
sequence (strict build, corpus contract 8138, validation 0 errors, release gate,
262+
manifest verification) passes; the built site was served and loaded in a real
263+
browser against this build's artefacts. Receipts:
264+
`docs/estate-closeout/2026-09-05/`. This is local source, build, test and
265+
browser evidence; it does not re-certify any deployment.

0 commit comments

Comments
 (0)