mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-16 03:42:20 +02:00
fix(runtime): scope completion claims to execution obligations
This commit is contained in:
+92
-6
@@ -280,6 +280,40 @@ def _known_input_is_explicit_mutation_target(instruction: str, path: str) -> boo
|
||||
)
|
||||
|
||||
|
||||
def _unquoted_statements(text: str) -> Iterable[tuple[str, str]]:
|
||||
"""Yield original statements and their reportable prose, with quotes masked.
|
||||
|
||||
Mask before splitting so punctuation inside an example cannot change the
|
||||
scope of the surrounding sentence. Inline code identifiers stay visible.
|
||||
"""
|
||||
def mask(match: re.Match[str]) -> str:
|
||||
value = match.group()
|
||||
# Quotation marks around an artifact identify a target, rather than
|
||||
# quote a report. Keep that target available for exact path matching.
|
||||
if value[0] in {'"', "'"} and re.fullmatch(_ARTIFACT_PATH, value[1:-1]):
|
||||
return ' ' + value[1:-1] + ' '
|
||||
return re.sub(r'[^\n]', ' ', value)
|
||||
|
||||
masked = re.sub(
|
||||
r'```[\s\S]*?```|~~~[\s\S]*?~~~|"[^"\n]*"|(?<!\w)\'[^\'\n]*\'(?!\w)',
|
||||
mask, text,
|
||||
)
|
||||
start = 0
|
||||
for boundary in re.finditer(r'(?<=[.!?;])(?=\s)|(?<=\n)', masked):
|
||||
end = boundary.start()
|
||||
if end > start:
|
||||
yield text[start:end], masked[start:end].replace('`', '')
|
||||
start = end
|
||||
if start < len(text):
|
||||
yield text[start:], masked[start:].replace('`', '')
|
||||
|
||||
|
||||
def _execution_obligation(requirements: CompletionRequirements) -> bool:
|
||||
"""A derived view of the existing contract, never a separate declaration."""
|
||||
return bool(requirements.required_artifacts or requirements.verifier_required
|
||||
or requirements.executable_verifier_available or requirements.verifier_commands)
|
||||
|
||||
|
||||
def infer_completion_requirements(
|
||||
instruction: str,
|
||||
*,
|
||||
@@ -289,7 +323,15 @@ def infer_completion_requirements(
|
||||
) -> CompletionRequirements:
|
||||
"""Infer only explicitly requested output/edit paths from an instruction."""
|
||||
|
||||
text = str(instruction or "")
|
||||
# Explanations can contain imperative examples. Their embedded actions
|
||||
# are not requests to execute those actions. Keep independent requests in
|
||||
# other statements, and keep explicitly supplied verifier requirements.
|
||||
explanatory_request = re.compile(
|
||||
r'^\s*(?:please\s+|(?:can|could|would)\s+you\s+)?'
|
||||
r'(?:explain|describe|summari[sz]e|teach|discuss|'
|
||||
r'show\s+(?:me\s+)?(?:an?\s+)?example|how\b)', re.I)
|
||||
text = ''.join(scoped for _, scoped in _unquoted_statements(str(instruction or ''))
|
||||
if not explanatory_request.search(scoped))
|
||||
paths: list[str] = []
|
||||
for pattern in (
|
||||
_ARTIFACT_REQUEST_RE,
|
||||
@@ -353,18 +395,23 @@ def infer_completion_requirements(
|
||||
for command in verifier_commands
|
||||
if str(command or "").strip()
|
||||
))
|
||||
explicit_test_request = re.search(
|
||||
r'(?:^|[.;\n]|\b(?:and|then))\s*'
|
||||
r'(?:please\s+|(?:can|could|would)\s+you\s+)?'
|
||||
r'(?:run|execute)\s+(?:(?:the|all|a|full)\s+)*'
|
||||
r'(?:tests?\b|test\s+suite\b|pytest\b|unittest\b|npm\s+test\b)', text, re.I)
|
||||
verifier_required = executable_verifier_available or bool(cleaned_verifier_commands) or bool(
|
||||
re.search(
|
||||
explicit_test_request or (paths and re.search(
|
||||
r"\b(?:then|after(?:wards)?|and)\b[^\n]{0,100}\b(?:test|verify|check|validate)\b",
|
||||
str(instruction or ""),
|
||||
text,
|
||||
re.IGNORECASE,
|
||||
)
|
||||
))
|
||||
)
|
||||
return CompletionRequirements(
|
||||
required_artifacts=tuple(paths),
|
||||
verifier_required=verifier_required,
|
||||
executable_verifier_available=(
|
||||
executable_verifier_available or bool(cleaned_verifier_commands)
|
||||
executable_verifier_available or bool(cleaned_verifier_commands) or bool(explicit_test_request)
|
||||
),
|
||||
verifier_commands=cleaned_verifier_commands,
|
||||
)
|
||||
@@ -575,6 +622,9 @@ class EvidenceLedger:
|
||||
self.events: list[EvidenceEvent] = []
|
||||
self._verification_versions: dict[str, str] = {}
|
||||
self._verification_versions_captured = False
|
||||
# Retain receipt command identity privately for presentation matching;
|
||||
# model prose and client dictionaries never populate this evidence.
|
||||
self._verifier_commands: dict[str, tuple[str, ...]] = {}
|
||||
|
||||
@classmethod
|
||||
def from_tool_events(
|
||||
@@ -718,13 +768,14 @@ class EvidenceLedger:
|
||||
versions = event.get('artifact_versions')
|
||||
self._verification_versions = dict(versions) if isinstance(versions, Mapping) else {}
|
||||
self._verification_versions_captured = isinstance(versions, Mapping)
|
||||
self._append(
|
||||
verifier = self._append(
|
||||
kind=EvidenceKind.VERIFIER_RESULT,
|
||||
success=success,
|
||||
authoritative=authoritative,
|
||||
source=event,
|
||||
detail="executable test/verifier command",
|
||||
)
|
||||
self._verifier_commands[verifier.event_id] = executable_words(_command_text(command))
|
||||
elif tool in {"bash", "host_shell"} and is_validation_command(command) and not mutation_paths:
|
||||
for path in self.requirements.required_artifacts:
|
||||
if _path_is_mentioned(command, path):
|
||||
@@ -736,6 +787,41 @@ class EvidenceLedger:
|
||||
artifact_path=path,
|
||||
)
|
||||
|
||||
def _supports_verifier_claim(self, identities: Sequence[str] = (), paths: Sequence[str] = ()) -> bool:
|
||||
"""Only the current passing verifier may support its named runner."""
|
||||
if self.evaluate().status != CompletionStatus.VERIFIED:
|
||||
return False
|
||||
latest = next((event for event in reversed(self.events)
|
||||
if event.kind == EvidenceKind.VERIFIER_RESULT and event.authoritative), None)
|
||||
if latest is None or not latest.success:
|
||||
return False
|
||||
words = self._verifier_commands.get(latest.event_id, ())
|
||||
names = {Path(words[0]).name} if words else set()
|
||||
if words and re.fullmatch(r'python(?:\d+(?:\.\d+)*)?', Path(words[0]).name) and '-m' in words:
|
||||
module_index = words.index('-m') + 1
|
||||
if module_index < len(words):
|
||||
names.add(words[module_index])
|
||||
return (all(identity in names for identity in identities)
|
||||
and all(any(_artifact_path_matches_required(word, path, self.requirements.workspace_root)
|
||||
for word in words) for path in paths))
|
||||
|
||||
def _supports_artifact_claim(self, kind: EvidenceKind, paths: Sequence[str]) -> bool:
|
||||
"""Match every claimed artifact by identity, never by basename."""
|
||||
targets = tuple(paths) or self.requirements.required_artifacts
|
||||
if not targets or (not paths and len(targets) != 1):
|
||||
return False
|
||||
for path in targets:
|
||||
matching = [event for event in self.events if event.kind == kind and event.authoritative
|
||||
and _artifact_path_matches_required(event.artifact_path, path, self.requirements.workspace_root)]
|
||||
successful = [event for event in matching if event.success]
|
||||
# Match evaluate(): atomic helper failures preserve the previous
|
||||
# successful artifact; a partial shell/Python failure may not.
|
||||
destructive_failure = bool(matching and not matching[-1].success
|
||||
and matching[-1].tool in {'bash', 'python'})
|
||||
if not successful or destructive_failure:
|
||||
return False
|
||||
return True
|
||||
|
||||
def record_media_ingress(self, metadata: Mapping[str, Any]) -> None:
|
||||
for artifact in metadata.get("artifacts") or []:
|
||||
if not isinstance(artifact, Mapping):
|
||||
|
||||
Reference in New Issue
Block a user