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/effect_witness.py ADDED
@@ -0,0 +1,393 @@
1
+ """effect_witness — did the world actually CHANGE the way the agent CLAIMED? (docs/181)
2
+
3
+ The result-state witness DOS named (docs/176/177) as its most valuable member: the
4
+ one tool-verification check whose value *grows* with model strength, because it does
5
+ not read the trajectory at all. Every in-trajectory detector (`tool_stream`,
6
+ `terminal_error`, `dangling_intent`) reads a distress *shape* the agent's own bytes
7
+ co-author, so a competent model fails them silently (docs/177: 83.3% of frontier
8
+ fails leave no in-trace signal). This module reads a different thing: an
9
+ **out-of-trajectory read-back of world state**, authored by a witness the agent did
10
+ not control, and asks whether the claimed effect is actually *present* in it.
11
+
12
+ The field shipped this in three shapes in early 2026 (docs/180) — Agent-Diff
13
+ (state-diff against a golden delta), VAGEN (a verifier agent that takes its OWN read
14
+ actions), Tool Receipts (an HMAC receipt the LLM cannot forge). This is DOS's
15
+ domain-free, deterministic, floor-disciplined version of the same idea, fused with
16
+ the apparatus the kernel already proved in `evidence.py`.
17
+
18
+ The one idea: a verdict is a JOIN of two independently-authored facts
19
+ =====================================================================
20
+
21
+ `effect_witness` does NOT verify by re-reading the agent's claim against itself — that
22
+ is the mirror-verifier trap (`[[consistency-is-not-grounding]]`): re-deriving an
23
+ author's own bytes is consistency, never grounding. It mints a verdict ONLY by
24
+ joining two facts with *different* byte-authors (the `derived_witness` /
25
+ `journal_delta`-vs-`git_delta` law, docs/179):
26
+
27
+ 1. the **claim** — what the agent ASSERTED it did to the world (an `EffectClaim`:
28
+ an opaque effect key the agent narrated, e.g. "quiz:Classic-Art-History created"
29
+ or "row id=42 inserted in table orders"). The agent authored this. It is the
30
+ forgeable floor — on its own it can never grant belief.
31
+ 2. the **read-back** — an `evidence.EvidenceFacts` from a witness that RE-READ the
32
+ world from a surface the agent did not author (a fresh GET against the live API,
33
+ a state-snapshot diff, an OS-recorded query result). The witness authored this.
34
+
35
+ The verdict is the JOIN: *is the claimed effect PRESENT in the witnessed state?* —
36
+ and crucially the join's TRUST is capped by the read-back's `accountability`, exactly
37
+ as `believe_under_floor` requires. A claim "confirmed" only by re-reading the agent's
38
+ own narration is structurally incapable of CONFIRMED here; the read-back must come
39
+ from a non-forgeable rung. This is the §5a satisfaction-predicate line held: we never
40
+ ask the agent's own bytes "is the answer right?" — we ask an independent witness "is
41
+ the claimed change THERE?", which is a presence question over non-forgeable bytes.
42
+
43
+ Why "presence" and not "correctness"
44
+ ====================================
45
+
46
+ We deliberately verify **claim ⊆ witnessed-delta** (was the change the agent claimed
47
+ actually made?), not "is the end-state globally correct?". Global correctness needs a
48
+ gold state (a benchmark oracle has one; a live deployment does not). Presence needs
49
+ only the agent's claim + a read-back, both of which a live runtime HAS. This is the
50
+ honest, domain-free slice: DOS confirms the *specific effect the agent took credit
51
+ for*, refutes it when the witness shows it absent, and abstains when no accountable
52
+ witness could be reached — never inventing a gold state it cannot have.
53
+
54
+ The four-valued verdict (the typed-verdict family)
55
+ ==================================================
56
+
57
+ CONFIRMED — an accountable (non-forgeable) witness re-read the world and the
58
+ claimed effect is PRESENT. The only value that grants belief; gated by
59
+ the floor (a forgeable read-back can never reach it).
60
+ REFUTED — an accountable witness re-read the world and the claimed effect is
61
+ ABSENT (the agent said it created the quiz; the fresh GET shows no such
62
+ quiz). The load-bearing value: this is the silent frontier-fail
63
+ (docs/177) made VISIBLE — a confidently-narrated success the world
64
+ does not corroborate. Stronger than "no signal".
65
+ UNWITNESSED — no accountable witness could be reached, OR the only read-back was on
66
+ the forgeable floor (the agent re-read its own surface). The honest
67
+ abstain — what every degrade lands on. Distinct from REFUTED: we could
68
+ not tell, not "we checked and it's absent".
69
+ NO_CLAIM — the agent asserted no checkable effect (free prose, "I'm done"). There
70
+ is nothing to witness; the `claim_extract` abstain-never-invent law,
71
+ restated for effects. (A consumer reads this as "nothing to do here",
72
+ NOT as a pass.)
73
+
74
+ PURE — no I/O. The claim was extracted at the boundary (`claim_extract` or a host
75
+ adapter) and the read-back was gathered at the boundary (`evidence.gather_evidence`
76
+ over a `drivers/*` witness). This module only JOINS them. Sits in the kernel layer
77
+ beside `evidence`/`liveness`/`completion`. A real read-back witness (a state-diff
78
+ prober, an HTTP re-GET, an HMAC-receipt checker) lives in a driver — it imports the
79
+ kernel; the kernel never imports it.
80
+ """
81
+
82
+ from __future__ import annotations
83
+
84
+ import enum
85
+ from dataclasses import dataclass, field
86
+
87
+ from dos.evidence import (
88
+ Accountability,
89
+ BeliefVerdict,
90
+ EvidenceFacts,
91
+ EvidenceStance,
92
+ believe_under_floor,
93
+ )
94
+
95
+ __all__ = [
96
+ "EffectClaim",
97
+ "EffectStance",
98
+ "EffectWitnessVerdict",
99
+ "witness_effect",
100
+ "PRESENT",
101
+ "ABSENT",
102
+ "INDETERMINATE",
103
+ ]
104
+
105
+
106
+ # ---------------------------------------------------------------------------
107
+ # The claim side — what the agent asserted it did to the world.
108
+ # ---------------------------------------------------------------------------
109
+
110
+
111
+ @dataclass(frozen=True)
112
+ class EffectClaim:
113
+ """One checkable effect the agent ASSERTED it produced.
114
+
115
+ `key` is the OPAQUE effect identity the join is over — the host/extractor decides
116
+ its grammar (`"quiz:Classic-Art-History"`, `"orders:row:42"`, an idempotency key).
117
+ It is the bridge between "what the agent said" and "what to look for in the
118
+ read-back": a witness re-reads the world and reports whether an effect with THIS
119
+ key is present. `subject` is the witness's correlation handle (often == key, but a
120
+ host may map a claim key to a different probe subject — e.g. the command/URL that
121
+ re-reads it). `narrated` is the agent's original phrasing, carried for the
122
+ operator surface (legible distrust — show WHAT was claimed), never parsed for
123
+ truth. The claim is, by construction, `AGENT_AUTHORED` — the forgeable floor; it
124
+ is the thing to be checked, never itself evidence.
125
+ """
126
+
127
+ key: str
128
+ subject: str = ""
129
+ narrated: str = ""
130
+
131
+ def probe_subject(self) -> str:
132
+ """The handle to hand a read-back witness — `subject` if set, else `key`."""
133
+ return self.subject or self.key
134
+
135
+
136
+ # ---------------------------------------------------------------------------
137
+ # The read-back side reports one of three *presence* answers about the effect.
138
+ # These are NOT the witness's reachability (that is EvidenceFacts.reachable/stance);
139
+ # they are what an accountable, reached witness SAW about the claimed effect's
140
+ # presence in world state. A host's read-back witness encodes its answer in the
141
+ # EvidenceFacts stance it returns (see witness_effect's mapping), but we also accept
142
+ # an explicit presence tag for a witness that distinguishes "reached, effect absent"
143
+ # from "reached, a DIFFERENT effect present".
144
+ # ---------------------------------------------------------------------------
145
+
146
+
147
+ class EffectStance(str, enum.Enum):
148
+ """What an accountable read-back saw about the CLAIMED effect's presence."""
149
+
150
+ PRESENT = "PRESENT" # the claimed effect IS in the witnessed state
151
+ ABSENT = "ABSENT" # the witness re-read and the effect is NOT there
152
+ INDETERMINATE = "INDETERMINATE" # reached, but cannot tell about THIS effect
153
+
154
+ def __str__(self) -> str: # pragma: no cover - trivial
155
+ return self.value
156
+
157
+
158
+ PRESENT = EffectStance.PRESENT
159
+ ABSENT = EffectStance.ABSENT
160
+ INDETERMINATE = EffectStance.INDETERMINATE
161
+
162
+
163
+ # ---------------------------------------------------------------------------
164
+ # The verdict.
165
+ # ---------------------------------------------------------------------------
166
+
167
+
168
+ class _Verdict(str, enum.Enum):
169
+ CONFIRMED = "CONFIRMED"
170
+ REFUTED = "REFUTED"
171
+ UNWITNESSED = "UNWITNESSED"
172
+ NO_CLAIM = "NO_CLAIM"
173
+
174
+ def __str__(self) -> str: # pragma: no cover - trivial
175
+ return self.value
176
+
177
+
178
+ @dataclass(frozen=True)
179
+ class EffectWitnessVerdict:
180
+ """The folded answer: did an accountable witness corroborate the claimed effect?
181
+
182
+ `verdict` is the four-valued result token (CONFIRMED / REFUTED / UNWITNESSED /
183
+ NO_CLAIM). `believe` is the positive bit a consumer may consume — True ONLY on
184
+ CONFIRMED (a non-forgeable witness saw the effect present). `refuted` is surfaced
185
+ separately because a refutation by an accountable witness is the silent-fail
186
+ detector — a consumer may RED-flag on it even though `believe` is also False.
187
+ `claim_key`/`narrated` echo what was checked; `witness`/`accountability` name the
188
+ read-back behind the verdict; `reason` is the one-line legible-distrust string for
189
+ `dos doctor` / the decisions queue / `--json`.
190
+ """
191
+
192
+ verdict: _Verdict
193
+ believe: bool
194
+ refuted: bool
195
+ reason: str
196
+ claim_key: str = ""
197
+ narrated: str = ""
198
+ witness: str = ""
199
+ accountability: Accountability | None = None
200
+ silent_witnesses: tuple[str, ...] = field(default_factory=tuple)
201
+
202
+ @property
203
+ def is_confirmed(self) -> bool:
204
+ return self.verdict is _Verdict.CONFIRMED
205
+
206
+ @property
207
+ def is_refuted(self) -> bool:
208
+ return self.verdict is _Verdict.REFUTED
209
+
210
+ def to_dict(self) -> dict:
211
+ return {
212
+ "verdict": self.verdict.value,
213
+ "believe": self.believe,
214
+ "refuted": self.refuted,
215
+ "reason": self.reason,
216
+ "claim_key": self.claim_key,
217
+ "narrated": self.narrated,
218
+ "witness": self.witness,
219
+ "accountability": self.accountability.value if self.accountability else None,
220
+ "silent_witnesses": list(self.silent_witnesses),
221
+ }
222
+
223
+
224
+ def _effect_stance_of(facts: EvidenceFacts) -> EffectStance:
225
+ """Map a read-back `EvidenceFacts` onto a presence answer about the claimed effect.
226
+
227
+ The default, conservative mapping for a witness that does NOT carry an explicit
228
+ presence tag (most do not — they answer "did the acceptance check pass?"):
229
+
230
+ * a reached ATTESTED read → PRESENT (the witness confirmed the effect)
231
+ * a reached REFUTED read → ABSENT (the witness disconfirmed the effect)
232
+ * NO_SIGNAL / unreachable → INDETERMINATE (could not tell)
233
+
234
+ A richer witness that distinguishes "effect absent" from "reached but can't tell
235
+ about this specific effect" encodes that by returning REFUTED vs a reached
236
+ NO_SIGNAL; we honor the stance it chose. We never UPGRADE a stance — a witness's
237
+ own conservatism is preserved.
238
+ """
239
+ if facts.reachable and facts.stance is EvidenceStance.ATTESTED:
240
+ return EffectStance.PRESENT
241
+ if facts.reachable and facts.stance is EvidenceStance.REFUTED:
242
+ return EffectStance.ABSENT
243
+ return EffectStance.INDETERMINATE
244
+
245
+
246
+ def witness_effect(
247
+ claim: EffectClaim | None,
248
+ readbacks: "tuple[EvidenceFacts, ...] | list[EvidenceFacts]",
249
+ ) -> EffectWitnessVerdict:
250
+ """Join a claimed effect to its read-back witnesses under the floor discipline.
251
+
252
+ The pure keystone. The rule, structural and not a host-tunable threshold:
253
+
254
+ > CONFIRMED ⟺ at least one read-back on a NON-FORGEABLE rung
255
+ > (`OS_RECORDED`/`THIRD_PARTY`) was reached and saw the effect PRESENT.
256
+ > REFUTED ⟺ (no non-forgeable witness confirmed it) AND at least one
257
+ > non-forgeable read-back was reached and saw the effect ABSENT.
258
+ > NO_CLAIM ⟺ there is no claim to check.
259
+ > UNWITNESSED otherwise — no accountable witness reached a presence answer
260
+ > (only forgeable-floor reads, or only NO_SIGNAL).
261
+
262
+ The floor is enforced by delegating the belief decision to
263
+ `evidence.believe_under_floor` — a forgeable-floor read-back (the agent re-read its
264
+ OWN surface, `AGENT_AUTHORED`) is recorded but structurally cannot CONFIRM or, by
265
+ the symmetric rule, REFUTE on its own. So the worst a lying same-surface witness can
266
+ do is be IGNORED (a safe-direction no-op), never manufacture a CONFIRMED for an
267
+ effect that did not happen, nor a REFUTED for one that did.
268
+
269
+ PURE — no I/O. Claim extracted at the boundary, read-backs gathered at the boundary
270
+ (`evidence.gather_evidence`); this only folds.
271
+ """
272
+ if claim is None or not (claim.key or "").strip():
273
+ return EffectWitnessVerdict(
274
+ verdict=_Verdict.NO_CLAIM,
275
+ believe=False,
276
+ refuted=False,
277
+ reason="no checkable effect claimed — nothing to witness (abstain, never invent)",
278
+ )
279
+
280
+ facts = tuple(readbacks)
281
+
282
+ # Reuse the floor's belief fold for the PRESENT side: an ATTESTED read-back means
283
+ # "effect present", so a believed BeliefVerdict over the read-backs == an
284
+ # accountable witness saw the effect present. This keeps the floor discipline in
285
+ # ONE place (the dual-of-overlap_policy guarantee) rather than re-implementing it.
286
+ belief: BeliefVerdict = believe_under_floor(facts)
287
+
288
+ # Identify, per the same accountability rule, whether any non-forgeable witness saw
289
+ # the effect ABSENT (a REFUTED read-back on a non-forgeable rung). believe_under_floor
290
+ # already computes `refuted` exactly this way, so we read it off the fold.
291
+ confirmed = belief.believe
292
+ refuted_by_accountable = belief.refuted
293
+
294
+ # Name the witness behind the headline answer, for the operator surface.
295
+ def _first_nonforgeable(stance: EvidenceStance) -> EvidenceFacts | None:
296
+ for f in facts:
297
+ if (
298
+ f.reachable
299
+ and f.stance is stance
300
+ and not f.accountability.is_agent_authored
301
+ ):
302
+ return f
303
+ return None
304
+
305
+ silent = tuple(
306
+ f.source_name
307
+ for f in facts
308
+ if not (f.reachable and f.stance in (EvidenceStance.ATTESTED, EvidenceStance.REFUTED))
309
+ )
310
+
311
+ if confirmed and refuted_by_accountable:
312
+ # Accountable witnesses disagree — the CONFLICT case. Surface both; a consumer
313
+ # routes to a human (the believe_under_floor CONFLICT posture). We do NOT
314
+ # collapse to CONFIRMED: a disagreement among accountable witnesses is not a
315
+ # clean confirmation.
316
+ w = _first_nonforgeable(EvidenceStance.ATTESTED)
317
+ return EffectWitnessVerdict(
318
+ verdict=_Verdict.REFUTED, # conservative: a contested effect is not believed
319
+ believe=False,
320
+ refuted=True,
321
+ reason=(
322
+ f"CONFLICT — accountable witnesses disagree on effect {claim.key!r}: "
323
+ f"{', '.join(belief.attesting)} present, {', '.join(belief.refuting)} absent "
324
+ f"(route to a human)"
325
+ ),
326
+ claim_key=claim.key,
327
+ narrated=claim.narrated,
328
+ witness=(w.source_name if w else ""),
329
+ accountability=(w.accountability if w else None),
330
+ silent_witnesses=silent,
331
+ )
332
+
333
+ if confirmed:
334
+ w = _first_nonforgeable(EvidenceStance.ATTESTED)
335
+ return EffectWitnessVerdict(
336
+ verdict=_Verdict.CONFIRMED,
337
+ believe=True,
338
+ refuted=False,
339
+ reason=(
340
+ f"CONFIRMED — non-forgeable witness re-read the world and effect "
341
+ f"{claim.key!r} is PRESENT: {', '.join(belief.attesting)}"
342
+ ),
343
+ claim_key=claim.key,
344
+ narrated=claim.narrated,
345
+ witness=(w.source_name if w else ""),
346
+ accountability=(w.accountability if w else None),
347
+ silent_witnesses=silent,
348
+ )
349
+
350
+ if refuted_by_accountable:
351
+ w = _first_nonforgeable(EvidenceStance.REFUTED)
352
+ return EffectWitnessVerdict(
353
+ verdict=_Verdict.REFUTED,
354
+ believe=False,
355
+ refuted=True,
356
+ reason=(
357
+ f"REFUTED — non-forgeable witness re-read the world and effect "
358
+ f"{claim.key!r} is ABSENT: {', '.join(belief.refuting)} "
359
+ f"(a narrated success the world does not corroborate)"
360
+ ),
361
+ claim_key=claim.key,
362
+ narrated=claim.narrated,
363
+ witness=(w.source_name if w else ""),
364
+ accountability=(w.accountability if w else None),
365
+ silent_witnesses=silent,
366
+ )
367
+
368
+ # Nothing accountable reached a presence answer — abstain. If something attested on
369
+ # the forgeable floor only, say WHY it didn't count (the believe_under_floor
370
+ # forgeable-floor reason), so an operator sees the same-surface read-back was
371
+ # ignored on purpose.
372
+ if belief.attesting:
373
+ reason = (
374
+ f"UNWITNESSED — effect {claim.key!r} was only re-read on the forgeable floor "
375
+ f"(AGENT_AUTHORED: {', '.join(belief.attesting)}); no accountable witness — "
376
+ f"cannot confirm (the agent re-reading its own surface is not corroboration)"
377
+ )
378
+ else:
379
+ reason = (
380
+ f"UNWITNESSED — no accountable witness reached effect {claim.key!r} "
381
+ f"(no signal); cannot tell whether it happened"
382
+ )
383
+ return EffectWitnessVerdict(
384
+ verdict=_Verdict.UNWITNESSED,
385
+ believe=False,
386
+ refuted=False,
387
+ reason=reason,
388
+ claim_key=claim.key,
389
+ narrated=claim.narrated,
390
+ witness="",
391
+ accountability=None,
392
+ silent_witnesses=silent,
393
+ )