@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.
- package/CHANGELOG.md +150 -0
- package/LICENSE +21 -0
- package/README.md +231 -2
- package/SECURITY.md +81 -0
- package/bin/junamis-skills.js +7 -0
- package/dist/cli.d.ts +59 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +564 -0
- package/dist/cli.js.map +1 -0
- package/dist/color.d.ts +40 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +55 -0
- package/dist/color.js.map +1 -0
- package/dist/design/atomic.d.ts +4 -0
- package/dist/design/atomic.d.ts.map +1 -0
- package/dist/design/atomic.js +14 -0
- package/dist/design/atomic.js.map +1 -0
- package/dist/design/bootstrap.d.ts +23 -0
- package/dist/design/bootstrap.d.ts.map +1 -0
- package/dist/design/bootstrap.js +411 -0
- package/dist/design/bootstrap.js.map +1 -0
- package/dist/design/cli.d.ts +86 -0
- package/dist/design/cli.d.ts.map +1 -0
- package/dist/design/cli.js +425 -0
- package/dist/design/cli.js.map +1 -0
- package/dist/design/delta.d.ts +45 -0
- package/dist/design/delta.d.ts.map +1 -0
- package/dist/design/delta.js +557 -0
- package/dist/design/delta.js.map +1 -0
- package/dist/design/drift.d.ts +26 -0
- package/dist/design/drift.d.ts.map +1 -0
- package/dist/design/drift.js +341 -0
- package/dist/design/drift.js.map +1 -0
- package/dist/design/errors.d.ts +25 -0
- package/dist/design/errors.d.ts.map +1 -0
- package/dist/design/errors.js +30 -0
- package/dist/design/errors.js.map +1 -0
- package/dist/design/events.d.ts +18 -0
- package/dist/design/events.d.ts.map +1 -0
- package/dist/design/events.js +44 -0
- package/dist/design/events.js.map +1 -0
- package/dist/design/fingerprint.d.ts +10 -0
- package/dist/design/fingerprint.d.ts.map +1 -0
- package/dist/design/fingerprint.js +66 -0
- package/dist/design/fingerprint.js.map +1 -0
- package/dist/design/index-gen.d.ts +16 -0
- package/dist/design/index-gen.d.ts.map +1 -0
- package/dist/design/index-gen.js +94 -0
- package/dist/design/index-gen.js.map +1 -0
- package/dist/design/schema.d.ts +54 -0
- package/dist/design/schema.d.ts.map +1 -0
- package/dist/design/schema.js +408 -0
- package/dist/design/schema.js.map +1 -0
- package/dist/design/yaml.d.ts +12 -0
- package/dist/design/yaml.d.ts.map +1 -0
- package/dist/design/yaml.js +264 -0
- package/dist/design/yaml.js.map +1 -0
- package/dist/external.d.ts +61 -0
- package/dist/external.d.ts.map +1 -0
- package/dist/external.js +426 -0
- package/dist/external.js.map +1 -0
- package/dist/guide.d.ts +17 -0
- package/dist/guide.d.ts.map +1 -0
- package/dist/guide.js +219 -0
- package/dist/guide.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/install-external.d.ts +3 -0
- package/dist/install-external.d.ts.map +1 -0
- package/dist/install-external.js +37 -0
- package/dist/install-external.js.map +1 -0
- package/dist/library-install.d.ts +39 -0
- package/dist/library-install.d.ts.map +1 -0
- package/dist/library-install.js +663 -0
- package/dist/library-install.js.map +1 -0
- package/dist/orchestrator/boot.d.ts +3 -0
- package/dist/orchestrator/boot.d.ts.map +1 -0
- package/dist/orchestrator/boot.js +515 -0
- package/dist/orchestrator/boot.js.map +1 -0
- package/dist/orchestrator/cli.d.ts +37 -0
- package/dist/orchestrator/cli.d.ts.map +1 -0
- package/dist/orchestrator/cli.js +563 -0
- package/dist/orchestrator/cli.js.map +1 -0
- package/dist/orchestrator/commands.d.ts +46 -0
- package/dist/orchestrator/commands.d.ts.map +1 -0
- package/dist/orchestrator/commands.js +752 -0
- package/dist/orchestrator/commands.js.map +1 -0
- package/dist/orchestrator/compaction.d.ts +21 -0
- package/dist/orchestrator/compaction.d.ts.map +1 -0
- package/dist/orchestrator/compaction.js +93 -0
- package/dist/orchestrator/compaction.js.map +1 -0
- package/dist/orchestrator/drift.d.ts +11 -0
- package/dist/orchestrator/drift.d.ts.map +1 -0
- package/dist/orchestrator/drift.js +181 -0
- package/dist/orchestrator/drift.js.map +1 -0
- package/dist/orchestrator/errors.d.ts +52 -0
- package/dist/orchestrator/errors.d.ts.map +1 -0
- package/dist/orchestrator/errors.js +96 -0
- package/dist/orchestrator/errors.js.map +1 -0
- package/dist/orchestrator/frontmatter.d.ts +6 -0
- package/dist/orchestrator/frontmatter.d.ts.map +1 -0
- package/dist/orchestrator/frontmatter.js +50 -0
- package/dist/orchestrator/frontmatter.js.map +1 -0
- package/dist/orchestrator/fsx.d.ts +45 -0
- package/dist/orchestrator/fsx.d.ts.map +1 -0
- package/dist/orchestrator/fsx.js +295 -0
- package/dist/orchestrator/fsx.js.map +1 -0
- package/dist/orchestrator/handoff.d.ts +8 -0
- package/dist/orchestrator/handoff.d.ts.map +1 -0
- package/dist/orchestrator/handoff.js +246 -0
- package/dist/orchestrator/handoff.js.map +1 -0
- package/dist/orchestrator/hash.d.ts +10 -0
- package/dist/orchestrator/hash.d.ts.map +1 -0
- package/dist/orchestrator/hash.js +65 -0
- package/dist/orchestrator/hash.js.map +1 -0
- package/dist/orchestrator/journal.d.ts +35 -0
- package/dist/orchestrator/journal.d.ts.map +1 -0
- package/dist/orchestrator/journal.js +163 -0
- package/dist/orchestrator/journal.js.map +1 -0
- package/dist/orchestrator/lease.d.ts +31 -0
- package/dist/orchestrator/lease.d.ts.map +1 -0
- package/dist/orchestrator/lease.js +175 -0
- package/dist/orchestrator/lease.js.map +1 -0
- package/dist/orchestrator/plan.d.ts +27 -0
- package/dist/orchestrator/plan.d.ts.map +1 -0
- package/dist/orchestrator/plan.js +240 -0
- package/dist/orchestrator/plan.js.map +1 -0
- package/dist/orchestrator/report.d.ts +49 -0
- package/dist/orchestrator/report.d.ts.map +1 -0
- package/dist/orchestrator/report.js +244 -0
- package/dist/orchestrator/report.js.map +1 -0
- package/dist/orchestrator/state.d.ts +43 -0
- package/dist/orchestrator/state.d.ts.map +1 -0
- package/dist/orchestrator/state.js +369 -0
- package/dist/orchestrator/state.js.map +1 -0
- package/dist/orchestrator/store.d.ts +42 -0
- package/dist/orchestrator/store.d.ts.map +1 -0
- package/dist/orchestrator/store.js +202 -0
- package/dist/orchestrator/store.js.map +1 -0
- package/dist/orchestrator/test-hooks.d.ts +5 -0
- package/dist/orchestrator/test-hooks.d.ts.map +1 -0
- package/dist/orchestrator/test-hooks.js +31 -0
- package/dist/orchestrator/test-hooks.js.map +1 -0
- package/dist/orchestrator/time.d.ts +11 -0
- package/dist/orchestrator/time.d.ts.map +1 -0
- package/dist/orchestrator/time.js +38 -0
- package/dist/orchestrator/time.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +42 -0
- package/dist/paths.js.map +1 -0
- package/dist/pinned-source.d.ts +13 -0
- package/dist/pinned-source.d.ts.map +1 -0
- package/dist/pinned-source.js +238 -0
- package/dist/pinned-source.js.map +1 -0
- package/dist/reconcile/cli.d.ts +17 -0
- package/dist/reconcile/cli.d.ts.map +1 -0
- package/dist/reconcile/cli.js +171 -0
- package/dist/reconcile/cli.js.map +1 -0
- package/dist/reconcile/detectors.d.ts +29 -0
- package/dist/reconcile/detectors.d.ts.map +1 -0
- package/dist/reconcile/detectors.js +294 -0
- package/dist/reconcile/detectors.js.map +1 -0
- package/dist/reconcile/manifest.d.ts +11 -0
- package/dist/reconcile/manifest.d.ts.map +1 -0
- package/dist/reconcile/manifest.js +118 -0
- package/dist/reconcile/manifest.js.map +1 -0
- package/dist/reconcile/queue.d.ts +3 -0
- package/dist/reconcile/queue.d.ts.map +1 -0
- package/dist/reconcile/queue.js +723 -0
- package/dist/reconcile/queue.js.map +1 -0
- package/dist/reconcile/score.d.ts +19 -0
- package/dist/reconcile/score.d.ts.map +1 -0
- package/dist/reconcile/score.js +58 -0
- package/dist/reconcile/score.js.map +1 -0
- package/dist/scripts/check-opencode-config.d.ts +12 -0
- package/dist/scripts/check-opencode-config.d.ts.map +1 -0
- package/dist/scripts/check-opencode-config.js +216 -0
- package/dist/scripts/check-opencode-config.js.map +1 -0
- package/dist/scripts/check-pack.d.ts +3 -0
- package/dist/scripts/check-pack.d.ts.map +1 -0
- package/dist/scripts/check-pack.js +74 -0
- package/dist/scripts/check-pack.js.map +1 -0
- package/dist/scripts/check-pins.d.ts +9 -0
- package/dist/scripts/check-pins.d.ts.map +1 -0
- package/dist/scripts/check-pins.js +65 -0
- package/dist/scripts/check-pins.js.map +1 -0
- package/dist/scripts/check-security.d.ts +3 -0
- package/dist/scripts/check-security.d.ts.map +1 -0
- package/dist/scripts/check-security.js +47 -0
- package/dist/scripts/check-security.js.map +1 -0
- package/dist/scripts/check-skills-lock.d.ts +7 -0
- package/dist/scripts/check-skills-lock.d.ts.map +1 -0
- package/dist/scripts/check-skills-lock.js +36 -0
- package/dist/scripts/check-skills-lock.js.map +1 -0
- package/dist/scripts/check-skills-sync.d.ts +7 -0
- package/dist/scripts/check-skills-sync.d.ts.map +1 -0
- package/dist/scripts/check-skills-sync.js +146 -0
- package/dist/scripts/check-skills-sync.js.map +1 -0
- package/dist/scripts/check-yaml.d.ts +3 -0
- package/dist/scripts/check-yaml.d.ts.map +1 -0
- package/dist/scripts/check-yaml.js +41 -0
- package/dist/scripts/check-yaml.js.map +1 -0
- package/dist/scripts/publish-npm.d.ts +3 -0
- package/dist/scripts/publish-npm.d.ts.map +1 -0
- package/dist/scripts/publish-npm.js +67 -0
- package/dist/scripts/publish-npm.js.map +1 -0
- package/dist/scripts/release-check.d.ts +3 -0
- package/dist/scripts/release-check.d.ts.map +1 -0
- package/dist/scripts/release-check.js +97 -0
- package/dist/scripts/release-check.js.map +1 -0
- package/dist/scripts/support.d.ts +41 -0
- package/dist/scripts/support.d.ts.map +1 -0
- package/dist/scripts/support.js +78 -0
- package/dist/scripts/support.js.map +1 -0
- package/dist/targets/claude.d.ts +4 -0
- package/dist/targets/claude.d.ts.map +1 -0
- package/dist/targets/claude.js +42 -0
- package/dist/targets/claude.js.map +1 -0
- package/dist/targets/cline.d.ts +4 -0
- package/dist/targets/cline.d.ts.map +1 -0
- package/dist/targets/cline.js +39 -0
- package/dist/targets/cline.js.map +1 -0
- package/dist/targets/cursor.d.ts +4 -0
- package/dist/targets/cursor.d.ts.map +1 -0
- package/dist/targets/cursor.js +40 -0
- package/dist/targets/cursor.js.map +1 -0
- package/dist/targets/index.d.ts +4 -0
- package/dist/targets/index.d.ts.map +1 -0
- package/dist/targets/index.js +11 -0
- package/dist/targets/index.js.map +1 -0
- package/dist/targets/opencode.d.ts +4 -0
- package/dist/targets/opencode.d.ts.map +1 -0
- package/dist/targets/opencode.js +48 -0
- package/dist/targets/opencode.js.map +1 -0
- package/dist/targets/windsurf.d.ts +4 -0
- package/dist/targets/windsurf.d.ts.map +1 -0
- package/dist/targets/windsurf.js +41 -0
- package/dist/targets/windsurf.js.map +1 -0
- package/dist/types/common.d.ts +193 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +6 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/design.d.ts +185 -0
- package/dist/types/design.d.ts.map +1 -0
- package/dist/types/design.js +3 -0
- package/dist/types/design.js.map +1 -0
- package/dist/types/guards.d.ts +13 -0
- package/dist/types/guards.d.ts.map +1 -0
- package/dist/types/guards.js +64 -0
- package/dist/types/guards.js.map +1 -0
- package/dist/types/handoff.d.ts +29 -0
- package/dist/types/handoff.d.ts.map +1 -0
- package/dist/types/handoff.js +3 -0
- package/dist/types/handoff.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/orchestrator.d.ts +414 -0
- package/dist/types/orchestrator.d.ts.map +1 -0
- package/dist/types/orchestrator.js +4 -0
- package/dist/types/orchestrator.js.map +1 -0
- package/dist/types/reconcile.d.ts +160 -0
- package/dist/types/reconcile.d.ts.map +1 -0
- package/dist/types/reconcile.js +3 -0
- package/dist/types/reconcile.js.map +1 -0
- package/docs/RECONCILE.md +505 -0
- package/docs/design/_schema.md +506 -0
- package/junamis-skills.yml +328 -0
- package/library/EXTERNAL.md +35 -0
- package/library/HANDOFF.md +93 -0
- package/library/RESUME.md +429 -0
- package/library/SAFETY.md +83 -0
- package/library/agents/context-keeper.md +41 -0
- package/library/agents/frontend.md +43 -0
- package/library/agents/maintainer.md +44 -0
- package/library/agents/nestjs.md +40 -0
- package/library/agents/nextjs.md +40 -0
- package/library/agents/operator.md +42 -0
- package/library/agents/orchestrator.md +313 -0
- package/library/agents/researcher.md +40 -0
- package/library/agents/reviewer.md +40 -0
- package/library/skills/db-migrate/SKILL.md +50 -0
- package/library/skills/decision-record/SKILL.md +74 -0
- package/library/skills/dependency-upgrade/SKILL.md +57 -0
- package/library/skills/deploy-verify/SKILL.md +51 -0
- package/library/skills/document/SKILL.md +51 -0
- package/library/skills/env-doctor/SKILL.md +65 -0
- package/library/skills/frontend/SKILL.md +63 -0
- package/library/skills/handoff/SKILL.md +79 -0
- package/library/skills/incident-response/SKILL.md +69 -0
- package/library/skills/nestjs/SKILL.md +49 -0
- package/library/skills/nextjs/SKILL.md +48 -0
- package/library/skills/perf-budget/SKILL.md +62 -0
- package/library/skills/refactor-safely/SKILL.md +48 -0
- package/library/skills/release-prep/SKILL.md +75 -0
- package/library/skills/research/SKILL.md +66 -0
- package/library/skills/rollback/SKILL.md +49 -0
- package/library/skills/route/SKILL.md +107 -0
- package/library/skills/route-external/SKILL.md +67 -0
- package/library/skills/security-audit/SKILL.md +64 -0
- package/library/skills/skill-author/SKILL.md +49 -0
- package/opencode.json +5906 -0
- package/package.json +88 -4
- package/scripts/design-registry.mjs +7 -0
- package/scripts/orchestrator-state.mjs +7 -0
- package/scripts/reconcile.mjs +7 -0
- 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."
|