trace-field-notes / schemas.py
JacobLinCool's picture
feat: add privacy filtering and execution modes
8457788 verified
Raw
History Blame Contribute Delete
7.21 kB
"""Shared data structures and codebook constants for Trace Field Notes."""
from __future__ import annotations
from dataclasses import asdict, dataclass, field
from typing import Any, Literal
AgentType = Literal["codex", "claude_code", "pi", "unknown"]
DIFFICULTY_TYPES = {
"requirement_uncertainty": "Requirements, specification, or user intent are unclear.",
"localization_difficulty": "The relevant module, file, function, or root cause is unclear.",
"architecture_complexity": "The system structure, dependencies, or shared surfaces are more complex than expected.",
"implementation_difficulty": "The direction is known, but the implementation is non-trivial.",
"compatibility_risk": "A change may break existing behavior or nearby surfaces.",
"verification_difficulty": "It is unclear how to verify that the work is correct.",
"environment_blocker": "Dependencies, permissions, network, runtime, or local environment block progress.",
"insufficient_context": "The agent reports that more context is needed.",
"conflicting_assumptions": "A prior assumption conflicts with new evidence.",
"unknown": "The evidence is too weak to classify.",
}
APPRAISALS = {
"local_fix_possible": "The agent frames the issue as locally fixable.",
"needs_more_context": "The agent says it needs more information.",
"initial_hypothesis_wrong": "The agent revises an earlier hypothesis.",
"risk_is_higher_than_expected": "The agent recognizes higher side-effect or regression risk.",
"scope_too_large": "The agent decides the original scope is too broad.",
"needs_alternative_path": "The agent seeks a different route.",
"cannot_reliably_verify": "The agent says verification is not reliable yet.",
"task_boundary_unclear": "The agent sees the task boundary as unclear.",
"unknown": "The evidence is too weak to classify.",
}
DETOUR_TYPES = {
"direct_continuation": "The agent continues the original strategy.",
"decomposition": "The agent breaks the problem down.",
"scope_narrowing": "The agent narrows the scope.",
"alternative_path": "The agent switches route.",
"workaround": "The agent works around the issue without resolving the root cause.",
"rollback_or_reversal": "The agent abandons or reverses a prior direction.",
"hypothesis_switch": "The agent changes its problem hypothesis.",
"verification_shift": "The agent changes verification strategy.",
"ask_or_defer": "The agent asks for input or defers judgment.",
"premature_closure": "The agent closes before the difficulty is resolved.",
"unknown": "The evidence is too weak to classify.",
}
RESOLUTION_MODES = {
"information_gathering": "The episode resolves through additional context.",
"problem_reframing": "The agent reframes the problem.",
"minimal_patch": "The agent applies a focused patch.",
"structural_change": "The agent makes or proposes a structural change.",
"defensive_handling": "The agent adds guards, validation, or explicit handling.",
"alternative_implementation": "The agent changes implementation approach.",
"goal_reduction": "The agent lowers the goal or solves a subset.",
"explicit_limitation": "The agent explicitly states a limitation.",
"narrative_rationalization": "The agent smooths over unresolved evidence in prose.",
"unknown": "The evidence is too weak to classify.",
}
RECOVERY_PATTERNS = {
"smooth_recovery": "The agent quickly understands the issue and moves forward.",
"iterative_recovery": "The agent recovers through repeated attempts.",
"detour_recovery": "The agent recovers after a route change.",
"partial_recovery": "The agent solves part of the issue while preserving caveats.",
"failed_recovery": "The episode does not recover.",
"avoidant_recovery": "The agent bypasses the difficulty by doing adjacent work.",
"overconfident_recovery": "The agent claims success without enough visible support.",
"reflective_recovery": "The agent identifies a wrong assumption and corrects course.",
"unknown": "The evidence is too weak to classify.",
}
OUTCOME_CLAIMS = {
"resolved_with_confidence": "The agent clearly claims completion.",
"resolved_with_caveat": "The agent claims completion with a caveat.",
"partially_resolved": "The agent says only part of the work is complete.",
"not_resolved": "The agent says the issue remains unresolved.",
"needs_verification": "The agent says more testing or confirmation is needed.",
"uncertain_but_proceeding": "The agent proceeds despite uncertainty.",
"premature_success_claim": "The agent claims success with weak visible evidence.",
"unknown": "The evidence is too weak to classify.",
}
@dataclass(slots=True)
class NarrativeMessage:
"""A visible user or assistant message extracted from an agent trace."""
index: int
role: Literal["assistant", "user"]
text: str
timestamp: str | None = None
source: str = "unknown"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(slots=True)
class MessageSpan:
start_index: int
end_index: int
start_time: str | None = None
end_time: str | None = None
duration_label: str = "unknown"
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(slots=True)
class DifficultyEpisode:
episode_id: str
title: str
message_span: MessageSpan
initial_intention: str
reported_difficulty: str
difficulty_type: str
appraisal: str
strategy_before: str
strategy_after: str
detour_type: str
resolution_mode: str
recovery_pattern: str
outcome_claim: str
productive_detour: Literal["yes", "no", "mixed", "unknown"]
evidence_quotes: list[str] = field(default_factory=list)
analyst_memo: str = ""
def to_dict(self) -> dict[str, Any]:
data = asdict(self)
data["message_span"] = self.message_span.to_dict()
return data
@dataclass(slots=True)
class AnalysisResult:
trace_title: str
agent_type_guess: AgentType
analysis_scope: str
privacy_notes: list[str]
episodes: list[DifficultyEpisode]
overall_patterns: dict[str, str]
narrative_message_count: int
redaction_count: int = 0
engine: str = "deterministic-codebook"
model_notes: list[str] = field(default_factory=list)
model_memo: dict[str, Any] = field(default_factory=dict)
session_verdict: dict[str, Any] = field(default_factory=dict)
def to_dict(self) -> dict[str, Any]:
return {
"trace_title": self.trace_title,
"agent_type_guess": self.agent_type_guess,
"analysis_scope": self.analysis_scope,
"privacy_notes": self.privacy_notes,
"episodes": [episode.to_dict() for episode in self.episodes],
"overall_patterns": self.overall_patterns,
"narrative_message_count": self.narrative_message_count,
"redaction_count": self.redaction_count,
"engine": self.engine,
"model_notes": self.model_notes,
"model_memo": self.model_memo,
"session_verdict": self.session_verdict,
}