Trail Model
Operator reference for the Phase 4 runtime consumption baseline.
Overview
Every standalone Spec Kitty dispatch leaves an auditable trail. The trail serves three purposes:
- Local accountability: operators can reconstruct what happened on any checkout without SaaS connectivity.
- SaaS coherence: the dashboard timeline shows the same history as the local audit log.
- Governance provenance: downstream retrospective and doctrine work can reference specific invocations.
minimal viable trail
One JSONL file per invocation, written locally before the executor returns.
Every spec-kitty dispatch "<request>" call writes a started event to:
kitty-ops/{invocation_id}.jsonl
When spec-kitty profile-invocation complete is called, a completed event is appended to the same file.
This is the unconditional minimum — it is always written, regardless of SaaS connectivity, charter state, or sync configuration. The data model is defined in src/specify_cli/invocation/record.py.
Mission-scoped dispatchers may also record mission_id, wp_id, and the
catalog-winning model_id on the started event. An implement or review claim
that supplies --invocation-id treats those values as a provenance assertion:
the requested ULID and the record's embedded ID, mission, WP, action, profile,
and model must agree exactly. Uncorrelated legacy records remain readable, but
cannot prove a resolved model actual for a claim.
Mode-of-Work Taxonomy
Every invocation belongs to one of four work modes. The mode determines which optional trail tiers are eligible — it does not override the mandatory Tier 1 rule.
| Mode | Description | Example actions | Tier 2 eligible | Tier 3 eligible |
|---|---|---|---|---|
task_execution |
Standalone governed work, including advice, review, code changes, and test runs | dispatch |
Yes (caller-triggered) | No |
mission_step |
One step in a governed mission workflow | specify, plan, tasks, merge, accept |
Yes (caller-triggered) | Yes |
query |
Read-only, no execution | profiles list, invocations list |
No | No |
Mode-of-work is recorded on the started event as the mode_of_work field. New standalone dispatch records use task_execution. Runtime enforcement is active: profile-invocation complete --evidence is rejected for records that are not evidence-eligible (see "Mode Enforcement at Tier 2 Promotion" below).
Mode Enforcement at Tier 2 Promotion
spec-kitty profile-invocation complete --evidence <path> is rejected with InvalidModeForEvidenceError when the target invocation is not evidence-eligible. The enforcement runs before any write, so the invocation remains open and uncommitted — rerun complete without --evidence to close cleanly.
Pre-mission records (invocations opened before this enforcement landed) have no mode_of_work field and are accepted by enforcement — legacy behaviour is preserved. See ADR-002-mode-derivation.md for the full derivation table and rationale.
Trail Tiers
Tier 1 — Every Invocation (mandatory)
Written unconditionally before the executor returns.
- Storage:
kitty-ops/{invocation_id}.jsonl - Content: Two JSONL lines — a
startedevent and (after completion) acompletedevent. - When: All standalone
dispatchinvocations.
Glossary Check Event (conditional, Tier 1)
When the invocation executor's glossary chokepoint scan detects at least one
conflict — or encounters an error — it appends a glossary_checked event to the
same Tier 1 JSONL file, immediately after the started event.
Written ONLY when:
all_conflictsis non-empty (one or more semantic conflicts detected), ORerror_msgis non-null (the chokepoint scan encountered an unexpected exception).
Clean invocations produce NO glossary_checked line. This keeps Tier 1
files minimal when there are no glossary issues to report.
Example glossary_checked event line:
{"event": "glossary_checked", "invocation_id": "01HXYZ...", "matched_urns": ["glossary:d93244e7"], "high_severity": [{"term": "lane", "conflict_type": "ambiguous_scope", "severity": "HIGH", "candidate_senses": ["execution lane (WP routing)", "git branch lane (worktree)"]}], "all_conflicts": [...], "tokens_checked": 8, "duration_ms": 2.7, "error_msg": null}
Readers that encounter "event": "glossary_checked" and do not recognise this
event type may safely skip the line — it is additive metadata and never affects
the started/completed pair.
Correlation Links (Tier 1 extension)
spec-kitty profile-invocation complete accepts two additional flags that append correlation events to the invocation JSONL:
--artifact <path>— repeatable. Each value appends one{event: "artifact_link", invocation_id, kind, ref, at}line tokitty-ops/<id>.jsonl. Refs are stored repo-relative when the resolved path is under the checkout, absolute otherwise.--commit <sha>— singular. Appends one{event: "commit_link", invocation_id, sha, at}line.
Both events are append-only (never mutate existing lines) and readable by a single-file scan. Readers that do not recognise these event types may safely skip the line — the same additive-reader invariant that protects glossary_checked.
SaaS projection status (3.2.x): Correlation events are local-only in the 3.2.x line. The projection policy (POLICY_TABLE in src/specify_cli/invocation/projection_policy.py) assigns project=True for task_execution / mission_step correlation events, but the dict-record submission path in _propagate_one is not yet wired. SaaS projection of correlation events will land in a future release consistent with the ADR-004 local-only stance for Tier 2 content.
See ADR-001-correlation-contract.md for the design; contracts/profile-invocation-complete.md for the CLI shape.
Tier 2 — Evidence Artifact (optional, caller-triggered)
Created when the caller explicitly flags that the invocation produced checkable output.
- Trigger: Caller sets
--evidence <path>onspec-kitty profile-invocation complete. - Storage:
.kittify/evidence/{invocation_id}/evidence.mdand.kittify/evidence/{invocation_id}/record.json - When:
task_executionandmission_stepmodes only.
Tier 3 — Durable Project State (optional, action-driven)
Promotion to kitty-specs/ or doctrine artifacts only when the invocation changes project-domain state.
- Trigger: Action is in
TIER_3_ACTIONS—{specify, plan, tasks, merge, accept}. - Storage:
kitty-specs/{mission_slug}/— existing spec/plan/tasks/status files. - When:
mission_stepmode only.
Promotion Rules
Tier 1 always written
|
+-- If caller sets evidence_ref --> Tier 2 artifact created
|
+-- If action in TIER_3_ACTIONS --> Tier 3 artifacts produced by workflow
SaaS Read-Model Policy
Projection is conditional on CheckoutSyncRouting.effective_sync_enabled. When sync is disabled for a checkout, no events are emitted — even if the user is authenticated. When sync is enabled and the user is authenticated, Spec Kitty consults src/specify_cli/invocation/projection_policy.py::POLICY_TABLE to decide per (mode_of_work, event) what to project.
| mode_of_work | event | project | include_request_text | include_evidence_ref |
|---|---|---|---|---|
| task_execution | started | yes | yes | no |
| task_execution | completed | yes | yes | yes |
| task_execution | artifact_link | yes | no | no |
| task_execution | commit_link | yes | no | no |
| mission_step | started | yes | yes | no |
| mission_step | completed | yes | yes | yes |
| mission_step | artifact_link | yes | no | no |
| mission_step | commit_link | yes | no | no |
| query | any | no | — | — |
Pre-mission records (no mode_of_work) project under the task_execution rules — the legacy 3.2.0a5 behaviour is preserved for them.
Policy is additive and resolvable from code/config alone. See ADR-003-projection-policy.md for the rationale.
Projection is additive. Events accumulate; there is no deletion, replay-based overwrite, or idempotency-key gating in 3.2.
Tier 2 SaaS Projection — Deferred
Status: Tier 2 evidence artifacts (.kittify/evidence/<invocation_id>/evidence.md and record.json) are local-only in the 3.2.x release line. They are not uploaded to SaaS. This decision was finalised by the Phase 4 closeout mission (ADR-004-tier2-saas-deferral.md).
Reasoning:
- The shipped 3.2.0a5 baseline already behaves this way; operators observing the product today see local-only evidence.
- SaaS projection of evidence bodies requires privacy, redaction, and size-limit design that lies outside the Phase 4 closeout scope.
- Future projection remains possible without contract change — a later epic can read the existing local artifact and emit its own envelope.
Revisit trigger: any of (a) a named future epic accepts SaaS evidence projection as scope, (b) operators actively request the feature with a concrete use case, (c) a regulatory or audit requirement mandates centralised retention.
Retention and Redaction
| Field | Treatment |
|---|---|
request_text |
Retained as-written in local JSONL. No automatic redaction in 3.2. |
governance_context_hash |
First 16 hex chars of SHA-256 only. Full governance context is never persisted. |
| JSONL files | Persist indefinitely unless the operator purges kitty-ops/. |
| SaaS propagation | Additive. No delete-on-disable in 3.2. |
Propagation failures are written to kitty-ops/propagation-errors.jsonl and never affect the CLI exit code.
spec-kitty intake — Not a Profile Invocation
spec-kitty intake ingests a plan document into .kittify/mission-brief.md for use by /spec-kitty.specify brief-intake mode. It is not a standalone Op and produces no InvocationRecord. The governed trail begins when the host calls spec-kitty dispatch "<request>" — not when the user stages a brief.
Host surfaces that teach the trail
The standalone dispatch surface is taught to host LLMs through per-host skill packs. See docs/host-surface-parity.md for the authoritative matrix of supported hosts and each host's parity status.
spec-kitty explain — Deferred to Phase 5
spec-kitty explain (issue #534) is not part of this release. It requires Phase 5 DRG glossary addressability to produce fully-cited answers. A partial implementation without glossary citations would be misleading.