[OK] REQ-TAG-SEND-PRETOOL-TRACE required: [] stages: -doc -impl -unit -int RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel by design. The evidence this requirement described has been DELETED, not merely left untagged, so the stages are cleared rather than the requirement removed: what it protected is kept here as the reasoning that has to outlive the code. ORIGINAL: The mid-turn (PreToolUse) tag-send leg records its send outcomes in the hook trace exactly as the Stop leg does, so the trace covers BOTH dispatch legs and a diagnosis can never read half the population as if it were all of it [OK] REQ-TAG-SEND-QUEUED-VISIBLE required: [] stages: -doc -impl -unit -int RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel by design. The evidence this requirement described has been DELETED, not merely left untagged, so the stages are cleared rather than the requirement removed: what it protected is kept here as the reasoning that has to outlive the code. ORIGINAL: A peer send that lands as QUEUED (accepted + spooled, target not listening) is reported as QUEUED, never merged into 'delivered': the mid-turn confirm names the spooled targets, and the Stop leg — which drops success confirms by design — records them in the hook trace, so 'sitting in a spool' is always distinguishable from 'never dispatched' [OK] REQ-TAG-SEND-STAMP-EXPLICIT required: [] stages: -doc +impl +unit -int RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel by design. The evidence this requirement described has been DELETED, not merely left untagged, so the stages are cleared rather than the requirement removed: what it protected is kept here as the reasoning that has to outlive the code. ORIGINAL: Adapter-dispatched `@<…@>` peer sends carry `OWL_SESSION_ID` EXPLICITLY, set to the dispatching turn's own session id, so spt-core's send site can compute the `sender_proven` stamp. Core reads that variable FROM THE ENVIRONMENT at the send site and never from `--from` (which is reply-routing metadata); the hook process carries it on NEITHER dispatch leg (MEASURED 2026-08-21, `owl=empty` on PreToolUse and on Stop, two different pids), while an agent's own Bash-tool shell does (measured on two endpoints) because SessionStart writes the export into CC's env FILE, which tool shells read and hook children do not. The consequence of leaving it: one agent, two outbound paths, different attribution — an unstamped send makes core's tier-1 sender rules ABSTAIN (it forges nothing), silently defeating any receiver-side rule naming that agent, and the receiver cannot recover it because the endpoint spool has no `sender_proven` column at all. Same-node traffic hides the whole thing, since same-node origin short-circuits to Allow before the store is consulted, so this surfaces only on a remote arm as an arrival that looks non-discriminating for reasons nobody logged. SHAPE: a `spt_send_with_env` seam (spt_send delegates to it with an empty env, so there is ONE spawn implementation and no second copy to drift), and the tag-dispatch call site passes `OWL_SESSION_ID = ` — the same move `resolved_id`'s whoami call already makes, using the payload's session rather than any ambient value, so a descendant session cannot dispatch as its ancestor. The probe from REQ-TAG-SEND-STAMP-PROBE stays and now records `inherited=` beside `owl=explicit`: what the harness happens to provide is still worth seeing, it just no longer decides the stamp. [OK] REQ-TAG-SEND-STAMP-PROBE required: [] stages: -doc -impl +unit -int RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel by design. The evidence this requirement described has been DELETED, not merely left untagged, so the stages are cleared rather than the requirement removed: what it protected is kept here as the reasoning that has to outlive the code. ORIGINAL: A turn that dispatches `@<…@>` peer messages RECORDS which `OWL_SESSION_ID` its send child inherited, and which leg dispatched. spt-core stamps `sender_proven` from the SENDING side and the CLI computes it by reading `OWL_SESSION_ID` FROM THE ENVIRONMENT (never `--from`, which is reply-routing metadata), resolving it to an endpoint with a readable perch record; otherwise the field is absent. An absent stamp FORGES NOTHING — core's tier-1 sender rules abstain — but it silently defeats any receiver-side rule naming this agent, and the receiver cannot tell: the endpoint spool carries no `sender_proven` column at all (schema read, lia 2026-08-04), so emission is evidenceable ONLY at the emitter. Our tag dispatch shells `spt send --from ` from the HOOK process and passes nothing explicitly, inheriting that process's environment wholesale, while an agent's own Bash-tool shell is MEASURED to satisfy the predicate on two independent endpoints (perri, lia) because SessionStart appends `export OWL_SESSION_ID` to CC's env FILE — which reaches tool shells, not necessarily CC's own process env. So one agent may stamp on one outbound path and not the other, invisibly at both ends, and same-node traffic hides it completely (same-node origin short-circuits to Allow before the store is consulted). THIS REQUIREMENT IS THE MEASUREMENT, NOT THE FIX, and that separation is deliberate: the standing suspicion rests on an ABSENCE-GREP (no production launcher sets the var), the same instrument class that misled this project twice on 2026-08-04. The probe fires ONLY on a turn that really dispatches (a rolling log must not fill with per-turn wallpaper), names its LEG (PreToolUse and Stop are different processes' children and need not agree — an instrument that cannot separate its two legs is the half-population trap already paid for once), classifies as `self` / `foreign` / `empty` (an inherited ancestor value is NOT folded into either happy or absent, since it may still resolve core-side), and NEVER logs the session id value. The fix — passing the session id explicitly the way the identity call already does — waits on the reading. READING TAKEN 2026-08-21 on HFENDULEAM, and it settles BOTH legs: `owl=empty leg=PreToolUse` and `owl=empty leg=Stop`, logged from two different pids, so the hook child inherits the var on NEITHER dispatch leg and every adapter-dispatched tag send was going out unstamped while the same agent's tool-shell sends carried the stamp. The suspicion the absence-grep raised was correct — which is not the same as it having been evidence. Measured without manufacturing traffic: a SELF-targeted tag fires the probe and is dropped before any send, honoring the standing constraint (lia, 2026-08-04) that no more sends of unknown stamping be produced. Fix shipped as REQ-TAG-SEND-STAMP-EXPLICIT; the probe stays and now records `inherited=` alongside, so a harness change that starts or stops providing the var is visible rather than silent. [OK] REQ-TAG-SEND-VERDICT-NOT-CATCHALL required: [] stages: -doc -impl -unit -int RETIRED 2026-08-29 by REQ-IO-COMPLIANCE-DECLARED (Release B): this adapter no longer parses or dispatches shortform - spt-core does, off the ingest payloads we report, and per-target outcomes surface through the now-signal DISPATCH_RESULTS category, which core documents as the only channel by design. The evidence this requirement described has been DELETED, not merely left untagged, so the stages are cleared rather than the requirement removed: what it protected is kept here as the reasoning that has to outlive the code. ORIGINAL: A tag-send verdict never asserts more than it measured: NO PERCH is reported ONLY for a core NO_PERCH answer, a failed `spt` spawn is named as a spawn failure, and an unrecognized answer is reported WITH its raw token — so a send outcome is never a claim about a peer's perch that the adapter did not observe [OK] REQ-TRUST-AUTOSEED required: [impl, unit] stages: -doc +impl +unit -int An spt-hosted endpoint must never come up wedged on a startup dialog no human is watching. The launch shim seeds Claude Code's per-project startup approvals for the cwd it is about to spawn in, BEFORE spawning: `hasTrustDialogAccepted`, plus `hasClaudeMdExternalIncludesApproved` and `hasClaudeMdExternalIncludesWarningShown`. THE FAILURE IT CLOSES IS SILENT BY CONSTRUCTION: `spt endpoint run` prints ENDPOINT_RUN_STARTED, the harness then sits at a modal dialog with null stdin, and the endpoint stays ready=false FOREVER with no hooks, no transcript, ~1s CPU and a blank PTY on attach - the F-027 core, and the dominant spawn-failure mode measured on this node. THREE INVARIANTS, EACH ALREADY PAID FOR, AND ALL THREE ARE THE REQUIREMENT rather than notes on it. (1) NEVER OPEN-TRUNCATE `.claude.json`: an ENOSPC mid-write once wiped trust for 16 projects, so the store is written tmp-then-rename in the same directory, never opened for truncation in place. (2) TRUST IS PER-CONFIG-ROOT: the write targets the root THE SPAWN WILL RESOLVE - the `--account` root when the profile names one, else `$CLAUDE_CONFIG_DIR`, else `~/.claude.json` - using the same resolution the spawn itself uses, because seeding the operator shell's root while the spawn resolved a different one produced a valid-looking seed and a wedge anyway (measured: two spawns on one box resolved two different roots). (3) TRUST ALONE DOES NOT CLEAR STARTUP: external-CLAUDE.md-imports is a SECOND dialog that hangs a spawn just as hard, hit whenever the cwd's CLAUDE.md chain imports outside the cwd (any subdirectory of a repo whose root CLAUDE.md uses an `@` import), so seeding trust alone would half-deliver the feature's own promise. THE PROJECT KEY IS AN EXACT STRING MATCH, not a path comparison: Claude Code writes forward-slash keys (75 of 75 in this node's live store, zero backslash) and matches trust by exact key, so a slash-direction or canonicalization mismatch is a silent miss that wedges exactly as an absent key does. WRITE ONLY WHEN A VALUE IS ACTUALLY WRONG - the happy path reads and returns without touching the file, which keeps invariant 1's blast radius near zero and keeps the read-modify-write window (the store is rewritten by every live session every 15-25s) essentially unreachable in steady state. A seed that cannot be performed is a NOTICE, never a refused launch: a wedge is bad, but refusing to start an endpoint because its trust store could not be parsed is worse, and Claude Code's own dialog remains the fallback. [OK] REQ-TRUST-WARNING-CARRY required: [doc, impl, unit] stages: +doc +impl +unit -int The RECEIVER-COMPOSED `trust-warning` envelope attribute survives the adapter's re-render and is surfaced to the agent, VERBATIM, with the message it is about. Contract (spt-releases #170, gated PASS, routed by doyle 2026-08-21; the docs-site section networking/monics -> 'The warning rides the message' PUBLISHED with the PORTER core cut (v0.59.0) and was re-checked 2026-08-21: the attribute shape matches what was built, and the page states the surfacing obligation in the same inverted terms): a delivered message from a warning-eligible stranger carries its trust warning on its own envelope as a `trust-warning` attribute composed by the RECEIVING node, exactly as `mnemonics-json` is — one arrival instead of two. The value is the FULLY COMPOSED block, never a token: the identifying spine ('TRUST WARNING - this message is from , who reached you through an access rule rather than through anything you decided about them. You hold no note about them.'), the advisory line (a custom override may replace the advisory, NEVER the spine), and the how-to-silence line, attr-escaped by the one composer. NOTHING IS EXPANDED ADAPTER-SIDE, EVER: preserve, do not interpret. NEWLINES RIDE AS ` ` AND THE DECODE ORDER IS LOAD-BEARING (doyle Q3, re-measured and RULED 2026-08-21): the envelope codec is LINE-FRAMED, so a literal newline in an attribute tears the envelope at any line-based reader; the attr rule gains exactly one entity beyond the four, escaping normalizes CR/CRLF to LF then maps LF to ` ` AFTER the `&`->`&` step, so the adapter decode must run BEFORE attr_unescape's amp-LAST step - which is what makes literal ` ` CONTENT round-trip (it rides as `&#10;`, the newline decode leaves it alone, the amp step returns it as text). The wrong order silently turns an operator's advisory override saying ` ` into a line break. `
` is never decoded in an attribute (body rule vs attr rule stay distinct), and the decode stays scoped to this attribute until the docs-site attr-rule section publishes the fifth entity. THE SEQUENCE IS PART OF THE RECORD: the first ruling was 'literal newlines, guaranteed' and this decode was REMOVED on it; re-measured at the lane tip, literal newlines proved to be current BEHAVIOUR but a LATENT CORE DEFECT rather than the contract (the 'one line, always' pin only ever covered the monic attribute, whose newlines are a two-character JSON escape), and the codec extension now rides the same unlanded lane ahead of this feature publishing - an adapter-side question about escaping found a core-side defect. THIS ATTRIBUTE DELIBERATELY INVERTS THE mnemonics-json PRECEDENT that unknown attributes are safely ignored — for this one, BEING IGNORED IS THE FAILURE, because a silently dropped trust warning is a security caution that never happened. hook::render_frames re-renders every delivery (keeps `from` + body), so claude-spt holds custody of the envelope and the obligation is ours: the same seam that dropped mnemonics-json in v0.26.2. LOSS SCOPE, measured by the contract rather than guessed (doyle, Q2): the once-per-session-per-peer cadence mark is made by the RECEIVING NODE when the caution enters the delivery channel — the same act that hands the enveloped message over — with no adapter-side acknowledgement in the loop, so an adapter that drops the attribute silences that (session, peer) pair for THE REMAINDER OF THAT SESSION ONLY, not permanently (the dedup marker lives in the per-session scratch, so any reset that mints a new session owes the warning again; the marker is best-effort and fails toward warning again, and an undelivered warning claims nothing). Scoped, still a real loss. BUILD: a `` sibling block LEADING its message at the adapter's own FRAME level, text verbatim after standard attr-unescape, never summarized and never renderer-truncated (spill owns size); ordered ahead of the `` block - a LIVE path, not a defensive one: a CONTENT-triggered monic legitimately matches a stranger's message (classification is a sender question; content matching is not), so warning + monic ride the same frame by design, and only a SENDER-classifying monic beside a warning about that same sender is the disagreement the invariant forbids, which core suppresses at the source (doyle, 2026-08-21); and the digest surfaces that span with the message. THE PAIRING IS PART OF THE CONTRACT: the block rides the SAME delivery as its message, never batched and never reordered across deliveries. Bodies that are already typed envelopes are UNCHANGED (the warning stays its own system-authored delivery under a reserved author, delivered first, no carrier), and anything a SENDER writes into `trust-warning` is stripped at ingress, so the value read here is always the receiving node's own. Imitation surface identical to REQ-MONIC-REVEAL's and bounded the same way: the discriminant is STRUCTURAL (a genuine block sits at our frame level, ahead of and outside the peer's `` block, where nothing a sender writes can appear), which is the same reasoning core uses for the warning's reserved author. [OK] REQ-UPDATE-NUDGE-VERSION-GATED required: [impl, unit] stages: -doc +impl +unit -int When an `` frame rides a UserPromptSubmit poll drain, the adapter appends a version-GATED update nudge — fired ONLY when this node's running `spt --version` is strictly older than the version advertised in the notify body. Self-suppressing: once this node updates, the gate closes and the nudge stops even with the notif undismissed. The nudge steers the agent to `spt update apply` at a safe point (daemon-only bounce; broker + nested agents survive) and explicitly does NOT tell the agent to `spt notif dismiss` — dismissal replicates subnet-wide and would suppress the prompt for nodes not yet updated (leave dismissal to the operator). Only the spt-update notify triggers it; a peer message mentioning a version cannot. [OK] REQ-UPS-IDENTITY-FASTPATH required: [impl, unit] stages: -doc +impl +unit -int Hook identity resolution is CONSTANT-TIME on ordinary spt-hosted sessions: when $SPT_ENDPOINT_ID is set AND the custody-gated session carrier (REQ-HAZARD-CARRIER-CUSTODY) records the hook payload's session_id, the hook uses that endpoint id directly — ZERO whoami / endpoint-list / endpoint-info / project-history / Git calls. ROOT (2026-07-10 RCA, hertz): spt-core >=0.31.0 aliases `whoami --json` to the full enriched endpoint listing (latest_project_ref per perch -> synchronous Git fanout; measured 45.6s on HFENDULEAM vs CC's ~30s external hook ceiling), so every self_id call risked timing out the hook — UserPromptSubmit missed busy-mark/drain (reachability black-hole) and Stop missed its idle mark (stuck-busy class). The proof also rejects leaked-env impostors: a nested/subagent session inheriting $SPT_ENDPOINT_ID has a different payload sid → falls through to the fallback rather than acting as the parent. FALLBACK: missing env / missing carrier / mismatch → the existing whoami path (harness-hosted live sessions unchanged); it remains deadline-vulnerable until spt-core ships the identity-only session→endpoint API (filed to spt-core) and must never widen back into a default. A /sptc:live turn performs exactly ONE endpoint listing (the explicit roster), never a second via identity. Applies to ALL self_id call sites: UserPromptSubmit, PreToolUse, Stop, SessionEnd, SubagentStart. [OK] REQ-UPS-INJECTION required: [doc, impl, unit, int] stages: +doc +impl +unit +int UserPromptSubmit hook detects /sptc:X and injects X's real instructions as additionalContext (SKILL.md files stay skeletons); must be empirically confirmed UPS fires on slash-commands [OK] REQ-UPS-KEYWORD-HINTS required: [impl, unit] stages: -doc +impl +unit -int The UserPromptSubmit hook PIPES THE FULL USER MESSAGE to `spt api hint --session ` and injects the matched hint, which is the published contract for the `[[hints]]` table every claude-spt manifest has carried since v0.2.x (manifest.schema.json, `hints`: 'the adapter's user-prompt hook pipes the full user message to `spt api hint`; a matching keyword surfaces `text` to the agent's context channel, at most once per session and once per message'). ROOT (2026-08-04 field report, two independent sightings): an agent asked in prose for a knock code and an operator pasted an `sptkc_` invite code — both match the shipped table by hand (`spt api --adapter claude-spt hint` answers each with the right Tip) and NEITHER agent saw anything, because the hook never made the call. The table was INERT from the day it was declared: no keyword hint has ever fired in claude-spt, for any keyword, in any session — a whole declared feature delivering nothing while reading as shipped, and REQ-SKILL-KNOCK's 'Two [[hints]]' clause counted a declaration as evidence. A manifest table is a declaration TO spt-core, never a substitute for the call that consumes it. SHAPE: core frames the answer for a human (`keyword hint for SPT adapter : ""-->Tip: …`) on STDOUT and the agent gets the TIP, not the framing — but an answer without the `-->` separator (core's presentation, not a documented contract) is injected WHOLE rather than dropped, since a hint we cannot parse is still a hint we were given. SUPPRESSED on a slash-command turn (skill_key non-empty): the injected skill body is the operative text, and a Tip naming the command the operator just typed would spend that hint's one per-session firing on a no-op. Blank prompt = no call. The once-per-session seen-set is core's, keyed by session id, so a /clear re-arms every hint — the adapter holds no state of its own here. AMENDED 2026-08-28 (claude-spt-bs#22, REQ-NOW-SIGNAL-INJECT): the hint now reaches the agent through spt-core's ONE turn-boundary funnel, `spt api now-signal`, whose HINTS category IS this contract — `api hint` is published as a thin alias over that category sharing its seen-set, so injecting both would inject the same thing twice. EXACTLY ONE of the two verbs runs per prompt, chosen by whether the session has an endpoint id: `now-signal` requires one as a positional and `hint` does not, and this call was deliberately never perch-gated ('an unregistered session is exactly who a tip is for'), so an id-less session keeps the alias and every other session gets the superset. The `[[hints]]` table, the once-per-session cadence, the slash-command suppression and core's ownership of the seen-set are all unchanged; only the transport moved. One consequence to hold: the funnel takes the turn text as an ARGV value with no stdin form, so it is capped (REQ-NOW-SIGNAL-INJECT) where the alias piped the whole message — a keyword past the cap in a very long paste will not match. [OK] REQ-VERSION-SELF-REPORT required: [impl, unit] stages: -doc +impl +unit -int The adapter binary reports its OWN adapter version (`claude-spt version`, and the `--version`/`-V` aliases), compiled in at build time from the SINGLE source of truth — the `[adapter] version` in `adapter/claude-spt.toml` — so a field operator holding an installed binary can establish which build it actually is without trusting the registry, the manifest beside it, or a filename. TWO INDEPENDENT REASONS, and the second is structural: (1) DIAGNOSIS — measuring an install in the field, there was no way to self-report the version from the binary, so a stranded binary could not be distinguished from a current one on the evidence of the file itself; (2) DELIVERABILITY — spt-core skips rewriting an install destination whose CONTENT is identical, so a release changing only packaging or manifest data emits byte-identical binaries and is UNDELIVERABLE to existing installs (see REQ-HAZARD-ADAPTER-EXEC-BIT). Compiling the adapter version into the binary makes every release's binary content differ BY CONSTRUCTION, so that class of stranded release cannot recur for this adapter regardless of how spt-core resolves it. The build MUST FAIL LOUDLY rather than embed a wrong or placeholder version: exactly one `version = "…"` key is expected, and zero or many is a build error, never a silent fallback. [OK] REQ-WAKE-EMIT-FLIP required: [impl, unit] stages: -doc +impl +unit -int The wake EMIT side sends the NEW envelope keys ({"wake_arm":"v1"[,"directive":…]} for ARM, {"wake_fire":"v1"} for FIRE) — stage 2 of the staged across/wake rename (REQ-WAKE-RENAME-STAGED shipped receive-both in v0.23.0, so every post-v0.23.0 resident translate parses the new keys; the one-release stagger is what makes this flip safe). The RECEIVE side still accepts BOTH generations this release; legacy envelope + !!checkpoint!! marker acceptance retires the release AFTER this one (needs one full release where no pre-flip resident can remain). [OK] REQ-WAKE-LEGACY-RETIRED required: [impl, unit, int] stages: -doc +impl +unit +int Stage 3 of the staged across/wake rename: the RECEIVE side accepts ONLY the new generation. The legacy `!!checkpoint!!` commune marker and the legacy `{"checkpoint":"v1","wake":…}` / `{"checkpoint_fire":"v1"}` envelope shapes are refused — a retired marker is ordinary text (it neither arms nor pairs, and a lone live marker beside it is still a single marker), and a retired envelope delivers as an ordinary message (no clear, no armed or drained wake). WHY NOW: REQ-WAKE-RENAME-STAGED shipped receive-both at v0.23.0 and REQ-WAKE-EMIT-FLIP flipped the emit at v0.24.0 with retirement promised for 'the release after'; it slipped forty releases. Retirement is safe because every hook that can meet this translate has emitted the new keys since v0.24.0 and both binaries ship in one adapter archive, and it is WANTED because agent-facing text stopped teaching `!!checkpoint!!` at v0.23.0, so the only remaining way that spelling reaches a commune is prose about Claude Code's own /checkpoint feature — a stale acceptance whose sole remaining effect is to arm a boundary nobody asked for (the class REQ-WAKE-MARKER-QUOTED narrowed for the live marker). [OK] REQ-WAKE-MARKER-QUOTED required: [impl, unit] stages: -doc +impl +unit -int A wake marker inside a code quotation is a QUOTATION, not a trigger — the rule claude-spt's shortform peer-tags already carry, applied to the wake convention the adapter owns end to end. Both wake helpers read a byte-length-preserving MASKED copy of the commune body in which fenced code blocks and inline code spans are blanked, so (a) a commune that merely quotes the marker (a release note, a plan, a message about this very defect) can no longer ARM a context reset its author never requested, and (b) a directive is paired from real markers only, never from two incidental mentions. Marker offsets still index the ORIGINAL body so the extracted directive keeps its verbatim text. Inline spans close on the SAME line only — deliberate: an unmatched stray backtick must never swallow the rest of the body and silently kill a live marker, because a dead boundary fails silently while a spurious mask is invisible. Failing toward arming is the safe direction. [OK] REQ-WAKE-RENAME-STAGED required: [impl, unit] stages: -doc +impl +unit -int The across/wake rename is STAGED so a cross-version boundary can never brick a live endpoint (the hook_cmd-LOCKSTEP degrade discipline applied to the wake pipeline): agent-facing verbiage hard-cuts to --across / 'commune across' / !!wake!! (the word 'checkpoint' is PURGED from agent-facing text — Claude Code ships an official /checkpoint skill that semantically collides), while the RECEIVE side accepts both marker generations (!!wake!! + legacy !!checkpoint!!, same-generation pairing only) and both envelope shapes ({"wake_arm"/"wake_fire"} + legacy {"checkpoint"/"checkpoint_fire"}), and the EMIT side keeps the LEGACY envelope keys for this one release — an un-bounced pre-rename resident translate receiving an unknown key would full-type raw JSON at a post-clear boundary. The emit flips to the wake keys next release. Findings: [must] misplaced_tag REQ-ALT-ACCOUNT-ROOTS criterion=tag-placement stage=unit tests/manifest-shortcut.sh:94 — unit tag attaches to `alt_spawn` at line 99, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-ALT-ACCOUNT-ROOTS criterion=tag-placement stage=impl tools/claude-spt/src/alt.rs:35 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-ALT-ACCOUNT-ROOTS criterion=tag-placement stage=impl tools/claude-spt/src/launch.rs:47 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-ALT-AUTO-INIT criterion=tag-placement stage=impl tools/claude-spt/src/alt.rs:35 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-ALT-AUTO-INIT criterion=tag-placement stage=impl tools/claude-spt/src/launch.rs:47 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-BRIEF-WORK-DISCIPLINE criterion=tag-placement stage=impl adapter/strings/briefs/work-discipline.md:17 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-CCS-PROFILES criterion=tag-placement stage=unit tests/manifest-shortcut.sh:107 — unit tag attaches to `ccs_spawn` at line 111, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-CI-GATES criterion=tag-placement stage=unit tests/ci-gates.sh:19 — unit tag attaches to `g` at line 20, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-CI-OWL-DISCOVERY criterion=tag-placement stage=unit tests/ci-gates.sh:8 — unit tag attaches to `realexe` at line 9, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-BINARY-CONSOLIDATE criterion=tag-placement stage=impl tools/claude-spt/src/post_update.rs:30 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-BOUNDARY-RENAME criterion=tag-placement stage=int ci/idle-translate/translate-proof-int.sh:172 — int tag attaches to `RN` at line 173, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-BOUNDARY-ROTATE criterion=tag-placement stage=int docs/KNOWN-HAZARDS.md:151 — int tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-DIST-BOUNDARY-ROTATE criterion=tag-placement stage=int docs/SPT-CORE-FINDINGS.md:1406 — int tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-DIST-CHECKPOINT-COMMUNE criterion=tag-placement stage=int ci/idle-translate/translate-proof-int.sh:114 — int tag attaches to `CKPT` at line 115, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-CHECKPOINT-COMMUNE criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:27 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-DIGEST-EXTRACTOR criterion=tag-placement stage=impl tools/claude-spt/src/digest.rs:48 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-HOOK-BINARY criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:10 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-HOOKS-API criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:26 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-IDLE-MULTILINE criterion=tag-placement stage=int ci/idle-translate/translate-proof-int.sh:93 — int tag attaches to `EVENT_FULL` at line 94, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-IDLE-MULTILINE criterion=tag-placement stage=int docs/plans/CORE-054-MIGRATION-PLAN.md:146 — int tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-DIST-IDLE-TRANSLATE criterion=tag-placement stage=unit tests/manifest-shortcut.sh:119 — unit tag attaches to `idle` at line 124, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-IDLE-TRANSLATE criterion=tag-placement stage=impl tools/claude-spt/src/translate.rs:87 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-MANIFEST-SCHEMA criterion=tag-placement stage=impl ci/manifest/validate_manifest.py:12 — impl tag is not attached to an evidence item: a function, type, or value declaration must start on this line or directly below it, separated only by blank, comment, or attribute lines [must] misplaced_tag REQ-DIST-MANIFEST-SCHEMA criterion=tag-placement stage=unit tests/manifest-schema.sh:5 — unit tag attaches to `ROOT` at line 6, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-PLUGIN-SKELETON criterion=tag-placement stage=unit tests/skeleton-validate.sh:5 — unit tag attaches to `ROOT` at line 6, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-PRETOOL-POLL criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:27 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-RC-STARTUP criterion=tag-placement stage=impl tools/claude-spt/src/launch.rs:37 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-RESUME-CONTEXT criterion=tag-placement stage=int ci/psyche-download/psyche-download-int.sh:73 — int tag attaches to `MARK` at line 74, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-RESUME-CONTEXT criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:27 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-SESSION-RESUME criterion=tag-placement stage=unit tests/manifest-shortcut.sh:40 — unit tag attaches to `resume` at line 45, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-SESSIONSTART-BRIEF criterion=tag-placement stage=unit tests/ring-perchless-only.sh:11 — unit tag attaches to `ROOT` at line 12, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-SESSIONSTART-BRIEF criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:26 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-SHORTCUT-BASENAME criterion=tag-placement stage=unit tests/manifest-shortcut.sh:7 — unit tag attaches to `ROOT` at line 8, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-DIST-SHORTCUT-BASENAME criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:28 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-SKELETON-THIN criterion=tag-placement stage=impl plugin/sptc/skills/knock/SKILL.md:29 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-DIST-SKELETON-THIN criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:28 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DIST-UPDATE-MESSAGE criterion=tag-placement stage=impl tools/claude-spt/src/post_update.rs:30 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-DOCS-DRIFT criterion=tag-placement stage=unit tests/docs-gen.sh:3 — unit tag attaches to `ROOT` at line 4, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-ADAPTER-EXEC-BIT criterion=tag-placement stage=unit tests/adapter-archive.sh:92 — unit tag attaches to `LONGLIST` at line 93, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-CHECKPOINT-CLEAR-RACE criterion=tag-placement stage=int ci/idle-translate/translate-proof-int.sh:114 — int tag attaches to `CKPT` at line 115, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-CHECKPOINT-CLEAR-RACE criterion=tag-placement stage=impl tools/claude-spt/src/translate.rs:29 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-HAZARD-CI-KILL-SCOPING criterion=tag-placement stage=unit tests/ci-kill-scoping.sh:7 — unit tag attaches to `ROOT` at line 8, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-INTERRUPT-STUCK-BUSY criterion=tag-placement stage=impl tools/claude-spt/src/interrupt_watch.rs:67 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-HAZARD-MSYS-PATHCONV criterion=tag-placement stage=unit tests/msys-hazard.sh:7 — unit tag attaches to `ROOT` at line 8, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-PERCH-COLLISION criterion=tag-placement stage=unit tests/acceptance-harness.sh:8 — unit tag attaches to `SPT_AGENT_ID` at line 10, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-PSYCHE-PERMS-DEADLOCK criterion=tag-placement stage=unit tests/manifest-shortcut.sh:25 — unit tag attaches to `spawn` at line 34, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HAZARD-RATE-LIMIT-STUCK-BUSY criterion=tag-placement stage=impl tools/claude-spt/src/interrupt_watch.rs:56 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-HAZARD-VERSION-GATE-FAIL-CLOSED criterion=tag-placement stage=unit tests/ci-gates.sh:69 — unit tag attaches to `INT` at line 72, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-HISTORY-FETCHER criterion=tag-placement stage=impl tools/claude-spt/src/history.rs:1 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-IO-COMPLIANCE-DECLARED criterion=tag-placement stage=impl tools/claude-spt/src/tag_scan.rs:13 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-LIVE-ANCHOR-WIN32 criterion=tag-placement stage=impl adapter/strings/skills/live-normal.md:12 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-PSYCHE-EPHEMERAL-SHIM criterion=tag-placement stage=impl tools/claude-spt/src/psyche.rs:16 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-RECHARGE-VOCABULARY criterion=tag-placement stage=impl adapter/strings/briefs/live-ops.md:52 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-RECHARGE-VOCABULARY criterion=tag-placement stage=impl adapter/strings/briefs/work-discipline.md:17 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-RECHARGE-VOCABULARY criterion=tag-placement stage=impl plugin/sptc/skills/commune/SKILL.md:15 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-SESSION-ECHO-COMMUNE criterion=tag-placement stage=impl tools/claude-spt/src/echo_commune.rs:2 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-SKILL-ARG-HINT criterion=tag-placement stage=impl plugin/sptc/skills/knock/SKILL.md:28 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-SKILL-ARG-HINT criterion=tag-placement stage=unit tests/skeleton-validate.sh:44 — unit tag attaches to `v2` at line 45, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-SKILL-ARG-HINT criterion=tag-placement stage=unit tests/skeleton-validate.sh:51 — unit tag attaches to `v3` at line 52, which is a value declaration; unit evidence must be a function, type, module, or block that can hold a test [must] misplaced_tag REQ-SKILL-KNOCK criterion=tag-placement stage=impl plugin/sptc/skills/knock/SKILL.md:25 — impl tag is in a Markdown file, which carries no code items; only doc and custom-stage evidence lives in prose [must] misplaced_tag REQ-SKILL-LIVE criterion=tag-placement stage=impl tools/claude-spt/src/psyche.rs:49 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-UPS-INJECTION criterion=tag-placement stage=impl tools/claude-spt/src/hook.rs:26 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-VERSION-SELF-REPORT criterion=tag-placement stage=impl tools/claude-spt/build.rs:19 — impl tag sits in the file's comment header, attached to no item; a module banner is not impl evidence (allow it with [placement].module_banner = "accept") [must] misplaced_tag REQ-WAKE-LEGACY-RETIRED criterion=tag-placement stage=int ci/idle-translate/translate-proof-int.sh:148 — int tag attaches to `LEGACY` at line 149, which is a value declaration; int evidence must be a function, type, module, or block that can hold a test note: 3 tag-carrying file(s) not placement-judged (no grammar for the language, or the parse recovered from errors)