syntaur 0.43.1 → 0.44.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 (71) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dashboard/dist/assets/{_basePickBy-CabSPDlA.js → _basePickBy-CNjxCBYf.js} +1 -1
  3. package/dashboard/dist/assets/{_baseUniq-DGO4Y46J.js → _baseUniq-1yktSv9L.js} +1 -1
  4. package/dashboard/dist/assets/{arc-C0lxzBYC.js → arc-CUp_7cxd.js} +1 -1
  5. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-DAa-zxeT.js → architectureDiagram-2XIMDMQ5-BhQNIov3.js} +1 -1
  6. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-BhFavWXG.js → blockDiagram-WCTKOSBZ-BbrHpJX7.js} +1 -1
  7. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-BxKqhk8H.js → c4Diagram-IC4MRINW-BzAgIl-O.js} +1 -1
  8. package/dashboard/dist/assets/channel-Dcp4Ds-Z.js +1 -0
  9. package/dashboard/dist/assets/{chunk-4BX2VUAB-CayPDVSU.js → chunk-4BX2VUAB-DxR-gcvU.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-55IACEB6-DE34igmQ.js → chunk-55IACEB6-DgMbDP9S.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-FMBD7UC4-CWHswGwW.js → chunk-FMBD7UC4-zECir1CK.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-JSJVCQXG-DnsqdfIB.js → chunk-JSJVCQXG-Cnl5h8xD.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-KX2RTZJC-FbqVE08c.js → chunk-KX2RTZJC-Ck2VpQt9.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-NQ4KR5QH-DcsdDqWQ.js → chunk-NQ4KR5QH-B8kgPwoS.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-QZHKN3VN-DZBdzXAZ.js → chunk-QZHKN3VN-CsN9VGXC.js} +1 -1
  16. package/dashboard/dist/assets/{chunk-WL4C6EOR-DV11wZKH.js → chunk-WL4C6EOR-BP27dBI1.js} +1 -1
  17. package/dashboard/dist/assets/classDiagram-VBA2DB6C-CnkOuwPH.js +1 -0
  18. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-CnkOuwPH.js +1 -0
  19. package/dashboard/dist/assets/clone-cpjQdgQb.js +1 -0
  20. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-Cc5iZnSF.js → cose-bilkent-S5V4N54A-m2V_HPK-.js} +1 -1
  21. package/dashboard/dist/assets/{dagre-KLK3FWXG-DdhTE6jK.js → dagre-KLK3FWXG-CZfxqYb1.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-E7M64L7V-DNwcjAks.js → diagram-E7M64L7V-DtzcWFtr.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-IFDJBPK2-UNMmAgBt.js → diagram-IFDJBPK2-D2IymgnX.js} +1 -1
  24. package/dashboard/dist/assets/{diagram-P4PSJMXO-DFVklVy0.js → diagram-P4PSJMXO-D24UPsRu.js} +1 -1
  25. package/dashboard/dist/assets/{erDiagram-INFDFZHY-CN8yM6gL.js → erDiagram-INFDFZHY-CZKUJMzt.js} +1 -1
  26. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-CueIaRLY.js → flowDiagram-PKNHOUZH-DL_F8pzV.js} +1 -1
  27. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-DnYhCq5T.js → ganttDiagram-A5KZAMGK-D8fgmRAI.js} +1 -1
  28. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-ISNXg3k0.js → gitGraphDiagram-K3NZZRJ6-2-zNwJhX.js} +1 -1
  29. package/dashboard/dist/assets/{graph-BZz0E7Ci.js → graph-BGFPrUov.js} +1 -1
  30. package/dashboard/dist/assets/{index-Dzh96P4Z.js → index-C4lUbUTt.js} +101 -101
  31. package/dashboard/dist/assets/{index-BqxbS9Wf.css → index-D1f1wB-7.css} +1 -1
  32. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-bNvKINb_.js → infoDiagram-LFFYTUFH-C_AYIIRq.js} +1 -1
  33. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DKfRfWXE.js → ishikawaDiagram-PHBUUO56-BF1Td7it.js} +1 -1
  34. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-BfKl4TNb.js → journeyDiagram-4ABVD52K-EMMIV9Ho.js} +1 -1
  35. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-3b_Gc82P.js → kanban-definition-K7BYSVSG-Bf_bRjc1.js} +1 -1
  36. package/dashboard/dist/assets/{layout-CDFST2WK.js → layout-DVtc1c49.js} +1 -1
  37. package/dashboard/dist/assets/{linear-DFkg06qv.js → linear-B-_q9tMu.js} +1 -1
  38. package/dashboard/dist/assets/{mermaid.core-eqq1_dL_.js → mermaid.core-DsNAtlU2.js} +4 -4
  39. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-3UicY0_v.js → mindmap-definition-YRQLILUH-CIk_H2CD.js} +1 -1
  40. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-CZyg0jjE.js → pieDiagram-SKSYHLDU-CuqaiuOZ.js} +1 -1
  41. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-Cj6oadbs.js → quadrantDiagram-337W2JSQ-By2Uoys0.js} +1 -1
  42. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-BlfA8l6H.js → requirementDiagram-Z7DCOOCP-RQe6sA24.js} +1 -1
  43. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-CHU0rdbD.js → sankeyDiagram-WA2Y5GQK-BWqm0u7o.js} +1 -1
  44. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-fP5IFexC.js → sequenceDiagram-2WXFIKYE-DZ4Esix3.js} +1 -1
  45. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-CdthThpd.js → stateDiagram-RAJIS63D-Xae5htdZ.js} +1 -1
  46. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-BfD_wvla.js +1 -0
  47. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-DI1ep504.js → timeline-definition-YZTLITO2-DxW_e6Qq.js} +1 -1
  48. package/dashboard/dist/assets/{treemap-KZPCXAKY-CvuW7d81.js → treemap-KZPCXAKY-BTD-CY69.js} +1 -1
  49. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-DEuyxMbM.js → vennDiagram-LZ73GAT5-BhpyjM1r.js} +1 -1
  50. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-BVlWbeAK.js → xychartDiagram-JWTSCODW-BmQJbBCA.js} +1 -1
  51. package/dashboard/dist/index.html +2 -2
  52. package/dist/dashboard/server.js +4853 -4299
  53. package/dist/dashboard/server.js.map +1 -1
  54. package/dist/index.js +2817 -2142
  55. package/dist/index.js.map +1 -1
  56. package/dist/launch/index.d.ts +15 -0
  57. package/dist/launch/index.js +3130 -2709
  58. package/dist/launch/index.js.map +1 -1
  59. package/package.json +1 -1
  60. package/platforms/claude-code/.claude-plugin/plugin.json +1 -1
  61. package/platforms/claude-code/skills/manage-statuses/SKILL.md +49 -1
  62. package/platforms/codex/.codex-plugin/plugin.json +1 -1
  63. package/platforms/codex/skills/manage-statuses/SKILL.md +49 -1
  64. package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
  65. package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
  66. package/skills/manage-statuses/SKILL.md +49 -1
  67. package/dashboard/dist/assets/channel-gkqjyV0r.js +0 -1
  68. package/dashboard/dist/assets/classDiagram-VBA2DB6C-D1CF55uI.js +0 -1
  69. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-D1CF55uI.js +0 -1
  70. package/dashboard/dist/assets/clone-Cx1NBdWo.js +0 -1
  71. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-kKo_Asao.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syntaur",
3
- "version": "0.43.1",
3
+ "version": "0.44.0",
4
4
  "description": "Project workflow CLI with dashboard, Claude Code plugin, and Codex plugin",
5
5
  "homepage": "https://github.com/prong-horn/syntaur#readme",
6
6
  "repository": {
@@ -5,7 +5,7 @@
5
5
  "name": "Brennen",
6
6
  "email": ""
7
7
  },
8
- "version": "0.43.1",
8
+ "version": "0.44.0",
9
9
  "skills": [
10
10
  "./skills/syntaur-protocol",
11
11
  "./skills/grab-assignment",
@@ -62,11 +62,59 @@ After every mutating subcommand, run `syntaur status list` (or `--json` for mach
62
62
  - **After a `remove --force`,** the affected assignments now reference an undefined status. `syntaur doctor` will flag them as invalid. Suggest the user run `syntaur doctor` and either re-add the status (`syntaur status add ...`) or edit each frontmatter to a valid id.
63
63
  - **After `transition add`,** the dashboard's transition buttons reflect the new transition only after the cache invalidation above.
64
64
 
65
+ ## Custom facts and attestations
66
+
67
+ Beyond the 14 built-in derived-status facts, users can declare their **own** facts under `statuses.facts` and reference them in `phaseLadder` / `disposition` conditions. There are two kinds.
68
+
69
+ **1. Custom asserted facts** — config-declared `bool` / `number` values, asserted via `syntaur fact set` and stored in a `facts:` frontmatter map:
70
+
71
+ ```yaml
72
+ statuses:
73
+ facts:
74
+ - name: qaPassed
75
+ type: bool
76
+ - name: storyPoints
77
+ type: number
78
+ ```
79
+
80
+ ```bash
81
+ syntaur fact set <assignment> qaPassed true --project <p>
82
+ syntaur fact set <assignment> storyPoints 5 --project <p>
83
+ ```
84
+
85
+ `bool` accepts case-insensitive `true`/`false`; `number` accepts any finite number. The declared `name` exports a single derive field of the same name (`qaPassed:true`, `storyPoints > 3`). Stored in frontmatter as `facts:\n qaPassed: "true"`.
86
+
87
+ **2. Attestation facts** — model "agent X reviewed revision Y with verdict Z". Declared with `type: attestation` and a `binds:` mode:
88
+
89
+ ```yaml
90
+ statuses:
91
+ facts:
92
+ - name: codeReview
93
+ type: attestation
94
+ binds: plan # plan | commit | none
95
+ ```
96
+
97
+ ```bash
98
+ syntaur attest <assignment> codeReview --agent codex --verdict approved --project <p>
99
+ syntaur attest <assignment> codeReview --agent pi --verdict changes-requested --note "fix the lock" --project <p>
100
+ ```
101
+
102
+ `--verdict` defaults to `approved` (the other value is `changes-requested`). One record per actor — re-attesting **replaces** that actor's record. Stored in an `attestations:` frontmatter list (`{fact, actor, verdict, at, note?}` + binding snapshot).
103
+
104
+ Each attestation fact exports **five** derive fields (for `codeReview`): `codeReview` (any valid record), `codeReviewApproved`, `codeReviewChangesRequested` (bools), and `codeReviewBy`, `codeReviewApprovedBy` (actor **sets** — use `:` for contains / `IN`-lists, e.g. `codeReviewApprovedBy:"agent:codex"`; quote actor values that contain a `:`). This makes review loops self-modeling — a rung `when: "codeReviewApproved:true"` fires on approval, and `when: "codeReviewChangesRequested:true"` expresses "reviewed but not signed off".
105
+
106
+ **Revision binding** is what makes attestations self-invalidate:
107
+ - `binds: plan` — bound to the latest plan file + its digest (same semantics as plan approval). A replan or a post-attest plan edit makes the record **stale**; stale records contribute nothing (the fact flips false, the actor drops out of the `*By` sets).
108
+ - `binds: commit` — bound to the workspace branch HEAD sha at attest time. A new commit makes it stale. **Lazy convergence:** dashboard payloads and `ls --query` compute facts fresh per request (always honest), but the *persisted* phase regression lands on the next recompute trigger (any CLI verb, watcher event, config change, or boot sweep) — there is no git watcher.
109
+ - `binds: none` — never stale (a standing sign-off).
110
+
111
+ **Validation & teeth.** Declared names are validated by `syntaur doctor` (the `derive-config.valid` check): bad name/type/binds and any collision of an exported field with a built-in or another declaration is reported as an error and the offending declaration is dropped (built-ins always win). A derive condition that references an **undeclared** fact still fails at recompute time (`CompileError`), exactly as before. `syntaur fact set` / `syntaur attest` reject undeclared names, wrong types, and invalid verdicts. Every `fact set` / `attest` is recorded in `statusHistory` with its actor and cause, even when no dimension moves.
112
+
65
113
  ## Safety notes
66
114
 
67
115
  - **`remove` is destructive.** Without `--force` it refuses if any assignment references the id. Don't suggest `--force` without first running `syntaur status remove <id>` (no force) so the user sees the affected list.
68
116
  - **`rename` rewrites many files.** It edits `config.md` AND every affected `assignment.md` in a single atomic transaction (with rollback if any write fails partway). Always run `--dry-run` first on a non-trivial codebase so the user sees the per-file diff.
69
117
  - **`terminal: true` is load-bearing.** Terminal statuses affect dashboard progress bars and dependency-satisfaction logic — an assignment with a terminal status counts as "done" for downstream `dependsOn` checks and project-rollup status. Don't toggle this on `pending`-style states without thinking.
70
- - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations.
118
+ - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations. It resets to the built-in defaults and therefore **drops any `statuses.facts` declarations and `derive` rules** along with the custom statuses — every other `status` subcommand (`set`/`add`/`remove`/`rename`/`reorder`/`transition`) preserves them.
71
119
  - **Concurrency.** `rename`'s buffer-write-rollback strategy assumes no concurrent writers. Tell the user to close the dashboard / pause other agents during a rename.
72
120
  - **`SYNTAUR_HOME` precedence.** If the user has `SYNTAUR_HOME` set, the CLI writes there instead of `~/.syntaur`. Mirror their environment.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syntaur",
3
- "version": "0.43.1",
3
+ "version": "0.44.0",
4
4
  "description": "Run Syntaur project and assignment workflows from Codex, including claiming work, planning, completing handoffs, session/server tracking, save-session-summary continuity, and write-boundary enforcement.",
5
5
  "author": {
6
6
  "name": "Brennen"
@@ -62,11 +62,59 @@ After every mutating subcommand, run `syntaur status list` (or `--json` for mach
62
62
  - **After a `remove --force`,** the affected assignments now reference an undefined status. `syntaur doctor` will flag them as invalid. Suggest the user run `syntaur doctor` and either re-add the status (`syntaur status add ...`) or edit each frontmatter to a valid id.
63
63
  - **After `transition add`,** the dashboard's transition buttons reflect the new transition only after the cache invalidation above.
64
64
 
65
+ ## Custom facts and attestations
66
+
67
+ Beyond the 14 built-in derived-status facts, users can declare their **own** facts under `statuses.facts` and reference them in `phaseLadder` / `disposition` conditions. There are two kinds.
68
+
69
+ **1. Custom asserted facts** — config-declared `bool` / `number` values, asserted via `syntaur fact set` and stored in a `facts:` frontmatter map:
70
+
71
+ ```yaml
72
+ statuses:
73
+ facts:
74
+ - name: qaPassed
75
+ type: bool
76
+ - name: storyPoints
77
+ type: number
78
+ ```
79
+
80
+ ```bash
81
+ syntaur fact set <assignment> qaPassed true --project <p>
82
+ syntaur fact set <assignment> storyPoints 5 --project <p>
83
+ ```
84
+
85
+ `bool` accepts case-insensitive `true`/`false`; `number` accepts any finite number. The declared `name` exports a single derive field of the same name (`qaPassed:true`, `storyPoints > 3`). Stored in frontmatter as `facts:\n qaPassed: "true"`.
86
+
87
+ **2. Attestation facts** — model "agent X reviewed revision Y with verdict Z". Declared with `type: attestation` and a `binds:` mode:
88
+
89
+ ```yaml
90
+ statuses:
91
+ facts:
92
+ - name: codeReview
93
+ type: attestation
94
+ binds: plan # plan | commit | none
95
+ ```
96
+
97
+ ```bash
98
+ syntaur attest <assignment> codeReview --agent codex --verdict approved --project <p>
99
+ syntaur attest <assignment> codeReview --agent pi --verdict changes-requested --note "fix the lock" --project <p>
100
+ ```
101
+
102
+ `--verdict` defaults to `approved` (the other value is `changes-requested`). One record per actor — re-attesting **replaces** that actor's record. Stored in an `attestations:` frontmatter list (`{fact, actor, verdict, at, note?}` + binding snapshot).
103
+
104
+ Each attestation fact exports **five** derive fields (for `codeReview`): `codeReview` (any valid record), `codeReviewApproved`, `codeReviewChangesRequested` (bools), and `codeReviewBy`, `codeReviewApprovedBy` (actor **sets** — use `:` for contains / `IN`-lists, e.g. `codeReviewApprovedBy:"agent:codex"`; quote actor values that contain a `:`). This makes review loops self-modeling — a rung `when: "codeReviewApproved:true"` fires on approval, and `when: "codeReviewChangesRequested:true"` expresses "reviewed but not signed off".
105
+
106
+ **Revision binding** is what makes attestations self-invalidate:
107
+ - `binds: plan` — bound to the latest plan file + its digest (same semantics as plan approval). A replan or a post-attest plan edit makes the record **stale**; stale records contribute nothing (the fact flips false, the actor drops out of the `*By` sets).
108
+ - `binds: commit` — bound to the workspace branch HEAD sha at attest time. A new commit makes it stale. **Lazy convergence:** dashboard payloads and `ls --query` compute facts fresh per request (always honest), but the *persisted* phase regression lands on the next recompute trigger (any CLI verb, watcher event, config change, or boot sweep) — there is no git watcher.
109
+ - `binds: none` — never stale (a standing sign-off).
110
+
111
+ **Validation & teeth.** Declared names are validated by `syntaur doctor` (the `derive-config.valid` check): bad name/type/binds and any collision of an exported field with a built-in or another declaration is reported as an error and the offending declaration is dropped (built-ins always win). A derive condition that references an **undeclared** fact still fails at recompute time (`CompileError`), exactly as before. `syntaur fact set` / `syntaur attest` reject undeclared names, wrong types, and invalid verdicts. Every `fact set` / `attest` is recorded in `statusHistory` with its actor and cause, even when no dimension moves.
112
+
65
113
  ## Safety notes
66
114
 
67
115
  - **`remove` is destructive.** Without `--force` it refuses if any assignment references the id. Don't suggest `--force` without first running `syntaur status remove <id>` (no force) so the user sees the affected list.
68
116
  - **`rename` rewrites many files.** It edits `config.md` AND every affected `assignment.md` in a single atomic transaction (with rollback if any write fails partway). Always run `--dry-run` first on a non-trivial codebase so the user sees the per-file diff.
69
117
  - **`terminal: true` is load-bearing.** Terminal statuses affect dashboard progress bars and dependency-satisfaction logic — an assignment with a terminal status counts as "done" for downstream `dependsOn` checks and project-rollup status. Don't toggle this on `pending`-style states without thinking.
70
- - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations.
118
+ - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations. It resets to the built-in defaults and therefore **drops any `statuses.facts` declarations and `derive` rules** along with the custom statuses — every other `status` subcommand (`set`/`add`/`remove`/`rename`/`reorder`/`transition`) preserves them.
71
119
  - **Concurrency.** `rename`'s buffer-write-rollback strategy assumes no concurrent writers. Tell the user to close the dashboard / pause other agents during a rename.
72
120
  - **`SYNTAUR_HOME` precedence.** If the user has `SYNTAUR_HOME` set, the CLI writes there instead of `~/.syntaur`. Mirror their environment.
@@ -62,11 +62,59 @@ After every mutating subcommand, run `syntaur status list` (or `--json` for mach
62
62
  - **After a `remove --force`,** the affected assignments now reference an undefined status. `syntaur doctor` will flag them as invalid. Suggest the user run `syntaur doctor` and either re-add the status (`syntaur status add ...`) or edit each frontmatter to a valid id.
63
63
  - **After `transition add`,** the dashboard's transition buttons reflect the new transition only after the cache invalidation above.
64
64
 
65
+ ## Custom facts and attestations
66
+
67
+ Beyond the 14 built-in derived-status facts, users can declare their **own** facts under `statuses.facts` and reference them in `phaseLadder` / `disposition` conditions. There are two kinds.
68
+
69
+ **1. Custom asserted facts** — config-declared `bool` / `number` values, asserted via `syntaur fact set` and stored in a `facts:` frontmatter map:
70
+
71
+ ```yaml
72
+ statuses:
73
+ facts:
74
+ - name: qaPassed
75
+ type: bool
76
+ - name: storyPoints
77
+ type: number
78
+ ```
79
+
80
+ ```bash
81
+ syntaur fact set <assignment> qaPassed true --project <p>
82
+ syntaur fact set <assignment> storyPoints 5 --project <p>
83
+ ```
84
+
85
+ `bool` accepts case-insensitive `true`/`false`; `number` accepts any finite number. The declared `name` exports a single derive field of the same name (`qaPassed:true`, `storyPoints > 3`). Stored in frontmatter as `facts:\n qaPassed: "true"`.
86
+
87
+ **2. Attestation facts** — model "agent X reviewed revision Y with verdict Z". Declared with `type: attestation` and a `binds:` mode:
88
+
89
+ ```yaml
90
+ statuses:
91
+ facts:
92
+ - name: codeReview
93
+ type: attestation
94
+ binds: plan # plan | commit | none
95
+ ```
96
+
97
+ ```bash
98
+ syntaur attest <assignment> codeReview --agent codex --verdict approved --project <p>
99
+ syntaur attest <assignment> codeReview --agent pi --verdict changes-requested --note "fix the lock" --project <p>
100
+ ```
101
+
102
+ `--verdict` defaults to `approved` (the other value is `changes-requested`). One record per actor — re-attesting **replaces** that actor's record. Stored in an `attestations:` frontmatter list (`{fact, actor, verdict, at, note?}` + binding snapshot).
103
+
104
+ Each attestation fact exports **five** derive fields (for `codeReview`): `codeReview` (any valid record), `codeReviewApproved`, `codeReviewChangesRequested` (bools), and `codeReviewBy`, `codeReviewApprovedBy` (actor **sets** — use `:` for contains / `IN`-lists, e.g. `codeReviewApprovedBy:"agent:codex"`; quote actor values that contain a `:`). This makes review loops self-modeling — a rung `when: "codeReviewApproved:true"` fires on approval, and `when: "codeReviewChangesRequested:true"` expresses "reviewed but not signed off".
105
+
106
+ **Revision binding** is what makes attestations self-invalidate:
107
+ - `binds: plan` — bound to the latest plan file + its digest (same semantics as plan approval). A replan or a post-attest plan edit makes the record **stale**; stale records contribute nothing (the fact flips false, the actor drops out of the `*By` sets).
108
+ - `binds: commit` — bound to the workspace branch HEAD sha at attest time. A new commit makes it stale. **Lazy convergence:** dashboard payloads and `ls --query` compute facts fresh per request (always honest), but the *persisted* phase regression lands on the next recompute trigger (any CLI verb, watcher event, config change, or boot sweep) — there is no git watcher.
109
+ - `binds: none` — never stale (a standing sign-off).
110
+
111
+ **Validation & teeth.** Declared names are validated by `syntaur doctor` (the `derive-config.valid` check): bad name/type/binds and any collision of an exported field with a built-in or another declaration is reported as an error and the offending declaration is dropped (built-ins always win). A derive condition that references an **undeclared** fact still fails at recompute time (`CompileError`), exactly as before. `syntaur fact set` / `syntaur attest` reject undeclared names, wrong types, and invalid verdicts. Every `fact set` / `attest` is recorded in `statusHistory` with its actor and cause, even when no dimension moves.
112
+
65
113
  ## Safety notes
66
114
 
67
115
  - **`remove` is destructive.** Without `--force` it refuses if any assignment references the id. Don't suggest `--force` without first running `syntaur status remove <id>` (no force) so the user sees the affected list.
68
116
  - **`rename` rewrites many files.** It edits `config.md` AND every affected `assignment.md` in a single atomic transaction (with rollback if any write fails partway). Always run `--dry-run` first on a non-trivial codebase so the user sees the per-file diff.
69
117
  - **`terminal: true` is load-bearing.** Terminal statuses affect dashboard progress bars and dependency-satisfaction logic — an assignment with a terminal status counts as "done" for downstream `dependsOn` checks and project-rollup status. Don't toggle this on `pending`-style states without thinking.
70
- - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations.
118
+ - **`init --force` overwrites a custom block.** Use `reset` first if the user wants a clean slate, OR confirm before passing `--force` if they have unsaved customizations. It resets to the built-in defaults and therefore **drops any `statuses.facts` declarations and `derive` rules** along with the custom statuses — every other `status` subcommand (`set`/`add`/`remove`/`rename`/`reorder`/`transition`) preserves them.
71
119
  - **Concurrency.** `rename`'s buffer-write-rollback strategy assumes no concurrent writers. Tell the user to close the dashboard / pause other agents during a rename.
72
120
  - **`SYNTAUR_HOME` precedence.** If the user has `SYNTAUR_HOME` set, the CLI writes there instead of `~/.syntaur`. Mirror their environment.
@@ -1 +0,0 @@
1
- import{aq as o,ar as n}from"./mermaid.core-eqq1_dL_.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-DV11wZKH.js";import{_ as i}from"./mermaid.core-eqq1_dL_.js";import"./chunk-FMBD7UC4-CWHswGwW.js";import"./chunk-JSJVCQXG-DnsqdfIB.js";import"./chunk-55IACEB6-DE34igmQ.js";import"./chunk-KX2RTZJC-FbqVE08c.js";import"./index-Dzh96P4Z.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-DV11wZKH.js";import{_ as i}from"./mermaid.core-eqq1_dL_.js";import"./chunk-FMBD7UC4-CWHswGwW.js";import"./chunk-JSJVCQXG-DnsqdfIB.js";import"./chunk-55IACEB6-DE34igmQ.js";import"./chunk-KX2RTZJC-FbqVE08c.js";import"./index-Dzh96P4Z.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{b as r}from"./_baseUniq-DGO4Y46J.js";var e=4;function a(o){return r(o,e)}export{a as c};
@@ -1 +0,0 @@
1
- import{s as e,b as r,a,S as s}from"./chunk-NQ4KR5QH-DcsdDqWQ.js";import{_ as i}from"./mermaid.core-eqq1_dL_.js";import"./chunk-55IACEB6-DE34igmQ.js";import"./chunk-KX2RTZJC-FbqVE08c.js";import"./index-Dzh96P4Z.js";var p={parser:a,get db(){return new s(2)},renderer:r,styles:e,init:i(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{p as diagram};