docs(plan): answer the Door B/A capability-gap order from ms-ai-architect

ms-ai-architect's bake-off measured that no door carries both freetext
ingestion and a formable index. Verified against the code (not the
report) that neither offered alternative closes it: a BundleProfile
carries no title-derivation field, and a Door A connector was already
rejected by the consumer's own 2026-07-20 reasoning. The real gap is a
Door B title-derivation feature, independent of profile selection;
recorded as a decision only, no implementation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-08-26 23:54:35 +02:00
commit dc9ea599c5

View file

@ -225,3 +225,66 @@ No scanning, sanitizing, or quarantine logic is implemented here.
`llm-ingestion-guard` (automated:
`test_the_only_runtime_dependency_is_the_security_boundary`; the range
itself is `>=0.3,<0.4` since the bump).
## Door B ↔ Door A capability gap, answered 2026-08-26
Order `20260826T114527Z-9684928014-from-ms-ai-architect`, routed via `.claude`
as PM. ms-ai-architect ran a bake-off (OKF vs. non-OKF, for their "second
brain" use case) and measured that no door carries both capabilities that use
case needs: Door B takes freetext but labels concepts with `title = path.stem`
and never a real title, starts its index empty, and takes no `profile`; Door A
has the formable index (`bundle_summary` prose + manifest-authored labels) but
its connectors are `read_csv`/`read_sql`/`read_http` only — no freetext. They
posed four options and asked which we pick: (a) Door B takes a `profile`,
(b) a freetext connector on Door A, (c) not a gap we close, (d) something else.
**Answer: (d), narrowly.** The missing piece is not a door choice — it is a
title-derivation feature scoped entirely inside Door B's existing boundary.
Verified against the code before deciding (message content is not evidence on
its own):
- `BundleProfile.index` (`IndexPolicy`, `profiles.py:437-444`) carries only
link-rendering/validation fields (`link_template`, `per_directory`,
`heading_required`, `entries_match_directory`, ...) — nothing that produces
or improves a label. `OKF_V0_2`'s extra keys (`profiles.py:755-757`:
`verified`, `status`, `stale_after`) are declared but constructed nowhere —
`grep -rn '"verified"\|"status"\|"stale_after"' src/*.py` outside
`profiles.py` returns nothing. Giving Door B a `profile` parameter would pick
a frontmatter *shape*; it cannot produce the label richness the bake-off
measured as missing. **(a) as literally posed does not close the measured
gap** — it answers the separate, already-flagged question at
`materialize.py:296-299` ("which profile Doors B/C should own"), which stays
open on its own terms.
- **(b) was already decided against, by ms-ai-architect itself**, on
2026-07-20 (`docs/plan/2026-07-20-trinn-c-svar.local.md:101-106`): their
freetext is LLM-authored or user-pasted, never fetched from a queryable
source, so a Door A connector (pull model: manifest → connector → fetch)
gives their use case nothing. That reasoning is exactly what produced Door B
in the first place (F1 split into F1a/F1b; F1a closed as Door B, not a
connector). Nothing in the new message supplies a fact that reopens it.
- **(c) is too strong.** The specific missing capability — a real title
instead of `path.stem` — needs no model call (a leading `# heading` or an
explicit `title:` frontmatter key already present in the dropped file,
falling back to `path.stem` when neither exists is a deterministic parse),
so it sits inside the boundary Door B already owns ("all file-type→text
extraction lives HERE") rather than outside it.
- Confirmed both `render_inbox_concept` (`inbox.py:84-129`) and
`process_inbox` (`inbox.py:221`) hardcode `DEFAULT` today, and that
`title` has exactly one source, `path.stem` (`inbox.py:337`) — no code path
reads a source file's own heading or frontmatter for it.
**What this does and does not close.** Title derivation would close the label
half of the gap. It would NOT reproduce Door A's `bundle_summary`: that field
is human-authored via the manifest, and a file dropped in an inbox has no
equivalent authorship step. That half stays open — nothing proposed in the
order closes it, and the consumer did not ask for a summary specifically.
**Phase and sequencing.** This is Door B (Phase 2, already shipped)
demand-driven work, not Phase 4 — it is Python, not Node, and needs no
cross-repo agreement step; the consumption contract §5 line "no consumer has
asked for one" no longer holds for this specific feature, because one now
has. No implementation is undertaken by this decision — recorded as a
decision only, per the order's own discipline ("this is a decision that is
ordered, not code"). It is a demand-driven candidate for a future TDD session
(failing test first, per this repo's Iron Law), not scheduled by this entry.