@gobing-ai/spur 0.3.76 → 0.3.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -43,22 +43,91 @@ command, skill, script, or second workflow.
43
43
 
44
44
  ## Run setup
45
45
 
46
- 1. Resolve the command inputs, `--auto`, and any explicit `--vars`; read the selected YAML and overlay
47
- its `vars` defaults with those invocation values. An explicit non-inline executor selection
48
- chooses the subprocess workflow path.
46
+ **Shared startup contract (task 0814 R1/R3/R4/R6/R7).** The order is load-bearing: publish a compact
47
+ **bootstrap checklist** immediately (host-preparation rows, never copied workflow states); run quick
48
+ deterministic readiness (admission, not an implementation certificate) before any isolation; when
49
+ `--worktree` is valid, create/adopt and switch to the execution tree; then publish the **workflow
50
+ inventory** (the CLI todo projection) — and only then read the full YAML for comprehensive/model work.
51
+ Comprehensive checks stay at their owning boundaries and run after the plan is visible and after
52
+ isolation when requested (R7); quick readiness and plan projection dispatch zero models and execute
53
+ zero workflow actions (R8). Use the stable label helpers
54
+ (`columnLabel` / `buildStepLabels` / `labelChild` in `packages/app/src/workflow/step-reporter.ts`) for
55
+ the human/native presentation layer — labels are display addresses only, never an execution key.
56
+
57
+ 1. Resolve the command inputs, `--auto`, and any explicit `--vars` — **without reading the selected
58
+ YAML yet**. An explicit non-inline executor selection chooses the subprocess workflow path.
49
59
  2. Allocate a collision-resistant inline run id (`uuidgen`, with a timestamp/pid fallback), create
50
60
  `.spur/run/`, and use `.spur/run/<run-id>.log` as the run log.
51
- 3. Resolve the host session id from `.spur/context/.session.json`, accepting the normalized hook key
61
+ 3. **Authoritative run identity (task 0804 R1, fail-closed).** Persist the run row through the
62
+ internal delegate before any stage executes — this is what makes bound `run.artifact` record
63
+ accept the inline run (0785 R3):
64
+
65
+ ```bash
66
+ SETUP_SCRIPT="plugins/sp/scripts/inline-run-setup.ts";
67
+ [ -f "$SETUP_SCRIPT" ] || SETUP_SCRIPT="$(superskill script path sp inline-run-setup.ts 2>/dev/null)";
68
+ [ -n "$SETUP_SCRIPT" ] && [ -f "$SETUP_SCRIPT" ] && \
69
+ bun "$SETUP_SCRIPT" --run-id "$RUN_ID" --file <selected-pipeline-yaml> \
70
+ || { echo "inline run setup failed closed — checker not found; run 'superskill install sp'" >&2; exit 1; }
71
+ ```
72
+
73
+ The delegate resolves the app service from the SPUR_BIN chain, creates-or-attaches the row,
74
+ and writes `.spur/run/<run-id>-inline-setup.json`. Seed `__runId` and `__definitionDigest`
75
+ from that file so proof capture and bound registration verify against the persisted identity.
76
+ A non-zero exit (missing row identity, changed definition, bundle-only install) stops the run —
77
+ never continue unbound and never fabricate a PASS. (The delegate persists the authoritative
78
+ RUN row only — the 0808 inline record is the registration-equivalent convention below, not a
79
+ setup-time artifact-ledger insert.)
80
+
81
+ **Frozen invocation identity (task 0809 R4).** The definition parsed and hashed at setup is
82
+ the definition for the ENTIRE run: keep one invocation-time parsed definition and never
83
+ re-resolve or reseed `__definitionDigest` at record because a workflow YAML changed. Two
84
+ digests serve different purposes: `proof.digest` is the freshly captured current-input
85
+ fingerprint; `proof.definitionDigest` identifies the workflow actually interpreted (the setup
86
+ identity). A source-only edit of a TRACKED workflow YAML before capture is part of current
87
+ input proof — the Git fingerprint covers tracked working-tree files, and ignored/external
88
+ workflow files are NOT part of it (their executed identity remains the setup digest).
89
+ Post-capture changes to fingerprinted inputs invalidate that proof and take the normal
90
+ certification loop — stale post-capture evidence is refused, never reconciled. If execution
91
+ must switch to a different definition, or the executed identity cannot be established: stop
92
+ before record, preserve the run log and evidence, and start a FRESH inline run with a fresh
93
+ run id and fresh gate/review/verify certification. Never mutate old run/proof identities,
94
+ manufacture a paused engine snapshot, or call `continuePaused` for a running inline row;
95
+ task text, Git attribution and `--auto` are not consent to stamp `resumeDefinitionDigest` —
96
+ explicit consent for actual paused engine runs stays owned by task 0784.
97
+ 4. Resolve the host session id from `.spur/context/.session.json`, accepting the normalized hook key
52
98
  `session` and the Codex key `session_id` (in that order). If neither is available, allocate
53
99
  `host-session-<run-id>` and record that fallback in the log; provenance must never be blank or
54
100
  guessed from an executor subprocess.
55
- 4. Render the two-layer plan into the host todo list (task 0596):
56
- - **Layer 1** = `spur workflow show <pipeline-yaml> --format todo --json` its `steps[]`: the
57
- declared state inventory in declaration order with `initial` / `terminal` / `failure` /
58
- `pause` / `loopBack` / `conditional` markers. Mark the active state. Never re-derive this
59
- list from the YAML.
101
+ 5. **Publish the bootstrap checklist (R1).** Render host-preparation rows into the host todo list
102
+ before any expensive check: `A, Quick readiness`, `B, Prepare Git`, `C, Publish workflow plan`,
103
+ `D, Comprehensive checking`. These are host preparation, never copied workflow states; they are
104
+ not silently reassigned to unrelated workflow states when the workflow view later appears.
105
+ 6. **Quick deterministic readiness (R2), before isolation.** Evaluate `quickReadiness` from
106
+ `plugins/sp/scripts/batch-preflight.ts` with the operation, status, filtered-set size, the
107
+ matrix-selected required/present sections, and content-policy findings. Record the outcome
108
+ (runnable / needs-refinement / blocked / skipped / invalid) in the run log. Admission decision
109
+ only — no model, no full tests/lint, no live-data probe, no feature mutation, no corpus-wide
110
+ relational check.
111
+ 7. **Isolation (R3), only when `--worktree` is valid.** After quick readiness and the required Git
112
+ safety checks succeed, create/adopt and `cd` into the execution tree; confirm absolute cwd,
113
+ branch, base SHA, and ownership. An invalid/empty target, unsupported mode, ambiguous ownership,
114
+ or stale target stops without creating a tree or discarding work. All subsequent tools, agents,
115
+ corpus writes, and run artifacts use the confirmed execution tree.
116
+ 8. **Publish the workflow inventory (R4), BEFORE reading the YAML.** Resolve the selected workflow
117
+ through the same project/bundled resolver as execution and run
118
+ `spur workflow show <resolved-file> --no-logo --format todo --json`. Validate the projection with
119
+ `parseWorkflowInventory` and bind it to the run's persisted `__definitionDigest` with
120
+ `assertInventoryIdentity` — a drift or projection failure stops the run before any
121
+ comprehensive/model work, never executing with a misleading plan.
122
+ - **Layer 1** = that projection's `steps[]`: the declared state inventory in declaration order
123
+ with `initial` / `terminal` / `failure` / `pause` / `loopBack` / `conditional` markers. Mark
124
+ the active state. Never re-derive this list from the YAML.
125
+ 9. **Read the selected YAML and overlay its `vars` defaults** with the invocation values. Compare the
126
+ resolved definition identity against the bound `__definitionDigest`; a mismatch is identity drift
127
+ and fails closed (step 8 already caught projection-side drift; this re-checks the same definition
128
+ the interpreter will execute).
60
129
  - **Layer 2** = the active state's `onEnter` actions (`kind` + resolved `input`/`command`), from
61
- the YAML parsed in step 1, shown only for the active state.
130
+ the YAML read here, shown only for the active state.
62
131
  - **Refresh cadence** = stage boundaries only (when the current state changes after a transition),
63
132
  never per action.
64
133
  - **Transition reconciliation (task 0727)** = at every stage boundary the host must
@@ -67,9 +136,18 @@ command, skill, script, or second workflow.
67
136
  whether the stage ran via native subagent, host-inline execution, or the post-dispatch host
68
137
  fallback, so a run can never terminate with earlier stages stuck `in_progress` (task 0726
69
138
  ended 0/11 with precheck and implement still open).
70
- - **Source of truth** = the CLI projection for layer 1; the YAML parsed in step 1 for layer 2.
139
+ - **Source of truth** = the CLI projection for layer 1; the YAML read here for layer 2.
71
140
  Never hand-copy or hand-derive the state list into the driver, a command, a skill, or a script.
72
- 5. For task execution only, record lifecycle provenance before entering the FSM:
141
+ - **Stable labels (task 0814 R5).** Top-level declaration indexes map to A, B, Z, AA, AB …;
142
+ visible children restart numbering under their parent (A1, A2, B1 …). Labels never replace the
143
+ canonical step id, and are re-derived identically on retry/resume against the same definition.
144
+ - **Truthful progress (task 0814 R6).** Publish pending/active state before the visible item
145
+ starts, then update it immediately after the observed item completes and before the next item
146
+ starts. Keep completed, skipped, failed, blocked, paused, and unattempted outcomes distinct;
147
+ never mark skipped/conditional work completed merely to clear the UI. If the host has no
148
+ suitable native todo tool, or it fails, use an explicit Markdown fallback with the same labels
149
+ and truth — never a fabricated successful tool invocation.
150
+ 10. For task execution only, record lifecycle provenance before entering the FSM:
73
151
 
74
152
  ```bash
75
153
  spur task run-link <wbs> --source inline-full --run-id <run-id> --json
@@ -78,6 +156,28 @@ command, skill, script, or second workflow.
78
156
  This is required for the normal `testing → done` provenance guard. Planning pipelines have no
79
157
  task lifecycle link and skip this task-specific action.
80
158
 
159
+ ## Comprehensive-check retention and evidence (R7/R8)
160
+
161
+ **R7 — comprehensive checks stay at their owning boundaries.** Quick readiness and plan projection are
162
+ admission and visibility, not a substitute for the owning gates. After the plan is visible and after
163
+ isolation when requested, retain the full task/feature integrity, size, evidence-channel,
164
+ provenance, capability, dependency, quality, review, and verification gates exactly where their
165
+ owners declare them. Prefer deterministic checks; invoke semantic model work only for an identified
166
+ unresolved requirement/design/evidence question and record its reason in the run log. Reuse a
167
+ cached observation only while its relevant inputs (task content, effective status, matrix, dependency
168
+ snapshot, cwd) remain unchanged; refresh after branch/tree changes, task writes, dependency
169
+ completion, or resume. Never run a shadow copy of a workflow precheck state in the host — if a
170
+ workflow defines a precheck state, its result updates that state, not a host-side duplicate.
171
+
172
+ **R8 — matched before/after evidence, no invented claims.** Record a timestamped event trace under
173
+ `.spur/run/<run-id>-event-trace.md` (render via `renderEventTrace` in
174
+ `packages/app/src/workflow/workflow-inventory.ts`) naming event ordering, time-to-first-visible
175
+ checklist, time-to-workflow-inventory, confirmed execution cwd, and CLI/process/model invocation
176
+ counts. Quick readiness and plan projection must dispatch zero models and execute zero workflow
177
+ actions — record that as observed. Record unavailable measurements as `unknown`; never present a
178
+ simulated run as a real verified outcome. Event order and provenance are evidence; wall-clock/token
179
+ savings are observations, never fabricated pass conditions.
180
+
81
181
  ## YAML interpreter
82
182
 
83
183
  Start at `initialState`. For each current state, execute its `onEnter` actions in declaration order,
@@ -101,6 +201,22 @@ Action semantics come from the YAML and the workflow action contract:
101
201
  `answerFile`; assert `expectFile`; enforce `requireDiff` against a pre-action git snapshot,
102
202
  including the task-scope guard; honor declared error policy. `timeoutMs` is recorded as not
103
203
  applicable because the host session has no independent kill boundary.
204
+ - `run.artifact` — the engine's ledger registration has **no inline execution surface** (0808 R4).
205
+ The inline equivalent is a documented **registration-equivalent convention**: before the record
206
+ state mutates the task, the host validates the same refusal conditions inline — the declared
207
+ artifact exists at the resolved path and is canonical-valid for the run's wbs (for
208
+ `verify-verdict`: verdict `PASS`), `proofBinding: current` is honored against a freshly captured
209
+ proof digest, and the run-scoped review-completion marker exists — then appends one provenance
210
+ line to `.spur/run/<run-id>.log` naming the equivalence (artifact kind, path, verdict, digest) and
211
+ proceeds to `spur task record`. A failed validation stops at the state and follows the failure
212
+ contract; the step is never silently skipped. Artifact-provenance consumers read that run-log
213
+ line on the inline path — there is no ledger row. The validation also includes **run/definition
214
+ identity agreement from authoritative evidence** (task 0809 R4): the verdict's `proof.runId` and
215
+ `proof.definitionDigest` must agree with the setup artifact `.spur/run/<run-id>-inline-setup.json`
216
+ and the persisted run row; if that identity is absent or conflicts, STOP — recreating a row is
217
+ not a diagnostic operation. The app-service bound-artifact fixture (which writes a real engine
218
+ ledger row) is service-level test evidence for this identity mechanics, not evidence that the
219
+ inline host writes a ledger.
104
220
 
105
221
  **Native-subagent dispatch (R2 eligibility, evaluated before each action):**
106
222
 
@@ -204,10 +320,11 @@ tasks (0617, 0619) because the sections were hand-written **before** the verdict
204
320
  and `L3.required-section-placeholder` before the transition, not after.
205
321
  3. **Solution change-map anchor rule (L4.anchor-subject-mismatch).** A Solution change-map table must
206
322
  list **one `file:line` per row**. A ·-joined paragraph makes every anchor's "subject" the other
207
- anchors and trips the L4 subject check. Paths containing `_` (e.g. `docs/help/cmd_*.md`,
208
- `spur-cli-matrix.md`) can **never** match their cited line the snake_case filename token is
209
- extracted as the subject and cannot appear in the line content so drop those rows from the table
210
- (prose still covers them).
323
+ anchors and trips the L4 subject check. Since 0804 R9, subject extraction ignores complete parsed
324
+ citation spans, so a path's underscores no longer manufacture a subject: an underscore path row
325
+ (`docs/help/cmd_example.md:12`) is checked exactly like any other rowcite an **existing file**
326
+ with a **valid line or line range** whose content names the requirement's subject. A real absent
327
+ symbol, nonexistent file or invalid range still reports; never replace a citable row with prose.
211
328
 
212
329
  ## Failure contract
213
330