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.
- pdl_taskmaster/__init__.py +6 -0
- pdl_taskmaster/contracts/AUTHORITY_MAP.json +19 -0
- pdl_taskmaster/contracts/CALIBRATION.json +7 -0
- pdl_taskmaster/contracts/CONTRACT_MANIFEST.json +231 -0
- pdl_taskmaster/contracts/EXECUTION_CONTRACT.json +615 -0
- pdl_taskmaster/contracts/IMPLEMENTATION_BOUNDARY.json +32 -0
- pdl_taskmaster/contracts/VERIFICATION_CONTRACT.json +379 -0
- pdl_taskmaster/contracts/standards/ARTIFACT_STANDARD.md +7 -0
- pdl_taskmaster/contracts/standards/AUTHORITY_STANDARD.md +17 -0
- pdl_taskmaster/contracts/standards/CONFORMANCE_STANDARD.md +15 -0
- pdl_taskmaster/contracts/standards/CONTEXT_STANDARD.md +15 -0
- pdl_taskmaster/contracts/standards/EXECUTION_STANDARD.md +14 -0
- pdl_taskmaster/contracts/standards/HANDOFF_STANDARD.md +21 -0
- pdl_taskmaster/contracts/standards/INSTALLATION_STANDARD.md +17 -0
- pdl_taskmaster/contracts/standards/PDL_STANDARD.md +19 -0
- pdl_taskmaster/contracts/standards/PROMPT_STANDARD.md +13 -0
- pdl_taskmaster/contracts/standards/PROTOCOL_STANDARD.md +17 -0
- pdl_taskmaster/contracts/standards/RESPONSE_PLAN_STANDARD.md +24 -0
- pdl_taskmaster/contracts/standards/RESULT_STANDARD.md +35 -0
- pdl_taskmaster/contracts/standards/REVIEW_STANDARD.md +31 -0
- pdl_taskmaster/contracts/standards/SEMANTIC_INPUT_STANDARD.md +15 -0
- pdl_taskmaster/contracts/standards/TASK_SEMANTICS_STANDARD.md +9 -0
- pdl_taskmaster/controller/__init__.py +0 -0
- pdl_taskmaster/controller/mechanical_controller.py +542 -0
- pdl_taskmaster/controller/schemas/activation_decision.schema.json +34 -0
- pdl_taskmaster/controller/schemas/artifact_body.schema.json +14 -0
- pdl_taskmaster/controller/schemas/artifact_review_facts.schema.json +91 -0
- pdl_taskmaster/controller/schemas/bootstrap_analysis.schema.json +60 -0
- pdl_taskmaster/controller/schemas/execution_draft.schema.json +47 -0
- pdl_taskmaster/controller/schemas/execution_input_decision.schema.json +43 -0
- pdl_taskmaster/controller/schemas/execution_outcome.schema.json +201 -0
- pdl_taskmaster/controller/schemas/plan_artifact.schema.json +14 -0
- pdl_taskmaster/controller/schemas/prompt_artifact.schema.json +63 -0
- pdl_taskmaster/controller/schemas/protocol_discussion.schema.json +8 -0
- pdl_taskmaster/controller/schemas/result_ir_repair.schema.json +140 -0
- pdl_taskmaster/eval/__init__.py +1 -0
- pdl_taskmaster/eval/build_adversarial_battery.py +351 -0
- pdl_taskmaster/eval/compare_eval_runs.py +251 -0
- pdl_taskmaster/eval/control_api_call.py +428 -0
- pdl_taskmaster/eval/export_rlcd_dataset.py +799 -0
- pdl_taskmaster/eval/fidelity_scan.py +268 -0
- pdl_taskmaster/eval/gen_fidelity_battery.py +457 -0
- pdl_taskmaster/eval/leak_scan.py +260 -0
- pdl_taskmaster/eval/rerecord_fixtures.py +139 -0
- pdl_taskmaster/eval/run_canary_shape_probe.py +229 -0
- pdl_taskmaster/eval/run_dual_gate_probe.py +404 -0
- pdl_taskmaster/eval/run_qualified_batch.py +841 -0
- pdl_taskmaster/eval/summarize_run.py +194 -0
- pdl_taskmaster/host/__init__.py +1 -0
- pdl_taskmaster/host/app.py +164 -0
- pdl_taskmaster/host/cli.py +100 -0
- pdl_taskmaster/host/repl.py +866 -0
- pdl_taskmaster/observation/__init__.py +1 -0
- pdl_taskmaster/observation/cli.py +47 -0
- pdl_taskmaster/observation/observed_session.py +219 -0
- pdl_taskmaster/observation/parsers.py +66 -0
- pdl_taskmaster/observation/records.py +58 -0
- pdl_taskmaster/observation/session.py +3 -0
- pdl_taskmaster/observation/sink.py +3 -0
- pdl_taskmaster/observation/sinks.py +20 -0
- pdl_taskmaster/providers/README.md +66 -0
- pdl_taskmaster/providers/__init__.py +1 -0
- pdl_taskmaster/providers/api_worker.py +411 -0
- pdl_taskmaster/providers/base.py +26 -0
- pdl_taskmaster/providers/codex_worker.py +328 -0
- pdl_taskmaster/providers/fixtures.py +157 -0
- pdl_taskmaster/providers/live_stub.py +66 -0
- pdl_taskmaster/providers/recorded.py +120 -0
- pdl_taskmaster/py.typed +1 -0
- pdl_taskmaster/runtime/__init__.py +0 -0
- pdl_taskmaster/runtime/context_compiler.py +151 -0
- pdl_taskmaster/runtime/model_classification.py +290 -0
- pdl_taskmaster/runtime/normative_store.py +157 -0
- pdl_taskmaster/runtime/operation_bridge.py +336 -0
- pdl_taskmaster/runtime/presentation.py +18 -0
- pdl_taskmaster/runtime/quarantine.py +91 -0
- pdl_taskmaster/runtime/result_ir.py +401 -0
- pdl_taskmaster/runtime/semantic_observer.py +40 -0
- pdl_taskmaster/runtime/session_engine.py +1168 -0
- pdl_taskmaster/runtime/standard_registry.py +55 -0
- pdl_taskmaster/runtime/wire_payloads.py +462 -0
- pdl_taskmaster/runtime/worker-bootstrap.txt +4 -0
- pdl_taskmaster/runtime/workspace.py +602 -0
- pdl_taskmaster/tracking/__init__.py +1 -0
- pdl_taskmaster/tracking/log_live_session.py +98 -0
- pdl_taskmaster/tracking/mlflow_sink.py +58 -0
- pdl_taskmaster/verify/verify_repl_baseline.py +299 -0
- pdl_taskmaster-2.4.0.dist-info/METADATA +155 -0
- pdl_taskmaster-2.4.0.dist-info/RECORD +92 -0
- pdl_taskmaster-2.4.0.dist-info/WHEEL +4 -0
- pdl_taskmaster-2.4.0.dist-info/entry_points.txt +2 -0
- pdl_taskmaster-2.4.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
from pydantic import TypeAdapter, ValidationError
|
|
11
|
+
|
|
12
|
+
from pdl_taskmaster.runtime.context_compiler import CompiledProjection, ContextCompiler
|
|
13
|
+
from pdl_taskmaster.runtime.workspace import WorkspaceInvocation, WorkspaceRun
|
|
14
|
+
from pdl_taskmaster.runtime.wire_payloads import (
|
|
15
|
+
ActivationDecisionPayload,
|
|
16
|
+
ActivationRoute,
|
|
17
|
+
ApproachChangeDimension,
|
|
18
|
+
ArtifactReviewPayload,
|
|
19
|
+
BootstrapAnalysisData,
|
|
20
|
+
BootstrapAnalysisPayload,
|
|
21
|
+
ExecutionDraftBlockedData,
|
|
22
|
+
ExecutionDraftPayload,
|
|
23
|
+
ExecutionDraftResultData,
|
|
24
|
+
ExecutionInputPayload,
|
|
25
|
+
ExecutionInputReviseData,
|
|
26
|
+
ExecutionOutcomePayload,
|
|
27
|
+
ExecutionRequestInputData,
|
|
28
|
+
ExecutionResultData,
|
|
29
|
+
NeutralPlanBodyPayload,
|
|
30
|
+
PromptBodyPayload,
|
|
31
|
+
PromptDraftData,
|
|
32
|
+
PromptDraftPayload,
|
|
33
|
+
ProtocolDiscussionPayload,
|
|
34
|
+
ResultIRRepairPayload,
|
|
35
|
+
ReviewFactsData,
|
|
36
|
+
SYSTEM1_CONFIDENCE_FLOOR,
|
|
37
|
+
TaskChangeDimension,
|
|
38
|
+
WireError,
|
|
39
|
+
format_validation_feedback,
|
|
40
|
+
map_validation_error_to_wire_reason,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class ActivationDecision:
|
|
46
|
+
route: ActivationRoute
|
|
47
|
+
response: str | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True)
|
|
51
|
+
class PromptDraftOutcome:
|
|
52
|
+
kind: str
|
|
53
|
+
prompt_body: str | None = None
|
|
54
|
+
approach_handoff: str = "NONE"
|
|
55
|
+
blocking_basis: str | None = None
|
|
56
|
+
response: str | None = None
|
|
57
|
+
task_entities: tuple[str, ...] | None = None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass(frozen=True)
|
|
61
|
+
class ExecutionOutcome:
|
|
62
|
+
kind: str
|
|
63
|
+
body: str
|
|
64
|
+
expected_type: str | None = None
|
|
65
|
+
description: str | None = None
|
|
66
|
+
result_ir: dict | None = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(frozen=True)
|
|
70
|
+
class ExecutionDraftOutcome:
|
|
71
|
+
kind: str
|
|
72
|
+
brief_body: str
|
|
73
|
+
execution_entities: tuple[dict, ...] = ()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(frozen=True)
|
|
77
|
+
class ModelRequest:
|
|
78
|
+
projection: CompiledProjection
|
|
79
|
+
prompt: str
|
|
80
|
+
workspace_invocation: WorkspaceInvocation
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def operation(self) -> str:
|
|
84
|
+
return self.projection.operation
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def manifest(self) -> dict[str, Any]:
|
|
88
|
+
return self.projection.manifest
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class OperationBridge:
|
|
92
|
+
def __init__(self, repo_root: str | Path, *, render_compact: bool = False):
|
|
93
|
+
self.repo_root = Path(repo_root)
|
|
94
|
+
self.render_compact = render_compact
|
|
95
|
+
self.compiler = ContextCompiler(self.repo_root)
|
|
96
|
+
bootstrap_path = Path(__file__).parent / "worker-bootstrap.txt"
|
|
97
|
+
if not bootstrap_path.is_file():
|
|
98
|
+
bootstrap_path = self.repo_root / "src" / "pdl_taskmaster" / "runtime" / "worker-bootstrap.txt"
|
|
99
|
+
self.bootstrap = bootstrap_path.read_text(encoding="utf-8")
|
|
100
|
+
|
|
101
|
+
def request(
|
|
102
|
+
self,
|
|
103
|
+
operation: str,
|
|
104
|
+
values: dict[str, Any],
|
|
105
|
+
*,
|
|
106
|
+
workspace: WorkspaceRun,
|
|
107
|
+
higher_priority_constraints: Any = None,
|
|
108
|
+
operator_correction: str | None = None,
|
|
109
|
+
) -> ModelRequest:
|
|
110
|
+
invocation = workspace.materialize_operation(
|
|
111
|
+
operation, values, higher_priority_constraints=higher_priority_constraints
|
|
112
|
+
)
|
|
113
|
+
materialized_values, materialized_higher_priority = workspace.load_operation_values(invocation)
|
|
114
|
+
projection = self.compiler.compile(
|
|
115
|
+
operation,
|
|
116
|
+
materialized_values,
|
|
117
|
+
higher_priority_constraints=materialized_higher_priority,
|
|
118
|
+
)
|
|
119
|
+
workspace.record_projection(invocation, projection.manifest, projection.document)
|
|
120
|
+
prompt = projection.render(self.bootstrap, compact=self.render_compact)
|
|
121
|
+
if operator_correction:
|
|
122
|
+
# Appended outside the projection document so projection_sha256
|
|
123
|
+
# (and fixture replay) stay stable; only used on the retry path.
|
|
124
|
+
prompt = prompt + operator_correction.strip() + "\n"
|
|
125
|
+
return ModelRequest(projection, prompt, invocation)
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def _object(model_text: str) -> dict[str, Any]:
|
|
129
|
+
"""Extract exactly one JSON object from a worker response.
|
|
130
|
+
|
|
131
|
+
Tolerant of *placement* (leading/trailing prose, BOM, markdown fences
|
|
132
|
+
anywhere in the text) but never repairs *content*: malformed JSON
|
|
133
|
+
still raises WireError("invalid_json") so the caller's retry path
|
|
134
|
+
can ask the stateless worker to re-emit (see SessionEngine._call).
|
|
135
|
+
"""
|
|
136
|
+
stripped = model_text.strip().lstrip("\ufeff")
|
|
137
|
+
last_error: json.JSONDecodeError | None = None
|
|
138
|
+
value: Any = None
|
|
139
|
+
try:
|
|
140
|
+
value = json.loads(stripped)
|
|
141
|
+
except json.JSONDecodeError as exc:
|
|
142
|
+
last_error = exc
|
|
143
|
+
if value is None:
|
|
144
|
+
unfenced = re.sub(r"```(?:json)?", "", stripped).strip()
|
|
145
|
+
try:
|
|
146
|
+
value = json.loads(unfenced)
|
|
147
|
+
except json.JSONDecodeError as exc:
|
|
148
|
+
last_error = exc
|
|
149
|
+
if value is None:
|
|
150
|
+
# Balanced-brace scan: locate the first parseable JSON object
|
|
151
|
+
# embedded in surrounding prose. raw_decode consumes exactly one
|
|
152
|
+
# balanced value starting at each candidate brace.
|
|
153
|
+
decoder = json.JSONDecoder()
|
|
154
|
+
for idx, char in enumerate(stripped):
|
|
155
|
+
if char != "{":
|
|
156
|
+
continue
|
|
157
|
+
try:
|
|
158
|
+
candidate, _ = decoder.raw_decode(stripped[idx:])
|
|
159
|
+
except json.JSONDecodeError as exc:
|
|
160
|
+
last_error = exc
|
|
161
|
+
continue
|
|
162
|
+
if isinstance(candidate, dict):
|
|
163
|
+
value = candidate
|
|
164
|
+
break
|
|
165
|
+
if value is None:
|
|
166
|
+
# Carry the underlying JSONDecodeError detail (e.g. "Invalid
|
|
167
|
+
# \\escape") so the retry's operator correction names the actual
|
|
168
|
+
# defect instead of a generic invalid_json.
|
|
169
|
+
detail = f"invalid_json ({last_error.msg} at column {last_error.pos + 1})" if last_error else "invalid_json"
|
|
170
|
+
raise WireError(detail)
|
|
171
|
+
if not isinstance(value, dict):
|
|
172
|
+
raise WireError("not_object")
|
|
173
|
+
return value
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def _keys(value: dict[str, Any], allowed: set[str], required: set[str]) -> None:
|
|
177
|
+
if set(value) - allowed:
|
|
178
|
+
raise WireError("extra_fields")
|
|
179
|
+
if not required <= set(value):
|
|
180
|
+
raise WireError("missing_fields")
|
|
181
|
+
|
|
182
|
+
def _validate(self, operation: str, model_type: Any, model_text: str) -> Any:
|
|
183
|
+
value = self._object(model_text)
|
|
184
|
+
try:
|
|
185
|
+
adapter = TypeAdapter(model_type)
|
|
186
|
+
return adapter.validate_python(value)
|
|
187
|
+
except ValidationError as val_err:
|
|
188
|
+
reason = map_validation_error_to_wire_reason(
|
|
189
|
+
operation, val_err, value if isinstance(value, dict) else None
|
|
190
|
+
)
|
|
191
|
+
feedback = format_validation_feedback(val_err)
|
|
192
|
+
raise WireError(reason, operator_feedback=feedback, validation_error=val_err) from val_err
|
|
193
|
+
|
|
194
|
+
def parse_activation(self, model_text: str) -> ActivationDecision:
|
|
195
|
+
payload: ActivationDecisionPayload = self._validate("INTERPRET_ACTIVATION", ActivationDecisionPayload, model_text)
|
|
196
|
+
if payload.confidence is not None and payload.confidence < SYSTEM1_CONFIDENCE_FLOOR:
|
|
197
|
+
# ADR-0012 Fail-closed: low-confidence activation classification defaults to protocol application
|
|
198
|
+
return ActivationDecision(ActivationRoute.APPLY_PROTOCOL)
|
|
199
|
+
return ActivationDecision(payload.route, payload.response.strip() if payload.response else None)
|
|
200
|
+
|
|
201
|
+
def parse_prompt_draft(self, model_text: str) -> PromptDraftOutcome:
|
|
202
|
+
payload: PromptDraftPayload = self._validate("DRAFT_PROMPT", PromptDraftPayload, model_text)
|
|
203
|
+
if isinstance(payload, PromptDraftData):
|
|
204
|
+
return PromptDraftOutcome(
|
|
205
|
+
payload.kind,
|
|
206
|
+
payload.prompt_body.strip(),
|
|
207
|
+
payload.approach_handoff,
|
|
208
|
+
task_entities=tuple(payload.task_entities) if payload.task_entities else (),
|
|
209
|
+
)
|
|
210
|
+
return PromptDraftOutcome(
|
|
211
|
+
payload.kind,
|
|
212
|
+
blocking_basis=payload.blocking_basis,
|
|
213
|
+
response=payload.response.strip(),
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
def _parse_named_body(self, model_text: str, field: str) -> str:
|
|
217
|
+
if field == "prompt_body":
|
|
218
|
+
return self.parse_prompt_body(model_text)
|
|
219
|
+
if field == "neutral_plan_body":
|
|
220
|
+
return self.parse_plan_body(model_text)
|
|
221
|
+
value = self._object(model_text)
|
|
222
|
+
self._keys(value, {field}, {field})
|
|
223
|
+
body = value[field]
|
|
224
|
+
if not isinstance(body, str) or not body.strip():
|
|
225
|
+
raise WireError(field)
|
|
226
|
+
return body.strip()
|
|
227
|
+
|
|
228
|
+
def parse_prompt_body(self, model_text: str) -> str:
|
|
229
|
+
payload: PromptBodyPayload = self._validate("REVISE_PROMPT", PromptBodyPayload, model_text)
|
|
230
|
+
return payload.prompt_body.strip()
|
|
231
|
+
|
|
232
|
+
def parse_plan_body(self, model_text: str) -> str:
|
|
233
|
+
payload: NeutralPlanBodyPayload = self._validate("DRAFT_PLAN", NeutralPlanBodyPayload, model_text)
|
|
234
|
+
return payload.neutral_plan_body.strip()
|
|
235
|
+
|
|
236
|
+
def _parse_artifact_review(self, model_text: str) -> dict[str, Any]:
|
|
237
|
+
payload: ArtifactReviewPayload = self._validate("INTERPRET_PROMPT_REVIEW", ArtifactReviewPayload, model_text)
|
|
238
|
+
if hasattr(payload, "confidence") and payload.confidence is not None and payload.confidence < SYSTEM1_CONFIDENCE_FLOOR:
|
|
239
|
+
# ADR-0012 Fail-closed: low-confidence review classification must never progress or silently route.
|
|
240
|
+
# Escalate to UNRESOLVED to re-prompt human confirmation per REVIEW-09.
|
|
241
|
+
return {"intent": "UNRESOLVED"}
|
|
242
|
+
if isinstance(payload, ReviewFactsData):
|
|
243
|
+
task_changed = bool(payload.task_change_dimensions)
|
|
244
|
+
approach_changed = bool(payload.approach_change_dimensions)
|
|
245
|
+
if not (task_changed or approach_changed or payload.progression_requested):
|
|
246
|
+
# All-empty REVIEW_FACTS: the model reports the message changed
|
|
247
|
+
# no dimension and requested no progression. Per REVIEW-09/13/14,
|
|
248
|
+
# mechanically treat this as SUBSTANTIVE_DISCUSSION.
|
|
249
|
+
return {"intent": "SUBSTANTIVE_DISCUSSION"}
|
|
250
|
+
if task_changed:
|
|
251
|
+
return {"intent": "REVISE_TASK", "also_changes_approach": approach_changed}
|
|
252
|
+
if approach_changed:
|
|
253
|
+
return {"intent": "REVISE_APPROACH"}
|
|
254
|
+
return {"intent": "ACCEPT_CURRENT"}
|
|
255
|
+
return {"intent": payload.kind}
|
|
256
|
+
|
|
257
|
+
def parse_prompt_review(self, model_text: str) -> dict[str, Any]:
|
|
258
|
+
return self._parse_artifact_review(model_text)
|
|
259
|
+
|
|
260
|
+
def parse_plan_review(self, model_text: str) -> dict[str, Any]:
|
|
261
|
+
return self._parse_artifact_review(model_text)
|
|
262
|
+
|
|
263
|
+
def parse_bootstrap_analysis(self, model_text: str) -> dict[str, Any]:
|
|
264
|
+
payload: BootstrapAnalysisPayload = self._validate("BOOTSTRAP_ANALYSIS", BootstrapAnalysisPayload, model_text)
|
|
265
|
+
if isinstance(payload, BootstrapAnalysisData):
|
|
266
|
+
return {
|
|
267
|
+
"kind": payload.kind,
|
|
268
|
+
"task_summary": payload.task_summary,
|
|
269
|
+
"approach_notes": payload.approach_notes,
|
|
270
|
+
"risk_notes": payload.risk_notes,
|
|
271
|
+
"task_entities": list(payload.task_entities),
|
|
272
|
+
}
|
|
273
|
+
return {"kind": payload.kind, "response": payload.response.strip()}
|
|
274
|
+
|
|
275
|
+
def parse_execution_input(self, model_text: str) -> dict[str, Any]:
|
|
276
|
+
payload: ExecutionInputPayload = self._validate("INTERPRET_EXECUTION_INPUT", ExecutionInputPayload, model_text)
|
|
277
|
+
if hasattr(payload, "confidence") and payload.confidence is not None and payload.confidence < SYSTEM1_CONFIDENCE_FLOOR:
|
|
278
|
+
return {"intent": "UNRESOLVED"}
|
|
279
|
+
if isinstance(payload, ExecutionInputReviseData):
|
|
280
|
+
return {
|
|
281
|
+
"intent": "REVISE_TASK",
|
|
282
|
+
"also_changes_approach": payload.also_changes_approach,
|
|
283
|
+
}
|
|
284
|
+
return {"intent": payload.kind}
|
|
285
|
+
|
|
286
|
+
def parse_protocol_discussion(self, model_text: str) -> str:
|
|
287
|
+
payload: ProtocolDiscussionPayload = self._validate("ANSWER_PROTOCOL_DISCUSSION", ProtocolDiscussionPayload, model_text)
|
|
288
|
+
return payload.body.strip()
|
|
289
|
+
|
|
290
|
+
def parse_execution_draft(self, model_text: str) -> ExecutionDraftOutcome:
|
|
291
|
+
payload: ExecutionDraftPayload = self._validate("DRAFT_EXECUTION", ExecutionDraftPayload, model_text)
|
|
292
|
+
if isinstance(payload, ExecutionDraftBlockedData):
|
|
293
|
+
return ExecutionDraftOutcome(payload.kind, payload.brief_body.strip(), ())
|
|
294
|
+
clean: list[dict] = []
|
|
295
|
+
for e in payload.execution_entities:
|
|
296
|
+
if isinstance(e, dict) and str(e.get("value", "")).strip():
|
|
297
|
+
clean.append({
|
|
298
|
+
"kind": str(e.get("kind", "meta")),
|
|
299
|
+
"value": str(e["value"]).strip(),
|
|
300
|
+
"name": e.get("name"),
|
|
301
|
+
"struct_format": e.get("struct_format"),
|
|
302
|
+
"declared_size": e.get("declared_size"),
|
|
303
|
+
})
|
|
304
|
+
elif isinstance(e, str) and e.strip():
|
|
305
|
+
clean.append({
|
|
306
|
+
"kind": "meta",
|
|
307
|
+
"value": e.strip(),
|
|
308
|
+
"name": None,
|
|
309
|
+
"struct_format": None,
|
|
310
|
+
"declared_size": None,
|
|
311
|
+
})
|
|
312
|
+
return ExecutionDraftOutcome(payload.kind, payload.brief_body.strip(), tuple(clean))
|
|
313
|
+
|
|
314
|
+
def parse_result_ir_repair(self, model_text: str) -> dict:
|
|
315
|
+
payload: ResultIRRepairPayload = self._validate("EMIT_RESULT_IR", ResultIRRepairPayload, model_text)
|
|
316
|
+
return payload.result_ir.model_dump()
|
|
317
|
+
|
|
318
|
+
def parse_execution(self, model_text: str) -> ExecutionOutcome:
|
|
319
|
+
payload: ExecutionOutcomePayload = self._validate("EXECUTE", ExecutionOutcomePayload, model_text)
|
|
320
|
+
if isinstance(payload, ExecutionRequestInputData):
|
|
321
|
+
return ExecutionOutcome(
|
|
322
|
+
payload.kind,
|
|
323
|
+
payload.body.strip(),
|
|
324
|
+
payload.expected_type.strip(),
|
|
325
|
+
payload.description.strip(),
|
|
326
|
+
None,
|
|
327
|
+
)
|
|
328
|
+
ir_dict = payload.result_ir.model_dump() if payload.result_ir is not None else None
|
|
329
|
+
return ExecutionOutcome(
|
|
330
|
+
payload.kind,
|
|
331
|
+
payload.body.strip(),
|
|
332
|
+
None,
|
|
333
|
+
None,
|
|
334
|
+
ir_dict,
|
|
335
|
+
)
|
|
336
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
def prompt_artifact(body: str) -> str:
|
|
2
|
+
return f"Prompt Pseudocode\n\n{body}\n\nConfirm or correct this interpretation."
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def plan_artifact(body: str) -> str:
|
|
6
|
+
return f"Response Plan Pseudocode\n\n{body}\n\nConfirm or correct this response approach."
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def deferred_substantive() -> str:
|
|
10
|
+
return "I’ll address that substantive task question after the current confirmations are complete."
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def review_clarification() -> str:
|
|
14
|
+
return "Please clarify how that message should affect the current review."
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def cancelled() -> str:
|
|
18
|
+
return "Cancelled."
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Quarantine sanitizer (protocol v2, semantic-bootstrap containment).
|
|
2
|
+
|
|
3
|
+
The data-plane sanitizer: verbatim content emitted by the semantic-read
|
|
4
|
+
(bootstrap) operation is sanitized before it becomes a compile operation's
|
|
5
|
+
context.
|
|
6
|
+
|
|
7
|
+
- `compile_bootstrap_output`: sanitizes the bootstrap analysis before it
|
|
8
|
+
becomes a compile operation's context. Explicit canary tokens, tripwire
|
|
9
|
+
strings, override directives, and quoted spans carrying them are replaced
|
|
10
|
+
with [REDACTED_IOC]. Legitimate code specifications, identifiers, exception
|
|
11
|
+
classes, and parameter names are strictly preserved.
|
|
12
|
+
|
|
13
|
+
The retired in-band evidence-sink delimiters (`<<<EVIDENCE>>>` /
|
|
14
|
+
`<<<END_EVIDENCE>>>`) and their mechanical strip were permanently removed per
|
|
15
|
+
Decision D24 / TRD-0002: containment is out-of-band schema field isolation
|
|
16
|
+
(`task_summary` vs `risk_notes`), never in-band delimiter fences.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import re
|
|
21
|
+
|
|
22
|
+
# Known canary, tripwire, and exploit directive patterns
|
|
23
|
+
_CANARY_OR_TRIPWIRE = re.compile(
|
|
24
|
+
r"\b(?:TRIPWIRE_[A-Za-z0-9_]+|CANARY_[A-Za-z0-9_]+|PWNED_[A-Za-z0-9_]+|ACTIVATED|ROOTKIT-[A-Za-z0-9_]+)\b"
|
|
25
|
+
)
|
|
26
|
+
_OVERRIDE_DIRECTIVE = re.compile(r"\+{3}\s*(?:SYSTEM\s+(?:DIRECTIVE\s+)?OVERRIDE|END)\s*\+{3}", re.IGNORECASE)
|
|
27
|
+
|
|
28
|
+
# D29 generalized opaque-identifier shapes: canaries need not carry a
|
|
29
|
+
# recognizable prefix (UUID / long-hex canaries measurably reached the
|
|
30
|
+
# deliverable on the primary tier -- runs/canary_shape_probe). These
|
|
31
|
+
# apply ONLY to the sanitized summary surface, where an untrusted literal
|
|
32
|
+
# of digest length or UUID shape has no legitimate role; digest
|
|
33
|
+
# verification belongs in code, which this sanitizer never touches
|
|
34
|
+
# (execution-stage output is out of scope). Deliberate policy: >=32 hex
|
|
35
|
+
# chars includes SHA-256-length digests on this surface -- refer to them
|
|
36
|
+
# by role, not verbatim.
|
|
37
|
+
_UUID_SHAPE = re.compile(
|
|
38
|
+
r"\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b"
|
|
39
|
+
)
|
|
40
|
+
_LONG_HEX_RUN = re.compile(r"\b[0-9a-fA-F]{32,}\b")
|
|
41
|
+
_EXPLOIT_PHRASE = re.compile(
|
|
42
|
+
r"(?:system\s+(?:directive\s+)?override|ignore\s+previous\s+instructions|dump\s+system\s+secrets|rootkit|credential[- ]harvesting)",
|
|
43
|
+
re.IGNORECASE,
|
|
44
|
+
)
|
|
45
|
+
_QUOTED_SPAN = re.compile(r"(\"[^\"]{6,}\"|'[^']{6,}'|`[^`]{6,}`)")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def compile_bootstrap_output(raw_source: str, analysis_text: str) -> tuple[str, dict]:
|
|
49
|
+
"""Sanitize a bootstrap analysis for use as a compile-operation input.
|
|
50
|
+
|
|
51
|
+
1. Replace explicit canary tokens, tripwire strings, and override directives
|
|
52
|
+
with [REDACTED_IOC].
|
|
53
|
+
2. Redact quoted spans that contain exploit directives or canary tokens.
|
|
54
|
+
Legitimate code specifications, identifiers, exception classes, and
|
|
55
|
+
parameter names are strictly preserved.
|
|
56
|
+
Returns (sanitized_text, meta{redactions}).
|
|
57
|
+
"""
|
|
58
|
+
meta: dict = {"redactions": 0}
|
|
59
|
+
if not analysis_text:
|
|
60
|
+
return "", meta
|
|
61
|
+
|
|
62
|
+
text = analysis_text
|
|
63
|
+
if not raw_source:
|
|
64
|
+
return text, meta
|
|
65
|
+
|
|
66
|
+
# 1. Redact quoted spans if they contain attack directives, canaries, or overrides
|
|
67
|
+
def _redact_quoted_span(m: re.Match) -> str:
|
|
68
|
+
inner = m.group(1)[1:-1]
|
|
69
|
+
if _EXPLOIT_PHRASE.search(inner) or _CANARY_OR_TRIPWIRE.search(inner) or _OVERRIDE_DIRECTIVE.search(inner):
|
|
70
|
+
meta["redactions"] += 1
|
|
71
|
+
return "[REDACTED_IOC]"
|
|
72
|
+
return m.group(0)
|
|
73
|
+
|
|
74
|
+
text = _QUOTED_SPAN.sub(_redact_quoted_span, text)
|
|
75
|
+
|
|
76
|
+
# 2. Redact explicit tripwire/canary tokens
|
|
77
|
+
def _redact_token(m: re.Match) -> str:
|
|
78
|
+
meta["redactions"] += 1
|
|
79
|
+
return "[REDACTED_IOC]"
|
|
80
|
+
|
|
81
|
+
text = _CANARY_OR_TRIPWIRE.sub(_redact_token, text)
|
|
82
|
+
text = _OVERRIDE_DIRECTIVE.sub(_redact_token, text)
|
|
83
|
+
|
|
84
|
+
# 3. D29 generalized-shape redaction (prefix-independent canaries)
|
|
85
|
+
def _redact_generalized(m: re.Match) -> str:
|
|
86
|
+
meta["redactions_generalized"] = meta.get("redactions_generalized", 0) + 1
|
|
87
|
+
return "[REDACTED_IOC]"
|
|
88
|
+
|
|
89
|
+
text = _UUID_SHAPE.sub(_redact_generalized, text)
|
|
90
|
+
text = _LONG_HEX_RUN.sub(_redact_generalized, text)
|
|
91
|
+
return text, meta
|