dos-kernel 0.22.0__py3-none-win_amd64.whl

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 (178) hide show
  1. dos/__init__.py +261 -0
  2. dos/_bin/dos-hook.exe +0 -0
  3. dos/_filelock.py +255 -0
  4. dos/_job_policy.py +97 -0
  5. dos/_tree.py +145 -0
  6. dos/admission.py +433 -0
  7. dos/answer_shape.py +299 -0
  8. dos/arbiter.py +859 -0
  9. dos/archive_lock.py +266 -0
  10. dos/arg_provenance.py +814 -0
  11. dos/attest.py +472 -0
  12. dos/breaker.py +311 -0
  13. dos/churn.py +226 -0
  14. dos/claim_extract.py +229 -0
  15. dos/claim_ttl.py +150 -0
  16. dos/cli.py +8721 -0
  17. dos/commit_audit.py +666 -0
  18. dos/completion.py +466 -0
  19. dos/concurrency_class.py +154 -0
  20. dos/config.py +1380 -0
  21. dos/config_lint.py +464 -0
  22. dos/cooldown.py +390 -0
  23. dos/coverage.py +387 -0
  24. dos/dangling_intent.py +287 -0
  25. dos/data_class.py +397 -0
  26. dos/decisions.py +1274 -0
  27. dos/decisions_tui.py +251 -0
  28. dos/dispatch_top.py +740 -0
  29. dos/dispatch_top_tui.py +116 -0
  30. dos/drivers/__init__.py +40 -0
  31. dos/drivers/ci_status.py +630 -0
  32. dos/drivers/citation_resolve.py +703 -0
  33. dos/drivers/decision_stop.py +98 -0
  34. dos/drivers/export_file.py +173 -0
  35. dos/drivers/export_otlp.py +275 -0
  36. dos/drivers/export_statsd.py +242 -0
  37. dos/drivers/hook_dialects.py +391 -0
  38. dos/drivers/job.py +47 -0
  39. dos/drivers/llm_judge.py +360 -0
  40. dos/drivers/memory_recall.py +1231 -0
  41. dos/drivers/notify_slack.py +373 -0
  42. dos/drivers/notify_webhook.py +251 -0
  43. dos/drivers/operator_judge.py +114 -0
  44. dos/drivers/os_acceptance.py +228 -0
  45. dos/drivers/paste_log.py +132 -0
  46. dos/drivers/plan_scope.py +133 -0
  47. dos/drivers/self_improve.py +375 -0
  48. dos/drivers/similarity_judge.py +249 -0
  49. dos/drivers/state_diff.py +274 -0
  50. dos/drivers/supervisor.py +347 -0
  51. dos/drivers/watchdog.py +363 -0
  52. dos/drivers/workshop.py +160 -0
  53. dos/durable_schema.py +344 -0
  54. dos/effect_witness.py +393 -0
  55. dos/efficiency.py +318 -0
  56. dos/enforce.py +414 -0
  57. dos/enumerate.py +776 -0
  58. dos/env_print.py +378 -0
  59. dos/event_severity.py +258 -0
  60. dos/evidence.py +692 -0
  61. dos/exec_capability.py +256 -0
  62. dos/export_cursor.py +143 -0
  63. dos/exporter.py +320 -0
  64. dos/firing_label.py +353 -0
  65. dos/fleet_roll.py +226 -0
  66. dos/gate_classify.py +827 -0
  67. dos/gh4_coverage.py +179 -0
  68. dos/git_delta.py +122 -0
  69. dos/guard.py +215 -0
  70. dos/health.py +552 -0
  71. dos/help_summary.py +519 -0
  72. dos/home.py +934 -0
  73. dos/hook_binary.py +194 -0
  74. dos/hook_dialect.py +271 -0
  75. dos/hook_exit.py +191 -0
  76. dos/hook_install.py +437 -0
  77. dos/id_alloc.py +304 -0
  78. dos/improve.py +499 -0
  79. dos/intent_ledger.py +635 -0
  80. dos/interpret.py +176 -0
  81. dos/intervention.py +769 -0
  82. dos/intervention_eval.py +371 -0
  83. dos/journal_delta.py +308 -0
  84. dos/judge_eval.py +328 -0
  85. dos/judges.py +366 -0
  86. dos/lane_infer.py +127 -0
  87. dos/lane_journal.py +1001 -0
  88. dos/lane_lease.py +952 -0
  89. dos/lane_overlap.py +228 -0
  90. dos/lease_health.py +282 -0
  91. dos/lifecycle.py +211 -0
  92. dos/liveness.py +352 -0
  93. dos/lock_modes.py +185 -0
  94. dos/log_source.py +395 -0
  95. dos/loop_decide.py +1746 -0
  96. dos/marker_gate.py +254 -0
  97. dos/marker_sensor.py +396 -0
  98. dos/noop_streak.py +280 -0
  99. dos/notify.py +479 -0
  100. dos/observe.py +175 -0
  101. dos/oracle.py +1661 -0
  102. dos/overlap_eval.py +214 -0
  103. dos/overlap_policy.py +342 -0
  104. dos/packet_sidecar.py +267 -0
  105. dos/phase_shipped.py +1985 -0
  106. dos/pick_priority.py +225 -0
  107. dos/pickable.py +369 -0
  108. dos/picker_oracle.py +1037 -0
  109. dos/plan_board.py +513 -0
  110. dos/plan_board_tui.py +113 -0
  111. dos/plan_source.py +455 -0
  112. dos/posttool_sensor.py +528 -0
  113. dos/precursor_gate.py +499 -0
  114. dos/precursor_gate_eval.py +239 -0
  115. dos/preflight.py +825 -0
  116. dos/pretool_sensor.py +490 -0
  117. dos/proc_delta.py +181 -0
  118. dos/productivity.py +296 -0
  119. dos/provider_limit.py +242 -0
  120. dos/py.typed +4 -0
  121. dos/reason_morphology.py +299 -0
  122. dos/reasons.py +449 -0
  123. dos/reconcile.py +173 -0
  124. dos/recurring_wedge.py +206 -0
  125. dos/render.py +393 -0
  126. dos/result_state.py +468 -0
  127. dos/resume.py +578 -0
  128. dos/resume_evidence.py +293 -0
  129. dos/retention.py +344 -0
  130. dos/reward.py +372 -0
  131. dos/rewind.py +587 -0
  132. dos/rewind_evidence.py +168 -0
  133. dos/rewind_tokens.py +252 -0
  134. dos/run_id.py +342 -0
  135. dos/scope.py +520 -0
  136. dos/scope_source.py +382 -0
  137. dos/scout.py +982 -0
  138. dos/self_modify.py +209 -0
  139. dos/sibling_scan.py +569 -0
  140. dos/skills/EXAMPLES.md +584 -0
  141. dos/skills/dos-class-cycle/SKILL.md +107 -0
  142. dos/skills/dos-dispatch/SKILL.md +177 -0
  143. dos/skills/dos-dispatch-loop/SKILL.md +254 -0
  144. dos/skills/dos-goal-gate/SKILL.md +269 -0
  145. dos/skills/dos-next-up/SKILL.md +231 -0
  146. dos/skills/dos-promote/SKILL.md +114 -0
  147. dos/skills/dos-replan/SKILL.md +159 -0
  148. dos/skills/dos-replan-loop/SKILL.md +114 -0
  149. dos/skills/dos-self-improve/SKILL.md +213 -0
  150. dos/skills/dos-supervise-loop/SKILL.md +180 -0
  151. dos/skills/dos-unstick/SKILL.md +108 -0
  152. dos/skills/dos-witness-claim/SKILL.md +251 -0
  153. dos/stamp.py +1002 -0
  154. dos/state_health.py +387 -0
  155. dos/status.py +114 -0
  156. dos/stop_policy.py +334 -0
  157. dos/supervise.py +1014 -0
  158. dos/testwitness.py +392 -0
  159. dos/timeline.py +1027 -0
  160. dos/tokens.py +485 -0
  161. dos/tool_stream.py +393 -0
  162. dos/tool_stream_eval.py +226 -0
  163. dos/trace.py +524 -0
  164. dos/verdict.py +140 -0
  165. dos/verdict_cli.py +189 -0
  166. dos/verdict_journal.py +497 -0
  167. dos/verdict_rollup.py +217 -0
  168. dos/verdicts.py +181 -0
  169. dos/wedge_reason.py +282 -0
  170. dos_kernel-0.22.0.dist-info/METADATA +859 -0
  171. dos_kernel-0.22.0.dist-info/RECORD +178 -0
  172. dos_kernel-0.22.0.dist-info/WHEEL +5 -0
  173. dos_kernel-0.22.0.dist-info/entry_points.txt +39 -0
  174. dos_kernel-0.22.0.dist-info/licenses/LICENSE +21 -0
  175. dos_kernel-0.22.0.dist-info/top_level.txt +2 -0
  176. dos_mcp/__init__.py +52 -0
  177. dos_mcp/py.typed +2 -0
  178. dos_mcp/server.py +779 -0
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: dos-class-cycle
3
+ description: One automatic plan-class lifecycle tick. Reads the DECLARED class set + transition list from the workspace `[lifecycle]` table (not a hardcoded taxonomy), evaluates each trigger, spawns a read-only JUDGE-rung adjudicator (the `dos.judges` seam — advisory, fail-to-abstain) to approve/defer each candidate transition, applies the gated transitions as plan-meta edits + one commit per cycle, and logs to the run archive. Failsafes (per-cycle cap, per-plan cooldown, a veto class) are `[lifecycle]` data; the judge content is a host `dos.judges` driver. Every path/class comes from `dos doctor --json`. Use to garden a plan portfolio's lifecycle automatically, judge-gated. The DOS lifecycle gardener (SKP Axis 5, docs/207 Phase 5c).
4
+ ---
5
+
6
+ # dos-class-cycle — the judge-gated plan-lifecycle tick
7
+
8
+ > **Garden the portfolio, but never alone.** A plan's class (active / done /
9
+ > parked / …) should track reality — a done plan should not sit "active," a
10
+ > long-idle one should park. `/dos-class-cycle` runs ONE tick of that gardening:
11
+ > it evaluates the declared triggers, asks a **JUDGE-rung adjudicator** (advisory,
12
+ > fail-to-abstain) to approve each candidate transition, applies only the gated
13
+ > ones, and logs the cycle. The class set, the legal transitions, and the
14
+ > failsafes are **declared data** (`[lifecycle]`) — a 2-class repo and a richly-
15
+ > classed one run the identical mechanism.
16
+
17
+ The shape: **read the declared lifecycle → evaluate triggers → build candidates
18
+ (deterministic order) → judge each → enact gated transitions → log.** The cycle
19
+ is domain-free mechanism; the taxonomy is `[lifecycle]` policy; the judge content
20
+ is a host `dos.judges` driver.
21
+
22
+ ## Inputs
23
+
24
+ - `--dry-run` (optional) — evaluate + judge but enact nothing (a preview cycle).
25
+
26
+ ## Step 0 — Read the declared lifecycle + the layout
27
+
28
+ ```bash
29
+ dos doctor --workspace . --json
30
+ ```
31
+
32
+ Read `lifecycle` — the declared `classes`, `transitions` (each `{from, to,
33
+ trigger, auto}`), `veto_class`, `max_transitions_per_cycle`, and
34
+ `per_plan_cooldown_hours` — and `paths` (the plan + run dirs). **Use these; never
35
+ hardcode a class name, a trigger, or a cap.** A repo that declared only
36
+ `active`/`done` cycles with those two; a repo with a richer taxonomy declares more.
37
+
38
+ ## Step 1 — Evaluate each declared trigger → candidate transitions
39
+
40
+ For each declared `transition`, evaluate its `trigger` against the portfolio (the
41
+ plan-meta classes, the run-archive history, git). A trigger that fires on a plan
42
+ proposes that plan for that `from→to` transition. Build the candidate list in a
43
+ DETERMINISTIC order (plan id ascending) so a replay is byte-stable.
44
+
45
+ Skip a plan that is:
46
+ - in the `veto_class` (never auto-transitioned — a human moves it by hand), or
47
+ - transitioned within `per_plan_cooldown_hours` (the per-plan cooldown), or
48
+ - already past `max_transitions_per_cycle` candidates this tick (the cap).
49
+
50
+ The trigger evaluator is the host's (an opaque trigger token like
51
+ `all_phases_shipped` / `idle_30d` — the kernel never interprets it). A natural
52
+ ground-truth trigger: a plan whose `dos enumerate` residual is empty AND every
53
+ unit `dos verify`s SHIPPED is a real `all_phases_shipped` → done candidate.
54
+
55
+ ## Step 2 — Judge each candidate (the JUDGE rung, advisory)
56
+
57
+ A class transition is a judgment call, so it goes to the **JUDGE rung** — a
58
+ non-deterministic adjudicator that rules on the residue the deterministic checks
59
+ left. Resolve the active judge by name and ask it to approve / defer each
60
+ candidate:
61
+
62
+ ```bash
63
+ dos judge-eval --judge <name> # the judge seam; built-in `abstain`, shipped `llm`, or a dos.judges plugin
64
+ ```
65
+
66
+ The judge is hedged by the four disciplines (deterministic-first, advisory-only,
67
+ **fail-to-abstain** — a raise/bad-return becomes ABSTAIN, never APPROVE —
68
+ abstention-first). The judge *content* (the prompt) is a host `dos.judges` driver;
69
+ this skill spawns it via the seam and reads its verdict. An ABSTAIN defers the
70
+ transition to a human (the safe direction — the kernel never auto-applies on an
71
+ abstention).
72
+
73
+ ## Step 3 — Enact the gated transitions (auto only where declared)
74
+
75
+ For each candidate the judge APPROVED **and** whose declared transition has
76
+ `auto = true`, enact it: rewrite the plan-meta `classification:` to the `to`
77
+ class, ONE commit per cycle. Read the trunk + ship grammar from `dos doctor
78
+ --json`'s `stamp`; **do not hardcode a commit prefix.** A transition with
79
+ `auto = false`, or one the judge deferred/abstained on, is surfaced for a human —
80
+ never enacted.
81
+
82
+ ## Step 4 — Log the cycle (even a 0-transition tick)
83
+
84
+ Write a cycle record under `paths.runs`: the candidates, the judge verdicts, the
85
+ applied transitions, and the failsafe state (cap/cooldown/veto). A heartbeat row
86
+ every cycle — even one that applied nothing — so the gardener's history is
87
+ auditable.
88
+
89
+ ## What this skill deliberately does NOT do (no silent gap)
90
+
91
+ - **No host class taxonomy.** Classes/transitions/failsafes are `[lifecycle]`
92
+ data; this skill carries none. A transition naming an unknown class is a config
93
+ error the kernel raises at load, not a silent skip.
94
+ - **No judge content.** The adjudicator prompt is a host `dos.judges` driver; the
95
+ skill resolves + spawns it, fail-to-abstain. Forcing the prompt generic would
96
+ re-couple the kernel.
97
+ - **No transition past a failsafe.** The per-cycle cap, the per-plan cooldown, and
98
+ the veto class are hard gates; the cycle never exceeds them.
99
+
100
+ ## Anti-patterns
101
+
102
+ - ❌ Applying a transition the judge ABSTAINED on — abstention defers to a human;
103
+ the kernel never auto-applies on an abstention (the fail-to-abstain floor).
104
+ - ❌ Hardcoding `ACTIVE`/`PARK`/`TOMB` or a trigger like `idle_14d` — read the
105
+ declared set from `dos doctor --json`'s `lifecycle`.
106
+ - ❌ Exceeding `max_transitions_per_cycle` in one tick — a runaway judge must not
107
+ churn the whole portfolio; the cap is the backstop.
@@ -0,0 +1,177 @@
1
+ ---
2
+ name: dos-dispatch
3
+ description: End-to-end plan-and-ship for one lane — snapshot the portfolio with /dos-next-up, take a lane lease via `dos arbitrate` so parallel dispatches don't collide, gate the empty case via `dos gate`, ship the packet, and archive the run under the configured run dir. Driven entirely by `dos` verbs + the workspace's `dos.toml`; names no host path, lane, or commit convention. Use when you want to plan and ship the next batch on one lane in a single command, with concurrency safety. The DOS reference dispatch workflow (SKP Axis 5).
4
+ ---
5
+
6
+ # dos-dispatch — the generic chained snapshot→ship cycle
7
+
8
+ > **The concurrency-safe dispatch.** It chains `/dos-next-up` (the packet) to a
9
+ > ship, but first takes a **lane lease** through the admission kernel so several
10
+ > dispatches on disjoint lanes run in parallel without editing the same files.
11
+ > The "may I run on this lane" decision is the kernel's (`dos arbitrate`), not
12
+ > inline prose. Every path/lane comes from `dos doctor --json`; nothing is
13
+ > hardcoded.
14
+
15
+ The shape: **discover → take a lane → snapshot → gate → ship → archive.** The
16
+ lane taxonomy and the run-dir location are data (`[lanes]`, `[paths]`); the
17
+ admission and the gate verdict are kernel syscalls.
18
+
19
+ ## Inputs
20
+
21
+ - `--lane <name>` (optional) — the lane to dispatch on (a name from the active
22
+ `[lanes]`). Omitted = a bare auto-pick: the arbiter picks a free lane from the
23
+ `autopick` ladder.
24
+ - `--leases <json>` (optional) — the live leases other dispatches hold, as a JSON
25
+ list of `{lane, lane_kind, tree}` (the arbiter keys exclusivity on `lane_kind`,
26
+ so include it — `cluster`/`keyword`/`global`). In a real loop these come from a
27
+ status query; for a single dispatch this is usually `[]`.
28
+
29
+ ## Step 0 — Discover the layout + the lane taxonomy
30
+
31
+ ```bash
32
+ dos doctor --workspace . --json
33
+ ```
34
+
35
+ Read `lanes` (the taxonomy), `paths.next_packets` (packet output), and
36
+ `paths.runs` (the run dir to archive under). **Use these; never hardcode a lane
37
+ name or a run path.**
38
+
39
+ ## Step 1 — Take a lane lease (the admission kernel)
40
+
41
+ Ask the kernel whether this dispatch may run on the requested lane, given the
42
+ live leases. The arbiter runs the tree-disjointness algebra over the lanes'
43
+ declared trees — two dispatches on disjoint trees both ADMIT; overlapping trees
44
+ COLLIDE.
45
+
46
+ ```bash
47
+ dos arbitrate --workspace . --lane <LANE> --kind cluster --leases '<LIVE_LEASES>'
48
+ ```
49
+
50
+ Read the `LaneDecision` JSON: `{outcome, lane, tree, reason, free_clusters, …}`.
51
+
52
+ - `outcome: "acquire"` → admitted. `lane` is the lane to run on (may differ from
53
+ the request when auto-pick reassigned it); `tree` is its file tree. Proceed.
54
+ - `outcome: "refuse"` → not admitted. `reason` explains why; `free_clusters`
55
+ lists lanes you could pick instead. **Stop** (or retry on a free lane). Do not
56
+ force — `--force` is an operator-only override, not an automation default.
57
+
58
+ The exit code mirrors the outcome (0 = acquire, 1 = refuse), so the screenplay
59
+ can branch on it directly.
60
+
61
+ ## Step 2 — Snapshot the portfolio (the packet)
62
+
63
+ Run `/dos-next-up` scoped to the acquired lane:
64
+
65
+ ```
66
+ /dos-next-up --scope <LANE>
67
+ ```
68
+
69
+ It writes a packet under `paths.next_packets` and returns its path + a gate
70
+ verdict. Capture the packet path and its `.dispositions-<tag>.json` sidecar.
71
+
72
+ ## Step 3 — Gate the empty case (typed verdict)
73
+
74
+ Before shipping, classify the packet so an empty packet doesn't launch a no-op
75
+ ship:
76
+
77
+ ```bash
78
+ dos gate --workspace . <paths.next_packets>/.dispositions-<tag>.json
79
+ ```
80
+
81
+ Branch on the exit code (the verdict IS the code):
82
+
83
+ - `0` **LIVE** → there is dispatchable work; proceed to Step 4 (ship).
84
+ - `3` **DRAIN** → empty backlog; **skip the ship**, archive a no-op, report drained.
85
+ - `4` **STALE-STAMP** → shipped-but-unstamped drift; skip the ship, surface the
86
+ drift for reconciliation (a `/dos-replan` can stamp it).
87
+ - `5` **BLOCKED** → picks blocked; skip, surface.
88
+ - `6` **RACE** → lost a render race; retry the snapshot once.
89
+
90
+ ## Step 4 — Ship the packet (LIVE only)
91
+
92
+ Launch the packet's dispatch list (the per-pick prompts `/dos-next-up` rendered).
93
+ How you ship is host-shaped — the generic baseline launches each pick's prompt as
94
+ its own agent. Record what shipped.
95
+
96
+ ## Step 5 — Archive the run
97
+
98
+ Write a run record under `paths.runs` (the run dir from `dos doctor --json`): the
99
+ lane, the packet path, the gate verdict, and what shipped. Commit it with a
100
+ generic subject — **read your trunk and ship-grammar from config; do not hardcode
101
+ a commit prefix.** (`dos doctor --json`'s `stamp` names the active grammar.)
102
+
103
+ ## Step 6 — Release the lane lease
104
+
105
+ If you took a cross-process `dos lease` for the archive, release it:
106
+
107
+ ```bash
108
+ dos lease --workspace . release <owner>
109
+ ```
110
+
111
+ The lane lease itself is advisory state in `live_leases`; a real loop
112
+ (`/dos-dispatch-loop`) threads it forward. A single dispatch simply finishes.
113
+
114
+ ## What this skill deliberately does NOT do (no silent gap)
115
+
116
+ - **No per-pick soft-claim leasing.** It takes a *lane* lease (`dos arbitrate`),
117
+ not the heavy per-pick soft-claim core (`CLAUDE.md` heavy tier). Two loops on
118
+ the same lane serialize on the lane, not on individual picks.
119
+ - **No rate-limit resume / focus scheduler.** Those are the host's heavy tier; a
120
+ generic dispatch ships once and archives. `/dos-dispatch-loop` adds the cadence.
121
+ - **No host packet template / commit subject.** It reads the ship grammar from
122
+ `[stamp]` and assembles a generic archive record.
123
+
124
+ **Log the gap, never silently skip it.** The first time the skill would have
125
+ reached for one of these (a per-pick soft-claim, a focus-scheduler pick, a
126
+ rate-limit resume), emit a one-line `log` naming what it is not doing — so the
127
+ capability gap is surfaced at runtime, matching `/dos-dispatch-loop`.
128
+
129
+ ## Worked example (live transcript)
130
+
131
+ > **The shape, run for real.** `doctor → arbitrate → gate → ship → verify`,
132
+ > with the actual `LaneDecision` JSON and the exit codes that branch it. Captured
133
+ > against a live DOS workspace (`dos 0.22.0`); copy-paste, then read the RUNG.
134
+
135
+ ```bash
136
+ $ dos doctor --workspace . --json
137
+ { ... "lanes": {"concurrent": ["benchmark","docs","examples","scripts","spikes","src","tests"],
138
+ "exclusive": ["global"], "autopick": ["benchmark","docs",...,"tests"]},
139
+ "paths": {"plans_glob":"docs/**/*-plan.md","next_packets":".dos/verdicts","runs":".dos/runs"},
140
+ "stamp": {"style":"grep"}, "overlap_policy": {"active":"prefix"} }
141
+ ```
142
+ The WCR on-ramp — lanes/paths/stamp are DATA. Nothing below is hardcoded.
143
+
144
+ ```bash
145
+ $ dos arbitrate --workspace . --lane src
146
+ {"auto_picked":true,"free_clusters":[],"lane":"benchmark","lane_kind":"cluster","outcome":"acquire","pick_count":null,"reason":"auto-picked free cluster lane benchmark (requested src was busy).","tree":["benchmark/**"]}
147
+ ```
148
+ exit 0 (**acquire**) — but you asked for `src` and got `benchmark`: a live lease made
149
+ `src` contended, so the admission kernel redirected rather than double-book. Run on
150
+ `lane` (= `benchmark`), not your request. exit 1 (**refuse**) would mean stop / pick from `free_clusters`.
151
+
152
+ ```bash
153
+ $ dos gate --workspace . .dos/verdicts/.dispositions-benchmark.json
154
+ ```
155
+ The verdict IS the code: `0` LIVE → ship; `3` DRAIN → skip + archive no-op; `4`
156
+ STALE-STAMP / `5` BLOCKED → skip + surface; `6` RACE → retry the snapshot once.
157
+
158
+ ```bash
159
+ $ dos verify --workspace . docs/82_liveness-oracle-plan liveness --json
160
+ {"phase":"liveness","plan":"docs/82_liveness-oracle-plan","rung":"direct","sha":"80d4f30","shipped":true,"source":"grep-subject","summary":"80d4f30 liveness: exclude the BIRTH acquire from the ADVANCING event count"}
161
+ ```
162
+ exit 0 SHIPPED — but `source` is **`grep-subject`**, not `registry`: a commit *subject*
163
+ carrying the phase token flips this true even if little was built. Read the rung.
164
+
165
+ ```bash
166
+ $ dos verify --workspace . docs/99_runtime-validation-and-the-actuation-boundary halt --json
167
+ {"phase":"halt","plan":"docs/99_runtime-validation-and-the-actuation-boundary","shipped":false,"source":"none"}
168
+ ```
169
+ exit 1 NOT_SHIPPED `(source=none)` — git ancestry never stamped it. The oracle closes
170
+ the phase from git, never from "I'm done." Then `/release` cuts the version.
171
+
172
+ ## Anti-patterns
173
+
174
+ - ❌ Launching a ship on a 0-pick packet — gate first; DRAIN/STALE-STAMP skip.
175
+ - ❌ `--force`-ing past a refuse in automation — a refuse means a real collision;
176
+ pick a free lane from `free_clusters` or stop.
177
+ - ❌ Hardcoding a run dir or a commit prefix — read them from `dos doctor --json`.
@@ -0,0 +1,254 @@
1
+ ---
2
+ name: dos-dispatch-loop
3
+ description: Run /dos-dispatch on a recurring cadence, alternating with /dos-replan when the backlog drains — the dispatch→replan→dispatch cycle. The continue/stop/next-mode decision is the kernel's typed loop decision, not inline prose: each iteration is classified (`dos gate`) into a verdict and the loop's counters (drained-twice, the unclear/dirty-zero breakers, the iteration cap) drive the next step. Several loops on disjoint lanes run concurrently, each taking its own lane lease via `dos arbitrate`. Driven entirely by `dos` verbs + the workspace's `dos.toml`. The DOS reference loop workflow (SKP Axis 5).
4
+ ---
5
+
6
+ # dos-dispatch-loop — the generic dispatch⇄replan cadence
7
+
8
+ > **The unattended plan-and-ship loop.** It runs `/dos-dispatch` repeatedly and
9
+ > falls to `/dos-replan` when a lane drains, stopping on a typed, kernel-decided
10
+ > condition (not a prose guess). The stop/continue logic is the kernel's
11
+ > `loop_decide.decide` — the loop carries counters, the kernel decides. Several
12
+ > loops on disjoint lanes run in parallel, each holding its own lane lease.
13
+
14
+ The stop conditions are the kernel's, in one place:
15
+
16
+ 1. **iteration cap** — reached `max_iterations` (default 10).
17
+ 2. **drained-twice** — a DRAIN after a *productive* `/dos-replan` that itself
18
+ followed a DRAIN (the lane is genuinely exhausted).
19
+ 3. **consecutive-unclear** — the dispatch subprocess is failing systematically.
20
+ 4. **rate-limited** — a usage window is exhausted (don't burn launches).
21
+ 5. **launch-failed** — a subprocess never started.
22
+ 6. **pick-held-invariant** — the next unit is held ONLY by a reason a re-dispatch
23
+ cannot change (draft-class / operator-gated / soak-open / dependency-unmet);
24
+ re-dispatching it would re-block identically, so honest-STOP + surface the hold.
25
+ 7. **pick-cooldown** — the next unit was attempted-and-didn't-move inside its
26
+ cooldown window AND nothing fresher is offerable; re-dispatching it would
27
+ re-storm a known drain (the ~5%-shipping re-pick loop the bare loop hit).
28
+
29
+ The last two are the docs/207 anti-churn rungs: the loop stops re-picking work it
30
+ cannot move, instead of burning the cap re-confirming a known hold.
31
+
32
+ ## Inputs
33
+
34
+ - `--lane <name>` (optional) — focus the whole loop on one lane (fixed for the
35
+ run; a bare loop auto-picks a free lane at Step 0).
36
+ - `--gate hard|soft|drive` (default `hard`) — the verdict policy. `hard` routes a
37
+ non-LIVE verdict through `/dos-replan`; `soft`/`drive` stop on a true DRAIN;
38
+ `drive` self-heals a STALE-STAMP inline.
39
+ - `--max-iterations <N>` (default 10).
40
+
41
+ ## Step 0 — Pre-flight: take the lane, read the taxonomy
42
+
43
+ ```bash
44
+ dos doctor --workspace . --json
45
+ dos arbitrate --workspace . --lane <LANE> --kind cluster --leases '<SIBLING_LEASES>'
46
+ ```
47
+
48
+ The arbiter ADMITs a free lane (or auto-picks one); a REFUSE means a sibling loop
49
+ already holds an overlapping lane — pick a free one from `free_clusters` or exit.
50
+ Initialise the loop counters (iteration=1, the breakers at 0).
51
+
52
+ ## Step 1 — Pick-selection: skip held + cooled units (the anti-churn gate)
53
+
54
+ Before a `dispatch` iteration offers a unit, screen the candidate unit set so the
55
+ loop never re-storms work it cannot move (the docs/207 §6 throughline). For each
56
+ candidate, in order:
57
+
58
+ ```bash
59
+ dos pickable <UNIT> --state '<host-gathered state>' # OFFERABLE=0; HELD=per-reason code
60
+ dos cooldown <UNIT> # CLEAR=0; RECENTLY_ATTEMPTED=3
61
+ ```
62
+
63
+ - A `pickable` exit of **0** (OFFERABLE) **and** a `cooldown` exit of **0** (CLEAR)
64
+ → this unit is dispatchable; offer it and proceed to the iteration.
65
+ - A `pickable` HELD by a re-dispatch-CURABLE reason (IN_FLIGHT / SOFT_CLAIMED /
66
+ STALE_CLAIM / UNPARSEABLE) or a `cooldown` of **3** (RECENTLY_ATTEMPTED) → **skip
67
+ this unit, try the next candidate** (the skip-to-next is pick-selection's job).
68
+ - A `pickable` HELD by a re-dispatch-INVARIANT reason (DRAFT_CLASS=10 /
69
+ OPERATOR_GATED=11 / SOAK_OPEN=12 / DEPENDENCY_UNMET=13) → carry that verdict into
70
+ Step 2; the kernel will honest-STOP on it (don't re-dispatch a unit a re-dispatch
71
+ cannot un-gate).
72
+
73
+ When EVERY remaining candidate is skipped (all cooled / curably-held), carry the
74
+ last `cooldown` RECENTLY_ATTEMPTED (or the invariant `pickable` hold) into Step 2
75
+ as the loop's pre-dispatch evidence — the kernel turns "nothing fresh is offerable"
76
+ into the `pick-cooldown` / `pick-held-invariant` honest-STOP. **Do not re-dispatch
77
+ the cooled/held unit yourself** — that is the re-pick storm this gate prevents.
78
+
79
+ ## Step 1b — Run one iteration
80
+
81
+ For a `dispatch` iteration, invoke `/dos-dispatch --lane <LANE>` (it snapshots,
82
+ gates, and ships). For a `replan` iteration, invoke `/dos-replan`. Capture the
83
+ iteration's outcome:
84
+
85
+ - a **dispatch** iteration that reached the gate carries a typed verdict — get it
86
+ from `dos gate` over the packet's dispositions sidecar (LIVE/DRAIN/STALE-STAMP/
87
+ BLOCKED/RACE).
88
+ - a **replan** iteration carries a productivity signal (did it refill/garden?).
89
+
90
+ ## Step 2 — Decide continue / replan / stop (the kernel decides)
91
+
92
+ This is the load-bearing step: **the decision is a kernel mechanism, not prose.**
93
+ Feed the iteration outcome + the carried counters to the loop decider. In code a
94
+ host calls `dos.loop_decide.decide(state, outcome)`; the screenplay's job is to
95
+ construct the typed `IterationOutcome` and read the returned `LoopDecision`:
96
+
97
+ - `action: "continue"` → run the next iteration in `next_mode` (`dispatch` or
98
+ `replan`); if `reconcile` is set (a soft/drive STALE-STAMP), run an inline
99
+ stamp-reconcile pass first. Carry `next_state` forward (the updated counters).
100
+ - `action: "stop"` → the loop ends; report `stop_reason` (one of the five above)
101
+ and `surface` (whether it needs operator attention).
102
+ - `action: "retry-same-iter"` → a transient overload; sleep `backoff_seconds`
103
+ and re-run the SAME iteration.
104
+
105
+ The drained-twice rule is the kernel's: a DRAIN counts toward an early stop ONLY
106
+ after a *productive* `/dos-replan`. A STALE-STAMP or BLOCKED gate routes to
107
+ `/dos-replan` (under `hard`) but never arms a false drained-twice stop — that is
108
+ the structural fix the typed gate exists for.
109
+
110
+ The pre-dispatch evidence from Step 1 rides into the decision too: the kernel reads
111
+ the carried `Pickability` (→ `pick-held-invariant` stop) and `Cooldown` (→
112
+ `pick-cooldown` stop). So the loop's continue/stop is driven END-TO-END by kernel
113
+ rungs — the honest-STOP that used to be a per-run human override is now a kernel
114
+ rule, not prose the loop re-applies each iteration.
115
+
116
+ ## Step 3 — Reconcile each claimed pick (the cross-run KEEP)
117
+
118
+ A `dispatch` iteration that SHIPPED claims picks done — but a claim is a
119
+ self-report. Before the archive drops a claimed pick from the residual, reconcile
120
+ its claim against ground truth so a quietly-incomplete pick re-enters the pickable
121
+ set next iteration, flagged:
122
+
123
+ ```bash
124
+ dos reconcile <UNIT> --claimed-done --plan <PLAN> --phase <PHASE> # oracle from git
125
+ ```
126
+
127
+ Branch on the exit code (the verdict IS the code):
128
+
129
+ - `0` **VERIFIED** → the oracle confirms it shipped; it leaves the residual.
130
+ - `3` **QUIET_INCOMPLETE** → CLAIMED done but the oracle says NOT_SHIPPED — KEEP it
131
+ in the residual, flagged; it re-enters the pickable set next iteration so the
132
+ host routes it (a verifier pass / `/dos-replan` / a finding). **Do NOT believe
133
+ the claim** — only ground truth removes work (the FQ-336 touch-counts-as-ship
134
+ false-DRAIN is exactly what this catches).
135
+ - `4` **HONEST_OPEN** → not claimed, not shipped; honest open work, stays in the
136
+ residual.
137
+
138
+ This is the cross-run KEEP wired at the boundary that runs the write (the
139
+ `CLAUDE.md` "wire the contract into the step that runs the write" rule).
140
+
141
+ ## Step 4 — Archive + release (and leave the lane's tree clean)
142
+
143
+ When the loop stops, write a loop record under `paths.runs` (the run dir from
144
+ `dos doctor --json`: the per-iteration verdicts, the reconcile flags, the stop
145
+ reason) and release the lane lease. Commit with a generic subject read from config
146
+ — no hardcoded prefix.
147
+
148
+ **Leave the tree clean for the lane you held — an unattended loop must not strand
149
+ its own writes.** A loop that ships work but leaves it uncommitted is the bug the
150
+ oracle catches next session: `dos verify` answers from git ancestry, so an
151
+ uncommitted change is a phase the kernel reports `NOT_SHIPPED` (the "a commit IS the
152
+ ship-stamp" contract). So at close-out, commit your lane's writes — driven by the
153
+ same `dos` verbs the loop already uses, with generic git:
154
+
155
+ - **Commit your lane's writes by explicit pathspec** — stage exactly the files
156
+ under the lane region you leased (the `tree` globs `dos arbitrate` handed back),
157
+ then commit naming those paths: `git add <lane paths>`; `git commit -m "<subject>"
158
+ -- <lane paths>`. **Never a bare `git add -A`** — when sibling loops hold disjoint
159
+ lanes on the same tree, a blanket add sweeps another loop's in-flight edits into
160
+ your commit. The lane lease you held names exactly which paths are yours; commit
161
+ only those.
162
+ - **Confirm the tree is clean for your lane before you exit.** `git status
163
+ --porcelain -- <lane paths>` over the region you leased should come back empty once
164
+ you have committed. If it does not, you stranded durable work — `log` it and commit
165
+ it (or, if a path turns out to belong to a *still-live* sibling lease — check
166
+ `dos arbitrate`/the lane journal — leave it for that loop). Either way the loop
167
+ must not exit leaving its own lane dirty off a self-reported "done".
168
+ - **Scratch is not stranded work.** Short-lived probe output (a host's scratch
169
+ convention — temp dirs, `*.err`, leading-underscore probes) is deletable noise, not
170
+ a phase to ship; `rm` it or leave it gitignored, don't commit it into the lane.
171
+
172
+ This close-out is what keeps an unattended fleet's tree **clean and well-organized
173
+ across runs**: each loop commits its own lane and confirms it left nothing behind, so
174
+ the trunk never accumulates anonymous WIP from a loop that stopped mid-write.
175
+
176
+ > **DOS-repo note (not part of the generic skill):** when this loop runs *in the DOS
177
+ > kernel repo itself*, that repo ships an advisory `scripts/git_hygiene.py --strict`
178
+ > that mechanizes the "is my lane clean?" check above (exit 1 on stranded durable
179
+ > work, lease-aware). It is a DOS-repo convenience, not a `dos` verb — a foreign
180
+ > workspace uses the generic `git status` form above. Both express the same
181
+ > discipline.
182
+
183
+ ## What this skill deliberately does NOT do (no silent gap, `CLAUDE.md` heavy tier)
184
+
185
+ - **No soft-claim lease core.** It coordinates loops by *lane* lease
186
+ (`dos arbitrate`), not the per-pick soft-claim machinery that stays host-side.
187
+ `log` this when a sibling lane is busy rather than waiting on a soft-claim.
188
+ - **No value-greedy focus scheduler.** It picks by lane order + the gate verdict,
189
+ not a host's per-iteration focus ranking. That scheduler is the heavy tier.
190
+ - **No rate-limit predictive monitor / resume manifest.** It stops on a
191
+ RATE_LIMITED outcome and reports it; it does not pre-empt or auto-resume. A
192
+ host adds that as a driver concern.
193
+
194
+ It `log`s each of these the first time it would have used them, so the capability
195
+ gap is named, never silent.
196
+
197
+ ## Worked example (live transcript)
198
+
199
+ > **The cadence loop, by hand.** Take a lane, keep the WAL beat alive, ask the
200
+ > kernel if the run is moving. Every line is a real `dos` verb; the heartbeat is
201
+ > the `HEARTBEAT` op the trajectory-audit cross-signal reads.
202
+
203
+ Step 0 — take a lane. You ask for `src`; a live lease made it contended, so the
204
+ arbiter auto-picks a free cluster lane instead (it never double-books a region):
205
+
206
+ ```bash
207
+ $ dos arbitrate --workspace . --lane src
208
+ {"auto_picked":true,"free_clusters":[],"lane":"benchmark","lane_kind":"cluster","outcome":"acquire","pick_count":null,"reason":"auto-picked free cluster lane benchmark (requested src was busy).","tree":["benchmark/**"]}
209
+ ```
210
+
211
+ → exit `0` (`acquire`); the redirect IS the admission kernel refusing a collision.
212
+
213
+ Keep the beat alive across iterations — `acquire` once, `heartbeat` each pass,
214
+ `release` at the end. The `HEARTBEAT` op is what makes `SPINNING` reachable from
215
+ real evidence (a beat is not an event):
216
+
217
+ ```bash
218
+ $ dos lease-lane acquire --workspace . --lane benchmark # writes ACQUIRE to the WAL
219
+ $ dos lease-lane heartbeat --workspace . --lane benchmark # writes HEARTBEAT each iteration
220
+ $ dos lease-lane release --workspace . --lane benchmark # writes RELEASE when the loop stops
221
+ ```
222
+
223
+ Ask the kernel if the run is moving (the temporal verdict, from git delta — never
224
+ the loop's "making progress" self-report):
225
+
226
+ ```bash
227
+ $ dos liveness --workspace . --run-id R --start-sha 80d4f30
228
+ ```
229
+
230
+ → exit `0` = `ADVANCING` · `3` = `SPINNING` · `4` = `STALLED` (`2` contract-error).
231
+ Drive the loop off the exit code, not stdout prose.
232
+
233
+ Read the beat back from the WAL — an `ACQUIRE`/`HEARTBEAT`/`REFUSE`/`RELEASE`
234
+ sequence on generic lanes (ILLUSTRATIVE shape; `dos journal replay` folds it):
235
+
236
+ ```bash
237
+ $ dos journal --workspace . tail 4
238
+ {"op":"ACQUIRE","lane":"benchmark","tree":["benchmark/**"]}
239
+ {"op":"HEARTBEAT","lane":"benchmark"}
240
+ {"op":"REFUSE","lane":"benchmark","reason":"lane benchmark is already held by a live loop — pick a different --lane or wait."}
241
+ {"op":"RELEASE","lane":"benchmark"}
242
+ ```
243
+
244
+ → the `REFUSE` row is the WAL recording the arbiter's "no" — a sibling loop's
245
+ overlapping lane, fossilized for `dos decisions` to surface.
246
+
247
+ ## Anti-patterns
248
+
249
+ - ❌ Re-implementing the stop conditions in prose — route every outcome through
250
+ the kernel loop decision; the counters/breakers/cap are the kernel's.
251
+ - ❌ Counting a STALE-STAMP/BLOCKED toward drained-twice — only a true DRAIN after
252
+ a productive replan counts (the kernel enforces this; don't second-guess it).
253
+ - ❌ Running two loops on overlapping lanes — the arbiter REFUSEs the second;
254
+ honor it, don't `--force`.