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
dos/self_modify.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""The SELF_MODIFY built-in admission predicate — the self-modification guard (ADM Phase 2, docs/73).
|
|
2
|
+
|
|
3
|
+
This is the first *real* second built-in predicate (the first, `DisjointnessPredicate`,
|
|
4
|
+
was a behavior-preserving refactor of the existing rule). It refuses a lease whose
|
|
5
|
+
requested file tree intersects the **orchestrator's own running code** — the kernel
|
|
6
|
+
modules that sit in a live dispatch loop's execution path.
|
|
7
|
+
|
|
8
|
+
Why this is a kernel concern (`project-dos-self-modification-hazard`, mechanism (a)):
|
|
9
|
+
editing the arbiter / classifiers / token rules *while a loop that depends on them
|
|
10
|
+
is live* is a T1 hazard — a packet that rewrites `arbiter.py` between two Step-0
|
|
11
|
+
admission checks changes the very logic deciding whether the next packet may run,
|
|
12
|
+
silently, mid-flight. The "natural DOS-kernel realization" of guarding against it is
|
|
13
|
+
a new typed arbiter refuse: intersect the requested tree with a frozen
|
|
14
|
+
`_DISPATCH_RUNTIME_FILES` set and refuse on a hit. ADM's predicate seam is the
|
|
15
|
+
vehicle; this is its first safety payload.
|
|
16
|
+
|
|
17
|
+
The override is `--force` and ONLY `--force` — the operator's explicit "yes, I am
|
|
18
|
+
editing the kernel between loop runs, I know what I'm doing" (the safe, human-in-loop
|
|
19
|
+
path the hazard memo calls for). A predicate can never force itself; `--force` skips
|
|
20
|
+
predicate refusals exactly as it skips the disjointness refuse (see `arbiter.arbitrate`).
|
|
21
|
+
|
|
22
|
+
Pure stdlib + the `_tree` prefix algebra — no I/O, no host names. The set is data,
|
|
23
|
+
pinned with a comment tying each entry to *why* it is runtime-critical, so a reviewer
|
|
24
|
+
can audit the blast radius of the guard at a glance.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from dos._tree import norm_tree_prefix as _norm_tree_prefix
|
|
30
|
+
from dos._tree import prefixes_collide as _prefixes_collide
|
|
31
|
+
from dos.admission import AdmissionRequest, AdmissionVerdict
|
|
32
|
+
|
|
33
|
+
# The typed reason a SELF_MODIFY refusal carries — declared in
|
|
34
|
+
# `dos.reasons.BASE_REASONS` so it is simultaneously emittable (here), verifiable
|
|
35
|
+
# (the registry's `category_for`), refusable (`is_refusal`), and `dos man
|
|
36
|
+
# wedge SELF_MODIFY`-documented (the Axis-1 completeness rail).
|
|
37
|
+
SELF_MODIFY_REASON = "SELF_MODIFY"
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# The T1 runtime set — the kernel modules in a LIVE dispatch loop's own decision
|
|
41
|
+
# path. Editing any of these mid-flight changes the logic that admits the NEXT
|
|
42
|
+
# packet, silently. Repo-relative POSIX paths (the form a lane tree carries). Each
|
|
43
|
+
# entry is annotated with WHY it is runtime-critical so the guard's blast radius
|
|
44
|
+
# is auditable. This is the T1 set from `project-dos-self-modification-hazard`,
|
|
45
|
+
# scoped to the kernel's *adjudication* path — NOT every kernel file (a lease
|
|
46
|
+
# editing `timeline.py`, pure post-hoc assembly, is not a live-decision hazard).
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
_DISPATCH_RUNTIME_FILES: tuple[str, ...] = (
|
|
49
|
+
# The admission kernel itself — the code that runs THIS very check. A packet
|
|
50
|
+
# rewriting it between two Step-0 calls changes whether the next loop admits.
|
|
51
|
+
"src/dos/arbiter.py",
|
|
52
|
+
# The admission-predicate seam + the self-modify guard — the conjunction
|
|
53
|
+
# runner and this predicate. Editing them mid-flight can disable the guard
|
|
54
|
+
# that is protecting the edit (the most direct self-defeat).
|
|
55
|
+
"src/dos/admission.py",
|
|
56
|
+
"src/dos/self_modify.py",
|
|
57
|
+
# The soft-overlap / tree-disjointness algebra the arbiter delegates its
|
|
58
|
+
# collision check to — the substance of "may these two lanes coexist."
|
|
59
|
+
"src/dos/lane_overlap.py",
|
|
60
|
+
"src/dos/_tree.py",
|
|
61
|
+
# The loop's go/no-go classifiers: whether a phase is gated, whether the loop
|
|
62
|
+
# should continue, the token-budget accounting those read. A live loop calls
|
|
63
|
+
# these every iteration; rewriting them mid-loop reshapes its control flow.
|
|
64
|
+
"src/dos/gate_classify.py",
|
|
65
|
+
"src/dos/loop_decide.py",
|
|
66
|
+
"src/dos/tokens.py",
|
|
67
|
+
# The structured-refusal vocabulary the loop emits/verifies against. Changing
|
|
68
|
+
# the reason set under a live loop desyncs producer↔oracle (the exact drift
|
|
69
|
+
# the registry exists to forbid), so it is a runtime-path edit.
|
|
70
|
+
"src/dos/wedge_reason.py",
|
|
71
|
+
"src/dos/reasons.py",
|
|
72
|
+
# The config seam — the lane taxonomy + paths a live arbiter reads on every
|
|
73
|
+
# admission. Re-pointing the workspace or rewriting the taxonomy mid-loop
|
|
74
|
+
# changes what "disjoint" even means for the next packet.
|
|
75
|
+
"src/dos/config.py",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Pre-normalized prefixes (truncated at the first glob `*`, `\\`→`/`), computed
|
|
79
|
+
# once at import. The intersection test compares against these — the same
|
|
80
|
+
# normalization `lane_overlap._shared_count` / `_tree.lane_trees_disjoint` use,
|
|
81
|
+
# so "does this lane touch a runtime file" is decided by the identical algebra
|
|
82
|
+
# the rest of the kernel trusts for collision detection.
|
|
83
|
+
_RUNTIME_PREFIXES: tuple[str, ...] = tuple(
|
|
84
|
+
_norm_tree_prefix(p) for p in _DISPATCH_RUNTIME_FILES
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _tree_touches_runtime(
|
|
89
|
+
requested_tree: list[str],
|
|
90
|
+
runtime_files: tuple[str, ...] = _DISPATCH_RUNTIME_FILES,
|
|
91
|
+
) -> list[str]:
|
|
92
|
+
"""Return the runtime files a requested tree would touch (empty = none).
|
|
93
|
+
|
|
94
|
+
Prefix-collision in BOTH directions (a requested `src/dos/` glob contains
|
|
95
|
+
`src/dos/arbiter.py`; a requested `src/dos/arbiter.py` IS a runtime file) —
|
|
96
|
+
the same rule `_tree.lane_trees_disjoint` uses, now shared verbatim via
|
|
97
|
+
`_tree.prefixes_collide`. Returns the offending runtime paths (the original,
|
|
98
|
+
un-normalized entries) so the refusal can name exactly what was hit, in
|
|
99
|
+
declaration order.
|
|
100
|
+
|
|
101
|
+
A **leading-glob** request (`**/*`) normalizes to the empty (universal)
|
|
102
|
+
prefix, which collides with EVERY runtime file — so a whole-repo lease is
|
|
103
|
+
correctly flagged as touching the kernel's own code, not waved through as
|
|
104
|
+
"touches nothing." Only literally-blank entries are filtered (no path
|
|
105
|
+
information); the empty prefix from a real glob is kept. (This is the
|
|
106
|
+
self-modify half of the `**/*`-normalizes-to-empty bug.)
|
|
107
|
+
|
|
108
|
+
``runtime_files`` is the kernel-source set to check against. It defaults to
|
|
109
|
+
the full static `_DISPATCH_RUNTIME_FILES`, but a boundary caller hands in the
|
|
110
|
+
subset that actually EXISTS under the served workspace (`existing_runtime_files`)
|
|
111
|
+
— so a `**/*` lane in a *foreign* repo (which has no `src/dos/*.py`) collides
|
|
112
|
+
with the empty set and is admitted, while the same lane in the DOS repo itself
|
|
113
|
+
is refused. The default keeps the pure, workspace-unaware behavior for direct
|
|
114
|
+
callers and tests.
|
|
115
|
+
"""
|
|
116
|
+
hits: list[str] = []
|
|
117
|
+
req_prefixes = [_norm_tree_prefix(p) for p in (requested_tree or []) if p]
|
|
118
|
+
if not req_prefixes:
|
|
119
|
+
return hits
|
|
120
|
+
for original in runtime_files:
|
|
121
|
+
rp = _norm_tree_prefix(original)
|
|
122
|
+
if any(_prefixes_collide(nr, rp) for nr in req_prefixes):
|
|
123
|
+
hits.append(original)
|
|
124
|
+
return hits
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class SelfModifyPredicate:
|
|
128
|
+
"""Refuse a lease whose tree includes the orchestrator's own running code.
|
|
129
|
+
|
|
130
|
+
Always-on, like `DisjointnessPredicate` (`admission.built_in_predicates`).
|
|
131
|
+
Unlike disjointness, it is **request-absolute**: it does NOT depend on the
|
|
132
|
+
live lease — self-modification is a hazard regardless of what else is
|
|
133
|
+
running — so it answers from the REQUEST alone and ignores ``live_lease``.
|
|
134
|
+
(It still implements the per-lease predicate signature so it composes in the
|
|
135
|
+
same conjunction; it returns the same verdict for every live lease, which is
|
|
136
|
+
harmless: `run_predicates` short-circuits on the first refusal.)
|
|
137
|
+
|
|
138
|
+
It fires on EVERY admit path, including an otherwise-idle repo with NO live
|
|
139
|
+
leases: `run_predicates` runs the conjunction once against a synthetic
|
|
140
|
+
empty-lease sentinel exactly so request-absolute predicates are not skipped
|
|
141
|
+
when nothing else is live, and `arbiter.arbitrate` gates its cluster /
|
|
142
|
+
exclusive-lane / keyword fast-paths through that conjunction (it does not
|
|
143
|
+
return `acquire` before consulting the predicates). So a self-modifying lease
|
|
144
|
+
is refused whether the repo is busy or idle, whether the request is a cluster,
|
|
145
|
+
an exclusive lane, or a keyword. `--force` is the sole override. (This closes
|
|
146
|
+
the idle-repo / fast-path gaps an adversarial review caught; see
|
|
147
|
+
`test_self_modify_*` and `TestSelfModifyGatesEveryAdmitPath` for the pinned
|
|
148
|
+
contract across all paths.)
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
name = "self-modify"
|
|
152
|
+
|
|
153
|
+
def __init__(self, runtime_files: tuple[str, ...] = _DISPATCH_RUNTIME_FILES):
|
|
154
|
+
"""``runtime_files`` is the kernel-source set this guard protects.
|
|
155
|
+
|
|
156
|
+
Defaults to the full static `_DISPATCH_RUNTIME_FILES` (pure, workspace-
|
|
157
|
+
unaware — the safe default for a direct/test caller). A boundary builder
|
|
158
|
+
(`admission.built_in_predicates(workspace=…)`) constructs the predicate
|
|
159
|
+
with the subset that actually EXISTS under the served workspace
|
|
160
|
+
(`existing_runtime_files`), so the guard fires only where the kernel
|
|
161
|
+
source it protects is genuinely present — the DOS repo serving itself,
|
|
162
|
+
not a foreign repo whose `**/*` lane cannot edit a `src/dos/` file that
|
|
163
|
+
isn't there. Stored verbatim; no I/O here (the existence probe already
|
|
164
|
+
ran at the boundary).
|
|
165
|
+
"""
|
|
166
|
+
self._runtime_files = tuple(runtime_files)
|
|
167
|
+
|
|
168
|
+
def __call__(self, request: AdmissionRequest, live_lease: dict,
|
|
169
|
+
config: object) -> AdmissionVerdict:
|
|
170
|
+
hits = _tree_touches_runtime(list(request.tree), self._runtime_files)
|
|
171
|
+
if not hits:
|
|
172
|
+
return AdmissionVerdict.admit()
|
|
173
|
+
shown = ", ".join(hits[:3]) + ("…" if len(hits) > 3 else "")
|
|
174
|
+
return AdmissionVerdict.refuse(
|
|
175
|
+
f"lane {request.lane!r} would edit the orchestrator's own running "
|
|
176
|
+
f"code ({shown}) — refusing to let a live loop rewrite the kernel "
|
|
177
|
+
f"that is adjudicating it (SELF_MODIFY). Pass --force only if you "
|
|
178
|
+
f"are deliberately editing the kernel between loop runs.",
|
|
179
|
+
reason_class=SELF_MODIFY_REASON,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# ---------------------------------------------------------------------------
|
|
184
|
+
# Boundary helper — the ONE place the existence I/O lives. Mirrors
|
|
185
|
+
# `admission.active_predicates` (entry-point discovery) and the liveness/arbitrate
|
|
186
|
+
# pattern: I/O is gathered at the CALL BOUNDARY and the result is handed to a pure
|
|
187
|
+
# predicate, never run inside `arbitrate` itself.
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
def existing_runtime_files(workspace) -> tuple[str, ...]:
|
|
190
|
+
"""The `_DISPATCH_RUNTIME_FILES` that actually exist under ``workspace``.
|
|
191
|
+
|
|
192
|
+
This is what makes the SELF_MODIFY guard **workspace-aware**: the static set
|
|
193
|
+
is the kernel's own source paths (`src/dos/arbiter.py`, …), which exist only
|
|
194
|
+
when DOS is serving its OWN repo. Against a foreign repo (or a fresh
|
|
195
|
+
scaffold) none of them resolve, so this returns ``()`` and a `**/*` lane
|
|
196
|
+
touches nothing — the correct admit. Against the DOS repo every entry
|
|
197
|
+
resolves and the guard fires on a whole-repo lease.
|
|
198
|
+
|
|
199
|
+
The single existence I/O of the self-modify guard. Called by
|
|
200
|
+
`admission.built_in_predicates(workspace=…)` at the boundary; the predicate
|
|
201
|
+
it feeds stays pure. ``workspace`` is a path-like (the `SubstrateConfig.workspace`);
|
|
202
|
+
a falsy/None workspace yields the full static set (cannot prove non-existence,
|
|
203
|
+
so stay conservative — the safe direction for a safety guard).
|
|
204
|
+
"""
|
|
205
|
+
if not workspace:
|
|
206
|
+
return _DISPATCH_RUNTIME_FILES
|
|
207
|
+
from pathlib import Path
|
|
208
|
+
root = Path(workspace)
|
|
209
|
+
return tuple(f for f in _DISPATCH_RUNTIME_FILES if (root / f).exists())
|