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
dos/packet_sidecar.py ADDED
@@ -0,0 +1,267 @@
1
+ """The `.prompts.json` packet sidecar — the WRITE half of the contract.
2
+
3
+ FQ-419/FQ-420 root cure. `dos.preflight` already owns the *read* half of the
4
+ prompt sidecar — `load_packet_sidecar` (PRESENT/ABSENT/CORRUPT), the
5
+ `_sidecar_dropped_refusal` gate, and the `build_context` wiring that refuses a
6
+ packet whose `.prompts.json` is missing. But nothing owned the *write* half:
7
+ the reference userland renderer (`scripts/next_up_render.py:cmd_render`) emitted
8
+ the human packet `.md` and printed `Saved:` / exit-0 **without ever writing the
9
+ machine-readable `.prompts.json` the orchestrator actually launches workers
10
+ from.** Producer and consumer were out of contract — the schema token
11
+ `next-up-prompts-v1` was a *default* in the reader and **defined nowhere**, so
12
+ the renderer simply didn't emit it.
13
+
14
+ The cost was structural and recurring: every clean-validating packet shipped
15
+ without its prompt bodies, and the failure surfaced only one rung downstream as
16
+ a `/fanout` `body_empty_picks` refuse — naming the symptom, never the cause. By
17
+ 2026-06-01 it had wedged 6+ consecutive `/dispatch` runs across the apply,
18
+ tailor, and CD lanes (7d live ship-rate 0.0%).
19
+
20
+ This module closes the loop, the same way `dos.wedge_reason` closed the
21
+ no-pick-reason drift: **one place declares the schema, and both ends import
22
+ it.** It carries two kernel responsibilities:
23
+
24
+ 1. ``write_packet_sidecar(packet_path, picks)`` — the canonical serializer.
25
+ The renderer calls this; `dos.preflight.load_packet_sidecar` reads exactly
26
+ what it writes. The schema token (`SIDECAR_SCHEMA`) lives here and the
27
+ reader imports it, so the two can never drift to different strings.
28
+
29
+ 2. ``assert_packet_shippable(packet_path, rendered_pick_count)`` — the
30
+ PRODUCER-side verify. This is the DOS thesis applied at the source
31
+ (dispatch-os-vision §0, *the kernel is the part that doesn't believe the
32
+ agents*): the renderer is an unreliable, self-narrating worker; its exit-0
33
+ `Saved:` is a self-report. The kernel does not believe it — it re-opens the
34
+ artifact it was told exists and refuses if the prompt bodies are absent,
35
+ corrupt, or empty. Catching the drop here (one rung *above* `/fanout`)
36
+ turns a downstream `body_empty_picks` mystery into a loud, typed
37
+ `RENDERER_SIDECAR_DROPPED` refusal that points straight at the renderer.
38
+
39
+ Pure stdlib (mirrors `preflight` / `wedge_reason` leaf-import character) so the
40
+ renderer can import it without dragging heavy deps. The `WedgeReason` import is
41
+ the only intra-package dependency, and it is itself a leaf module.
42
+ """
43
+
44
+ from __future__ import annotations
45
+
46
+ import json
47
+ from dataclasses import dataclass, field
48
+ from pathlib import Path
49
+ from typing import Any
50
+
51
+ # Single-source the prompt-sidecar schema token. `dos.preflight.load_packet_sidecar`
52
+ # imports THIS constant for its `d.get("schema", SIDECAR_SCHEMA)` default, so the
53
+ # writer and reader can never disagree on the string. (Before this module the
54
+ # token was a bare literal default in the reader and was emitted by no writer at
55
+ # all — the exact producer/consumer drift `dos.wedge_reason` exists to end.)
56
+ SIDECAR_SCHEMA = "next-up-prompts-v1"
57
+
58
+ # The fields a sidecar pick carries — the contract `dos.preflight` consumes
59
+ # downstream (`load_packet_sidecar` → `merge_picks_with_verdicts`). `prompt_text`
60
+ # is the load-bearing one (the worker's actual prompt body); the rest are
61
+ # routing/observability metadata. A writer that omits `prompt_text`, or writes it
62
+ # empty, is exactly the drop this module refuses.
63
+ _PICK_FIELDS = (
64
+ "n",
65
+ "plan_id",
66
+ "phase_id",
67
+ "phase_title",
68
+ "phase_chain",
69
+ "doc_path",
70
+ "subagent_type",
71
+ "mode",
72
+ "pick_kind",
73
+ "files",
74
+ "gates_on",
75
+ "reserve_paths",
76
+ "prompt_text",
77
+ )
78
+
79
+
80
+ def sidecar_path_for(packet_path: Path) -> Path:
81
+ """The `.prompts.json` path beside a packet `.md` — the one naming rule.
82
+
83
+ `next-up-2026-06-01-13.md` → `next-up-2026-06-01-13.prompts.json`. Kept here
84
+ (not inlined at the call sites) so the writer and `dos.preflight`'s reader
85
+ derive the sibling path through the *same* function — a future rename touches
86
+ one line. Mirrors `load_packet_sidecar`'s
87
+ `packet_path.with_name(packet_path.stem + ".prompts.json")`.
88
+ """
89
+ return packet_path.with_name(packet_path.stem + ".prompts.json")
90
+
91
+
92
+ def _coerce_pick(raw: dict, *, index: int) -> dict:
93
+ """Project a renderer pick onto the sidecar pick contract (`_PICK_FIELDS`).
94
+
95
+ Only the contract fields are carried (a renderer pick holds far more
96
+ internal state — `anchors`, `audit`, `one_hop_metric`, … — that the worker
97
+ launch does not need). `n` defaults to the 1-based position so a pick that
98
+ omitted it still numbers correctly. `prompt_text` is taken verbatim from the
99
+ caller — this module does NOT render it (that is the host renderer's job via
100
+ its own template); the kernel only serializes and verifies what it is given.
101
+ """
102
+ out: dict[str, Any] = {}
103
+ for f in _PICK_FIELDS:
104
+ if f in raw:
105
+ out[f] = raw[f]
106
+ out.setdefault("n", index)
107
+ # Normalize the load-bearing body to a string (never None) so the reader's
108
+ # `len(p.get("prompt_text") or "")` and our own empty-check agree.
109
+ out["prompt_text"] = str(out.get("prompt_text") or "")
110
+ return out
111
+
112
+
113
+ def build_sidecar_payload(picks: list[dict]) -> dict:
114
+ """The full sidecar document: `{schema, picks}` — what gets written to disk.
115
+
116
+ Separated from `write_packet_sidecar` so a caller (and a test) can build the
117
+ exact payload without touching the filesystem. Each pick is projected onto
118
+ `_PICK_FIELDS`; `prompt_text` is carried verbatim.
119
+ """
120
+ return {
121
+ "schema": SIDECAR_SCHEMA,
122
+ "picks": [_coerce_pick(p, index=i) for i, p in enumerate(picks, start=1)],
123
+ }
124
+
125
+
126
+ def write_packet_sidecar(packet_path: Path, picks: list[dict]) -> Path:
127
+ """Write `<packet>.prompts.json` beside the packet `.md` and return its path.
128
+
129
+ The canonical serializer the host renderer calls. `dos.preflight.load_packet_sidecar`
130
+ reads exactly this shape (same schema token, same per-pick `prompt_text`
131
+ field), so a packet written here loads as `SIDECAR_PRESENT` with non-empty
132
+ bodies — the write/read contract is closed by construction (a test asserts
133
+ the round-trip).
134
+
135
+ Does NOT validate shippability — a caller that wants the producer-side
136
+ guarantee calls `assert_packet_shippable` after writing (the renderer does
137
+ both: write, then assert, then exit). Writing is kept separate from
138
+ verifying so the verify can also run standalone against a packet written by
139
+ an older renderer.
140
+ """
141
+ payload = build_sidecar_payload(picks)
142
+ side = sidecar_path_for(packet_path)
143
+ side.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
144
+ return side
145
+
146
+
147
+ # ---------------------------------------------------------------------------
148
+ # Producer-side shippability verify — the kernel does not believe the renderer.
149
+ # ---------------------------------------------------------------------------
150
+
151
+ # `assert_packet_shippable` outcome reasons. These are the structured causes a
152
+ # refuse carries; the host renderer maps a refuse onto the `RENDERER_SIDECAR_DROPPED`
153
+ # WedgeReason for the `.verdict` envelope it writes.
154
+ SHIPPABLE_OK = "ok"
155
+ SHIPPABLE_ABSENT = "sidecar_absent" # the renderer never wrote the sidecar
156
+ SHIPPABLE_CORRUPT = "sidecar_corrupt" # sidecar on disk but bad JSON / wrong shape
157
+ SHIPPABLE_EMPTY_BODIES = "sidecar_empty_bodies" # sidecar present but ≥1 pick body is empty
158
+
159
+
160
+ @dataclass(frozen=True)
161
+ class ShippableVerdict:
162
+ """The result of the producer-side sidecar verify.
163
+
164
+ `refuse` is the single load-bearing bool the renderer branches on before
165
+ `Saved:`/exit-0. `reason_code` is one of the `SHIPPABLE_*` constants
166
+ (machine-readable, stable). `reason` is the operator-facing string.
167
+ `empty_body_picks` lists the 1-based pick numbers whose `prompt_text` was
168
+ empty (so the renderer can name them, the same way the downstream gate names
169
+ `body_empty_picks`). `rendered_pick_count` echoes the input so the envelope
170
+ can record what the packet claimed.
171
+ """
172
+
173
+ refuse: bool
174
+ reason_code: str
175
+ reason: str | None = None
176
+ empty_body_picks: list[int] = field(default_factory=list)
177
+ rendered_pick_count: int = 0
178
+
179
+ def envelope(self) -> dict:
180
+ """A small JSON-able dict for the renderer's `.verdict`/stderr envelope."""
181
+ return {
182
+ "refuse": self.refuse,
183
+ "reason_code": self.reason_code,
184
+ "reason": self.reason,
185
+ "empty_body_picks": self.empty_body_picks,
186
+ "rendered_pick_count": self.rendered_pick_count,
187
+ }
188
+
189
+
190
+ def assert_packet_shippable(
191
+ packet_path: Path, *, rendered_pick_count: int
192
+ ) -> ShippableVerdict:
193
+ """Re-open the just-written sidecar and verify the prompt bodies are real.
194
+
195
+ The DOS thesis at the producer: the renderer's exit-0 `Saved:` is a
196
+ self-report the kernel does not trust. This re-reads the artifact from disk
197
+ (not from the in-memory picks the renderer *thinks* it wrote) and refuses if:
198
+
199
+ * `rendered_pick_count > 0` and the sidecar is **absent** — the renderer
200
+ rendered picks but never serialized their bodies (the FQ-420 root drop);
201
+ * the sidecar is **corrupt** — on disk but unreadable / wrong shape;
202
+ * the sidecar is **present** but one or more picks have an **empty
203
+ `prompt_text`** — a half-built payload that would launch empty workers.
204
+
205
+ Does NOT refuse when `rendered_pick_count <= 0`: a genuine empty DRAIN packet
206
+ legitimately has no sidecar and no bodies (refusing it would mislabel a true
207
+ drain as a renderer drop — the same carve-out `_sidecar_dropped_refusal`
208
+ makes downstream).
209
+
210
+ Reads from disk via `sidecar_path_for(packet_path)`. Pure (no git / network);
211
+ the only I/O is the single sidecar read.
212
+ """
213
+ if rendered_pick_count <= 0:
214
+ return ShippableVerdict(
215
+ refuse=False, reason_code=SHIPPABLE_OK, rendered_pick_count=rendered_pick_count
216
+ )
217
+
218
+ side = sidecar_path_for(packet_path)
219
+ if not side.exists():
220
+ return ShippableVerdict(
221
+ refuse=True,
222
+ reason_code=SHIPPABLE_ABSENT,
223
+ reason=(
224
+ f"sidecar_dropped:absent rendered_picks={rendered_pick_count} "
225
+ f"(renderer rendered picks but never wrote {side.name} — every "
226
+ f"worker prompt body would be empty)"
227
+ ),
228
+ rendered_pick_count=rendered_pick_count,
229
+ )
230
+
231
+ try:
232
+ doc = json.loads(side.read_text(encoding="utf-8"))
233
+ picks = doc.get("picks", []) if isinstance(doc, dict) else None
234
+ if not isinstance(picks, list):
235
+ raise ValueError("sidecar has no picks list")
236
+ except (OSError, json.JSONDecodeError, ValueError) as exc:
237
+ return ShippableVerdict(
238
+ refuse=True,
239
+ reason_code=SHIPPABLE_CORRUPT,
240
+ reason=(
241
+ f"sidecar_dropped:corrupt rendered_picks={rendered_pick_count} "
242
+ f"({side.name} exists but is unreadable/bad-shape: {exc})"
243
+ ),
244
+ rendered_pick_count=rendered_pick_count,
245
+ )
246
+
247
+ empty = [
248
+ int(p.get("n", i))
249
+ for i, p in enumerate(picks, start=1)
250
+ if not str(p.get("prompt_text") or "").strip()
251
+ ]
252
+ if empty:
253
+ return ShippableVerdict(
254
+ refuse=True,
255
+ reason_code=SHIPPABLE_EMPTY_BODIES,
256
+ reason=(
257
+ f"sidecar_empty_bodies picks={','.join(str(n) for n in empty)} "
258
+ f"({side.name} was written but those picks carry no prompt_text — "
259
+ f"a half-built payload)"
260
+ ),
261
+ empty_body_picks=empty,
262
+ rendered_pick_count=rendered_pick_count,
263
+ )
264
+
265
+ return ShippableVerdict(
266
+ refuse=False, reason_code=SHIPPABLE_OK, rendered_pick_count=rendered_pick_count
267
+ )