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.
- dos/__init__.py +261 -0
- dos/_bin/dos-hook.exe +0 -0
- dos/_filelock.py +255 -0
- dos/_job_policy.py +97 -0
- dos/_tree.py +145 -0
- dos/admission.py +433 -0
- dos/answer_shape.py +299 -0
- dos/arbiter.py +859 -0
- dos/archive_lock.py +266 -0
- dos/arg_provenance.py +814 -0
- dos/attest.py +472 -0
- dos/breaker.py +311 -0
- dos/churn.py +226 -0
- dos/claim_extract.py +229 -0
- dos/claim_ttl.py +150 -0
- dos/cli.py +8721 -0
- dos/commit_audit.py +666 -0
- dos/completion.py +466 -0
- dos/concurrency_class.py +154 -0
- dos/config.py +1380 -0
- dos/config_lint.py +464 -0
- dos/cooldown.py +390 -0
- dos/coverage.py +387 -0
- dos/dangling_intent.py +287 -0
- dos/data_class.py +397 -0
- dos/decisions.py +1274 -0
- dos/decisions_tui.py +251 -0
- dos/dispatch_top.py +740 -0
- dos/dispatch_top_tui.py +116 -0
- dos/drivers/__init__.py +40 -0
- dos/drivers/ci_status.py +630 -0
- dos/drivers/citation_resolve.py +703 -0
- dos/drivers/decision_stop.py +98 -0
- dos/drivers/export_file.py +173 -0
- dos/drivers/export_otlp.py +275 -0
- dos/drivers/export_statsd.py +242 -0
- dos/drivers/hook_dialects.py +391 -0
- dos/drivers/job.py +47 -0
- dos/drivers/llm_judge.py +360 -0
- dos/drivers/memory_recall.py +1231 -0
- dos/drivers/notify_slack.py +373 -0
- dos/drivers/notify_webhook.py +251 -0
- dos/drivers/operator_judge.py +114 -0
- dos/drivers/os_acceptance.py +228 -0
- dos/drivers/paste_log.py +132 -0
- dos/drivers/plan_scope.py +133 -0
- dos/drivers/self_improve.py +375 -0
- dos/drivers/similarity_judge.py +249 -0
- dos/drivers/state_diff.py +274 -0
- dos/drivers/supervisor.py +347 -0
- dos/drivers/watchdog.py +363 -0
- dos/drivers/workshop.py +160 -0
- dos/durable_schema.py +344 -0
- dos/effect_witness.py +393 -0
- dos/efficiency.py +318 -0
- dos/enforce.py +414 -0
- dos/enumerate.py +776 -0
- dos/env_print.py +378 -0
- dos/event_severity.py +258 -0
- dos/evidence.py +692 -0
- dos/exec_capability.py +256 -0
- dos/export_cursor.py +143 -0
- dos/exporter.py +320 -0
- dos/firing_label.py +353 -0
- dos/fleet_roll.py +226 -0
- dos/gate_classify.py +827 -0
- dos/gh4_coverage.py +179 -0
- dos/git_delta.py +122 -0
- dos/guard.py +215 -0
- dos/health.py +552 -0
- dos/help_summary.py +519 -0
- dos/home.py +934 -0
- dos/hook_binary.py +194 -0
- dos/hook_dialect.py +271 -0
- dos/hook_exit.py +191 -0
- dos/hook_install.py +437 -0
- dos/id_alloc.py +304 -0
- dos/improve.py +499 -0
- dos/intent_ledger.py +635 -0
- dos/interpret.py +176 -0
- dos/intervention.py +769 -0
- dos/intervention_eval.py +371 -0
- dos/journal_delta.py +308 -0
- dos/judge_eval.py +328 -0
- dos/judges.py +366 -0
- dos/lane_infer.py +127 -0
- dos/lane_journal.py +1001 -0
- dos/lane_lease.py +952 -0
- dos/lane_overlap.py +228 -0
- dos/lease_health.py +282 -0
- dos/lifecycle.py +211 -0
- dos/liveness.py +352 -0
- dos/lock_modes.py +185 -0
- dos/log_source.py +395 -0
- dos/loop_decide.py +1746 -0
- dos/marker_gate.py +254 -0
- dos/marker_sensor.py +396 -0
- dos/noop_streak.py +280 -0
- dos/notify.py +479 -0
- dos/observe.py +175 -0
- dos/oracle.py +1661 -0
- dos/overlap_eval.py +214 -0
- dos/overlap_policy.py +342 -0
- dos/packet_sidecar.py +267 -0
- dos/phase_shipped.py +1985 -0
- dos/pick_priority.py +225 -0
- dos/pickable.py +369 -0
- dos/picker_oracle.py +1037 -0
- dos/plan_board.py +513 -0
- dos/plan_board_tui.py +113 -0
- dos/plan_source.py +455 -0
- dos/posttool_sensor.py +528 -0
- dos/precursor_gate.py +499 -0
- dos/precursor_gate_eval.py +239 -0
- dos/preflight.py +825 -0
- dos/pretool_sensor.py +490 -0
- dos/proc_delta.py +181 -0
- dos/productivity.py +296 -0
- dos/provider_limit.py +242 -0
- dos/py.typed +4 -0
- dos/reason_morphology.py +299 -0
- dos/reasons.py +449 -0
- dos/reconcile.py +173 -0
- dos/recurring_wedge.py +206 -0
- dos/render.py +393 -0
- dos/result_state.py +468 -0
- dos/resume.py +578 -0
- dos/resume_evidence.py +293 -0
- dos/retention.py +344 -0
- dos/reward.py +372 -0
- dos/rewind.py +587 -0
- dos/rewind_evidence.py +168 -0
- dos/rewind_tokens.py +252 -0
- dos/run_id.py +342 -0
- dos/scope.py +520 -0
- dos/scope_source.py +382 -0
- dos/scout.py +982 -0
- dos/self_modify.py +209 -0
- dos/sibling_scan.py +569 -0
- dos/skills/EXAMPLES.md +584 -0
- dos/skills/dos-class-cycle/SKILL.md +107 -0
- dos/skills/dos-dispatch/SKILL.md +177 -0
- dos/skills/dos-dispatch-loop/SKILL.md +254 -0
- dos/skills/dos-goal-gate/SKILL.md +269 -0
- dos/skills/dos-next-up/SKILL.md +231 -0
- dos/skills/dos-promote/SKILL.md +114 -0
- dos/skills/dos-replan/SKILL.md +159 -0
- dos/skills/dos-replan-loop/SKILL.md +114 -0
- dos/skills/dos-self-improve/SKILL.md +213 -0
- dos/skills/dos-supervise-loop/SKILL.md +180 -0
- dos/skills/dos-unstick/SKILL.md +108 -0
- dos/skills/dos-witness-claim/SKILL.md +251 -0
- dos/stamp.py +1002 -0
- dos/state_health.py +387 -0
- dos/status.py +114 -0
- dos/stop_policy.py +334 -0
- dos/supervise.py +1014 -0
- dos/testwitness.py +392 -0
- dos/timeline.py +1027 -0
- dos/tokens.py +485 -0
- dos/tool_stream.py +393 -0
- dos/tool_stream_eval.py +226 -0
- dos/trace.py +524 -0
- dos/verdict.py +140 -0
- dos/verdict_cli.py +189 -0
- dos/verdict_journal.py +497 -0
- dos/verdict_rollup.py +217 -0
- dos/verdicts.py +181 -0
- dos/wedge_reason.py +282 -0
- dos_kernel-0.22.0.dist-info/METADATA +859 -0
- dos_kernel-0.22.0.dist-info/RECORD +178 -0
- dos_kernel-0.22.0.dist-info/WHEEL +5 -0
- dos_kernel-0.22.0.dist-info/entry_points.txt +39 -0
- dos_kernel-0.22.0.dist-info/licenses/LICENSE +21 -0
- dos_kernel-0.22.0.dist-info/top_level.txt +2 -0
- dos_mcp/__init__.py +52 -0
- dos_mcp/py.typed +2 -0
- dos_mcp/server.py +779 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dos-goal-gate
|
|
3
|
+
description: Ground a "keep working until the goal is met" stop condition in a witness the agent did not author, instead of letting the agent self-certify "done". A harness goal/Stop-hook condition is normally checked by the model re-reading its OWN work — consistency, not grounding. This skill turns the operator's goal into checkable EFFECT claims and wires `dos hook stop` so the Stop is refused until git ancestry (a shipped phase) or an effect read-back corroborates the claimed effect. Driven by `dos` verbs and the workspace's own `dos.toml` — no host-specific paths, lanes, or commit conventions. Use when you want a self-stopping agent (or a `/loop` worker) to be unable to declare a goal complete on its own say-so. The single-agent self-stop analogue of `dos-witness-claim`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dos-goal-gate — gate "I'm done" on a witness, not on self-report
|
|
7
|
+
|
|
8
|
+
> **A completion condition the agent checks against its own narration is the
|
|
9
|
+
> exact failure DOS exists to fix.** When an agent decides "the goal is met" by
|
|
10
|
+
> re-reading what it just wrote, the part deciding ground truth *is* the part
|
|
11
|
+
> being judged — that is **consistency, not grounding** (docs/138). This skill
|
|
12
|
+
> never decides done-ness by re-reading the transcript. It turns the goal into a
|
|
13
|
+
> set of checkable EFFECT claims, then wires the Stop decision so the agent
|
|
14
|
+
> cannot stop until a read-back whose **byte-author is not the agent** (git
|
|
15
|
+
> ancestry, an OS exit code, a fresh state read) corroborates each effect. The
|
|
16
|
+
> kernel decides; the skill narrates.
|
|
17
|
+
|
|
18
|
+
The shape is domain-free: **state the goal as effects → wire the Stop gate →
|
|
19
|
+
on each stop, witness every effect → stop only when all are corroborated.** The
|
|
20
|
+
*policy* (which plan grammar, which lanes, where state lives) is data read from
|
|
21
|
+
`dos doctor --json`, never literals this screenplay hardcodes.
|
|
22
|
+
|
|
23
|
+
**Why this is not just "ask the model if it's done."** A harness stop-condition
|
|
24
|
+
("keep going until X") is evaluated by a model reading the session — so a
|
|
25
|
+
confident, fluent narration of an X that the world does not corroborate ends the
|
|
26
|
+
work early (the silent fail of docs/177). The gate below replaces that judgment
|
|
27
|
+
with a verdict over evidence the agent did not write: a phase is done when *git*
|
|
28
|
+
says a commit backs it, not when the agent says it committed; a file exists when
|
|
29
|
+
a *fresh read* finds it, not when the agent says it wrote it.
|
|
30
|
+
|
|
31
|
+
## When to use this (and when not)
|
|
32
|
+
|
|
33
|
+
- **Use it** when a single agent self-paces toward a stated goal and you want its
|
|
34
|
+
"done" to be unfalsifiable-by-narration — a `/loop` worker, a self-stopping
|
|
35
|
+
task agent, or any run where the operator stated a completion condition.
|
|
36
|
+
- **Use `dos-witness-claim` instead** when many workers' results are folded at a
|
|
37
|
+
`parallel()`/`pipeline()` barrier — that skill is the *fan-out fold* analogue;
|
|
38
|
+
this one is the *single-agent self-stop* analogue. Same witness discipline,
|
|
39
|
+
different site.
|
|
40
|
+
- **This is advisory (a PDP, not a PEP — docs/99).** It computes a Stop verdict
|
|
41
|
+
and lets the runtime act on it via the user-owned hook seam. It blocks a *false*
|
|
42
|
+
done; it never blocks a *true* one, and it never enforces beyond the Stop hook.
|
|
43
|
+
|
|
44
|
+
## Inputs
|
|
45
|
+
|
|
46
|
+
- The operator's **goal** — the completion condition in plain words ("the auth
|
|
47
|
+
refactor is shipped and the suite is green", "the migration plan's phases are
|
|
48
|
+
all landed"). Free prose is the *input*, never the *test*.
|
|
49
|
+
- Optionally, a **transcript path** for the running session (the Stop event
|
|
50
|
+
carries it; you rarely pass it by hand).
|
|
51
|
+
|
|
52
|
+
## Step 0 — Discover the workspace layout (one call)
|
|
53
|
+
|
|
54
|
+
Run the doctor verb and read the result. **Every path / lane / exit-code below
|
|
55
|
+
comes from here, never a literal.**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
dos doctor --workspace . --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The fields this skill uses:
|
|
62
|
+
|
|
63
|
+
- `exit_codes.verify` — `{shipped, not_shipped, contract_error}`. Branch on these
|
|
64
|
+
for a **git-phase** effect (Step 2a), never on parsing prose.
|
|
65
|
+
- `exit_codes."verify-result"` — `{healthy, unreadable, dead, contract_error}`
|
|
66
|
+
(`dead=3`). Branch on these for the **terminal-state** witness when a transcript
|
|
67
|
+
is in play.
|
|
68
|
+
- `paths.plans_glob` / `lanes` / `stamp` — the host's plan grammar, lane taxonomy,
|
|
69
|
+
and ship-stamp convention, if a goal names a `(plan, phase)`.
|
|
70
|
+
- `git` — if `false`, the git-existence witness (Step 2a) has no history; every
|
|
71
|
+
git-phase effect resolves `source="none"`. Say so; do not silently pass it.
|
|
72
|
+
- `runtime_hooks` — which runtimes already have a `dos hook …` Stop entry wired
|
|
73
|
+
(so you know whether Step 1 still needs doing).
|
|
74
|
+
|
|
75
|
+
## Step 1 — Wire the Stop gate (once per workspace)
|
|
76
|
+
|
|
77
|
+
The gate is `dos hook stop`: a Stop / SubagentStop hook that refuses to let the
|
|
78
|
+
agent stop while a confidently-CLAIMED phase is NOT corroborated by git. Wire it
|
|
79
|
+
into the runtime's settings — idempotent, merged into any existing hooks, never
|
|
80
|
+
clobbering the operator's own:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
dos init --with-hooks --workspace . # Claude Code (the default runtime)
|
|
84
|
+
# cross-runtime: dos init --hooks <runtime> --workspace . (preview with --dry-run)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This binds three hooks; the load-bearing one here is **Stop → `dos hook stop`**.
|
|
88
|
+
On every stop it extracts the `(plan, phase)` the agent claimed and refuses the
|
|
89
|
+
stop (feeding the verdict back as the next instruction) if git does not back it.
|
|
90
|
+
That refusal IS the grounded form of "keep working until the goal is met": the
|
|
91
|
+
work cannot end on the agent's word that a phase shipped.
|
|
92
|
+
|
|
93
|
+
> **Two Stop hooks, opposite triggers — do not conflate them.** `dos hook stop`
|
|
94
|
+
> blocks a *false done* (the agent claimed a phase, git disagrees). `dos hook
|
|
95
|
+
> marker` (docs/259) blocks a *premature give-up while a keep-alive budget is
|
|
96
|
+
> unspent*, then gets out of the way. A host may wire both; this skill is about
|
|
97
|
+
> the first. If your goal is "don't stop polling yet," that is `dos hook marker`,
|
|
98
|
+
> not this gate.
|
|
99
|
+
|
|
100
|
+
### Step 1a — How this composes with the harness `/goal` command
|
|
101
|
+
|
|
102
|
+
The Claude Code `/goal <condition>` command is itself a **session-scoped Stop
|
|
103
|
+
hook — but a *model-evaluated* one**: a fast model re-reads the session after each
|
|
104
|
+
turn and rules on whether the condition holds. That is precisely the
|
|
105
|
+
consistency-not-grounding shape this skill exists to fix — the judge is a model
|
|
106
|
+
reading the agent's own narration, with no witness the agent did not author.
|
|
107
|
+
|
|
108
|
+
You do **not** replace `/goal`; you wire `dos hook stop` (Step 1) **alongside**
|
|
109
|
+
it, and the harness combines them for you. Claude Code runs every matching Stop
|
|
110
|
+
hook in parallel and applies an **ANY-block** rule: *the stop is refused if **any**
|
|
111
|
+
hook blocks it* (a `{"decision":"block",…}` at exit 0, or exit 2). So with both
|
|
112
|
+
active, the agent may stop only when the `/goal` model-judge **AND** the grounded
|
|
113
|
+
git gate both allow it — a logical AND of "the narration reads done" and "ground
|
|
114
|
+
truth backs it." The grounded gate can only ever *add* a refusal the model-judge
|
|
115
|
+
missed; it never loosens `/goal`. That is the whole win: keep using `/goal` for
|
|
116
|
+
its fluent, free, prose-level check, and let `dos hook stop` veto the case where
|
|
117
|
+
the prose says done but git does not corroborate it.
|
|
118
|
+
|
|
119
|
+
> **The two hooks are independent — the gate does not read the goal text.** A
|
|
120
|
+
> settings.json Stop hook receives the session/transcript, not the `/goal`
|
|
121
|
+
> condition string (the harness exposes no goal field to hooks). So `dos hook
|
|
122
|
+
> stop` does not "check the goal"; it independently checks that every phase the
|
|
123
|
+
> agent *claimed shipped* is backed by git. The alignment between the two is the
|
|
124
|
+
> operator's job: state the goal as the same checkable effects the gate verifies
|
|
125
|
+
> (Step 2), so "the model thinks it's done" and "git backs every claimed phase"
|
|
126
|
+
> converge on the same finish line. Do not write the gate as if it parses the
|
|
127
|
+
> goal — it parses the agent's claims and asks git.
|
|
128
|
+
|
|
129
|
+
## Step 2 — State the goal as checkable effects (the decomposition)
|
|
130
|
+
|
|
131
|
+
A goal is met when its **effects** are present in the world. Translate the prose
|
|
132
|
+
goal into a list of named, checkable effects — and **abstain rather than invent**.
|
|
133
|
+
An effect you cannot name an identifier for is not a passable goal; it is a
|
|
134
|
+
**NO_CLAIM** to surface for the operator, never a test you fabricate (docs/134).
|
|
135
|
+
|
|
136
|
+
Map each effect to its witness rung:
|
|
137
|
+
|
|
138
|
+
| Effect the goal asserts | Witness (byte-author ≠ agent) | Verb today |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| "(plan, phase) is shipped" | git ancestry + ship-stamp grammar | `dos verify` (Step 2a) — SHIPPED |
|
|
141
|
+
| "this terminal result is real" (a transcript is in play) | harness authorship marker | `dos verify-result` — SHIPPED |
|
|
142
|
+
| "I created file X / inserted row Y / sent message Z / deployed" | a fresh GET / state-diff / OS exit / counterparty record | **no CLI verb** (Step 2b) — Python-API gap |
|
|
143
|
+
|
|
144
|
+
The first two are shipped CLI verbs. The third is the open seam — handled
|
|
145
|
+
honestly in Step 2b. The goal's "done" is the **conjunction** of all its effects'
|
|
146
|
+
witnesses: every one CONFIRMED/SHIPPED, or the goal is not met.
|
|
147
|
+
|
|
148
|
+
### Step 2a — git-phase effects: ask the truth syscall
|
|
149
|
+
|
|
150
|
+
For each `(plan, phase)` the goal names, never trust "I committed it" and never
|
|
151
|
+
grep commit subjects yourself:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
dos verify --workspace . <PLAN> <PHASE> --json
|
|
155
|
+
echo "exit=$?"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Read the `ShipVerdict` `{shipped, source, sha?}`, branch on `exit_codes.verify`,
|
|
159
|
+
and **read the rung**:
|
|
160
|
+
|
|
161
|
+
- `source: "registry"` — the strongest git ship; a ship row exists. Effect met.
|
|
162
|
+
- `source: "grep-subject"` — a commit *subject* carried the phase token. SHIPPED,
|
|
163
|
+
but weaker (a subject can flip the verdict even if little was built). Met, but
|
|
164
|
+
mark the rung; do not treat it as equal to `registry`.
|
|
165
|
+
- `source: "none"` — no positive git evidence. The agent CLAIMED the phase but git
|
|
166
|
+
does not corroborate it. **The effect is NOT met** — this is the narrated
|
|
167
|
+
success the world does not back. The goal is unmet; keep working.
|
|
168
|
+
|
|
169
|
+
This is grounding because git is a witness the agent did not author: a commit's
|
|
170
|
+
existence in ancestry is a fact about the repository, not about the agent's prose.
|
|
171
|
+
|
|
172
|
+
### Step 2b — created-file / DB-row / sent-message effects: the read-back gap
|
|
173
|
+
|
|
174
|
+
**There is NO `dos verify-effect` (or `dos witness`) CLI verb.** The
|
|
175
|
+
effect-witness join is shipped in the kernel as a **Python API**, not a command
|
|
176
|
+
(exactly as `tool_stream` has no `dos tool-stream` verb — see EXAMPLES.md Recipe
|
|
177
|
+
5). So for any effect outside git, document the pattern and **log the gap at
|
|
178
|
+
runtime**, rather than pretending a verb exists:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from dos.claim_extract import extract_claims # (a) abstain, never invent
|
|
182
|
+
from dos.effect_witness import EffectClaim, witness_effect
|
|
183
|
+
from dos.evidence import gather_evidence, resolve_evidence_source # (b) read-back
|
|
184
|
+
|
|
185
|
+
# (a) Extract the claim from the agent's terminal text. extract_claims fires only
|
|
186
|
+
# on an explicit ID-shaped token or a DOS-CLAIM: marker — free prose yields [].
|
|
187
|
+
# That [] is a NO_CLAIM (surface it), not a met effect.
|
|
188
|
+
|
|
189
|
+
# (b) Gather a read-back from a witness the agent did not author. A real witness
|
|
190
|
+
# (a fresh HTTP GET, an OS exit code, a state-snapshot diff) lives in a driver
|
|
191
|
+
# registered under the `dos.evidence_sources` entry-point group; resolve it by
|
|
192
|
+
# name and run it at the boundary:
|
|
193
|
+
source = resolve_evidence_source("<your-witness-name>") # built-in `null` if none wired
|
|
194
|
+
facts = gather_evidence(source, subject="<effect key>", config=cfg)
|
|
195
|
+
|
|
196
|
+
# (c) The effect is met ONLY on CONFIRMED — the join is capped by the read-back's
|
|
197
|
+
# accountability (believe_under_floor): a forgeable same-surface read-back
|
|
198
|
+
# (AGENT_AUTHORED) is recorded but structurally CANNOT grant belief.
|
|
199
|
+
verdict = witness_effect(EffectClaim(key="<effect key>", narrated="<what agent said>"),
|
|
200
|
+
(facts,))
|
|
201
|
+
# verdict.verdict -> CONFIRMED | REFUTED | UNWITNESSED | NO_CLAIM
|
|
202
|
+
# verdict.believe -> True ONLY on CONFIRMED
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The load-bearing rule, enforced structurally by `believe_under_floor`: a read-back
|
|
206
|
+
on the forgeable floor (`AGENT_AUTHORED` — the agent re-reading its own surface, a
|
|
207
|
+
pasted receipt, an mtime) is recorded but **structurally incapable** of granting
|
|
208
|
+
belief. So the worst a lying same-surface read-back can do is be ignored, never
|
|
209
|
+
manufacture a CONFIRMED. **Log the gap, never silently skip it:** the first time a
|
|
210
|
+
non-git effect needs witnessing and no `dos.evidence_sources` driver is wired,
|
|
211
|
+
emit a one-line `log` naming the unwitnessed effect — surface it up, never launder
|
|
212
|
+
it into "goal met."
|
|
213
|
+
|
|
214
|
+
## Step 3 — The gate's verdict is the stop decision
|
|
215
|
+
|
|
216
|
+
With the gate wired (Step 1), the runtime already enforces the git-phase rung on
|
|
217
|
+
every stop. Your job in the screenplay is to keep the agent's claimed effects and
|
|
218
|
+
the goal's effect-list aligned, and to read the gate's verdict honestly:
|
|
219
|
+
|
|
220
|
+
- **All effects CONFIRMED / SHIPPED** → the goal is met. The Stop hook emits
|
|
221
|
+
nothing (`{"checked": N, "ok": true}` under `--json`) and the agent stops. This
|
|
222
|
+
is the only path to "done."
|
|
223
|
+
- **Any effect `source: "none"` / REFUTED** → the goal is unmet. `dos hook stop`
|
|
224
|
+
emits `{"decision": "block", "reason": "…"}`, the runtime declines to stop, and
|
|
225
|
+
the reason is fed back as the next instruction — *keep working*. The agent does
|
|
226
|
+
not get to overrule this by asserting completion again.
|
|
227
|
+
- **Any effect UNWITNESSED / NO_CLAIM** → you cannot say the goal is met. Surface
|
|
228
|
+
it for the operator; do not let the agent stop on an effect no accountable
|
|
229
|
+
witness reached. (The git-phase rung fails *safe* — a `source:"none"` is treated
|
|
230
|
+
as not-shipped, so the gate keeps working rather than passing an unproven claim.)
|
|
231
|
+
|
|
232
|
+
You can check the gate's reasoning out-of-band, before relying on it, by feeding a
|
|
233
|
+
synthetic Stop event:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
echo '{"transcript_path":"<session.jsonl>"}' | dos hook stop --workspace . --json
|
|
237
|
+
# {"ok": false, "reason": "DOS verify: you claimed … shipped, but git has no commit backing it …", "results": [...]}
|
|
238
|
+
# ok:false → the goal is NOT met; the agent will be kept working.
|
|
239
|
+
# ok:true → every claimed phase is corroborated; the agent may stop.
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
This is the same out-of-loop check as `dos plan --once` / `dos commit-audit`: a
|
|
243
|
+
verdict over ground truth, run from outside the loop that wrote the claim.
|
|
244
|
+
|
|
245
|
+
## Anti-patterns
|
|
246
|
+
|
|
247
|
+
- ❌ Deciding "the goal is met" by re-reading the transcript / the agent's last
|
|
248
|
+
message. That is consistency, not grounding — the agent judging its own bytes.
|
|
249
|
+
Decompose into effects and witness each one.
|
|
250
|
+
- ❌ Treating "I committed the phase" as the phase shipping. Run `dos verify`; a
|
|
251
|
+
`source:"none"` means git does not back the claim, regardless of the narration.
|
|
252
|
+
- ❌ Grepping commit subjects yourself to confirm a ship. The ship-stamp grammar
|
|
253
|
+
is `dos.toml` `[stamp]` data the oracle reads — ask `dos verify`, do not
|
|
254
|
+
re-implement the rung (a subject is forgeable; let the oracle weigh the rung).
|
|
255
|
+
- ❌ Letting the agent stop on an UNWITNESSED / NO_CLAIM effect "because it
|
|
256
|
+
probably worked." Abstain surfaces it; it is never a met effect.
|
|
257
|
+
- ❌ Wiring `dos hook marker` when you mean this gate (or vice versa). Marker
|
|
258
|
+
bounds keep-alive polling; this gate refuses a false done. Opposite triggers.
|
|
259
|
+
- ❌ Naming a specific lane, plan dir, ship prefix, or witness backend as a
|
|
260
|
+
literal — read the active layout from `dos doctor --json` and resolve witnesses
|
|
261
|
+
by name.
|
|
262
|
+
|
|
263
|
+
## The one rule under this skill
|
|
264
|
+
|
|
265
|
+
"The goal is met" is a **claim with a byte-author**. Let the agent stop only when
|
|
266
|
+
a witness whose byte-author is *not the agent* corroborates every effect the goal
|
|
267
|
+
named. The agent's confidence and its fluent description of success are irrelevant
|
|
268
|
+
to that gate — which is the whole point: the part that decides the goal is done is
|
|
269
|
+
never the part being judged.
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dos-next-up
|
|
3
|
+
description: Snapshot a repo's phased-plan portfolio and produce a parallel-agent dispatch packet, driven entirely by `dos` verbs and the workspace's own `dos.toml` — no host-specific paths, lanes, or commit conventions. Walks the configured plans glob, audits each candidate pick against `dos verify` for its true shipped/unshipped status, renders a self-contained packet to the configured output dir, and reports a typed gate verdict via `dos gate`. Use when you want a "where are we / what's next / who-does-what" snapshot of any repo that has a few plan docs and real commits. This is the DOS reference workflow (SKP Axis 5); a host may use it, fork it, or ignore it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dos-next-up — the generic plan-and-ship snapshot
|
|
7
|
+
|
|
8
|
+
> **This is the baseline screenplay DOS ships, not a prerequisite.** It drives the
|
|
9
|
+
> kernel syscalls (`verify`, `gate`) against *any* repo whose layout lives in
|
|
10
|
+
> `dos.toml`. It names no host directory, no host lane, and no host commit
|
|
11
|
+
> convention — every host specific comes from `dos doctor --json` (paths/lanes,
|
|
12
|
+
> via WCR) or `dos.toml [stamp]` (the ship grammar, via SCV). Copy it into your
|
|
13
|
+
> own skills dir, point `dos` at your workspace, and it runs.
|
|
14
|
+
|
|
15
|
+
The shape is domain-free: **discover the layout → walk the plans → audit each
|
|
16
|
+
pick against the truth syscall → render a packet → gate the empty case.** The
|
|
17
|
+
*policy* (which lanes, which plan grammar, where output lands) is data the
|
|
18
|
+
screenplay reads, never literals it hardcodes.
|
|
19
|
+
|
|
20
|
+
## Inputs
|
|
21
|
+
|
|
22
|
+
- `--scope <name>` (repeatable, optional) — narrow candidates to one lane (a
|
|
23
|
+
name from the active `[lanes]` taxonomy) or one plan id. Omitted = all plans.
|
|
24
|
+
- `--limit <N>` (optional, default 5) — how many top picks to render.
|
|
25
|
+
|
|
26
|
+
## Step 0 — Discover the workspace layout (one call)
|
|
27
|
+
|
|
28
|
+
Run the doctor verb and read the result. **This is the WCR on-ramp: every
|
|
29
|
+
path/lane below comes from here, never a literal.**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
dos doctor --workspace . --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Parse the JSON object. The fields you use:
|
|
36
|
+
|
|
37
|
+
- `paths.plans_glob` — the glob to walk for plan docs (whatever the workspace
|
|
38
|
+
declared). **Use this value; never assume a fixed plans directory.**
|
|
39
|
+
- `paths.next_packets` — where the rendered packet is written (the configured
|
|
40
|
+
output dir; `.dos/verdicts` under the generic default).
|
|
41
|
+
- `lanes.concurrent` / `lanes.exclusive` / `lanes.trees` — the active lane
|
|
42
|
+
taxonomy, if you need to group picks by lane or honor a `--scope`.
|
|
43
|
+
- `stamp` — the active ship-subject grammar (informational; `dos verify` applies
|
|
44
|
+
it for you — you never grep subjects yourself).
|
|
45
|
+
|
|
46
|
+
If `git` is `false`, warn the operator: `dos verify`'s git rung has no history to
|
|
47
|
+
read, so every pick will report `source="none"` unless a registry exists.
|
|
48
|
+
|
|
49
|
+
## Step 1 — Walk the plans glob → candidate picks
|
|
50
|
+
|
|
51
|
+
List the plan docs under `paths.plans_glob` (relative to `paths.root`). For each
|
|
52
|
+
plan doc, read its phase headings to extract `(plan_id, phase_id)` candidate
|
|
53
|
+
pairs — the next not-yet-shipped phases. Keep this generic: a "phase" is a
|
|
54
|
+
heading the doc marks as a unit of work; you do not need the job's exact
|
|
55
|
+
frontmatter. If a `--scope` was given, keep only plans/lanes that match it.
|
|
56
|
+
|
|
57
|
+
Collect a flat list of candidate `(plan, phase)` picks. Do not rank by any
|
|
58
|
+
host-specific signal — order by plan-doc order, then truncate later.
|
|
59
|
+
|
|
60
|
+
## Step 2 — Audit each candidate against the truth syscall
|
|
61
|
+
|
|
62
|
+
For **each** candidate pick, ask the kernel whether it already shipped — never
|
|
63
|
+
trust the plan doc's own stamp, and never grep commit subjects yourself:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
dos verify --workspace . <PLAN> <PHASE> --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Read the `ShipVerdict` JSON: `{shipped, source, sha?, plan, phase}`. `source`
|
|
70
|
+
tells you *how* the kernel knows: `registry` (a ship row), `grep` (a commit
|
|
71
|
+
subject under the active `[stamp]` grammar), or `none` (no positive evidence).
|
|
72
|
+
This is the SCV payoff — a foreign repo whose commits read `AUTH2: …` is
|
|
73
|
+
recognized iff its `dos.toml` declares the matching `[stamp]`.
|
|
74
|
+
|
|
75
|
+
Classify each pick into one of three dispositions — this is what the gate reads:
|
|
76
|
+
|
|
77
|
+
- **`shipped: false, source: "none"`** → **live**: a real next pick. Disposition
|
|
78
|
+
`{phase, live: true}`.
|
|
79
|
+
- **`shipped: true, source: "registry"`** → **done, cleanly**: a ship row exists.
|
|
80
|
+
Disposition `{phase, live: false, drop_reason: "shipped"}` — drop it.
|
|
81
|
+
- **`shipped: true, source: "grep"`** → a real **git ship**. Now check the plan
|
|
82
|
+
doc: does its heading for this phase carry a SHIPPED stamp? If **yes**, drop it
|
|
83
|
+
as a clean ship (as above). If **no**, this is a **stale stamp** — the work
|
|
84
|
+
shipped in git but the plan doc lags — and you must encode it so the gate can
|
|
85
|
+
catch the false-drain: `{phase, live: false, drop_reason: "shipped",
|
|
86
|
+
"ship_via": "direct", "plan_doc_stamped": false}`.
|
|
87
|
+
|
|
88
|
+
The `ship_via: "direct"` + `plan_doc_stamped: false` pair is the *exact* shape
|
|
89
|
+
`dos gate` classifies as STALE-STAMP (a `grep` ship the plan doc doesn't reflect).
|
|
90
|
+
**Do not put verify's `source` value into `ship_via`** — `ship_via` is the gate's
|
|
91
|
+
own direct-ship marker, set to the literal `"direct"` only for an unstamped git
|
|
92
|
+
ship; a `registry` hit is a clean `shipped` drop, never STALE-STAMP.
|
|
93
|
+
|
|
94
|
+
Keep the first `--limit` live picks as the packet's dispatch list.
|
|
95
|
+
|
|
96
|
+
## Step 3 — Render the dispatch packet
|
|
97
|
+
|
|
98
|
+
Assemble a self-contained markdown packet **yourself** (DOS ships no packet
|
|
99
|
+
template in the kernel — see the friction log: the `[render]` packet-template
|
|
100
|
+
seam is a named open axis). Write it under `paths.next_packets`, named
|
|
101
|
+
`next-up-<UTC-date>-<N>.md`. The packet has, generically:
|
|
102
|
+
|
|
103
|
+
1. **Header** — the workspace root, the active lane taxonomy, the run timestamp.
|
|
104
|
+
2. **Portfolio snapshot** — one row per plan: plan id, how many phases, how many
|
|
105
|
+
verified shipped (from Step 2), the next live phase.
|
|
106
|
+
3. **Dispatch list** — for each live pick, a self-contained prompt another agent
|
|
107
|
+
could be launched with: the plan id, the phase id, the plan-doc path, and the
|
|
108
|
+
one-line goal. Keep each prompt standalone (no shared context).
|
|
109
|
+
4. **Already shipped** — the picks Step 2 found `shipped: true`, with `source`/`sha`.
|
|
110
|
+
|
|
111
|
+
Alongside the packet, emit the gate sidecar so Step 4 can classify it — write
|
|
112
|
+
`<paths.next_packets>/.dispositions-<tag>.json` with the kernel's contract. One
|
|
113
|
+
entry per pick the packet considered, using the Step-2 classification:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"schema": "oc3-dispositions-v1",
|
|
118
|
+
"tag": "<tag>",
|
|
119
|
+
"dispositions": [
|
|
120
|
+
{"phase": "AUTH2", "live": true},
|
|
121
|
+
{"phase": "AUTH1", "live": false, "drop_reason": "shipped"},
|
|
122
|
+
{"phase": "AUTH3", "live": false, "drop_reason": "shipped",
|
|
123
|
+
"ship_via": "direct", "plan_doc_stamped": false}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
In this example: `AUTH2` is live (a dispatch-list pick); `AUTH1` is a clean ship
|
|
129
|
+
(verify `source` was `registry`, or `grep` with the plan doc stamped) — a plain
|
|
130
|
+
`shipped` drop; `AUTH3` is a **stale stamp** (verify `source` was `grep` but the
|
|
131
|
+
plan doc is unstamped) — `ship_via: "direct"` + `plan_doc_stamped: false` is what
|
|
132
|
+
makes `dos gate` return STALE-STAMP for it. A clean ship omits both fields (it
|
|
133
|
+
must NOT carry `ship_via: "direct"`, or it would be misread as stale).
|
|
134
|
+
|
|
135
|
+
## Step 4 — Gate the packet (typed verdict)
|
|
136
|
+
|
|
137
|
+
Classify the packet through the kernel so the outcome is a typed verdict, not a
|
|
138
|
+
prose guess:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
dos gate --workspace . <paths.next_packets>/.dispositions-<tag>.json
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Read the exit code (the verdict IS the code):
|
|
145
|
+
|
|
146
|
+
- `0` **LIVE** — the packet has dispatchable work; report the packet path and the
|
|
147
|
+
dispatch count. This is the success case.
|
|
148
|
+
- `3` **DRAIN** — no live picks: a genuine empty backlog. Report "nothing to
|
|
149
|
+
dispatch — the portfolio is drained."
|
|
150
|
+
- `4` **STALE-STAMP** — phases shipped in git but the plan docs lag. Report the
|
|
151
|
+
drift (the operator should reconcile the stamps); this is NOT an empty backlog.
|
|
152
|
+
- `5` **BLOCKED** — picks exist but are blocked (a sibling claim / quota). Surface.
|
|
153
|
+
- `6` **RACE** — a concurrent render lost a lock race; retry once.
|
|
154
|
+
- `2` — a contract error (the sidecar was malformed). Fix the sidecar; do not
|
|
155
|
+
treat it as DRAIN.
|
|
156
|
+
|
|
157
|
+
## Step 5 — Return
|
|
158
|
+
|
|
159
|
+
Print the packet path and the gate verdict. **Return the packet path** as the
|
|
160
|
+
final line so a caller (e.g. `dos-dispatch`) can chain it:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Saved: <paths.next_packets>/next-up-<date>-<N>.md (verdict=<VERDICT>)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## What this skill deliberately does NOT do (no silent gap)
|
|
167
|
+
|
|
168
|
+
- **No soft-claim leasing.** It does not register per-pick soft-claims (the heavy
|
|
169
|
+
lease core stays host-side, `CLAUDE.md` heavy tier). `dos-dispatch` takes a
|
|
170
|
+
*lane* lease via `dos arbitrate`; the per-pick soft-claim is out of scope.
|
|
171
|
+
- **No host evidence sources.** It does not read a host's curated ranking file or
|
|
172
|
+
a postmortem stream — those are host gardening inputs (an evidence-source hook
|
|
173
|
+
is a named open seam). It ranks by plan-doc order, audited by `dos verify`.
|
|
174
|
+
- **No host packet template.** It assembles a generic packet; the exact section
|
|
175
|
+
grammar / commit subject a host wants is the `[render]` template seam (open).
|
|
176
|
+
|
|
177
|
+
**Log the gap, never silently skip it.** The first time the skill would have used
|
|
178
|
+
one of these (a soft-claim, a host evidence source), emit a one-line `log` naming
|
|
179
|
+
what it is not doing and why — so the capability gap is surfaced at runtime, not
|
|
180
|
+
just documented here.
|
|
181
|
+
|
|
182
|
+
## Worked example (live transcript)
|
|
183
|
+
|
|
184
|
+
> **The shape, run for real against a `dos` workspace.** Copy-pasteable verbs,
|
|
185
|
+
> actual captured output. The whole point is the last gloss on each block:
|
|
186
|
+
> **read the RUNG**, not the bare `shipped` boolean.
|
|
187
|
+
|
|
188
|
+
Step 0 — discover the layout (the WCR on-ramp):
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
$ dos doctor --workspace . --json
|
|
192
|
+
# dos_version 0.22.0; git true; stamp.style "grep" (generic, any/no dir prefix)
|
|
193
|
+
# paths.plans_glob "docs/**/*-plan.md"; paths.next_packets ".dos/verdicts"
|
|
194
|
+
# lanes.concurrent [benchmark, docs, examples, scripts, spikes, src, tests]
|
|
195
|
+
```
|
|
196
|
+
↳ every path/lane below is read from this object — never a literal.
|
|
197
|
+
|
|
198
|
+
Step 2 — audit a pick that DID ship. Read the `source` rung, not just `shipped`:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
$ dos verify --workspace . docs/82_liveness-oracle-plan liveness --json
|
|
202
|
+
{"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"}
|
|
203
|
+
```
|
|
204
|
+
↳ RUNG `source="grep-subject"` (NOT bare `grep`): a commit SUBJECT carrying the
|
|
205
|
+
phase token flips this to SHIPPED even if little was built. Read the rung.
|
|
206
|
+
|
|
207
|
+
Step 2 — and a pick that has NOT shipped:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
$ dos verify --workspace . docs/99_runtime-validation-and-the-actuation-boundary halt --json
|
|
211
|
+
{"phase":"halt","plan":"docs/99_runtime-validation-and-the-actuation-boundary","shipped":false,"source":"none"}
|
|
212
|
+
```
|
|
213
|
+
↳ RUNG `source="none"`: no positive git/registry evidence → a live pick.
|
|
214
|
+
|
|
215
|
+
Step 4 — gate the packet; the verdict IS the exit code:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
$ dos gate --workspace . .dos/verdicts/.dispositions-<tag>.json ; echo "exit=$?"
|
|
219
|
+
exit=0 # LIVE — dispatchable work (3=DRAIN, 4=STALE-STAMP, 5=BLOCKED, 6=RACE, 2=contract-error)
|
|
220
|
+
```
|
|
221
|
+
↳ exit-code `0` carried the verdict — LIVE, not a prose guess.
|
|
222
|
+
|
|
223
|
+
## Anti-patterns
|
|
224
|
+
|
|
225
|
+
- ❌ Hardcoding a plans directory or an output directory — read both from
|
|
226
|
+
`dos doctor --json` (the `paths` object).
|
|
227
|
+
- ❌ Greping commit subjects for a ship marker yourself — call `dos verify` (it
|
|
228
|
+
applies the active `[stamp]` grammar for you).
|
|
229
|
+
- ❌ Treating a 0-pick packet as "drained" without `dos gate` — a STALE-STAMP is a
|
|
230
|
+
false drain, and only the typed gate distinguishes it.
|
|
231
|
+
- ❌ Naming a specific lane as a literal — read the active `lanes` from doctor.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dos-promote
|
|
3
|
+
description: The visibility-inverse of lifecycle-demote. Run `dos pickable` over every declared unit; for each HELD unit, surface it with its typed HoldReason and the derived unblock action (DRAFT_CLASS→promote-to-active, UNPARSEABLE→inspect-the-deriver, OPERATOR_GATED→raise-a-decision, SOAK_OPEN→wait, DEPENDENCY_UNMET→ship-the-prerequisite). The only auto-applied action is a safe mechanical reclassify (gated, one commit); everything else is surfaced for a human via `dos decisions`. Every path/lane/class comes from `dos doctor --json`. Use when units are stuck un-pickable and you want each one's typed reason + the right unblock move. The operator-facing half of the shipped `pickable` gate (SKP Axis 5, docs/207 Phase 5b).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dos-promote — surface every held unit + its unblock action
|
|
7
|
+
|
|
8
|
+
> **Make the invisible pickable.** The picker silently drops a unit it cannot
|
|
9
|
+
> offer; `/dos-promote` does the inverse — it runs the **pre-dispatch gate**
|
|
10
|
+
> (`dos pickable`) over every declared unit, and for each one that is HELD it
|
|
11
|
+
> surfaces the unit, its *typed* hold reason, and the derived unblock action. The
|
|
12
|
+
> hold reason → action routing is data, not a guess: a `DRAFT_CLASS` hold wants a
|
|
13
|
+
> promotion, a `SOAK_OPEN` hold wants the clock, an `OPERATOR_GATED` hold wants a
|
|
14
|
+
> decision. This is the operator-facing half of the shipped `pickable` primitive.
|
|
15
|
+
|
|
16
|
+
The shape: **enumerate the units → gate each → route each hold to its action →
|
|
17
|
+
auto-enact only the safe mechanical reclassify → surface the rest.** The gate and
|
|
18
|
+
the enumeration are kernel verbs (`dos pickable`, `dos enumerate`); the
|
|
19
|
+
reason→action routing is derivable from the `HoldReason` itself.
|
|
20
|
+
|
|
21
|
+
## Inputs
|
|
22
|
+
|
|
23
|
+
- `--scope <lane>` (optional) — limit to one lane from the active `[lanes]`.
|
|
24
|
+
Omitted = every declared unit the workspace can see.
|
|
25
|
+
|
|
26
|
+
## Step 0 — Discover the layout
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
dos doctor --workspace . --json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Read `paths.plans_glob` (where the plan docs live), `lanes` (the taxonomy), and
|
|
33
|
+
`lifecycle.classes` (the declared class set — which class is the workspace's
|
|
34
|
+
"draft" / "active"). **Use these; never hardcode a plan path or a class name.**
|
|
35
|
+
|
|
36
|
+
## Step 1 — Enumerate the declared units
|
|
37
|
+
|
|
38
|
+
For each plan doc under `paths.plans_glob`, enumerate the units it declares:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dos enumerate <plan-doc> --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Read `units` (the universe), `remaining` (the not-yet-shipped), and `drift` — a
|
|
45
|
+
`drift[kind=unparseable]` is itself a held-by-UNPARSEABLE signal (the
|
|
46
|
+
picker-invisibility cure: a typed refusal, never a silent drop). Collect the
|
|
47
|
+
remaining units across all plans as the candidate set.
|
|
48
|
+
|
|
49
|
+
## Step 2 — Gate each candidate (the pre-dispatch verdict)
|
|
50
|
+
|
|
51
|
+
For each remaining unit, run the pre-dispatch gate over the unit's host-gathered
|
|
52
|
+
state (its plan class, soak index, live claims):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
dos pickable <UNIT> --state '<json>' --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Branch on the exit code (the verdict IS the code — distinct per hold):
|
|
59
|
+
|
|
60
|
+
- `0` **OFFERABLE** → a worker could pick it up now; NOT surfaced (it is not stuck).
|
|
61
|
+
- `10` **DRAFT_CLASS** → the plan is draft-class; the unblock is a **promotion**.
|
|
62
|
+
- `11` **OPERATOR_GATED** → blocked on a decision; raise it.
|
|
63
|
+
- `12` **SOAK_OPEN** → a soak deadline; **wait** (never promote — time un-gates it).
|
|
64
|
+
- `13` **DEPENDENCY_UNMET** → ship the prerequisite first.
|
|
65
|
+
- `24` **UNPARSEABLE** → inspect/fix the deriver or the doc; the unit is invisible.
|
|
66
|
+
- `20`–`23` **IN_FLIGHT / SOFT_CLAIMED / STALE_CLAIM / COOLDOWN** → a live/transient
|
|
67
|
+
hold that clears on its own; surface as info, no action.
|
|
68
|
+
|
|
69
|
+
## Step 3 — Route each hold to its unblock action (data, not a guess)
|
|
70
|
+
|
|
71
|
+
The action is derived from the typed `HoldReason`, not re-discovered per unit:
|
|
72
|
+
|
|
73
|
+
| Hold | Unblock action |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `DRAFT_CLASS` | promote the plan draft→active (the workspace's `lifecycle` default→next class) |
|
|
76
|
+
| `OPERATOR_GATED` | raise an operator decision (`dos decisions add`) |
|
|
77
|
+
| `SOAK_OPEN` | wait for the soak to close — surface the deadline, do NOT promote |
|
|
78
|
+
| `DEPENDENCY_UNMET` | ship the named prerequisite first |
|
|
79
|
+
| `UNPARSEABLE` | inspect the deriver / backfill the doc's phase grammar |
|
|
80
|
+
|
|
81
|
+
A host may declare a richer reason→action map in `dos.toml`; absent one, this
|
|
82
|
+
default routing (documented on the `HoldReason` enum) is used.
|
|
83
|
+
|
|
84
|
+
## Step 4 — Auto-enact ONLY the safe mechanical reclassify
|
|
85
|
+
|
|
86
|
+
The single auto-applied action is the **DRAFT→active promotion** of a plan whose
|
|
87
|
+
draft phases are demonstrably wanted — a mechanical plan-meta `classification:`
|
|
88
|
+
edit + ONE commit, gated. Read the trunk + ship grammar from `dos doctor --json`'s
|
|
89
|
+
`stamp`; **do not hardcode a commit prefix.** Everything else — a decision, a
|
|
90
|
+
soak wait, a dependency, an unparseable doc — is surfaced for a human, never
|
|
91
|
+
auto-applied (those are real judgment calls).
|
|
92
|
+
|
|
93
|
+
## Step 5 — Surface the rest
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
dos decisions add # one row per held unit that needs a human
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## What this skill deliberately does NOT do (no silent gap)
|
|
100
|
+
|
|
101
|
+
- **No auto-decision / auto-dependency-ship.** Only the mechanical reclassify is
|
|
102
|
+
auto; an OPERATOR_GATED / DEPENDENCY_UNMET hold is a human's call.
|
|
103
|
+
- **No soak fast-forward.** A SOAK_OPEN hold is surfaced with its deadline; the
|
|
104
|
+
loop NEVER promotes past a soak (time is the only thing that un-gates it).
|
|
105
|
+
- **No host class taxonomy.** The draft/active classes come from
|
|
106
|
+
`lifecycle.classes`; a 2-class repo and a job-shaped repo both run this skill.
|
|
107
|
+
|
|
108
|
+
## Anti-patterns
|
|
109
|
+
|
|
110
|
+
- ❌ Promoting a SOAK_OPEN unit — a soak is un-gated by the clock, not a promotion;
|
|
111
|
+
promoting it re-introduces the very drain-trap the typed hold prevents.
|
|
112
|
+
- ❌ Auto-resolving an OPERATOR_GATED hold — that decision is the operator's.
|
|
113
|
+
- ❌ Hardcoding "DRAFT"/"ACTIVE" — read the class set from `dos doctor --json`'s
|
|
114
|
+
`lifecycle.classes`.
|