# The change workflow

**Non-normative.** This document describes how the deterministic commands
specified in [SPEC.md](./SPEC.md) and [SPEC-CHANGE.md](./SPEC-CHANGE.md)
are intended to be driven by a calling agent or workflow engine. Nothing
here adds behavior to the tool; where this document and the specs
disagree, the specs win.

The caller is deliberately unspecified: every step below needs only a
shell and the `traceable-reqs` CLI, so the loop can be driven by any
workflow engine, a CI job, an ad-hoc agent, or a human at a terminal.
No orchestrator is a dependency of this tool — engines that ship a
canonical encoding of this loop (e.g. Attractor's
`traceable-change-loop` workflow) are downstream consumers, never
requirements.

## The division of labor

The tool is the deterministic oracle; the caller supplies every step
that requires judgment. The determinism contract in SPEC-CHANGE.md is
the admission test: if a step's output can differ between two runs on
identical inputs, it runs *outside* the tool and its results re-enter
only through defined interfaces (tags in source, manifest entries, or
`annotations` with `"basis": "inference"`).

| Step | Nature | Owner | Interface back into the tool |
|------|--------|-------|------------------------------|
| 1. Resolve intent | judgment | agent / human | requirement IDs passed to `change compile` |
| 2. Compile context | deterministic | tool | the Change Contract document |
| 3. Implement | judgment | agent | edits + `[stage->REQ-ID]` tags in source |
| 4. Verify (mechanical half) | deterministic | tool | re-run `change compile` + `check`; diff contracts |
| 5. Verify (semantic half) | judgment | agent | `annotations` entries with `basis: "inference"` |
| 6. Audit spec quality | judgment, periodic | orchestrator | manifest edits + new evidence, then re-run `check` |

## The loop, step by step

### 1. Resolve intent (agent)

Map the natural-language task to declared requirement IDs, using
`list --json` (optionally `list --type`, `lint`) to browse candidates.
Rules of engagement:

- Never invent an ID. Tags never create requirements; neither do agents.
- If no declared requirement covers the task, **stop** — the manifest is
  the contract, so the missing requirement is added (with human
  approval) before any code is written.
- When resolution is ambiguous, surface the candidate IDs and titles to
  the human rather than guessing.

### 2. Compile the contract (tool, deterministic)

```text
traceable-reqs change compile <REQ-ID>... --json
```

The contract is the task's context package. The agent starts from it
instead of exploring the repository:

- `contextFiles` is the reading list — including every co-located tag,
  so obligations belonging to *other* requirements in those files are
  visible before editing.
- `related` is the do-not-break list: requirements sharing evidence
  files with the targets.
- `obligations` is the definition of done: every entry must be
  satisfied when the work is finished.
- Non-empty scan-health `findings` mean the evidence graph itself is
  suspect; fix those before trusting the rest of the contract.

### 3. Implement (agent)

Make the change. New requirement-bearing code carries tags; evidence
that moves keeps its tags with it. The contract's obligations say which
stages need evidence — an `impl` edit without its matching `unit` (or
`int`) evidence leaves an obligation unsatisfied and step 4 will say so.

### 4. Verify, mechanical half (tool, deterministic)

Re-run `change compile` with the same IDs and diff against the
pre-change contract, then run `check`:

- Every obligation `satisfied` — including ones the change was supposed
  to close.
- No new `missing_stage` on targets; no new scan-health findings.
- Changes to evidence in files listed under `related` requirements are
  the deterministic early-warning for undeclared impact: if the diff
  touched lines carrying another requirement's tags, that requirement
  was affected without being declared a target. Escalate it — either it
  becomes a target (rerun from step 2) or the edit is reworked.

`check` remains the merge gate; the contract diff is the change-scoped
lens over the same facts.

**The promotion move.** Whenever anything — the deterministic diff
check above, or an agent threading the call graph in step 5 —
suspects an undeclared requirement is affected, the response is the
same: add that requirement to the target set and recompile from
step 2. Promotion is how a best-effort hunch is upgraded into facts:
the suspected requirement's obligations, evidence, and context files
enter the contract as graph facts, and this step's mechanical verify
now holds the change to them. A suspicion that stays a suspicion is
recorded as an inference annotation; a suspicion worth acting on
becomes a target. The cost of promoting wrongly is bounded — one
requirement verified unnecessarily — so when in doubt, promote.

### 5. Verify, semantic half (agent)

Judgment questions — "was the co-located behavior actually preserved?",
"does the new test really pin the requested behavior?" — are answered by
an agent reading the code, in the spirit of the kernel's `lint`/`review`
prompts. Its conclusions are appended to the contract as `annotations`
entries carrying `"basis": "inference"` and a `message`. They never
overwrite core sections: a consumer can always separate graph facts
(no `basis` field) from judgments.

When this pass surfaces a likely-affected requirement rather than a
mere observation, don't leave it as an annotation — use the promotion
move (step 4) so the deterministic tool takes over checking it.

### 6. Audit spec quality (orchestrator, periodic)

Requirement mutation testing — perturb a requirement, ask whether any
test or lint notices — is an orchestration workflow that *calls* this
tool, not a feature of it. Its deterministic kernel (apply a structural
manifest mutation, re-run `check`, require the findings to change,
else the trace is vacuous) may join the `change` subsystem later;
generating semantic mutations and judging test discrimination stay with
the orchestrator's agents. Run it as a scheduled audit over
high-priority requirements, not as a per-commit gate.

## The resolution ladder

Every impact claim in this system stands on one of four rungs. The
ladder trades soundness for reach as it descends; the tool's job is to
make sure each claim wears its rung, and the promotion move exists so
any claim from any rung can be escalated into obligations the top rung
enforces.

| Rung | Source | Guarantee | Label in output |
|------|--------|-----------|-----------------|
| 1. Tags | `[stage->REQ-ID]` in scanned files | sound: the evidence exists at that line | none (graph fact) |
| 2. Syntactic | tree-sitter enclosing symbols (shipped: `enclosingSymbol` on context tags for Rust/Python) | deterministic given a pinned grammar; names, not resolved references | `resolution: "syntactic"` |
| 3. Semantic | caller-supplied compiler index (SCIP or similar), declared in the manifest | resolved references; reproducible given the toolchain and lockfile that built the index | `resolution: "semantic"` |
| 4. Inference | agent judgment (call-graph threading, behavior reasoning) | best effort | `basis: "inference"` |

Rules of the ladder:

- **The tool computes rungs 1–2 and consumes rung 3; it never produces
  rung 3 or 4.** Building a semantic index requires a toolchain and a
  build environment — orchestrator work (for example, a workflow node
  that runs `rust-analyzer scip .` after a green build and commits or
  caches the artifact). The manifest declares where the artifact lives,
  making it an explicit, diffable input like a signoff URL.
- **Provenance is recorded, never assumed.** A contract enriched from a
  semantic index carries the index's generating tool, version, and
  content hash, so consumers know exactly what those edges stand on and
  can detect staleness against the tree.
- **Degradation is graceful and downward.** No index, or a stale one,
  means falling back to rung 1's file-level `related` net — coarse but
  sound. Nothing on a lower rung is ever silently presented as a
  higher one.
- **Even rung 3 is not rung 1.** Compiler-grade indexes under-
  approximate dynamic dispatch, reflection, and duck typing. Semantic
  edges are strong evidence, not proof — which is why the promotion
  move, not the index, is what turns suspicion into obligation.

## Failure modes this structure prevents

- **Context wandering:** the agent starts from a compiled contract, not
  a repository crawl, so its inputs are reproducible and reviewable.
- **Laundered judgment:** a model's "looks preserved to me" can never
  appear as a graph fact — the `basis` field is structural, not
  stylistic.
- **Silent scope creep in the tool:** any proposed `change` feature
  that fails the determinism contract already has a designated home
  outside the tool (SPEC-CHANGE.md, "Out of scope, and where it goes
  instead"). The answer to "can the tool just call the model?" is
  permanently no.
