# JIT plan — clear the 64 `misplaced_tag` findings (traceable-reqs 0.4.1)

## Scope

`sh ci/run-gates.sh` is RED. Cause is traceable-reqs 0.4.1's new `tag-placement` criterion,
which judges whether a tag is attached to a real evidence item. 64 findings, all pre-existing
(measured identical at `619911c` and at HEAD) and unrelated to #300. Tests themselves pass —
568 rust tests green. This is placement only.

Gate: `sh ci/run-gates.sh` PASS and `traceable-reqs check` exit 0.

## What the tool actually accepts (measured, not assumed)

Probed the 0.4.1 binary and confirmed empirically on `tests/ci-gates.sh`:

- `[placement]` has exactly two knobs: `enforce = "on"|"off"` and
  `module_banner = "reject"|"accept"`. There is **no** per-class opt-out for the other classes.
- A shell **function** IS an accepted evidence item. A bare `{ ... }` compound group is NOT
  (the finding changes from "attaches to a value declaration" to "not attached to an evidence
  item", so the group is seen and rejected). Measured, both directions.
- Prose is legal for `doc` and for **declared custom stages** — the tool's own message says so.
- Custom stages (`[stages.<name>]`) and `[[signoffs]]` are core capabilities in this version.

## Decisions, per class

### A — impl tag in a module comment banner (27 findings, Rust + 1 Python)

**Do NOT set `module_banner = "accept"`.** AGENTS.md rule 1 is binding and explicit: tag "on or
immediately above the real evidence — never at file tops to satisfy coverage." Accepting module
banners would sanction in config exactly what our own contract forbids.

26 of the 27 reqs already carry in-body impl evidence elsewhere → **delete the banner tag, keep
the prose.** The explanation stays where it reads well; the evidence claim moves off the banner.

`REQ-DIST-DIGEST-EXTRACTOR` (`digest.rs:48`) is the sole exception — the banner is its only `.rs`
impl tag → **move it onto the real item.** Same treatment for
`ci/manifest/validate_manifest.py:12`, where the tag sits in the module docstring.

### B — unit/int tag on a value declaration in a shell test (23 sites)

The tag sits above a comment block introducing an assertion group whose first line happens to be
a variable assignment. The real evidence is the assertion group.

**Wrap each tagged assertion group in a named shell function and call it.** Verified
behaviour-preserving on `tests/ci-gates.sh`: `sh -n` clean, output byte-identical against the
pre-edit baseline, rc 0 both. POSIX `sh` functions share the caller's variables, so `fail=1`
still propagates.

### C1 — impl tag in shipped prose (7 findings)

`adapter/strings/**` and `plugin/sptc/skills/**` are the shipped product artifact: for these
requirements the **text itself is the implementation**. All 7 reqs do also carry code-side impl
evidence, so deleting the prose tags would keep the gate green — and would be the wrong fix: it
would drop the trace from the requirement to the artifact that actually satisfies it.

**Declare a custom stage for shipped prose and retag these sites.** This is the route the tool
itself names for prose, and it preserves traceability instead of discarding it.

### C2 — int tag in Markdown (3 findings)

Two are **not evidence claims at all** — they are backticked prose *mentions* of a tag
(`KNOWN-HAZARDS.md:151`, `docs/plans/CORE-054-MIGRATION-PLAN.md:146`). The scanner does not honor
backticks, so prose discussing a tag mints false evidence. **De-fang them** the way AGENTS.md
already de-fangs its own illustrations (angle-bracket the stage word).

The third (`docs/SPT-CORE-FINDINGS.md:1406`) is a deliberate record of an operator-run live E2E
(doyle verdict E2E-0104) and is `REQ-DIST-BOUNDARY-ROTATE`'s only `int` evidence. The manifest's
own note already concedes it is "not scriptable in CI — needs a real spt-hosted CC issuing
/clear". Calling that `int` overstates what it is. **Declare a custom stage for operator-run live
integration, retag the record, and swap that requirement's `int` for it** — a verdict may not
assert more than it measured, and this makes the stage name match the evidence.

## Tasks

1. Class A — delete 26 banner tags; move 2 (digest.rs, validate_manifest.py) onto real items.
2. Class B — function-wrap 23 assertion groups across `tests/` and `ci/`; diff each script's
   output against its pre-edit baseline, not just `sh -n`.
3. Class C1 — declare the shipped-prose custom stage in `traceable-reqs.toml`; retag 7 sites.
4. Class C2 — de-fang 2 prose mentions; declare the live-E2E stage, retag 1 record, swap
   `REQ-DIST-BOUNDARY-ROTATE`'s required stage.
5. Record both new stages in `docs/TRACEABILITY.md` (the contract doc) — what each means and
   when to use it, so the next agent does not re-derive this.
6. Gate: `traceable-reqs check` exit 0 + `sh ci/run-gates.sh` PASS.

## Open

None blocking. The two new stage names are mine to choose; everything else is determined by the
tool's measured behaviour and by AGENTS.md rule 1.
