17 KiB
Ingest specification — connectors and bundle materialization (framework-neutral)
Status: normative. This document specifies the ingest layer both reference implementations build: a deterministic step that connects the framework to real data sources and materializes the extract as an OKF knowledge bundle, which the existing 8-step loop (method-spec.md) then consumes unchanged. It is written so the layer can be implemented from this spec alone — without reverse-engineering any existing implementation. The prose is framework-neutral by rule: it never names a concrete agent toolkit or vendor stack, and a guard test keeps it that way.
The key words MUST, MUST NOT, SHOULD, and MAY are to be interpreted as in RFC 2119. Requirements are labelled normative; anything marked (reference) documents the reference implementation's concrete choice and is informative, not binding — except where a golden extraction (§11) freezes it.
1. Scope and conformance
Ingest is an addition in front of the loop: nothing in this document changes the method spec, the golden suite, or agent behaviour.
- The method spec (§3 Step 1) forbids query-time retrieval against the bundle. The consequence is architecture-defining: data reaches the model ONLY via OKF bundles. Connectors therefore live in a deterministic ingest step that runs BEFORE the optimiser and materializes the extract as a bundle — not RAG, not live lookups inside the agent loop, no retrieval tools in the run path.
- Ingest makes zero model calls and is deterministic end to end (§11).
- Conformance: a conforming implementation MUST implement the
fileandsqlsource types (§4) with the materialization contract of §5–§7 and the gates of §8–§9, and MUST reproduce the shared golden extractions (§11) byte for byte. Thehttpsource type is an OPTIONAL extension point: implementing it (e.g. against a local mock, or via an MCP-based connector) does not require any change to this spec, and NOT implementing it does not break conformance. - Honesty rule (unwaivable, method spec §1): a machine-generated bundle is labelled as
such (
generated: trueplus a manifest reference, §7) everywhere it is presented. - Boundary: the deploying organisation owns processing purposes and impact assessments; ingest provides only the technical prerequisites (local-only default, provenance, no silent egress).
2. Architecture
manifest → connector → mapping → OKF bundle (incl. index generation) → [existing loop, unchanged]
An expert's coupling to a source is one JSON manifest (§4). A connector executes the
manifest's extractions against the source. Materialization (§5) maps each extraction to an
OKF concept file with a provenance frontmatter layer (§7) and generates or updates the
bundle's index.md (§6). The loop then reads the bundle exactly as it reads a hand-curated
one — by navigation, never retrieval.
Index generation is part of the contract. A bundle without index.md is an error, and
navigation follows ONLY index cross-links (method spec §3 Step 1) — a generated concept file
without an index link is unreachable. The materializer therefore creates or updates index.md
(§6); navigability is a load-bearing requirement (§11), not a detail.
3. Layer separation in the bundle (unwaivable)
The bundle is not only input — it is also the wiki the promotion gate (method spec §6) lifts approved knowledge into. Two rules keep ingest and the learning loop apart:
- The verdict layer is RESERVED. A manifest mapping MUST NOT produce
type: verdictfiles, and generated filenames MUST NOT fall in thepromoted-verdict-*namespace (nor beindex.md, which is managed per §6). The promotion gate is the ONLY path into the verdict layer. Rationale: seeding (method spec §3 Step 1) turns everytype: verdictfile into a store entry with decision defaultapproved— an ingest that could write verdict-typed files would inject machine-generated "approved" verdicts around the gate, exactly the self-contamination the gate exists to prevent. This MUST be enforced fail-fast at manifest validation (before any source call) and proven by a load-bearing test (§11). - Ingest owns only its own files. Re-materialization replaces EXACTLY the files carrying
the ingest stamp (
generated: trueplus aningest_manifestreference, §7) and MUST NOT touch curated or promoted files. If a generated filename collides with an existing file that does NOT carry the stamp, materialization MUST fail — never overwrite curated content. Index updating is idempotent and preserves curated links (§6).
4. The ingest manifest (the contract)
One JSON file per source coupling. The manifest MUST be schema-validated fail-fast BEFORE any source call — a malformed manifest never starts a run (the startup-contract discipline of method spec §10). Queries are configuration, not code: declarative strings the connector interprets; a connector MUST NOT evaluate manifest content as program code.
Top-level fields (all required):
| Field | Meaning |
|---|---|
manifest_version |
Integer schema version; this spec defines version 1. |
source |
The source description, polymorphic on source.type (below). |
bundle_summary |
Prose used as the index body when the materializer creates a fresh index.md (§6). |
extractions |
Non-empty list of extraction descriptions (below). |
source — polymorphic on type (common field: id, the source-system identifier
matching [a-z0-9][a-z0-9-]*, stamped as source_system in §7):
type: "file"— a local file catalogue. Fieldroot: the directory the extraction paths resolve against. Path resolution MUST be boundary-checked againstroot, fail-closed (the OKF path rule) — an extraction can never read outside the catalogue.type: "sql"— a SQL database. Fieldconnection_ref: the NAME of a runtime-resolved reference (an environment variable) whose value is the connection string or database path.type: "http"— a remote endpoint (OPTIONAL extension point, §1). Fieldbase_url: the endpoint base; it MUST NOT embed credentials. Optional fieldcredential_ref: the NAME of a runtime-resolved secret reference. An MCP-based connector is an extension of this family and MUST honour the same extraction, materialization, and gate contracts.
Credentials never live in the manifest. The manifest carries only references by name
(connection_ref, credential_ref); the secret is resolved at run time from the
environment. A manifest is therefore versionable and shareable without secrets.
extractions — each entry (all fields required unless marked optional):
| Field | Meaning |
|---|---|
id |
Unique within the manifest, matching [a-z0-9][a-z0-9-]*; names the generated file (§5). |
title |
Human-readable title; becomes the title frontmatter and the index link label. Single-line. |
query |
The extraction query, polymorphic on the source type (below). |
okf_type |
The generated file's OKF type. MUST NOT be verdict (case-insensitive; §3). |
max_rows |
Required positive integer cap on the extraction size (§8). |
query by source type: for file, a relative path (within root) to a CSV file whose first
row is the header; for sql, a single read-only SELECT statement (one statement, no data
modification — the connector SHOULD enforce read-only access, and the query SHOULD carry an
explicit ORDER BY, since golden conformance requires a stable row order); for http, a path
joined to base_url, fetched with GET.
5. Materialization (deterministic)
Materialization takes three EXPLICIT inputs: the manifest, the target bundle directory, and
ingested_at — plus the network opt-in flag (§8) when the source type requires it.
ingested_atis an explicit required argument — there is NO wall-clock default (mirroring the promotion gate's timestamp rule, method spec §6). Format: ISO-8601 UTC with aZsuffix (e.g.2026-07-03T12:00:00Z), stamped verbatim. This is what makes golden extractions bit-deterministic.- One concept file per extraction, named
ingest-{extraction id}.md(the extraction-id grammar in §4 makes the name path-safe; theingest-prefix keeps the namespace disjoint fromindex.mdandpromoted-verdict-*). Splitting one extraction into per-row files is an extension point, not version 1. - Frontmatter — exactly these keys, in exactly this order (OKF line-oriented
key: value; §7 defines the provenance semantics):type,title,source_system,source_query,ingested_at,ingest_manifest,generated. All values MUST be single-line; the materializer MUST collapse whitespace runs (including newlines) insource_queryto single spaces. - Body rendering — for
fileandsql: a markdown table, header row = column names, data rows in source order. Cell values: text verbatim with\escaped as\\,|escaped as\|, and newlines replaced by single spaces; integers in plain decimal; non-integral numbers in their shortest round-trip decimal form; SQL NULL as the empty string; any other value type MUST fail (never silent coercion). Forhttp: the response body verbatim inside a fenced code block. Files are LF-only and end with exactly one trailing newline. ingest_manifestis stamped as{manifest filename stem}@{h}where{h}is the first 16 hex characters of the SHA-256 of the manifest file's raw bytes — so every generated file points at the exact manifest version that produced it.- Replacement semantics (§3): materialization first removes every file in the bundle whose frontmatter carries the ingest stamp, then writes the new set, then updates the index (§6). Version 1 assumes ONE manifest per bundle; multiple manifests feeding one bundle is an extension point.
6. Index generation
- If
index.mdis missing, the materializer creates it withbundle_summaryas the body; if it exists, every line it does not itself manage is preserved byte for byte. - Each generated file gets one index cross-link,
- [{title}](ingest-{id}.md), appended in manifest extraction order. Linking is idempotent by target: a link whose target is already present in the index is never added twice (reference: the reference implementation's existing index-linking primitive has exactly these semantics). - On re-materialization, index links whose target is an ingest-owned file removed in this run (§5) MUST be removed; ALL other links — curated and promoted — are preserved verbatim. A promoted verdict's index link therefore survives re-ingest (load-bearing, §11).
- The link label is the extraction
title— generated files are context-layer content, so a descriptive label is correct here. (The fixed-neutral-label rule of method spec §6 protects the VERDICT layer and is untouched by this spec.) - (reference limitation) the index read-modify-write is not atomic — single-process use is assumed, as in the promotion gate.
7. Provenance — a separate layer, an unbroken chain
Ingest provenance is its OWN frontmatter layer on generated concept files — NOT an extension of the method spec's §9 proposal provenance. §9 links a proposal to a bundle file and text span; ingest provenance links the bundle file to the source system. Two separate contracts that are never mixed — the same discipline as the two falsifiers.
| Field | Meaning |
|---|---|
source_system |
The source.id from the manifest. |
source_query |
The query that fetched the content (whitespace-collapsed, §5). |
ingested_at |
The explicit timestamp argument, verbatim (§5). |
ingest_manifest |
The manifest reference {stem}@{hash16} (§5). |
generated |
Literally true — the machine-generated marker (§1 honesty rule). |
- OKF consumers preserve unknown frontmatter fields, so this layer rides through navigation and context rendering unchanged.
- Chain integrity: the chain expert → proposal → bundle file + span → source + query + timestamp holds GIVEN versioned bundles (the OKF premise: curated, version-controlled). A re-materialization is a new bundle version carrying the new stamp, so a run's citations can be tied to the concrete materialization. Bundle versioning is a documented deployer prerequisite — no claim of "unbroken" is made beyond it.
8. Security frame
- Local-only default, no silent egress. Network sources (
http, and any other non-local transport) require an EXPLICIT per-run opt-in flag; without the flag the connector MUST refuse fail-fast. The flag is a run argument, never a manifest field — the manifest cannot grant itself network access. - Source calls are logged (which source, when, row count).
- Extraction size caps: each extraction's
max_rows(§4) is enforced fail-fast — an extraction exceeding its cap is an ERROR, never a silent truncation. - Impact assessments and processing purposes stay with the deployer (§1).
9. The HITL gate
Two layers, both required:
- Procedural: ingest NEVER runs automatically — always an explicit operator/expert command with a manifest path. No scheduler, no implicit re-ingest.
- Technical: fail-fast schema validation before any source call (§4), plus the network opt-in flag (§8).
Richer approval mechanics (a signed approved_by, an approval registry) are an extension
point — not version 1.
10. Re-ingest and versioning
Version 1 re-ingest is full re-materialization of the ingest-owned files (§5): given the
same source content, manifest, and ingested_at, the result is byte-identical and repeated
runs are idempotent. Curated and promoted content ALWAYS survives (§3, §6). Incremental
re-ingest is an extension point.
11. Determinism, golden extractions, and load-bearing tests
Connectors are tested ONLY against fixtures and golden extractions — never against live sources. Test suites MUST run without credentials and without network access.
Golden extraction format: one directory per case, convention
examples/ingest-golden-{source type}/, containing:
| Entry | Meaning |
|---|---|
manifest.json |
The manifest under test. |
fixture/ |
The source content (the file catalogue, the database file, or the mock payloads). |
ingested-at.txt |
The fixed timestamp, one line, §5 format. |
expected-bundle/ |
The expected materialized bundle, compared file by file, byte for byte. |
Load-bearing conformance tests (a test MUST fail when its seam is detached — the method spec §11 regime):
| Seam | The test MUST fail when… |
|---|---|
| Provenance stamping | a generated file no longer carries the §7 layer |
| Navigability | the generated bundle stops being consumable by the UNCHANGED bundle-navigation code, index links included |
| Verdict reservation | a manifest mapping to type: verdict (or the reserved filename namespace) stops being rejected |
| Re-ingest layer safety | re-materialization over a bundle with a promoted verdict deletes the verdict file or its index link |
| Golden regression | any byte of a golden extraction's expected bundle diverges |
| Network gate | an http source stops refusing fail-fast without the opt-in flag |
| Spec integrity | this spec goes missing, names a concrete agent toolkit, or stops documenting a contract field |
12. Cross-check table
Every field of the machine-readable contracts, mapped to its normative section (completeness is enforced by the spec-integrity test):
| Field | Contract | Section |
|---|---|---|
manifest_version |
manifest (top level) | §4 |
source |
manifest (top level) | §4 |
bundle_summary |
manifest (top level) | §4, §6 |
extractions |
manifest (top level) | §4 |
type |
manifest source discriminator / OKF frontmatter | §4, §5 |
id |
manifest source and extraction identifiers | §4 |
root |
manifest source (file) |
§4 |
connection_ref |
manifest source (sql) |
§4 |
base_url |
manifest source (http) |
§4 |
credential_ref |
manifest source (http) |
§4 |
title |
manifest extraction / frontmatter / index label | §4, §5, §6 |
query |
manifest extraction | §4 |
okf_type |
manifest extraction | §4, §3 |
max_rows |
manifest extraction | §4, §8 |
source_system |
provenance frontmatter | §7 |
source_query |
provenance frontmatter | §5, §7 |
ingested_at |
provenance frontmatter / materialization argument | §5, §7 |
ingest_manifest |
provenance frontmatter | §5, §7 |
generated |
provenance frontmatter | §3, §7 |
manifest.json, fixture/, ingested-at.txt, expected-bundle/ |
golden extraction case | §11 |