@gobing-ai/spur 0.3.99 → 0.4.1
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/config.global.yaml +17 -0
- package/config/decisions/gates.yaml +36 -0
- package/config/decisions/history-anatomy.yaml +35 -0
- package/config/decisions/idea-pipeline.yaml +38 -0
- package/config/decisions/task-pipeline.yaml +55 -0
- package/config/plugin-scripts.json +25 -0
- package/config/rules/boundary/sp-runtime-path.yaml +2 -0
- package/config/rules/docs/sourced-api-claims.yaml +60 -0
- package/config/rules/quality/coverage-gate.yaml +5 -3
- package/config/rules/recommended-pre-check.yaml +8 -3
- package/config/rules/strict/runtime-boundaries.yaml +11 -0
- package/config/rules/structure/protected-files.yaml +3 -0
- package/config/rules/structure/scratch-evidence-pointer.yaml +35 -0
- package/config/script-placement-baseline.json +2 -2
- package/config/workflows/feature-lifecycle.yaml +9 -2
- package/config/workflows/history-anatomy.yaml +22 -0
- package/config/workflows/idea-pipeline.yaml +75 -0
- package/config/workflows/task-pipeline.yaml +368 -49
- package/config/workflows/wrapup-pipeline.yaml +106 -13
- package/package.json +9 -9
- package/plugins/sp/README.md +25 -2
- package/plugins/sp/agents/super-planner.md +11 -0
- package/plugins/sp/agents/super-reviewer.md +39 -11
- package/plugins/sp/bunfig.toml +8 -0
- package/plugins/sp/commands/dev-brainstorm.md +29 -16
- package/plugins/sp/commands/dev-changelog.md +5 -4
- package/plugins/sp/commands/dev-find-way.md +80 -0
- package/plugins/sp/commands/dev-idea.md +6 -0
- package/plugins/sp/commands/dev-parallel.md +8 -2
- package/plugins/sp/commands/dev-plan.md +6 -0
- package/plugins/sp/commands/dev-review-session.md +14 -7
- package/plugins/sp/commands/dev-run.md +17 -4
- package/plugins/sp/commands/dev-runall.md +21 -10
- package/plugins/sp/hooks/agent-lifecycle.ts +155 -0
- package/plugins/sp/hooks/context-session-start.ts +1 -1
- package/plugins/sp/hooks/fleet-guest-stop.ts +180 -0
- package/plugins/sp/hooks/hooks.json +45 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +21 -0
- package/plugins/sp/lib/history-anatomy.generated.mjs +5 -0
- package/plugins/sp/lib/idea-handoff.generated.mjs +72 -11
- package/plugins/sp/lib/inline-run-app.ts +28 -0
- package/plugins/sp/lib/inline-run.generated.d.mts +6 -0
- package/plugins/sp/lib/inline-run.generated.mjs +364 -46
- package/plugins/sp/lib/plan-projection.generated.d.mts +28 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +255 -0
- package/plugins/sp/lib/quality-gate.generated.d.mts +47 -1
- package/plugins/sp/lib/quality-gate.generated.mjs +30489 -82
- package/plugins/sp/lib/residual-scan.generated.d.mts +19 -0
- package/plugins/sp/lib/residual-scan.generated.mjs +66 -0
- package/plugins/sp/lib/run-summary-core.ts +561 -0
- package/plugins/sp/lib/transcript.ts +275 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +335 -0
- package/plugins/sp/scripts/batch-plan.ts +100 -0
- package/plugins/sp/scripts/batch-preflight.mjs +51 -3
- package/plugins/sp/scripts/batch-preflight.ts +72 -1
- package/plugins/sp/scripts/commit-guard.mjs +216 -0
- package/plugins/sp/scripts/commit-guard.ts +249 -0
- package/plugins/sp/scripts/history-anatomy-cache.mjs +5 -0
- package/plugins/sp/scripts/inline-run-dispatch.mjs +130 -0
- package/plugins/sp/scripts/inline-run-dispatch.ts +135 -0
- package/plugins/sp/scripts/inline-run-setup.mjs +563 -91
- package/plugins/sp/scripts/inline-run-setup.ts +65 -97
- package/plugins/sp/scripts/persist-out-check.mjs +90 -41
- package/plugins/sp/scripts/persist-out-check.ts +112 -57
- package/plugins/sp/scripts/quality-gate.mjs +30407 -73
- package/plugins/sp/scripts/quality-gate.ts +21 -5
- package/plugins/sp/scripts/residual-scan.mjs +88 -38
- package/plugins/sp/scripts/residual-scan.ts +35 -38
- package/plugins/sp/scripts/run-summary.mjs +693 -0
- package/plugins/sp/scripts/run-summary.ts +105 -0
- package/plugins/sp/scripts/session-timeline.mjs +331 -0
- package/plugins/sp/scripts/session-timeline.ts +204 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +150 -2
- package/plugins/sp/scripts/wrapup-steps.ts +203 -1
- package/plugins/sp/skills/brainstorm/SKILL.md +9 -47
- package/plugins/sp/skills/branch-workflow/SKILL.md +1 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +1 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +48 -1
- package/plugins/sp/skills/code-verification/SKILL.md +8 -4
- package/plugins/sp/skills/code-verification/references/secu-review.md +3 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +68 -0
- package/plugins/sp/skills/fleet-join/SKILL.md +63 -0
- package/plugins/sp/skills/session-review/SKILL.md +77 -24
- package/plugins/sp/skills/source-driven-development/SKILL.md +5 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +5 -3
- package/plugins/sp/skills/spur-cli/SKILL.md +6 -2
- package/plugins/sp/skills/spur-cli/references/agent.md +124 -17
- package/plugins/sp/skills/spur-cli/references/decision.md +98 -0
- package/plugins/sp/skills/spur-cli/references/message.md +7 -7
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +41 -3
- package/plugins/sp/skills/spur-cli/references/tasks.md +10 -7
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +7 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +7 -2
- package/plugins/sp/skills/spur-composer/SKILL.md +28 -2
- package/plugins/sp/skills/spur-dev/SKILL.md +18 -14
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +6 -3
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +49 -14
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +51 -18
- package/plugins/sp/skills/spur-dev/references/execution-batch-continuation.md +68 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +194 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +113 -963
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +130 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +20 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +471 -0
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +379 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +51 -9
- package/plugins/sp/skills/spur-dev/references/glossary.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +361 -156
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +6 -0
- package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +178 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +10 -14
- package/schemas/decision-catalog.schema.json +226 -0
- package/schemas/spur-config.schema.json +25 -0
- package/schemas/state-machine-workflow.schema.json +23 -0
- package/spur.js +28165 -19051
- package/web/_astro/{BoardApp.i4eh_fHA.js → BoardApp.D66k_s_T.js} +1 -1
- package/web/_astro/BoardApp.D6sjAJr_.js +324 -0
- package/web/_astro/{TaskDetail.C5Cu8LdB.js → TaskDetail.BynLnMNc.js} +1 -1
- package/web/_astro/{arc.Bu5XpBEz.js → arc._BUadrdH.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.9vHQTvhF.js → architectureDiagram-3BPJPVTR.Dh7xS1Pp.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.Cn2Xl7D6.js → blockDiagram-GPEHLZMM.DFDVpfXm.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.7o0P_QDo.js → c4Diagram-AAUBKEIU.V7_3_glh.js} +1 -1
- package/web/_astro/channel.DZVfto-r.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.C3zZFsNt.js → chunk-2J33WTMH.De1yx7Jz.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CNy_M7fO.js → chunk-4BX2VUAB.BDhHFuxx.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.2TiPnLBL.js → chunk-55IACEB6.DDLkWnmC.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.5CGSyKAp.js → chunk-727SXJPM.CwfiLnA7.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.w-ZIgfsK.js → chunk-AQP2D5EJ.CtGDmUnM.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.BkcEyhKa.js → chunk-FMBD7UC4.BOLjpw73.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.mxKKbBG4.js → chunk-ND2GUHAM.BDhQls6O.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.cyA0z9aT.js → chunk-QZHKN3VN.76qBynDF.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CqtUzwhX.js → classDiagram-4FO5ZUOK.N0mpPHT0.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CqtUzwhX.js → classDiagram-v2-Q7XG4LA2.N0mpPHT0.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.BExPTopI.js → cose-bilkent-S5V4N54A.CKknFfjB.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.Bq2i10Cn.js → cynefin-OW5HDTMX.Cw3ZWBAh.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.By_HsOuv.js → dagre-BM42HDAG.D3yIKCRD.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.BtU0b7hz.js → diagram-2AECGRRQ.D51dO83Z.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.D00ztMdT.js → diagram-5GNKFQAL.Bb-FViDj.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DMVJWaUN.js → diagram-KO2AKTUF.D3mN8S6x.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.Cxqrjg5-.js → diagram-LMA3HP47.dMMyPcbJ.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.2lz_1B5h.js → diagram-OG6HWLK6.AzbvzY4C.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BVQEuJ3T.js → erDiagram-TEJ5UH35.BR5I4OZb.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.Qlyo90ky.js → flowDiagram-I6XJVG4X.DFqvhGkn.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DRwb8HHZ.js → ganttDiagram-6RSMTGT7.ByJbhH6J.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.YfoPthfS.js → gitGraphDiagram-PVQCEYII.CInHjQR3.js} +1 -1
- package/web/_astro/index.COh_kBxN.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DvFREck1.js → infoDiagram-5YYISTIA.Cm0dGVjJ.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BzCj9Q0-.js → ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.BDMT_AFb.js → journeyDiagram-JHISSGLW.4IvLa2MW.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D6Fh3gj9.js → kanban-definition-UN3LZRKU.DS87Cl-k.js} +1 -1
- package/web/_astro/{linear.Dxw00fGQ.js → linear.MzmRrNER.js} +1 -1
- package/web/_astro/{mermaid.core.CsoxUWa0.js → mermaid.core.fK-WNswS.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CN8oeHLu.js → mindmap-definition-RKZ34NQL.BqipOHhY.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C7ADqQ_7.js → pieDiagram-4H26LBE5.0nBiPqFG.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Cw9lKyHP.js → quadrantDiagram-W4KKPZXB.Szj7Zpx5.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.B1ni-z4q.js → requirementDiagram-4Y6WPE33.D4UR6TWo.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BhexdjVr.js → sankeyDiagram-5OEKKPKP.DAE7BdOs.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.C3Rm7dpQ.js → sequenceDiagram-3UESZ5HK.BP9ZVq25.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.CkuMt27u.js → stateDiagram-AJRCARHV.BQW7mIxk.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Dc_aazUA.js → stateDiagram-v2-BHNVJYJU.PbK4nDih.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.ja7sUFhH.js → timeline-definition-PNZ67QCA.Ci_GvUpo.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.BxIshX_K.js → vennDiagram-CIIHVFJN.DNw1Y5qx.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DfHlC0sh.js → wardleyDiagram-YWT4CUSO.CwlkaaNe.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DSnhHwCh.js → xychartDiagram-2RQKCTM6.MI6ZuiH_.js} +1 -1
- package/web/board-runtime.json +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.BVp-LYi6.js +0 -322
- package/web/_astro/channel.6IFIKBhu.js +0 -1
- package/web/_astro/index.CbNz17Sx.css +0 -1
|
@@ -43,6 +43,12 @@ creation.
|
|
|
43
43
|
spur feature create "<name>" [--parent <id>]
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
Without `--parent`, choose one before creating: list the tree (`spur feature list --json`) and nest the
|
|
47
|
+
feature under the existing feature that owns the surface or its design satellite. A new root feature
|
|
48
|
+
is a last resort that needs an explicit operator decision. When a parent is full (the 9-child limit),
|
|
49
|
+
nest under the closest owning child, and use `spur feature move <id> --parent <id> --dry-run` to
|
|
50
|
+
relocate an existing feature.
|
|
51
|
+
|
|
46
52
|
The feature file lands in `docs/features/<ID>_<slug>.md`. Immediately author the `## Goal`
|
|
47
53
|
(single sentence) and `## Scope` (in/out bullets).
|
|
48
54
|
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: structured-trace-emission
|
|
3
|
+
description: "Structured trace emission (task 1128 split, ADR-117 / task 0868): the action vocabulary, the per-step emit shape, the close contract and the parse rules the host driver follows. Read it when the first trace event is emitted."
|
|
4
|
+
see_also:
|
|
5
|
+
- inline-pipeline-driver
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Structured trace emission (ADR-117, task 0868)
|
|
9
|
+
|
|
10
|
+
`.spur/memory/runs/<run-id>.md` is the human half of the two-file run record — evidence, **not the record
|
|
11
|
+
of truth**. A run's
|
|
12
|
+
observability is a property of the run, so the inline driver owes the same structured trace the
|
|
13
|
+
engine subprocess writes — and it owes it through the **same writer**, never a parallel
|
|
14
|
+
implementation. The shared writer is `WorkflowActionTraceWriter`
|
|
15
|
+
(`packages/app/src/workflow/action-trace.ts`): the same decorator the engine composition installs
|
|
16
|
+
around `DbWorkflowPersistenceAdapter`, so the two surfaces call one emission path and one run-row
|
|
17
|
+
closure path and cannot drift.
|
|
18
|
+
|
|
19
|
+
The driver reaches it through the existing run delegate (`$SETUP_SCRIPT`,
|
|
20
|
+
`plugins/sp/scripts/inline-run-setup.ts`) — no new entry point, no second resolution chain:
|
|
21
|
+
|
|
22
|
+
- **Every executed action** — after the action settles, whether it ran host-inline or via a native
|
|
23
|
+
subagent — append its provenance line as before, then record the boundary:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
|
|
27
|
+
--status <done|failed> --ok <true|false> [--duration-ms <measured-ms>] [--estimated] \
|
|
28
|
+
--project-root "$OWNING_TREE"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`<state-id>` is the current YAML state id (the `node`), `<action-kind>` the YAML action kind
|
|
32
|
+
(`agent.run`, `shell`, `note`, `doctor.probe`, …). `--status` is `done` when the action settled
|
|
33
|
+
under its declared error policy and `failed` otherwise. This writes the `action_runs` row (node,
|
|
34
|
+
kind, status, `ok`, `duration_ms`, `run_id`) the engine would have written, so the run's rows are
|
|
35
|
+
queryable by run id (`spur workflow progress <run-id>`, `ActionRunDao`) without reading the text
|
|
36
|
+
log. The writer
|
|
37
|
+
back-dates the row's `started_at` from its own `completed_at` minus the measured duration
|
|
38
|
+
(0887 R8), so `completed_at − started_at == duration_ms` exactly; a back-date failure is
|
|
39
|
+
recorded (`action.backdate`) and never affects the run.
|
|
40
|
+
|
|
41
|
+
**`--project-root` names the tree that owns the run row (task 1136 R1/R2).** Per-tree DBs are
|
|
42
|
+
deliberate, so when the driver runs inside a `--worktree` (or any other execution tree) the run row
|
|
43
|
+
lives in the **invoking** tree's `.spur/spur.db` while the action commands run in the execution
|
|
44
|
+
tree. `--project-root` is the invoking tree recorded by the WT-3 marker; without it the row is read
|
|
45
|
+
from the cwd tree. A run-row miss is a **correctness failure**, not a best-effort emission failure:
|
|
46
|
+
`--action`, `--actions-file` and `--node-enter` exit `1` with
|
|
47
|
+
`{"ok":false,"code":"RUN_NOT_FOUND"}`, exactly like `--close`. **Never redirect these calls'
|
|
48
|
+
stdout/stderr to `/dev/null`** — the suppressed-RUN_NOT_FOUND run of task 1132 lost 93 action rows
|
|
49
|
+
to exactly that redirect. Capture the output or let it stream; a failure must be visible.
|
|
50
|
+
|
|
51
|
+
**Durations: measured beats reported (task 1136 R4).** Stamp the enter time before the action runs:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bun "$SETUP_SCRIPT" --node-enter --run-id "$RUN_ID" --node <state-id> --project-root "$OWNING_TREE"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then call `--action` **without** `--duration-ms` — the delegate computes
|
|
58
|
+
`duration = now − enter` and stamps `provenance: measured` into `action_runs.result_json`. A
|
|
59
|
+
caller-supplied `--duration-ms` stays valid but is recorded `provenance: host-reported` (with
|
|
60
|
+
`--estimated` marking a value reconstructed after the fact); every other inline row is
|
|
61
|
+
`host-reported` too, and the projection exposes `provenance` per attempt so the Board can label a
|
|
62
|
+
reported duration instead of presenting it as measured. A row whose computed start would precede
|
|
63
|
+
`runs.started_at` is **rejected** (exit `1`) — a timestamp before the run began is a broken clock,
|
|
64
|
+
not evidence. Calling `--action` without `--duration-ms` and without a matching `--node-enter`
|
|
65
|
+
exits `1` with `code:"ACTION_DURATION_UNAVAILABLE"`; it never silently drops the row.
|
|
66
|
+
|
|
67
|
+
- **A state with several actions (1007 R5)** — emit the whole state's boundaries in one call
|
|
68
|
+
instead of one `--action` invocation per action. Write a JSON array
|
|
69
|
+
(`[{node,kind,status,ok,durationMs,estimated?}, …]` — the `--action` fields, `estimated`
|
|
70
|
+
optional and `false` when absent) to a temp file and pass it with `--actions-file`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
bun "$SETUP_SCRIPT" --actions-file <actions.json> --run-id "$RUN_ID" --project-root "$OWNING_TREE"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Every row is recorded through the same writer as `--action` (one `action_runs` row per entry);
|
|
77
|
+
the batch is validated in full before the first write, so an invalid row or unreadable file
|
|
78
|
+
exits `1` with `{"ok":false}` and leaves **no** partial rows — fix the batch and re-emit. On
|
|
79
|
+
success it prints `{"ok":true,"runId":…,"recorded":<n>}` and exits `0`. Row emission stays
|
|
80
|
+
best-effort exactly like `--action`: if a row's write fails mid-batch, the failure is recorded
|
|
81
|
+
to the run record and the call reports `{"ok":false,…,"error":…}` but still exits `0` — the run
|
|
82
|
+
continues; never retry the batch or backfill by hand. `--actions-file` is exclusive with the
|
|
83
|
+
other mode flags (`--action`, `--decide`, `--close`, …): mixing them is a usage error (exit 2),
|
|
84
|
+
and a mixed call must be corrected, not silently split.
|
|
85
|
+
|
|
86
|
+
- **A `decide` action (0941)** — the driver never executes the DecisionMaker itself; it delegates
|
|
87
|
+
to the same app runner the engine registers, which writes the resultFile row (schemaVersion 1)
|
|
88
|
+
and returns the decision, then the delegate records the `action_runs` row (`kind=decide`)
|
|
89
|
+
through the same writer as every other action:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bun "$SETUP_SCRIPT" --decide --run-id "$RUN_ID" --node <state-id> --options-json <options-file>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The options JSON mirrors the YAML `decide` options (`id`, `method: choice|noul`, `question`,
|
|
96
|
+
`choices`/`default`, optional `evidence`, optional `minConfidence`, `resultFile`); paths resolve
|
|
97
|
+
against the project workdir. The decision never pauses and never fails the run for model
|
|
98
|
+
problems: a degraded outcome (feature switch off, no backend, error, timeout, low confidence)
|
|
99
|
+
prints `ok:true` with `degraded:true`, the declared `reason`, and `value = default`, and exits
|
|
100
|
+
`0` — route on the resultFile's `.value` with the declared file guards. Every row carries
|
|
101
|
+
`source: model|default` (0976 R2), and the delegate appends
|
|
102
|
+
`decide node=<id> value=<v> source=<s> reason=<r>` to the run log, so a declared-default
|
|
103
|
+
fallback is never read as a model decision. Only an invalid options
|
|
104
|
+
schema exits `1` (fail closed), and usage errors exit `2`. The `action_runs` trace row is
|
|
105
|
+
best-effort exactly like `--action`.
|
|
106
|
+
|
|
107
|
+
- **An operator pause is its own row (task 1136 R5)** — while the driver waits on a `hitl.confirm`
|
|
108
|
+
or `hitl.input`, emit the wait as its own boundary instead of charging it to the neighbouring
|
|
109
|
+
node:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind operator-wait \
|
|
113
|
+
--status done --ok true --duration-ms <waited-ms> --project-root "$OWNING_TREE"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`operator-wait` is a row kind, not a new state — the decision itself still belongs to the
|
|
117
|
+
declared node, and the wait's wall clock stays visible instead of inflating the node's duration.
|
|
118
|
+
|
|
119
|
+
- **At the run's declared terminal state** — before the driver reports the run complete, close the
|
|
120
|
+
row so a successful inline run is never left non-terminal for `spur workflow clean` to reap as
|
|
121
|
+
stale:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
bun "$SETUP_SCRIPT" --close --run-id "$RUN_ID" --status <done|failed|paused> --project-root "$OWNING_TREE"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The close also produces the execution summary (1146 R1): its stdout carries
|
|
128
|
+
**`summaryFile`** (`.spur/run/<runId>-summary.md`) unless `--no-summary` was passed. Print that
|
|
129
|
+
file's contents verbatim under an `### Execution summary` heading — the driver generates nothing
|
|
130
|
+
itself, and the window is the run row's `started_at` → close time, so no `SINCE` is recorded. A
|
|
131
|
+
summary failure never changes the close verdict: the file then holds exactly
|
|
132
|
+
`Execution summary: n/a (<reason>)`.
|
|
133
|
+
|
|
134
|
+
`--status` is the declared terminal state's verdict, not a guess: a run that reached a terminal
|
|
135
|
+
state is `done`; a run halted by a failing action under its error policy is `failed`. On success
|
|
136
|
+
the close reports the recorded evidence: `{"ok":true,"runId":…,"actionRows":<n>}` plus
|
|
137
|
+
**`missingNodes`** — the declared states the driver recorded as entered that never emitted an
|
|
138
|
+
`action_runs` row (`{"missingNodes":["precheck","verify"]}`, empty array when the trace is
|
|
139
|
+
whole). `missingNodes` is a **trace defect reported, never a close failure**: the close still
|
|
140
|
+
exits `0`, and it exists so a gap is visible — the repair is to emit the missing rows in the next
|
|
141
|
+
run, never to backfill them (ADR-117).
|
|
142
|
+
After the close, the invoking command prints the measured
|
|
143
|
+
[execution summary](dev-operations.md#execution-summary) for `$RUN_ID` unless `--no-summary`.
|
|
144
|
+
|
|
145
|
+
**Zero-row done closes are a named failure (task 0975 R2).** A run closed `done` with **zero**
|
|
146
|
+
`action_runs` rows (`actionRows:0`) finalizes the row but exits `1` with
|
|
147
|
+
`{"ok":false,"code":"NO_ACTION_ROWS","actionRows":0}` — a run that claims success without a
|
|
148
|
+
single recorded action is exactly the untraced-runs gap ADR-117 closes, so the driver must
|
|
149
|
+
surface the code in its final report instead of reporting a clean close. The failure must NOT
|
|
150
|
+
be repaired by backfilling rows: the run row is already terminal, and hand-written rows are
|
|
151
|
+
forbidden (ADR-117) — record the finding and let the task's evidence show the gap. A `failed`
|
|
152
|
+
close with zero rows stays a clean `0` (a halt before the first boundary legitimately records
|
|
153
|
+
nothing), and any `done` close with `actionRows ≥ 1` exits `0`.
|
|
154
|
+
|
|
155
|
+
**Best-effort at the action boundary only (ADR-117, task 1136 R1/R2).** An `--action` persistence
|
|
156
|
+
failure is recorded — the delegate appends a `trace-emission-failed` line to
|
|
157
|
+
`.spur/memory/runs/<run-id>.md` and prints `{"ok":false}` on stdout — and the run continues to its
|
|
158
|
+
declared terminal state; the delegate exits `0` for that outcome and the driver must never treat an
|
|
159
|
+
emission failure as a run failure, retry it in a loop, or substitute a hand-written row. The
|
|
160
|
+
exception is the **run row itself**: a missing run row, a duration that cannot be measured, or a
|
|
161
|
+
start time before `runs.started_at` are correctness failures and exit `1`
|
|
162
|
+
(`RUN_NOT_FOUND`, `ACTION_DURATION_UNAVAILABLE`). The run-row closure (`--close`) is bookkeeping, not
|
|
163
|
+
trace emission, and is **not** best-effort either: a missing run row or a persistence failure exits
|
|
164
|
+
`1` with `{"ok":false}` and a named error (a missing row also carries `code:"RUN_NOT_FOUND"`),
|
|
165
|
+
because a silently `running` row is exactly the stale state `spur workflow clean` reaps as `failed`.
|
|
166
|
+
Exit `2` means the invocation itself was malformed (missing `--node`/`--kind`/`--status`/`--ok`, a
|
|
167
|
+
miscased `--ok`, or a malformed `--duration-ms`) and must be corrected, not ignored.
|
|
168
|
+
|
|
169
|
+
**Never suppress this output.** The driver reference forbids redirecting `inline-run-setup`,
|
|
170
|
+
`quality-gate` and `persist-out*` stdout/stderr to `/dev/null`; a static pin fails any reference
|
|
171
|
+
snippet that does. Suppressing a `RUN_NOT_FOUND` is how task 1132's 93 action rows disappeared.
|
|
172
|
+
|
|
173
|
+
Emission is not optional and not deferred: an inline run that skips it reintroduces the
|
|
174
|
+
1,011-untraced-runs gap ADR-117 exists to close.
|
|
175
|
+
|
|
176
|
+
Transition guards are not advisory. Execute the declared guard exactly, in order, with the same
|
|
177
|
+
resolved variables and artifacts. `--no-lifecycle` remains bookkeeping only; the YAML's task checks,
|
|
178
|
+
verdict gate, record step, and done guard all remain authoritative.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wayfinder
|
|
3
|
-
description: "Chart a multi-session investigation map when the destination is too foggy to spec in one session. Creates a spur feature as the map, decomposes specifiable questions into spur tasks, and resolves them one at a time until the route becomes visible. Triggers: wayfind, chart a course, multi-session investigation,
|
|
3
|
+
description: "Chart a multi-session investigation map when the destination is too foggy to spec in one session. Creates a spur feature as the map, decomposes specifiable questions into spur tasks, and resolves them one at a time until the route becomes visible. Triggers: wayfind, chart a course, multi-session investigation, /sp:dev-find-way."
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
version: 1.0.0
|
|
6
6
|
created_at: 2026-07-06
|
|
@@ -57,7 +57,7 @@ Activate sp:wayfinder when:
|
|
|
57
57
|
| "multi-session investigation" | User expects multiple sessions to reach clarity |
|
|
58
58
|
| "find the way to X" | Destination is named but the route is unknown |
|
|
59
59
|
| "explore the solution space" | Open-ended exploration before committing |
|
|
60
|
-
|
|
|
60
|
+
| `/sp:dev-find-way` | The command entry — charting or one-ticket resolution in an isolated worktree |
|
|
61
61
|
|
|
62
62
|
**NOT for:**
|
|
63
63
|
- A clear spec that just needs decomposition (use `sp:spec-decomposition` instead)
|
|
@@ -110,7 +110,7 @@ Two modes. Either way, **never resolve more than one ticket per session.**
|
|
|
110
110
|
|
|
111
111
|
Invoked when the operator has a loose idea and the destination itself is foggy. Charting IS one session's work — do not also resolve tickets.
|
|
112
112
|
|
|
113
|
-
0. **
|
|
113
|
+
0. **Worktree first.** Run in an isolated git worktree on its own branch — `/sp:dev-find-way` does this (`sp/wayfind-<slug>-<short-id>`, FF-merged on success). Never `git checkout -b` in a shared tree: it switches the checkout under every other agent using it. The `corpus.ungraduated-fog` gate measures `merge-base(origin/main, HEAD)..(working tree)`, so it **cannot fire at all** on the default branch — how the 2026-08-07 incident shipped.
|
|
114
114
|
1. **Name the destination.** Run a discovery interview (one question at a time, always with a recommendation) to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first.
|
|
115
115
|
2. **Map the frontier breadth-first.** Fan out across the whole space rather than deep on any one thread, surfacing open decisions and the first steps takeable now. Use the decision-brief format for each HITL choice (see `../spur-dev/references/decision-brief.md`).
|
|
116
116
|
3. **Create the map as a spur feature.** `spur feature create "<destination>"`. The feature description carries:
|
|
@@ -130,7 +130,7 @@ Invoked when the operator has a loose idea and the destination itself is foggy.
|
|
|
130
130
|
|
|
131
131
|
Invoked when a map already exists (operator provides the feature ID). A ticket is **optional** — without one, pick the next frontier ticket, not the operator's preference. Pipeline runs: `references/pipeline-resolution.md`.
|
|
132
132
|
|
|
133
|
-
0. **
|
|
133
|
+
0. **Worktree first.** Same rule as charting (`sp/wayfind-<wbs>-<short-id>`): steps 6 and 7 remove fog from the map, and the gate that checks the removal measures the branch, not the commit. The `wip` claim lands only in the worktree until the merge, so `/sp:dev-find-way` excludes tickets held by other active `dev-find-way` worktree markers when picking the frontier.
|
|
134
134
|
1. **Load the map** — the feature description (the low-res view), not every task body. Read the destination and Decisions-so-far to orient.
|
|
135
135
|
2. **Pick the first frontier ticket.** Query: `spur task list --feature <id> --status todo` — the first open, unblocked, unclaimed task. If the operator named one, use it instead.
|
|
136
136
|
3. **Claim it.** `spur task update <wbs> wip` — before any work.
|
|
@@ -195,13 +195,9 @@ Ruling something out of scope is a scoping act, not a step on the route. When a
|
|
|
195
195
|
|
|
196
196
|
## Invocation
|
|
197
197
|
|
|
198
|
-
### From `/sp:dev-
|
|
198
|
+
### From `/sp:dev-find-way` (primary)
|
|
199
199
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
> *"This is a multi-session investigation. Want me to chart a wayfinder map so we can work through it one decision at a time?"*
|
|
203
|
-
|
|
204
|
-
The operator confirms before wayfinding begins — never silently escalate. The `--wayfind` flag on `/sp:dev-brainstorm` skips the prompt and enters wayfinding directly.
|
|
200
|
+
`/sp:dev-find-way "<idea>"` charts; `/sp:dev-find-way <feature-id> [<wbs>]` resolves one ticket. The command owns the worktree lifecycle and dispatches here. `/sp:dev-brainstorm` never charts: when its scope check finds a foggy destination it stops and recommends `/sp:dev-find-way` — the operator decides.
|
|
205
201
|
|
|
206
202
|
### Direct invocation
|
|
207
203
|
|
|
@@ -225,9 +221,9 @@ The operator invokes this skill directly: `Skill(skill="sp:wayfinder", args="<lo
|
|
|
225
221
|
## Red Flags
|
|
226
222
|
|
|
227
223
|
- Resolving more than one ticket in a single session.
|
|
228
|
-
- Charting or resolving
|
|
224
|
+
- Charting or resolving outside an isolated worktree — on the default branch the branch-scoped `corpus.ungraduated-fog` gate never fires; a `git checkout -b` in a shared tree moves every other agent's checkout.
|
|
229
225
|
- Creating a map without a destination statement — the destination fixes scope; without it, every ticket is unbounded.
|
|
230
|
-
-
|
|
226
|
+
- Starting wayfinding without operator confirmation.
|
|
231
227
|
- An empty or missing **### Not yet specified** section when the destination was described as foggy — fog that isn't written down is fog the next session can't see.
|
|
232
228
|
- Skipping the claim step (`spur task update <wbs> wip`) before work — concurrent sessions may collide.
|
|
233
229
|
- Pre-slicing fog into ticket stubs before the questions are sharp.
|
|
@@ -243,7 +239,7 @@ The operator invokes this skill directly: `Skill(skill="sp:wayfinder", args="<lo
|
|
|
243
239
|
|
|
244
240
|
### Charting verification
|
|
245
241
|
|
|
246
|
-
- [ ] The session ran
|
|
242
|
+
- [ ] The session ran in its own worktree + branch (`git rev-parse --git-dir` ≠ `--git-common-dir`; branch is not the default).
|
|
247
243
|
- [ ] Destination is a single, concrete sentence (not a paragraph, not a vague noun phrase).
|
|
248
244
|
- [ ] Map feature exists (`spur feature show <id>` returns clean).
|
|
249
245
|
- [ ] Feature description has all six sections: Destination, Notes, Open questions, Decisions so far (empty), Not yet specified, Out of scope.
|
|
@@ -256,7 +252,7 @@ The operator invokes this skill directly: `Skill(skill="sp:wayfinder", args="<lo
|
|
|
256
252
|
|
|
257
253
|
### Resolution verification
|
|
258
254
|
|
|
259
|
-
- [ ] The session ran
|
|
255
|
+
- [ ] The session ran in its own worktree + branch (`git rev-parse --git-dir` ≠ `--git-common-dir`; branch is not the default).
|
|
260
256
|
- [ ] Exactly one ticket was resolved this session.
|
|
261
257
|
- [ ] The ticket was claimed (`wip`) before work began.
|
|
262
258
|
- [ ] The resolution is recorded in the task body (not just a status transition — the answer is written down).
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "AI decision catalog",
|
|
4
|
+
"description": "Declarative decision catalog for @gobing-ai/ts-ai-decision (task 0089). Strict: unknown keys are rejected at every level. Cross-field checks (fallback vocabulary, ${params.*} references, defaults, reserved instructions parameter) run at load time.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["version", "decisions"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Bundled package-specifier ref to this schema; validated when present."
|
|
12
|
+
},
|
|
13
|
+
"version": {
|
|
14
|
+
"const": 1
|
|
15
|
+
},
|
|
16
|
+
"defaults": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"additionalProperties": false,
|
|
19
|
+
"properties": {
|
|
20
|
+
"maker": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
23
|
+
"description": "Registered maker name (built-ins: typesafe | fm-local | laya-local)."
|
|
24
|
+
},
|
|
25
|
+
"model": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Forwarded as the ask-level model; omit for the backend default."
|
|
28
|
+
},
|
|
29
|
+
"minConfidence": {
|
|
30
|
+
"type": "number",
|
|
31
|
+
"minimum": 0,
|
|
32
|
+
"maximum": 1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"decisions": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"minProperties": 1,
|
|
39
|
+
"propertyNames": {
|
|
40
|
+
"pattern": "^[a-z][a-z0-9_-]*$"
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": {
|
|
43
|
+
"$ref": "#/$defs/decision"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"$defs": {
|
|
48
|
+
"jsonValue": {
|
|
49
|
+
"anyOf": [
|
|
50
|
+
{
|
|
51
|
+
"type": "string"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"type": "number"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "boolean"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"type": "null"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"type": "array",
|
|
64
|
+
"items": {
|
|
65
|
+
"$ref": "#/$defs/jsonValue"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": {
|
|
71
|
+
"$ref": "#/$defs/jsonValue"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"jevEntry": {
|
|
77
|
+
"description": "A Jev entry: description string, JSON object, JSON array, or null (left undescribed). Description string leaves support ${params.*} templating.",
|
|
78
|
+
"anyOf": [
|
|
79
|
+
{
|
|
80
|
+
"type": "string"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"type": "null"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": {
|
|
88
|
+
"$ref": "#/$defs/jsonValue"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": {
|
|
94
|
+
"$ref": "#/$defs/jsonValue"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"paramType": {
|
|
100
|
+
"enum": ["string", "number", "boolean", "enum", "json"]
|
|
101
|
+
},
|
|
102
|
+
"param": {
|
|
103
|
+
"anyOf": [
|
|
104
|
+
{
|
|
105
|
+
"$ref": "#/$defs/paramType"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"type": "object",
|
|
109
|
+
"additionalProperties": false,
|
|
110
|
+
"required": ["type"],
|
|
111
|
+
"properties": {
|
|
112
|
+
"type": {
|
|
113
|
+
"$ref": "#/$defs/paramType"
|
|
114
|
+
},
|
|
115
|
+
"default": {},
|
|
116
|
+
"values": {
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"minItems": 1,
|
|
122
|
+
"description": "Accepted strings for type: enum (at least one)."
|
|
123
|
+
},
|
|
124
|
+
"description": {
|
|
125
|
+
"type": "string"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
"choiceCriteria": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"minProperties": 2,
|
|
134
|
+
"additionalProperties": {
|
|
135
|
+
"$ref": "#/$defs/jevEntry"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"scoreCriteria": {
|
|
139
|
+
"type": "array",
|
|
140
|
+
"minItems": 2,
|
|
141
|
+
"items": {
|
|
142
|
+
"$ref": "#/$defs/jevEntry"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"noulCriteria": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"additionalProperties": false,
|
|
148
|
+
"properties": {
|
|
149
|
+
"true": {
|
|
150
|
+
"$ref": "#/$defs/jevEntry"
|
|
151
|
+
},
|
|
152
|
+
"false": {
|
|
153
|
+
"$ref": "#/$defs/jevEntry"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"decision": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"additionalProperties": false,
|
|
160
|
+
"required": ["type", "fallback"],
|
|
161
|
+
"properties": {
|
|
162
|
+
"type": {
|
|
163
|
+
"enum": ["choice", "score", "noul"]
|
|
164
|
+
},
|
|
165
|
+
"description": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"description": "Documentation only; never sent to the model."
|
|
168
|
+
},
|
|
169
|
+
"instructions": {
|
|
170
|
+
"$ref": "#/$defs/jevEntry",
|
|
171
|
+
"description": "Templated Jev entry; defaults to \"${params.instructions}\"."
|
|
172
|
+
},
|
|
173
|
+
"parameters": {
|
|
174
|
+
"type": "object",
|
|
175
|
+
"propertyNames": {
|
|
176
|
+
"pattern": "^[a-z][a-zA-Z0-9_]*$"
|
|
177
|
+
},
|
|
178
|
+
"additionalProperties": {
|
|
179
|
+
"$ref": "#/$defs/param"
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"criteria": {
|
|
183
|
+
"description": "choice: label map (>= 2 labels); score: ordered rubric (>= 2 levels); noul: optional { true?, false? }.",
|
|
184
|
+
"anyOf": [
|
|
185
|
+
{
|
|
186
|
+
"$ref": "#/$defs/choiceCriteria"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"$ref": "#/$defs/scoreCriteria"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"$ref": "#/$defs/noulCriteria"
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
"fallback": {
|
|
197
|
+
"description": "choice: a declared label; score: integer level in [0, levels-1]; noul: boolean.",
|
|
198
|
+
"anyOf": [
|
|
199
|
+
{
|
|
200
|
+
"type": "string"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"type": "number"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"type": "boolean"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
"minConfidence": {
|
|
211
|
+
"type": "number",
|
|
212
|
+
"minimum": 0,
|
|
213
|
+
"maximum": 1
|
|
214
|
+
},
|
|
215
|
+
"maker": {
|
|
216
|
+
"type": "string",
|
|
217
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
218
|
+
"description": "Registered maker name; checked by the hub, not the loader."
|
|
219
|
+
},
|
|
220
|
+
"model": {
|
|
221
|
+
"type": "string"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -287,6 +287,31 @@
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
},
|
|
290
|
+
"decisions": {
|
|
291
|
+
"type": "object",
|
|
292
|
+
"description": "Decision-catalog resolution and DecisionMaker selection (feature P / ADR-134). The whole section is optional.",
|
|
293
|
+
"properties": {
|
|
294
|
+
"paths": {
|
|
295
|
+
"type": "array",
|
|
296
|
+
"items": {
|
|
297
|
+
"type": "string"
|
|
298
|
+
},
|
|
299
|
+
"description": "Extra catalog folders for the registered decision layer (absolute, project-relative, or 'bundled:<sub>' against the installed package's config root)."
|
|
300
|
+
},
|
|
301
|
+
"maker": {
|
|
302
|
+
"type": "string",
|
|
303
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
304
|
+
"description": "Default DecisionMaker for every decision point (built-ins: typesafe | fm-local | laya-local). Must be registered; an unknown name is a config error, never a silent fallback."
|
|
305
|
+
},
|
|
306
|
+
"makers": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"additionalProperties": {
|
|
309
|
+
"type": "string"
|
|
310
|
+
},
|
|
311
|
+
"description": "Per-decision-point maker overrides, keyed by decision id; outrank decisions.maker."
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
},
|
|
290
315
|
"redaction": {
|
|
291
316
|
"type": "object",
|
|
292
317
|
"properties": {
|
|
@@ -105,6 +105,29 @@
|
|
|
105
105
|
"type": "boolean",
|
|
106
106
|
"description": "When true, the engine pauses the run at this state for HITL (E3); resume with `spur workflow continue`."
|
|
107
107
|
},
|
|
108
|
+
"display": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"additionalProperties": false,
|
|
111
|
+
"description": "Presentation-only metadata for plan/UI generators; the engine never reads it at run time.",
|
|
112
|
+
"required": ["phase"],
|
|
113
|
+
"properties": {
|
|
114
|
+
"phase": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"minLength": 1
|
|
117
|
+
},
|
|
118
|
+
"phaseTitle": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"minLength": 1
|
|
121
|
+
},
|
|
122
|
+
"title": {
|
|
123
|
+
"type": "string",
|
|
124
|
+
"minLength": 1
|
|
125
|
+
},
|
|
126
|
+
"show": {
|
|
127
|
+
"enum": ["plan", "on-entry"]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
108
131
|
"onEnter": {
|
|
109
132
|
"type": "array",
|
|
110
133
|
"items": {
|