---
name: spt-core-harness-boundary-and-grounding
description: "Two binding operator corrections (2026-06-15): spt-core never caters to a specific harness (adapter formats output); ground all completeness questions in CONTEXT.md/ADRs"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: ce7ce158-107f-4da4-a203-cea98da80b27
---

Two binding operator corrections during the perri F-001 harness-contract triage (2026-06-15):

1. **spt-core does NOT cater to any specific harness — the ADAPTER DEV formats spt-core's output
   for the target harness.** Don't document harness-specific glue (CC hook-event→api mappings, CC
   hooks.json shape, CC param-sourcing, CC additionalContext injection-formatting) on spt-core's
   surface. spt-core publishes harness-AGNOSTIC primitives (the `spt api` command surface +
   semantics + I/O formats, the substitution-key catalog, the manifest schema); the adapter maps
   them to its harness's events and formats the output for its injection channel.

2. **Ground every spt-core completeness question in CONTEXT.md + the ADRs before calling anything a
   gap or writing a fix.** The project is thoroughly planned — an apparent "gap" is most likely
   already specified. Ignoring CONTEXT/ADRs is problematic. (Same discipline as
   [[gate-against-documented-design]].)

**Why:** spt-core is harness-INDEPENDENT by design (CONTEXT L7/L52: "harness-specific surfaces…
abstracted behind a runtime layer that consumers supply"; L181: "spt-core supplies the subcommands;
the adapter supplies the env aliases"; L112: "spt-core docs must TEACH adapter devs the format").
Documenting CC specifics would violate that line and bloat the agnostic core. This is
[[adapter-glue-model-boundary]] applied to docs, not just code.

**How to apply:** When an adapter dev (perri) reports a "missing contract," first ask: is it (a)
already in CONTEXT/ADRs (→ surface it, don't re-author), (b) harness-specific glue (→ the adapter's
job, not an spt-core gap), or (c) a genuinely under-documented AGNOSTIC primitive (→ narrow doc fix
propagating CONTEXT's existing spec, never inventing new semantics). I over-reached on F-001 by
offering to document CC param-sourcing + injection-formatting + a CC-event mapping table on the
spt-core surface; retracted. F-001 disposition: most = adapter-authoring (perri owns); single spt-core
residual = publish the agnostic primitives (api poll emit-frame-format + substitution-key catalog) to
the public docs-site, VERIFIED against CONTEXT/ADRs first (may already exist in docs/).

**RESIDUAL VERIFIED (doyle 2026-06-15):** TWO narrow items, both propagate-existing-spec (not new design):
(1) `api poll` EMIT FRAME format — named sender = `__REPLY_TO__:<from_id>\n<body>`, anonymous = bare
body (spt-store/src/spool.rs:89-95). The `__REPLY_TO__` convention is in KNOWN-HAZARDS + ADR-0009
(access-gate reply correlation) + ADR-0012 (Psyche routing) but NOT on the adapter-facing
docs-site/harness-contract → real CONTEXT-L112 gap (must teach adapter devs the format). Adapter parses
the header to identify reply target, formats/strips per harness (legacy owl → `<owl_messages from=…>`).
(2) Full substitution-key catalog (12 keys) only partially in docs-site manifest.md examples; the
complete enumerated table isn't published — minor. Gave perri the exact frame format from source;
HOLDING the docs-site write until perri's throwaway-session observation of `api poll` confirms-match
(one clean write, no drift). See
[[spt-claude-code-next]], [[adapter-glue-model-boundary]], [[gate-against-documented-design]].

**SUPERSEDED 2026-06-15:** residual item (1) above is now OBSOLETE — ADR-0020 ([[event-envelope-reply-to-removal]]) REMOVED the `__REPLY_TO__` emit-frame entirely; `api poll`/`worker-poll` now emit the `<EVENT type="msg" from=…>` envelope (the same canonical format as `api listen`). The adapter parses `<EVENT>`, not the relic. Don't publish the `__REPLY_TO__` frame format to docs-site — that doc gap dissolved with the relic.

**F-003 (perri, 2026-06-15) — SAME PATTERN, capability already built:** perri filed "file-backed [strings] ABSENT from published v0.7.0" (ADR-0001 names it a hard M12 dep for UPS-injection skill bodies). VERIFIED in spt-core code: it IS shipped — **REQ-MANIFEST-5** (M12-W3 @ e08cea0), `key = { file = "rel/path" }` value-position inline-table FILE POINTER (profile.rs::as_file_pointer + registry.rs get_string lazy-resolve, validate-at-register containment, skip-diagnostics, local-profile-dir update-safety, [impl]+[unit] tagged). perri searched for @file/include/set-string --from-file (wrong syntax) + the open-object schema didn't flag `{file=...}`. NOT a capability gap → ADR-0001 dep SATISFIED, no amendment, no build change. REAL gap = PUBLISHED-DOCS visibility: docs-site/llms-full.txt has ZERO mention (grep-confirmed); the `[doc->REQ-MANIFEST-5]` evidence lives only in CONTEXT.md §adapter strings (internal), docs/MANIFEST.md thin too. doyle's docs/contract leg to surface the `{ file }` syntax on docs-site. Gave perri exact usage → unblocked. LESSON REINFORCED: verify the CODE (grep the REQ impl) before treating a perri "absent" as a real gap — F-001 was glue, F-003 was a docs-discovery gap with the capability already built+specified.

**#17 counter-38 (2026-06-30) — I VIOLATED THIS, twice-over, operator caught it.** Field bug: ccs-profile agents get NO digest (transcript relocated to $CLAUDE_CONFIG_DIR, spt-core's locate misses → os error 3). My FIRST ruling "FIX A" baked a harness-specific solution INTO spt-core: capture `CLAUDE_CONFIG_DIR` by name + a `{config_dir}` key = a CC-ism in the agnostic core. WRONG DIRECTION. Operator: "spt-core wholly harness-agnostic; needs a more universally applicable solution." TRUTH (found by /grill-with-docs vs CONTEXT + grepping the manifest): the base `~/.claude` was ALREADY in the ADAPTER template (not spt-core); the real gap was that `[env.<VAR>] direction="read"` (EnvDirection::Read) is DECLARED-BUT-DORMANT (only Inject wired). Fix = WIRE the existing GENERIC primitive (adapter declares which env var; spt-core captures declared read-vars generically, names none). TWO-PART LESSON: (a) same as F-003 — the "missing feature" is often a DORMANT generic primitive already in the schema (grep the manifest structs for a latent mechanism BEFORE inventing one); (b) NEVER fix a harness-specific symptom by teaching spt-core a harness-specific name/path — find the generic seam the adapter drives. And: RUN every milestone design decision through CONTEXT.md (source of truth) — CONTEXT L128-132 (Path A adapter-owns-locate) + the [env] read direction were the whole answer. See [[gate-against-documented-design]].
