@devenius/junamis-skills 0.0.0-stage → 1.1.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 (311) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/LICENSE +21 -0
  3. package/README.md +231 -2
  4. package/SECURITY.md +81 -0
  5. package/bin/junamis-skills.js +7 -0
  6. package/dist/cli.d.ts +59 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +564 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/color.d.ts +40 -0
  11. package/dist/color.d.ts.map +1 -0
  12. package/dist/color.js +55 -0
  13. package/dist/color.js.map +1 -0
  14. package/dist/design/atomic.d.ts +4 -0
  15. package/dist/design/atomic.d.ts.map +1 -0
  16. package/dist/design/atomic.js +14 -0
  17. package/dist/design/atomic.js.map +1 -0
  18. package/dist/design/bootstrap.d.ts +23 -0
  19. package/dist/design/bootstrap.d.ts.map +1 -0
  20. package/dist/design/bootstrap.js +411 -0
  21. package/dist/design/bootstrap.js.map +1 -0
  22. package/dist/design/cli.d.ts +86 -0
  23. package/dist/design/cli.d.ts.map +1 -0
  24. package/dist/design/cli.js +425 -0
  25. package/dist/design/cli.js.map +1 -0
  26. package/dist/design/delta.d.ts +45 -0
  27. package/dist/design/delta.d.ts.map +1 -0
  28. package/dist/design/delta.js +557 -0
  29. package/dist/design/delta.js.map +1 -0
  30. package/dist/design/drift.d.ts +26 -0
  31. package/dist/design/drift.d.ts.map +1 -0
  32. package/dist/design/drift.js +341 -0
  33. package/dist/design/drift.js.map +1 -0
  34. package/dist/design/errors.d.ts +25 -0
  35. package/dist/design/errors.d.ts.map +1 -0
  36. package/dist/design/errors.js +30 -0
  37. package/dist/design/errors.js.map +1 -0
  38. package/dist/design/events.d.ts +18 -0
  39. package/dist/design/events.d.ts.map +1 -0
  40. package/dist/design/events.js +44 -0
  41. package/dist/design/events.js.map +1 -0
  42. package/dist/design/fingerprint.d.ts +10 -0
  43. package/dist/design/fingerprint.d.ts.map +1 -0
  44. package/dist/design/fingerprint.js +66 -0
  45. package/dist/design/fingerprint.js.map +1 -0
  46. package/dist/design/index-gen.d.ts +16 -0
  47. package/dist/design/index-gen.d.ts.map +1 -0
  48. package/dist/design/index-gen.js +94 -0
  49. package/dist/design/index-gen.js.map +1 -0
  50. package/dist/design/schema.d.ts +54 -0
  51. package/dist/design/schema.d.ts.map +1 -0
  52. package/dist/design/schema.js +408 -0
  53. package/dist/design/schema.js.map +1 -0
  54. package/dist/design/yaml.d.ts +12 -0
  55. package/dist/design/yaml.d.ts.map +1 -0
  56. package/dist/design/yaml.js +264 -0
  57. package/dist/design/yaml.js.map +1 -0
  58. package/dist/external.d.ts +61 -0
  59. package/dist/external.d.ts.map +1 -0
  60. package/dist/external.js +426 -0
  61. package/dist/external.js.map +1 -0
  62. package/dist/guide.d.ts +17 -0
  63. package/dist/guide.d.ts.map +1 -0
  64. package/dist/guide.js +219 -0
  65. package/dist/guide.js.map +1 -0
  66. package/dist/index.d.ts +2 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +7 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/install-external.d.ts +3 -0
  71. package/dist/install-external.d.ts.map +1 -0
  72. package/dist/install-external.js +37 -0
  73. package/dist/install-external.js.map +1 -0
  74. package/dist/library-install.d.ts +39 -0
  75. package/dist/library-install.d.ts.map +1 -0
  76. package/dist/library-install.js +663 -0
  77. package/dist/library-install.js.map +1 -0
  78. package/dist/orchestrator/boot.d.ts +3 -0
  79. package/dist/orchestrator/boot.d.ts.map +1 -0
  80. package/dist/orchestrator/boot.js +515 -0
  81. package/dist/orchestrator/boot.js.map +1 -0
  82. package/dist/orchestrator/cli.d.ts +37 -0
  83. package/dist/orchestrator/cli.d.ts.map +1 -0
  84. package/dist/orchestrator/cli.js +563 -0
  85. package/dist/orchestrator/cli.js.map +1 -0
  86. package/dist/orchestrator/commands.d.ts +46 -0
  87. package/dist/orchestrator/commands.d.ts.map +1 -0
  88. package/dist/orchestrator/commands.js +752 -0
  89. package/dist/orchestrator/commands.js.map +1 -0
  90. package/dist/orchestrator/compaction.d.ts +21 -0
  91. package/dist/orchestrator/compaction.d.ts.map +1 -0
  92. package/dist/orchestrator/compaction.js +93 -0
  93. package/dist/orchestrator/compaction.js.map +1 -0
  94. package/dist/orchestrator/drift.d.ts +11 -0
  95. package/dist/orchestrator/drift.d.ts.map +1 -0
  96. package/dist/orchestrator/drift.js +181 -0
  97. package/dist/orchestrator/drift.js.map +1 -0
  98. package/dist/orchestrator/errors.d.ts +52 -0
  99. package/dist/orchestrator/errors.d.ts.map +1 -0
  100. package/dist/orchestrator/errors.js +96 -0
  101. package/dist/orchestrator/errors.js.map +1 -0
  102. package/dist/orchestrator/frontmatter.d.ts +6 -0
  103. package/dist/orchestrator/frontmatter.d.ts.map +1 -0
  104. package/dist/orchestrator/frontmatter.js +50 -0
  105. package/dist/orchestrator/frontmatter.js.map +1 -0
  106. package/dist/orchestrator/fsx.d.ts +45 -0
  107. package/dist/orchestrator/fsx.d.ts.map +1 -0
  108. package/dist/orchestrator/fsx.js +295 -0
  109. package/dist/orchestrator/fsx.js.map +1 -0
  110. package/dist/orchestrator/handoff.d.ts +8 -0
  111. package/dist/orchestrator/handoff.d.ts.map +1 -0
  112. package/dist/orchestrator/handoff.js +246 -0
  113. package/dist/orchestrator/handoff.js.map +1 -0
  114. package/dist/orchestrator/hash.d.ts +10 -0
  115. package/dist/orchestrator/hash.d.ts.map +1 -0
  116. package/dist/orchestrator/hash.js +65 -0
  117. package/dist/orchestrator/hash.js.map +1 -0
  118. package/dist/orchestrator/journal.d.ts +35 -0
  119. package/dist/orchestrator/journal.d.ts.map +1 -0
  120. package/dist/orchestrator/journal.js +163 -0
  121. package/dist/orchestrator/journal.js.map +1 -0
  122. package/dist/orchestrator/lease.d.ts +31 -0
  123. package/dist/orchestrator/lease.d.ts.map +1 -0
  124. package/dist/orchestrator/lease.js +175 -0
  125. package/dist/orchestrator/lease.js.map +1 -0
  126. package/dist/orchestrator/plan.d.ts +27 -0
  127. package/dist/orchestrator/plan.d.ts.map +1 -0
  128. package/dist/orchestrator/plan.js +240 -0
  129. package/dist/orchestrator/plan.js.map +1 -0
  130. package/dist/orchestrator/report.d.ts +49 -0
  131. package/dist/orchestrator/report.d.ts.map +1 -0
  132. package/dist/orchestrator/report.js +244 -0
  133. package/dist/orchestrator/report.js.map +1 -0
  134. package/dist/orchestrator/state.d.ts +43 -0
  135. package/dist/orchestrator/state.d.ts.map +1 -0
  136. package/dist/orchestrator/state.js +369 -0
  137. package/dist/orchestrator/state.js.map +1 -0
  138. package/dist/orchestrator/store.d.ts +42 -0
  139. package/dist/orchestrator/store.d.ts.map +1 -0
  140. package/dist/orchestrator/store.js +202 -0
  141. package/dist/orchestrator/store.js.map +1 -0
  142. package/dist/orchestrator/test-hooks.d.ts +5 -0
  143. package/dist/orchestrator/test-hooks.d.ts.map +1 -0
  144. package/dist/orchestrator/test-hooks.js +31 -0
  145. package/dist/orchestrator/test-hooks.js.map +1 -0
  146. package/dist/orchestrator/time.d.ts +11 -0
  147. package/dist/orchestrator/time.d.ts.map +1 -0
  148. package/dist/orchestrator/time.js +38 -0
  149. package/dist/orchestrator/time.js.map +1 -0
  150. package/dist/paths.d.ts +9 -0
  151. package/dist/paths.d.ts.map +1 -0
  152. package/dist/paths.js +42 -0
  153. package/dist/paths.js.map +1 -0
  154. package/dist/pinned-source.d.ts +13 -0
  155. package/dist/pinned-source.d.ts.map +1 -0
  156. package/dist/pinned-source.js +238 -0
  157. package/dist/pinned-source.js.map +1 -0
  158. package/dist/reconcile/cli.d.ts +17 -0
  159. package/dist/reconcile/cli.d.ts.map +1 -0
  160. package/dist/reconcile/cli.js +171 -0
  161. package/dist/reconcile/cli.js.map +1 -0
  162. package/dist/reconcile/detectors.d.ts +29 -0
  163. package/dist/reconcile/detectors.d.ts.map +1 -0
  164. package/dist/reconcile/detectors.js +294 -0
  165. package/dist/reconcile/detectors.js.map +1 -0
  166. package/dist/reconcile/manifest.d.ts +11 -0
  167. package/dist/reconcile/manifest.d.ts.map +1 -0
  168. package/dist/reconcile/manifest.js +118 -0
  169. package/dist/reconcile/manifest.js.map +1 -0
  170. package/dist/reconcile/queue.d.ts +3 -0
  171. package/dist/reconcile/queue.d.ts.map +1 -0
  172. package/dist/reconcile/queue.js +723 -0
  173. package/dist/reconcile/queue.js.map +1 -0
  174. package/dist/reconcile/score.d.ts +19 -0
  175. package/dist/reconcile/score.d.ts.map +1 -0
  176. package/dist/reconcile/score.js +58 -0
  177. package/dist/reconcile/score.js.map +1 -0
  178. package/dist/scripts/check-opencode-config.d.ts +12 -0
  179. package/dist/scripts/check-opencode-config.d.ts.map +1 -0
  180. package/dist/scripts/check-opencode-config.js +216 -0
  181. package/dist/scripts/check-opencode-config.js.map +1 -0
  182. package/dist/scripts/check-pack.d.ts +3 -0
  183. package/dist/scripts/check-pack.d.ts.map +1 -0
  184. package/dist/scripts/check-pack.js +74 -0
  185. package/dist/scripts/check-pack.js.map +1 -0
  186. package/dist/scripts/check-pins.d.ts +9 -0
  187. package/dist/scripts/check-pins.d.ts.map +1 -0
  188. package/dist/scripts/check-pins.js +65 -0
  189. package/dist/scripts/check-pins.js.map +1 -0
  190. package/dist/scripts/check-security.d.ts +3 -0
  191. package/dist/scripts/check-security.d.ts.map +1 -0
  192. package/dist/scripts/check-security.js +47 -0
  193. package/dist/scripts/check-security.js.map +1 -0
  194. package/dist/scripts/check-skills-lock.d.ts +7 -0
  195. package/dist/scripts/check-skills-lock.d.ts.map +1 -0
  196. package/dist/scripts/check-skills-lock.js +36 -0
  197. package/dist/scripts/check-skills-lock.js.map +1 -0
  198. package/dist/scripts/check-skills-sync.d.ts +7 -0
  199. package/dist/scripts/check-skills-sync.d.ts.map +1 -0
  200. package/dist/scripts/check-skills-sync.js +146 -0
  201. package/dist/scripts/check-skills-sync.js.map +1 -0
  202. package/dist/scripts/check-yaml.d.ts +3 -0
  203. package/dist/scripts/check-yaml.d.ts.map +1 -0
  204. package/dist/scripts/check-yaml.js +41 -0
  205. package/dist/scripts/check-yaml.js.map +1 -0
  206. package/dist/scripts/publish-npm.d.ts +3 -0
  207. package/dist/scripts/publish-npm.d.ts.map +1 -0
  208. package/dist/scripts/publish-npm.js +67 -0
  209. package/dist/scripts/publish-npm.js.map +1 -0
  210. package/dist/scripts/release-check.d.ts +3 -0
  211. package/dist/scripts/release-check.d.ts.map +1 -0
  212. package/dist/scripts/release-check.js +97 -0
  213. package/dist/scripts/release-check.js.map +1 -0
  214. package/dist/scripts/support.d.ts +41 -0
  215. package/dist/scripts/support.d.ts.map +1 -0
  216. package/dist/scripts/support.js +78 -0
  217. package/dist/scripts/support.js.map +1 -0
  218. package/dist/targets/claude.d.ts +4 -0
  219. package/dist/targets/claude.d.ts.map +1 -0
  220. package/dist/targets/claude.js +42 -0
  221. package/dist/targets/claude.js.map +1 -0
  222. package/dist/targets/cline.d.ts +4 -0
  223. package/dist/targets/cline.d.ts.map +1 -0
  224. package/dist/targets/cline.js +39 -0
  225. package/dist/targets/cline.js.map +1 -0
  226. package/dist/targets/cursor.d.ts +4 -0
  227. package/dist/targets/cursor.d.ts.map +1 -0
  228. package/dist/targets/cursor.js +40 -0
  229. package/dist/targets/cursor.js.map +1 -0
  230. package/dist/targets/index.d.ts +4 -0
  231. package/dist/targets/index.d.ts.map +1 -0
  232. package/dist/targets/index.js +11 -0
  233. package/dist/targets/index.js.map +1 -0
  234. package/dist/targets/opencode.d.ts +4 -0
  235. package/dist/targets/opencode.d.ts.map +1 -0
  236. package/dist/targets/opencode.js +48 -0
  237. package/dist/targets/opencode.js.map +1 -0
  238. package/dist/targets/windsurf.d.ts +4 -0
  239. package/dist/targets/windsurf.d.ts.map +1 -0
  240. package/dist/targets/windsurf.js +41 -0
  241. package/dist/targets/windsurf.js.map +1 -0
  242. package/dist/types/common.d.ts +193 -0
  243. package/dist/types/common.d.ts.map +1 -0
  244. package/dist/types/common.js +6 -0
  245. package/dist/types/common.js.map +1 -0
  246. package/dist/types/design.d.ts +185 -0
  247. package/dist/types/design.d.ts.map +1 -0
  248. package/dist/types/design.js +3 -0
  249. package/dist/types/design.js.map +1 -0
  250. package/dist/types/guards.d.ts +13 -0
  251. package/dist/types/guards.d.ts.map +1 -0
  252. package/dist/types/guards.js +64 -0
  253. package/dist/types/guards.js.map +1 -0
  254. package/dist/types/handoff.d.ts +29 -0
  255. package/dist/types/handoff.d.ts.map +1 -0
  256. package/dist/types/handoff.js +3 -0
  257. package/dist/types/handoff.js.map +1 -0
  258. package/dist/types/index.d.ts +7 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +11 -0
  261. package/dist/types/index.js.map +1 -0
  262. package/dist/types/orchestrator.d.ts +414 -0
  263. package/dist/types/orchestrator.d.ts.map +1 -0
  264. package/dist/types/orchestrator.js +4 -0
  265. package/dist/types/orchestrator.js.map +1 -0
  266. package/dist/types/reconcile.d.ts +160 -0
  267. package/dist/types/reconcile.d.ts.map +1 -0
  268. package/dist/types/reconcile.js +3 -0
  269. package/dist/types/reconcile.js.map +1 -0
  270. package/docs/RECONCILE.md +505 -0
  271. package/docs/design/_schema.md +506 -0
  272. package/junamis-skills.yml +328 -0
  273. package/library/EXTERNAL.md +35 -0
  274. package/library/HANDOFF.md +93 -0
  275. package/library/RESUME.md +429 -0
  276. package/library/SAFETY.md +83 -0
  277. package/library/agents/context-keeper.md +41 -0
  278. package/library/agents/frontend.md +43 -0
  279. package/library/agents/maintainer.md +44 -0
  280. package/library/agents/nestjs.md +40 -0
  281. package/library/agents/nextjs.md +40 -0
  282. package/library/agents/operator.md +42 -0
  283. package/library/agents/orchestrator.md +313 -0
  284. package/library/agents/researcher.md +40 -0
  285. package/library/agents/reviewer.md +40 -0
  286. package/library/skills/db-migrate/SKILL.md +50 -0
  287. package/library/skills/decision-record/SKILL.md +74 -0
  288. package/library/skills/dependency-upgrade/SKILL.md +57 -0
  289. package/library/skills/deploy-verify/SKILL.md +51 -0
  290. package/library/skills/document/SKILL.md +51 -0
  291. package/library/skills/env-doctor/SKILL.md +65 -0
  292. package/library/skills/frontend/SKILL.md +63 -0
  293. package/library/skills/handoff/SKILL.md +79 -0
  294. package/library/skills/incident-response/SKILL.md +69 -0
  295. package/library/skills/nestjs/SKILL.md +49 -0
  296. package/library/skills/nextjs/SKILL.md +48 -0
  297. package/library/skills/perf-budget/SKILL.md +62 -0
  298. package/library/skills/refactor-safely/SKILL.md +48 -0
  299. package/library/skills/release-prep/SKILL.md +75 -0
  300. package/library/skills/research/SKILL.md +66 -0
  301. package/library/skills/rollback/SKILL.md +49 -0
  302. package/library/skills/route/SKILL.md +107 -0
  303. package/library/skills/route-external/SKILL.md +67 -0
  304. package/library/skills/security-audit/SKILL.md +64 -0
  305. package/library/skills/skill-author/SKILL.md +49 -0
  306. package/opencode.json +5906 -0
  307. package/package.json +88 -4
  308. package/scripts/design-registry.mjs +7 -0
  309. package/scripts/orchestrator-state.mjs +7 -0
  310. package/scripts/reconcile.mjs +7 -0
  311. package/skills-lock.json +197 -0
@@ -0,0 +1,505 @@
1
+ # RECONCILE.md — Work Queue Contract
2
+
3
+ **Status:** normative
4
+ **Schema version:** 1
5
+ **Companion contracts:** `HANDOFF.md` (step output), `RESUME.md` (run persistence), `DESIGN.md` (design registry), `skills-lock.json`, `library/*`
6
+
7
+ ---
8
+
9
+ ## 1. Purpose
10
+
11
+ Define the **work queue generator** — the capability that decides *what to do next*.
12
+
13
+ `RESUME.md` answers "where did the run stop". `DESIGN.md` answers "what should be true". The journal answers "what is true". **`RECONCILE` computes the gap and turns it into a prioritized, dependency-safe work queue** that `route` dispatches from.
14
+
15
+ Without `RECONCILE`, the orchestrator is a very good executor with a static plan. With it, the orchestrator is a controller that converges the project toward the design registry on every session.
16
+
17
+ ---
18
+
19
+ ## 2. Core principle
20
+
21
+ > **The next action is derived, not remembered.**
22
+
23
+ The orchestrator MUST NOT replay a plan blindly. On every reconcile pass it MUST re-read the current state from the durable artifacts (journal + design registry + plan + fingerprints), run detectors, and emit a fresh queue. A queue is valid only for the state it was built against; it is invalidated by any `step_end`, `drift_detected`, or `design_delta_rejected` event.
24
+
25
+ ---
26
+
27
+ ## 3. Invariants (MUST rules)
28
+
29
+ 1. **R1 — Queue is derived.** `work-queue.json` is never hand-edited and never read as input on the next pass. Each pass rebuilds it.
30
+ 2. **R2 — Deterministic scoring.** Priority is computed by a fixed function over `(reason, severity, plan_position)`. No model reasoning influences priority. Any deviation MUST be journaled as `priority_override` with a `rationale` string.
31
+ 3. **R3 — Drift blocks the queue.** When `RESUME.md` reports `Status: BLOCKED_DRIFT` or `HALT_CORRUPT`, `RECONCILE` MUST NOT emit a queue. It emits a `needs_review` work item only.
32
+ 4. **R4 — Shadow safety.** A candidate whose `resolved_skill` is shadowed by an internal override MUST NOT be emitted as executable. If the override fingerprint is stale, emit `shadow_conflict` as `needs_review` instead.
33
+ 5. **R5 — No self-prioritization.** A skill's own emitted estimate or priority is advisory only. The scoring function is the sole authority.
34
+ 6. **R6 — Dependency closure.** A candidate is emitted as `ready` only if all its `depends_on` (plan) and `design.depends_on` prerequisites are `done` or absent. Blocked candidates emit as `blocked` with the blocking surface/task id.
35
+ 7. **R7 — Provenance is preserved.** Every candidate carries the detector(s) that produced it and the journal seq at which they fired. Two detectors on the same target produce one candidate with two provenance entries, not two candidates.
36
+ 8. **R8 — Reconcile is cheap.** A pass MUST NOT invoke a model. It is file reads, comparisons, and arithmetic. Model calls happen only when `route` dispatches the head.
37
+ 9. **R9 — Queue is ephemeral.** `work-queue.json` lives under `$ORCH_STATE_ROOT`, not in the design registry or the plan. It is not committed to the repo.
38
+ 10. **R10 — Empty queue is a state, not a bug.** A `no_work` status is valid and MUST be reported explicitly with the reason (all done, all blocked, needs_review only).
39
+
40
+ ---
41
+
42
+ ## 4. When `RECONCILE` runs
43
+
44
+ `RECONCILE` is a **capability**, not just a boot step. It MUST run at all four points:
45
+
46
+ | Trigger | Reason |
47
+ |---|---|
48
+ | **Boot** (`RESUME.md` B7.5, between resume report and `route`) | Establish the initial queue from durable state |
49
+ | **After every `step_end`** | The last step unlocked, broke, or drifted something |
50
+ | **After every `drift_detected` or `design_delta_rejected`** | Re-prioritize immediately; the queue built against the old state is stale |
51
+ | **Periodic tick** (every `N = 10` `step_end` events, configurable) | Catch slow-burn signals like `stale_surface` |
52
+
53
+ A pass is skipped (not run) when `Status: BLOCKED_DRIFT` or `HALT_CORRUPT` per R3.
54
+
55
+ ---
56
+
57
+ ## 5. Inputs
58
+
59
+ All inputs are already produced by the companion contracts:
60
+
61
+ | Input | Source | Used for |
62
+ |---|---|---|
63
+ | `state.json` | `RESUME.md` §5.1 | Cursor, env fingerprint, task summary |
64
+ | `journal.ndjson` | `RESUME.md` §5.3 | Recent failures, escalations, drift events |
65
+ | `plan.json` | `RESUME.md` §5.2 | Pending / blocked / done tasks, dependency graph |
66
+ | `tasks/<id>/task.json` | `RESUME.md` §5.4 | Per-task status, current step, retries |
67
+ | `tasks/<id>/handoffs/*.yaml` | `HANDOFF.md` | Step outcomes |
68
+ | `docs/design/` | `DESIGN.md` §4 | Surface status, drift flags, coverage |
69
+ | `docs/design/INDEX.md` | `DESIGN.md` §11 | Surface list, gap counts |
70
+ | Override/manifest fingerprint | `RESUME.md` §5.1, `state.env_fingerprint` | Shadow safety |
71
+
72
+ No input is optional. A missing input is a validation failure (`HALT: missing_input`) — never a silent default.
73
+
74
+ ---
75
+
76
+ ## 6. Detectors
77
+
78
+ Each detector is a pure function over the inputs; it emits zero or more `candidate` objects (§7). Detectors MUST be deterministic for a given input snapshot.
79
+
80
+ ### 6.1 Required detectors (MVP)
81
+
82
+ | id | Reads | Emits | Capability | Severity |
83
+ |---|---|---|---|---|
84
+ | `plan_pending` | `plan.json`, `task.json` | Next unblocked `pending` plan task | from plan | from plan |
85
+ | `code_drift` | `docs/design/*`, git or mtime | Surface with `CODE_DRIFT` | `document` | high |
86
+ | `failed_step` | `journal`, `task.json` | Task whose last step was `failed` | same as last | high |
87
+
88
+ ### 6.2 Extended detectors (add after MVP)
89
+
90
+ | id | Reads | Emits | Capability | Severity |
91
+ |---|---|---|---|---|
92
+ | `coverage_gap` | `docs/design/*` | Unclaimed code path | `document` | medium |
93
+ | `dependency_drift` | `docs/design/*` | Surface whose `depends_on` bumped | `develop` or `check` | medium |
94
+ | `needs_review` | `design`, `task.json` | Item in `needs_review` | `audit` or operator | p0 gate |
95
+ | `stale_surface` | `docs/design/*`, git mtime | `active` surface untouched for N days | `check` | low |
96
+ | `shadow_conflict` | override map, `route` table | Skill shadowed but still routed | `needs_review` | p0 gate |
97
+
98
+ Detectors are registered in a manifest (§8) so the orchestrator can enable/disable them without code changes.
99
+
100
+ ---
101
+
102
+ ## 7. Candidate schema
103
+
104
+ ```yaml
105
+ candidate:
106
+ candidate_id: "cand-20261109-0001" # stable hash of (surface_id | task_id, reason)
107
+ capability: develop # one of: scope|architect|develop|test|check|document|audit|sync|needs_review
108
+ target:
109
+ kind: surface # surface | task | repo
110
+ id: api/get-user # surface_id or task_id
111
+ reason: code_drift # detector id (primary)
112
+ priority: p2 # p0..p3, computed (§9)
113
+ severity: high # low | medium | high | critical
114
+ effort: unknown # unknown | small | medium | large (advisory)
115
+ ready: true # false if blocked
116
+ blocked_by: [] # list of task_id or surface_id
117
+ resolved_skill: library/develop # from override map or manifest
118
+ resolution_source: internal_override # internal_override | manifest | needs_review
119
+ provenance:
120
+ - { detector: code_drift, at_seq: 137, at_ts: "2026-11-09T10:42:13Z" }
121
+ rationale: "api/get-user code changed but design_checksum unchanged since last_reviewed"
122
+ ```
123
+
124
+ Rules:
125
+ - `candidate_id` MUST be stable across passes for the same `(target.id, reason)`. Two passes on unchanged state produce the same id.
126
+ - `resolved_skill` is resolved via the same precedence rule as `route` (internal > manifest). `RECONCILE` does **not** dispatch — it resolves only to enable R4 shadow checks.
127
+ - If `resolution_source: needs_review`, the candidate is emitted but its `ready` flag is forced `false` and `reason` becomes `shadow_conflict`.
128
+
129
+ ---
130
+
131
+ ## 8. Detector manifest
132
+
133
+ `$ORCH_STATE_ROOT/reconcile/detectors.yaml` — declares which detectors are active.
134
+
135
+ ```yaml
136
+ schema_version: 1
137
+ detectors:
138
+ - id: plan_pending
139
+ enabled: true
140
+ order: 10
141
+ - id: code_drift
142
+ enabled: true
143
+ order: 20
144
+ params:
145
+ use_git: true
146
+ fallback_mtime: true
147
+ - id: failed_step
148
+ enabled: true
149
+ order: 30
150
+ params:
151
+ max_retries: 3
152
+ - id: coverage_gap
153
+ enabled: false
154
+ order: 40
155
+ - id: shadow_conflict
156
+ enabled: true
157
+ order: 5
158
+ ```
159
+
160
+ `order` breaks ties in the scoring function (§9) when `reason` alone is insufficient. Lower order = evaluated earlier.
161
+
162
+ ---
163
+
164
+ ## 9. Scoring function (fixed, deterministic)
165
+
166
+ Priority is computed from a small lookup table, not inferred.
167
+
168
+ ### 9.1 Severity → base
169
+
170
+ | severity | base |
171
+ |---|---|
172
+ | critical | 0 |
173
+ | high | 1 |
174
+ | medium | 2 |
175
+ | low | 3 |
176
+
177
+ ### 9.2 Reason weight (tie-breaker)
178
+
179
+ ```yaml
180
+ # Lower = higher priority within the same severity
181
+ reason_weight:
182
+ shadow_conflict: 0
183
+ needs_review: 1
184
+ failed_step: 2
185
+ code_drift: 3
186
+ coverage_gap: 4
187
+ dependency_drift: 5
188
+ plan_pending: 6
189
+ stale_surface: 7
190
+ ```
191
+
192
+ ### 9.3 Plan position
193
+
194
+ For `plan_pending` candidates, the task's index in the topologically-sorted `plan.json` is added as a fractional component `+ index / 10000`. This preserves plan order within `plan_pending` while never overriding a different reason.
195
+
196
+ ### 9.4 Priority bucket
197
+
198
+ ```python
199
+ score = base(severity) * 100 + reason_weight(reason) + plan_position_frac
200
+ if score < 100: priority = "p0" # critical always
201
+ elif score < 200: priority = "p1"
202
+ elif score < 300: priority = "p2"
203
+ else: priority = "p3"
204
+ ```
205
+
206
+ The scoring function is defined **here** and MUST NOT be reimplemented per detector. Adding a reason requires adding a `reason_weight` entry; unknown reasons MUST be treated as weight `100` (lowest) and journaled as `unknown_reason` so they can be triaged.
207
+
208
+ ### 9.5 Overrides
209
+
210
+ An override MUST be a journal event, not a silent mutation:
211
+
212
+ ```json
213
+ {"type":"priority_override","candidate_id":"cand-...","from":"p2","to":"p0","rationale":"blocks release","by":"operator","ts":"..."}
214
+ ```
215
+
216
+ Override entries are read on each pass and applied after scoring. No override is valid unless it names a `rationale`.
217
+
218
+ ---
219
+
220
+ ## 10. Queue construction algorithm
221
+
222
+ Executable, deterministic. Run in this exact order.
223
+
224
+ ```
225
+ INPUT: state, journal, plan, tasks, design, detectors, overrides
226
+ OUTPUT: work-queue.json, reconcile-report.md
227
+
228
+ 1. GUARD.
229
+ If state.status in {BLOCKED_DRIFT, HALT_CORRUPT}: emit queue with
230
+ one needs_review item carrying the drift diff; STOP.
231
+
232
+ 2. RUN DETECTORS.
233
+ For each enabled detector in `detectors.yaml` (ordered by `order`):
234
+ candidates += detector.run(inputs)
235
+
236
+ 3. DEDUPE.
237
+ Group candidates by (target.kind, target.id). Merge provenance lists.
238
+ Primary reason = the one with the lowest reason_weight. Secondary reasons
239
+ are preserved in provenance.
240
+
241
+ 4. RESOLVE SKILLS.
242
+ For each candidate: resolved_skill, resolution_source = resolve(capability).
243
+ If shadowed and fingerprint is stale (RESUME.md B4 would have failed):
244
+ reason = shadow_conflict, ready = false, resolution_source = needs_review.
245
+
246
+ 5. DEPENDENCY CHECK.
247
+ For each candidate:
248
+ blockers = plan_task.depends_on (unresolved) ∪ design.depends_on (not done)
249
+ ready = (blockers is empty)
250
+ blocked_by = blockers
251
+
252
+ 6. SCORE.
253
+ priority = score(candidate) per §9.
254
+ Apply operator overrides from journal.
255
+
256
+ 7. SORT.
257
+ Primary sort: priority ascending (p0 first)
258
+ Secondary sort: ready descending (ready before blocked)
259
+ Tertiary sort: plan_position ascending (for plan_pending)
260
+ Final tiebreak: candidate_id ascending (deterministic)
261
+
262
+ 8. EMIT.
263
+ Write work-queue.json (schema §11).
264
+ Write reconcile-report.md (format §12).
265
+ Journal one `reconcile_pass` event with:
266
+ { pass_id, input_fingerprint, candidate_count, ready_count, head_candidate_id }
267
+
268
+ 9. HANDOFF.
269
+ If queue is empty: state.reconcile = "no_work" (R10)
270
+ Else: state.reconcile = "ready"
271
+ Return head to `route`. If head is `ready: false`, `route` MUST NOT
272
+ dispatch — it MUST escalate (§13).
273
+ ```
274
+
275
+ ---
276
+
277
+ ## 11. `work-queue.json` schema
278
+
279
+ Stored at `$ORCH_STATE_ROOT/work-queue.json`. Regenerated on every pass; not committed.
280
+
281
+ ```json
282
+ {
283
+ "schema_version": 1,
284
+ "pass_id": "rec-20261109-0003",
285
+ "generated_at": "2026-11-09T10:42:20Z",
286
+ "input_fingerprint": {
287
+ "journal_head_seq": 137,
288
+ "plan_checksum": "sha256:ab12...",
289
+ "design_index_sha256": "sha256:cd34...",
290
+ "env_fingerprint": { "skills_lock_sha256": "...", "library_overrides_sha256": "..." }
291
+ },
292
+ "status": "ready", // ready | no_work | blocked_drift
293
+ "summary": {
294
+ "total": 4,
295
+ "ready": 2,
296
+ "blocked": 1,
297
+ "needs_review": 1,
298
+ "by_priority": { "p0": 0, "p1": 1, "p2": 2, "p3": 1 }
299
+ },
300
+ "queue": [ /* candidate objects, sorted per §10 */ ]
301
+ }
302
+ ```
303
+
304
+ `input_fingerprint` MUST be recorded so a later pass can detect whether its queue was built against the current state (`input_fingerprint` mismatch = stale queue).
305
+
306
+ ---
307
+
308
+ ## 12. `reconcile-report.md` format
309
+
310
+ Human-readable companion, rewritten on each pass. Minimum content:
311
+
312
+ ```markdown
313
+ # Reconcile Report
314
+
315
+ - Pass: rec-20261109-0003
316
+ - Generated: 2026-11-09T10:42:20Z
317
+ - Status: ready
318
+ - Input fingerprint: journal@137 · plan sha256:ab12… · design sha256:cd34…
319
+
320
+ ## Head
321
+
322
+ - Candidate: cand-20261109-0001
323
+ - Capability: develop → library/develop (internal_override)
324
+ - Target: api/get-user
325
+ - Reason: code_drift (provenance: code_drift@137)
326
+ - Priority: p2 · severity: high · ready: true
327
+
328
+ ## Queue
329
+
330
+ | # | priority | ready | capability | target | reason | skill |
331
+ |---|----------|-------|-----------|--------|--------|-------|
332
+ | 1 | p2 | yes | develop | api/get-user | code_drift | library/develop |
333
+ | 2 | p2 | yes | test | api/get-user | plan_pending | library/test |
334
+ | 3 | p2 | no | develop | web/homepage | plan_pending | library/develop |
335
+ | 4 | p0 | no | needs_review | surface:api/get-user | shadow_conflict | needs_review |
336
+
337
+ ## Blocked
338
+
339
+ - #3 blocked_by: [api/get-user] (design dependency)
340
+ - #4 requires operator resolution (shadow_conflict)
341
+
342
+ ## Detector status
343
+
344
+ | detector | enabled | fired | candidates |
345
+ |----------|---------|-------|------------|
346
+ | shadow_conflict | yes | 1 | 1 |
347
+ | code_drift | yes | 1 | 1 |
348
+ | plan_pending | yes | 2 | 2 |
349
+ ```
350
+
351
+ If `Status: blocked_drift`, the report MUST include a `## Drift` section identical to `resume-report.md`'s `## Drift` section so a reader has the diff in one place.
352
+
353
+ ---
354
+
355
+ ## 13. Escalation rules
356
+
357
+ `RECONCILE` emits; `route` acts. The following are the only valid `route` responses to a queue:
358
+
359
+ | Head state | `route` action |
360
+ |---|---|
361
+ | `ready: true`, `resolution_source` internal_override or manifest | dispatch skill, journal `step_start` |
362
+ | `ready: true`, `resolution_source: needs_review` | **do not dispatch** — journal `escalation` reason `shadow_conflict`, emit to operator |
363
+ | `ready: false`, `blocked_by` non-empty | **do not dispatch** — journal `queue_blocked` and wait for the blocker to resolve (next `step_end` will re-reconcile) |
364
+ | `status: no_work` | journal `run_complete`; stop unless plan has pending items that are all blocked (then emit `run_stalled` with the blocking set) |
365
+ | `status: blocked_drift` | journal `escalation` reason `drift`; stop |
366
+
367
+ `route` MUST NOT skip past the head to dispatch a later candidate. Doing so breaks R7 (provenance) and R3 (drift) — the queue is only sound in order.
368
+
369
+ ---
370
+
371
+ ## 14. Integration points
372
+
373
+ ### 14.1 With `RESUME.md`
374
+
375
+ Add a new boot step **B7.5** between B7 (resume report) and B8 (hand to `route`):
376
+
377
+ ```
378
+ B7.5 — RECONCILE pass.
379
+ If resume Status in {BLOCKED_DRIFT, HALT_CORRUPT}:
380
+ write work-queue.json with status blocked_drift; continue to B8.
381
+ Else:
382
+ run §10 algorithm; write work-queue.json + reconcile-report.md.
383
+ Journal `reconcile_pass`. Continue to B8.
384
+ ```
385
+
386
+ B8 passes `work-queue.json` (not a raw signal) to `route`.
387
+
388
+ The `input_fingerprint` in `work-queue.json` becomes the third fingerprint checked by B4 on the next boot (alongside `skills_lock_sha256`, `library_overrides_sha256`, `design_registry`). A mismatch means the previous queue is stale — regenerate, do not reuse.
389
+
390
+ ### 14.2 With `DESIGN.md`
391
+
392
+ `RECONCILE` reads the design registry; it **never writes to it**. Design facts flow into the queue via detectors, and back out via `design_delta` from skills (handled by `DESIGN.md` §8). The two are read-only on each other's side of the boundary.
393
+
394
+ Add `design_registry.index_sha256` to `input_fingerprint` so a stale queue after design drift is detectable.
395
+
396
+ ### 14.3 With `HANDOFF.md`
397
+
398
+ Every `step_end` event triggers a reconcile pass (§4). The handoff's `status` field feeds `failed_step` and `plan_pending` detectors. Malformed handoffs (§`RESUME.md` B6) emit `needs_review` candidates with `reason: invalid_handoff` (add this to §9.2 weights at weight `1`).
399
+
400
+ ### 14.4 With `skills-lock.json` and `library/*`
401
+
402
+ `RECONCILE` resolves `capability → skill` using the same precedence as `route`. It reads the override map, not the manifest directly, so shadowed entries are already excluded. The `shadow_conflict` detector exists only to catch cases where a candidate's capability has **no** internal override and the manifest entry was removed (a hole in coverage).
403
+
404
+ ---
405
+
406
+ ## 15. Journal events (additions to `RESUME.md` §5.3)
407
+
408
+ New event types emitted by `RECONCILE`:
409
+
410
+ | type | fields |
411
+ |---|---|
412
+ | `reconcile_pass` | `pass_id`, `input_fingerprint`, `candidate_count`, `ready_count`, `head_candidate_id`, `status` |
413
+ | `priority_override` | `candidate_id`, `from`, `to`, `rationale`, `by` |
414
+ | `queue_blocked` | `candidate_id`, `blocked_by` |
415
+ | `queue_stale` | `pass_id`, `mismatched_field` |
416
+ | `unknown_reason` | `reason`, `detector` |
417
+ | `run_stalled` | `blocking_set` (list of task/surface ids) |
418
+
419
+ `reconcile_pass` MUST be emitted even when the queue is empty, so replay can reconstruct queue history.
420
+
421
+ ---
422
+
423
+ ## 16. CI tests
424
+
425
+ **R-T1 — Determinism.** Two passes on the same input snapshot produce byte-equal `work-queue.json`.
426
+
427
+ **R-T2 — Stable ids.** Adding an unrelated candidate does not change the `candidate_id` of existing candidates.
428
+
429
+ **R-T3 — Scoring.** Fixture set of `(reason, severity, plan_position)` → expected `priority`. Covers §9.2 table and §9.4 bucket boundaries.
430
+
431
+ **R-T4 — Drift guard.** `RESUME.md` `BLOCKED_DRIFT` → `RECONCILE` emits `status: blocked_drift` and no dispatchable candidates.
432
+
433
+ **R-T5 — Shadow safety.** A candidate whose `resolved_skill` is shadowed is emitted as `needs_review`, not dispatchable (R4).
434
+
435
+ **R-T6 — Dependency closure.** A candidate with an unmet `depends_on` is `ready: false` with the correct `blocked_by` (R6).
436
+
437
+ **R-T7 — Dedup.** Same target from two detectors → one candidate with two provenance entries (R7).
438
+
439
+ **R-T8 — Reconcile on `step_end`.** A `step_end` event triggers exactly one `reconcile_pass` (not zero, not two).
440
+
441
+ **R-T9 — Empty queue.** All tasks done → `status: no_work` and `run_complete` journaled (R10).
442
+
443
+ **R-T10 — Stalled queue.** All plan items blocked by design items in `needs_review` → `run_stalled` with the blocking set.
444
+
445
+ **R-T11 — Resume integration.** Crash after `step_end` before next reconcile → on boot, B7.5 produces the same head candidate as the uninterrupted run.
446
+
447
+ **R-T12 — Priority override audit.** An operator override without `rationale` is rejected and journaled `priority_override_rejected`.
448
+
449
+ ---
450
+
451
+ ## 17. MVP cut (ship this first)
452
+
453
+ If you want to land `RECONCILE` incrementally, the smallest version that delivers value:
454
+
455
+ 1. **Detectors:** `plan_pending`, `code_drift`, `failed_step` only.
456
+ 2. **Scoring:** §9 with the three reason weights; no `plan_position_frac` (sort `plan_pending` by original plan order instead).
457
+ 3. **Triggers:** boot (B7.5) and after every `step_end`. No periodic tick.
458
+ 4. **Queue:** `work-queue.json` with `ready`/`blocked`; no `needs_review` escalation yet (still emit `shadow_conflict` if it fires, but wire it to a plain log line until §13 lands).
459
+ 5. **Tests:** R-T1, R-T3, R-T8, R-T11.
460
+
461
+ That's roughly a day of work and it immediately makes the orchestrator **convergent**. Add `coverage_gap`, `dependency_drift`, `shadow_conflict`, `stale_surface`, and the periodic tick in a second pass — each is independently shippable, and each adds a specific class of correctness without changing the algorithm.
462
+
463
+ ---
464
+
465
+ ## 18. Acceptance criteria
466
+
467
+ - [ ] Every dispatch by `route` originates from a candidate in the current `work-queue.json` (R1, §13).
468
+ - [ ] Two passes on the same input produce byte-equal queues (R-T1).
469
+ - [ ] A `step_end`, `drift_detected`, or `design_delta_rejected` event triggers a fresh pass (§4).
470
+ - [ ] `Status: BLOCKED_DRIFT` produces `status: blocked_drift` and zero dispatchable candidates (R-T4).
471
+ - [ ] Shadowed skills are never dispatchable via the queue (R-T5).
472
+ - [ ] `route` never skips past the head (§13).
473
+ - [ ] An empty queue is `status: no_work` with `run_complete` journaled, not silently nothing (R10).
474
+ - [ ] Every priority override carries a `rationale` and is journaled (R2, R-T12).
475
+ - [ ] Reconcile passes do not invoke any model (R8) — verified by inspection of the pass code path.
476
+ - [ ] Crash after `step_end` before reconcile still produces the correct next head on boot (R-T11).
477
+
478
+ ---
479
+
480
+ ## 19. Non-goals
481
+
482
+ - `RECONCILE` does **not** execute skills. That is `route`'s job.
483
+ - `RECONCILE` does **not** write to `docs/design/`. Only `design_delta` does.
484
+ - `RECONCILE` does **not** rewrite `plan.json`. Plan changes are a `scope`/`architect` capability outcome, emitted via `HANDOFF.md`.
485
+ - `RECONCILE` does **not** schedule parallel dispatch. The queue is linear; parallelism is a `route` concern if it is added later.
486
+ - `RECONCILE` does **not** decide retry policy. `RESUME.md` §9 remains authoritative; `RECONCILE` only surfaces the retry as a candidate.
487
+ - `RECONCILE` does **not** infer new capabilities. Capabilities are declared by the plan or by the override map.
488
+
489
+ ---
490
+
491
+ ## 20. The convergence loop (why this contract closes the architecture)
492
+
493
+ ```
494
+ DESIGN.md → "what should be true"
495
+ journal → "what is true"
496
+ RECONCILE → gap → prioritized queue
497
+ route → dispatch head
498
+ skill → execute
499
+ HANDOFF → delta
500
+ DESIGN.md → updated truth
501
+ RESUME.md → durable record
502
+ └→ next reconcile pass
503
+ ```
504
+
505
+ The four contracts compose into a loop. `RECONCILE` is the scheduler that turns passive records into active work. Without it, the other three are a filing cabinet. With it, the orchestrator converges the project toward its design registry on every session — which is the actual requirement behind "the orchestrator controls all sub-agents without me managing them."