@kontourai/flow-agents 3.1.0 → 3.3.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 (86) hide show
  1. package/.github/workflows/ci.yml +16 -0
  2. package/CHANGELOG.md +30 -0
  3. package/build/src/cli/assignment-provider.d.ts +45 -0
  4. package/build/src/cli/assignment-provider.js +107 -13
  5. package/build/src/cli/workflow-artifact-cleanup-audit.js +418 -11
  6. package/build/src/cli/workflow-sidecar.d.ts +238 -4
  7. package/build/src/cli/workflow-sidecar.js +875 -14
  8. package/build/src/tools/validate-source-tree.js +3 -2
  9. package/context/contracts/artifact-contract.md +16 -2
  10. package/context/contracts/assignment-provider-contract.md +1 -1
  11. package/context/contracts/execution-contract.md +78 -0
  12. package/context/scripts/hooks/config-protection.js +11 -4
  13. package/context/scripts/hooks/stop-goal-fit.js +259 -4
  14. package/context/scripts/hooks/workflow-steering.js +73 -1
  15. package/docs/adr/0022-fail-closed-delivery-reconciliation-with-governed-exemptions.md +111 -0
  16. package/docs/coordination-guide.md +370 -0
  17. package/docs/decisions/agent-coordination.md +26 -9
  18. package/docs/decisions/index.md +2 -2
  19. package/docs/decisions/trust-reconcile.md +42 -9
  20. package/docs/fixture-ownership.md +3 -2
  21. package/docs/index.md +4 -0
  22. package/docs/integrations/flow-agents-console.md +108 -0
  23. package/docs/integrations/index.md +4 -0
  24. package/docs/workflow-artifact-lifecycle.md +38 -1
  25. package/evals/ci/antigaming-suite.sh +1 -0
  26. package/evals/ci/run-baseline.sh +8 -0
  27. package/evals/fixtures/reconcile-preflight/disputed-critique-unsuperseded.json +48 -0
  28. package/evals/fixtures/reconcile-preflight/standalone-disputed-session-local.json +59 -0
  29. package/evals/integration/test_checkpoint_signing.sh +14 -5
  30. package/evals/integration/test_ci_actor_identity.sh +221 -0
  31. package/evals/integration/test_fixture_retirement_audit.sh +2 -2
  32. package/evals/integration/test_gate_lockdown.sh +36 -0
  33. package/evals/integration/test_model_routing_escalation.sh +145 -0
  34. package/evals/integration/test_publish_delivery.sh +73 -8
  35. package/evals/integration/test_reconcile_preflight.sh +304 -0
  36. package/evals/integration/test_stop_hook_release.sh +552 -0
  37. package/evals/integration/test_takeover_protocol.sh +340 -0
  38. package/evals/integration/test_trust_reconcile_negatives.sh +261 -0
  39. package/evals/integration/test_verify_hold.sh +910 -0
  40. package/evals/integration/test_veritas_governance_kit.sh +257 -0
  41. package/evals/integration/test_workflow_artifact_cleanup_audit.sh +575 -3
  42. package/evals/run.sh +14 -0
  43. package/evals/static/test_model_routing_hints.sh +107 -0
  44. package/kits/builder/skills/builder-shape/SKILL.md +10 -0
  45. package/kits/builder/skills/continue-work/SKILL.md +2 -0
  46. package/kits/builder/skills/deliver/SKILL.md +125 -11
  47. package/kits/builder/skills/design-probe/SKILL.md +10 -0
  48. package/kits/builder/skills/execute-plan/SKILL.md +13 -0
  49. package/kits/builder/skills/fix-bug/SKILL.md +17 -0
  50. package/kits/builder/skills/idea-to-backlog/SKILL.md +10 -0
  51. package/kits/builder/skills/plan-work/SKILL.md +9 -0
  52. package/kits/builder/skills/pull-work/SKILL.md +22 -2
  53. package/kits/builder/skills/review-work/SKILL.md +11 -0
  54. package/kits/builder/skills/tdd-workflow/SKILL.md +17 -0
  55. package/kits/builder/skills/verify-work/SKILL.md +11 -0
  56. package/kits/knowledge/adapters/default-store/index.js +56 -15
  57. package/kits/knowledge/adapters/flow-runner/index.js +912 -16
  58. package/kits/knowledge/adapters/obsidian-store/index.js +29 -11
  59. package/kits/knowledge/adapters/shared/codec.js +124 -0
  60. package/kits/knowledge/docs/store-contract.md +405 -3
  61. package/kits/knowledge/evals/audit-freshness/suite.test.js +92 -1
  62. package/kits/knowledge/evals/consolidate-incremental/suite.test.js +494 -0
  63. package/kits/knowledge/evals/consolidation/suite.test.js +1 -1
  64. package/kits/knowledge/evals/contract-suite/suite.test.js +36 -0
  65. package/kits/knowledge/evals/freshness/suite.test.js +339 -0
  66. package/kits/knowledge/evals/inbound-references/suite.test.js +351 -0
  67. package/kits/knowledge/evals/retirement/suite.test.js +1 -1
  68. package/kits/knowledge/evals/supersede-propagation/suite.test.js +384 -0
  69. package/kits/veritas-governance/docs/README.md +81 -3
  70. package/kits/veritas-governance/fixtures/exemption/approved.trust-bundle.json +74 -0
  71. package/kits/veritas-governance/fixtures/exemption/not-approved.trust-bundle.json +74 -0
  72. package/kits/veritas-governance/flows/exemption-issuance.flow.json +35 -0
  73. package/kits/veritas-governance/kit.json +5 -0
  74. package/package.json +1 -1
  75. package/schemas/workflow-handoff.schema.json +6 -0
  76. package/scripts/ci/mint-attestation.js +33 -6
  77. package/scripts/ci/trust-reconcile.js +222 -279
  78. package/scripts/hooks/config-protection.js +11 -4
  79. package/scripts/hooks/lib/actor-identity.js +82 -0
  80. package/scripts/hooks/stop-goal-fit.js +259 -4
  81. package/scripts/hooks/workflow-steering.js +73 -1
  82. package/scripts/lib/reconcile-shape.js +381 -0
  83. package/src/cli/assignment-provider.ts +122 -13
  84. package/src/cli/workflow-artifact-cleanup-audit.ts +483 -10
  85. package/src/cli/workflow-sidecar.ts +965 -14
  86. package/src/tools/validate-source-tree.ts +3 -2
package/evals/run.sh CHANGED
@@ -148,6 +148,8 @@ run_static() {
148
148
  bash "$EVAL_DIR/static/test_unit_helpers.sh" || result=1
149
149
  echo ""
150
150
  bash "$EVAL_DIR/static/test_knowledge_providers.sh" || result=1
151
+ echo ""
152
+ bash "$EVAL_DIR/static/test_model_routing_hints.sh" || result=1
151
153
  return $result
152
154
  }
153
155
 
@@ -197,14 +199,22 @@ run_integration() {
197
199
  echo ""
198
200
  bash "$EVAL_DIR/integration/test_actor_identity.sh" || result=1
199
201
  echo ""
202
+ bash "$EVAL_DIR/integration/test_ci_actor_identity.sh" || result=1
203
+ echo ""
200
204
  bash "$EVAL_DIR/integration/test_assignment_provider_local_file.sh" || result=1
201
205
  echo ""
202
206
  bash "$EVAL_DIR/integration/test_assignment_provider_github.sh" || result=1
203
207
  echo ""
208
+ bash "$EVAL_DIR/integration/test_stop_hook_release.sh" || result=1
209
+ echo ""
204
210
  bash "$EVAL_DIR/integration/test_pull_work_assignment_join.sh" || result=1
205
211
  echo ""
206
212
  bash "$EVAL_DIR/integration/test_ensure_session_ownership_guard.sh" || result=1
207
213
  echo ""
214
+ bash "$EVAL_DIR/integration/test_verify_hold.sh" || result=1
215
+ echo ""
216
+ bash "$EVAL_DIR/integration/test_takeover_protocol.sh" || result=1
217
+ echo ""
208
218
  bash "$EVAL_DIR/integration/test_current_json_per_actor.sh" || result=1
209
219
  echo ""
210
220
  bash "$EVAL_DIR/integration/test_liveness_heartbeat.sh" || result=1
@@ -276,12 +286,16 @@ run_integration() {
276
286
  echo ""
277
287
  bash "$EVAL_DIR/integration/test_publish_delivery.sh" || result=1
278
288
  echo ""
289
+ bash "$EVAL_DIR/integration/test_reconcile_preflight.sh" || result=1
290
+ echo ""
279
291
  bash "$EVAL_DIR/integration/test_mint_attestation.sh" || result=1
280
292
  echo ""
281
293
  bash "$EVAL_DIR/integration/test_verify_cli.sh" || result=1
282
294
  echo ""
283
295
  bash "$EVAL_DIR/integration/test_kit_identity_trust.sh" || result=1
284
296
  echo ""
297
+ bash "$EVAL_DIR/integration/test_model_routing_escalation.sh" || result=1
298
+ echo ""
285
299
  bash "$EVAL_DIR/acceptance/prove-capture-teeth-declared.sh" || result=1
286
300
  return $result
287
301
  }
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env bash
2
+ # test_model_routing_hints.sh — #376
3
+ # Asserts that every delegating Builder Kit skill carries a per-step model-role
4
+ # hint pointing at the execution contract (AC1/R1), that the execution contract
5
+ # documents the escalate-on-gate-failure ladder (R2) and the Goodhart guard
6
+ # (R3, review/verify tier >= worker tier), and that review/verify skill hints
7
+ # encode that guard.
8
+ set -euo pipefail
9
+
10
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
11
+ cd "$ROOT_DIR"
12
+
13
+ SKILLS="kits/builder/skills"
14
+ CONTRACT="context/contracts/execution-contract.md"
15
+ POINTER="context/contracts/execution-contract.md"
16
+
17
+ pass() { echo "PASS: $1"; }
18
+ fail() { echo "FAIL: $1" >&2; exit 1; }
19
+
20
+ require_contains() {
21
+ local file="$1" pattern="$2" label="$3"
22
+ grep -Fq -- "$pattern" "$file" || fail "$label ($file)"
23
+ pass "$label"
24
+ }
25
+
26
+ skill_has_routing_hint() {
27
+ # A delegating skill must have a Model Routing section that points at the
28
+ # execution contract's routing section — the single consumption instruction.
29
+ local skill="$1"
30
+ local file="$SKILLS/$skill/SKILL.md"
31
+ [[ -f "$file" ]] || fail "$skill SKILL.md missing"
32
+ grep -q "^## Model Routing" "$file" || fail "$skill has no '## Model Routing' section"
33
+ grep -Fq "$POINTER" "$file" || fail "$skill routing hint does not point at the execution contract"
34
+ pass "$skill has a Model Routing hint pointing at the execution contract"
35
+ }
36
+
37
+ skill_names_role() {
38
+ local skill="$1" role="$2"
39
+ local file="$SKILLS/$skill/SKILL.md"
40
+ grep -Fq "$role" "$file" || fail "$skill does not name role '$role'"
41
+ pass "$skill names role '$role'"
42
+ }
43
+
44
+ # ── R1/AC1: the delegating Builder Kit skills and the role each must name ──────
45
+ # Design tier: shaping / probing / planning need design latitude.
46
+ for s in builder-shape design-probe idea-to-backlog plan-work; do
47
+ skill_has_routing_hint "$s"
48
+ skill_names_role "$s" "delegate-design"
49
+ done
50
+
51
+ # Mechanical tier: board selection / sync / scan bookkeeping.
52
+ skill_has_routing_hint "pull-work"
53
+ skill_names_role "pull-work" "delegate-mechanical"
54
+
55
+ # Implementation tier: worker slices.
56
+ skill_has_routing_hint "execute-plan"
57
+ skill_names_role "execute-plan" "delegate-implementation"
58
+
59
+ # Review / verify: default implementation, subject to the Goodhart guard (R3).
60
+ for s in review-work verify-work; do
61
+ skill_has_routing_hint "$s"
62
+ skill_names_role "$s" "delegate-implementation"
63
+ done
64
+
65
+ # Multi-delegate orchestrators carry a role table covering all three tiers.
66
+ for s in deliver fix-bug tdd-workflow; do
67
+ skill_has_routing_hint "$s"
68
+ skill_names_role "$s" "delegate-mechanical"
69
+ skill_names_role "$s" "delegate-implementation"
70
+ skill_names_role "$s" "delegate-design"
71
+ done
72
+
73
+ # ── Drift guard: any builder skill that names a tool-* delegate must be a
74
+ # registered delegating skill above (i.e., must carry a Model Routing hint).
75
+ DELEGATING="builder-shape design-probe idea-to-backlog plan-work pull-work execute-plan review-work verify-work deliver fix-bug tdd-workflow"
76
+ for file in "$SKILLS"/*/SKILL.md; do
77
+ skill="$(basename "$(dirname "$file")")"
78
+ if grep -qE "tool-(worker|planner|code-reviewer|security-reviewer|verifier|playwright)" "$file"; then
79
+ case " $DELEGATING " in
80
+ *" $skill "*) : ;;
81
+ *) fail "skill '$skill' names a tool-* delegate but has no registered Model Routing hint (register it in test_model_routing_hints.sh and add the hint)" ;;
82
+ esac
83
+ fi
84
+ done
85
+ pass "every tool-* delegating builder skill is registered with a Model Routing hint"
86
+
87
+ # ── R3/AC3: review + verify skill hints encode the Goodhart guard ─────────────
88
+ for s in review-work verify-work; do
89
+ file="$SKILLS/$s/SKILL.md"
90
+ grep -Fq "Goodhart guard" "$file" || fail "$s hint does not name the Goodhart guard"
91
+ grep -Fq "never" "$file" || fail "$s hint does not state the never-downgrade rule"
92
+ grep -Fiq "below" "$file" || fail "$s hint does not say review/verify never resolves below the checked work"
93
+ pass "$s hint encodes the Goodhart guard (never below the checked-work tier)"
94
+ done
95
+
96
+ # ── R2/AC2 + R3/AC3: the execution contract documents ladder + guard + record ─
97
+ require_contains "$CONTRACT" "delegate-mechanical < delegate-implementation < delegate-design" "contract defines the tier ladder ordering"
98
+ require_contains "$CONTRACT" "Escalation on gate failure" "contract documents the escalation ladder"
99
+ require_contains "$CONTRACT" "one tier higher" "contract escalates the fix one tier higher on gate failure"
100
+ require_contains "$CONTRACT" "Goodhart guard" "contract documents the Goodhart guard"
101
+ require_contains "$CONTRACT" "greater than or equal to" "contract states review/verify tier >= checked-work tier"
102
+ # R4: contract names the additive per-delegation recording shape (#349 consumable).
103
+ require_contains "$CONTRACT" "Routing decisions in the run artifact" "contract documents routing-in-artifact recording"
104
+ require_contains "$CONTRACT" "--escalated-from" "contract records escalations with --escalated-from"
105
+ require_contains "$CONTRACT" "flow-agents#349" "contract ties routing records to the #349 economics record"
106
+
107
+ echo "Model routing hint + ladder + Goodhart guard static checks passed."
@@ -22,6 +22,16 @@ Invoke the Builder Kit `shape` flow for raw product ideas, vague build goals, cu
22
22
  - Compatibility: Direct `idea-to-backlog` usage remains valid and should behave exactly as described in `kits/builder/skills/idea-to-backlog/SKILL.md`.
23
23
  - Primitive recovery: if a user invokes `idea-to-backlog` or another primitive with missing shaping context and appears to want the product flow, explain that Builder Kit shape is the entry point and offer to route there.
24
24
 
25
+ ## Model Routing
26
+
27
+ When this skill delegates its shaping work (to `idea-to-backlog` / `design-probe`
28
+ alignment), resolve the `delegate-design` role from `.datum/config.json`
29
+ (`npx @kontourai/datum resolve delegate-design --json`) and pass the resolved
30
+ model explicitly — shaping needs design latitude, so it routes to the design
31
+ tier. See `context/contracts/execution-contract.md` § Delegation: Model Routing.
32
+ Fallback: inherit the session model when datum/config is absent, noted in the
33
+ artifact.
34
+
25
35
  ## Invocation
26
36
 
27
37
  Use this skill when the user says things like:
@@ -49,6 +49,8 @@ Before doing anything else, restore the item's durable record into context throu
49
49
 
50
50
  If no durable record exists for the item, record that gap and rely on the issue body plus merged PRs/commits as the authoritative history.
51
51
 
52
+ If the item was taken over from a stale incumbent (a `reclaimable` selection resumed via pull-work's **Takeover Protocol**, #294 / ADR 0021 §5), restoring the durable record IS the resumption: the deterministic slug points at the incumbent's existing `.kontourai/flow-agents/<slug>/`, and you continue the incumbent's branch (the `resume_branch` from `takeover-preflight`/the supersede output) — never a new branch, never a restarted plan. Takeover is resumption, not restart.
53
+
52
54
  ### 2. Determine the next undone slice
53
55
 
54
56
  From the issue body plus the merged PRs and commits referencing the issue, determine which slices have **landed** and which is the **next undone slice**.
@@ -32,11 +32,16 @@ source of truth for the mapping):
32
32
  |---|---|
33
33
  | tool-worker | `delegate-mechanical` for fully-specified mechanical tasks, `delegate-implementation` for precisely-planned implementation, `delegate-design` when the task needs design latitude |
34
34
  | tool-planner | `delegate-design` |
35
- | tool-code-reviewer / tool-security-reviewer | `delegate-implementation` |
36
- | tool-verifier / tool-playwright | `delegate-implementation` |
35
+ | tool-code-reviewer / tool-security-reviewer | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
36
+ | tool-verifier / tool-playwright | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
37
37
 
38
- If datum or the config is absent, fall back to the runtime's inherited model
39
- and note the fallback in the session artifact.
38
+ On a review/verify gate failure, re-dispatch the fix one tier higher on the
39
+ ladder and record the escalation in the session artifact via
40
+ `record-agent-event --kind escalation --role <higher> --escalated-from <lower>`
41
+ (see `context/contracts/execution-contract.md` § Escalation on gate failure and
42
+ § Routing decisions in the run artifact). If datum or the config is absent, fall
43
+ back to the runtime's inherited model and note the fallback in the session
44
+ artifact.
40
45
 
41
46
  ## Orchestrator Rule
42
47
 
@@ -236,23 +241,132 @@ Record the final local state with `advance-state`. Use `status: verified` only w
236
241
  After review, verification, evidence, and Goal Fit are clean for the same diff:
237
242
 
238
243
  1. Confirm the working tree contains only verified scope.
239
- 2. Publish the session trust bundle to `delivery/` so the CI trust-reconcile job can verify what the agent claimed. `record-release` (via the sidecar writer) does this automatically (best-effort). To publish or re-publish explicitly:
244
+ 2. Publish the session trust bundle so the CI trust-reconcile job can verify what the agent claimed. `record-release` (via the sidecar writer) does this automatically (best-effort). To publish or re-publish explicitly:
240
245
 
241
246
  ```bash
242
247
  npm run workflow:sidecar -- publish-delivery .kontourai/flow-agents/<slug>
243
248
  ```
244
249
 
245
- Then force-stage the trust artifacts for the delivery commit. They are gitignored
246
- by default (they are runtime artifacts written on every local delivery) — `-f`
247
- commits them deliberately into THIS delivery PR so CI's trust-reconcile job can
248
- reconcile the session's claims against fresh CI results:
250
+ **#356 local reconcile-shape preflight.** `publish-delivery`/`record-release` now run a
251
+ local, pre-push **reconcile-shape preflight** on the session's `trust.bundle` before
252
+ copying anything into `delivery/`. It reuses the exact same claim-shape classification
253
+ `scripts/ci/trust-reconcile.js` enforces in CI (`scripts/lib/reconcile-shape.js`), so it
254
+ can never silently drift from what the required Trust Reconcile check actually does. If
255
+ the bundle is ADR-0020-invalid (e.g. a command-backed claim whose command isn't in the
256
+ reconcile manifest, an unwaived `assumed` claim, or an un-superseded disputed critique),
257
+ publish is **refused, fail-closed** — non-zero exit, a loud `REFUSING to publish` message
258
+ naming each invalid claim and its fix, and nothing is written to `delivery/`. This is
259
+ distinct from the existing fail-**soft** behavior when no `trust.bundle` exists yet at all
260
+ (still a silent no-op). When refused: fix the named claim (re-record evidence, add a
261
+ missing waiver, or supersede the disputed critique), then retry — do not attempt to push
262
+ past the refusal. You can also run the same check manually, any time before publish, to
263
+ catch a shape issue locally instead of discovering it minutes later in CI:
249
264
 
250
265
  ```bash
251
- git add -f delivery/trust.bundle delivery/trust.checkpoint.json
266
+ npm run workflow:sidecar -- reconcile-preflight .kontourai/flow-agents/<slug>
252
267
  ```
253
268
 
254
- 3. Commit the verified diff, including the force-added `delivery/trust.bundle` and `delivery/trust.checkpoint.json`.
269
+ **#379 per-session delivery paths.** `publishDelivery()` writes to a PER-SESSION path
270
+ `delivery/<slug>/trust.bundle` (+ `trust.checkpoint.json` companions), where `<slug>` is
271
+ your session artifact dir's basename — NOT the old shared flat `delivery/trust.bundle`.
272
+ This is deliberate: a shared path guaranteed a git merge conflict between ANY two
273
+ concurrent deliveries, and a conflicting PR gets no CI (see the loud callout below). The
274
+ CI reconciler discovers both the flat (back-compat) and per-session layouts and selects
275
+ the NEWEST candidate whose checkpoint attests THIS change by commit ancestry — so an older
276
+ inherited bundle that also happens to be an ancestor of your change is ignored in favour of
277
+ your fresh one, and stale siblings from other sessions are ignored. `publishDelivery()`
278
+ also prunes inherited per-session sibling seal dirs (unique-named, never a cross-PR
279
+ conflict) so `delivery/` stays small; it deliberately does NOT delete the shared flat
280
+ `delivery/trust.bundle` legacy path (a concurrent PR may still seal there, and deleting it
281
+ would cause the DIRTY→no-CI conflict in the callout below).
282
+
283
+ Then force-stage the per-session trust dir for the delivery commit. It is gitignored by
284
+ default (runtime artifacts written on every local delivery) — `-f` commits it
285
+ deliberately into THIS delivery PR so CI's trust-reconcile job can reconcile the
286
+ session's claims against fresh CI results:
287
+
288
+ ```bash
289
+ git add -f delivery/<slug>/
290
+ ```
291
+
292
+ (If `publishDelivery()` pruned a superseded per-session SIBLING dir, stage that deletion
293
+ too — `git add -A delivery/` after the force-add. Do NOT hand-delete the flat
294
+ `delivery/trust.bundle` in a delivery PR while other PRs may still seal to it.)
295
+
296
+ **#293 — verify-hold gate. HARD STOP.** Before committing/pushing/opening a PR/merging,
297
+ run the verify-hold check (it also runs automatically inside `publish-delivery` /
298
+ `record-release` / `advance-state --status delivered`, but run it explicitly here BEFORE
299
+ committing/pushing, since by the time `record-release` runs the branch may already be
300
+ pushed). **The command differs by this repo's configured assignment provider kind — a bare
301
+ `verify-hold <slug>` with no provider flag always defaults to `--assignment-provider
302
+ local-file` (`runVerifyHold`'s documented default), so on a `github`-provider repo it reads
303
+ no local claim record and silently resolves `free`/PASS regardless of the real GitHub hold
304
+ state. The local-file-only invocation below is NOT sufficient for a `github`-provider repo —
305
+ the github branch is MANDATORY for that provider kind:**
306
+
307
+ - **local-file provider** (this repo's configured assignment provider, from
308
+ `effective-assignment-provider-settings`, is `local-file`):
309
+
310
+ ```bash
311
+ npm run workflow:sidecar -- verify-hold .kontourai/flow-agents/<slug>
312
+ ```
313
+
314
+ - **github provider**: render-then-execute, mirroring `pull-work`'s SKILL.md claim-side
315
+ pattern for the same ADR 0021 §1 join — first read the effective state (no live `gh` call
316
+ happens inside `workflow-sidecar.ts`; the skill renders it here), then pass the rendered
317
+ `.effective` JSON into `verify-hold` via `--effective-state-json`:
318
+
319
+ ```bash
320
+ gh issue view <issue-number> --json assignees,labels,comments > /tmp/issue.json
321
+ npm run assignment-provider -- status \
322
+ --provider github \
323
+ --subject-id <slug> \
324
+ --issue-json /tmp/issue.json \
325
+ --liveness-stream <path-to-events.jsonl> \
326
+ --self-actor <actor> \
327
+ > /tmp/assignment-status.json
328
+ npm run workflow:sidecar -- verify-hold .kontourai/flow-agents/<slug> \
329
+ --assignment-provider github \
330
+ --effective-state-json /tmp/assignment-status.json
331
+ ```
332
+
333
+ (`/tmp/assignment-status.json`'s top-level shape is `{ role, provider, assignment,
334
+ effective }`; `verify-hold --effective-state-json` reads the `.effective` field, matching
335
+ `assignment-provider status`'s own output shape directly — no reshaping needed.)
336
+
337
+ This is the ONE point in the whole workflow that BLOCKS instead of warns (ADR 0021 §3). It
338
+ asks exactly one question: is this actor still the fresh, non-superseded holder of this
339
+ subject (or is the subject free/self-held)? **If the check reports not-fresh-holder (exit
340
+ non-zero, `ok:false` in the JSON result): DO NOT commit, push, open a PR, or merge.** This
341
+ is a different failure mode from the `publish-delivery`/reconcile-shape preflight paragraph
342
+ above — that one is about the trust *bundle's shape* being invalid; this one is about
343
+ *actor hold* — another actor holds a fresh claim on this subject, your own claim has gone
344
+ stale, or the subject is assigned to a human. Do not conflate the two "REFUSING to publish"
345
+ messages. When refused, follow the reconcile guidance (the CLI's own `guidance` field, or
346
+ verbatim): re-run `pull-work`/`pickup-probe` to discover the current holder and hand off
347
+ cleanly (`learning-review`/handoff), or, if a human confirms this session should resume
348
+ ownership, run `ensure-session --supersede-stale` before retrying.
349
+
350
+ 3. Commit the verified diff, including the force-added `delivery/<slug>/` trust artifacts.
255
351
  4. Push the branch.
352
+
353
+ > **⚠ LOUD FAILURE MODE — a DIRTY PR gets NO CI, silently (#335/#379).** If `main` moves
354
+ > under your open PR and produces a merge conflict, GitHub marks the PR `DIRTY` and
355
+ > **schedules NO `pull_request` workflows for it** — zero checks, no error, nothing. The
356
+ > required **Trust Reconcile** gate then silently never runs, and the PR sits unbuildable
357
+ > looking like "CI vanished" rather than "conflict." Per-session delivery paths (#379)
358
+ > remove the STRUCTURAL cause for delivery-artifact conflicts (concurrent seals no longer
359
+ > share a file), but ANY other same-file conflict with `main` can still trigger it.
360
+ > **Diagnose it explicitly — do not assume a missing required check means "not run yet":**
361
+ >
362
+ > ```bash
363
+ > gh pr view <pr> --json mergeStateStatus,mergeable,statusCheckRollup
364
+ > ```
365
+ >
366
+ > `mergeStateStatus: DIRTY` (or `CONFLICTING`) with an ABSENT Trust Reconcile check is the
367
+ > signature. Fix by rebasing/merging `main` to clear the conflict and re-pushing — that
368
+ > re-triggers the `pull_request` workflows. A green-looking PR with the required gate simply
369
+ > MISSING is not "pending"; it is this failure mode until proven otherwise.
256
370
  5. Open or update the provider change record with issue links, closing refs, evidence links, and verification summary, or record an explicit no-provider-change reason.
257
371
  6. Wait for provider checks/CI or record missing checks as `NOT_VERIFIED`.
258
372
  7. Record the gate claim for the Builder Kit `pr-open` step immediately after the PR is opened or updated:
@@ -24,6 +24,16 @@ This skill is modeled after Matt Pocock's `grill-me`: interview the user relentl
24
24
  - Stop when shared understanding exists, or when the remaining uncertainty is explicitly recorded as an accepted gap.
25
25
  - Do not silently convert uncertainty into implementation work.
26
26
 
27
+ ## Model Routing
28
+
29
+ When this skill delegates its probing/alignment work, resolve the
30
+ `delegate-design` role from `.datum/config.json`
31
+ (`npx @kontourai/datum resolve delegate-design --json`) and pass the resolved
32
+ model explicitly — probing a goal, design, or recovery path needs design
33
+ latitude, so it routes to the design tier. See
34
+ `context/contracts/execution-contract.md` § Delegation: Model Routing. Fallback:
35
+ inherit the session model when datum/config is absent, noted in the artifact.
36
+
27
37
  ## When To Use
28
38
 
29
39
  Use this skill for:
@@ -13,6 +13,19 @@ Plan artifact in, implemented code out. Fans out to tool-worker subagents in par
13
13
  |---|---|
14
14
  | tool-worker | Implementation per task spec (up to 4 parallel) |
15
15
 
16
+ ## Model Routing
17
+
18
+ Worker slices (`tool-worker`) route by task shape: `delegate-implementation` for
19
+ precisely-planned implementation (the default), `delegate-mechanical` for
20
+ fully-specified mechanical slices (issue sync, doc/scan bookkeeping),
21
+ `delegate-design` when a slice genuinely needs design latitude. Resolve the role
22
+ from `.datum/config.json` (`npx @kontourai/datum resolve <role> --json`) and pass
23
+ the model explicitly. On a review/verify gate failure of a slice, re-dispatch its
24
+ fix one tier higher and record the escalation. See
25
+ `context/contracts/execution-contract.md` § Delegation: Model Routing (and
26
+ § Escalation on gate failure). Fallback: inherit the session model when
27
+ datum/config is absent, noted in the artifact.
28
+
16
29
  ## Orchestrator Rule
17
30
 
18
31
  You do not write source files. You read the plan artifact, fan out tasks to tool-worker, and update the session file between waves.
@@ -20,6 +20,23 @@ Inherited from primitives + diagnosis:
20
20
  | tool-verifier | verify-work |
21
21
  | tool-playwright | diagnosis (reproduce) + verify-work |
22
22
 
23
+ ## Model Routing
24
+
25
+ Delegates are spawned with an explicit model override resolved from
26
+ `.datum/config.json` via `npx @kontourai/datum resolve <role> --json` — see
27
+ `context/contracts/execution-contract.md` § Delegation: Model Routing:
28
+
29
+ | Delegate | Role |
30
+ |---|---|
31
+ | tool-worker | `delegate-mechanical` for fully-specified mechanical slices, `delegate-implementation` for precisely-planned implementation, `delegate-design` when a slice needs design latitude |
32
+ | tool-planner | `delegate-design` |
33
+ | tool-code-reviewer / tool-security-reviewer | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
34
+ | tool-verifier / tool-playwright | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
35
+
36
+ On a review/verify gate failure, re-dispatch the fix one tier higher and record
37
+ the escalation (contract § Escalation on gate failure). Fallback: inherit the
38
+ session model when datum/config is absent, noted in the artifact.
39
+
23
40
  ## Orchestrator Rule
24
41
 
25
42
  You never use `read`, `glob`, `grep`, or `code` on source files. All codebase analysis goes through tool-planner. All review goes through review-work. All verification goes through tool-verifier or tool-playwright.
@@ -21,6 +21,16 @@ Convert raw ideas into shaped, prioritized, executable backlog without starting
21
21
  - Keep separate ideas separate until a shared outcome, hard dependency, or sequencing reason justifies bundling them.
22
22
  - Push back when the user blends unrelated ideas, and ask them to justify why the ideas belong together before shaping bundled work.
23
23
 
24
+ ## Model Routing
25
+
26
+ When this skill delegates its shaping work (opportunity review, option
27
+ exploration, slicing), resolve the `delegate-design` role from
28
+ `.datum/config.json` (`npx @kontourai/datum resolve delegate-design --json`) and
29
+ pass the resolved model explicitly — shaping a raw idea into a backlog needs
30
+ design latitude, so it routes to the design tier. See
31
+ `context/contracts/execution-contract.md` § Delegation: Model Routing. Fallback:
32
+ inherit the session model when datum/config is absent, noted in the artifact.
33
+
24
34
  ## Artifact Contract
25
35
 
26
36
  Create or update `.kontourai/flow-agents/<slug>/<slug>--idea-to-backlog.md` with:
@@ -13,6 +13,15 @@ Goal + directory in, structured plan artifact out. Pure planning primitive.
13
13
  |---|---|
14
14
  | tool-planner | Codebase analysis, structured execution plan, writes plan artifact |
15
15
 
16
+ ## Model Routing
17
+
18
+ Planning delegation (`tool-planner`) resolves the `delegate-design` role from
19
+ `.datum/config.json` (`npx @kontourai/datum resolve delegate-design --json`) and
20
+ passes the resolved model explicitly — turning a goal into a plan needs design
21
+ latitude, so it routes to the design tier. See
22
+ `context/contracts/execution-contract.md` § Delegation: Model Routing. Fallback:
23
+ inherit the session model when datum/config is absent, noted in the artifact.
24
+
16
25
  ## Orchestrator Rule
17
26
 
18
27
  You do not read source files. You delegate to tool-planner and read the artifact it produces.
@@ -26,6 +26,16 @@ Select ready backlog work and prepare a bounded execution handoff without implem
26
26
  - Every pull-work artifact must correlate to selected backlog refs, shepherding refs for active PRs/sidecars/issues being finished before new work, or `backlog_gap=true` with a route to `idea-to-backlog`; direct audits with no new selection must record `shepherding_item_ids` or `backlog_gap`, not free-floating implementation scope.
27
27
  - A stale broad continuation instruction, such as "keep going", "pick up the next two", or "continue after merge", may allow queue inspection but must not bypass per-item pickup Probe evidence.
28
28
 
29
+ ## Model Routing
30
+
31
+ Board selection, WIP/shepherding scans, dependency joins, liveness preflight, and
32
+ issue-sync-style bookkeeping are fully-specified mechanical work: when this skill
33
+ delegates them, resolve the `delegate-mechanical` role from `.datum/config.json`
34
+ (`npx @kontourai/datum resolve delegate-mechanical --json`) and pass the resolved
35
+ model explicitly. See `context/contracts/execution-contract.md` § Delegation:
36
+ Model Routing. Fallback: inherit the session model when datum/config is absent,
37
+ noted in the artifact.
38
+
29
39
  ## Inputs
30
40
 
31
41
  - Repository or working directory.
@@ -157,14 +167,24 @@ Read the returned `.effective.effective_state` and `.effective.reason` and class
157
167
 
158
168
  1. `effective_state: "held"` with `reason: "self_is_holder"` ⇒ `mine`: hand to `### 2. Enforce WIP And Shepherding`'s existing personal-WIP logic; do not re-offer as new, do not exclude as held-by-other.
159
169
  2. else `effective_state: "held"` (`reason: "fresh_liveness_heartbeat"` or `"liveness_claim_present_assignment_lagging"`) ⇒ excluded from the ready set by default.
160
- 3. else `effective_state: "reclaimable"` ⇒ offered, flagged, with a warning; selecting it requires an explicit recorded opt-in (record in `reclaimable_override`, and/or `alignment_questions`), never a silent normal pick. This issue does not implement takeover — offering a `reclaimable` candidate, never auto-reclaiming it, is the correct scope boundary (Design Decision 2; full takeover protocol is ADR 0021 §5 / #294).
170
+ 3. else `effective_state: "reclaimable"` ⇒ offered, flagged, with a warning; selecting it requires an explicit recorded opt-in (record in `reclaimable_override`, and/or `alignment_questions`), never a silent normal pick. On selecting a `reclaimable` candidate, run the **Takeover Protocol** (#294, ADR 0021 §5) below — takeover is resumption, not restart: grace-beat, supersede, then continue the incumbent's branch. Never auto-reclaim without the recorded opt-in.
161
171
  4. else `effective_state: "human-held"` ⇒ surfaced, never auto-reclaimed (Design Decision 3 / ADR 0021 §6): record the assignee identity and idle duration (`effective.holder.assignee`, `effective.holder.idle_days`) in `alignment_questions` with a recommended answer (e.g. "assigned to `<assignee>`, idle `<idle_days>` days — reclaim?" recommending confirmation before proceeding), and select only on the user's explicit confirmation.
162
- 5. else `effective_state: "free"` ⇒ offered normally — except a `superseded` liveness row (no active assignment, no fresh liveness) is surfaced but never auto-selected (full takeover semantics are #294; this is an accepted gap, not silently ignored), exactly as before this join upgrade.
172
+ 5. else `effective_state: "free"` ⇒ offered normally — including a `superseded` liveness row (no active assignment, no fresh liveness): now select-able via the **Takeover Protocol** below once the reclaimable/opt-in gate is satisfied (#294 implements the takeover semantics previously deferred here).
163
173
 
164
174
  An explicit user instruction to proceed despite a `held` or `reclaimable` classification (`--force`, "take it anyway", equivalent) overrides the exclusion/opt-in requirement; the override and its stated reason must be recorded in the artifact (`liveness_preflight`, `reclaimable_override`, and/or `priority_rationale`). A `human-held` classification is never overridden by `--force` alone — only the user's explicit answer to the recorded `alignment_questions` entry authorizes selecting it.
165
175
 
166
176
  This preflight now computes the **full** ADR 0021 §1 `assignment ⋈ liveness` join (previously liveness-only, pending #290): the assignment dimension is `#290`'s `AssignmentProvider` `status()` (`context/contracts/assignment-provider-contract.md`), joined against the same liveness stream this preflight already reads.
167
177
 
178
+ #### Takeover Protocol (#294, ADR 0021 §5) — resumption, not restart
179
+
180
+ When a `reclaimable` (or `superseded`-liveness) candidate is selected WITH the recorded opt-in, take it over by resuming the incumbent's work — never by starting a parallel branch or replanning. This is render-don't-execute: the CLI computes the decision and emits the exact steps; you run them.
181
+
182
+ 1. **Preflight:** `npm run workflow:sidecar -- takeover-preflight .kontourai/flow-agents/<slug>`. It returns `{action, effective_state, holder, resume_branch, grace_seconds, next_steps}`. Only `action: "grace-then-supersede"` proceeds; `back-off` (incumbent live/revived) ⇒ STOP and reselect; `ask-first` (human-held) ⇒ do not proceed without the user's explicit answer.
183
+ 2. **Grace beat:** wait `grace_seconds` (one heartbeat interval), then **re-run `takeover-preflight`**. If it now returns `back-off`, the incumbent revived — concede and reselect (this is the AC2 race guard). Proceed only if it is still `grace-then-supersede`.
184
+ 3. **Supersede:** `npm run workflow:sidecar -- ensure-session … --supersede-stale`. It re-checks the state and REFUSES if the incumbent revived in the meantime (a live `held` is never superseded), records the audit trail ("superseded actor X, last seen T, resuming from trust bundle"), and prints `resumed_branch`.
185
+ 4. **Resume the incumbent's branch — never a new one:** `git fetch origin <resume_branch> && git checkout <resume_branch>` (the `resume_branch` from step 1/3). Re-enter the existing artifact dir (the deterministic slug points at the same `.kontourai/flow-agents/<slug>/`); restore the durable record via the resume surface (#153) and continue from `handoff.json`/plan — do NOT re-plan or restart.
186
+ 5. **Record** the takeover (superseded actor, `resume_branch`, grace outcome) in `reclaimable_override`. If the superseded incumbent later wakes, it is blocked at publish by the verify-hold gate (#293) — the takeover is authoritative.
187
+
168
188
  `liveness claim`/`status`/`whoami` read/write the local runtime liveness stream, never GitHub issue/label/assignee state — this is not a provider mutation, and the two-provider-writes-only invariant in `## Contract` is unchanged by this slice. `#290` adds the one narrow, audited durable assignment claim that pairs with this liveness emit — see "Assignment Claim On Selection" below.
169
189
 
170
190
  ### 2. Enforce WIP And Shepherding
@@ -29,6 +29,17 @@ Keeping them separate makes failures route cleanly:
29
29
  | tool-dependencies-updater | Dependency review when package manifests, dependency manifests, package manager config, or lockfiles change |
30
30
  | configured architecture/domain/IaC/policy reviewer | Optional reviewer when the project or user configures one |
31
31
 
32
+ ## Model Routing
33
+
34
+ Review roles never resolve **below** the tier of the work they check (Goodhart
35
+ guard): default `delegate-implementation`, raised to match or exceed the tier
36
+ that produced the work under review — a reviewer of `delegate-design` work
37
+ resolves `delegate-design` or `orchestrator`, never a cheaper tier. Resolve the
38
+ role from `.datum/config.json` (`npx @kontourai/datum resolve <role> --json`) and
39
+ pass the model explicitly. See `context/contracts/execution-contract.md`
40
+ § Delegation: Model Routing and § Goodhart guard. Fallback: inherit the session
41
+ model when datum/config is absent, noted in the artifact.
42
+
32
43
  ## Shared Contracts
33
44
 
34
45
  Follow:
@@ -25,6 +25,23 @@ Same as deliver (inherited from primitives):
25
25
  | tool-verifier | verify-work (with coverage check) |
26
26
  | tool-playwright | verify-work (if UI) |
27
27
 
28
+ ## Model Routing
29
+
30
+ Delegates are spawned with an explicit model override resolved from
31
+ `.datum/config.json` via `npx @kontourai/datum resolve <role> --json` — see
32
+ `context/contracts/execution-contract.md` § Delegation: Model Routing:
33
+
34
+ | Delegate | Role |
35
+ |---|---|
36
+ | tool-worker | `delegate-mechanical` for fully-specified mechanical slices, `delegate-implementation` for precisely-planned implementation (RED/GREEN/REFACTOR), `delegate-design` when a slice needs design latitude |
37
+ | tool-planner | `delegate-design` |
38
+ | tool-code-reviewer / tool-security-reviewer | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
39
+ | tool-verifier / tool-playwright | `delegate-implementation` by default, raised to the worker's tier when higher — never below the tier of the checked work (Goodhart guard) |
40
+
41
+ On a review/verify gate failure, re-dispatch the fix one tier higher and record
42
+ the escalation (contract § Escalation on gate failure). Fallback: inherit the
43
+ session model when datum/config is absent, noted in the artifact.
44
+
28
45
  ## Orchestrator Rule
29
46
 
30
47
  Same as deliver: you never touch source files. You coordinate the primitives with TDD-specific context.
@@ -16,6 +16,17 @@ Verification is not critique. Run `review-work` first when the task needs mainta
16
16
  | tool-verifier | Code verification, acceptance criteria checking, structured verdicts |
17
17
  | tool-playwright | Visual verification, screenshots, accessibility checks |
18
18
 
19
+ ## Model Routing
20
+
21
+ Verify roles never resolve **below** the tier of the work they check (Goodhart
22
+ guard): default `delegate-implementation`, raised to match or exceed the tier
23
+ that produced the work under verification — a verifier of `delegate-design` work
24
+ resolves `delegate-design` or `orchestrator`, never a cheaper tier. Resolve the
25
+ role from `.datum/config.json` (`npx @kontourai/datum resolve <role> --json`) and
26
+ pass the model explicitly. See `context/contracts/execution-contract.md`
27
+ § Delegation: Model Routing and § Goodhart guard. Fallback: inherit the session
28
+ model when datum/config is absent, noted in the artifact.
29
+
19
30
  ## Orchestrator Rule
20
31
 
21
32
  You do not review source files. You delegate to tool-verifier and tool-playwright, then read the verdict artifact.