heyspex 0.1.0 → 0.2.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 (322) hide show
  1. package/README.md +21 -0
  2. package/bin/hs.mjs +931 -98
  3. package/bin/spexcode.mjs +262 -0
  4. package/dev-factory/engine/worktree.mjs +740 -0
  5. package/dev-factory/lib/code-repo-root.mjs +67 -0
  6. package/dev-factory/lib/context-budget.mjs +84 -0
  7. package/dev-factory/lib/epic-detect.mjs +190 -0
  8. package/dev-factory/lib/fleet-queue-file.mjs +846 -0
  9. package/dev-factory/lib/fleet-queue.mjs +426 -0
  10. package/dev-factory/lib/fleet-state.mjs +14 -18
  11. package/dev-factory/lib/model-catalog.mjs +338 -0
  12. package/dev-factory/lib/seat-context.mjs +199 -0
  13. package/dev-factory/lib/spec-io.mjs +93 -0
  14. package/dev-factory/lib/sufficiency-score.mjs +8 -2
  15. package/dev-factory/lib/worktree-allocator.mjs +744 -0
  16. package/dev-factory/model-catalog.json +222 -0
  17. package/dist/cli/hs-check.mjs +1085 -103
  18. package/dist/cli/hs-claim.mjs +936 -63
  19. package/dist/cli/hs-connect.mjs +9786 -1910
  20. package/dist/cli/hs-defer.mjs +5267 -3053
  21. package/dist/cli/hs-dev.mjs +564 -0
  22. package/dist/cli/hs-env.mjs +385 -299
  23. package/dist/cli/hs-index-rebuild.mjs +7129 -0
  24. package/dist/cli/hs-index-reconcile.mjs +7852 -0
  25. package/dist/cli/hs-init.mjs +777 -138
  26. package/dist/cli/hs-install.mjs +6583 -485
  27. package/dist/cli/hs-join.mjs +10137 -2368
  28. package/dist/cli/hs-vault-pull.mjs +4659 -5882
  29. package/dist/cli/hs-vault.mjs +3793 -1537
  30. package/dist/cli/hs-workspace.mjs +2550 -524
  31. package/dist/cli-templates/customer-vault/specs/entity-model.md +594 -601
  32. package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +110 -177
  33. package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -0
  34. package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +13 -15
  35. package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +91 -0
  36. package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +150 -168
  37. package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -0
  38. package/dist/cli-templates/harness-commands/claude/hs-auto.md +36 -0
  39. package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -0
  40. package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -0
  41. package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -0
  42. package/dist/cli-templates/harness-commands/claude/hs-dev.md +20 -0
  43. package/dist/cli-templates/harness-commands/claude/hs-doctor.md +32 -0
  44. package/dist/cli-templates/harness-commands/claude/hs-ground.md +28 -0
  45. package/dist/cli-templates/harness-commands/claude/hs-handoff.md +33 -0
  46. package/dist/cli-templates/harness-commands/claude/hs-log.md +27 -0
  47. package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -0
  48. package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -0
  49. package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -0
  50. package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -0
  51. package/dist/cli-templates/harness-commands/claude/hs-res.md +63 -0
  52. package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -0
  53. package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -0
  54. package/dist/cli-templates/harness-commands/claude/hs-view.md +26 -0
  55. package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -0
  56. package/dist/cli-templates/harness-commands/claude/prototype.md +91 -0
  57. package/dist/cli-templates/harness-commands/cursor/hs-auto.md +40 -0
  58. package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +31 -0
  59. package/dist/cli-templates/harness-commands/cursor/hs-capture.md +65 -0
  60. package/dist/cli-templates/harness-commands/cursor/hs-defer.md +32 -0
  61. package/dist/cli-templates/harness-commands/cursor/hs-dev.md +24 -0
  62. package/dist/cli-templates/harness-commands/cursor/hs-doctor.md +36 -0
  63. package/dist/cli-templates/harness-commands/cursor/hs-ground.md +31 -0
  64. package/dist/cli-templates/harness-commands/cursor/hs-handoff.md +37 -0
  65. package/dist/cli-templates/harness-commands/cursor/hs-log.md +31 -0
  66. package/dist/cli-templates/harness-commands/cursor/hs-next.md +32 -0
  67. package/dist/cli-templates/harness-commands/cursor/hs-promote.md +73 -0
  68. package/dist/cli-templates/harness-commands/cursor/hs-push.md +38 -0
  69. package/dist/cli-templates/harness-commands/cursor/hs-qc.md +30 -0
  70. package/dist/cli-templates/harness-commands/cursor/hs-res.md +67 -0
  71. package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +26 -0
  72. package/dist/cli-templates/harness-commands/cursor/hs-review.md +26 -0
  73. package/dist/cli-templates/harness-commands/cursor/hs-view.md +30 -0
  74. package/dist/cli-templates/harness-commands/cursor/kill-ports.md +35 -0
  75. package/dist/cli-templates/harness-commands/cursor/prototype.md +95 -0
  76. package/docs/mcp-client-config.md +259 -6
  77. package/package.json +231 -124
  78. package/plugins/heyspex/.claude-plugin/plugin.json +12 -0
  79. package/plugins/heyspex/.cursor-plugin/plugin.json +15 -0
  80. package/plugins/heyspex/.mcp.json +12 -0
  81. package/plugins/heyspex/bin/launch-mcp.mjs +95 -0
  82. package/plugins/heyspex/bin/run-hook.mjs +62 -0
  83. package/plugins/heyspex/hooks/cursor-hooks.json +227 -0
  84. package/plugins/heyspex/hooks/hooks.json +361 -0
  85. package/plugins/heyspex/mcp.json +13 -0
  86. package/scripts/check-mcp-freshness.mjs +17 -9
  87. package/scripts/claude-hooks/_env-vault-events.mjs +68 -0
  88. package/scripts/claude-hooks/_guardrail-events.mjs +96 -0
  89. package/scripts/claude-hooks/_guardrail-loader.mjs +494 -0
  90. package/scripts/claude-hooks/_intent-classifier-router.mjs +410 -0
  91. package/scripts/claude-hooks/_intent-classifier-semantic.mjs +351 -0
  92. package/scripts/claude-hooks/_run.mjs +120 -0
  93. package/scripts/claude-hooks/_transcript-text.mjs +60 -0
  94. package/scripts/claude-hooks/_vault-retrieval.mjs +322 -0
  95. package/scripts/claude-hooks/agent-spawn-delegation-gate.mjs +133 -0
  96. package/scripts/claude-hooks/capture-workflow-gate.mjs +11 -0
  97. package/scripts/claude-hooks/check-auto-memory-budget.mjs +396 -0
  98. package/scripts/claude-hooks/check-claude-md-budget.mjs +327 -0
  99. package/scripts/claude-hooks/check-mcp-freshness-hook.mjs +14 -0
  100. package/scripts/claude-hooks/claim-before-code-gate.mjs +11 -0
  101. package/scripts/claude-hooks/claim-liveness-shared.mjs +575 -0
  102. package/scripts/claude-hooks/close-terminal-on-ship.mjs +64 -0
  103. package/scripts/claude-hooks/coo-denylist-gate.mjs +11 -0
  104. package/scripts/claude-hooks/coo-guard-check.mjs +11 -0
  105. package/scripts/claude-hooks/deep-research-cost-gate.mjs +11 -0
  106. package/scripts/claude-hooks/dev-server-task-reminder.mjs +15 -0
  107. package/scripts/claude-hooks/emit-claim-status.mjs +41 -0
  108. package/scripts/claude-hooks/enforce-session-sequence.mjs +11 -0
  109. package/scripts/claude-hooks/enforce-vault-naming.mjs +11 -0
  110. package/scripts/claude-hooks/env-vault-guard.mjs +11 -0
  111. package/scripts/claude-hooks/epic-milestone-phrasing-gate.mjs +11 -0
  112. package/scripts/claude-hooks/git-identity-guard.mjs +11 -0
  113. package/scripts/claude-hooks/git-reflog-audit.mjs +15 -0
  114. package/scripts/claude-hooks/git-stash-gate.mjs +11 -0
  115. package/scripts/claude-hooks/guard-auto-memory-writes.mjs +137 -0
  116. package/scripts/claude-hooks/id-display-format-gate.mjs +11 -0
  117. package/scripts/claude-hooks/inject-communication-style.mjs +66 -0
  118. package/scripts/claude-hooks/inject-coo-seat.mjs +78 -0
  119. package/scripts/claude-hooks/inject-dev-server-awareness.mjs +11 -0
  120. package/scripts/claude-hooks/inject-doctrine.mjs +13 -0
  121. package/scripts/claude-hooks/inject-vault-context.mjs +14 -0
  122. package/scripts/claude-hooks/intent-classifier-trigger.mjs +247 -0
  123. package/scripts/claude-hooks/log-session-activity.mjs +341 -0
  124. package/scripts/claude-hooks/naughty-list-gate.mjs +11 -0
  125. package/scripts/claude-hooks/notify-status-flip.mjs +72 -0
  126. package/scripts/claude-hooks/plan-exit-ingest-gate.mjs +170 -0
  127. package/scripts/claude-hooks/plan-ingest-close-reminder.mjs +66 -0
  128. package/scripts/claude-hooks/plan-review-gate.mjs +11 -0
  129. package/scripts/claude-hooks/preflight-reminder.mjs +262 -0
  130. package/scripts/claude-hooks/protected-action-intent.mjs +221 -0
  131. package/scripts/claude-hooks/research-method-guard.mjs +398 -0
  132. package/scripts/claude-hooks/research-protocol-gate.mjs +11 -0
  133. package/scripts/claude-hooks/session-end.mjs +449 -0
  134. package/scripts/claude-hooks/settings-write-gate.mjs +11 -0
  135. package/scripts/claude-hooks/settlement-check-gate.mjs +39 -0
  136. package/scripts/claude-hooks/status-flip-detect.mjs +17 -0
  137. package/scripts/claude-hooks/terminal-close-shared.mjs +426 -0
  138. package/scripts/claude-hooks/terminal-close-watcher.mjs +122 -0
  139. package/scripts/claude-hooks/wip-checkpoint.mjs +298 -0
  140. package/scripts/cursor-hooks/manifest.mjs +235 -0
  141. package/scripts/dev-server-status.mjs +34 -13
  142. package/scripts/dev-server-stop.mjs +313 -0
  143. package/scripts/heyspex-mode.mjs +268 -0
  144. package/scripts/hs-auto-resolve.mjs +240 -0
  145. package/scripts/hs-auto-source.mjs +398 -0
  146. package/scripts/hs-auto.mjs +134 -0
  147. package/scripts/hs-capture-cli.mjs +326 -0
  148. package/scripts/hs-classifier.mjs +136 -0
  149. package/scripts/hs-companion.mjs +88 -0
  150. package/scripts/hs-gateway.mjs +115 -0
  151. package/scripts/hs-mode.mjs +125 -0
  152. package/scripts/hs-next.mjs +441 -0
  153. package/scripts/hs-settings.mjs +338 -0
  154. package/scripts/hs-view.mjs +333 -0
  155. package/scripts/hs-worktree.mjs +201 -0
  156. package/scripts/install-claude-code-hooks.mjs +270 -0
  157. package/scripts/install-cursor-hooks.mjs +471 -0
  158. package/scripts/lib/agent-env-markers.mjs +38 -0
  159. package/scripts/lib/console-url-resolver.mjs +197 -60
  160. package/scripts/lib/customer-kit.mjs +886 -0
  161. package/scripts/lib/dev-mode.mjs +244 -28
  162. package/scripts/lib/heyspex-home.mjs +72 -0
  163. package/scripts/lib/hs-command.mjs +277 -0
  164. package/scripts/lib/hs-companion-settings.mjs +472 -0
  165. package/scripts/lib/hs-source-commit.mjs +59 -5
  166. package/scripts/lib/hs-source-identity.mjs +526 -0
  167. package/scripts/lib/hs-source-log.mjs +11 -21
  168. package/scripts/lib/hs-source-push.mjs +107 -58
  169. package/scripts/lib/hs-worktree-args.mjs +115 -0
  170. package/scripts/lib/shared-path-helpers.mjs +134 -0
  171. package/scripts/lib/standalone-doctor.mjs +540 -3
  172. package/scripts/lib/subagent-git-lock.mjs +109 -0
  173. package/scripts/lib/template-pin.mjs +34 -0
  174. package/scripts/provenance-lib.mjs +91 -0
  175. package/scripts/stamp-provenance-on-edit.mjs +222 -0
  176. package/scripts/wip-ledger-health.mjs +653 -0
  177. package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -0
  178. package/spexharness/src/adapters/audit.mjs +197 -0
  179. package/spexharness/src/adapters/claude-code.mjs +441 -0
  180. package/spexharness/src/chat/tui/ansi.mjs +448 -0
  181. package/spexharness/src/chat/tui/palette.mjs +22 -0
  182. package/spexharness/src/chat/tui/select.mjs +208 -0
  183. package/spexharness/src/config-root.mjs +54 -0
  184. package/spexharness/src/context-budget.mjs +141 -0
  185. package/spexharness/src/dev-server-control.mjs +389 -0
  186. package/spexharness/src/doctrine/behaviour.mjs +371 -0
  187. package/spexharness/src/doctrine/corpus.mjs +733 -0
  188. package/spexharness/src/doctrine/inject.mjs +338 -0
  189. package/spexharness/src/doctrine/merge.mjs +184 -0
  190. package/spexharness/src/doctrine/sources.mjs +252 -0
  191. package/spexharness/src/doctrine/synthesize.mjs +401 -0
  192. package/spexharness/src/doctrine/vault-source.mjs +574 -0
  193. package/spexharness/src/doctrine/writer.mjs +176 -0
  194. package/spexharness/src/events.mjs +84 -0
  195. package/spexharness/src/gates/capture-workflow-gate.mjs +202 -0
  196. package/spexharness/src/gates/claim-before-code-gate.decide.mjs +33 -0
  197. package/spexharness/src/gates/claim-before-code-gate.mjs +129 -0
  198. package/spexharness/src/gates/deep-research-cost-gate.mjs +274 -0
  199. package/spexharness/src/gates/enforce-session-sequence.mjs +895 -0
  200. package/spexharness/src/gates/enforce-vault-naming.mjs +215 -0
  201. package/spexharness/src/gates/epic-milestone-phrasing-gate.mjs +233 -0
  202. package/spexharness/src/gates/git-identity-guard.decide.mjs +436 -0
  203. package/spexharness/src/gates/git-identity-guard.mjs +61 -0
  204. package/spexharness/src/gates/git-reflog-audit.mjs +151 -0
  205. package/spexharness/src/gates/git-stash-gate.decide.mjs +361 -0
  206. package/spexharness/src/gates/git-stash-gate.mjs +159 -0
  207. package/spexharness/src/gates/id-display-format-gate.mjs +190 -0
  208. package/spexharness/src/gates/inject-doctrine-gate.mjs +89 -0
  209. package/spexharness/src/gates/inject-vault-context.mjs +239 -0
  210. package/spexharness/src/gates/naughty-list-gate.mjs +213 -0
  211. package/spexharness/src/gates/plan-review-gate.mjs +233 -0
  212. package/spexharness/src/gates/preflight-reminder-gate.mjs +265 -0
  213. package/spexharness/src/gates/research-protocol-gate.mjs +175 -0
  214. package/spexharness/src/gates/settings-write-gate.decide.mjs +96 -0
  215. package/spexharness/src/gates/settings-write-gate.mjs +104 -0
  216. package/spexharness/src/git-reflog-audit.mjs +294 -0
  217. package/spexharness/src/intent-classifier.mjs +194 -0
  218. package/spexharness/src/intent-directive.mjs +541 -0
  219. package/spexharness/src/profile/learn.mjs +551 -0
  220. package/spexharness/src/profile/proposals.mjs +357 -0
  221. package/spexharness/src/profile/vault-inclusion.mjs +386 -0
  222. package/spexharness/src/redact.mjs +151 -0
  223. package/spexharness/src/rule-table.mjs +819 -0
  224. package/spexharness/src/seat-context.mjs +122 -0
  225. package/spexharness/src/session-bootstrap.mjs +512 -0
  226. package/spexharness/src/session-record.mjs +815 -0
  227. package/spexharness/src/token-inventory.mjs +207 -0
  228. package/vendor/heyspex-mcp/account-switch.mjs +95 -0
  229. package/vendor/heyspex-mcp/alignment-gate.mjs +315 -1
  230. package/vendor/heyspex-mcp/blocker-resolver.mjs +37 -2
  231. package/vendor/heyspex-mcp/breakdown-ladder.mjs +119 -4
  232. package/vendor/heyspex-mcp/breakdown-source.mjs +271 -0
  233. package/vendor/heyspex-mcp/breakdown-writer.mjs +23 -3
  234. package/vendor/heyspex-mcp/capture-buffer-patches.mjs +46 -5
  235. package/vendor/heyspex-mcp/capture-channel.mjs +55 -5
  236. package/vendor/heyspex-mcp/capture-console-client.mjs +80 -1
  237. package/vendor/heyspex-mcp/capture-focus.mjs +1035 -29
  238. package/vendor/heyspex-mcp/capture-outbox.mjs +5 -1
  239. package/vendor/heyspex-mcp/capture-tools.mjs +1219 -0
  240. package/vendor/heyspex-mcp/claim-tools.mjs +1124 -0
  241. package/vendor/heyspex-mcp/cli-verbs.mjs +2076 -0
  242. package/vendor/heyspex-mcp/cli.mjs +201 -15524
  243. package/vendor/heyspex-mcp/cloud-tool-surface.mjs +128 -0
  244. package/vendor/heyspex-mcp/cloud-vault-writes.mjs +412 -0
  245. package/vendor/heyspex-mcp/config-seed.yaml +15 -0
  246. package/vendor/heyspex-mcp/config-settings.mjs +290 -7
  247. package/vendor/heyspex-mcp/console-fetch.mjs +657 -16
  248. package/vendor/heyspex-mcp/console-transport.mjs +166 -0
  249. package/vendor/heyspex-mcp/credentials.mjs +584 -0
  250. package/vendor/heyspex-mcp/defer-spec.mjs +44 -4
  251. package/vendor/heyspex-mcp/deferred-reclaim.mjs +29 -3
  252. package/vendor/heyspex-mcp/design-handlers.mjs +31 -0
  253. package/vendor/heyspex-mcp/design-tools.mjs +4 -1
  254. package/vendor/heyspex-mcp/dev-factory-bridge.mjs +4 -4
  255. package/vendor/heyspex-mcp/dev-mode-core.mjs +45 -0
  256. package/vendor/heyspex-mcp/dev-tools.mjs +124 -0
  257. package/vendor/heyspex-mcp/diagnose-handlers.mjs +54 -0
  258. package/vendor/heyspex-mcp/events-tools.mjs +207 -0
  259. package/vendor/heyspex-mcp/filing-tools.mjs +688 -0
  260. package/vendor/heyspex-mcp/fleet-handlers.mjs +37 -0
  261. package/vendor/heyspex-mcp/fleet-queue-tools.mjs +69 -14
  262. package/vendor/heyspex-mcp/focus-tools.mjs +190 -0
  263. package/vendor/heyspex-mcp/folder-trust-store.mjs +59 -0
  264. package/vendor/heyspex-mcp/http-transport.mjs +300 -0
  265. package/vendor/heyspex-mcp/list-tools.mjs +257 -0
  266. package/vendor/heyspex-mcp/login-handoff.mjs +15 -1
  267. package/vendor/heyspex-mcp/mcp-config.mjs +94 -0
  268. package/vendor/heyspex-mcp/memory-tools.mjs +523 -0
  269. package/vendor/heyspex-mcp/mvp-mode.mjs +53 -6
  270. package/vendor/heyspex-mcp/occupied-keys.mjs +141 -0
  271. package/vendor/heyspex-mcp/on-deck-brief.mjs +3360 -0
  272. package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -0
  273. package/vendor/heyspex-mcp/package-root.mjs +32 -0
  274. package/vendor/heyspex-mcp/peer-presence.mjs +8 -1
  275. package/vendor/heyspex-mcp/plan-ground.mjs +621 -652
  276. package/vendor/heyspex-mcp/plan-push.mjs +906 -21
  277. package/vendor/heyspex-mcp/plan-review.mjs +124 -30
  278. package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
  279. package/vendor/heyspex-mcp/procedure-handlers.mjs +325 -0
  280. package/vendor/heyspex-mcp/procedure-tools.mjs +540 -351
  281. package/vendor/heyspex-mcp/promote-capture.mjs +386 -69
  282. package/vendor/heyspex-mcp/promote-diagnose.mjs +74 -0
  283. package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +9 -2
  284. package/vendor/heyspex-mcp/promote-research.mjs +660 -53
  285. package/vendor/heyspex-mcp/promotion-helpers.mjs +251 -0
  286. package/vendor/heyspex-mcp/prompts.mjs +1460 -0
  287. package/vendor/heyspex-mcp/read-path.mjs +29 -9
  288. package/vendor/heyspex-mcp/receipt-shape.mjs +146 -0
  289. package/vendor/heyspex-mcp/recipe-handlers.mjs +117 -0
  290. package/vendor/heyspex-mcp/regen-tasks.mjs +210 -3
  291. package/vendor/heyspex-mcp/register-spec.mjs +266 -54
  292. package/vendor/heyspex-mcp/request-context.mjs +59 -0
  293. package/vendor/heyspex-mcp/research-focus.mjs +207 -4
  294. package/vendor/heyspex-mcp/research-handlers.mjs +623 -0
  295. package/vendor/heyspex-mcp/research-tools.mjs +4 -4
  296. package/vendor/heyspex-mcp/response-budget.mjs +348 -0
  297. package/vendor/heyspex-mcp/review-focus.mjs +25 -1
  298. package/vendor/heyspex-mcp/search-specs.mjs +280 -0
  299. package/vendor/heyspex-mcp/seat-block-ledger.mjs +113 -0
  300. package/vendor/heyspex-mcp/seat-identity.mjs +2 -6
  301. package/vendor/heyspex-mcp/session-owner.mjs +108 -0
  302. package/vendor/heyspex-mcp/session-tools.mjs +152 -0
  303. package/vendor/heyspex-mcp/settings-registry.mjs +232 -0
  304. package/vendor/heyspex-mcp/settings-tools.mjs +85 -12
  305. package/vendor/heyspex-mcp/spec-edit-tools.mjs +446 -0
  306. package/vendor/heyspex-mcp/spec-id-lib.mjs +93 -17
  307. package/vendor/heyspex-mcp/split-research.mjs +301 -56
  308. package/vendor/heyspex-mcp/stdio-rpc.mjs +22 -0
  309. package/vendor/heyspex-mcp/submit-for-review.mjs +132 -6
  310. package/vendor/heyspex-mcp/summary-contract.mjs +105 -0
  311. package/vendor/heyspex-mcp/summary-write-tools.mjs +224 -0
  312. package/vendor/heyspex-mcp/symptom-query.mjs +146 -0
  313. package/vendor/heyspex-mcp/test-helpers.mjs +108 -1
  314. package/vendor/heyspex-mcp/tool-catalog.mjs +2813 -0
  315. package/vendor/heyspex-mcp/tool-dispatch.mjs +639 -0
  316. package/vendor/heyspex-mcp/tool-helpers.mjs +325 -0
  317. package/vendor/heyspex-mcp/validate-linkage.mjs +414 -27
  318. package/vendor/heyspex-mcp/vault-io.mjs +724 -0
  319. package/vendor/heyspex-mcp/vault-less-endpoints.mjs +52 -0
  320. package/vendor/heyspex-mcp/vault-resolve.mjs +366 -68
  321. package/vendor/heyspex-mcp/verify-reproduction.mjs +270 -30
  322. package/vendor/heyspex-mcp/whoami.mjs +91 -0
@@ -4,23 +4,17 @@ name: HeySpex Entity Model
4
4
  type: l2
5
5
  status: draft
6
6
  priority: 0
7
- owner: pwher
8
- assisted_by:
9
- - Claude Code
7
+ owner: TODO — your name/handle
10
8
  created: 2026-05-14
11
9
  updated: 2026-05-18
12
10
  tags: "[foundation, l2, entity-model, schema]"
13
- related:
14
- - "heyspex-north-star"
15
- - "HS-DOC-architecture-foundations"
16
- - "uc-ingest-anywhere"
17
- - "uc-voice-ingest-hey-spex"
18
- - "uc-capture-intent"
19
- - "companion-capture-inbox-and-bundles"
20
- - "HS-D1YU-OVFO-TASK-bundle-submit-composite-draft-source-set"
21
- - "ai-deliberation-gate"
22
11
  ---
23
12
 
13
+
14
+
15
+
16
+
17
+
24
18
  # HeySpex Entity Model
25
19
 
26
20
  > [!important] Constitutional dependency
@@ -35,7 +29,7 @@ This L2 spec defines the shape of every artifact that lives in a HeySpex vault:
35
29
  - **Entity type.** The value of the `type:` field in frontmatter. Determines which folder the spec lives in, which other fields are required, and how the spec is rendered in the console.
36
30
  - **Hierarchy level.** L1 / L2 / L3. Vision → architecture → use-case. A different axis from entity type. Some entity types are level-tagged (`type: l1`, `type: l2`, `type: l3`); most are not.
37
31
  - **Wikilink.** A reference of the form `[[link-target]]`, resolved by filename match across the vault.
38
- - **Memory (conceptual layer).** Durable project knowledge surfaced together in the console: `memory-lesson`, `memory-decision`, `memory-reference`, `memory-ux-principle`, `memory-ui-pattern`, and `protocol`. Protocols are filed under `specs/protocols/` on disk but are a **subsection of Memory** in navigation and in `hs prime` — not a peer of Memory beside Epics/Tasks. See memory-protocols-subsection-of-memory. Work to _create_ or change a protocol remains `type: epic` / `task`.
32
+ - **Memory (conceptual layer).** Durable project knowledge surfaced together in the console: `memory-lesson`, `memory-decision`, `memory-reference`, `memory-ux-principle`, `memory-ui-pattern`, and `protocol`. Protocols are filed under `specs/protocols/` on disk but are a **subsection of Memory** in navigation and in `hs prime` — not a peer of Memory beside Epics/Tasks. See memory-protocols-subsection-of-memory. Work to *create* or change a protocol remains `type: epic` / `task`.
39
33
 
40
34
  ## Vault root layout
41
35
 
@@ -134,7 +128,7 @@ Two committed siblings live **outside** `specs/` at the repo root, written/owned
134
128
  - **`heyspex.yaml`** — the top-level vault marker (`schema_version`, `console_url`, `vault_root`) written by `hs init` (HS-FD93-AEHR-EPIC-audit-export-heyspex-yaml-and-heyspex-retirement §2). `schema_version: 2` = the post-SCAH Neon-control-plane layout; `1` was the implicit pre-SCAH `.heyspex/`-files layout. The web companion reads it to bootstrap a vault.
135
129
  - **`.heyspex/`** — per-vault config home (adr-0009-heyspex-directory-contract): tracked `config.yaml`, `.gitignore`, `*.example` scaffolding templates, and `focus.yaml` (cross-machine pin SSOT, focus-yaml-is-tracked-pin-ssot). On the **free tier** (no Neon) this directory ALSO holds the live runtime state (`active-claims.json`, `claim-history.jsonl`, `focus-history.jsonl`); on the **paid tier** that state lives in Neon and these files are the export's free-tier source only (HS-7FA9-FREE-EPIC-zero-neon-local-only-tier). The audit export (`specs/events/`) reads whichever store is live for the tier.
136
130
 
137
- The L1 lives at the vault root as `heyspex-north-star.md`. The other L2 specs (`entity-model.md`, `architecture-foundations.md`, `principles.md`, `glossary.md`) also live at the root because they are foundational — in the console they surface under the **North Star** rail group, not Business (which is scoped to `business-*` types) or Memory (scoped to `memory-*` types). The glossary carries a `marketing` _tag_ because marketing copy consumes its definitions, but its `type: l2` keeps it in the foundational tier. Everything else is filed under a folder matching its entity type.
131
+ The L1 lives at the vault root as `heyspex-north-star.md`. The other L2 specs (`entity-model.md`, `architecture-foundations.md`, `principles.md`, `glossary.md`) also live at the root because they are foundational — in the console they surface under the **North Star** rail group, not Business (which is scoped to `business-*` types) or Memory (scoped to `memory-*` types). The glossary carries a `marketing` *tag* because marketing copy consumes its definitions, but its `type: l2` keeps it in the foundational tier. Everything else is filed under a folder matching its entity type.
138
132
 
139
133
  > [!note] Why folders, not flat?
140
134
  > Obsidian works with either, and HeySpex's link resolution treats folders as opaque (see [Wikilink resolution rules](#wikilink-resolution-rules)). Folders exist purely for human navigation and for the indexer's "list all <type>" view. Files can be moved between folders without breaking links.
@@ -143,50 +137,50 @@ The L1 lives at the vault root as `heyspex-north-star.md`. The other L2 specs (`
143
137
 
144
138
  The table below names every entity type in v1 and points at the frontmatter contract. Each type has its own subsection below with the full schema.
145
139
 
146
- | `type:` value | Folder | Hierarchy level | One-line description |
147
- | ---------------------- | ----------------------------------------------------------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
148
- | `l1` | root | L1 | The North Star vision; one per vault. |
149
- | `l2` | root | L2 | Foundational architecture or model documents. |
150
- | `l3` | `use-cases/` | L3 | Use-case specs that elaborate L1 system use cases. |
151
- | `adr` | `adr/` | — | Architectural Decision Record. |
152
- | `task` | `tasks/` | — | The atomic unit of work. Subsumes bd's `task`, `feature`, and `bug` types. |
153
- | `epic` | `epics/` | — | A grouping of related tasks under a common goal. |
154
- | `milestone` | `milestones/` | — | The grouping **above** epic: a coherent multi-epic ship that closes when every child epic closes and the milestone's own acceptance gate is met. Distinct from the legacy `kind: milestone` task discriminator (see [`#### task`](#task)). |
155
- | `diagnose` | `diagnoses/` | — | A user-reported **bug fix** as first-class executable work (claimable, decomposable). Standalone by default — no epic/milestone parent required — with an optional `parent:` (epic or milestone) for organization. Carries `severity:`; surfaces on the Resolution surface as a derived `kind: "bug"` row that links back to the diagnose. Elevates the bug concept that `task` historically subsumed (see [`#### task`](#task)) into its own lane. Ratified by introduction lineage HS-OXBS-BFIX-MIL-bug-fix-diagnose-lane (milestone-precedent, like `milestone`/`pillar`). See HS-AO2F-1KZK-RES-bug-fix-resolution-task-entity-model-and. Proposed (not-yet-ratified) field extensions — a `problem_layer: symptom \| core \| unknown` classifier and an optional bidirectional `caused_by`/`symptoms` link pair — are designed in HS-4QOK-UBJM-RES-diagnose-problem-layer-classification-sy. End-to-end workflow procedure: resolution-diagnose-workflow. |
156
- | `pillar` | `pillars/` | — | Perpetual categorical container that never closes; cross-cutting axis for epics. Every epic carries `pillar:` (required, single primary) + optional `secondary_pillars:`. Canonical Pillars ship pre-loaded with HeySpex; customers may add scoped Pillars. Orthogonal to `milestone` (a milestone is a shippable increment; a Pillar is a perpetual concern). See HS-PILR-pillars (meta-Pillar) and HS-AWDI-PILR-RES-pm-perpetual-container-terminology (research + 2026-05-31 resolution). |
157
- | `agent` | `agents/` | — | A durable, user-authored **agent identity** (the "home where agents live"): name, role, preferred tools, model tier, procedures, and persona body. Compiles to the host-native agent formats (`.claude/agents/*.md`, `.cursor/agents/*.md`) — the vault spec is the SSOT, the generated files are derived. Carries HeySpex-only extras (`lane`, `color`, `owned_paths`, `golden_cases`, and `source_attribution` when imported) stripped on compile. `owned_paths` is the machine-checkable file-ownership set for parallel-agent stomp-detection; `lane` remains a human label. An **imported** agent (community-collection per HS-SURM-TMXZ-EPIC-default-agent-roster-and-import-path AC#2, or own-agent per HS-11ME-1NL4-EPIC-import-and-adopt-your-own-existing-agent) records its provenance in `source_attribution` (collection, url, path, commit, license, imported_at); authored agents omit it. Evergreen (does not close). See HS-XNX5-UQHA-MIL-agent-home. |
158
- | `golden-case` | `agents/golden-cases/` | — | A saved **eval fixture** for one agent identity: the prompt (and optional setup + deterministic graders) the test-before-publish harness runs against a draft agent (HS-R1JM-OAG3-EPIC-agent-testing-harness-try-a-draft-agent). Stored under the `agents/` tree so fixtures version beside the identities they exercise in the same git history. Evergreen (updated in place). Introduced by HS-8AQT-J6FU-TASK-golden-case-vault-artifact-format-and-st. |
159
- | `branch-brief` | `branches/` | — | "What this git branch is trying to do, and how it actually went." Plan-vs-actual + evidence for one branch. |
160
- | `memory-lesson` | `memory/lessons/` | — | "Here's what went wrong and how to avoid it." |
161
- | `memory-decision` | `memory/decisions/` | — | "Here's what we chose and why." |
162
- | `memory-reference` | `memory/references/` | — | "Here's where to look for X." |
163
- | `memory-ui-pattern` | `memory/ui-patterns/` | — | "Here's a reusable console interaction/visual pattern to copy." |
164
- | `memory-ux-principle` | `memory/ux-principles/` | — | "Here's a cross-brand UX rule (what/why) before implementation." |
165
- | `protocol` | `protocols/` | Memory subsection | Repeatable how-we-work rules for agents/humans (session-close, memory capture, MCP usage). Browsed under Memory → Protocols in console; not a peer nav item beside Memory. |
166
- | `review` | `reviews/` | — | Companion fill-in workspace for an `in_review` parent spec — acceptance verification, reviewer notes, memory candidates, decision. One per parent, suffix-matched 1:1. |
167
- | `business-positioning` | `business/positioning/` | — | Brand H1, taglines, audience qualifier, message hierarchy. |
168
- | `business-pricing` | `business/pricing/` | — | Tier tables, AI add-on terms, discount/refund policy. |
169
- | `business-marketing` | `business/marketing/` | — | Channels, launches, campaigns, copy decks. |
170
- | `business-model` | `business/model/` | — | Unit economics, cost structure, monetization decisions. |
171
- | `roadmap` | `roadmaps/` | — | Phased plan orchestrating tasks/epics; compact `roadmap_manifest` for indexer/CLI (adr-0012-roadmap-storage). |
172
- | `capture` | `captures/` | — | Concise capture entry; `kind:` field discriminates idea / bug-fix / clip / reference / question / spec-import. Replaces the legacy `type: idea` entity (renamed 2026-05-22 per HS-B2B8-DLQI-EPIC-capture-rename-migration-idea-to-capture). `spec-import` is the **import-origin** kind — one capture per imported foreign doc, created by the bulk spec-import feature (HS-8V8T-8SBG-EPIC-first-connect-rough-import / HS-ROIU-9P4B-EPIC-import-preview-and-confirm); grounding HS-J7T5-VEW8-RES-import-specs-one-click-feature-pipeline. |
173
- | `research` | `research/` | — | Audit reports, feature inventories, exploratory notes. |
174
- | `planning-flow` | `flows/` | — | Epic lifecycle orchestration diagram (mermaid source + canvas projection). |
175
- | `draft` | `drafts/` | — | Ingested content awaiting triage. |
176
- | `daily` | `daily/` | — | Optional daily-note scratchpad. |
177
- | `run-retrospective` | `dev-factory/reports/retrospectives/` (outside `specs/`, sibling to `heyspex.yaml`/`.heyspex/`) | — | A **generated** run-close record — never hand-authored, not scheduled/claimable, not a wikilink-addressable spec. One file per COO-dispatcher run, `<runId>.md` (`runId` = the run's milestone id), produced deterministically by `dev-factory/lib/retrospective.mjs` from `run-events.jsonl` + the gate ledger + `coo-dispatcher-state.json`. Frontmatter: `runId`, `generatedAt`, `shippedUnits[]` (gate-verified units), `autoAppliedDecisions[]` (dispatcher auto-applies), `stoppedReason`, `restartCondition`, `ownerGates[]` (pending owner-only gates). Body: the three Retrospective sections (what went well / what could be improved / actionable next steps). Read by What's Next's Retrospective hero (Assisted/Autonomous fronts) — see HS-4HI5-JEPA-EPIC-what-s-next-multi-run-mode-run-dashboard and the-retrospective-is-a-generated-run-rec. |
140
+ | `type:` value | Folder | Hierarchy level | One-line description |
141
+ | --- | --- | --- | --- |
142
+ | `l1` | root | L1 | The North Star vision; one per vault. |
143
+ | `l2` | root | L2 | Foundational architecture or model documents. |
144
+ | `l3` | `use-cases/` | L3 | Use-case specs that elaborate L1 system use cases. |
145
+ | `adr` | `adr/` | — | Architectural Decision Record. |
146
+ | `task` | `tasks/` | — | The atomic unit of work. Subsumes bd's `task`, `feature`, and `bug` types. |
147
+ | `epic` | `epics/` | — | A grouping of related tasks under a common goal. |
148
+ | `milestone` | `milestones/` | — | The grouping **above** epic: a coherent multi-epic ship that closes when every child epic closes and the milestone's own acceptance gate is met. Distinct from the legacy `kind: milestone` task discriminator (see [`#### task`](#task)). |
149
+ | `diagnose` | `diagnoses/` | — | A user-reported **bug fix** as first-class executable work (claimable, decomposable). Standalone by default — no epic/milestone parent required — with an optional `parent:` (epic or milestone) for organization. Carries `severity:`; surfaces on the Resolution surface as a derived `kind: "bug"` row that links back to the diagnose. Elevates the bug concept that `task` historically subsumed (see [`#### task`](#task)) into its own lane. Ratified by introduction lineage HS-OXBS-BFIX-MIL-bug-fix-diagnose-lane (milestone-precedent, like `milestone`/`pillar`). See HS-AO2F-1KZK-RES-bug-fix-resolution-task-entity-model-and. Proposed (not-yet-ratified) field extensions — a `problem_layer: symptom \| core \| unknown` classifier and an optional bidirectional `caused_by`/`symptoms` link pair — are designed in HS-4QOK-UBJM-RES-diagnose-problem-layer-classification-sy. End-to-end workflow procedure: resolution-diagnose-workflow. |
150
+ | `pillar` | `pillars/` | — | Perpetual categorical container that never closes; cross-cutting axis for epics. Every epic carries `pillar:` (required, single primary) + optional `secondary_pillars:`. Canonical Pillars ship pre-loaded with HeySpex; customers may add scoped Pillars. Orthogonal to `milestone` (a milestone is a shippable increment; a Pillar is a perpetual concern). See HS-PILR-pillars (meta-Pillar) and HS-AWDI-PILR-RES-pm-perpetual-container-terminology (research + 2026-05-31 resolution). |
151
+ | `agent` | `agents/` | — | A durable, user-authored **agent identity** (the "home where agents live"): name, role, preferred tools, model tier, procedures, and persona body. Compiles to the host-native agent formats (`.claude/agents/*.md`, `.cursor/agents/*.md`) — the vault spec is the SSOT, the generated files are derived. Carries HeySpex-only extras (`lane`, `color`, `owned_paths`, `golden_cases`, and `source_attribution` when imported) stripped on compile. `owned_paths` is the machine-checkable file-ownership set for parallel-agent stomp-detection; `lane` remains a human label. An **imported** agent (community-collection per HS-SURM-TMXZ-EPIC-default-agent-roster-and-import-path AC#2, or own-agent per HS-11ME-1NL4-EPIC-import-and-adopt-your-own-existing-agent) records its provenance in `source_attribution` (collection, url, path, commit, license, imported_at); authored agents omit it. Evergreen (does not close). See HS-XNX5-UQHA-MIL-agent-home. |
152
+ | `golden-case` | `agents/golden-cases/` | — | A saved **eval fixture** for one agent identity: the prompt (and optional setup + deterministic graders) the test-before-publish harness runs against a draft agent (HS-R1JM-OAG3-EPIC-agent-testing-harness-try-a-draft-agent). Stored under the `agents/` tree so fixtures version beside the identities they exercise in the same git history. Evergreen (updated in place). Introduced by HS-8AQT-J6FU-TASK-golden-case-vault-artifact-format-and-st. |
153
+ | `branch-brief` | `branches/` | — | "What this git branch is trying to do, and how it actually went." Plan-vs-actual + evidence for one branch. |
154
+ | `memory-lesson` | `memory/lessons/` | — | "Here's what went wrong and how to avoid it." |
155
+ | `memory-decision` | `memory/decisions/` | — | "Here's what we chose and why." |
156
+ | `memory-reference` | `memory/references/` | — | "Here's where to look for X." |
157
+ | `memory-ui-pattern` | `memory/ui-patterns/` | — | "Here's a reusable console interaction/visual pattern to copy." |
158
+ | `memory-ux-principle` | `memory/ux-principles/` | — | "Here's a cross-brand UX rule (what/why) before implementation." |
159
+ | `protocol` | `protocols/` | Memory subsection | Repeatable how-we-work rules for agents/humans (session-close, memory capture, MCP usage). Browsed under Memory → Protocols in console; not a peer nav item beside Memory. |
160
+ | `review` | `reviews/` | — | Companion fill-in workspace for an `in_review` parent spec — acceptance verification, reviewer notes, memory candidates, decision. One per parent, suffix-matched 1:1. |
161
+ | `business-positioning` | `business/positioning/` | — | Brand H1, taglines, audience qualifier, message hierarchy. |
162
+ | `business-pricing` | `business/pricing/` | — | Tier tables, AI add-on terms, discount/refund policy. |
163
+ | `business-marketing` | `business/marketing/` | — | Channels, launches, campaigns, copy decks. |
164
+ | `business-model` | `business/model/` | — | Unit economics, cost structure, monetization decisions. |
165
+ | `roadmap` | `roadmaps/` | — | Phased plan orchestrating tasks/epics; compact `roadmap_manifest` for indexer/CLI (adr-0012-roadmap-storage). |
166
+ | `capture` | `captures/` | — | Concise capture entry; `kind:` field discriminates idea / bug-fix / clip / reference / question / spec-import. Replaces the legacy `type: idea` entity (renamed 2026-05-22 per HS-B2B8-DLQI-EPIC-capture-rename-migration-idea-to-capture). `spec-import` is the **import-origin** kind — one capture per imported foreign doc, created by the bulk spec-import feature (HS-8V8T-8SBG-EPIC-first-connect-rough-import / HS-ROIU-9P4B-EPIC-import-preview-and-confirm); grounding HS-J7T5-VEW8-RES-import-specs-one-click-feature-pipeline. |
167
+ | `research` | `research/` | — | Audit reports, feature inventories, exploratory notes. |
168
+ | `planning-flow` | `flows/` | — | Epic lifecycle orchestration diagram (mermaid source + canvas projection). |
169
+ | `draft` | `drafts/` | — | Ingested content awaiting triage. |
170
+ | `daily` | `daily/` | — | Optional daily-note scratchpad. |
171
+ | `run-retrospective` | `dev-factory/reports/retrospectives/` (outside `specs/`, sibling to `heyspex.yaml`/`.heyspex/`) | — | A **generated** run-close record — never hand-authored, not scheduled/claimable, not a wikilink-addressable spec. One file per COO-dispatcher run, `<runId>.md` (`runId` = the run's milestone id), produced deterministically by `dev-factory/lib/retrospective.mjs` from `run-events.jsonl` + the gate ledger + `coo-dispatcher-state.json`. Frontmatter: `runId`, `generatedAt`, `shippedUnits[]` (gate-verified units), `autoAppliedDecisions[]` (dispatcher auto-applies), `stoppedReason`, `restartCondition`, `ownerGates[]` (pending owner-only gates). Body: the three Retrospective sections (what went well / what could be improved / actionable next steps). Read by What's Next's Retrospective hero (Assisted/Autonomous fronts) — see HS-4HI5-JEPA-EPIC-what-s-next-multi-run-mode-run-dashboard and the-retrospective-is-a-generated-run-rec.
178
172
 
179
173
  Adding a new entity type requires an ADR. `branch-brief` was added by adr-0008-branch-brief-and-evidence-schema; `roadmap` by adr-0012-roadmap-storage; all other core types ratified at adr-0001-vault-format. `milestone` is the exception that proves the rule: the type was used informally first — 33 `HS-MIL-*` files (e.g. HS-RM22-IART-MIL-console-ia-restructure) were hand-authored before formalization — so rather than a standalone ADR, the convention is ratified by its introduction lineage, HS-VK7C-MILE-EPIC-milestone-entity-type-and-surfacing (this schema row, the validator, MCP support) followed by HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity (required-parent-on-epics + the roadmap drilldown). The canonical hierarchy these two epics serve is documented in [[spec-hierarchy]].
180
174
 
181
175
  `pillar` follows the same milestone-precedent (no standalone "introduce the entity type" ADR): ratified by its introduction lineage HS-EBIL-0011-EPIC-goal-hierarchy-l2-strategic-pillars-l3 (the L2 perpetual-Pillars epic, sibling of HS-OR8V-0010-EPIC-north-star-vision-first-class-entity in HS-J6K8-NSPL-MIL-north-star-and-strategic-pillars-hierarchy) plus the design captured in HS-AWDI-PILR-RES-pm-perpetual-container-terminology; the privacy-boundary side of the work (aggregate-learning telemetry on the Pillar Library) is in adr-0016-pillar-library-privacy-boundary. The 2026-05-31 resolution that produced the Pillar tier also retired the previously planned L3 Themes tier (per-epic teleological anchoring collapsed into perpetual Pillars). First canonical Pillar filed: HS-PILR-pillars (the meta-Pillar; dogfooding instance).
182
176
 
183
- `agent` follows the same milestone/pillar-precedent (no standalone "introduce the entity type" ADR): ratified by its introduction lineage HS-XNX5-UQHA-MIL-agent-home (this schema row, the frontmatter-schema branch, the `KIND_RULES`/`TYPE_TO_FOLDER` registration, and the compiler that exports identities to host-native `.claude/agents`/`.cursor/agents` formats). The agent identity is the durable, user-authored counterpart to the ephemeral control-plane presence (`active_claims`) — the vault holds _who an agent is_, the control plane holds _what it is doing now_. Positioning context: HS-O46R-R30X-RES-agent-layer-as-the-demand-side-twin-of-t.
177
+ `agent` follows the same milestone/pillar-precedent (no standalone "introduce the entity type" ADR): ratified by its introduction lineage HS-XNX5-UQHA-MIL-agent-home (this schema row, the frontmatter-schema branch, the `KIND_RULES`/`TYPE_TO_FOLDER` registration, and the compiler that exports identities to host-native `.claude/agents`/`.cursor/agents` formats). The agent identity is the durable, user-authored counterpart to the ephemeral control-plane presence (`active_claims`) — the vault holds *who an agent is*, the control plane holds *what it is doing now*. Positioning context: HS-O46R-R30X-RES-agent-layer-as-the-demand-side-twin-of-t.
184
178
 
185
179
  `golden-case` follows the same introduction-lineage precedent under HS-R1JM-OAG3-EPIC-agent-testing-harness-try-a-draft-agent / HS-8AQT-J6FU-TASK-golden-case-vault-artifact-format-and-st: a first-class vault artifact for agent eval fixtures (not JSON sidecars or console-only blobs). Bodies follow a fixed section contract; optional deterministic graders validate against `specs/schemas/golden-case-body.schema.json`.
186
180
 
187
181
  ## Lifecycle classes
188
182
 
189
- Entity types fall into four lifecycle classes. The class determines which subset of the [universal status enum](#frontmatter-schemas) a type uses, when its `canonical:` flag flips, and what the close-out ritual is. **A reader asking _"can I flip this file's status to `in_review`?"_ should consult this section first — the answer depends entirely on which class the file's type belongs to.**
183
+ Entity types fall into four lifecycle classes. The class determines which subset of the [universal status enum](#frontmatter-schemas) a type uses, when its `canonical:` flag flips, and what the close-out ritual is. **A reader asking *"can I flip this file's status to `in_review`?"* should consult this section first — the answer depends entirely on which class the file's type belongs to.**
190
184
 
191
185
  ### Evergreen (living reference substrate)
192
186
 
@@ -198,7 +192,7 @@ These are **standalone reference artifacts**. `status: open` is the resting stat
198
192
  - **Supersession** is the only "lifecycle event" — record it via relational fields (`supersedes:` / `superseded_by:` on ADRs, `superseded_by:` on memories and research, `canonical: false` as the universal drift tombstone per canonicalization-arbiter-is-link-graph-not-policy). The original stays as the historical record at `status: open`.
199
193
  - **Research lineage** to downstream artifacts is recorded via `enhances:`, `spawned_epics:`, `bound_epic:`, `incorporated_into:` — these are relational edges, **not** status transitions. See research-is-evergreen for the full rule and the deferred MCP-tool / UI-epic / validator surfaces still being remediated.
200
194
 
201
- Session-close protocol carve-out: an agent who touched an evergreen doc this session **must not** flip its status. See session-close-protocol step 1.
195
+ Session-close protocol carve-out: an agent who touched an evergreen doc this session **must not** flip its status. See [[session-close-protocol]] step 1.
202
196
 
203
197
  ### Trackable plan-side (open → in_progress → in_review → closed)
204
198
 
@@ -206,7 +200,7 @@ Session-close protocol carve-out: an agent who touched an evergreen doc this ses
206
200
 
207
201
  These are **work containers** with a definite scope and a moment at which they're done. They follow the full status flow and are **frozen at close** per closed-trackable-specs-are-historical-record-not-living-docs — the body becomes historical record of the plan as it was at the moment of close.
208
202
 
209
- - **Session close** flips completed-this-session specs to `status: in_review` and creates an `HS-REV-<suffix>` companion (session-close-protocol).
203
+ - **Session close** flips completed-this-session specs to `status: in_review` and creates an `HS-REV-<suffix>` companion ([[session-close-protocol]]).
210
204
  - **Reviewer close** flips `in_review → closed`, flips `canonical: true → false`, optionally sets the `outcome:`/`outcome_note:` verdict (`met` | `partially-met` | `not-met` — reviewer judgment, never inferred; see §Iteration lineage), and freezes the frontmatter forever after.
211
205
  - **`branch-brief`** closes when the branch ships; **`planning-flow`** closes with its bound epic.
212
206
 
@@ -228,12 +222,12 @@ These are **inbound surfaces** scoped to one input session. They don't close in
228
222
 
229
223
  ### Cross-reference summary
230
224
 
231
- | Class | Status values used | Close-as-historical-record? | `canonical: false` trigger |
232
- | ------------------- | ----------------------------------------------------------------- | --------------------------------- | ------------------------------ |
233
- | Evergreen | `open` (resting state) | No | Supersession (relational edge) |
234
- | Trackable plan-side | `open` → `in_progress` → `in_review` → `closed` (plus `deferred`) | Yes — frozen at close | Close-out write |
235
- | Single-shot ingest | `open` (capture/draft pre-promotion) / N/A (daily) | No — promoted or archived by date | Not used |
236
- | Per-instance | Declared at filing | Per-instance | Per-instance |
225
+ | Class | Status values used | Close-as-historical-record? | `canonical: false` trigger |
226
+ |---|---|---|---|
227
+ | Evergreen | `open` (resting state) | No | Supersession (relational edge) |
228
+ | Trackable plan-side | `open` → `in_progress` → `in_review` → `closed` (plus `deferred`) | Yes — frozen at close | Close-out write |
229
+ | Single-shot ingest | `open` (capture/draft pre-promotion) / N/A (daily) | No — promoted or archived by date | Not used |
230
+ | Per-instance | Declared at filing | Per-instance | Per-instance |
237
231
 
238
232
  ## Identity, IDs, and filenames
239
233
 
@@ -244,56 +238,55 @@ These are **inbound surfaces** scoped to one input session. They don't close in
244
238
 
245
239
  A managed spec's basename decomposes into named tokens. Canonical names per glossary §Identifier anatomy and HS-37O7-T9KP-RES-identifier-token-terminology-family-key (external-validated; supersedes the "pipeline ID / type token / file ID" names in HS-MF8M-CCVE-RES-family-first-spec-identifier-format-hs-i).
246
240
 
247
- | Token | Example | Role |
248
- | -------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
249
- | **File key** | `L6Y4` | The per-file 4+ char uppercase-alphanumeric key (at least one letter), **unique vault-wide** — the identity and one-token citation handle for exactly one file. Recorded in frontmatter `file_id:` (SSOT) and embedded in the filename; becomes the `id:` itself (`id: HS-L6Y4`) under era 3. Server-minted, never hand-picked. |
250
- | **Family key** | `P2TR` | The shared 4+ char alphanumeric code that groups one initiative's specs — an epic and all its child tasks, research, and reviews — into one greppable **family** (`grep HS-P2TR` returns the whole family). Shared across the family; uniqueness is enforced on the full **basename** per kind, never on the family key alone (see vault-id-assignment-protocol §Shared-suffix families). |
251
- | **Type label** | `TASK` | The entity-kind token (`TASK`, `EPIC`, `MILESTONE`, `RESEARCH`, `REVIEW`, …). A **human-readable hint only**. |
252
- | **Title slug** | `verification-state-schema` | The lowercased-hyphenated descriptive tail derived from `title:` — the part that makes each basename unique within a family. |
241
+ | Token | Example | Role |
242
+ | --- | --- | --- |
243
+ | **File key** | `L6Y4` | The per-file 4+ char uppercase-alphanumeric key (at least one letter), **unique vault-wide** — the identity and one-token citation handle for exactly one file. Recorded in frontmatter `file_id:` (SSOT) and embedded in the filename; becomes the `id:` itself (`id: HS-L6Y4`) under era 3. Server-minted, never hand-picked. |
244
+ | **Family key** | `P2TR` | The shared 4+ char alphanumeric code that groups one initiative's specs — an epic and all its child tasks, research, and reviews — into one greppable **family** (`grep HS-P2TR` returns the whole family). Shared across the family; uniqueness is enforced on the full **basename** per kind, never on the family key alone (see vault-id-assignment-protocol §Shared-suffix families). |
245
+ | **Type label** | `TASK` | The entity-kind token (`TASK`, `EPIC`, `MILESTONE`, `RESEARCH`, `REVIEW`, …). A **human-readable hint only**. |
246
+ | **Title slug** | `verification-state-schema` | The lowercased-hyphenated descriptive tail derived from `title:` — the part that makes each basename unique within a family. |
253
247
 
254
248
  **Filename shapes (era = type-label position):**
255
-
256
249
  - **File-key-first (era 3, ratified target):** `HS-<file key>-<family key>-<type label>-<title slug>.md` → `HS-L6Y4-01D7-EPIC-deterministic-rename-with-link-rewrite.md` — lands vault-wide with HS-L6Y4-01D7-EPIC-deterministic-rename-with-link-rewrite.
257
250
  - **Family-first (era 2, current on disk / current minting):** `HS-<family key>-<type label>-[<file key>-]<title slug>.md` → `HS-P2TR-TASK-verification-state-schema.md`, `HS-0G910-EPIC-G3D3-api-foundation-keys-scopes-error.md`
258
251
  - **Type-first (era 1, legacy):** `HS-<type label>-<family key>-<title slug>.md` → `HS-TASK-P2TR-verification-state-schema.md`
259
252
 
260
253
  **Routing rule (SSOT for entity type):** code MUST determine a spec's entity type from the frontmatter **`type:`** field (and its directory), **never** by parsing the type label out of the filename. The type label is a convenience hint that survives out of directory context (wikilinks, search results, clipboard, terminal output); it is **not** authoritative and must never drive a mutation, a route, or a reclassification on its own. This is the semantic-identifier guardrail from HS-MF8M-CCVE-RES-family-first-spec-identifier-format-hs-i (don't route on parsed-ID semantics).
261
254
 
262
- **Retired / avoid:** **"suffix"** (the legacy name for the family key — self-contradictory once the family key leads), **"pipeline ID"** (overloaded with CI/CD + the feature-pipeline graph), **"prefix" / "type prefix"** for the family key (industry convention encodes _type_, not a family). The legacy term `<suffix>` still appears in the tables below and in the `legacy_slug_only` naming atoms until the Phase 3 codegen flip.
255
+ **Retired / avoid:** **"suffix"** (the legacy name for the family key — self-contradictory once the family key leads), **"pipeline ID"** (overloaded with CI/CD + the feature-pipeline graph), **"prefix" / "type prefix"** for the family key (industry convention encodes *type*, not a family). The legacy term `<suffix>` still appears in the tables below and in the `legacy_slug_only` naming atoms until the Phase 3 codegen flip.
263
256
 
264
257
  ### ID format
265
258
 
266
- | Entity type | ID format | Example |
267
- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
268
- | `l1` | `HS-L1` | `HS-L1` |
269
- | `l2` | `HS-L2-<UPPER>` | `HS-L2-ENTITY`, `HS-L2-FOUNDATIONS` |
270
- | `l3` | `HS-UC-<short>` | `HS-UC-CAPTURE` |
271
- | `adr` | `HS-ADR-NNNN` (zero-padded sequence) | `HS-ADR-0001` |
272
- | `task` | `HS-TASK-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol). Pre-2026-05-22 entries (`HS-NNNN`, `HS-<4+ A-Z0-9>`) were migrated to this prefix. | `HS-TASK-K7M2` |
273
- | `epic` | `HS-EPIC-<suffix>` — same rules | `HS-DE8L`, `HS-V888` |
274
- | `milestone` | `HS-MIL-<suffix>` — `<suffix>` is 4+ uppercase `A–Z0–9` (vault-id-assignment-protocol); legacy 4-character mnemonic IDs (e.g. `HS-RM22`) remain valid | `HS-RM22`, `HS-1JC8` |
275
- | `diagnose` | `HS-DIAG-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol) | `HS-DIAG-K7M2` |
276
- | `pillar` | `HS-PILR-<slug>` (canonical; slug uniquely identifies the concept; no random suffix) or `HS-PILR-<suffix>-<slug>` (customer-scoped; random 4+ A-Z0-9) | `HS-PILR-pillars`, `HS-PILR-scaling`, `HS-PILR-K7M2-team-onboarding` |
277
- | `branch-brief` | `HS-BB-<slug>` | `HS-BB-feature-checkout-redesign` |
278
- | `memory-lesson` | `HS-LES-<slug>` | `HS-LES-bd-process-leak` |
279
- | `memory-decision` | `HS-DEC-<slug>` | `HS-DEC-dep-relate-for-epic-children` |
280
- | `memory-reference` | `HS-REF-<slug>` | `HS-REF-dolt-time-travel-docs` |
281
- | `memory-ui-pattern` | `HS-UIP-<slug>` | `HS-UIP-rail-active-vs-keyboard-cursor` |
282
- | `memory-ux-principle` | `HS-UXP-<slug>` | `HS-UXP-toggle-current-state-semantics` |
283
- | `protocol` | `HS-PROTO-<slug>` | `HS-PROTO-session-close` |
284
- | `review` | `HS-REV-<suffix>` — `<suffix>` matches the parent task/epic id 1:1 (e.g. parent `HS-76RX` → review `HS-QMHO`). Detection: [`extractSpecSuffix` in `console/src/lib/vault.ts:155`](../console/src/lib/vault.ts). | `HS-QMHO`, `HS-R3HO`, `HS-CCEQ` |
285
- | `business-positioning` | `HS-BIZ-POS-<slug>` | `HS-BIZ-POS-2nd-brain-harness-for-specs` |
286
- | `business-pricing` | `HS-BIZ-PRI-<slug>` | `HS-BIZ-PRI-tiers-and-byok-2026-05` |
287
- | `business-marketing` | `HS-BIZ-MKT-<slug>` | `HS-BIZ-MKT-launch-playbook-companion` |
288
- | `business-model` | `HS-BIZ-MOD-<slug>` | `HS-BIZ-MOD-flat-per-vault-economics` |
289
- | `roadmap` | `HS-ROADMAP-<SLUG>` | `HS-ROADMAP-PRODUCT` |
290
- | `research` | `HS-RES-<suffix>` — legacy `HS-RES-NNN` or random `HS-RES-<4+ A-Z0-9>` (vault-id-assignment-protocol) | `HS-RES-001`, `HS-RES-K7M2` |
291
- | `capture` | `HS-CAP-<suffix>` — same rules; legacy `HS-IDEA-<suffix>` preserved in `legacy_idea_id:` for archaeology | `HS-CAP-JKLN`, `HS-CAP-OAP3` |
292
- | `agent` | `HS-AGENT-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol) | `HS-634I` |
293
- | `golden-case` | `HS-GCASE-<suffix>` — same rules | `HS-HPIO` |
294
- | `planning-flow` | `HS-FLOW-NNN` | `HS-FLOW-001` |
295
- | `draft` | `HS-DRAFT-<slug>` | `HS-DRAFT-2026-05-14-1130-article-link` |
296
- | `daily` | `HS-DAILY-YYYY-MM-DD` | `HS-DAILY-2026-05-14` |
259
+ | Entity type | ID format | Example |
260
+ | --- | --- | --- |
261
+ | `l1` | `HS-L1` | `HS-L1` |
262
+ | `l2` | `HS-L2-<UPPER>` | `HS-L2-ENTITY`, `HS-L2-FOUNDATIONS` |
263
+ | `l3` | `HS-UC-<short>` | `HS-UC-CAPTURE` |
264
+ | `adr` | `HS-ADR-NNNN` (zero-padded sequence) | `HS-ADR-0001` |
265
+ | `task` | `HS-TASK-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol). Pre-2026-05-22 entries (`HS-NNNN`, `HS-<4+ A-Z0-9>`) were migrated to this prefix. | `HS-TASK-K7M2` |
266
+ | `epic` | `HS-EPIC-<suffix>` — same rules | `HS-DE8L`, `HS-V888` |
267
+ | `milestone` | `HS-MIL-<suffix>` — `<suffix>` is 4+ uppercase `A–Z0–9` (vault-id-assignment-protocol); legacy 4-character mnemonic IDs (e.g. `HS-RM22`) remain valid | `HS-RM22`, `HS-1JC8` |
268
+ | `diagnose` | `HS-DIAG-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol) | `HS-DIAG-K7M2` |
269
+ | `pillar` | `HS-PILR-<slug>` (canonical; slug uniquely identifies the concept; no random suffix) or `HS-PILR-<suffix>-<slug>` (customer-scoped; random 4+ A-Z0-9) | `HS-PILR-pillars`, `HS-PILR-scaling`, `HS-PILR-K7M2-team-onboarding` |
270
+ | `branch-brief` | `HS-BB-<slug>` | `HS-BB-feature-checkout-redesign` |
271
+ | `memory-lesson` | `HS-LES-<slug>` | `HS-LES-bd-process-leak` |
272
+ | `memory-decision` | `HS-DEC-<slug>` | `HS-DEC-dep-relate-for-epic-children` |
273
+ | `memory-reference` | `HS-REF-<slug>` | `HS-REF-dolt-time-travel-docs` |
274
+ | `memory-ui-pattern` | `HS-UIP-<slug>` | `HS-UIP-rail-active-vs-keyboard-cursor` |
275
+ | `memory-ux-principle` | `HS-UXP-<slug>` | `HS-UXP-toggle-current-state-semantics` |
276
+ | `protocol` | `HS-PROTO-<slug>` | `HS-PROTO-session-close` |
277
+ | `review` | `HS-REV-<suffix>` — `<suffix>` matches the parent task/epic id 1:1 (e.g. parent `HS-76RX` → review `HS-QMHO`). Detection: [`extractSpecSuffix` in `console/src/lib/vault.ts:155`](../console/src/lib/vault.ts). | `HS-QMHO`, `HS-R3HO`, `HS-CCEQ` |
278
+ | `business-positioning` | `HS-BIZ-POS-<slug>` | `HS-BIZ-POS-2nd-brain-harness-for-specs` |
279
+ | `business-pricing` | `HS-BIZ-PRI-<slug>` | `HS-BIZ-PRI-tiers-and-byok-2026-05` |
280
+ | `business-marketing` | `HS-BIZ-MKT-<slug>` | `HS-BIZ-MKT-launch-playbook-companion` |
281
+ | `business-model` | `HS-BIZ-MOD-<slug>` | `HS-BIZ-MOD-flat-per-vault-economics` |
282
+ | `roadmap` | `HS-ROADMAP-<SLUG>` | `HS-ROADMAP-PRODUCT` |
283
+ | `research` | `HS-RES-<suffix>` — legacy `HS-RES-NNN` or random `HS-RES-<4+ A-Z0-9>` (vault-id-assignment-protocol) | `HS-RES-001`, `HS-RES-K7M2` |
284
+ | `capture` | `HS-CAP-<suffix>` — same rules; legacy `HS-IDEA-<suffix>` preserved in `legacy_idea_id:` for archaeology | `HS-CAP-JKLN`, `HS-CAP-OAP3` |
285
+ | `agent` | `HS-AGENT-<suffix>` — `<suffix>` is 4+ random A-Z0-9 (vault-id-assignment-protocol) | `HS-634I` |
286
+ | `golden-case` | `HS-GCASE-<suffix>` — same rules | `HS-HPIO` |
287
+ | `planning-flow` | `HS-FLOW-NNN` | `HS-FLOW-001` |
288
+ | `draft` | `HS-DRAFT-<slug>` | `HS-DRAFT-2026-05-14-1130-article-link` |
289
+ | `daily` | `HS-DAILY-YYYY-MM-DD` | `HS-DAILY-2026-05-14` |
297
290
 
298
291
  **New task/epic/research/capture IDs** (console `POST /api/specs`, MCP `heyspex_save_research`, agents): allocate a random 4-character suffix from `A–Z` and `0–9`, checking the full vault for collisions (frontmatter `id` and filename prefix). When every combination at the current length is taken, the suffix grows to 5 characters, then 6, and so on. Legacy sequential IDs (`HS-NNNN`, `HS-RES-NNN`, `HS-IDEA-*`, slug-only research filenames) remain valid in the read-path until HS-23PN-9HVY-TASK-capture-rename-repo-wide-wikilink-rewrite retires them. Validate with `npm run validate:vault-ids` at the repo root.
299
292
 
@@ -301,32 +294,32 @@ A managed spec's basename decomposes into named tokens. Canonical names per glos
301
294
 
302
295
  The filename is **derived from the ID + an optional slug**, lowercased, with the same prefix the ID uses minus the `HS-` prefix (kept lowercase in filenames for readability):
303
296
 
304
- | Entity | Filename pattern | Example |
305
- | --------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
306
- | `l1` | `heyspex-north-star.md` (literal, only one) | `heyspex-north-star.md` |
307
- | `l2` | `<topic>.md` (literal slug) | `entity-model.md` |
308
- | `l3` | `uc-<short>.md` | `uc-capture-intent.md` |
309
- | `adr` | `adr-NNNN-<slug>.md` | `adr-0001-vault-format.md` |
310
- | `task` | `HS-TASK-<suffix>-<slug>.md` | `HS-TASK-K7M2-fix-foo.md` |
311
- | `epic` | `HS-EPIC-<suffix>-<slug>.md` | `HS-0007-EPIC-console-resilience.md`, `HS-W9ZE-EPIC-design-system-enforcement-auto-surface-u.md` |
312
- | `milestone` | `HS-MIL-<suffix>-<slug>.md` | `HS-IART-MIL-console-ia-restructure.md` |
313
- | `diagnose` | `HS-DIAG-<suffix>-<slug>.md` | `HS-DIAG-K7M2-console-startup-lag.md` |
314
- | `pillar` | `HS-PILR-<slug>.md` (canonical; slug IS the ID with no random suffix) or `HS-PILR-<suffix>-<slug>.md` (customer-scoped) | `HS-PILR-pillars.md`, `HS-PILR-K7M2-team-onboarding.md` |
315
- | `branch-brief` | `<branch-slug>.md` | `feature-checkout-redesign.md` |
316
- | `memory-lesson` | `<slug>.md` | `bd-process-leak.md` |
317
- | `memory-decision` | `<slug>.md` | `dep-relate-for-epic-children.md` |
318
- | `memory-reference` | `<slug>.md` | `dolt-time-travel-docs.md` |
319
- | `memory-ui-pattern` | `<slug>.md` | `rail-active-vs-keyboard-cursor.md` |
320
- | `memory-ux-principle` | `<slug>.md` | `toggle-current-state-semantics.md` |
321
- | `protocol` | `<slug>.md` | `session-close-protocol.md` |
322
- | `review` | `HS-REV-<suffix>-<slug>.md` (slug truncated from parent's slug, ≤40 chars) | `HS-SK1L-REV-hs-idea-skill-four-beats-layered-confirms.md` |
323
- | `research` | `HS-RES-<suffix>-<slug>.md` (legacy: `<slug>.md` only) | `HS-RES-K7M2-agent-governance.md` |
324
- | `capture` | `HS-CAP-<suffix>-<slug>.md` | `HS-CAP-JKLN-vault-triage.md` |
325
- | `agent` | `HS-AGENT-<suffix>-<slug>.md` | `HS-9TNK-AGENT-code-reviewer.md` |
326
- | `golden-case` | `HS-GCASE-<suffix>-<slug>.md` | `HS-R4VW-GCASE-review-missing-ac.md` |
327
- | `planning-flow` | `HS-FLOW-<NNN>-<slug>.md` | `HS-FLOW-001-epic-planning-flow-studio.md` |
328
- | `draft` | `<slug>.md` | `2026-05-14-1130-article-link.md` |
329
- | `daily` | `YYYY-MM-DD.md` | `2026-05-14.md` |
297
+ | Entity | Filename pattern | Example |
298
+ | --- | --- | --- |
299
+ | `l1` | `heyspex-north-star.md` (literal, only one) | `heyspex-north-star.md` |
300
+ | `l2` | `<topic>.md` (literal slug) | `entity-model.md` |
301
+ | `l3` | `uc-<short>.md` | `uc-capture-intent.md` |
302
+ | `adr` | `adr-NNNN-<slug>.md` | `adr-0001-vault-format.md` |
303
+ | `task` | `HS-TASK-<suffix>-<slug>.md` | `HS-TASK-K7M2-fix-foo.md` |
304
+ | `epic` | `HS-EPIC-<suffix>-<slug>.md` | `HS-0007-EPIC-console-resilience.md`, `HS-W9ZE-EPIC-design-system-enforcement-auto-surface-u.md` |
305
+ | `milestone` | `HS-MIL-<suffix>-<slug>.md` | `HS-IART-MIL-console-ia-restructure.md` |
306
+ | `diagnose` | `HS-DIAG-<suffix>-<slug>.md` | `HS-DIAG-K7M2-console-startup-lag.md` |
307
+ | `pillar` | `HS-PILR-<slug>.md` (canonical; slug IS the ID with no random suffix) or `HS-PILR-<suffix>-<slug>.md` (customer-scoped) | `HS-PILR-pillars.md`, `HS-PILR-K7M2-team-onboarding.md` |
308
+ | `branch-brief` | `<branch-slug>.md` | `feature-checkout-redesign.md` |
309
+ | `memory-lesson` | `<slug>.md` | `bd-process-leak.md` |
310
+ | `memory-decision` | `<slug>.md` | `dep-relate-for-epic-children.md` |
311
+ | `memory-reference` | `<slug>.md` | `dolt-time-travel-docs.md` |
312
+ | `memory-ui-pattern` | `<slug>.md` | `rail-active-vs-keyboard-cursor.md` |
313
+ | `memory-ux-principle` | `<slug>.md` | `toggle-current-state-semantics.md` |
314
+ | `protocol` | `<slug>.md` | `session-close-protocol.md` |
315
+ | `review` | `HS-REV-<suffix>-<slug>.md` (slug truncated from parent's slug, ≤40 chars) | `HS-SK1L-REV-hs-idea-skill-four-beats-layered-confirms.md` |
316
+ | `research` | `HS-RES-<suffix>-<slug>.md` (legacy: `<slug>.md` only) | `HS-RES-K7M2-agent-governance.md` |
317
+ | `capture` | `HS-CAP-<suffix>-<slug>.md` | `HS-CAP-JKLN-vault-triage.md` |
318
+ | `agent` | `HS-AGENT-<suffix>-<slug>.md` | `HS-9TNK-AGENT-code-reviewer.md` |
319
+ | `golden-case` | `HS-GCASE-<suffix>-<slug>.md` | `HS-R4VW-GCASE-review-missing-ac.md` |
320
+ | `planning-flow` | `HS-FLOW-<NNN>-<slug>.md` | `HS-FLOW-001-epic-planning-flow-studio.md` |
321
+ | `draft` | `<slug>.md` | `2026-05-14-1130-article-link.md` |
322
+ | `daily` | `YYYY-MM-DD.md` | `2026-05-14.md` |
330
323
 
331
324
  Slug rules: lowercase, ASCII, dash-separated, no trailing punctuation, no leading number for non-task types.
332
325
 
@@ -347,45 +340,45 @@ Every spec opens with a YAML frontmatter block. The schemas below define **requi
347
340
  Universal fields (every spec has these):
348
341
 
349
342
  ```yaml
350
- id: # required, string, matches the entity type's ID format
351
- name: # required, string, human-readable title
352
- type: # required, one of the entity type values above
353
- status: # required, see status enum below
354
- priority: # required, integer 0–4 (0 = highest)
355
- owner: # required, string (email or handle) — the ORIGINATING + accountable human (doubles as author).
356
- # See §Authorship provenance below.
357
- created: # required, ISO-8601 date (YYYY-MM-DD)
358
- updated: # required, ISO-8601 date
343
+ id: # required, string, matches the entity type's ID format
344
+ name: # required, string, human-readable title
345
+ type: # required, one of the entity type values above
346
+ status: # required, see status enum below
347
+ priority: # required, integer 0–4 (0 = highest)
348
+ owner: # required, string (email or handle) — the ORIGINATING + accountable human (doubles as author).
349
+ # See §Authorship provenance below.
350
+ created: # required, ISO-8601 date (YYYY-MM-DD)
351
+ updated: # required, ISO-8601 date
359
352
  contributors: # optional, list of "Name <email>" — OTHER humans who later enhanced the doc (append-only;
360
- # OMIT when empty). Auto-stamped, never hand-maintained. See §Authorship provenance.
361
- assisted_by: # optional, list of "AGENT" or "AGENT:MODEL" — agents/IDEs + model that assisted (append-only;
362
- # OMIT when empty). Auto-stamped, never hand-maintained. See §Authorship provenance.
363
- tags: # optional, list of strings
364
- related: # optional, list of wikilinks (alternative to inline body links)
353
+ # OMIT when empty). Auto-stamped, never hand-maintained. See §Authorship provenance.
354
+ assisted_by: # optional, list of "AGENT" or "AGENT:MODEL" — agents/IDEs + model that assisted (append-only;
355
+ # OMIT when empty). Auto-stamped, never hand-maintained. See §Authorship provenance.
356
+ tags: # optional, list of strings
357
+ related: # optional, list of wikilinks (alternative to inline body links)
365
358
  what_matters: # optional, enum: star | heart — per-spec user-priority signal
366
359
  ```
367
360
 
368
361
  **`what_matters`** is the per-spec user-priority signal that replaced the retired What Matters column (scheduler-and-whats-next-what-matters-column-mechanics, HS-78E7-Y9OJ-EPIC-deterministic-priority-scheduler). It is optional and two-level:
369
362
 
370
- - `star` (★) — _priority_: "consider this please."
371
- - `heart` (♥) — _very important_: "appreciate this being next if at all possible." A stronger signal than `star`.
363
+ - `star` (★) — *priority*: "consider this please."
364
+ - `heart` (♥) — *very important*: "appreciate this being next if at all possible." A stronger signal than `star`.
372
365
  - absent — unflagged (no default is injected).
373
366
 
374
367
  The value is held verbatim; an unrecognized value is tolerated by the parser and emits a warn-only `INVALID_WHAT_MATTERS` validator notice rather than an error. A Phase 7b scheduler stage consumes it for ordering.
375
368
 
376
369
  ### Authorship provenance
377
370
 
378
- Three universal fields carry GitHub-faithful provenance, following the cross-foundation `Assisted-by:` convention (Linux Kernel, Fedora, LLVM, OpenTelemetry) that keeps the human as the sole accountable author and records AI as a tool that _assisted_, not a co-author. Origin: HS-N1WG-W48S-RES-git-github-authorship-attribution-best-p → HS-Y4JH-IKIM-EPIC-authorship-provenance-frontmatter-owner. The SSOT question (frontmatter vs git history) is resolved in provenance-frontmatter-is-ssot-not-git-echo.
371
+ Three universal fields carry GitHub-faithful provenance, following the cross-foundation `Assisted-by:` convention (Linux Kernel, Fedora, LLVM, OpenTelemetry) that keeps the human as the sole accountable author and records AI as a tool that *assisted*, not a co-author. Origin: HS-N1WG-W48S-RES-git-github-authorship-attribution-best-p → HS-Y4JH-IKIM-EPIC-authorship-provenance-frontmatter-owner. The SSOT question (frontmatter vs git history) is resolved in provenance-frontmatter-is-ssot-not-git-echo.
379
372
 
380
- | Field | Who | Item format | Cardinality |
381
- | -------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------- |
382
- | `owner` | the **originating + accountable** human (doubles as author) | handle or email (e.g. `pwher`) | single scalar |
383
- | `contributors` | **other** humans who later enhanced the doc | `Name <email>` — GitHub form, round-trips with the `Co-authored-by:` trailer | append-only list |
384
- | `assisted_by` | agents/IDEs + model that assisted | `AGENT` or `AGENT:MODEL` — e.g. `Claude Opus 4.8`, `Cursor` | append-only list |
373
+ | Field | Who | Item format | Cardinality |
374
+ | --- | --- | --- | --- |
375
+ | `owner` | the **originating + accountable** human (doubles as author) | handle or email (e.g. `pwher`) | single scalar |
376
+ | `contributors` | **other** humans who later enhanced the doc | `Name <email>` — GitHub form, round-trips with the `Co-authored-by:` trailer | append-only list |
377
+ | `assisted_by` | agents/IDEs + model that assisted | `AGENT` or `AGENT:MODEL` — e.g. `Claude Opus 4.8`, `Cursor` | append-only list |
385
378
 
386
379
  Semantics (apply to every entity kind):
387
380
 
388
- - **`owner` is universally required** and unchanged in type — only its meaning is enriched here (originator + accountable, not merely a pointer). A later ownership _transfer_ is not preserved in frontmatter; git history (first-commit author) retains the original creator. Acceptable trade per HS-N1WG-W48S-RES-git-github-authorship-attribution-best-p.
381
+ - **`owner` is universally required** and unchanged in type — only its meaning is enriched here (originator + accountable, not merely a pointer). A later ownership *transfer* is not preserved in frontmatter; git history (first-commit author) retains the original creator. Acceptable trade per HS-N1WG-W48S-RES-git-github-authorship-attribution-best-p.
389
382
  - **`contributors` and `assisted_by` are universal-but-optional and omit-when-empty** — they are not emitted as empty lists, so a solo-vault doc stays clean and only grows a list once a second human or an agent touches the doc.
390
383
  - **Append-only + de-dup, never reorder/remove.** A new acting human ≠ `owner` is appended to `contributors`; an acting agent is appended to `assisted_by`; an entry already present is not duplicated.
391
384
  - **Auto-stamped, never hand-maintained.** Seeded at creation (`owner` from the resolved user, `assisted_by` from the acting agent) and appended on edit, sourced from the existing claim/session trail (Neon `active_claims`). Authoring/wiring lives in HS-Y4JH-IKIM-EPIC-authorship-provenance-frontmatter-owner.
@@ -398,8 +391,7 @@ Semantics (apply to every entity kind):
398
391
  An optional `artifact:` mapping records a published Claude Artifact that this spec/doc is the vault source for, so the artifact is never the only copy of its content — HS-6YIS-5GSW-EPIC-artifacts-as-vault-documents. **Universal** — unlike the type-specific schemas below, it attaches to ANY entity kind (a task, an epic, a research doc, a memory doc, or a non-frontmatter file like a roadmap page — see the HTML variant below), because a published artifact can belong to a doc at any level, not one lifecycle stage.
399
392
 
400
393
  ```yaml
401
- artifact:
402
- { title: "…", url: "https://claude.ai/code/artifact/…", version: "…", updated: "2026-08-23" }
394
+ artifact: { title: "…", url: "https://claude.ai/code/artifact/…", version: "…", updated: "2026-08-23" }
403
395
  # title: required when artifact: is present — the artifact's display title (matches its published <title>/heading).
404
396
  # url: required — the published URL.
405
397
  # version: optional, string — the last-published version stamp this vault file was confirmed against. This is
@@ -413,7 +405,7 @@ artifact:
413
405
 
414
406
  Either a single-line flow mapping (above) or an equivalent nested block mapping is valid YAML; the artifact-publish tooling (HS-6YIS-5GSW-EPIC-artifacts-as-vault-documents part 2, `scripts/hs-artifact.mjs`) reads and writes the flow-mapping form. Omit the whole `artifact:` key when the doc has no published artifact (omit-when-empty, same posture as `contributors`/`assisted_by`).
415
407
 
416
- **Non-frontmatter vault files** (a raw HTML page under `specs/roadmap/`, for example, has no YAML frontmatter at all): the same four fields are carried as a single machine-readable `ARTIFACT-STAMP: {...}` JSON line inside the file's existing leading `<!-- -->` source-of-truth comment, read/written by the same tooling. This is the shape `specs/roadmap/heyspex-sprint-roadmap.html` uses.
408
+ **Non-frontmatter vault files** (a raw HTML page under `specs/roadmap/`, for example, has no YAML frontmatter at all): the same four fields are carried as a single machine-readable `ARTIFACT-STAMP: {...}` JSON line inside the file's existing leading `<!-- -->` source-of-truth comment, read/written by the same tooling. This is the shape `specs/roadmap/heyspex-sprint-roadmap0829.html` uses.
417
409
 
418
410
  > [!note] Schema addition self-gating
419
411
  > Per entity-model-self-gates-schema-changes-via-adr, `artifact:` is admitted here **without a standalone ADR** under the same milestone-precedent as `contributors`/`assisted_by` above: additive, optional, omit-when-empty, not a new entity type or lifecycle — ratified by its introduction lineage, the owner's immediate order following the incident recorded in a-published-artifact-and-its-vault-copy → HS-6YIS-5GSW-EPIC-artifacts-as-vault-documents.
@@ -433,16 +425,16 @@ Status enum (universal):
433
425
 
434
426
  ```yaml
435
427
  type: l1
436
- aliases: # optional, list of alternative names
437
- brand: # optional, mapping with canonical/variants/pronunciation/comma
438
- domains: # optional, list of relevant domains
439
- version: # optional, monotonic integer — bumped on every material edit to the record.
440
- # The alignment-drift detector ([[HS-E3D3-RDFT-EPIC-alignment-drift-detector-into-resolution]])
441
- # compares the version an epic was last aligned against (its `alignment_baseline`)
442
- # to this current version; a bump past the baseline surfaces a `drift` resolution item.
428
+ aliases: # optional, list of alternative names
429
+ brand: # optional, mapping with canonical/variants/pronunciation/comma
430
+ domains: # optional, list of relevant domains
431
+ version: # optional, monotonic integer — bumped on every material edit to the record.
432
+ # The alignment-drift detector ([[HS-E3D3-RDFT-EPIC-alignment-drift-detector-into-resolution]])
433
+ # compares the version an epic was last aligned against (its `alignment_baseline`)
434
+ # to this current version; a bump past the baseline surfaces a `drift` resolution item.
443
435
  last_edited_at: # optional, ISO-8601 timestamp of the last edit to the record. Timestamp FALLBACK for
444
- # drift detection when an epic carries no per-layer `alignment_baseline`: the layer's
445
- # `last_edited_at` newer than the epic's `alignment_reviewed_at` means drift.
436
+ # drift detection when an epic carries no per-layer `alignment_baseline`: the layer's
437
+ # `last_edited_at` newer than the epic's `alignment_reviewed_at` means drift.
446
438
  ```
447
439
 
448
440
  Only one `l1` exists per vault. The `version` / `last_edited_at` fields are the versioning prerequisites carried from HS-OR8V-0010-EPIC-north-star-vision-first-class-entity; they make the L1 record a drift baseline anchor for the alignment-drift detector.
@@ -455,29 +447,29 @@ Universal fields only. No required L2-specific fields.
455
447
 
456
448
  ```yaml
457
449
  type: l3
458
- actors: # required, list of actor names from L1
459
- trigger: # required, string — what initiates this use case
460
- outcomes: # required, list — observable end states
461
- depends_on: # optional, list of wikilinks to other use cases
450
+ actors: # required, list of actor names from L1
451
+ trigger: # required, string — what initiates this use case
452
+ outcomes: # required, list — observable end states
453
+ depends_on: # optional, list of wikilinks to other use cases
462
454
  ```
463
455
 
464
456
  #### `adr`
465
457
 
466
458
  ```yaml
467
459
  type: adr
468
- decision_date: # required, ISO-8601 date
469
- deciders: # required, list of strings
470
- supersedes: # optional, wikilink to ADR this replaces
471
- superseded_by: # optional, wikilink to ADR replacing this
472
- status: # adr-status enum: proposed | accepted | deprecated
473
- # `superseded` is DEPRECATED 2026-06-03 per [[superseded-enum-values-deprecated-use-canonical-false-and-superseded-by]]
474
- # New writes: set `canonical: false` + `superseded_by: '[[<successor>]]'` instead. Existing
475
- # ADRs that already carry `status: superseded` stay as historical record per the
476
- # immutability principle ([[closed-trackable-specs-are-historical-record-not-living-docs]]) —
477
- # readers infer `canonical: false` from the legacy value.
478
- canonical: # universal flag — true (or absent) = current/authoritative; false = historical record
479
- # (current canonical is at `superseded_by:`). Flipped at supersession-time via
480
- # [[supersession-protocol]]; frozen thereafter.
460
+ decision_date: # required, ISO-8601 date
461
+ deciders: # required, list of strings
462
+ supersedes: # optional, wikilink to ADR this replaces
463
+ superseded_by: # optional, wikilink to ADR replacing this
464
+ status: # adr-status enum: proposed | accepted | deprecated
465
+ # `superseded` is DEPRECATED 2026-06-03 per [[superseded-enum-values-deprecated-use-canonical-false-and-superseded-by]]
466
+ # New writes: set `canonical: false` + `superseded_by: '[[<successor>]]'` instead. Existing
467
+ # ADRs that already carry `status: superseded` stay as historical record per the
468
+ # immutability principle ([[closed-trackable-specs-are-historical-record-not-living-docs]]) —
469
+ # readers infer `canonical: false` from the legacy value.
470
+ canonical: # universal flag — true (or absent) = current/authoritative; false = historical record
471
+ # (current canonical is at `superseded_by:`). Flipped at supersession-time via
472
+ # [[supersession-protocol]]; frozen thereafter.
481
473
  ```
482
474
 
483
475
  The ADR-specific `status` enum overrides the universal status enum for ADRs. The `canonical:` field applies to ADRs the same way it does to every spec type.
@@ -622,43 +614,43 @@ Durable agent identity (HS-XNX5-UQHA-MIL-agent-home). Evergreen — does not clo
622
614
 
623
615
  ```yaml
624
616
  type: agent
625
- role: # required, string — human-readable role title (also used as description fallback on compile)
626
- model: # optional, enum: opus | sonnet | haiku
627
- description: # optional, string — host-native description on compile
628
- goal: # optional, string — HeySpex-resident intent label (not compiled)
629
- allowed_tools: # optional, list of strings — compiled to host `tools:` when present
617
+ role: # required, string — human-readable role title (also used as description fallback on compile)
618
+ model: # optional, enum: opus | sonnet | haiku
619
+ description: # optional, string — host-native description on compile
620
+ goal: # optional, string — HeySpex-resident intent label (not compiled)
621
+ allowed_tools: # optional, list of strings — compiled to host `tools:` when present
630
622
  disallowed_tools: # optional, list of strings — compiled to host `disallowedTools:` when present
631
- procedures: # optional, list of wikilinks — HeySpex-resident procedure refs
632
- handoffs: # optional, list — HeySpex-resident handoff targets
633
- guardrails: # optional, list of strings — HeySpex-resident; persona body carries compiled guardrails
634
- lane: # optional, string — human label for parallel work (advisory in v1)
635
- isolation: # optional, enum: default | worktree — operator guidance for checkout
636
- # isolation when parallel agents each need a dev server; advisory in v1
637
- # ([[parallel-agent-isolation-guidance]]). `worktree` = use a dedicated git
638
- # worktree before implementation. HeySpex-only — stripped on compile (like `lane`).
639
- color: # optional, string — console roster accent (HeySpex-only)
640
- owned_paths: # optional, list of repo-relative glob strings — machine-checkable file/module
641
- # ownership for stomp-detection ([[HS-8PNX-Q1KC-EPIC-lanes-and-stomp-detection-for-parallel-a]]).
642
- # Example: spex-console/src/lib/scheduler/**, vendor/heyspex-mcp/**. HeySpex-only — stripped on compile.
643
- golden_cases: # optional, list of wikilinks to HS-GCASE-* fixtures owned by this agent.
644
- # Reverse of each case's `agent:` pointer. HeySpex-only — stripped on compile
645
- # ([[HS-8AQT-J6FU-TASK-golden-case-vault-artifact-format-and-st]]).
623
+ procedures: # optional, list of wikilinks — HeySpex-resident procedure refs
624
+ handoffs: # optional, list — HeySpex-resident handoff targets
625
+ guardrails: # optional, list of strings — HeySpex-resident; persona body carries compiled guardrails
626
+ lane: # optional, string — human label for parallel work (advisory in v1)
627
+ isolation: # optional, enum: default | worktree — operator guidance for checkout
628
+ # isolation when parallel agents each need a dev server; advisory in v1
629
+ # ([[parallel-agent-isolation-guidance]]). `worktree` = use a dedicated git
630
+ # worktree before implementation. HeySpex-only — stripped on compile (like `lane`).
631
+ color: # optional, string — console roster accent (HeySpex-only)
632
+ owned_paths: # optional, list of repo-relative glob strings — machine-checkable file/module
633
+ # ownership for stomp-detection ([[HS-8PNX-Q1KC-EPIC-lanes-and-stomp-detection-for-parallel-a]]).
634
+ # Example: spex-console/src/lib/scheduler/**, vendor/heyspex-mcp/**. HeySpex-only — stripped on compile.
635
+ golden_cases: # optional, list of wikilinks to HS-GCASE-* fixtures owned by this agent.
636
+ # Reverse of each case's `agent:` pointer. HeySpex-only — stripped on compile
637
+ # ([[HS-8AQT-J6FU-TASK-golden-case-vault-artifact-format-and-st]]).
646
638
  source_attribution: # optional object — import provenance for community/own-agent imports only
647
- tags: # required for roster grouping — MUST include `agent` plus at least one
648
- # `purpose/*` tag (see Purpose tags below). Plain frontmatter array;
649
- # no agent-only grouping engine ([[HS-IAYA-5345-TASK-lock-agent-purpose-taxonomy-and-tag-conv]]).
639
+ tags: # required for roster grouping — MUST include `agent` plus at least one
640
+ # `purpose/*` tag (see Purpose tags below). Plain frontmatter array;
641
+ # no agent-only grouping engine ([[HS-IAYA-5345-TASK-lock-agent-purpose-taxonomy-and-tag-conv]]).
650
642
  ```
651
643
 
652
644
  **Purpose tags** (HS-E2VS-LBUS-EPIC-roster-organization-and-discovery-for-a, HS-WDHW-0009-EPIC-tag-taxonomy-tag-browser-obsidian-style): agent identities reuse the vault's nested-tag namespaces — a dedicated **`purpose/`** namespace (seventh namespace alongside 0009's `area/`, `type/`, `surface/`, `theme/`, `dep/`, `stage/`) for roster discovery. Values are multi-select tags in `tags:`; grouping UI and `GET /api/agents` read them later (HS-NRND-UF9J-TASK-expose-agent-tags-in-get-api-agents-rost).
653
645
 
654
- | Tag | When to use |
655
- | --------------------- | -------------------------------------------------------------------------- |
656
- | `purpose/reviewer` | Verify acceptance criteria, review diffs, read-only audit before close-out |
657
- | `purpose/researcher` | Synthesize cited research into durable `HS-RES-*` specs |
658
- | `purpose/planner` | Ground plans/epics, stress-test assumptions at the plan→execute boundary |
659
- | `purpose/triager` | Intake routing — captures, resolution items, smallest-fix triage |
660
- | `purpose/implementer` | Build, edit, deploy — agents that modify code or infra |
661
- | `purpose/writer` | Prose/docs authoring (reserved; no starter roster member yet) |
646
+ | Tag | When to use |
647
+ |-----|-------------|
648
+ | `purpose/reviewer` | Verify acceptance criteria, review diffs, read-only audit before close-out |
649
+ | `purpose/researcher` | Synthesize cited research into durable `HS-RES-*` specs |
650
+ | `purpose/planner` | Ground plans/epics, stress-test assumptions at the plan→execute boundary |
651
+ | `purpose/triager` | Intake routing — captures, resolution items, smallest-fix triage |
652
+ | `purpose/implementer` | Build, edit, deploy — agents that modify code or infra |
653
+ | `purpose/writer` | Prose/docs authoring (reserved; no starter roster member yet) |
662
654
 
663
655
  Rules:
664
656
 
@@ -672,20 +664,20 @@ Saved eval fixture for the agent testing harness (HS-R1JM-OAG3-EPIC-agent-testin
672
664
 
673
665
  ```yaml
674
666
  type: golden-case
675
- agent: # required, wikilink to HS-AGENT-* — the identity under test
676
- tags: # should include golden-case, agents, testing
677
- related: # optional wikilinks — e.g. the task spec used as setup context
667
+ agent: # required, wikilink to HS-AGENT-* — the identity under test
668
+ tags: # should include golden-case, agents, testing
669
+ related: # optional wikilinks — e.g. the task spec used as setup context
678
670
  ```
679
671
 
680
672
  **Bidirectional linkage:** each golden case carries `agent:`; the agent MAY carry `golden_cases:` (list of wikilinks). Filing via `createSpec` / `heyspex_file_spec` with `frontmatter.agent` auto-appends to the agent's `golden_cases:` array (same pattern as task→epic `children:`).
681
673
 
682
674
  **Required body sections:**
683
675
 
684
- | Section | Required | Purpose |
685
- | -------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
686
- | `## Prompt` | yes | The user message the eval spawn sends to the draft agent (≥12 characters). |
687
- | `## Setup` | no | Freeform context — wikilinks to task specs, files in scope, env hints. |
688
- | `## Deterministic graders` | no | Fenced `yaml` block matching `specs/schemas/golden-case-body.schema.json`. Keys the reproducible pass/fail signal; LLM-judge critique remains advisory per OAG3 AC#4. |
676
+ | Section | Required | Purpose |
677
+ | --- | --- | --- |
678
+ | `## Prompt` | yes | The user message the eval spawn sends to the draft agent (≥12 characters). |
679
+ | `## Setup` | no | Freeform context — wikilinks to task specs, files in scope, env hints. |
680
+ | `## Deterministic graders` | no | Fenced `yaml` block matching `specs/schemas/golden-case-body.schema.json`. Keys the reproducible pass/fail signal; LLM-judge critique remains advisory per OAG3 AC#4. |
689
681
 
690
682
  **On-disk layout:** `specs/agents/golden-cases/HS-GCASE-<suffix>-<slug>.md` — nested under `agents/` so fixtures travel in the same git subtree as agent identities.
691
683
 
@@ -696,39 +688,39 @@ Same as `task` schema (including optional `affects_paths:`). The `type: epic` is
696
688
  **Planning flow requirements** (planning-flow-research-epic-lifecycle): every epic MUST include `research:` and `planning_flow:` wikilinks. Console Epic Studio and `POST /api/specs` enforce this for newly filed epics.
697
689
 
698
690
  ```yaml
699
- research: # required for new epics — wikilink to HS-RES-*
700
- planning_flow: # required for new epics — wikilink to HS-FLOW-*
701
- milestone: # REQUIRED — single wikilink to the parent HS-MIL-* this epic belongs to.
702
- # The inverse of the milestone's `epics:` array (write both sides;
703
- # `scripts/validate-vault-ids.mjs` rejects one-sided drift).
704
- # Grace window: missing `milestone:` is a validator warning until
705
- # 2026-06-26, then escalates to an error
706
- # ([[HS-V5UA-T5PX-TASK-required-milestone-parent-on-epic-validator-and-grace-window]],
707
- # part of [[HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity]]).
708
- # Pre-rule orphan epics live at
709
- # [[HS-3DJS-ORPH-MIL-uncategorized-pre-2026-05-26-epics]]
710
- # pending walk-the-floor reassignment.
711
- derived_from: # optional, single wikilink to HS-RES-* — the research that spawned this epic.
712
- # Reverse of `research.spawned_epics:` (1:N). See §Provenance edges.
691
+ research: # required for new epics — wikilink to HS-RES-*
692
+ planning_flow: # required for new epics — wikilink to HS-FLOW-*
693
+ milestone: # REQUIRED — single wikilink to the parent HS-MIL-* this epic belongs to.
694
+ # The inverse of the milestone's `epics:` array (write both sides;
695
+ # `scripts/validate-vault-ids.mjs` rejects one-sided drift).
696
+ # Grace window: missing `milestone:` is a validator warning until
697
+ # 2026-06-26, then escalates to an error
698
+ # ([[HS-V5UA-T5PX-TASK-required-milestone-parent-on-epic-validator-and-grace-window]],
699
+ # part of [[HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity]]).
700
+ # Pre-rule orphan epics live at
701
+ # [[HS-3DJS-ORPH-MIL-uncategorized-pre-2026-05-26-epics]]
702
+ # pending walk-the-floor reassignment.
703
+ derived_from: # optional, single wikilink to HS-RES-* — the research that spawned this epic.
704
+ # Reverse of `research.spawned_epics:` (1:N). See §Provenance edges.
713
705
  ```
714
706
 
715
707
  **Alignment fields** (drift-detection prerequisites; HS-E3D3-RDFT-EPIC-alignment-drift-detector-into-resolution, owned by HS-KA1E-0012-EPIC-creation-guardrails-agent-pushback for the vault-wide backfill):
716
708
 
717
709
  ```yaml
718
710
  alignment_rationale: # optional (backfill in progress), string — a wikilink to the Pillar / L1 principle
719
- # this epic advances PLUS a one-line "why", e.g.
720
- # "[[HS-PILR-architecture]] — advances the foundations concern by converging detection paths".
721
- # Distinct from the membership `pillar:` field: `pillar:` categorizes; `alignment_rationale`
722
- # carries the teleological "why" the drift detector reasons over. The wikilink target
723
- # SHOULD match the epic's `pillar:`. An `alignment_rationale` that resolves to no layer
724
- # record surfaces as an `orphan` resolution item.
725
- alignment_baseline: # optional, mapping { <layer-id>: <int version>, anti_goals?: <fingerprint> } — the layer
726
- # versions this epic was last aligned against. PRIMARY drift baseline: when a referenced
727
- # layer's current `version` exceeds the baseline here, a `drift` item is emitted. The
728
- # `anti_goals` key stamps the L1 anti-goal fingerprint so a changed anti-goal set re-checks
729
- # every active + recently-closed epic. Absent → the detector falls back to
730
- # `alignment_reviewed_at` vs the layer's `last_edited_at`; absent both → no drift (never a
731
- # false positive). Stamped by the alignment checkpoint on re-alignment.
711
+ # this epic advances PLUS a one-line "why", e.g.
712
+ # "[[HS-PILR-architecture]] — advances the foundations concern by converging detection paths".
713
+ # Distinct from the membership `pillar:` field: `pillar:` categorizes; `alignment_rationale`
714
+ # carries the teleological "why" the drift detector reasons over. The wikilink target
715
+ # SHOULD match the epic's `pillar:`. An `alignment_rationale` that resolves to no layer
716
+ # record surfaces as an `orphan` resolution item.
717
+ alignment_baseline: # optional, mapping { <layer-id>: <int version>, anti_goals?: <fingerprint> } — the layer
718
+ # versions this epic was last aligned against. PRIMARY drift baseline: when a referenced
719
+ # layer's current `version` exceeds the baseline here, a `drift` item is emitted. The
720
+ # `anti_goals` key stamps the L1 anti-goal fingerprint so a changed anti-goal set re-checks
721
+ # every active + recently-closed epic. Absent → the detector falls back to
722
+ # `alignment_reviewed_at` vs the layer's `last_edited_at`; absent both → no drift (never a
723
+ # false positive). Stamped by the alignment checkpoint on re-alignment.
732
724
  ```
733
725
 
734
726
  #### `milestone`
@@ -737,16 +729,16 @@ The grouping **above** epic: a coherent multi-epic ship (a restructure or releas
737
729
 
738
730
  ```yaml
739
731
  type: milestone
740
- status: # one of: open | in_progress | closed (subset of the universal enum)
741
- epics: # list of wikilinks to every child epic — the mirror of each child epic's
742
- # `milestone:` pointer. Write both sides (bidirectional linkage; see [[spec-hierarchy]]).
743
- informed_by: # optional, list of wikilinks to HS-RES-* — research docs that enhance this milestone.
744
- # Reverse of `research.enhances:` (each research enhances exactly one milestone, M:1;
745
- # one milestone may be informed by many research docs over time). Bidirectional
746
- # consistency enforced by `scripts/validate-vault-ids.mjs`. See §Provenance edges.
747
- target_date: # optional, ISO-8601 date or empty string "" — the intended ship date
748
- tags: # optional, list of strings
749
- related: # optional, list of wikilinks
732
+ status: # one of: open | in_progress | closed (subset of the universal enum)
733
+ epics: # list of wikilinks to every child epic — the mirror of each child epic's
734
+ # `milestone:` pointer. Write both sides (bidirectional linkage; see [[spec-hierarchy]]).
735
+ informed_by: # optional, list of wikilinks to HS-RES-* — research docs that enhance this milestone.
736
+ # Reverse of `research.enhances:` (each research enhances exactly one milestone, M:1;
737
+ # one milestone may be informed by many research docs over time). Bidirectional
738
+ # consistency enforced by `scripts/validate-vault-ids.mjs`. See §Provenance edges.
739
+ target_date: # optional, ISO-8601 date or empty string "" — the intended ship date
740
+ tags: # optional, list of strings
741
+ related: # optional, list of wikilinks
750
742
  ```
751
743
 
752
744
  **No scalar `priority:` field.** Milestone ordering is the **output** of the deterministic priority scheduler, never a stored scalar (deterministic-priority-scheduler-supersedes-scored-priority, HS-78E7-Y9OJ-EPIC-deterministic-priority-scheduler). This deliberately diverges from the universal "`priority:` required" rule above — the same way current epics and tasks omit the scalar. Do not add a `priority:` to a milestone.
@@ -761,25 +753,25 @@ A user-reported **bug fix** as first-class executable work — claimable and dec
761
753
 
762
754
  ```yaml
763
755
  type: diagnose
764
- status: # universal enum: open | in_progress | in_review | closed | …
765
- severity: # REQUIRED — one of: error | warning | info. Maps onto the scheduler's
766
- # existing priority signals (channel B): a higher-severity diagnose
767
- # competes higher for on-deck. Drives the derived bug row's color.
768
- parent: # OPTIONAL — single wikilink to an HS-EPIC-* or HS-MIL-* parent.
769
- # Standalone (absent) is the DEFAULT and is exempt from the
770
- # epic→milestone mandatory-parent rule. One-way pointer (no auto back-link).
771
- depends_on: # optional, list of wikilinks — tasks/specs that must close first.
772
- blocks: # optional, list of wikilinks to HS-EPIC-*/HS-TASK-* this fix gates.
773
- # Surfaces as a gating item in that spec's On-Deck overlay (channel A).
774
- promoted_from: # optional, single wikilink to HS-CAP-* — set when this diagnose was promoted
775
- # from a bug-report capture via `heyspex_promote_capture_to_diagnose`.
776
- # Reverse of `capture.promoted_to:` (first-promotion).
777
- derived_from: # optional, single wikilink to HS-RES-* — the research that surfaced this bug,
778
- # set when this diagnose was promoted from a research investigation via
779
- # `heyspex_promote_research_to_diagnose` (mirrors `epic.derived_from`).
780
- # Reverse of `research.produces_diagnose:` (1:N).
781
- tags: # optional, list of strings
782
- related: # optional, list of wikilinks
756
+ status: # universal enum: open | in_progress | in_review | closed | …
757
+ severity: # REQUIRED — one of: error | warning | info. Maps onto the scheduler's
758
+ # existing priority signals (channel B): a higher-severity diagnose
759
+ # competes higher for on-deck. Drives the derived bug row's color.
760
+ parent: # OPTIONAL — single wikilink to an HS-EPIC-* or HS-MIL-* parent.
761
+ # Standalone (absent) is the DEFAULT and is exempt from the
762
+ # epic→milestone mandatory-parent rule. One-way pointer (no auto back-link).
763
+ depends_on: # optional, list of wikilinks — tasks/specs that must close first.
764
+ blocks: # optional, list of wikilinks to HS-EPIC-*/HS-TASK-* this fix gates.
765
+ # Surfaces as a gating item in that spec's On-Deck overlay (channel A).
766
+ promoted_from: # optional, single wikilink to HS-CAP-* — set when this diagnose was promoted
767
+ # from a bug-report capture via `heyspex_promote_capture_to_diagnose`.
768
+ # Reverse of `capture.promoted_to:` (first-promotion).
769
+ derived_from: # optional, single wikilink to HS-RES-* — the research that surfaced this bug,
770
+ # set when this diagnose was promoted from a research investigation via
771
+ # `heyspex_promote_research_to_diagnose` (mirrors `epic.derived_from`).
772
+ # Reverse of `research.produces_diagnose:` (1:N).
773
+ tags: # optional, list of strings
774
+ related: # optional, list of wikilinks
783
775
  ```
784
776
 
785
777
  **No scalar `priority:`** — like task/epic/milestone, ordering is the scheduler's output; `severity:` is the diagnose's contribution to that ranking, not a stored priority.
@@ -792,19 +784,19 @@ Perpetual categorical container that never closes — the cross-cutting axis to
792
784
 
793
785
  ```yaml
794
786
  type: pillar
795
- status: # `perpetual` — non-terminal. Pillars never transition to closed/in_review/etc.
796
- # Universal status enum does NOT apply.
797
- canonical: # required, boolean
798
- # true → curated by HeySpex team; ships pre-loaded in customer vaults; read-only (fork to customize)
799
- # false → customer-scoped Pillar (filed by the customer with high friction)
800
- library_tier: # optional enum: meta | foundational | discretionary (placeholder; library taxonomy TBD)
787
+ status: # `perpetual` — non-terminal. Pillars never transition to closed/in_review/etc.
788
+ # Universal status enum does NOT apply.
789
+ canonical: # required, boolean
790
+ # true → curated by HeySpex team; ships pre-loaded in customer vaults; read-only (fork to customize)
791
+ # false → customer-scoped Pillar (filed by the customer with high friction)
792
+ library_tier: # optional enum: meta | foundational | discretionary (placeholder; library taxonomy TBD)
801
793
  secondary_pillars: # always present; usually empty []. Reserved for future cross-Pillar linking.
802
- version: # optional, monotonic integer — same semantics as the `l1` `version` field above.
803
- # A Pillar edit that materially changes scope bumps this; epics aligned against the
804
- # prior version surface as `drift` items ([[HS-E3D3-RDFT-EPIC-alignment-drift-detector-into-resolution]]).
805
- last_edited_at: # optional, ISO-8601 timestamp of the last edit — drift timestamp fallback (see `l1`).
806
- related: # optional, list of wikilinks
807
- tags: # optional, list of strings
794
+ version: # optional, monotonic integer — same semantics as the `l1` `version` field above.
795
+ # A Pillar edit that materially changes scope bumps this; epics aligned against the
796
+ # prior version surface as `drift` items ([[HS-E3D3-RDFT-EPIC-alignment-drift-detector-into-resolution]]).
797
+ last_edited_at: # optional, ISO-8601 timestamp of the last edit — drift timestamp fallback (see `l1`).
798
+ related: # optional, list of wikilinks
799
+ tags: # optional, list of strings
808
800
  ```
809
801
 
810
802
  The `version` / `last_edited_at` fields are the versioning prerequisites carried from HS-EBIL-0011-EPIC-goal-hierarchy-l2-strategic-pillars-l3; together with the L1 fields they let the alignment-drift detector tell a material Pillar revision apart from a no-op touch.
@@ -812,21 +804,21 @@ The `version` / `last_edited_at` fields are the versioning prerequisites carried
812
804
  **Per-epic membership** (new fields on every epic, added 2026-05-31 by HS-EBIL-0011-EPIC-goal-hierarchy-l2-strategic-pillars-l3):
813
805
 
814
806
  ```yaml
815
- pillar: # required on every epic, single wikilink to a Pillar.
816
- # The home for library/learning. Forces "what perpetual concern does this advance?"
817
- # at filing time. HARD-BLOCKED at the filing boundary (owner decision 2026-06-18):
818
- # POST /api/specs / heyspex_file_spec refuse an epic with no resolvable HS-PILR pillar
819
- # (400 pillar_required). Legacy pillar-less epics are caught by the EPIC_MISSING_PILLAR
820
- # vault-rule — warning (Resolution backfill queue) until 2026-07-31, then error.
821
- # Full rules: [[pillar-assignment-protocol]].
822
- secondary_pillars: # optional, list of wikilinks to Pillars.
823
- # For genuinely cross-cutting work ("Add caching layer" is primarily Scaling but also Reliability).
824
- # Tasks inherit their epic's primary pillar; do not set secondary on tasks.
807
+ pillar: # required on every epic, single wikilink to a Pillar.
808
+ # The home for library/learning. Forces "what perpetual concern does this advance?"
809
+ # at filing time. HARD-BLOCKED at the filing boundary (owner decision 2026-06-18):
810
+ # POST /api/specs / heyspex_file_spec refuse an epic with no resolvable HS-PILR pillar
811
+ # (400 pillar_required). Legacy pillar-less epics are caught by the EPIC_MISSING_PILLAR
812
+ # vault-rule — warning (Resolution backfill queue) until 2026-07-31, then error.
813
+ # Full rules: [[pillar-assignment-protocol]].
814
+ secondary_pillars: # optional, list of wikilinks to Pillars.
815
+ # For genuinely cross-cutting work ("Add caching layer" is primarily Scaling but also Reliability).
816
+ # Tasks inherit their epic's primary pillar; do not set secondary on tasks.
825
817
  ```
826
818
 
827
819
  **Authored as the work surfaces themes.** Pillars are created over time, not enumerated up front — there are deliberately only a few today and many more are expected. When filing an epic surfaces a theme with no pillar yet, the agent is prompted to author one (`heyspex_file_spec({ type: "pillar", name })`); the owner may also author a pillar standalone whenever a theme is foreseen. The procedure is pillar-assignment-protocol.
828
820
 
829
- **Milestones surface a derived pillar roll-up.** A milestone has **no authored `pillar:` field** — it is a dated ship that groups epics, which may belong to different pillars. Instead a milestone _surfaces_ the de-duped set of pillars its child epics carry (computed in `getSpec`, rendered on the milestone detail drawer). The roll-up is derived and may list multiple pillars, so it never drifts from the epics' `pillar:` fields.
821
+ **Milestones surface a derived pillar roll-up.** A milestone has **no authored `pillar:` field** — it is a dated ship that groups epics, which may belong to different pillars. Instead a milestone *surfaces* the de-duped set of pillars its child epics carry (computed in `getSpec`, rendered on the milestone detail drawer). The roll-up is derived and may list multiple pillars, so it never drifts from the epics' `pillar:` fields.
830
822
 
831
823
  **Status semantics.** Pillars carry `status: perpetual` as a single non-terminal value, distinct from the universal enum. The close-out protocol skips Pillars; the scheduler skips Pillars as on-deck candidates (only their epics are scheduled); review-doc flow does not apply. A Pillar's body grows over time as epics close and lessons accumulate against the concern — accumulation IS the point.
832
824
 
@@ -846,34 +838,34 @@ A durable "plan receipt" for one git branch. Ratified by adr-0008-branch-brief-a
846
838
 
847
839
  ```yaml
848
840
  type: branch-brief
849
- branch: # required, string — the raw (unsanitized) git branch name
850
- repo: # optional, string — repo name if multi-repo
851
- goal: # required, string — what this branch is trying to accomplish
852
- implements: # optional, list of wikilinks — tasks/epics this branch implements
853
- plan: # optional, list of { step: int, description: string }
854
- # the ORIGINAL intent. Sourced (priority order) from:
855
- # 1. the linked implementing spec's acceptance criteria
856
- # (its `acceptance:` array, else its `## Acceptance` body)
857
- # 2. a manual plan authored here (exploratory branches)
858
- # Commit messages / PR bodies are NOT v1 plan sources.
859
- actual: # optional, list of { step: int, description: string,
860
- # status: <drift enum>, evidence: [<evidence ref>] }
861
- # what was implemented, captured at brief-generation time.
862
- risks: # optional, list of strings — identified risks/concerns
863
- open_questions: # optional, list of strings — unresolved questions
864
- next_steps: # optional, list of strings — recommended next actions
865
- decisions: # optional, list of wikilinks — memory-decisions made on this branch
866
- evidence: # optional, evidence array (see "Evidence linking" below)
841
+ branch: # required, string — the raw (unsanitized) git branch name
842
+ repo: # optional, string — repo name if multi-repo
843
+ goal: # required, string — what this branch is trying to accomplish
844
+ implements: # optional, list of wikilinks — tasks/epics this branch implements
845
+ plan: # optional, list of { step: int, description: string }
846
+ # the ORIGINAL intent. Sourced (priority order) from:
847
+ # 1. the linked implementing spec's acceptance criteria
848
+ # (its `acceptance:` array, else its `## Acceptance` body)
849
+ # 2. a manual plan authored here (exploratory branches)
850
+ # Commit messages / PR bodies are NOT v1 plan sources.
851
+ actual: # optional, list of { step: int, description: string,
852
+ # status: <drift enum>, evidence: [<evidence ref>] }
853
+ # what was implemented, captured at brief-generation time.
854
+ risks: # optional, list of strings — identified risks/concerns
855
+ open_questions: # optional, list of strings — unresolved questions
856
+ next_steps: # optional, list of strings — recommended next actions
857
+ decisions: # optional, list of wikilinks — memory-decisions made on this branch
858
+ evidence: # optional, evidence array (see "Evidence linking" below)
867
859
  ```
868
860
 
869
861
  **Drift enum** (the `status:` of each `actual` step) — defined once here, reused by HS-838Y-ALDY-TASK-branch-brief-generation and any drift tooling (HS-CM22-0019-EPIC-post-edit-alignment-drift-detection):
870
862
 
871
- | Value | Meaning |
872
- | --------- | ------------------------------------------------------- |
873
- | `match` | Implementation achieves the planned step. |
874
- | `drift` | Implementation differs from the plan in a material way. |
875
- | `missing` | Planned step not implemented. |
876
- | `extra` | Implemented change that was not in the plan. |
863
+ | Value | Meaning |
864
+ | --- | --- |
865
+ | `match` | Implementation achieves the planned step. |
866
+ | `drift` | Implementation differs from the plan in a material way. |
867
+ | `missing` | Planned step not implemented. |
868
+ | `extra` | Implemented change that was not in the plan. |
877
869
 
878
870
  Required body sections: `## Goal`, `## Plan vs Actual` (a table rendering `plan`/`actual` with an `Evidence` column), and — when any step is `drift`/`missing`/`extra` — a `## Drift Analysis` section explaining each, with risk and a recommendation. Optional: `## Decisions`, `## Risks`, `## Open Questions`, `## Next Steps`, `## Evidence`. The frontmatter `plan`/`actual` arrays are canonical for queries; the body table is the human view (same canonical-frontmatter rule as dependencies and tags).
879
871
 
@@ -881,11 +873,11 @@ Required body sections: `## Goal`, `## Plan vs Actual` (a table rendering `plan`
881
873
 
882
874
  ```yaml
883
875
  type: memory-lesson
884
- topic: # required, short string — the subject
885
- observed: # required, ISO-8601 date — when the lesson was learned
886
- related: # optional, list of wikilinks
887
- evidence: # optional, evidence array — sources grounding the problem/fix
888
- # (see "Evidence linking" below)
876
+ topic: # required, short string — the subject
877
+ observed: # required, ISO-8601 date — when the lesson was learned
878
+ related: # optional, list of wikilinks
879
+ evidence: # optional, evidence array — sources grounding the problem/fix
880
+ # (see "Evidence linking" below)
889
881
  ```
890
882
 
891
883
  The body of a memory-lesson spec has two required sections: `## Problem` and `## Fix`.
@@ -894,12 +886,12 @@ The body of a memory-lesson spec has two required sections: `## Problem` and `##
894
886
 
895
887
  ```yaml
896
888
  type: memory-decision
897
- topic: # required, short string
898
- decided: # required, ISO-8601 date
899
- deciders: # required, list of strings
900
- supersedes: # optional, wikilink to a prior decision
901
- evidence: # optional, evidence array — sources grounding the rationale
902
- # (see "Evidence linking" below)
889
+ topic: # required, short string
890
+ decided: # required, ISO-8601 date
891
+ deciders: # required, list of strings
892
+ supersedes: # optional, wikilink to a prior decision
893
+ evidence: # optional, evidence array — sources grounding the rationale
894
+ # (see "Evidence linking" below)
903
895
  ```
904
896
 
905
897
  The body has two required sections: `## Decision` and `## Rationale`. (An ADR is a heavier-weight decision; a `memory-decision` is the day-to-day choice that doesn't warrant an ADR but should still be persisted.)
@@ -908,10 +900,10 @@ The body has two required sections: `## Decision` and `## Rationale`. (An ADR is
908
900
 
909
901
  ```yaml
910
902
  type: memory-reference
911
- topic: # required, short string
912
- url: # optional, URL the reference points at
913
- evidence: # optional, evidence array — additional grounded sources
914
- # (see "Evidence linking" below)
903
+ topic: # required, short string
904
+ url: # optional, URL the reference points at
905
+ evidence: # optional, evidence array — additional grounded sources
906
+ # (see "Evidence linking" below)
915
907
  ```
916
908
 
917
909
  Body is the brief context for why this reference matters.
@@ -920,10 +912,10 @@ Body is the brief context for why this reference matters.
920
912
 
921
913
  ```yaml
922
914
  type: memory-ui-pattern
923
- topic: # required, short string — the pattern name/slug
924
- documented: # required, ISO-8601 date — when the pattern was captured
925
- related: # optional, list of wikilinks
926
- evidence: # optional, evidence array
915
+ topic: # required, short string — the pattern name/slug
916
+ documented: # required, ISO-8601 date — when the pattern was captured
917
+ related: # optional, list of wikilinks
918
+ evidence: # optional, evidence array
927
919
  ```
928
920
 
929
921
  Reusable **console interaction and visual patterns** (keyboard ownership, two-layer highlights, drill-in between panes). Distinct from `memory-ux-principle` (cross-brand rules) and `memory-decision` (a one-time choice). Body sections: `## Pattern`, `## When to apply`, `## Rules`, `## Implementation` (file map + copy-paste shape). See rail-active-vs-keyboard-cursor.
@@ -932,22 +924,22 @@ Reusable **console interaction and visual patterns** (keyboard ownership, two-la
932
924
 
933
925
  ```yaml
934
926
  type: memory-ux-principle
935
- topic: # required, short string — the principle name/slug
936
- documented: # required, ISO-8601 date — when the principle was captured
937
- related: # optional, list of wikilinks
938
- evidence: # optional, evidence array
927
+ topic: # required, short string — the principle name/slug
928
+ documented: # required, ISO-8601 date — when the principle was captured
929
+ related: # optional, list of wikilinks
930
+ evidence: # optional, evidence array
939
931
  ```
940
932
 
941
933
  Cross-brand **interaction rules** (Apple HIG, Material, Linear, Nielsen) — product-agnostic **what/why**. Distinct from `memory-ui-pattern` (HeySpex **how**). Body sections: `## Principle`, `## When to apply`, `## Rules`, `## Related UI patterns`, `## Sources`. See toggle-current-state-semantics and ux-principles-vs-ui-patterns.
942
934
 
943
935
  #### `protocol`
944
936
 
945
- Part of the **Memory** layer (memory-protocols-subsection-of-memory). Epics/tasks that _implement_ or _revise_ a protocol stay in `epics/` / `tasks/`; only the finished operational doc is `type: protocol`.
937
+ Part of the **Memory** layer (memory-protocols-subsection-of-memory). Epics/tasks that *implement* or *revise* a protocol stay in `epics/` / `tasks/`; only the finished operational doc is `type: protocol`.
946
938
 
947
939
  ```yaml
948
940
  type: protocol
949
- scope: # required, one of: session | project | vault | tool
950
- version: # optional, semver-ish version of the protocol
941
+ scope: # required, one of: session | project | vault | tool
942
+ version: # optional, semver-ish version of the protocol
951
943
  ```
952
944
 
953
945
  Body describes the protocol with numbered steps.
@@ -958,13 +950,13 @@ Companion fill-in workspace for a parent spec at `status: in_review`. One review
958
950
 
959
951
  ```yaml
960
952
  type: review
961
- parent: # required, single wikilink — the spec under review
962
- reviews: # optional, single wikilink — same as parent (legacy alias retained for back-compat reads)
963
- # parent: is the canonical edge; reviews: is kept for older docs
953
+ parent: # required, single wikilink — the spec under review
954
+ reviews: # optional, single wikilink — same as parent (legacy alias retained for back-compat reads)
955
+ # parent: is the canonical edge; reviews: is kept for older docs
964
956
  deliberation_record: # optional; Council session output for invocation #4 (review close-out)
965
- # ([[adr-0015-council-as-cross-cutting-capability]]). Schema lives under `draft`
966
- # §`deliberation_record` above. Attached when the human triggers council during
967
- # `/hs-review` close-out; never gates the human's pass/reopen decision.
957
+ # ([[adr-0015-council-as-cross-cutting-capability]]). Schema lives under `draft`
958
+ # §`deliberation_record` above. Attached when the human triggers council during
959
+ # `/hs-review` close-out; never gates the human's pass/reopen decision.
968
960
  ```
969
961
 
970
962
  Body has four required sections — the unified workspace:
@@ -985,17 +977,17 @@ The four-section unified-workspace template and the close-out flow are specified
985
977
  Parallel layer to Memory for **business-side** knowledge: how the product is positioned, priced, marketed, and the business model itself. Like Memory, browsed in the console on its own surface (**Business**) with category filters.
986
978
 
987
979
  ```yaml
988
- type: business-positioning # or business-pricing | business-marketing | business-model
989
- topic: # required, short string — the subject (e.g. "homepage-h1", "tier-table")
990
- status: # universal status enum — draft | open | in_progress | in_review | closed | deferred
991
- # `active` is allowed as a synonym for `open` on migrated docs.
992
- related: # optional, list of wikilinks
993
- evidence: # optional, evidence array — sources grounding the claim/decision
980
+ type: business-positioning # or business-pricing | business-marketing | business-model
981
+ topic: # required, short string — the subject (e.g. "homepage-h1", "tier-table")
982
+ status: # universal status enum — draft | open | in_progress | in_review | closed | deferred
983
+ # `active` is allowed as a synonym for `open` on migrated docs.
984
+ related: # optional, list of wikilinks
985
+ evidence: # optional, evidence array — sources grounding the claim/decision
994
986
  ```
995
987
 
996
988
  Body is free-form prose; the recommended shape is a one-line H1 frame, then sections that match the doc's purpose (e.g. **Decision** / **Why each word is load-bearing** for positioning; **Tier table** / **AI add-on** / **What this also unlocks** for pricing).
997
989
 
998
- Distinct from `memory-decision` — memory captures _how-we-work_ decisions for agents/humans inside the project; business docs capture _what-we-sell-and-how_ decisions for the outside world. A pricing change is a `business-pricing` doc; a "don't mock the database in tests" rule is a `memory-decision`.
990
+ Distinct from `memory-decision` — memory captures *how-we-work* decisions for agents/humans inside the project; business docs capture *what-we-sell-and-how* decisions for the outside world. A pricing change is a `business-pricing` doc; a "don't mock the database in tests" rule is a `memory-decision`.
999
991
 
1000
992
  #### `capture`
1001
993
 
@@ -1003,49 +995,49 @@ Concise core-intent capture **before** research (capture-guardrails). Replaces t
1003
995
 
1004
996
  ```yaml
1005
997
  type: capture
1006
- kind: # required, one of: idea | bug-fix | clip | reference | question | spec-import | feedback
1007
- # idea → speculative concept worth exploring (default — migrated entries land here)
1008
- # bug-fix → defect observation paired with proposed fix
1009
- # clip → web/document excerpt saved verbatim for later use
1010
- # reference → a pointer to an external resource worth keeping
1011
- # question → an open question to revisit when more context lands
1012
- # spec-import→ an imported foreign doc (README / top-level project doc) landed as a RAW
1013
- # capture by the bulk spec-import feature ([[HS-8V8T-8SBG-EPIC-first-connect-rough-import]]);
1014
- # source doc in ## Source Material; carries source_repo/source_path for
1015
- # (repo, vault) idempotency; stays RAW for manual triage. The
1016
- # "pin → run feature pipeline" exit ([[HS-J7T5-VEW8-RES-import-specs-one-click-feature-pipeline]])
1017
- # is a deferred follow-on — NOT wired in this wave.
1018
- # feedback → app feedback / bug report / product idea / support question captured through
1019
- # a deterministic (no-AI) intake channel ([[HS-KQEW-I5DV-EPIC-feedback-capture-type-deterministic]]);
1020
- # classified by `routeFeedback()` ([[HS-FUII-EI9R-TASK-deterministic-feedback-router-module-no]]) toward diagnose/research/
1021
- # answered, or stays `feedback` when unmatched. Optional structured fields below
1022
- # (declared alongside `source:` further down this block — see `example`/
1023
- # `user_story`/`situation`).
1024
- example: # optional, string — a concrete example/repro illustrating the feedback (e.g. steps to reproduce a bug).
1025
- # Only ever populated on `kind: feedback` captures; never forced, never required by the schema.
1026
- user_story: # optional, string — "as a user, I want to… so that…" framing for a feedback-sourced product idea.
1027
- # Same optionality as `example`.
1028
- situation: # optional, string — the situational context the user was in when the feedback arose.
1029
- # Same optionality as `example`.
1030
- capture_status: # required, one of: raw | expanded — default raw
1031
- # raw → no Core Idea content yet (single textarea / quick capture)
1032
- # expanded → Core Idea / Concept / Details has been written (modal v3 or agent rewrite)
1033
- # Flips raw → expanded automatically when an agent writes to core_idea,
1034
- # concept, or agent_expansion via executeUpdateCapture (vendor/heyspex-mcp).
1035
- # Console save-time linter force-corrects raw → expanded when `# Core Idea`
1036
- # body has content. See [[HS-BDDT-Q1B7-EPIC-idea-capture-modal-v3-single-textbox-cle]].
1037
- promoted_to: # binary: null (not promoted) or "[[HS-RES-<suffix>-<slug>]]" (promoted to research).
1038
- # Records the FIRST research doc this capture was promoted into; not the full set.
1039
- # For the M:N "every research doc this capture informs" view, see `informs_research:`.
998
+ kind: # required, one of: idea | bug-fix | clip | reference | question | spec-import | feedback
999
+ # idea → speculative concept worth exploring (default — migrated entries land here)
1000
+ # bug-fix → defect observation paired with proposed fix
1001
+ # clip → web/document excerpt saved verbatim for later use
1002
+ # reference → a pointer to an external resource worth keeping
1003
+ # question → an open question to revisit when more context lands
1004
+ # spec-import→ an imported foreign doc (README / top-level project doc) landed as a RAW
1005
+ # capture by the bulk spec-import feature ([[HS-8V8T-8SBG-EPIC-first-connect-rough-import]]);
1006
+ # source doc in ## Source Material; carries source_repo/source_path for
1007
+ # (repo, vault) idempotency; stays RAW for manual triage. The
1008
+ # "pin → run feature pipeline" exit ([[HS-J7T5-VEW8-RES-import-specs-one-click-feature-pipeline]])
1009
+ # is a deferred follow-on — NOT wired in this wave.
1010
+ # feedback → app feedback / bug report / product idea / support question captured through
1011
+ # a deterministic (no-AI) intake channel ([[HS-KQEW-I5DV-EPIC-feedback-capture-type-deterministic]]);
1012
+ # classified by `routeFeedback()` ([[HS-FUII-EI9R-TASK-deterministic-feedback-router-module-no]]) toward diagnose/research/
1013
+ # answered, or stays `feedback` when unmatched. Optional structured fields below
1014
+ # (declared alongside `source:` further down this block — see `example`/
1015
+ # `user_story`/`situation`).
1016
+ example: # optional, string — a concrete example/repro illustrating the feedback (e.g. steps to reproduce a bug).
1017
+ # Only ever populated on `kind: feedback` captures; never forced, never required by the schema.
1018
+ user_story: # optional, string — "as a user, I want to… so that…" framing for a feedback-sourced product idea.
1019
+ # Same optionality as `example`.
1020
+ situation: # optional, string — the situational context the user was in when the feedback arose.
1021
+ # Same optionality as `example`.
1022
+ capture_status: # required, one of: raw | expanded — default raw
1023
+ # raw → no Core Idea content yet (single textarea / quick capture)
1024
+ # expanded → Core Idea / Concept / Details has been written (modal v3 or agent rewrite)
1025
+ # Flips raw → expanded automatically when an agent writes to core_idea,
1026
+ # concept, or agent_expansion via executeUpdateCapture (vendor/heyspex-mcp).
1027
+ # Console save-time linter force-corrects raw → expanded when `# Core Idea`
1028
+ # body has content. See [[HS-BDDT-Q1B7-EPIC-idea-capture-modal-v3-single-textbox-cle]].
1029
+ promoted_to: # binary: null (not promoted) or "[[HS-RES-<suffix>-<slug>]]" (promoted to research).
1030
+ # Records the FIRST research doc this capture was promoted into; not the full set.
1031
+ # For the M:N "every research doc this capture informs" view, see `informs_research:`.
1040
1032
  informs_research: # optional, list of wikilinks to HS-RES-* — every research doc this capture informs (M:N).
1041
- # Reverse of `research.sources_captures:`. Distinct from `promoted_to:` (binary
1042
- # first-promotion pointer); a capture may appear in multiple research docs over time.
1043
- # Bidirectional consistency enforced by `scripts/validate-vault-ids.mjs`. See §Provenance edges.
1044
- source: # optional capture channel (console, cli, companion, agent, …). On `kind: feedback` captures this
1045
- # also doubles as the free-text originating-channel/page-context signal `routeFeedback()`
1046
- # reads ([[HS-FUII-EI9R-TASK-deterministic-feedback-router-module-no]]) — still optional, never forced.
1047
- related: # optional wikilinks
1048
- legacy_idea_id: # optional, string — original HS-IDEA-* id for migrated entries (archaeology)
1033
+ # Reverse of `research.sources_captures:`. Distinct from `promoted_to:` (binary
1034
+ # first-promotion pointer); a capture may appear in multiple research docs over time.
1035
+ # Bidirectional consistency enforced by `scripts/validate-vault-ids.mjs`. See §Provenance edges.
1036
+ source: # optional capture channel (console, cli, companion, agent, …). On `kind: feedback` captures this
1037
+ # also doubles as the free-text originating-channel/page-context signal `routeFeedback()`
1038
+ # reads ([[HS-FUII-EI9R-TASK-deterministic-feedback-router-module-no]]) — still optional, never forced.
1039
+ related: # optional wikilinks
1040
+ legacy_idea_id: # optional, string — original HS-IDEA-* id for migrated entries (archaeology)
1049
1041
  ```
1050
1042
 
1051
1043
  `promoted_to` is the **single binary promotion field** (HS-KQ5O-IDFV-EPIC-unified-idea-workflow-v2 / HS-QOAC-IDFL-RES-unified-idea-workflow-v2). `research_stage` was removed 2026-05-22; intermediate "promoted-but-research-not-written-yet" state lives in `.heyspex/research-focus.yaml`, not in the spec.
@@ -1060,62 +1052,62 @@ Research is **evergreen** per the lifecycle-class taxonomy above and the canonic
1060
1052
 
1061
1053
  ```yaml
1062
1054
  type: research
1063
- research_type: # REQUIRED, enum — the declared purpose of this research doc, set at creation
1064
- # ([[HS-45YJ-120I-EPIC-research-type-field-the-declared-purpose]]). Coherent with the
1065
- # capture `kind:` vocabulary (`idea | bug-fix | clip | reference | question`) one
1066
- # level up the lifecycle, but not identical — research_type describes what the
1067
- # research is FOR, not what kind of capture seeded it. Five values:
1068
- # new-feature — grounds a not-yet-built capability or product surface
1069
- # enhancement — improves or extends something already shipped
1070
- # diagnose — investigates a bug, defect, or quality problem
1071
- # code-audit — reviews existing code/architecture with no specific bug in hand
1072
- # reference — captures external/background knowledge for reuse (the default)
1073
- # Enforced by `schemas/heyspex-frontmatter.schema.json`. Missing on a pre-existing
1074
- # doc is a WARNING during the grace window (`RESEARCH_TYPE_GRACE_END` in
1075
- # `spex-console/src/lib/indexer/vault-rules.mjs`, mirroring `EPIC_PILLAR_GRACE_END`),
1076
- # then a hard error. Deterministic kind→research_type suggestion is out of scope
1077
- # here — owned by [[HS-6CFV-MVC1-EPIC-deterministic-type-assist-suggest-resear]].
1078
- scope: # optional, enum — how broad a search context this research was run at:
1079
- # internal — specs/, memories, ADRs only
1080
- # codebase — the repo (console/, vendor/, scripts/, etc.)
1081
- # external — web search
1082
- # all — vault + codebase + web
1083
- # Default "internal" when omitted. This is a CONSISTENCY fix, not a new
1084
- # requirement — scope is NOT required and has no grace window
1085
- # ([[HS-NGD1-TASK-consolidate-and-fix-the-research-scope-field]]). Written the
1086
- # same way (same enum, same default) by `heyspex_save_research`,
1087
- # `heyspex_promote_capture`, and `heyspex_complete_research`. Validated as a
1088
- # string enum by `schemas/heyspex-frontmatter.schema.json` (distinct from the
1089
- # unrelated freetext `scope:` on `type: protocol`).
1090
- enhances: # REQUIRED when set — bidirectional consistency rule. If `enhances:` exists, the
1091
- # target milestone MUST list this research in `informed_by:` (see §Provenance edges).
1092
- # Single wikilink to the HS-MIL-* this research enhances. Not an array (M:1 rule).
1093
- # Open research may omit during exploration; the validator enforces bidirectional
1094
- # consistency whenever the field IS set. A research doc that spans multiple
1095
- # milestones must be split first ([[HS-TQQS-GTH9-TASK-hs-split-research-mcp-tool]]).
1096
- # NOTE: `scripts/validate-vault-ids.mjs` still gates on the legacy
1097
- # `status: closed` framing — validator catch-up to this "when set" framing is on
1098
- # the deferred list in [[research-is-evergreen]].
1055
+ research_type: # REQUIRED, enum — the declared purpose of this research doc, set at creation
1056
+ # ([[HS-45YJ-120I-EPIC-research-type-field-the-declared-purpose]]). Coherent with the
1057
+ # capture `kind:` vocabulary (`idea | bug-fix | clip | reference | question`) one
1058
+ # level up the lifecycle, but not identical — research_type describes what the
1059
+ # research is FOR, not what kind of capture seeded it. Five values:
1060
+ # new-feature — grounds a not-yet-built capability or product surface
1061
+ # enhancement — improves or extends something already shipped
1062
+ # diagnose — investigates a bug, defect, or quality problem
1063
+ # code-audit — reviews existing code/architecture with no specific bug in hand
1064
+ # reference — captures external/background knowledge for reuse (the default)
1065
+ # Enforced by `schemas/heyspex-frontmatter.schema.json`. Missing on a pre-existing
1066
+ # doc is a WARNING during the grace window (`RESEARCH_TYPE_GRACE_END` in
1067
+ # `spex-console/src/lib/indexer/vault-rules.mjs`, mirroring `EPIC_PILLAR_GRACE_END`),
1068
+ # then a hard error. Deterministic kind→research_type suggestion is out of scope
1069
+ # here — owned by [[HS-6CFV-MVC1-EPIC-deterministic-type-assist-suggest-resear]].
1070
+ scope: # optional, enum — how broad a search context this research was run at:
1071
+ # internal — specs/, memories, ADRs only
1072
+ # codebase — the repo (console/, vendor/, scripts/, etc.)
1073
+ # external — web search
1074
+ # all — vault + codebase + web
1075
+ # Default "internal" when omitted. This is a CONSISTENCY fix, not a new
1076
+ # requirement — scope is NOT required and has no grace window
1077
+ # ([[HS-NGD1-TASK-consolidate-and-fix-the-research-scope-field]]). Written the
1078
+ # same way (same enum, same default) by `heyspex_save_research`,
1079
+ # `heyspex_promote_capture`, and `heyspex_complete_research`. Validated as a
1080
+ # string enum by `schemas/heyspex-frontmatter.schema.json` (distinct from the
1081
+ # unrelated freetext `scope:` on `type: protocol`).
1082
+ enhances: # REQUIRED when set — bidirectional consistency rule. If `enhances:` exists, the
1083
+ # target milestone MUST list this research in `informed_by:` (see §Provenance edges).
1084
+ # Single wikilink to the HS-MIL-* this research enhances. Not an array (M:1 rule).
1085
+ # Open research may omit during exploration; the validator enforces bidirectional
1086
+ # consistency whenever the field IS set. A research doc that spans multiple
1087
+ # milestones must be split first ([[HS-TQQS-GTH9-TASK-hs-split-research-mcp-tool]]).
1088
+ # NOTE: `scripts/validate-vault-ids.mjs` still gates on the legacy
1089
+ # `status: closed` framing — validator catch-up to this "when set" framing is on
1090
+ # the deferred list in [[research-is-evergreen]].
1099
1091
  sources_captures: # optional, list of wikilinks to HS-CAP-* — captures this research aggregates (M:N).
1100
- # Reverse of `capture.informs_research:`. Bidirectional consistency enforced.
1101
- spawned_epics: # optional, list of wikilinks to HS-EPIC-* — epics this research spawned (1:N).
1102
- # Reverse of `epic.derived_from:`.
1103
- enhances_epics: # optional, list of wikilinks to HS-EPIC-* — already-existing epics this research
1104
- # augmented (M:N, rare). One-sided in v1 — no reverse field on epic.
1092
+ # Reverse of `capture.informs_research:`. Bidirectional consistency enforced.
1093
+ spawned_epics: # optional, list of wikilinks to HS-EPIC-* — epics this research spawned (1:N).
1094
+ # Reverse of `epic.derived_from:`.
1095
+ enhances_epics: # optional, list of wikilinks to HS-EPIC-* — already-existing epics this research
1096
+ # augmented (M:N, rare). One-sided in v1 — no reverse field on epic.
1105
1097
  produces_diagnose: # optional, list of wikilinks to HS-DIAG-* — bugs found during this research and
1106
- # promoted to a diagnose (1:N, mirrors `spawned_epics`). Reverse of
1107
- # `diagnose.derived_from:`. Written by `heyspex_promote_research_to_diagnose`
1108
- # ([[HS-W5VP-MSHY-TASK-research-diagnose-link-send-bugs-to-the]]); reuses the existing
1109
- # diagnose machinery — see [[resolution-diagnose-workflow]].
1110
- split_into: # optional, list of wikilinks — on the original (archive) research when split;
1111
- # names the child research docs that carry forward.
1112
- split_from: # optional, single wikilink — on a research created by splitting from an ancestor;
1113
- # mirror of `split_into:` on the ancestor.
1114
- source_capture: # optional wikilink to HS-CAP-* — legacy single-capture seed pointer; retained for
1115
- # read-side back-compat. New research uses `sources_captures:` (M:N) as canonical.
1116
- planning_flow: # optional until flow filed; then wikilink to HS-FLOW-*
1117
- bound_epic: # optional; set when epic filed — locks findings to append-only ([[planning-flow-research-epic-lifecycle]])
1118
- forked_from: # optional, wikilink — source HS-RES when forked for a new epic
1098
+ # promoted to a diagnose (1:N, mirrors `spawned_epics`). Reverse of
1099
+ # `diagnose.derived_from:`. Written by `heyspex_promote_research_to_diagnose`
1100
+ # ([[HS-W5VP-MSHY-TASK-research-diagnose-link-send-bugs-to-the]]); reuses the existing
1101
+ # diagnose machinery — see [[resolution-diagnose-workflow]].
1102
+ split_into: # optional, list of wikilinks — on the original (archive) research when split;
1103
+ # names the child research docs that carry forward.
1104
+ split_from: # optional, single wikilink — on a research created by splitting from an ancestor;
1105
+ # mirror of `split_into:` on the ancestor.
1106
+ source_capture: # optional wikilink to HS-CAP-* — legacy single-capture seed pointer; retained for
1107
+ # read-side back-compat. New research uses `sources_captures:` (M:N) as canonical.
1108
+ planning_flow: # optional until flow filed; then wikilink to HS-FLOW-*
1109
+ bound_epic: # optional; set when epic filed — locks findings to append-only ([[planning-flow-research-epic-lifecycle]])
1110
+ forked_from: # optional, wikilink — source HS-RES when forked for a new epic
1119
1111
  ```
1120
1112
 
1121
1113
  Body is the research note. After `bound_epic:` is set, findings sections are append-only; new epic scope uses `## Scope for <epic name>` addendum sections.
@@ -1124,9 +1116,9 @@ Body is the research note. After `bound_epic:` is set, findings sections are app
1124
1116
 
1125
1117
  A `research_type: code-audit` doc's body **must** carry a findings table — the authored standard for "reviewed the code, found N things, here's what happens to each" (HS-7D0I-WL88-TASK-code-audit-research-type-with-a-defined). Four columns, in this order:
1126
1118
 
1127
- | Finding | Severity | Action (diagnose\|task\|reference) | Exit (open\|closed) |
1128
- | -------------------------------------- | ---------------------------- | ----------------------------------- | ------------------- |
1129
- | One-line description of what was found | freetext (e.g. high/med/low) | `diagnose` \| `task` \| `reference` | `open` \| `closed` |
1119
+ | Finding | Severity | Action (diagnose\|task\|reference) | Exit (open\|closed) |
1120
+ | --- | --- | --- | --- |
1121
+ | One-line description of what was found | freetext (e.g. high/med/low) | `diagnose` \| `task` \| `reference` | `open` \| `closed` |
1130
1122
 
1131
1123
  Every row's `Action` maps to exactly one of three defined exits — no fourth "just leave it" option:
1132
1124
 
@@ -1145,19 +1137,19 @@ Orchestration artifact for epic filing (planning-flow-research-epic-lifecycle).
1145
1137
 
1146
1138
  ```yaml
1147
1139
  type: planning-flow
1148
- research: # required, wikilink to HS-RES-*
1149
- decisions: # optional, list of wikilinks — memory-decision or adr
1150
- epic: # optional until epic filed; then wikilink to HS-EPIC-*
1151
- has_diagram: # required, true — indexes canvas bridge + Shipped gallery when closed
1152
- related: # optional, wikilinks to tasks and supporting specs
1140
+ research: # required, wikilink to HS-RES-*
1141
+ decisions: # optional, list of wikilinks — memory-decision or adr
1142
+ epic: # optional until epic filed; then wikilink to HS-EPIC-*
1143
+ has_diagram: # required, true — indexes canvas bridge + Shipped gallery when closed
1144
+ related: # optional, wikilinks to tasks and supporting specs
1153
1145
  ```
1154
1146
 
1155
1147
  #### `roadmap`
1156
1148
 
1157
1149
  ```yaml
1158
1150
  type: roadmap
1159
- roadmap_manifest: # required, machine-readable phase index (see below)
1160
- related_roadmaps: # optional, wikilinks to other HS-ROADMAP-* specs
1151
+ roadmap_manifest: # required, machine-readable phase index (see below)
1152
+ related_roadmaps: # optional, wikilinks to other HS-ROADMAP-* specs
1161
1153
  ```
1162
1154
 
1163
1155
  `roadmap_manifest` shape (indexer validates; agents request via `--compact`):
@@ -1166,12 +1158,12 @@ related_roadmaps: # optional, wikilinks to other HS-ROADMAP-* specs
1166
1158
  roadmap_manifest:
1167
1159
  version: 1
1168
1160
  phases:
1169
- - id: M2 # short stable id
1161
+ - id: M2 # short stable id
1170
1162
  name: Indexer MVP
1171
- tasks: [HS-V3YS, HS-1BML] # HS-NNNN or HS-EPIC-NNNN ids
1172
- horizon: # may not ship — priority-4 / tag:horizon backlog
1163
+ tasks: [HS-V3YS, HS-1BML] # HS-NNNN or HS-EPIC-NNNN ids
1164
+ horizon: # may not ship — priority-4 / tag:horizon backlog
1173
1165
  - HS-WYHZ
1174
- initiatives: # optional links to other roadmap docs
1166
+ initiatives: # optional links to other roadmap docs
1175
1167
  - HS-ROADMAP-VOICE-CHROME
1176
1168
  ```
1177
1169
 
@@ -1183,44 +1175,44 @@ Horizon items use native `HS-NNNN` ids (or wikilinks to `future-considerations/`
1183
1175
 
1184
1176
  ```yaml
1185
1177
  type: draft
1186
- source: # optional, where this draft came from (URL, "phone capture", "screenshot", etc.)
1187
- captured_at: # required, ISO-8601 datetime
1178
+ source: # optional, where this draft came from (URL, "phone capture", "screenshot", etc.)
1179
+ captured_at: # required, ISO-8601 datetime
1188
1180
  source_intent_hash: # optional but required on Agent ingest; SHA-256 of canonical capture blob ([[plan-ingest-review-roadmap-workflow]])
1189
- source_intent: # optional verbatim excerpt (≤2 KB) of human inputs at capture time
1181
+ source_intent: # optional verbatim excerpt (≤2 KB) of human inputs at capture time
1190
1182
  agent_output_hash: # optional; SHA-256 of structured Agent preview at Save-to-drafts
1191
- review_stage: # optional, enum: inbox | deliberating | staging | review | promoted | rejected
1183
+ review_stage: # optional, enum: inbox | deliberating | staging | review | promoted | rejected
1192
1184
  council_requested: # optional bool | null — per-submit override; null = apply deliberation.triggers policy ([[council-opt-in-pre-review-conditioning]])
1193
- triage_record: # optional; scout pre-pass ([[council-triage-scout-optional-llm]], [[review-inbox-workshop-scout-overview]])
1185
+ triage_record: # optional; scout pre-pass ([[council-triage-scout-optional-llm]], [[review-inbox-workshop-scout-overview]])
1194
1186
  deliberation_record: # optional; Gate 0 output ([[ai-deliberation-gate]]) — append-only runs
1195
- suggestions: # optional; staged Gate A records ([[HS-EU98-GCGE-TASK-staged-draft-suggestion-schema]]) — omit when empty
1196
- review_record: # optional; Gate A commit audit — who/when/per-suggestion outcomes
1197
- ingest_mode: # optional, enum: manual | agent_llm — default manual when omitted
1198
- capture_scope: # optional, enum: selection | full — did a highlight scope the body? (HS-M54O); absent ⇒ full
1199
- purpose: # optional free string — the user's stated "why" for capturing (HS-7S40)
1200
- context_blocks: # optional list of { source: typed | voice, text, at: ISO-8601 } — enrichment
1201
- # added on the intent card (HS-JQ7O/0077), each bound to this draft's trace_id.
1202
- # Append-only within a trace_id; ordered by `at`. Absent ⇒ no extra context.
1203
- llm_route: # optional, required when ingest_mode is agent_llm — builder-selected route from console picker:
1204
- # chatgpt | gemini | claude | auto | ... (enum grows with integrations; must stay in sync with UI labels)
1187
+ suggestions: # optional; staged Gate A records ([[HS-EU98-GCGE-TASK-staged-draft-suggestion-schema]]) — omit when empty
1188
+ review_record: # optional; Gate A commit audit — who/when/per-suggestion outcomes
1189
+ ingest_mode: # optional, enum: manual | agent_llm — default manual when omitted
1190
+ capture_scope: # optional, enum: selection | full — did a highlight scope the body? (HS-M54O); absent ⇒ full
1191
+ purpose: # optional free string — the user's stated "why" for capturing (HS-7S40)
1192
+ context_blocks: # optional list of { source: typed | voice, text, at: ISO-8601 } — enrichment
1193
+ # added on the intent card (HS-JQ7O/0077), each bound to this draft's trace_id.
1194
+ # Append-only within a trace_id; ordered by `at`. Absent ⇒ no extra context.
1195
+ llm_route: # optional, required when ingest_mode is agent_llm — builder-selected route from console picker:
1196
+ # chatgpt | gemini | claude | auto | ... (enum grows with integrations; must stay in sync with UI labels)
1205
1197
  llm_resolved_at: # optional, ISO-8601 datetime when ingest_mode agent_llm — when the routed model finished
1206
- resolved_model: # optional free string or structured id — actual provider/model id after routing (meaningful when llm_route: auto or when aliases map to concrete models)
1207
- submission_kind: # optional, enum: external_media | refined_intent — Gate 0 epistemic mode ([[companion-external-media-vs-refined-intent-council]]); companion defaults external_media
1208
- capture_channel: # optional, enum: manual_ui | cli | voice | extension | companion | ...
1198
+ resolved_model: # optional free string or structured id — actual provider/model id after routing (meaningful when llm_route: auto or when aliases map to concrete models)
1199
+ submission_kind: # optional, enum: external_media | refined_intent — Gate 0 epistemic mode ([[companion-external-media-vs-refined-intent-council]]); companion defaults external_media
1200
+ capture_channel: # optional, enum: manual_ui | cli | voice | extension | companion | ...
1209
1201
  companion_dialogue: # optional append-only [{ role: user|assistant, text, at }] — pre-send chat about capture ([[HS-67TW-2966-TASK-companion-pre-council-context-dialogue]]); omit when empty
1210
- capture_group_id: # optional string — shared id linking multiple captures made in one multi-capture
1211
- # companion session; drafts sharing this id render as a connected set on the
1212
- # Captures surface, ordered by capture_group_seq. Distinct from capture_bundle_id
1213
- # below (one composite draft with multiple sources) — this links multiple SEPARATE
1214
- # draft files. Omit for standalone single captures.
1202
+ capture_group_id: # optional string — shared id linking multiple captures made in one multi-capture
1203
+ # companion session; drafts sharing this id render as a connected set on the
1204
+ # Captures surface, ordered by capture_group_seq. Distinct from capture_bundle_id
1205
+ # below (one composite draft with multiple sources) — this links multiple SEPARATE
1206
+ # draft files. Omit for standalone single captures.
1215
1207
  capture_group_seq: # optional positive integer — 1-based position within capture_group_id's group.
1216
- # Only meaningful when capture_group_id is set.
1208
+ # Only meaningful when capture_group_id is set.
1217
1209
  capture_bundle_id: # optional UUID — companion-local bundle id when submitted from Capture inbox ([[companion-capture-inbox-and-bundles]])
1218
- source_set: # optional — multi-source bundle; list of members, each with { url | file_path, title, member_trace_id, member_note, file_size?, file_type? }
1219
- # For web captures: url (required), title, member_trace_id, member_note ([[HS-D1YU-OVFO-TASK-bundle-submit-composite-draft-source-set]])
1220
- # For file captures: file_path (required), title (filename), file_size, file_type, member_trace_id, member_note ([[HS-5FI0-0036-EPIC-file-system-selection-voice-capture]])
1221
- # Omit for single-source captures
1222
- wake_used: # optional bool — companion wake phrase invoked (vs shortcut-only capture)
1223
- foreground_app: # optional string — OS-visible focused app title/name at capture time
1210
+ source_set: # optional — multi-source bundle; list of members, each with { url | file_path, title, member_trace_id, member_note, file_size?, file_type? }
1211
+ # For web captures: url (required), title, member_trace_id, member_note ([[HS-D1YU-OVFO-TASK-bundle-submit-composite-draft-source-set]])
1212
+ # For file captures: file_path (required), title (filename), file_size, file_type, member_trace_id, member_note ([[HS-5FI0-0036-EPIC-file-system-selection-voice-capture]])
1213
+ # Omit for single-source captures
1214
+ wake_used: # optional bool — companion wake phrase invoked (vs shortcut-only capture)
1215
+ foreground_app: # optional string — OS-visible focused app title/name at capture time
1224
1216
  spoken_command_tail: # optional sanitized transcript excerpt when capture_channel includes voice (see [[uc-voice-ingest-hey-spex]])
1225
1217
  shortcut_binding_id: # optional stable identifier for whichever hotkey initiated capture
1226
1218
  voice_companion_semver: # optional — installed companion semantic version emitting the draft
@@ -1237,15 +1229,15 @@ chrome_viewport_ratio_y:
1237
1229
  pointer_dom_hint: # optional heuristic from Chrome elementFromPoint; non-authoritative
1238
1230
 
1239
1231
  # File capture provenance (when source_type: local_file) — [[HS-5FI0-0036-EPIC-file-system-selection-voice-capture]]
1240
- source_type: # optional enum: local_file | url — discriminator; url is default/implicit for browser captures
1241
- file_path: # optional string — absolute path (single file or root folder); present when source_type: local_file
1242
- file_size: # optional int — file size in bytes
1243
- file_type: # optional string — MIME type or file extension
1232
+ source_type: # optional enum: local_file | url — discriminator; url is default/implicit for browser captures
1233
+ file_path: # optional string — absolute path (single file or root folder); present when source_type: local_file
1234
+ file_size: # optional int — file size in bytes
1235
+ file_type: # optional string — MIME type or file extension
1244
1236
  file_modified_at: # optional ISO-8601 — file mtime at capture
1245
- folder_depth: # optional int — recursion depth when folder captured
1237
+ folder_depth: # optional int — recursion depth when folder captured
1246
1238
  folder_file_count: # optional int — total files in folder/zip capture
1247
- zip_extracted: # optional bool — true if zip was extracted to temp for ingestion
1248
- zip_source_path: # optional string — original zip path when zip_extracted: true
1239
+ zip_extracted: # optional bool — true if zip was extracted to temp for ingestion
1240
+ zip_source_path: # optional string — original zip path when zip_extracted: true
1249
1241
  sensitive_files_included: # optional list of { path, pattern_matched, user_confirmed_at } — audit when user overrode sensitive file warning
1250
1242
  ```
1251
1243
 
@@ -1256,6 +1248,7 @@ Agent-assisted drafts **should** end the markdown body with a short human-readab
1256
1248
  Example footer (console-rendered; values must mirror frontmatter):
1257
1249
 
1258
1250
  ```markdown
1251
+
1259
1252
  ---
1260
1253
 
1261
1254
  _Ingest provenance:_ route `claude` → resolved `anthropic/claude-3-7-sonnet` · _Captured:_ 2026-05-16T12:00:00Z
@@ -1334,10 +1327,10 @@ triage_record:
1334
1327
  suggestions:
1335
1328
  - id: "<stable-uuid-within-draft>"
1336
1329
  kind: roadmap | priority | child_task | consideration
1337
- payload: {} # kind-specific proposed fields (epic stub, priority, etc.)
1330
+ payload: {} # kind-specific proposed fields (epic stub, priority, etc.)
1338
1331
  rationale: "<one line>"
1339
1332
  disposition: pending | accepted | edited | declined
1340
- edited_payload: {} # optional; present when disposition: edited
1333
+ edited_payload: {} # optional; present when disposition: edited
1341
1334
  provenance:
1342
1335
  llm_route: "<enum>"
1343
1336
  resolved_model: "<provider/model>"
@@ -1360,7 +1353,7 @@ review_record:
1360
1353
 
1361
1354
  ```yaml
1362
1355
  type: daily
1363
- date: # required, ISO-8601 date
1356
+ date: # required, ISO-8601 date
1364
1357
  ```
1365
1358
 
1366
1359
  Body is free-form notes for the day.
@@ -1378,9 +1371,9 @@ Beyond the type-specific required sections noted above, all specs follow these s
1378
1371
 
1379
1372
  Two SCEH-Pattern conventions (HS-U88E-SP34-EPIC-sceh-patterns-3-and-4-markdown-conventions) define optional `##` sections useful on specs that accumulate work across many sessions:
1380
1373
 
1381
- | Section | Protocol | Use when | Placement |
1382
- | ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
1383
- | `## Session Boundaries` | session-boundary-marker | Multi-session epics, milestones, and HS-REV review docs benefit from a five-column session-by-session trail (`session_id` / `agent` / `started` / `ended` / `summary`). | Immediately above `## Change log`. |
1374
+ | Section | Protocol | Use when | Placement |
1375
+ |---|---|---|---|
1376
+ | `## Session Boundaries` | session-boundary-marker | Multi-session epics, milestones, and HS-REV review docs benefit from a five-column session-by-session trail (`session_id` / `agent` / `started` / `ended` / `summary`). | Immediately above `## Change log`. |
1384
1377
  | `## Conflict Resolution` | conflict-resolution-section | Two or more sessions left contradictory opinions in the body, change log, or HS-REV companions and a reviewer has had to pick. Three-row table (opinions + bold `**resolution**`) with optional memory-extraction routing into `memory-decision` specs. | Below `## Session Boundaries` if present, above `## Change log`. |
1385
1378
 
1386
1379
  Both are **recommended** — opt-in per spec, not enforced by the wikilink validator. They are content commentary about the spec; control-plane runtime state (claim/focus/spec events, handoff context) stays in Neon (control-plane-belongs-in-neon).
@@ -1389,13 +1382,13 @@ Both are **recommended** — opt-in per spec, not enforced by the wikilink valid
1389
1382
 
1390
1383
  HeySpex inherits beads' four dependency types and adds a normalization choice: dependencies are expressed **both** as structured frontmatter arrays **and** as inline wikilinks in body prose. The frontmatter is canonical for queries; the body wikilinks are for reading flow.
1391
1384
 
1392
- | Type | Frontmatter field | Inverse field | Semantics |
1393
- | ------------------- | -------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1394
- | **Blocks** | `blocks: [[...]]` | `blocked_by: [[...]]` | Hard. A blocked task is not ready until all `blocked_by` resolve. |
1395
- | **Related** | `related: [[...]]` | `related:` (symmetric) | Soft. Navigational only; no readiness implication. |
1396
- | **Parent-child** | `children: [[...]]` | `parent: [[...]]` | Hierarchical. Children roll up to parent for "completion of parent" calculations. |
1397
- | **Discovered-from** | `discovered_from: [[...]]` | `discovered:` (list) | Provenance. "This task was born while working on X." |
1398
- | **Iterates-on** | `iterates_on: [[...]]` | `iteratedBy:` (computed) | Re-attempt. "This initiative re-attempts an outcome the target shipped but did not fully deliver." No readiness implication; neither doc is demoted. See §Iteration lineage below. |
1385
+ | Type | Frontmatter field | Inverse field | Semantics |
1386
+ | --- | --- | --- | --- |
1387
+ | **Blocks** | `blocks: [[...]]` | `blocked_by: [[...]]` | Hard. A blocked task is not ready until all `blocked_by` resolve. |
1388
+ | **Related** | `related: [[...]]` | `related:` (symmetric) | Soft. Navigational only; no readiness implication. |
1389
+ | **Parent-child** | `children: [[...]]` | `parent: [[...]]` | Hierarchical. Children roll up to parent for "completion of parent" calculations. |
1390
+ | **Discovered-from** | `discovered_from: [[...]]` | `discovered:` (list) | Provenance. "This task was born while working on X." |
1391
+ | **Iterates-on** | `iterates_on: [[...]]` | `iteratedBy:` (computed) | Re-attempt. "This initiative re-attempts an outcome the target shipped but did not fully deliver." No readiness implication; neither doc is demoted. See §Iteration lineage below. |
1399
1392
 
1400
1393
  Rules:
1401
1394
 
@@ -1409,13 +1402,13 @@ Rules:
1409
1402
 
1410
1403
  The promotion lifecycle — capture observation → research synthesis → milestone commitment — has cross-type provenance edges with strict cardinalities. Ratified by HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity §Architecture; enforced by `scripts/validate-vault-ids.mjs` (HS-HQRM-YJX6-TASK-research-enhances-exactly-one-milestone-validator-and-bidirectional-linkage).
1411
1404
 
1412
- | Edge | Cardinality | Forward field | Reverse field |
1413
- | ----------------------------------- | ---------------- | ----------------------------------------------------- | ---------------------------------------------- |
1414
- | **Capture → Research** | M:N | `capture.informs_research: [[[HS-RES-…]]]` | `research.sources_captures: [[[HS-CAP-…]]]` |
1415
- | **Research → Milestone** | **M:1** (strict) | `research.enhances: [[HS-MIL-…]]` (single, not array) | `milestone.informed_by: [[[HS-RES-…]]]` |
1416
- | **Research → Epic (spawned)** | 1:N | `research.spawned_epics: [[[HS-EPIC-…]]]` | `epic.derived_from: [[HS-RES-…]]` (single) |
1417
- | **Research → Epic (augmented)** | M:N | `research.enhances_epics: [[[HS-EPIC-…]]]` | (one-sided — no reverse field on epic in v1) |
1418
- | **Research → Diagnose (bug found)** | 1:N | `research.produces_diagnose: [[[HS-DIAG-…]]]` | `diagnose.derived_from: [[HS-RES-…]]` (single) |
1405
+ | Edge | Cardinality | Forward field | Reverse field |
1406
+ | --- | --- | --- | --- |
1407
+ | **Capture → Research** | M:N | `capture.informs_research: [[[HS-RES-…]]]` | `research.sources_captures: [[[HS-CAP-…]]]` |
1408
+ | **Research → Milestone** | **M:1** (strict) | `research.enhances: [[HS-MIL-…]]` (single, not array) | `milestone.informed_by: [[[HS-RES-…]]]` |
1409
+ | **Research → Epic (spawned)** | 1:N | `research.spawned_epics: [[[HS-EPIC-…]]]` | `epic.derived_from: [[HS-RES-…]]` (single) |
1410
+ | **Research → Epic (augmented)** | M:N | `research.enhances_epics: [[[HS-EPIC-…]]]` | (one-sided — no reverse field on epic in v1) |
1411
+ | **Research → Diagnose (bug found)** | 1:N | `research.produces_diagnose: [[[HS-DIAG-…]]]` | `diagnose.derived_from: [[HS-RES-…]]` (single) |
1419
1412
 
1420
1413
  Rules:
1421
1414
 
@@ -1424,37 +1417,37 @@ Rules:
1424
1417
  - **`enhances:` is single-valued.** Not an array — the validator rejects array form and points the author at the split flow.
1425
1418
  - **Bidirectional consistency is enforced.** If research X has `enhances: Y`, milestone Y MUST list X in `informed_by:`. If capture C has `informs_research: [X, Y]`, both X.sources_captures and Y.sources_captures MUST include C. The validator surfaces one-sided drift as a hard error on each side.
1426
1419
  - **Captures M:N research is intentional.** A single capture may inform multiple research docs over time (e.g. a "voice capture works" observation that lands in both companion research and console-voice research). The first promotion writes `capture.promoted_to:` (binary pointer); subsequent re-uses extend `capture.informs_research:` without touching `promoted_to:`.
1427
- - **`spawned_epics` vs `enhances_epics`.** `spawned_epics` is the canonical 1:N edge — epics this research _created_, mirrored as `epic.derived_from:` on each child. `enhances_epics` is the rarer case where research _augmented_ an already-existing epic; it's a one-sided list with no reverse field in v1.
1420
+ - **`spawned_epics` vs `enhances_epics`.** `spawned_epics` is the canonical 1:N edge — epics this research *created*, mirrored as `epic.derived_from:` on each child. `enhances_epics` is the rarer case where research *augmented* an already-existing epic; it's a one-sided list with no reverse field in v1.
1428
1421
  - **`produces_diagnose` mirrors `spawned_epics`.** A research investigation may surface a bug, which is promoted into a first-class `HS-DIAG-*` (not new machinery — the existing diagnose entity per resolution-diagnose-workflow). `research.produces_diagnose:` is the canonical 1:N edge, mirrored as `diagnose.derived_from:` on each child, written by `heyspex_promote_research_to_diagnose`. This is the research-side sibling of the capture-side exit `heyspex_promote_capture_to_diagnose` (which writes `diagnose.promoted_from:` ⇔ `capture.promoted_to:`/`informs_diagnose:` instead).
1429
1422
 
1430
1423
  Promotion-action contract (`/hs-promote-research`, HS-2ERO-QQHP-TASK-hs-promote-research-mcp-tool): writes all four sides (research.enhances, research.spawned_epics, milestone.informed_by, epic.derived_from) atomically. The validator is the safety net for hand-edited drift, not the primary write path.
1431
1424
 
1432
1425
  ## Iteration lineage (round-to-round re-attempts)
1433
1426
 
1434
- The **third doc-to-doc relation tier**, alongside supersession (terminal, whole-doc) and amends (partial, non-terminal) — ratified via HS-3TZX-T9T6-RES-iteration-loop-lineage-and-capture Part A, built by HS-O97P-T9T6-EPIC-iteration-loop-lineage-relation-tier. It expresses what neither existing tier can: _work shipped and closed, the outcome fell short of the goal, and a NEW family re-attempts the SAME goal._ Supersession would falsify round 1 (it wasn't wrong — it shipped, its review is accurate history); amends would misdescribe it (round 2 contradicts nothing).
1427
+ The **third doc-to-doc relation tier**, alongside supersession (terminal, whole-doc) and amends (partial, non-terminal) — ratified via HS-3TZX-T9T6-RES-iteration-loop-lineage-and-capture Part A, built by HS-O97P-T9T6-EPIC-iteration-loop-lineage-relation-tier. It expresses what neither existing tier can: *work shipped and closed, the outcome fell short of the goal, and a NEW family re-attempts the SAME goal.* Supersession would falsify round 1 (it wasn't wrong — it shipped, its review is accurate history); amends would misdescribe it (round 2 contradicts nothing).
1435
1428
 
1436
1429
  ### Fields
1437
1430
 
1438
1431
  ```yaml
1439
- iterates_on: # optional, YAML list of wikilinks — lives ONLY on the NEWER doc (one-edit-on-source,
1440
- # same principle as amends). Semantics: "this initiative re-attempts an outcome the
1441
- # target initiative shipped but did not fully deliver." Typically carried by the
1442
- # round-2 research doc pointing at the round-1 research doc — the research chain is
1443
- # the spine (research is evergreen, so the root research id is the durable handle
1444
- # spanning every round; no new entity type).
1432
+ iterates_on: # optional, YAML list of wikilinks — lives ONLY on the NEWER doc (one-edit-on-source,
1433
+ # same principle as amends). Semantics: "this initiative re-attempts an outcome the
1434
+ # target initiative shipped but did not fully deliver." Typically carried by the
1435
+ # round-2 research doc pointing at the round-1 research doc — the research chain is
1436
+ # the spine (research is evergreen, so the root research id is the durable handle
1437
+ # spanning every round; no new entity type).
1445
1438
  # iteratedBy — COMPUTED reverse map (indexer/validator output, like amendedBy) — never written
1446
- # by hand into frontmatter.
1447
- outcome: # optional, on TRACKABLE docs only, set by the HUMAN REVIEWER at close — never
1448
- # inferred, never agent-set. Enum: met | partially-met | not-met. Lives ONLY on
1449
- # the closed doc (not echoed onto the round-2 doc; discovery goes through the
1450
- # iteratedBy reverse map).
1451
- outcome_note: # optional, one-line reviewer prose qualifying the verdict.
1439
+ # by hand into frontmatter.
1440
+ outcome: # optional, on TRACKABLE docs only, set by the HUMAN REVIEWER at close — never
1441
+ # inferred, never agent-set. Enum: met | partially-met | not-met. Lives ONLY on
1442
+ # the closed doc (not echoed onto the round-2 doc; discovery goes through the
1443
+ # iteratedBy reverse map).
1444
+ outcome_note: # optional, one-line reviewer prose qualifying the verdict.
1452
1445
  ```
1453
1446
 
1454
1447
  ### Invariants
1455
1448
 
1456
1449
  - **Nothing is demoted.** Both docs stay `canonical: true`; round 1 keeps `status: closed`. `iterates_on:` is a lineage edge, not a supersession — demoting round 1 to `canonical: false` would falsify the record and hide shipped scope from round 2's breakdown.
1457
- - **`outcome:` is the reviewer's judgment alone.** `status: closed` without an `outcome:` says only "shipped"; it must never be read as "goal met." The verdict is written at reviewer close (the one mutable-at-close moment), per session-close-protocol.
1450
+ - **`outcome:` is the reviewer's judgment alone.** `status: closed` without an `outcome:` says only "shipped"; it must never be read as "goal met." The verdict is written at reviewer close (the one mutable-at-close moment), per [[session-close-protocol]].
1458
1451
  - **Distinct family keys are correct.** Round 2 is its own initiative with its own children and review, so it takes a new family key; `iterates_on:` is the cross-family edge that replaces the missing shared grep handle.
1459
1452
 
1460
1453
  ### Required `## Related / lineage` section on promoted docs
@@ -1464,11 +1457,11 @@ Every promoted doc's outline ends with a resolved-wikilink table (immediately be
1464
1457
  ```markdown
1465
1458
  ## Related / lineage
1466
1459
 
1467
- | Doc | Role |
1468
- | -------------------- | ---------------------- |
1469
- | [[round-1-research]] | Iterates on |
1470
- | [[HS-REV-...]] | Prior attempt's review |
1471
- | [[HS-CAP-...]] | Feedback capture |
1460
+ | Doc | Role |
1461
+ |---|---|
1462
+ | [[round-1-research]] | Iterates on |
1463
+ | [[HS-REV-...]] | Prior attempt's review |
1464
+ | [[HS-CAP-...]] | Feedback capture |
1472
1465
  ```
1473
1466
 
1474
1467
  Role vocabulary: **Iterates on · Prior attempt's review · Feedback capture · Amends · Superseded by · Pillar · Spawned epics** (extend with prose roles when none fits — e.g. "Source capture", "Enhances").
@@ -1482,23 +1475,23 @@ Role vocabulary: **Iterates on · Prior attempt's review · Feedback capture ·
1482
1475
 
1483
1476
  ```yaml
1484
1477
  evidence:
1485
- - type: commit # required — one of the evidence types below
1486
- ref: "abc123" # required — the reference, format per type
1487
- line: 42 # optional — line number (file/diff only)
1488
- description: "..." # optional — what this evidence shows
1478
+ - type: commit # required — one of the evidence types below
1479
+ ref: "abc123" # required — the reference, format per type
1480
+ line: 42 # optional — line number (file/diff only)
1481
+ description: "..." # optional — what this evidence shows
1489
1482
  ```
1490
1483
 
1491
1484
  Evidence types:
1492
1485
 
1493
- | Type | `ref` format | Example |
1494
- | -------- | ------------------------------------ | ---------------------------------------------------------------- |
1495
- | `commit` | short or full SHA | `abc123`, `abc123def…` |
1496
- | `file` | repo-relative path, optional `:line` | `src/foo.ts`, `src/foo.ts:42` |
1497
- | `pr` | PR number | `#123` |
1498
- | `diff` | `commit:path` | `abc123:src/pages/dashboard.tsx` |
1499
- | `issue` | issue number | `#42` |
1500
- | `note` | freeform text | `Builder confirmed via Slack 2026-05-15` |
1501
- | `test` | test/gate identifier | `vitest:src/lib/continuity/plan-vs-actual.test.ts`, `tsc:noEmit` |
1486
+ | Type | `ref` format | Example |
1487
+ | --- | --- | --- |
1488
+ | `commit` | short or full SHA | `abc123`, `abc123def…` |
1489
+ | `file` | repo-relative path, optional `:line` | `src/foo.ts`, `src/foo.ts:42` |
1490
+ | `pr` | PR number | `#123` |
1491
+ | `diff` | `commit:path` | `abc123:src/pages/dashboard.tsx` |
1492
+ | `issue` | issue number | `#42` |
1493
+ | `note` | freeform text | `Builder confirmed via Slack 2026-05-15` |
1494
+ | `test` | test/gate identifier | `vitest:src/lib/continuity/plan-vs-actual.test.ts`, `tsc:noEmit` |
1502
1495
 
1503
1496
  > [!note] `test` added 2026-08-11 (receipt-on-ship, HS-XGG4-IU2S-EPIC-receipt-on-ship-plan-vs-actual-proof-at). Additive extension per adr-0008-branch-brief-and-evidence-schema §Consequences ("a future change to evidence types … is a normal entity-model edit"); lets Plan Receipts cite test/gate results as typed evidence.
1504
1497
 
@@ -1516,19 +1509,19 @@ The indexer harvests inline shorthand and the frontmatter `evidence:` array into
1516
1509
  ## Delivery snapshot
1517
1510
 
1518
1511
  > [!note] User-persisted, not auto-maintained
1519
- > See HS-WB81-RBJ8-TASK-spec-delivery-frontmatter-snapshot. The live source of truth for "which commits touched this spec" is always `git log -- <spec_path>`; the `delivery:` block is an _optional persisted snapshot_ the Builder takes from the console's On Deck row so the vault carries its own delivery trail.
1512
+ > See HS-WB81-RBJ8-TASK-spec-delivery-frontmatter-snapshot. The live source of truth for "which commits touched this spec" is always `git log -- <spec_path>`; the `delivery:` block is an *optional persisted snapshot* the Builder takes from the console's On Deck row so the vault carries its own delivery trail.
1520
1513
 
1521
1514
  `delivery:` is an **optional, cross-type** key. It exists only after the Builder has clicked "snapshot to spec" in the console's delivery dropdown. Shape:
1522
1515
 
1523
1516
  ```yaml
1524
1517
  delivery:
1525
- snapshot_at: 2026-05-21T07:00:00-05:00 # ISO timestamp of when the snapshot was taken
1518
+ snapshot_at: 2026-05-21T07:00:00-05:00 # ISO timestamp of when the snapshot was taken
1526
1519
  commits:
1527
- - sha: 8648ad5e3f... # full SHA
1528
- short_sha: 8648ad5 # 7-char SHA
1529
- branch: hs-mvp0520 # primary branch (local before remote)
1530
- pushed: true # boolean — reachable from origin/*
1531
- at: 2026-05-21T05:14:32-05:00 # commit author time
1520
+ - sha: 8648ad5e3f... # full SHA
1521
+ short_sha: 8648ad5 # 7-char SHA
1522
+ branch: hs-mvp0520 # primary branch (local before remote)
1523
+ pushed: true # boolean — reachable from origin/*
1524
+ at: 2026-05-21T05:14:32-05:00 # commit author time
1532
1525
  author: pwher
1533
1526
  message: "feat(console): per-spec delivery dropdown on On Deck child rows"
1534
1527
  ```
@@ -1576,7 +1569,7 @@ The following keys are reserved by HeySpex and must not be repurposed:
1576
1569
  - `evidence` (cross-type; see [Evidence linking](#evidence-linking))
1577
1570
  - `delivery` (cross-type; user-persisted git-log snapshot — see [Delivery snapshot](#delivery-snapshot))
1578
1571
  - `legacy_bd_id`, `legacy_dolt_commit`
1579
- - Type-specific fields named above (including `branch-brief`'s `branch`, `goal`, `implements`, `plan`, `actual`, `risks`, `open_questions`, `next_steps`, `decisions`; `milestone`'s `epics`, `target_date`, `informed_by`; the `epic`'s `milestone` parent pointer and optional `derived_from`; `task`'s `split_of`, `split_index`, `handoff_id` (split lineage — envelope lives in body) and optional `affects_paths`; `research`'s `enhances`, `sources_captures`, `spawned_epics`, `enhances_epics`, `produces_diagnose`, `split_into`, `split_from`; `diagnose`'s optional `promoted_from` and `derived_from`; `capture`'s `informs_research`; the `agent` type's `role`, `model`, `allowed_tools`, `disallowed_tools`, `procedures`, `handoffs`, `guardrails`, `lane`, `color`, `owned_paths`, and `source_attribution` import-provenance object). Type-specific fields are additive and do **not** require an ADR (only a new _universal_ reserved key does); `source_attribution` was added under HS-GMLJ-K3KR-TASK-lock-the-community-import-design-and-add; `owned_paths` / `affects_paths` under HS-ZMAQ-M15C-TASK-declare-owned-path-globs-on-agent-identi.
1572
+ - Type-specific fields named above (including `branch-brief`'s `branch`, `goal`, `implements`, `plan`, `actual`, `risks`, `open_questions`, `next_steps`, `decisions`; `milestone`'s `epics`, `target_date`, `informed_by`; the `epic`'s `milestone` parent pointer and optional `derived_from`; `task`'s `split_of`, `split_index`, `handoff_id` (split lineage — envelope lives in body) and optional `affects_paths`; `research`'s `enhances`, `sources_captures`, `spawned_epics`, `enhances_epics`, `produces_diagnose`, `split_into`, `split_from`; `diagnose`'s optional `promoted_from` and `derived_from`; `capture`'s `informs_research`; the `agent` type's `role`, `model`, `allowed_tools`, `disallowed_tools`, `procedures`, `handoffs`, `guardrails`, `lane`, `color`, `owned_paths`, and `source_attribution` import-provenance object). Type-specific fields are additive and do **not** require an ADR (only a new *universal* reserved key does); `source_attribution` was added under HS-GMLJ-K3KR-TASK-lock-the-community-import-design-and-add; `owned_paths` / `affects_paths` under HS-ZMAQ-M15C-TASK-declare-owned-path-globs-on-agent-identi.
1580
1573
  - `reviews` (review type — back-compat alias for `parent:` pointing at the spec under review)
1581
1574
 
1582
1575
  Adding a new universal reserved key requires an ADR.
@@ -1611,7 +1604,7 @@ created: 2026-05-14
1611
1604
  updated: 2026-05-14
1612
1605
  kind: bug
1613
1606
  blocked_by:
1614
- - "[[HS-IS1A-TASK-cockpit-routing-rewrite]]"
1607
+ - "[[HS-IS1A-TASK-SpexConsole-routing-rewrite]]"
1615
1608
  related:
1616
1609
  - "[[HS-582Q-TASK-arrow-key-conflicts]]"
1617
1610
  tags: [console, ux, keyboard]
@@ -1629,9 +1622,9 @@ Arrow keys do not move focus between issues in the list view; only Tab works. Co
1629
1622
 
1630
1623
  ## Change log
1631
1624
 
1632
- | Date | Author | Change |
1633
- | ---------- | ------ | --------------------------- |
1634
- | 2026-05-14 | pwher | Created from drafts/triage. |
1625
+ | Date | Author | Change |
1626
+ | --- | --- | --- |
1627
+ | 2026-05-14 | pwher | Created from drafts/triage. |
1635
1628
  ```
1636
1629
 
1637
1630
  ### Memory lesson
@@ -1666,9 +1659,9 @@ At session start, run `Get-Process bd | Sort WorkingSet -Desc` on Windows and ki
1666
1659
 
1667
1660
  ## Change log
1668
1661
 
1669
- | Date | Author | Change |
1670
- | ---------- | ------ | -------------------------------------------------- |
1671
- | 2026-05-14 | pwher | Migrated from bd memory `lessons/bd-process-leak`. |
1662
+ | Date | Author | Change |
1663
+ | --- | --- | --- |
1664
+ | 2026-05-14 | pwher | Migrated from bd memory `lessons/bd-process-leak`. |
1672
1665
  ```
1673
1666
 
1674
1667
  ## Open questions
@@ -1701,35 +1694,35 @@ These are intentionally left for the Builder's confirmation in Phase 5 (migratio
1701
1694
 
1702
1695
  ## Change log
1703
1696
 
1704
- | Date | Author | Change |
1705
- | ---------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1706
- | 2026-05-14 | pwher (with claude opus 4.7) | Initial draft. Derived the entity-type set from L1 use cases plus the bd inventory. Locked in four dependency types (matching bd) and Obsidian-compatible wikilink resolution. Folder layout uses subfolders per type for human navigation; resolution is folder-agnostic. |
1707
- | 2026-05-16 | pwher | §`draft`: companion/voice + optional spatial cursor/click hints (uc-voice-ingest-hey-spex §Spatial pointers). |
1708
- | 2026-05-16 | pwher (with claude opus 4.7) | Added `branch-brief` entity type (folder `branches/`, ID `HS-BB-<slug>`, plan/actual + drift enum) and the cross-type `evidence:` array with inline shorthand. Per adr-0008-branch-brief-and-evidence-schema; closes HS-7E41/0052/0053 of HS-7KOO-0022-EPIC-continuity-layer-gaps. |
1709
- | 2026-05-17 | pwher | Added `roadmap` type + `roadmap_manifest`; `future-considerations/` layout; draft `source_intent_hash` / `review_stage`; task `roadmap_admission` / `ingest_draft`. Per adr-0012-roadmap-storage. |
1710
- | 2026-05-17 | pwher | Draft `deliberation_record` (ai-deliberation-gate); task `close_reason` enum + `superseded_by`; archive = filter not folder. |
1711
- | 2026-05-17 | pwher | Draft `suggestions:` + `review_record:` per HS-EU98-GCGE-TASK-staged-draft-suggestion-schema; omit-when-empty rule. |
1712
- | 2026-05-17 | pwher | `submission_kind`, `companion_dialogue[]`; companion `capture_channel` per companion-external-media-vs-refined-intent-council. |
1713
- | 2026-05-17 | pwher | `capture_bundle_id`, `source_set[]` for companion multi-article bundle submit (companion-capture-inbox-and-bundles, HS-D1YU-OVFO-TASK-bundle-submit-composite-draft-source-set). |
1714
- | 2026-05-17 | pwher | `triage_record` scout schema for Review inbox workshop (review-inbox-workshop-scout-overview). |
1715
- | 2026-05-18 | pwher (with claude opus 4.5) | Added `in_review` status to universal enum — human gate between agent work and closure (HS-YYEO-FLX9-TASK-review-column-human-gate-before-done). |
1716
- | 2026-05-20 | pwher | `canvases/diagrams/` + `canvases/as-built/` for spec diagram dual-surface (spec-diagram-design-vs-as-built-canvas). |
1717
- | 2026-05-20 | pwher | Added `specs/canvases/` for JSON Canvas design files per adr-0013-canvas-vault-format-and-obsidian-interop. |
1718
- | 2026-05-20 | pwher | Task/epic ID formats: random alphanumeric suffix for new specs (vault-id-assignment-protocol); legacy `HS-NNNN` migration IDs retained. |
1719
- | 2026-05-21 | pwher | Added `planning-flow` type (`specs/flows/`); research `bound_epic` / `planning_flow`; epic `research` / `planning_flow` requirements (planning-flow-research-epic-lifecycle). |
1720
- | 2026-05-22 | pwher + Claude Opus 4.7 (1M) | `idea` schema: `research_stage` removed (single binary `promoted_to`); body shape v2 — `# Core Idea` / `## Notes` / `## Concept` (≤1200 chars) / `<details>Details</details>`. See HS-KQ5O-IDFV-EPIC-unified-idea-workflow-v2 / HS-QOAC-IDFL-RES-unified-idea-workflow-v2. |
1721
- | 2026-05-22 | pwher + Claude Opus 4.7 (1M) | **Capture rename:** `type: idea` → `type: capture`; new required `kind:` field (idea / bug-fix / clip / reference / question); folder `specs/captures/` → `specs/captures/`; ID prefix `HS-IDEA-*` → `HS-CAP-*` (legacy preserved in `legacy_idea_id:`); research `source_idea:` → `source_capture:`. Per HS-B2B8-DLQI-EPIC-capture-rename-migration-idea-to-capture; source rationale HS-ZKFN-1FXG-CAP-capture-as-universal-companion-verb-and-parent-term. |
1722
- | 2026-05-24 | Claude Opus 4.7 (1M) | Capture schema: added `capture_status: raw \| expanded` (default `raw`). Flipped to `expanded` by MCP `executeUpdateCapture` on core_idea/concept/agent_expansion writes; force-corrected by console save-time linter when `# Core Idea` body has content. Backfilled across 21 existing captures by `scripts/backfill-capture-status.mjs`. Per HS-20PH-P2WA-TASK-b3-new-frontmatter-field-idea-status (B3 of HS-BDDT-Q1B7-EPIC-idea-capture-modal-v3-single-textbox-cle). |
1723
- | 2026-05-25 | pwher (with Claude Opus 4.7) | **Business layer added.** New entity types `business-positioning` / `business-pricing` / `business-marketing` / `business-model` filed under `specs/business/{positioning,pricing,marketing,model}/`. IDs `HS-BIZ-POS-* / HS-BIZ-PRI-* / HS-BIZ-MKT-* / HS-BIZ-MOD-*`. Browsed in the console on a dedicated **Business** surface that mirrors Memory's category-rail layout. `positioning-2nd-brain-harness-for-specs` migrated from `memory/decisions/` (`type: memory-decision`) to `business/positioning/` (`type: business-positioning`); basename unchanged so wikilinks resolve. |
1724
- | 2026-05-29 | pwher (with Claude Opus 4.8 [1m]) | **`milestone` entity type formalized.** Added folder `specs/milestones/`, Entity-types-table row, ID format `HS-MIL-<suffix>` (4+ uppercase; legacy 4-char mnemonics like `HS-RM22` valid), filename pattern `HS-MIL-<suffix>-<slug>.md`, and a full `#### milestone` schema subsection (`epics`, `target_date`, status enum, explicit "no scalar priority"). Disambiguated the legacy `kind: milestone` task discriminator from the new `type: milestone` entity; added the `milestone:` parent pointer to the `#### epic` schema; registered the new fields under Reserved frontmatter keys. Describes the 33 `HS-MIL-*` files already on disk (seed HS-RM22-IART-MIL-console-ia-restructure). Ratified by introduction lineage HS-VK7C-MILE-EPIC-milestone-entity-type-and-surfacing → HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity (in lieu of a standalone ADR); canonical hierarchy in [[spec-hierarchy]]. Per HS-9AUC-HRMZ-TASK-define-milestone-entity-type-in-entity-m. |
1725
- | 2026-05-26 | pwher (with Claude Opus 4.7) | **`review` entity type formalized.** Added folder `specs/reviews/`, ID format `HS-REV-<suffix>` (suffix matches parent task/epic id 1:1), filename pattern `HS-REV-<suffix>-<slug>.md`, and full `#### review` schema subsection documenting the four required body sections (Acceptance verification / Reviewer notes / Memory candidates / Decision). Documents what CLAUDE.md §Session Completion + ~100 existing review files already implement; provides the authoritative L2 schema for console, indexer, MCP, and future CLI consumers. Per T1 of HS-3K55-0033-EPIC-review-sibling-testing-workflow (grounded against HS-19F9-TEST-MIL-api-testing-dual-path + HS-UKD6-CLR4-RES-close-out-review-screen-jtbd-architecture). |
1726
- | 2026-05-29 | pwher (with Claude Opus 4.7 [1m]) | **Provenance edges formalized (capture → research → milestone).** Added new §Provenance edges section between §Dependencies and §Evidence linking with the cross-type cardinality table (Capture→Research M:N, Research→Milestone M:1 strict, Research→Epic spawned 1:N, Research→Epic augmented M:N). New frontmatter fields: `research.enhances` (M:1 required on closed), `research.sources_captures` (M:N), `research.spawned_epics` (1:N), `research.enhances_epics` (M:N rare), `research.split_into` / `research.split_from` (split-flow audit); `milestone.informed_by` (reverse of enhances); `capture.informs_research` (M:N, distinct from binary `promoted_to`); optional `epic.derived_from` (reverse of spawned_epics). Reserved-keys list updated. Per HS-HQRM-YJX6-TASK-research-enhances-exactly-one-milestone-validator-and-bidirectional-linkage of HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity. |
1727
- | 2026-05-31 | pwher (with claude opus 4.7) | **`pillar` entity type added** (folder `specs/pillars/`, ID format `HS-PILR-<slug>` for canonical or `HS-PILR-<suffix>-<slug>` for customer-scoped, filename matches ID, `status: perpetual` non-terminal). New required fields on every epic: `pillar:` (single primary) and optional `secondary_pillars:` array. Type ratified by introduction lineage HS-EBIL-0011-EPIC-goal-hierarchy-l2-strategic-pillars-l3 following the milestone precedent (no standalone ADR for the entity itself); privacy-boundary for the Pillar Library learning loop is adr-0016-pillar-library-privacy-boundary. **`architecture-pillars.md` renamed to `architecture-foundations.md`** (ID `HS-L2-PILLARS` → `HS-L2-FOUNDATIONS`) to disambiguate from the new entity; 172 wikilinks updated in a single bulk pass. Three "pillar" usages now coexist: the `type: pillar` entity, the unrelated "Pillars 0–5" section names in HS-DOC-architecture-foundations, and the renamed "FIVE COMPONENTS" section in HS-OR8V-0010-EPIC-north-star-vision-first-class-entity (previously "FIVE PILLARS"). L3 Themes (per-epic teleological anchor) retired in the same resolution — collapsed into perpetual Pillars. See HS-AWDI-PILR-RES-pm-perpetual-container-terminology §"Resolution against existing HS-J6K8" for the full rationale. |
1728
- | 2026-06-03 | claude opus 4.7 [1m] · session `local` (with pwher) | **`canonical:` universal field added; two `superseded` enum values deprecated.** Per evergreen-doc-architecture-srp-and-seo-pillars + canonicalization-arbiter-is-link-graph-not-policy + closed-trackable-specs-are-historical-record-not-living-docs: `canonical: true \| false` is now a universal frontmatter field on every spec type (pillars, L1/L2/L3 docs, HS-DOC-\*, ADRs, protocols, memory specs, epics, tasks, milestones, reviews). `true` (or absent) = current/authoritative; `false` = historical record. Trigger event for the flip: plan-side specs at the in_review → closed transition (per session-close-protocol step 4); evergreen docs at supersession (per supersession-protocol). `status: parked` / `status: deferred` keeps `canonical: true`. **Two enum values deprecated forward-only** per superseded-enum-values-deprecated-use-canonical-false-and-superseded-by: `status: superseded` removed from the ADR-status enum; `superseded` removed from the close_reason enum. Both were redundant with `canonical: false` + `superseded_by:`. Forward-only retirement — existing 11 specs (8 ADRs + 3 plan-side) keep their legacy values as historical record per immutability. New writes use `canonical: false` + `superseded_by:` instead. Added the `canonical:` field to the ADR and task schemas; expanded the `superseded_by:` description to clarify it's the pointer (vs. `canonical:` which is the state). |
1729
- | 2026-06-03 | claude opus 4.7 [1m] · session `local` (with pwher) | **`## Lifecycle classes` section added; `research` schema de-coupled from `status: closed`.** New top-level section between §Entity types and §Identity, IDs, and filenames classifying all 24 types into four lifecycle classes — **Evergreen** (`l1`/`l2`/`l3`/`adr`/`pillar`/`protocol`/`memory-*`/`research`/`business-*`), **Trackable plan-side** (`task`/`epic`/`milestone`/`review`/`branch-brief`/`planning-flow`), **Single-shot ingest** (`capture`/`draft`/`daily`), **Per-instance** (`roadmap`). Closes the discoverability gap that produced the research-is-evergreen incident: a reader asking _"can I flip this file's status to `in_review`?"_ now has one canonical place to look. Cross-references research-is-evergreen, closed-trackable-specs-are-historical-record-not-living-docs, canonicalization-arbiter-is-link-graph-not-policy, session-close-protocol. **Research schema (`#### research`) amended**: the `enhances:` field gate changed from "REQUIRED on `status: closed`" to "REQUIRED when set" — bidirectional consistency is enforced whenever the field is present, independent of status. Added a one-line note above the schema declaring research evergreen with a pointer to research-is-evergreen. The matching validator update in `scripts/validate-vault-ids.mjs` is on the deferred list — schema-vs-validator drift is acknowledged in the schema comment until that catches up. |
1730
- | 2026-06-13 | claude opus 4.8 [1m] · session `local` (with pwher) | **`diagnose` entity type added** (folder `specs/diagnoses/`, ID `HS-DIAG-<suffix>`, filename `HS-DIAG-<suffix>-<slug>.md`). A user-reported bug fix as first-class executable work — standalone by default (exempt from the epic→milestone parent rule), optional `parent:` (epic or milestone), required `severity:` (error/warning/info) that maps onto the scheduler's existing priority signals, optional `blocks:` gating edges. Surfaces on the Resolution surface as a derived `kind: "bug"` row that links back to the diagnose. Added entity-types-table row, ID-format row, filename row, `#### diagnose` schema subsection, and Trackable-plan-side lifecycle classification. Ratified by introduction lineage HS-OXBS-BFIX-MIL-bug-fix-diagnose-lane (milestone-precedent, no standalone ADR). Wiring: `vault.ts` (TYPE_TO_FOLDER + KIND_LINKAGE + body skeleton + generateId), `vault-id.ts`, `vault-rules.mjs` (KIND_RULES/KIND_ORDER), `validator.ts`, `validate-vault-ids.mjs`. Per HS-AO2F-1KZK-RES-bug-fix-resolution-task-entity-model-and. |
1731
- | 2026-06-23 | Cursor · session `local` | **Delegation handoff envelope + task split lineage.** Task frontmatter: `split_of`, `split_index`, `handoff_id` (option B from HS-DTL1-CX5K-CAP-task-split-handoff-when-context-runs-low). Handoff envelope SSOT is body (`## Handoff envelope` + fenced yaml) per `schemas/handoff-envelope.schema.json`; validated by `handoff-envelope.mjs` + `validate-vault-ids.mjs`. Engine rules in `vault-rules.mjs` (`TASK_SPLIT_*`). Per HS-PD6K-NCH5-TASK-handoff-envelope-schema-and-split-child / HS-HXE2-YQ5A-EPIC-delegation-defer-work-from-one-agent-to. |
1732
- | 2026-06-23 | Cursor · session `local` | **`owned_paths` / `affects_paths` for parallel-agent stomp-detection.** New `#### agent` schema subsection documents `owned_paths:` (machine-checkable file globs on agent identities). Task schema adds optional `affects_paths:` (advisory module hints on trackable specs). Entity-types table + reserved-keys list updated. Per HS-ZMAQ-M15C-TASK-declare-owned-path-globs-on-agent-identi / HS-8PNX-Q1KC-EPIC-lanes-and-stomp-detection-for-parallel-a. |
1733
- | 2026-07-05 | Claude Sonnet 5 [1m] · session `local` (with pwher) | **`research.produces_diagnose` → `diagnose.derived_from` edge added (research → diagnose intake).** Bugs found during a research investigation now route into the Resolution lane without new diagnose machinery: `research.produces_diagnose:` (optional, list of wikilinks to `HS-DIAG-*`, mirrors `spawned_epics`) reverse-linked by `diagnose.derived_from:` (optional, single wikilink, mirrors `epic.derived_from`). Written by the new `heyspex_promote_research_to_diagnose` tool (`vendor/heyspex-mcp/promote-research-to-diagnose.mjs`), the research-side sibling of `heyspex_promote_capture_to_diagnose`. Also documented `diagnose.promoted_from:` (existing capture-side back-reference, previously undocumented in this schema subsection). Provenance cardinality table + reserved-keys list updated; validated by the `type: research` block of `schemas/heyspex-frontmatter.schema.json`. Per HS-W5VP-MSHY-TASK-research-diagnose-link-send-bugs-to-the of HS-0FTO-MSHY-EPIC-research-to-diagnose-link-send-bugs-foun. |
1734
- | 2026-07-05 | Claude Sonnet 5 [1m] · session `local` (with pwher) | **`code-audit` findings-table format + closure gate.** New `##### Code-audit findings table` subsection under `#### research` documents the required 4-column body table (`Finding \| Severity \| Action (diagnose\|task\|reference) \| Exit (open\|closed)`) and its three defined exits: bug→diagnose (reuses `heyspex_promote_research_to_diagnose`/`research.produces_diagnose`, no new tooling), cleanup→task (new `task.discovered_from:` reverse pointer to the source research doc), non-actionable→reference (the row itself is the exit). Enriched the existing `task.discovered_from:` doc comment to name this use. Added `discovered_from` to the `type: task` block of `schemas/heyspex-frontmatter.schema.json` (previously documented in entity-model.md only, unenforced). Validator rules in `vault-rules.mjs`: `CODE_AUDIT_FINDINGS_MALFORMED` (no/malformed table) and `CODE_AUDIT_FINDINGS_OPEN_ON_CLOSE` (the closure gate — a `closed`/`review_pending` code-audit doc with any `Exit: open` row) — both warn during a new `CODE_AUDIT_GRACE_END` (2026-08-15, mirrors `RESEARCH_TYPE_GRACE_END`) so pre-existing docs like `HS-ZHAB-RES-doc-authoring-contract-audit-required-st` (no `research_type:` set, predates this format) aren't hard-failed, then error. Per HS-7D0I-WL88-TASK-code-audit-research-type-with-a-defined of HS-BI9D-WL88-EPIC-code-audit-research-type-with-a-defined. |
1735
- | 2026-08-14 | Claude Code (Fable 5) · session `5785e74c` (with pwher) | **Iteration lineage — third relation tier added.** New §Iteration lineage section (between §Provenance edges and §Evidence linking): `iterates_on:` (list of wikilinks, newer-doc-only, one-edit-on-source like amends; computed reverse map `iteratedBy`) expresses "re-attempts an outcome the target shipped but did not fully deliver" — the case supersession (would falsify round 1) and amends (nothing is contradicted) both misdescribe. `outcome:` (`met` \| `partially-met` \| `not-met`) + `outcome_note:` — reviewer-set at close on trackable docs, never inferred, closed-doc-only (not echoed onto round 2). Required `## Related / lineage` resolved-wikilink table on promoted docs with role vocabulary. Invariants: both docs stay `canonical: true`, round 1 keeps `status: closed`, round 2 takes its own family key. Dependencies table gained the Iterates-on row; Reviewer-close bullet gained the outcome write. Field-name + echo decisions resolved at breakdown (flagged for owner Walk). Per HS-VGQV-T9T6-TASK-entity-model-iterates-on-relation-tier of HS-O97P-T9T6-EPIC-iteration-loop-lineage-relation-tier, from HS-3TZX-T9T6-RES-iteration-loop-lineage-and-capture Part A. |
1697
+ | Date | Author | Change |
1698
+ | --- | --- | --- |
1699
+ | 2026-05-14 | pwher (with claude opus 4.7) | Initial draft. Derived the entity-type set from L1 use cases plus the bd inventory. Locked in four dependency types (matching bd) and Obsidian-compatible wikilink resolution. Folder layout uses subfolders per type for human navigation; resolution is folder-agnostic. |
1700
+ | 2026-05-16 | pwher | §`draft`: companion/voice + optional spatial cursor/click hints (uc-voice-ingest-hey-spex §Spatial pointers). |
1701
+ | 2026-05-16 | pwher (with claude opus 4.7) | Added `branch-brief` entity type (folder `branches/`, ID `HS-BB-<slug>`, plan/actual + drift enum) and the cross-type `evidence:` array with inline shorthand. Per adr-0008-branch-brief-and-evidence-schema; closes HS-7E41/0052/0053 of HS-7KOO-0022-EPIC-continuity-layer-gaps. |
1702
+ | 2026-05-17 | pwher | Added `roadmap` type + `roadmap_manifest`; `future-considerations/` layout; draft `source_intent_hash` / `review_stage`; task `roadmap_admission` / `ingest_draft`. Per adr-0012-roadmap-storage. |
1703
+ | 2026-05-17 | pwher | Draft `deliberation_record` (ai-deliberation-gate); task `close_reason` enum + `superseded_by`; archive = filter not folder. |
1704
+ | 2026-05-17 | pwher | Draft `suggestions:` + `review_record:` per HS-EU98-GCGE-TASK-staged-draft-suggestion-schema; omit-when-empty rule. |
1705
+ | 2026-05-17 | pwher | `submission_kind`, `companion_dialogue[]`; companion `capture_channel` per companion-external-media-vs-refined-intent-council. |
1706
+ | 2026-05-17 | pwher | `capture_bundle_id`, `source_set[]` for companion multi-article bundle submit (companion-capture-inbox-and-bundles, HS-D1YU-OVFO-TASK-bundle-submit-composite-draft-source-set). |
1707
+ | 2026-05-17 | pwher | `triage_record` scout schema for Review inbox workshop (review-inbox-workshop-scout-overview). |
1708
+ | 2026-05-18 | pwher (with claude opus 4.5) | Added `in_review` status to universal enum — human gate between agent work and closure (HS-YYEO-FLX9-TASK-review-column-human-gate-before-done). |
1709
+ | 2026-05-20 | pwher | `canvases/diagrams/` + `canvases/as-built/` for spec diagram dual-surface (spec-diagram-design-vs-as-built-canvas). |
1710
+ | 2026-05-20 | pwher | Added `specs/canvases/` for JSON Canvas design files per adr-0013-canvas-vault-format-and-obsidian-interop. |
1711
+ | 2026-05-20 | pwher | Task/epic ID formats: random alphanumeric suffix for new specs (vault-id-assignment-protocol); legacy `HS-NNNN` migration IDs retained. |
1712
+ | 2026-05-21 | pwher | Added `planning-flow` type (`specs/flows/`); research `bound_epic` / `planning_flow`; epic `research` / `planning_flow` requirements (planning-flow-research-epic-lifecycle). |
1713
+ | 2026-05-22 | pwher + Claude Opus 4.7 (1M) | `idea` schema: `research_stage` removed (single binary `promoted_to`); body shape v2 — `# Core Idea` / `## Notes` / `## Concept` (≤1200 chars) / `<details>Details</details>`. See HS-KQ5O-IDFV-EPIC-unified-idea-workflow-v2 / HS-QOAC-IDFL-RES-unified-idea-workflow-v2. |
1714
+ | 2026-05-22 | pwher + Claude Opus 4.7 (1M) | **Capture rename:** `type: idea` → `type: capture`; new required `kind:` field (idea / bug-fix / clip / reference / question); folder `specs/captures/` → `specs/captures/`; ID prefix `HS-IDEA-*` → `HS-CAP-*` (legacy preserved in `legacy_idea_id:`); research `source_idea:` → `source_capture:`. Per HS-B2B8-DLQI-EPIC-capture-rename-migration-idea-to-capture; source rationale HS-ZKFN-1FXG-CAP-capture-as-universal-companion-verb-and-parent-term. |
1715
+ | 2026-05-24 | Claude Opus 4.7 (1M) | Capture schema: added `capture_status: raw \| expanded` (default `raw`). Flipped to `expanded` by MCP `executeUpdateCapture` on core_idea/concept/agent_expansion writes; force-corrected by console save-time linter when `# Core Idea` body has content. Backfilled across 21 existing captures by `scripts/backfill-capture-status.mjs`. Per HS-20PH-P2WA-TASK-b3-new-frontmatter-field-idea-status (B3 of HS-BDDT-Q1B7-EPIC-idea-capture-modal-v3-single-textbox-cle). |
1716
+ | 2026-05-25 | pwher (with Claude Opus 4.7) | **Business layer added.** New entity types `business-positioning` / `business-pricing` / `business-marketing` / `business-model` filed under `specs/business/{positioning,pricing,marketing,model}/`. IDs `HS-BIZ-POS-* / HS-BIZ-PRI-* / HS-BIZ-MKT-* / HS-BIZ-MOD-*`. Browsed in the console on a dedicated **Business** surface that mirrors Memory's category-rail layout. `positioning-2nd-brain-harness-for-specs` migrated from `memory/decisions/` (`type: memory-decision`) to `business/positioning/` (`type: business-positioning`); basename unchanged so wikilinks resolve. |
1717
+ | 2026-05-29 | pwher (with Claude Opus 4.8 [1m]) | **`milestone` entity type formalized.** Added folder `specs/milestones/`, Entity-types-table row, ID format `HS-MIL-<suffix>` (4+ uppercase; legacy 4-char mnemonics like `HS-RM22` valid), filename pattern `HS-MIL-<suffix>-<slug>.md`, and a full `#### milestone` schema subsection (`epics`, `target_date`, status enum, explicit "no scalar priority"). Disambiguated the legacy `kind: milestone` task discriminator from the new `type: milestone` entity; added the `milestone:` parent pointer to the `#### epic` schema; registered the new fields under Reserved frontmatter keys. Describes the 33 `HS-MIL-*` files already on disk (seed HS-RM22-IART-MIL-console-ia-restructure). Ratified by introduction lineage HS-VK7C-MILE-EPIC-milestone-entity-type-and-surfacing → HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity (in lieu of a standalone ADR); canonical hierarchy in [[spec-hierarchy]]. Per HS-9AUC-HRMZ-TASK-define-milestone-entity-type-in-entity-m. |
1718
+ | 2026-05-26 | pwher (with Claude Opus 4.7) | **`review` entity type formalized.** Added folder `specs/reviews/`, ID format `HS-REV-<suffix>` (suffix matches parent task/epic id 1:1), filename pattern `HS-REV-<suffix>-<slug>.md`, and full `#### review` schema subsection documenting the four required body sections (Acceptance verification / Reviewer notes / Memory candidates / Decision). Documents what CLAUDE.md §Session Completion + ~100 existing review files already implement; provides the authoritative L2 schema for console, indexer, MCP, and future CLI consumers. Per T1 of HS-3K55-0033-EPIC-review-sibling-testing-workflow (grounded against HS-19F9-TEST-MIL-api-testing-dual-path + HS-UKD6-CLR4-RES-close-out-review-screen-jtbd-architecture). |
1719
+ | 2026-05-29 | pwher (with Claude Opus 4.7 [1m]) | **Provenance edges formalized (capture → research → milestone).** Added new §Provenance edges section between §Dependencies and §Evidence linking with the cross-type cardinality table (Capture→Research M:N, Research→Milestone M:1 strict, Research→Epic spawned 1:N, Research→Epic augmented M:N). New frontmatter fields: `research.enhances` (M:1 required on closed), `research.sources_captures` (M:N), `research.spawned_epics` (1:N), `research.enhances_epics` (M:N rare), `research.split_into` / `research.split_from` (split-flow audit); `milestone.informed_by` (reverse of enhances); `capture.informs_research` (M:N, distinct from binary `promoted_to`); optional `epic.derived_from` (reverse of spawned_epics). Reserved-keys list updated. Per HS-HQRM-YJX6-TASK-research-enhances-exactly-one-milestone-validator-and-bidirectional-linkage of HS-OFR5-M2J3-EPIC-introduce-milestones-as-highest-entity. |
1720
+ | 2026-05-31 | pwher (with claude opus 4.7) | **`pillar` entity type added** (folder `specs/pillars/`, ID format `HS-PILR-<slug>` for canonical or `HS-PILR-<suffix>-<slug>` for customer-scoped, filename matches ID, `status: perpetual` non-terminal). New required fields on every epic: `pillar:` (single primary) and optional `secondary_pillars:` array. Type ratified by introduction lineage HS-EBIL-0011-EPIC-goal-hierarchy-l2-strategic-pillars-l3 following the milestone precedent (no standalone ADR for the entity itself); privacy-boundary for the Pillar Library learning loop is adr-0016-pillar-library-privacy-boundary. **`architecture-pillars.md` renamed to `architecture-foundations.md`** (ID `HS-L2-PILLARS` → `HS-L2-FOUNDATIONS`) to disambiguate from the new entity; 172 wikilinks updated in a single bulk pass. Three "pillar" usages now coexist: the `type: pillar` entity, the unrelated "Pillars 0–5" section names in HS-DOC-architecture-foundations, and the renamed "FIVE COMPONENTS" section in HS-OR8V-0010-EPIC-north-star-vision-first-class-entity (previously "FIVE PILLARS"). L3 Themes (per-epic teleological anchor) retired in the same resolution — collapsed into perpetual Pillars. See HS-AWDI-PILR-RES-pm-perpetual-container-terminology §"Resolution against existing HS-J6K8" for the full rationale. |
1721
+ | 2026-06-03 | claude opus 4.7 [1m] · session `local` (with pwher) | **`canonical:` universal field added; two `superseded` enum values deprecated.** Per evergreen-doc-architecture-srp-and-seo-pillars + canonicalization-arbiter-is-link-graph-not-policy + closed-trackable-specs-are-historical-record-not-living-docs: `canonical: true \| false` is now a universal frontmatter field on every spec type (pillars, L1/L2/L3 docs, HS-DOC-*, ADRs, protocols, memory specs, epics, tasks, milestones, reviews). `true` (or absent) = current/authoritative; `false` = historical record. Trigger event for the flip: plan-side specs at the in_review → closed transition (per [[session-close-protocol]] step 4); evergreen docs at supersession (per supersession-protocol). `status: parked` / `status: deferred` keeps `canonical: true`. **Two enum values deprecated forward-only** per superseded-enum-values-deprecated-use-canonical-false-and-superseded-by: `status: superseded` removed from the ADR-status enum; `superseded` removed from the close_reason enum. Both were redundant with `canonical: false` + `superseded_by:`. Forward-only retirement — existing 11 specs (8 ADRs + 3 plan-side) keep their legacy values as historical record per immutability. New writes use `canonical: false` + `superseded_by:` instead. Added the `canonical:` field to the ADR and task schemas; expanded the `superseded_by:` description to clarify it's the pointer (vs. `canonical:` which is the state). |
1722
+ | 2026-06-03 | claude opus 4.7 [1m] · session `local` (with pwher) | **`## Lifecycle classes` section added; `research` schema de-coupled from `status: closed`.** New top-level section between §Entity types and §Identity, IDs, and filenames classifying all 24 types into four lifecycle classes — **Evergreen** (`l1`/`l2`/`l3`/`adr`/`pillar`/`protocol`/`memory-*`/`research`/`business-*`), **Trackable plan-side** (`task`/`epic`/`milestone`/`review`/`branch-brief`/`planning-flow`), **Single-shot ingest** (`capture`/`draft`/`daily`), **Per-instance** (`roadmap`). Closes the discoverability gap that produced the research-is-evergreen incident: a reader asking *"can I flip this file's status to `in_review`?"* now has one canonical place to look. Cross-references research-is-evergreen, closed-trackable-specs-are-historical-record-not-living-docs, canonicalization-arbiter-is-link-graph-not-policy, [[session-close-protocol]]. **Research schema (`#### research`) amended**: the `enhances:` field gate changed from "REQUIRED on `status: closed`" to "REQUIRED when set" — bidirectional consistency is enforced whenever the field is present, independent of status. Added a one-line note above the schema declaring research evergreen with a pointer to research-is-evergreen. The matching validator update in `scripts/validate-vault-ids.mjs` is on the deferred list — schema-vs-validator drift is acknowledged in the schema comment until that catches up. |
1723
+ | 2026-06-13 | claude opus 4.8 [1m] · session `local` (with pwher) | **`diagnose` entity type added** (folder `specs/diagnoses/`, ID `HS-DIAG-<suffix>`, filename `HS-DIAG-<suffix>-<slug>.md`). A user-reported bug fix as first-class executable work — standalone by default (exempt from the epic→milestone parent rule), optional `parent:` (epic or milestone), required `severity:` (error/warning/info) that maps onto the scheduler's existing priority signals, optional `blocks:` gating edges. Surfaces on the Resolution surface as a derived `kind: "bug"` row that links back to the diagnose. Added entity-types-table row, ID-format row, filename row, `#### diagnose` schema subsection, and Trackable-plan-side lifecycle classification. Ratified by introduction lineage HS-OXBS-BFIX-MIL-bug-fix-diagnose-lane (milestone-precedent, no standalone ADR). Wiring: `vault.ts` (TYPE_TO_FOLDER + KIND_LINKAGE + body skeleton + generateId), `vault-id.ts`, `vault-rules.mjs` (KIND_RULES/KIND_ORDER), `validator.ts`, `validate-vault-ids.mjs`. Per HS-AO2F-1KZK-RES-bug-fix-resolution-task-entity-model-and. |
1724
+ | 2026-06-23 | Cursor · session `local` | **Delegation handoff envelope + task split lineage.** Task frontmatter: `split_of`, `split_index`, `handoff_id` (option B from HS-DTL1-CX5K-CAP-task-split-handoff-when-context-runs-low). Handoff envelope SSOT is body (`## Handoff envelope` + fenced yaml) per `schemas/handoff-envelope.schema.json`; validated by `handoff-envelope.mjs` + `validate-vault-ids.mjs`. Engine rules in `vault-rules.mjs` (`TASK_SPLIT_*`). Per HS-PD6K-NCH5-TASK-handoff-envelope-schema-and-split-child / HS-HXE2-YQ5A-EPIC-delegation-defer-work-from-one-agent-to. |
1725
+ | 2026-06-23 | Cursor · session `local` | **`owned_paths` / `affects_paths` for parallel-agent stomp-detection.** New `#### agent` schema subsection documents `owned_paths:` (machine-checkable file globs on agent identities). Task schema adds optional `affects_paths:` (advisory module hints on trackable specs). Entity-types table + reserved-keys list updated. Per HS-ZMAQ-M15C-TASK-declare-owned-path-globs-on-agent-identi / HS-8PNX-Q1KC-EPIC-lanes-and-stomp-detection-for-parallel-a. |
1726
+ | 2026-07-05 | Claude Sonnet 5 [1m] · session `local` (with pwher) | **`research.produces_diagnose` → `diagnose.derived_from` edge added (research → diagnose intake).** Bugs found during a research investigation now route into the Resolution lane without new diagnose machinery: `research.produces_diagnose:` (optional, list of wikilinks to `HS-DIAG-*`, mirrors `spawned_epics`) reverse-linked by `diagnose.derived_from:` (optional, single wikilink, mirrors `epic.derived_from`). Written by the new `heyspex_promote_research_to_diagnose` tool (`vendor/heyspex-mcp/promote-research-to-diagnose.mjs`), the research-side sibling of `heyspex_promote_capture_to_diagnose`. Also documented `diagnose.promoted_from:` (existing capture-side back-reference, previously undocumented in this schema subsection). Provenance cardinality table + reserved-keys list updated; validated by the `type: research` block of `schemas/heyspex-frontmatter.schema.json`. Per HS-W5VP-MSHY-TASK-research-diagnose-link-send-bugs-to-the of HS-0FTO-MSHY-EPIC-research-to-diagnose-link-send-bugs-foun. |
1727
+ | 2026-07-05 | Claude Sonnet 5 [1m] · session `local` (with pwher) | **`code-audit` findings-table format + closure gate.** New `##### Code-audit findings table` subsection under `#### research` documents the required 4-column body table (`Finding \| Severity \| Action (diagnose\|task\|reference) \| Exit (open\|closed)`) and its three defined exits: bug→diagnose (reuses `heyspex_promote_research_to_diagnose`/`research.produces_diagnose`, no new tooling), cleanup→task (new `task.discovered_from:` reverse pointer to the source research doc), non-actionable→reference (the row itself is the exit). Enriched the existing `task.discovered_from:` doc comment to name this use. Added `discovered_from` to the `type: task` block of `schemas/heyspex-frontmatter.schema.json` (previously documented in entity-model.md only, unenforced). Validator rules in `vault-rules.mjs`: `CODE_AUDIT_FINDINGS_MALFORMED` (no/malformed table) and `CODE_AUDIT_FINDINGS_OPEN_ON_CLOSE` (the closure gate — a `closed`/`review_pending` code-audit doc with any `Exit: open` row) — both warn during a new `CODE_AUDIT_GRACE_END` (2026-08-15, mirrors `RESEARCH_TYPE_GRACE_END`) so pre-existing docs like `HS-ZHAB-RES-doc-authoring-contract-audit-required-st` (no `research_type:` set, predates this format) aren't hard-failed, then error. Per HS-7D0I-WL88-TASK-code-audit-research-type-with-a-defined of HS-BI9D-WL88-EPIC-code-audit-research-type-with-a-defined. |
1728
+ | 2026-08-14 | Claude Code (Fable 5) · session `5785e74c` (with pwher) | **Iteration lineage — third relation tier added.** New §Iteration lineage section (between §Provenance edges and §Evidence linking): `iterates_on:` (list of wikilinks, newer-doc-only, one-edit-on-source like amends; computed reverse map `iteratedBy`) expresses "re-attempts an outcome the target shipped but did not fully deliver" — the case supersession (would falsify round 1) and amends (nothing is contradicted) both misdescribe. `outcome:` (`met` \| `partially-met` \| `not-met`) + `outcome_note:` — reviewer-set at close on trackable docs, never inferred, closed-doc-only (not echoed onto round 2). Required `## Related / lineage` resolved-wikilink table on promoted docs with role vocabulary. Invariants: both docs stay `canonical: true`, round 1 keeps `status: closed`, round 2 takes its own family key. Dependencies table gained the Iterates-on row; Reviewer-close bullet gained the outcome write. Field-name + echo decisions resolved at breakdown (flagged for owner Walk). Per HS-VGQV-T9T6-TASK-entity-model-iterates-on-relation-tier of HS-O97P-T9T6-EPIC-iteration-loop-lineage-relation-tier, from HS-3TZX-T9T6-RES-iteration-loop-lineage-and-capture Part A. |