pdl-taskmaster 2.4.0__py3-none-any.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 (92) hide show
  1. pdl_taskmaster/__init__.py +6 -0
  2. pdl_taskmaster/contracts/AUTHORITY_MAP.json +19 -0
  3. pdl_taskmaster/contracts/CALIBRATION.json +7 -0
  4. pdl_taskmaster/contracts/CONTRACT_MANIFEST.json +231 -0
  5. pdl_taskmaster/contracts/EXECUTION_CONTRACT.json +615 -0
  6. pdl_taskmaster/contracts/IMPLEMENTATION_BOUNDARY.json +32 -0
  7. pdl_taskmaster/contracts/VERIFICATION_CONTRACT.json +379 -0
  8. pdl_taskmaster/contracts/standards/ARTIFACT_STANDARD.md +7 -0
  9. pdl_taskmaster/contracts/standards/AUTHORITY_STANDARD.md +17 -0
  10. pdl_taskmaster/contracts/standards/CONFORMANCE_STANDARD.md +15 -0
  11. pdl_taskmaster/contracts/standards/CONTEXT_STANDARD.md +15 -0
  12. pdl_taskmaster/contracts/standards/EXECUTION_STANDARD.md +14 -0
  13. pdl_taskmaster/contracts/standards/HANDOFF_STANDARD.md +21 -0
  14. pdl_taskmaster/contracts/standards/INSTALLATION_STANDARD.md +17 -0
  15. pdl_taskmaster/contracts/standards/PDL_STANDARD.md +19 -0
  16. pdl_taskmaster/contracts/standards/PROMPT_STANDARD.md +13 -0
  17. pdl_taskmaster/contracts/standards/PROTOCOL_STANDARD.md +17 -0
  18. pdl_taskmaster/contracts/standards/RESPONSE_PLAN_STANDARD.md +24 -0
  19. pdl_taskmaster/contracts/standards/RESULT_STANDARD.md +35 -0
  20. pdl_taskmaster/contracts/standards/REVIEW_STANDARD.md +31 -0
  21. pdl_taskmaster/contracts/standards/SEMANTIC_INPUT_STANDARD.md +15 -0
  22. pdl_taskmaster/contracts/standards/TASK_SEMANTICS_STANDARD.md +9 -0
  23. pdl_taskmaster/controller/__init__.py +0 -0
  24. pdl_taskmaster/controller/mechanical_controller.py +542 -0
  25. pdl_taskmaster/controller/schemas/activation_decision.schema.json +34 -0
  26. pdl_taskmaster/controller/schemas/artifact_body.schema.json +14 -0
  27. pdl_taskmaster/controller/schemas/artifact_review_facts.schema.json +91 -0
  28. pdl_taskmaster/controller/schemas/bootstrap_analysis.schema.json +60 -0
  29. pdl_taskmaster/controller/schemas/execution_draft.schema.json +47 -0
  30. pdl_taskmaster/controller/schemas/execution_input_decision.schema.json +43 -0
  31. pdl_taskmaster/controller/schemas/execution_outcome.schema.json +201 -0
  32. pdl_taskmaster/controller/schemas/plan_artifact.schema.json +14 -0
  33. pdl_taskmaster/controller/schemas/prompt_artifact.schema.json +63 -0
  34. pdl_taskmaster/controller/schemas/protocol_discussion.schema.json +8 -0
  35. pdl_taskmaster/controller/schemas/result_ir_repair.schema.json +140 -0
  36. pdl_taskmaster/eval/__init__.py +1 -0
  37. pdl_taskmaster/eval/build_adversarial_battery.py +351 -0
  38. pdl_taskmaster/eval/compare_eval_runs.py +251 -0
  39. pdl_taskmaster/eval/control_api_call.py +428 -0
  40. pdl_taskmaster/eval/export_rlcd_dataset.py +799 -0
  41. pdl_taskmaster/eval/fidelity_scan.py +268 -0
  42. pdl_taskmaster/eval/gen_fidelity_battery.py +457 -0
  43. pdl_taskmaster/eval/leak_scan.py +260 -0
  44. pdl_taskmaster/eval/rerecord_fixtures.py +139 -0
  45. pdl_taskmaster/eval/run_canary_shape_probe.py +229 -0
  46. pdl_taskmaster/eval/run_dual_gate_probe.py +404 -0
  47. pdl_taskmaster/eval/run_qualified_batch.py +841 -0
  48. pdl_taskmaster/eval/summarize_run.py +194 -0
  49. pdl_taskmaster/host/__init__.py +1 -0
  50. pdl_taskmaster/host/app.py +164 -0
  51. pdl_taskmaster/host/cli.py +100 -0
  52. pdl_taskmaster/host/repl.py +866 -0
  53. pdl_taskmaster/observation/__init__.py +1 -0
  54. pdl_taskmaster/observation/cli.py +47 -0
  55. pdl_taskmaster/observation/observed_session.py +219 -0
  56. pdl_taskmaster/observation/parsers.py +66 -0
  57. pdl_taskmaster/observation/records.py +58 -0
  58. pdl_taskmaster/observation/session.py +3 -0
  59. pdl_taskmaster/observation/sink.py +3 -0
  60. pdl_taskmaster/observation/sinks.py +20 -0
  61. pdl_taskmaster/providers/README.md +66 -0
  62. pdl_taskmaster/providers/__init__.py +1 -0
  63. pdl_taskmaster/providers/api_worker.py +411 -0
  64. pdl_taskmaster/providers/base.py +26 -0
  65. pdl_taskmaster/providers/codex_worker.py +328 -0
  66. pdl_taskmaster/providers/fixtures.py +157 -0
  67. pdl_taskmaster/providers/live_stub.py +66 -0
  68. pdl_taskmaster/providers/recorded.py +120 -0
  69. pdl_taskmaster/py.typed +1 -0
  70. pdl_taskmaster/runtime/__init__.py +0 -0
  71. pdl_taskmaster/runtime/context_compiler.py +151 -0
  72. pdl_taskmaster/runtime/model_classification.py +290 -0
  73. pdl_taskmaster/runtime/normative_store.py +157 -0
  74. pdl_taskmaster/runtime/operation_bridge.py +336 -0
  75. pdl_taskmaster/runtime/presentation.py +18 -0
  76. pdl_taskmaster/runtime/quarantine.py +91 -0
  77. pdl_taskmaster/runtime/result_ir.py +401 -0
  78. pdl_taskmaster/runtime/semantic_observer.py +40 -0
  79. pdl_taskmaster/runtime/session_engine.py +1168 -0
  80. pdl_taskmaster/runtime/standard_registry.py +55 -0
  81. pdl_taskmaster/runtime/wire_payloads.py +462 -0
  82. pdl_taskmaster/runtime/worker-bootstrap.txt +4 -0
  83. pdl_taskmaster/runtime/workspace.py +602 -0
  84. pdl_taskmaster/tracking/__init__.py +1 -0
  85. pdl_taskmaster/tracking/log_live_session.py +98 -0
  86. pdl_taskmaster/tracking/mlflow_sink.py +58 -0
  87. pdl_taskmaster/verify/verify_repl_baseline.py +299 -0
  88. pdl_taskmaster-2.4.0.dist-info/METADATA +155 -0
  89. pdl_taskmaster-2.4.0.dist-info/RECORD +92 -0
  90. pdl_taskmaster-2.4.0.dist-info/WHEEL +4 -0
  91. pdl_taskmaster-2.4.0.dist-info/entry_points.txt +2 -0
  92. pdl_taskmaster-2.4.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1 @@
1
+ """Observation suite for PDL-R2S."""
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+
7
+
8
+ def _show(path: Path) -> None:
9
+ for line in path.read_text(encoding="utf-8").splitlines():
10
+ if not line.strip():
11
+ continue
12
+ record = json.loads(line)
13
+ before = record.get("controller_before") or {}
14
+ after = record.get("controller_after") or {}
15
+ before_stage = (before.get("controller_state") or {}).get("stage")
16
+ after_stage = (after.get("controller_state") or {}).get("stage")
17
+ print(f"turn={record.get('turn_index')} {before_stage} -> {after_stage}")
18
+ for call in record.get("calls", []):
19
+ parsed = call.get("parsed")
20
+ if call.get("parse_error"):
21
+ parsed_summary = f"parse_error={call['parse_error']}"
22
+ else:
23
+ parsed_summary = json.dumps(parsed, sort_keys=True, default=str)[:300]
24
+ print(
25
+ f" {call.get('operation')} prompt={call.get('prompt_sha256')[:12]} "
26
+ f"response={call.get('response_sha256')[:12]} parsed={parsed_summary}"
27
+ )
28
+ event_kinds = [event.get("kind") for event in record.get("events", {}).get("new", [])]
29
+ if event_kinds:
30
+ print(f" events={event_kinds}")
31
+ if record.get("exception"):
32
+ print(f" exception={record['exception']}")
33
+
34
+
35
+ def main() -> int:
36
+ parser = argparse.ArgumentParser(description="PDL-R2S observation viewer")
37
+ sub = parser.add_subparsers(dest="command", required=True)
38
+ show = sub.add_parser("show", help="show recorded turns")
39
+ show.add_argument("--session", required=True, type=Path, help="path to session JSONL")
40
+ args = parser.parse_args()
41
+ if args.command == "show":
42
+ _show(args.session)
43
+ return 0
44
+
45
+
46
+ if __name__ == "__main__":
47
+ raise SystemExit(main())
@@ -0,0 +1,219 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Callable
5
+ import time
6
+ import tempfile
7
+
8
+ from pdl_taskmaster.observation.parsers import parse_operation_output
9
+ from pdl_taskmaster.observation.records import (
10
+ controller_snapshot,
11
+ event_delta,
12
+ read_events,
13
+ sha256_json,
14
+ sha256_text,
15
+ utcnow,
16
+ )
17
+ from pdl_taskmaster.observation.sink import JsonlSink
18
+
19
+
20
+ class ObservedSession:
21
+ """Wrap SessionEngine without becoming a second semantic participant.
22
+
23
+ Parsed facts are derived after the engine returns, using a disposable
24
+ OperationBridge. Observer failures are recorded and never change the
25
+ protocol result.
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ engine: Any,
31
+ sink: JsonlSink | None = None,
32
+ *,
33
+ run_id: str = "unset",
34
+ case_id: str | None = None,
35
+ include_bodies: bool = False,
36
+ worker: Any | None = None,
37
+ ):
38
+ self.engine = engine
39
+ self.sink = sink
40
+ self.run_id = run_id
41
+ self.case_id = case_id
42
+ self.include_bodies = include_bodies
43
+ self.turn_index = 0
44
+ self.calls: list[dict[str, Any]] = []
45
+ self._worker = worker
46
+ self._original_model_call = engine.model_call
47
+ engine.model_call = self._observed_model_call
48
+
49
+ @property
50
+ def session_id(self) -> str:
51
+ if self.engine.workspace is not None:
52
+ return str(self.engine.workspace.metadata.get("workspace_id", "workspace"))
53
+ return "session"
54
+
55
+ def _observed_model_call(self, request: Any) -> str:
56
+ started = time.perf_counter()
57
+ metadata: dict[str, Any] = {}
58
+ if self._worker is not None:
59
+ result = self._worker.call(request)
60
+ raw_text = result.text
61
+ metadata = dict(result.metadata or {})
62
+ else:
63
+ raw_text = self._original_model_call(request)
64
+ latency_ms = (time.perf_counter() - started) * 1000.0
65
+ call = {
66
+ "operation": request.operation,
67
+ "workspace_stage": request.workspace_invocation.stage,
68
+ "workspace_invocation_id": request.workspace_invocation.invocation_id,
69
+ "projection_manifest_sha256": sha256_json(request.manifest),
70
+ "prompt_sha256": sha256_text(request.prompt),
71
+ "response_sha256": sha256_text(raw_text),
72
+ "raw_text": raw_text,
73
+ "response_id": metadata.get("response_id"),
74
+ "observed_model": metadata.get("observed_model"),
75
+ "usage": metadata.get("usage"),
76
+ "latency_ms": metadata.get("latency_ms", latency_ms),
77
+ "raw_meta": metadata.get("raw_meta"),
78
+ }
79
+ self.calls.append(call)
80
+ return raw_text
81
+
82
+ def handle_user_message(self, user_message: str) -> Any:
83
+ before = controller_snapshot(self.engine)
84
+ events_before = read_events(self.engine.workspace)
85
+ call_start = len(self.calls)
86
+ started = time.perf_counter()
87
+ exception: dict[str, Any] | None = None
88
+ response = None
89
+ try:
90
+ response = self.engine.handle_user_message(user_message)
91
+ except Exception as exc:
92
+ exception = {"type": type(exc).__name__, "message": str(exc)}
93
+ wall_ms = (time.perf_counter() - started) * 1000.0
94
+ after = controller_snapshot(self.engine)
95
+ events_after = read_events(self.engine.workspace)
96
+ new_calls = self.calls[call_start:]
97
+ parsed_calls: list[dict[str, Any]] = []
98
+ observer_analysis_errors: list[str] = []
99
+ for call in new_calls:
100
+ parsed, parse_error = parse_operation_output(
101
+ self.engine.repo_root,
102
+ call["operation"],
103
+ call["raw_text"],
104
+ )
105
+ if parse_error is not None:
106
+ observer_analysis_errors.append(
107
+ f"{call['operation']}:{parse_error}"
108
+ )
109
+ public_call = {
110
+ "operation": call["operation"],
111
+ "workspace_stage": call["workspace_stage"],
112
+ "workspace_invocation_id": call["workspace_invocation_id"],
113
+ "projection_manifest_sha256": call["projection_manifest_sha256"],
114
+ "prompt_sha256": call["prompt_sha256"],
115
+ "response_sha256": call["response_sha256"],
116
+ "response_id": call["response_id"],
117
+ "observed_model": call["observed_model"],
118
+ "usage": call["usage"],
119
+ "latency_ms": call["latency_ms"],
120
+ "raw_meta": call["raw_meta"],
121
+ "parsed": parsed,
122
+ "parse_error": parse_error,
123
+ }
124
+ if self.include_bodies:
125
+ public_call["raw_text"] = call["raw_text"]
126
+ parsed_calls.append(public_call)
127
+
128
+ response_record: dict[str, Any] = {}
129
+ if response is not None:
130
+ response_record = {
131
+ "bypass": bool(getattr(response, "bypass", False)),
132
+ "closed": bool(getattr(response, "closed", False)),
133
+ "text_sha256": sha256_text(response.text or "") if response.text is not None else None,
134
+ "text_length": len(response.text or "") if response.text is not None else 0,
135
+ }
136
+ if self.include_bodies and response.text is not None:
137
+ response_record["text"] = response.text
138
+
139
+ record = {
140
+ "schema": 1,
141
+ "at_utc": utcnow(),
142
+ "run_id": self.run_id,
143
+ "case_id": self.case_id,
144
+ "session_id": self.session_id,
145
+ "workspace_id": after["workspace_id"] if after else None,
146
+ "workspace_path": after["workspace_path"] if after else None,
147
+ "turn_index": self.turn_index + 1,
148
+ "user_message_sha256": sha256_text(user_message),
149
+ "controller_before": before,
150
+ "controller_after": after,
151
+ "response": response_record,
152
+ "calls": parsed_calls,
153
+ "events": event_delta(events_before, events_after),
154
+ "exception": exception,
155
+ "observer_analysis_error": observer_analysis_errors or None,
156
+ "wall_ms": wall_ms,
157
+ }
158
+ if self.sink is not None:
159
+ self.sink.record(record)
160
+ self.turn_index += 1
161
+ if exception is not None:
162
+ raise RuntimeError(f"{exception['type']}: {exception['message']}")
163
+ return response
164
+
165
+ @classmethod
166
+ def restore(
167
+ cls,
168
+ candidate_repo: str | Path,
169
+ workspace_path: str | Path,
170
+ sink: JsonlSink | None = None,
171
+ *,
172
+ worker: Any | None = None,
173
+ run_id: str = "unset",
174
+ case_id: str | None = None,
175
+ include_bodies: bool = False,
176
+ **engine_kwargs: Any,
177
+ ) -> "ObservedSession":
178
+ import sys
179
+
180
+ repo = str(Path(candidate_repo).resolve())
181
+ if repo not in sys.path:
182
+ sys.path.insert(0, repo)
183
+ from pdl_taskmaster.runtime.session_engine import SessionEngine
184
+
185
+ engine = SessionEngine.restore(repo, lambda request: "", workspace_path, **engine_kwargs)
186
+ return cls(engine, sink, run_id=run_id, case_id=case_id, include_bodies=include_bodies, worker=worker)
187
+
188
+ @classmethod
189
+ def create(
190
+ cls,
191
+ candidate_repo: str | Path,
192
+ worker: Any,
193
+ *,
194
+ workspace_root: str | Path | None = None,
195
+ sink: JsonlSink | None = None,
196
+ run_id: str = "live",
197
+ case_id: str | None = None,
198
+ include_bodies: bool = False,
199
+ higher_priority_constraints: Any = "Obey applicable provider/platform safety, privacy, permission, and tool constraints.",
200
+ available_execution_tools: Any = None,
201
+ ) -> "ObservedSession":
202
+ """Create an observed session on a fresh workspace with arbitrary input."""
203
+ import sys
204
+
205
+ repo = str(Path(candidate_repo).resolve())
206
+ if repo not in sys.path:
207
+ sys.path.insert(0, repo)
208
+ from pdl_taskmaster.runtime.session_engine import SessionEngine
209
+
210
+ if workspace_root is None:
211
+ workspace_root = tempfile.mkdtemp(prefix="pdl-r2s-live-")
212
+ engine = SessionEngine(
213
+ repo,
214
+ lambda request: "",
215
+ higher_priority_constraints=higher_priority_constraints,
216
+ available_execution_tools=available_execution_tools or [],
217
+ workspace_root=workspace_root,
218
+ )
219
+ return cls(engine, sink, run_id=run_id, case_id=case_id, include_bodies=include_bodies, worker=worker)
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, is_dataclass
4
+ from enum import Enum
5
+ from pathlib import Path
6
+ from typing import Any
7
+ import sys
8
+
9
+
10
+ def _candidate_path(candidate_repo: str | Path) -> str:
11
+ value = str(Path(candidate_repo).resolve())
12
+ if value not in sys.path:
13
+ sys.path.insert(0, value)
14
+ return value
15
+
16
+
17
+ def new_operation_bridge(candidate_repo: str | Path) -> Any:
18
+ _candidate_path(candidate_repo)
19
+ from pdl_taskmaster.runtime.operation_bridge import OperationBridge
20
+
21
+ return OperationBridge(candidate_repo)
22
+
23
+
24
+ def _jsonable(value: Any) -> Any:
25
+ if is_dataclass(value):
26
+ return _jsonable(asdict(value))
27
+ if isinstance(value, Enum):
28
+ return value.value
29
+ if isinstance(value, dict):
30
+ return {str(k): _jsonable(v) for k, v in value.items()}
31
+ if isinstance(value, (list, tuple)):
32
+ return [_jsonable(v) for v in value]
33
+ if isinstance(value, Path):
34
+ return str(value)
35
+ return value
36
+
37
+
38
+ def operation_parsers() -> dict[str, str]:
39
+ return {
40
+ "INTERPRET_ACTIVATION": "parse_activation",
41
+ "DRAFT_PROMPT": "parse_prompt_draft",
42
+ "DRAFT_PLAN": "parse_plan_body",
43
+ "REVISE_PROMPT": "parse_prompt_body",
44
+ "REVISE_PLAN": "parse_plan_body",
45
+ "INTERPRET_PROMPT_REVIEW": "parse_prompt_review",
46
+ "INTERPRET_PLAN_REVIEW": "parse_plan_review",
47
+ "INTERPRET_EXECUTION_INPUT": "parse_execution_input",
48
+ "ANSWER_PROTOCOL_DISCUSSION": "parse_protocol_discussion",
49
+ "EXECUTE": "parse_execution",
50
+ }
51
+
52
+
53
+ def parse_operation_output(
54
+ candidate_repo: str | Path,
55
+ operation: str,
56
+ raw_text: str,
57
+ ) -> tuple[Any, str | None]:
58
+ method = operation_parsers().get(operation)
59
+ if method is None:
60
+ return None, f"no_parser_for_operation:{operation}"
61
+ try:
62
+ bridge = new_operation_bridge(candidate_repo)
63
+ parser = getattr(bridge, method)
64
+ return _jsonable(parser(raw_text)), None
65
+ except Exception as exc: # observation must never alter the protocol result
66
+ return None, f"{type(exc).__name__}: {exc}"
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timezone
4
+ from pathlib import Path
5
+ from typing import Any
6
+ import hashlib
7
+ import json
8
+
9
+
10
+ def sha256_text(value: str) -> str:
11
+ return hashlib.sha256(value.encode("utf-8")).hexdigest()
12
+
13
+
14
+ def sha256_json(value: Any) -> str:
15
+ payload = json.dumps(value, sort_keys=True, separators=(",", ":"), default=str)
16
+ return sha256_text(payload)
17
+
18
+
19
+ def utcnow() -> str:
20
+ return datetime.now(timezone.utc).isoformat()
21
+
22
+
23
+ def read_events(workspace: Any) -> list[dict[str, Any]]:
24
+ if workspace is None:
25
+ return []
26
+ path = Path(workspace.path) / "events" / "events.jsonl"
27
+ if not path.is_file():
28
+ return []
29
+ rows: list[dict[str, Any]] = []
30
+ for line in path.read_text(encoding="utf-8").splitlines():
31
+ if line.strip():
32
+ rows.append(json.loads(line))
33
+ return rows
34
+
35
+
36
+ def controller_snapshot(engine: Any) -> dict[str, Any] | None:
37
+ if engine is None or engine.controller is None:
38
+ return None
39
+ return {
40
+ "controller_state": engine.controller.state.to_dict(),
41
+ "workspace_id": engine.workspace.metadata.get("workspace_id") if engine.workspace is not None else None,
42
+ "workspace_path": str(engine.workspace.path) if engine.workspace is not None else None,
43
+ }
44
+
45
+
46
+ def event_delta(before: list[dict[str, Any]], after: list[dict[str, Any]]) -> dict[str, Any]:
47
+ if len(after) >= len(before):
48
+ new_events = after[len(before):]
49
+ else:
50
+ new_events = after
51
+ return {
52
+ "before_count": len(before),
53
+ "after_count": len(after),
54
+ "new": [
55
+ {"at_utc": event.get("at_utc"), "kind": event.get("kind"), "payload": event.get("payload")}
56
+ for event in new_events
57
+ ],
58
+ }
@@ -0,0 +1,3 @@
1
+ from pdl_taskmaster.observation.observed_session import ObservedSession
2
+
3
+ __all__ = ["ObservedSession"]
@@ -0,0 +1,3 @@
1
+ from pdl_taskmaster.observation.sinks import JsonlSink
2
+
3
+ __all__ = ["JsonlSink"]
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+ import json
6
+
7
+
8
+ class JsonlSink:
9
+ def __init__(self, output_dir: str | Path, session_id: str):
10
+ self.output_dir = Path(output_dir)
11
+ self.output_dir.mkdir(parents=True, exist_ok=True)
12
+ self.path = self.output_dir / f"{session_id}.jsonl"
13
+ self._handle = self.path.open("a", encoding="utf-8", newline="\n")
14
+
15
+ def record(self, record: dict[str, Any]) -> None:
16
+ self._handle.write(json.dumps(record, ensure_ascii=False, separators=(",", ":")) + "\n")
17
+ self._handle.flush()
18
+
19
+ def close(self) -> None:
20
+ self._handle.close()
@@ -0,0 +1,66 @@
1
+ # Worker adapters
2
+
3
+ ## Generic contract
4
+
5
+ `base.py` defines the generic `WorkerAdapter` contract:
6
+
7
+ ```text
8
+ ModelRequest
9
+ ->
10
+ raw model text
11
+ + optional transport metadata
12
+ ```
13
+
14
+ The adapter knows nothing about PDL wire validity. `OperationBridge` remains
15
+ the candidate-side authority for wire parsing.
16
+
17
+ ## Live demonstration worker
18
+
19
+ `live_stub.py` is a deterministic non-recorded worker used for live-capability
20
+ tests. It is labeled:
21
+
22
+ ```text
23
+ DEVELOPMENT / LIVE DEMONSTRATION WORKER
24
+ NOT A QUALIFIED R2S MEASUREMENT CONDITION
25
+ ```
26
+
27
+ `codex_worker.py` is the live Codex-backed demonstration worker. It is also
28
+ labeled as a **LIVE SEMANTIC WORKER** and a development/live demonstration
29
+ worker; it is not a qualified R2S measurement condition and is not a coding
30
+ domain execution backend.
31
+
32
+ ### Codex safety defaults
33
+
34
+ Normal local operation uses:
35
+
36
+ ```text
37
+ approval mode = never
38
+ sandbox mode = read-only
39
+ bypass = OFF
40
+ ```
41
+
42
+ `workspace-write` is opt-in (`/sandbox workspace-write` or
43
+ `--worker-sandbox workspace-write`) and remains constrained to an explicit
44
+ session/disposable workspace root. The dangerous bypass condition is a
45
+ separate startup-only mode intended only for externally hardened or
46
+ disposable execution environments; it is never an automatic fallback and is
47
+ not part of the Phase 0–5 seal.
48
+
49
+ ### Codex telemetry
50
+
51
+ Machine-readable `codex exec --json` events are preferred. Structured usage is
52
+ recorded only when the JSON explicitly provides the field, prefixed as
53
+ `codex_cli_*`. If only plaintext `tokens used` is available, it is recorded as
54
+ `codex_cli_reported_total` with `usage_source=codex_cli_plaintext` and
55
+ `usage_exact=false`. Parsed totals are never mapped into provider-authoritative
56
+ `total_tokens`, `input_tokens`, `cached_tokens`, or `reasoning_tokens`.
57
+ Telemetry records the Codex CLI version, requested/observed model, sandbox
58
+ mode, approval mode, workdir, JSON mode, response/session identifier,
59
+ latency, usage source, and usage exactness. Credentials are never stored.
60
+
61
+ ## Replay/qualification only
62
+
63
+ `recorded.py` and `fixtures.py` are replay/qualification utilities. They are
64
+ not the general-purpose worker contract and may reference historical evidence,
65
+ case IDs, and recorded turn sequences only because they exist to make
66
+ deterministic replay reproducible.
@@ -0,0 +1 @@
1
+ """Worker adapter package."""