@gobing-ai/spur 0.3.99 → 0.4.0

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.
Files changed (106) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.global.yaml +17 -0
  3. package/config/decisions/task-pipeline.yaml +55 -0
  4. package/config/plugin-scripts.json +10 -0
  5. package/config/rules/boundary/sp-runtime-path.yaml +2 -0
  6. package/config/rules/quality/coverage-gate.yaml +5 -3
  7. package/config/rules/strict/runtime-boundaries.yaml +11 -0
  8. package/config/rules/structure/protected-files.yaml +3 -0
  9. package/config/workflows/task-pipeline.yaml +178 -18
  10. package/package.json +9 -9
  11. package/plugins/sp/README.md +14 -1
  12. package/plugins/sp/agents/super-reviewer.md +25 -11
  13. package/plugins/sp/commands/dev-changelog.md +5 -4
  14. package/plugins/sp/commands/dev-review-session.md +12 -7
  15. package/plugins/sp/commands/dev-run.md +5 -2
  16. package/plugins/sp/commands/dev-runall.md +5 -2
  17. package/plugins/sp/hooks/agent-lifecycle.ts +155 -0
  18. package/plugins/sp/hooks/fleet-guest-stop.ts +180 -0
  19. package/plugins/sp/hooks/hooks.json +45 -1
  20. package/plugins/sp/hooks/pi/guard-extension.ts +21 -0
  21. package/plugins/sp/lib/history-anatomy.generated.mjs +5 -0
  22. package/plugins/sp/lib/idea-handoff.generated.mjs +34 -9
  23. package/plugins/sp/lib/inline-run.generated.d.mts +1 -0
  24. package/plugins/sp/lib/inline-run.generated.mjs +49 -19
  25. package/plugins/sp/lib/transcript.ts +160 -0
  26. package/plugins/sp/plugin.json +1 -1
  27. package/plugins/sp/scripts/history-anatomy-cache.mjs +5 -0
  28. package/plugins/sp/scripts/inline-run-setup.mjs +21 -20
  29. package/plugins/sp/scripts/inline-run-setup.ts +25 -31
  30. package/plugins/sp/scripts/residual-scan.mjs +2 -7
  31. package/plugins/sp/scripts/residual-scan.ts +7 -8
  32. package/plugins/sp/scripts/run-summary.mjs +286 -0
  33. package/plugins/sp/scripts/run-summary.ts +241 -0
  34. package/plugins/sp/scripts/session-timeline.mjs +234 -0
  35. package/plugins/sp/scripts/session-timeline.ts +152 -0
  36. package/plugins/sp/skills/code-verification/SKILL.md +5 -0
  37. package/plugins/sp/skills/fleet-join/SKILL.md +63 -0
  38. package/plugins/sp/skills/session-review/SKILL.md +46 -24
  39. package/plugins/sp/skills/spur-cli/SKILL.md +1 -0
  40. package/plugins/sp/skills/spur-cli/references/agent.md +108 -6
  41. package/plugins/sp/skills/spur-cli/references/decision.md +97 -0
  42. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +22 -0
  43. package/plugins/sp/skills/spur-composer/SKILL.md +27 -1
  44. package/plugins/sp/skills/spur-dev/references/dev-operations.md +28 -16
  45. package/plugins/sp/skills/spur-dev/references/execution-batch.md +64 -7
  46. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +14 -0
  47. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +16 -4
  48. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +32 -7
  49. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +6 -0
  50. package/schemas/decision-catalog.schema.json +226 -0
  51. package/schemas/spur-config.schema.json +25 -0
  52. package/spur.js +7440 -2424
  53. package/web/_astro/BoardApp.Bzr4OXrW.js +324 -0
  54. package/web/_astro/{BoardApp.i4eh_fHA.js → BoardApp.VeoxxLBy.js} +1 -1
  55. package/web/_astro/{TaskDetail.C5Cu8LdB.js → TaskDetail.LAyR_Pvn.js} +1 -1
  56. package/web/_astro/{arc.Bu5XpBEz.js → arc.f4e0OYLg.js} +1 -1
  57. package/web/_astro/{architectureDiagram-3BPJPVTR.9vHQTvhF.js → architectureDiagram-3BPJPVTR.SSIvxi-Z.js} +1 -1
  58. package/web/_astro/{blockDiagram-GPEHLZMM.Cn2Xl7D6.js → blockDiagram-GPEHLZMM.DSXIHOFf.js} +1 -1
  59. package/web/_astro/{c4Diagram-AAUBKEIU.7o0P_QDo.js → c4Diagram-AAUBKEIU.DG9Ubu85.js} +1 -1
  60. package/web/_astro/channel.CUFdtWhm.js +1 -0
  61. package/web/_astro/{chunk-2J33WTMH.C3zZFsNt.js → chunk-2J33WTMH.C7QU88Qh.js} +1 -1
  62. package/web/_astro/{chunk-4BX2VUAB.CNy_M7fO.js → chunk-4BX2VUAB.26Z94xBj.js} +1 -1
  63. package/web/_astro/{chunk-55IACEB6.2TiPnLBL.js → chunk-55IACEB6.DYRiBkqw.js} +1 -1
  64. package/web/_astro/{chunk-727SXJPM.5CGSyKAp.js → chunk-727SXJPM.D5Vfv5pe.js} +1 -1
  65. package/web/_astro/{chunk-AQP2D5EJ.w-ZIgfsK.js → chunk-AQP2D5EJ.DXHV47bN.js} +1 -1
  66. package/web/_astro/{chunk-FMBD7UC4.BkcEyhKa.js → chunk-FMBD7UC4.D1suAfOs.js} +1 -1
  67. package/web/_astro/{chunk-ND2GUHAM.mxKKbBG4.js → chunk-ND2GUHAM.D6BmdHEY.js} +1 -1
  68. package/web/_astro/{chunk-QZHKN3VN.cyA0z9aT.js → chunk-QZHKN3VN.rnPU-Ak-.js} +1 -1
  69. package/web/_astro/{classDiagram-4FO5ZUOK.CqtUzwhX.js → classDiagram-4FO5ZUOK.CvEfXIo1.js} +1 -1
  70. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CqtUzwhX.js → classDiagram-v2-Q7XG4LA2.CvEfXIo1.js} +1 -1
  71. package/web/_astro/{cose-bilkent-S5V4N54A.BExPTopI.js → cose-bilkent-S5V4N54A.DkMisLSm.js} +1 -1
  72. package/web/_astro/{cynefin-OW5HDTMX.Bq2i10Cn.js → cynefin-OW5HDTMX.C77Q-pF6.js} +1 -1
  73. package/web/_astro/{dagre-BM42HDAG.By_HsOuv.js → dagre-BM42HDAG.YaV8ce27.js} +1 -1
  74. package/web/_astro/{diagram-2AECGRRQ.BtU0b7hz.js → diagram-2AECGRRQ.CUyGEKge.js} +1 -1
  75. package/web/_astro/{diagram-5GNKFQAL.D00ztMdT.js → diagram-5GNKFQAL.CRgd8dgj.js} +1 -1
  76. package/web/_astro/{diagram-KO2AKTUF.DMVJWaUN.js → diagram-KO2AKTUF.Bmzys9hq.js} +1 -1
  77. package/web/_astro/{diagram-LMA3HP47.Cxqrjg5-.js → diagram-LMA3HP47.BvmJY4Lw.js} +1 -1
  78. package/web/_astro/{diagram-OG6HWLK6.2lz_1B5h.js → diagram-OG6HWLK6.0hEhD30d.js} +1 -1
  79. package/web/_astro/{erDiagram-TEJ5UH35.BVQEuJ3T.js → erDiagram-TEJ5UH35.Bjt8lrnm.js} +1 -1
  80. package/web/_astro/{flowDiagram-I6XJVG4X.Qlyo90ky.js → flowDiagram-I6XJVG4X.CJZTjRDV.js} +1 -1
  81. package/web/_astro/{ganttDiagram-6RSMTGT7.DRwb8HHZ.js → ganttDiagram-6RSMTGT7._VqoVafc.js} +1 -1
  82. package/web/_astro/{gitGraphDiagram-PVQCEYII.YfoPthfS.js → gitGraphDiagram-PVQCEYII.CEDb7tVo.js} +1 -1
  83. package/web/_astro/index.Dg_3bOaJ.css +1 -0
  84. package/web/_astro/{infoDiagram-5YYISTIA.DvFREck1.js → infoDiagram-5YYISTIA.CgwifPpK.js} +1 -1
  85. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BzCj9Q0-.js → ishikawaDiagram-YF4QCWOH.B99wx2J1.js} +1 -1
  86. package/web/_astro/{journeyDiagram-JHISSGLW.BDMT_AFb.js → journeyDiagram-JHISSGLW.2hRwJbEo.js} +1 -1
  87. package/web/_astro/{kanban-definition-UN3LZRKU.D6Fh3gj9.js → kanban-definition-UN3LZRKU.BahJkKNC.js} +1 -1
  88. package/web/_astro/{linear.Dxw00fGQ.js → linear.DguUUe6V.js} +1 -1
  89. package/web/_astro/{mermaid.core.CsoxUWa0.js → mermaid.core.CvgfmqVr.js} +4 -4
  90. package/web/_astro/{mindmap-definition-RKZ34NQL.CN8oeHLu.js → mindmap-definition-RKZ34NQL.B3qEA3x9.js} +1 -1
  91. package/web/_astro/{pieDiagram-4H26LBE5.C7ADqQ_7.js → pieDiagram-4H26LBE5.FlWA-_ru.js} +1 -1
  92. package/web/_astro/{quadrantDiagram-W4KKPZXB.Cw9lKyHP.js → quadrantDiagram-W4KKPZXB.9bVn35X7.js} +1 -1
  93. package/web/_astro/{requirementDiagram-4Y6WPE33.B1ni-z4q.js → requirementDiagram-4Y6WPE33.ChykIhct.js} +1 -1
  94. package/web/_astro/{sankeyDiagram-5OEKKPKP.BhexdjVr.js → sankeyDiagram-5OEKKPKP.Z2Y3hkYb.js} +1 -1
  95. package/web/_astro/{sequenceDiagram-3UESZ5HK.C3Rm7dpQ.js → sequenceDiagram-3UESZ5HK.J7JsHWDt.js} +1 -1
  96. package/web/_astro/{stateDiagram-AJRCARHV.CkuMt27u.js → stateDiagram-AJRCARHV.DAPbiCSS.js} +1 -1
  97. package/web/_astro/{stateDiagram-v2-BHNVJYJU.Dc_aazUA.js → stateDiagram-v2-BHNVJYJU.D2jvSi0q.js} +1 -1
  98. package/web/_astro/{timeline-definition-PNZ67QCA.ja7sUFhH.js → timeline-definition-PNZ67QCA.psW2ci29.js} +1 -1
  99. package/web/_astro/{vennDiagram-CIIHVFJN.BxIshX_K.js → vennDiagram-CIIHVFJN.DlILYVmg.js} +1 -1
  100. package/web/_astro/{wardleyDiagram-YWT4CUSO.DfHlC0sh.js → wardleyDiagram-YWT4CUSO.xNWwLJnn.js} +1 -1
  101. package/web/_astro/{xychartDiagram-2RQKCTM6.DSnhHwCh.js → xychartDiagram-2RQKCTM6.EU_BuH7V.js} +1 -1
  102. package/web/board-runtime.json +1 -1
  103. package/web/index.html +2 -2
  104. package/web/_astro/BoardApp.BVp-LYi6.js +0 -322
  105. package/web/_astro/channel.6IFIKBhu.js +0 -1
  106. package/web/_astro/index.CbNz17Sx.css +0 -1
@@ -301,10 +301,13 @@ tasks by `updated_at >= date`).
301
301
 
302
302
  **Anchor:** `#flag-fix`.
303
303
 
304
- Remediation policy on verify-family commands (`dev-verify`, `dev-verifyall`) and the refactor
305
- coordinator (`dev-refactor`):
304
+ Remediation policy on verify-family commands (`dev-verify`, `dev-verifyall`), the refactor
305
+ coordinator (`dev-refactor`) and the session review (`dev-review-session`):
306
306
  `none|blockers-first|all`. `none` reports findings without fixing; `blockers-first` fixes only P1/P2;
307
- `all` fixes everything found. Deprecated on `dev-review` (routes to `dev-verify --fix`).
307
+ `all` fixes everything found. On `dev-review-session` the vocabulary is `none|auto|all`: `none`
308
+ report-only, `auto` the `--triage` behavior (inline direct fixes, the rest filed as tasks), `all`
309
+ fixes every actionable finding inline and files no task. Deprecated on `dev-review` (routes to
310
+ `dev-verify --fix`).
308
311
 
309
312
  ### `--until <ref>` — upper bound on a range
310
313
 
@@ -336,6 +339,14 @@ specific status slice).
336
339
  Skip the shippable guard on verify-family commands (`dev-verify`, `dev-verifyall`). Used when
337
340
  verifying a task whose artifact is intentionally not yet shippable (e.g. a doc-only task).
338
341
 
342
+ ### `--no-summary` — skip the execution summary
343
+
344
+ **Anchor:** `#flag-no-summary`.
345
+
346
+ Skip the measured execution summary that run commands (`dev-run`, `dev-runall`) print by default
347
+ once the run settles: per-stage (or per-run) time, operator wait, tool calls and total / non-cached
348
+ tokens from the host transcript. Procedure: [dev-operations.md § Execution summary](dev-operations.md#execution-summary).
349
+
339
350
  ### `--skip-design` — omit the design package
340
351
 
341
352
  **Anchor:** `#flag-skip-design`.
@@ -445,7 +456,8 @@ Review commands (`dev-review`, `dev-review-session`): after the report, bucket e
445
456
  remainder through `spur task` — never fix straight from the raw findings list. Off by default
446
457
  (report-only). Both file one or more implement-ready tasks sized per cohesive unit, under existing
447
458
  features ([dev-operations.md § 2. review](dev-operations.md#2-review)); `dev-review-session` keeps
448
- the stricter direct-fix bar (pure docs / one-to-two-line fixes).
459
+ the stricter direct-fix bar (pure docs / one-to-two-line fixes), and there `--triage` is an alias
460
+ of `--fix auto` ([`--fix`](#flag-fix)).
449
461
 
450
462
  ### `--worktree [<name>]` — run the batch in an isolated git worktree (create or reuse)
451
463
 
@@ -159,6 +159,11 @@ the human/native presentation layer — labels are display addresses only, never
159
159
  resolved definition identity against the bound `__definitionDigest`; a mismatch is identity drift
160
160
  and fails closed (step 8 already caught projection-side drift; this re-checks the same definition
161
161
  the interpreter will execute).
162
+ - **Runtime-written vars are re-read, never cached.** A var a later state writes (`proofDigest`,
163
+ `proofDigestNow`, `taskSpecPath`, `featureSpecPath`, `taskPriority`, `mode`, `gateFindings`) is a
164
+ run artifact, not a YAML default: re-resolve it from `.spur/run/`/`.spur/memory/runs/` at every
165
+ state boundary, and never let a host-side copy of the invocation vars shadow it — a stale empty
166
+ `proofDigest` silently fails the bound `run.artifact` equivalence and the `record` proof guard.
162
167
  - **Layer 2** = the active state's `onEnter` actions (`kind` + resolved `input`/`command`), from
163
168
  the YAML read here, shown only for the active state.
164
169
  - **Refresh cadence** = stage boundaries only (when the current state changes after a transition),
@@ -342,9 +347,13 @@ or terminal close. Measure its actual duration and preserve its declared failure
342
347
 
343
348
  ```bash
344
349
  bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
345
- --status <done|failed> --ok <true|false> --duration-ms <measured-ms>
350
+ --status <done|failed> --ok <true|false> --duration-ms <measured-ms> [--estimated]
346
351
  ```
347
352
 
353
+ `--duration-ms` is the wall clock measured around the action. Pass `--estimated` when you did
354
+ **not** time it — for example a duration reconstructed after a subagent returned — so the row is
355
+ labelled instead of presented as measured. `--estimated` is valid only with `--action`.
356
+
348
357
  For a multi-action state, `--actions-file` may emit the measured boundaries together before leaving
349
358
  that state. Follow [Structured trace emission](#structured-trace-emission-adr-117-task-0868) for the
350
359
  payload, delegated `decide` emission and best-effort failure handling. Never retry a failed batch
@@ -357,6 +366,14 @@ Action semantics come from the YAML and the workflow action contract:
357
366
  - `note` — append the expanded message to the inline run log.
358
367
  - `doctor.probe` — run the declared Spur doctor once, persist its status file, and apply any
359
368
  `setVars` result (including a resolved executor) before the next action or state.
369
+ **Role-map mode has no inline surface (task 1088 session finding).** A `doctor.probe` that
370
+ declares `roles` resolves them through `AgentService.resolve`, which is reachable only in-process
371
+ (the engine composition injects the service); no CLI verb exposes it, so the host session cannot
372
+ reproduce `__executor.<role>` pins. The driver therefore probes the host-session agent instead,
373
+ writes that verdict to the declared status file, and records one run-log line naming the
374
+ substitution. Nothing downstream degrades: `__executor.<role>` pins are consumed by the
375
+ subprocess dispatch path, and the inline path executes its stages in the host session without
376
+ reading them. Never fabricate pins to satisfy the shape, and never skip the status file.
360
377
  - `file.read.into-var` — read the declared file into the declared run variable before subsequent
361
378
  actions/guards.
362
379
  - `hitl.confirm` — under `profile=auto`, follow the YAML's auto-skip transition. Otherwise pause,
@@ -628,23 +645,29 @@ The driver reaches it through the existing run delegate (`$SETUP_SCRIPT`,
628
645
 
629
646
  ```bash
630
647
  bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
631
- --status <done|failed> --ok <true|false> --duration-ms <measured-ms>
648
+ --status <done|failed> --ok <true|false> --duration-ms <measured-ms> [--estimated]
632
649
  ```
633
650
 
634
651
  `<state-id>` is the current YAML state id (the `node`), `<action-kind>` the YAML action kind
635
652
  (`agent.run`, `shell`, `note`, `doctor.probe`, …). `--status` is `done` when the action settled
636
653
  under its declared error policy and `failed` otherwise; `--duration-ms` is the wall clock the
637
- driver measured around the action. This writes the `action_runs` row (node, kind, status, `ok`,
638
- `duration_ms`, `run_id`) the engine would have written, so the run's rows are queryable by run id
639
- (`spur workflow progress <run-id>`, `ActionRunDao`) without reading the text log. The writer
654
+ driver measured around the action, and `--estimated` marks a duration the driver did **not**
655
+ time (a value reconstructed after the action returned). The row's provenance stamp rides
656
+ `action_runs.result_json` as `{provenance:'host-reported', estimated}`, and the projection
657
+ exposes it per attempt — `provenance` is `host-reported` for every inline row and `unknown`
658
+ for an engine-written or pre-stamp row, so the Board can label a host-reported duration
659
+ instead of presenting it as measured. This writes the `action_runs` row (node, kind, status,
660
+ `ok`, `duration_ms`, `run_id`) the engine would have written, so the run's rows are queryable
661
+ by run id (`spur workflow progress <run-id>`, `ActionRunDao`) without reading the text log.
662
+ The writer
640
663
  back-dates the row's `started_at` from its own `completed_at` minus the measured duration
641
664
  (0887 R8), so `completed_at − started_at == duration_ms` exactly; a back-date failure is
642
665
  recorded (`action.backdate`) and never affects the run.
643
666
 
644
667
  - **A state with several actions (1007 R5)** — emit the whole state's boundaries in one call
645
668
  instead of one `--action` invocation per action. Write a JSON array
646
- (`[{node,kind,status,ok,durationMs}, …]` — same fields the `--action` flags carry) to a temp
647
- file and pass it with `--actions-file`:
669
+ (`[{node,kind,status,ok,durationMs,estimated?}, …]` — the `--action` fields, `estimated`
670
+ optional and `false` when absent) to a temp file and pass it with `--actions-file`:
648
671
 
649
672
  ```bash
650
673
  bun "$SETUP_SCRIPT" --actions-file <actions.json> --run-id "$RUN_ID"
@@ -692,6 +715,8 @@ The driver reaches it through the existing run delegate (`$SETUP_SCRIPT`,
692
715
  `--status` is the declared terminal state's verdict, not a guess: a run that reached a terminal
693
716
  state is `done`; a run halted by a failing action under its error policy is `failed`. On success
694
717
  the close reports the recorded evidence: `{"ok":true,"runId":…,"actionRows":<n>}`.
718
+ After the close, the invoking command prints the measured
719
+ [execution summary](dev-operations.md#execution-summary) for `$RUN_ID` unless `--no-summary`.
695
720
 
696
721
  **Zero-row done closes are a named failure (task 0975 R2).** A run closed `done` with **zero**
697
722
  `action_runs` rows (`actionRows:0`) finalizes the row but exits `1` with
@@ -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,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": {