diff --git a/docs/PLAN.md b/docs/PLAN.md index ce63682..ae2e6dc 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -172,36 +172,82 @@ evasion (2504.11168), EchoLeak (CVE-2025-32711), RAGShield (2604.00387), CaMeL (2503.18813), Dual-LLM (Willison), and the litellm supply-chain compromise (corroborates the minimal-dependency thesis). -## v0.2+ stream sequencing (post-v0.1.0, decided 2026-07-06) +## v0.2+ stream sequencing (revised 2026-07-06) -v0.1.0 is tagged — the format-agnostic text core (modules 1–11, hardened at -`5397ba1`, released at `df30c7b`). Three forward streams, **all to be built**; -the order is dependency-driven, not preference: +v0.1.0 and v0.2.0 are tagged: the format-agnostic text core (modules 1–11, +`5397ba1` / released `df30c7b`) and the OKF adapter (stream 1, released +`542ac92`). The forward order was **re-sequenced on 2026-07-06** after a +ground-truth pass over the intended flagship consumer. -1. **OKF v0.2 hardening** — the OKF adapter + the 8 tasks in - `docs/OKF-INGESTION-BRIEF.md` §8 (internal order T8 → T1–T4+T6 → T7 → T5). -2. **Wire consumers** — `claude-code-llm-wiki`, `ms-ai-architect`, - `portfolio-optimiser` (its OKF-upload-inbox is the flagship). -3. **Node/polyglot port** — one polyglot repo over the shared JSON lexicon - (BRIEF §13.5/§8); driver = `ms-ai-architect` convergence. +**Finding that drove the change.** The named flagship — `portfolio-optimiser`'s +"OKF-upload-inbox" — does not exist as a seam. Both optimiser siblings are frozen +at their release milestone, carry their *own* OKF layer (navigate + materialize +from trusted manifests), receive no *external* bundles, and take no dependency on +this guard; the operator's own registered future work for them does not include +it. Wiring an immature guard into two mature, spec-frozen repos would complicate +them for a consumer that is not asking for it. **Consumer integration is therefore +deferred until the guard is mature**; consumers are informed at the operator's +timing, not pushed. -**Why this order (dependencies, not taste):** +Revised streams: -- The flagship consumer (`portfolio-optimiser`'s OKF-upload-inbox) *is* an OKF - surface. Wiring it before OKF hardening ships a knowingly-incomplete guard - into the exact case that needs it → **stream 2 depends on stream 1**. -- The Node port must port a *settled* public surface. OKF v0.2 adds the - OKF-adapter surface; porting before it = porting a moving target and exactly - the §13.3 split-drift the polyglot rule exists to forbid → **stream 3 after 1**. -- Within stream 1: **T8** (residual-risk docs, brief §7.2/§7.4) is the cheap, - decision-free first step — it lands independently and makes the live README - honest about uncovered OKF surfaces before anything else is built. **T3/T4/T5 - are blocked on an OKF-spec confirmation pass** (brief §9 "operator premise": - concept-ID=path-minus-`.md`, reserved `index.md`/`log.md`, the `resource` - field, `description`→`index.md` were taken from the brief, not checked against - `SPEC.md`). +1. **OKF v0.2 hardening** — shipped (adapter + brief §8 tasks; T5b/B deferred to a + consumer that owns corpus storage). +2. **Mature the guard here, keeping it Node-port-friendly** — the near-term work. + The lexicon is already shared JSON (polyglot-ready); keep the `text -> findings` + surface clean and free of Python-only cleverness in the OKF layer, so stream 3 + is a *translation*, not a redesign. The centrepiece is the **OKF inbox + showcase** (below): the guard demonstrating its own flagship use case + end-to-end, in-repo. +3. **Node/polyglot port** — the strategic enabler of painless integration (many + OKF consumers are Node/JS; the lexicon seed was `.mjs`). One polyglot repo over + the shared JSON lexicon; never split §13.3. Its API/lexicon contract should be + **scan-informed** (stream 4), not guessed. +4. **Pre-adaptation scan (operator-timed)** — at the operator's chosen point, scan + every repo and plugin that uses or plans Google OKF, then adapt the guard's + surface in advance so a later integration is painless. The scan is the input to + the "painless" guarantee: it grounds both the Node port's contract and any + consumer-specific seams before they are locked. + +### The OKF inbox showcase (next concrete build, TDD) + +The flagship artifact we hand a consumer later — an in-repo end-to-end +demonstration of the mode-b receive/quarantine gate, mirroring +`tests/test_showcase.py` but for a *received external OKF bundle*. It composes the +public `okf` surface exactly as an "upload inbox" consumer would, so it doubles as +the README's OKF worked example. Every test is authored by us — the point is to +prove intent, not to coincidentally pass. + +- **Composition** (`tests/test_okf_showcase.py`): an `_inbox(bundle)` helper + calling `okf.import_bundle(bundle, origin=Origin.EXTERNAL, channel=Channel.AUTOMATIC)` + and mapping the aggregate disposition — `WARN` → ADMIT, `QUARANTINE_REVIEW` → + HOLD, `FAIL_SECURE` → REJECT, any error → REJECT (fail-secure default). +- **One poisoned bundle** planting one attack per OKF surface at once, each with a + label proving it was caught/rejected: + - body injection (T1 scan) and frontmatter `description` injection (T1 + whole-concept scan); + - a non-`https` `resource:` URL (T3 → FAIL_SECURE); + - a path-traversal concept key `../x.md` (T4 → FAIL_SECURE) and a reserved-name + shadow `index.md` / `log.md` (T4); + - a dangerous frontmatter value (anchor / alias / explicit tag, T2 → FAIL_SECURE); + - a dangerous-scheme cross-link `[x](javascript:…)` (T5a → `links.rejected`); + - a dangling cross-link to an absent concept (§7.2 dormant signal → + `links.dangling`); + - a carrier/obfuscation-hidden body injection (zero-width / homoglyph / rot13 / + whole-string base64) routed through `scan_concept`. +- **Assertions:** aggregate disposition is FAIL_SECURE; every planted OKF + vulnerability appears in the per-concept rejects / findings / link graph; a + **clean** bundle admits (WARN, no rejects, no dangling); `BundleResult.log()` + renders one line per concept with rejects marked. **Detach-proof:** neutering + `import_bundle` to always-admit makes the poison assertions fail. +- **Honest scope:** demonstrates the *structural + known-pattern* OKF surface only + — semantic/factual poisoning stays out (README honest-limits), consistent with + the core showcase. + +**Deferred, unchanged:** T5b/B (the persisted cross-run link graph) waits for a +consumer that owns corpus storage; §7.2 dormant cross-run links remain a +documented residual until then. **Splittable early win (optional):** text-only consumers can be wired at v0.1.0 -today — for them the guard is already complete. Folded behind stream 1 by -default (editing other repos = context switch + weaker feedback than the -flagship). Pull forward only on explicit request. +today — for them the guard is already complete. Deferred with stream 2 by default; +pull forward only on explicit request.