agent-lifecycle-kit 1.50.1__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.
- agent_lifecycle/__init__.py +5 -0
- agent_lifecycle/__main__.py +5 -0
- agent_lifecycle/_version.py +3 -0
- agent_lifecycle/adapter_sessions/__init__.py +41 -0
- agent_lifecycle/adapter_sessions/contracts.py +133 -0
- agent_lifecycle/adapter_sessions/env.py +44 -0
- agent_lifecycle/adapter_sessions/launcher.py +101 -0
- agent_lifecycle/adapter_sessions/process.py +39 -0
- agent_lifecycle/adapter_sessions/redaction.py +30 -0
- agent_lifecycle/adapter_sessions/session_store.py +64 -0
- agent_lifecycle/adapter_sessions/task_intake.py +450 -0
- agent_lifecycle/adapter_sessions/workflow_bridge.py +154 -0
- agent_lifecycle/audit/__init__.py +67 -0
- agent_lifecycle/audit/bug_forensics.py +94 -0
- agent_lifecycle/audit/implementation.py +516 -0
- agent_lifecycle/audit/ownership.py +119 -0
- agent_lifecycle/audit/proof_integrity.py +814 -0
- agent_lifecycle/audit/review_verdict.py +116 -0
- agent_lifecycle/changesets/__init__.py +5 -0
- agent_lifecycle/changesets/git.py +35 -0
- agent_lifecycle/cli/__init__.py +5 -0
- agent_lifecycle/cli/adapter.py +360 -0
- agent_lifecycle/cli/dispatch.py +1220 -0
- agent_lifecycle/cli/followup.py +89 -0
- agent_lifecycle/cli/main.py +41 -0
- agent_lifecycle/cli/metrics_parser.py +49 -0
- agent_lifecycle/cli/parsers.py +618 -0
- agent_lifecycle/cli/policy.py +101 -0
- agent_lifecycle/cli/progress_hooks.py +117 -0
- agent_lifecycle/cli/worktree.py +74 -0
- agent_lifecycle/compiler/__init__.py +17 -0
- agent_lifecycle/compiler/small_model_packets.py +322 -0
- agent_lifecycle/compiler/task_packets.py +229 -0
- agent_lifecycle/context/__init__.py +20 -0
- agent_lifecycle/context/episode_retrieval.py +30 -0
- agent_lifecycle/context/external_memory.py +71 -0
- agent_lifecycle/context/profiles.py +104 -0
- agent_lifecycle/context/rendering.py +226 -0
- agent_lifecycle/contracts/__init__.py +25 -0
- agent_lifecycle/contracts/adapter_contract_schemas.py +130 -0
- agent_lifecycle/contracts/adapter_event_schemas.py +118 -0
- agent_lifecycle/contracts/adapter_session_schemas.py +130 -0
- agent_lifecycle/contracts/adapter_task_schemas.py +90 -0
- agent_lifecycle/contracts/audit_schemas.py +133 -0
- agent_lifecycle/contracts/bug_forensics_schemas.py +400 -0
- agent_lifecycle/contracts/canonical.py +55 -0
- agent_lifecycle/contracts/compatibility.py +242 -0
- agent_lifecycle/contracts/context_model_schemas.py +265 -0
- agent_lifecycle/contracts/core_schemas.py +252 -0
- agent_lifecycle/contracts/cross_check_schemas.py +121 -0
- agent_lifecycle/contracts/errors.py +26 -0
- agent_lifecycle/contracts/evidence_import_schemas.py +152 -0
- agent_lifecycle/contracts/host_capability_schemas.py +64 -0
- agent_lifecycle/contracts/import_dialect_schemas.py +166 -0
- agent_lifecycle/contracts/metric_schemas.py +315 -0
- agent_lifecycle/contracts/paths.py +31 -0
- agent_lifecycle/contracts/plan_contract_schemas.py +148 -0
- agent_lifecycle/contracts/policy_schemas.py +350 -0
- agent_lifecycle/contracts/progress_bridge_schemas.py +114 -0
- agent_lifecycle/contracts/progress_hook_schemas.py +119 -0
- agent_lifecycle/contracts/proof_integrity_schemas.py +240 -0
- agent_lifecycle/contracts/release_contract_schemas.py +476 -0
- agent_lifecycle/contracts/review_mesh_recommendation_schemas.py +64 -0
- agent_lifecycle/contracts/review_mesh_schemas.py +222 -0
- agent_lifecycle/contracts/review_quality_schemas.py +109 -0
- agent_lifecycle/contracts/runner_schemas.py +91 -0
- agent_lifecycle/contracts/runner_worktree_schemas.py +389 -0
- agent_lifecycle/contracts/sandbox_schemas.py +159 -0
- agent_lifecycle/contracts/schema_builders.py +23 -0
- agent_lifecycle/contracts/schemas.py +93 -0
- agent_lifecycle/contracts/status_goal_schemas.py +469 -0
- agent_lifecycle/contracts/task_template_schemas.py +96 -0
- agent_lifecycle/contracts/usage_export_schemas.py +68 -0
- agent_lifecycle/diagnostics/__init__.py +17 -0
- agent_lifecycle/diagnostics/bundles.py +124 -0
- agent_lifecycle/diagnostics/readiness.py +733 -0
- agent_lifecycle/evidence_index/__init__.py +39 -0
- agent_lifecycle/evidence_index/core.py +272 -0
- agent_lifecycle/evidence_index/episode_index.py +329 -0
- agent_lifecycle/evidence_index/external_context.py +276 -0
- agent_lifecycle/followup/__init__.py +23 -0
- agent_lifecycle/followup/records.py +404 -0
- agent_lifecycle/freeze/__init__.py +5 -0
- agent_lifecycle/freeze/locks.py +23 -0
- agent_lifecycle/goal/__init__.py +15 -0
- agent_lifecycle/goal/records.py +244 -0
- agent_lifecycle/goal/view.py +109 -0
- agent_lifecycle/host_protocol/__init__.py +65 -0
- agent_lifecycle/host_protocol/acp_capability.py +195 -0
- agent_lifecycle/host_protocol/capabilities.py +268 -0
- agent_lifecycle/host_protocol/contracts.py +214 -0
- agent_lifecycle/host_protocol/event_capture.py +390 -0
- agent_lifecycle/host_protocol/events.py +196 -0
- agent_lifecycle/host_protocol/inspection.py +194 -0
- agent_lifecycle/host_protocol/inspection_common.py +310 -0
- agent_lifecycle/host_protocol/inspection_cursor.py +164 -0
- agent_lifecycle/host_protocol/inspection_gemini_cli.py +163 -0
- agent_lifecycle/host_protocol/inspection_hermes.py +161 -0
- agent_lifecycle/host_protocol/inspection_kimi_code.py +169 -0
- agent_lifecycle/host_protocol/inspection_opencode.py +147 -0
- agent_lifecycle/host_protocol/inspection_qwen_code.py +143 -0
- agent_lifecycle/host_protocol/receipts.py +58 -0
- agent_lifecycle/host_protocol/scaffold.py +329 -0
- agent_lifecycle/host_protocol/validation.py +229 -0
- agent_lifecycle/imports/__init__.py +76 -0
- agent_lifecycle/imports/agentskills_profile.py +54 -0
- agent_lifecycle/imports/bmad_profile.py +49 -0
- agent_lifecycle/imports/constitution_adr.py +91 -0
- agent_lifecycle/imports/dialect_profiles.py +121 -0
- agent_lifecycle/imports/external_agent.py +28 -0
- agent_lifecycle/imports/external_dialects.py +486 -0
- agent_lifecycle/imports/external_workflow.py +28 -0
- agent_lifecycle/imports/multi_markdown.py +111 -0
- agent_lifecycle/imports/openspec_profile.py +49 -0
- agent_lifecycle/imports/planning.py +536 -0
- agent_lifecycle/imports/spec_kit_profile.py +49 -0
- agent_lifecycle/imports/spec_kitty_profile.py +49 -0
- agent_lifecycle/metrics/__init__.py +60 -0
- agent_lifecycle/metrics/cost_collection.py +315 -0
- agent_lifecycle/metrics/costs.py +203 -0
- agent_lifecycle/metrics/outcome_index.py +330 -0
- agent_lifecycle/metrics/phase_resources.py +208 -0
- agent_lifecycle/metrics/recommendations.py +507 -0
- agent_lifecycle/metrics/regression_signals.py +64 -0
- agent_lifecycle/metrics/usage_export.py +390 -0
- agent_lifecycle/model_routing/__init__.py +19 -0
- agent_lifecycle/model_routing/profiles.py +323 -0
- agent_lifecycle/model_routing/receipts.py +140 -0
- agent_lifecycle/model_routing/resolver.py +566 -0
- agent_lifecycle/neutrality/__init__.py +12 -0
- agent_lifecycle/neutrality/__main__.py +6 -0
- agent_lifecycle/neutrality/authority.py +265 -0
- agent_lifecycle/neutrality/canonical.py +28 -0
- agent_lifecycle/neutrality/cli.py +294 -0
- agent_lifecycle/neutrality/ed25519.py +124 -0
- agent_lifecycle/neutrality/errors.py +89 -0
- agent_lifecycle/neutrality/gate.py +269 -0
- agent_lifecycle/neutrality/paths.py +92 -0
- agent_lifecycle/neutrality/policy.py +76 -0
- agent_lifecycle/neutrality/receipt.py +135 -0
- agent_lifecycle/neutrality/scanner.py +310 -0
- agent_lifecycle/neutrality/test_runner.py +116 -0
- agent_lifecycle/planning/__init__.py +47 -0
- agent_lifecycle/planning/acceptance_markdown.py +159 -0
- agent_lifecycle/planning/completeness.py +362 -0
- agent_lifecycle/planning/continuity.py +255 -0
- agent_lifecycle/planning/templates.py +294 -0
- agent_lifecycle/planning/tiering.py +87 -0
- agent_lifecycle/planning/validation.py +72 -0
- agent_lifecycle/policy/__init__.py +37 -0
- agent_lifecycle/policy/adaptive_lifecycle.py +416 -0
- agent_lifecycle/policy/apply.py +44 -0
- agent_lifecycle/policy/proposals.py +189 -0
- agent_lifecycle/policy/quality_floor.py +144 -0
- agent_lifecycle/policy/runtime_receipts.py +160 -0
- agent_lifecycle/py.typed +1 -0
- agent_lifecycle/quality/__init__.py +89 -0
- agent_lifecycle/quality/bug_forensics.py +727 -0
- agent_lifecycle/quality/bug_forensics_advisor.py +88 -0
- agent_lifecycle/quality/bug_forensics_recipes.py +239 -0
- agent_lifecycle/quality/cross_check.py +437 -0
- agent_lifecycle/quality/failure_classification.py +318 -0
- agent_lifecycle/quality/packs.py +265 -0
- agent_lifecycle/reporting/__init__.py +37 -0
- agent_lifecycle/reporting/change_summary.py +156 -0
- agent_lifecycle/reporting/event_feed.py +101 -0
- agent_lifecycle/reporting/progress_bridge.py +153 -0
- agent_lifecycle/reporting/progress_hooks.py +161 -0
- agent_lifecycle/reporting/progress_terminal.py +95 -0
- agent_lifecycle/reporting/progress_view.py +284 -0
- agent_lifecycle/reporting/status_view.py +125 -0
- agent_lifecycle/reporting/usage_export.py +59 -0
- agent_lifecycle/review/__init__.py +5 -0
- agent_lifecycle/review/validation.py +29 -0
- agent_lifecycle/review_mesh/__init__.py +83 -0
- agent_lifecycle/review_mesh/assignments.py +160 -0
- agent_lifecycle/review_mesh/contracts.py +685 -0
- agent_lifecycle/review_mesh/operator_templates.py +320 -0
- agent_lifecycle/review_mesh/quorum.py +38 -0
- agent_lifecycle/review_mesh/recommendation.py +487 -0
- agent_lifecycle/review_mesh/results.py +98 -0
- agent_lifecycle/review_mesh/synthesis.py +102 -0
- agent_lifecycle/runner/__init__.py +47 -0
- agent_lifecycle/runner/attempt_snapshots.py +244 -0
- agent_lifecycle/runner/core.py +653 -0
- agent_lifecycle/runner/sandbox_receipts.py +628 -0
- agent_lifecycle/specification/__init__.py +23 -0
- agent_lifecycle/specification/completion_check.py +135 -0
- agent_lifecycle/specification/completion_gate.py +501 -0
- agent_lifecycle/specification/completion_signal.py +75 -0
- agent_lifecycle/specification/validation.py +48 -0
- agent_lifecycle/workflow/__init__.py +79 -0
- agent_lifecycle/workflow/artifacts.py +74 -0
- agent_lifecycle/workflow/budget_decisions.py +370 -0
- agent_lifecycle/workflow/budget_policy.py +140 -0
- agent_lifecycle/workflow/budget_receipts.py +70 -0
- agent_lifecycle/workflow/bug_forensics_gates.py +284 -0
- agent_lifecycle/workflow/controller.py +45 -0
- agent_lifecycle/workflow/events.py +50 -0
- agent_lifecycle/workflow/final_proof_integrity.py +74 -0
- agent_lifecycle/workflow/finalization.py +422 -0
- agent_lifecycle/workflow/gates.py +185 -0
- agent_lifecycle/workflow/implementation_audit_gate.py +126 -0
- agent_lifecycle/workflow/leases.py +220 -0
- agent_lifecycle/workflow/lineage.py +108 -0
- agent_lifecycle/workflow/managed_runner.py +167 -0
- agent_lifecycle/workflow/model_usage.py +106 -0
- agent_lifecycle/workflow/next_action.py +86 -0
- agent_lifecycle/workflow/operation_kernel.py +98 -0
- agent_lifecycle/workflow/plan_adoption.py +439 -0
- agent_lifecycle/workflow/query.py +52 -0
- agent_lifecycle/workflow/review_mesh_gate.py +93 -0
- agent_lifecycle/workflow/reviews.py +168 -0
- agent_lifecycle/workflow/run_transitions.py +163 -0
- agent_lifecycle/workflow/sandbox_policy.py +214 -0
- agent_lifecycle/workflow/selectors.py +57 -0
- agent_lifecycle/workflow/state.py +130 -0
- agent_lifecycle/workflow/task_transitions.py +421 -0
- agent_lifecycle/worktree/__init__.py +17 -0
- agent_lifecycle/worktree/isolation.py +407 -0
- agent_lifecycle_kit-1.50.1.dist-info/METADATA +201 -0
- agent_lifecycle_kit-1.50.1.dist-info/RECORD +227 -0
- agent_lifecycle_kit-1.50.1.dist-info/WHEEL +5 -0
- agent_lifecycle_kit-1.50.1.dist-info/entry_points.txt +3 -0
- agent_lifecycle_kit-1.50.1.dist-info/licenses/LICENSE +201 -0
- agent_lifecycle_kit-1.50.1.dist-info/licenses/NOTICE +5 -0
- agent_lifecycle_kit-1.50.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
"""Adapter task intake classifier and managed-run delegator."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from agent_lifecycle.adapter_sessions.workflow_bridge import managed_adapter_run
|
|
9
|
+
from agent_lifecycle.contracts import (
|
|
10
|
+
LifecycleError,
|
|
11
|
+
canonical_digest,
|
|
12
|
+
load_json_object,
|
|
13
|
+
sha256_hex,
|
|
14
|
+
write_json_create,
|
|
15
|
+
)
|
|
16
|
+
from agent_lifecycle.imports import import_planning_input, import_planning_text
|
|
17
|
+
from agent_lifecycle.quality.bug_forensics_advisor import (
|
|
18
|
+
bug_forensics_recommended,
|
|
19
|
+
build_bug_forensics_advisory,
|
|
20
|
+
)
|
|
21
|
+
from agent_lifecycle.review_mesh.recommendation import recommend_review_mesh_for_text
|
|
22
|
+
|
|
23
|
+
ADAPTER_TASK_START_RECEIPT_SCHEMA = "agent-adapter-task-start-receipt.v1"
|
|
24
|
+
ADAPTER_TASK_RUN_REQUEST_SCHEMA = "agent-adapter-task-run-request.v1"
|
|
25
|
+
|
|
26
|
+
_ANALYSIS_FIRST_MARKERS = (
|
|
27
|
+
"analyze code",
|
|
28
|
+
"analyse code",
|
|
29
|
+
"analysis before",
|
|
30
|
+
"inspect before",
|
|
31
|
+
"investigate before",
|
|
32
|
+
"review code before",
|
|
33
|
+
"risk scan",
|
|
34
|
+
"проанализ",
|
|
35
|
+
"анализ кода",
|
|
36
|
+
"перед внедрением",
|
|
37
|
+
"перед реализацией",
|
|
38
|
+
"сначала анализ",
|
|
39
|
+
"сначала проверь",
|
|
40
|
+
"исследуй",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def start_adapter_task(
|
|
45
|
+
*,
|
|
46
|
+
adapter_id: str,
|
|
47
|
+
task_file: Path | None = None,
|
|
48
|
+
task_text: str | None = None,
|
|
49
|
+
candidate_out: Path | None = None,
|
|
50
|
+
descriptor_path: Path | None = None,
|
|
51
|
+
session_root: Path | None = None,
|
|
52
|
+
state_path: Path | None = None,
|
|
53
|
+
lock_path: Path | None = None,
|
|
54
|
+
task_id: str | None = None,
|
|
55
|
+
operation_id: str | None = None,
|
|
56
|
+
expected_revision: int | None = None,
|
|
57
|
+
source_revision: str | None = None,
|
|
58
|
+
max_input_bytes: int = 32768,
|
|
59
|
+
target_tokens: int = 4096,
|
|
60
|
+
package_id: str = "adapter-task-intake",
|
|
61
|
+
) -> dict[str, Any]:
|
|
62
|
+
"""Classify adapter task input without turning raw text into authority."""
|
|
63
|
+
|
|
64
|
+
source, source_blockers = _load_source(task_file=task_file, task_text=task_text)
|
|
65
|
+
if source is None:
|
|
66
|
+
return _receipt(
|
|
67
|
+
adapter_id=adapter_id,
|
|
68
|
+
source=_empty_source(),
|
|
69
|
+
action="BLOCKED",
|
|
70
|
+
status="BLOCKED",
|
|
71
|
+
blockers=source_blockers,
|
|
72
|
+
)
|
|
73
|
+
parsed = _parse_json(source["data"])
|
|
74
|
+
if parsed is not None and parsed.get("schemaVersion") == ADAPTER_TASK_RUN_REQUEST_SCHEMA:
|
|
75
|
+
return _from_run_request(
|
|
76
|
+
adapter_id=adapter_id,
|
|
77
|
+
request=parsed,
|
|
78
|
+
source=_source_summary(source),
|
|
79
|
+
descriptor_path=descriptor_path,
|
|
80
|
+
session_root=session_root,
|
|
81
|
+
)
|
|
82
|
+
if parsed is not None and parsed.get("schemaVersion") == "agent-plan-manifest.v1":
|
|
83
|
+
if parsed.get("status") == "FROZEN":
|
|
84
|
+
if source.get("path") is None:
|
|
85
|
+
return _receipt(
|
|
86
|
+
adapter_id=adapter_id,
|
|
87
|
+
source=_source_summary(source),
|
|
88
|
+
action="BLOCKED",
|
|
89
|
+
status="BLOCKED",
|
|
90
|
+
blockers=[{"code": "adapter-task-frozen-manifest-file-required"}],
|
|
91
|
+
)
|
|
92
|
+
return _from_frozen_manifest(
|
|
93
|
+
adapter_id=adapter_id,
|
|
94
|
+
manifest_path=Path(source["path"]),
|
|
95
|
+
source=_source_summary(source),
|
|
96
|
+
descriptor_path=descriptor_path,
|
|
97
|
+
session_root=session_root,
|
|
98
|
+
state_path=state_path,
|
|
99
|
+
lock_path=lock_path,
|
|
100
|
+
task_id=task_id,
|
|
101
|
+
operation_id=operation_id,
|
|
102
|
+
expected_revision=expected_revision,
|
|
103
|
+
source_revision=source_revision,
|
|
104
|
+
)
|
|
105
|
+
return _planning_intake(
|
|
106
|
+
adapter_id=adapter_id,
|
|
107
|
+
source=source,
|
|
108
|
+
candidate_out=candidate_out,
|
|
109
|
+
max_input_bytes=max_input_bytes,
|
|
110
|
+
target_tokens=target_tokens,
|
|
111
|
+
package_id=package_id,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _load_source(*, task_file: Path | None, task_text: str | None) -> tuple[dict[str, Any] | None, list[dict[str, Any]]]:
|
|
116
|
+
if (task_file is None and task_text is None) or (task_file is not None and task_text is not None):
|
|
117
|
+
return None, [{"code": "adapter-task-source-invalid", "message": "exactly one of --file/--task-file or --text/--task-text is required"}]
|
|
118
|
+
if task_text is not None:
|
|
119
|
+
data = task_text.encode("utf-8")
|
|
120
|
+
return {"kind": "TEXT", "label": "inline-task", "data": data, "text": task_text, "path": None}, []
|
|
121
|
+
assert task_file is not None
|
|
122
|
+
if not task_file.is_file():
|
|
123
|
+
return None, [{"code": "adapter-task-file-missing", "sourceLabel": task_file.name}]
|
|
124
|
+
data = task_file.read_bytes()
|
|
125
|
+
try:
|
|
126
|
+
text = data.decode("utf-8")
|
|
127
|
+
except UnicodeDecodeError:
|
|
128
|
+
text = ""
|
|
129
|
+
return {"kind": "FILE", "label": task_file.name, "data": data, "text": text, "path": task_file.as_posix()}, []
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _planning_intake(
|
|
133
|
+
*,
|
|
134
|
+
adapter_id: str,
|
|
135
|
+
source: dict[str, Any],
|
|
136
|
+
candidate_out: Path | None,
|
|
137
|
+
max_input_bytes: int,
|
|
138
|
+
target_tokens: int,
|
|
139
|
+
package_id: str,
|
|
140
|
+
) -> dict[str, Any]:
|
|
141
|
+
if source["kind"] == "TEXT":
|
|
142
|
+
planning = import_planning_text(
|
|
143
|
+
source["text"],
|
|
144
|
+
source_label=source["label"],
|
|
145
|
+
package_id=package_id,
|
|
146
|
+
max_input_bytes=max_input_bytes,
|
|
147
|
+
target_tokens=target_tokens,
|
|
148
|
+
)
|
|
149
|
+
else:
|
|
150
|
+
planning = import_planning_input(
|
|
151
|
+
Path(source["path"]),
|
|
152
|
+
package_id=package_id,
|
|
153
|
+
max_input_bytes=max_input_bytes,
|
|
154
|
+
target_tokens=target_tokens,
|
|
155
|
+
)
|
|
156
|
+
if candidate_out is not None:
|
|
157
|
+
write_json_create(candidate_out, planning)
|
|
158
|
+
shape = _classify_task(source.get("text", ""))
|
|
159
|
+
review_mesh_recommendation = recommend_review_mesh_for_text(
|
|
160
|
+
source.get("text", ""),
|
|
161
|
+
source_label=source["label"],
|
|
162
|
+
)
|
|
163
|
+
blockers = [{"code": item.get("code", "planning-import-blocker"), **({"source": "planning-import"} if "code" in item else {})} for item in planning.get("blockers", [])]
|
|
164
|
+
status = "BLOCKED" if planning.get("status") != "PASS" else "REVIEW_REQUIRED"
|
|
165
|
+
action = "BLOCKED" if status == "BLOCKED" else ("DRAFT_PLAN_REVIEW" if _parse_json(source["data"]) else "DRAFT_INTAKE")
|
|
166
|
+
return _receipt(
|
|
167
|
+
adapter_id=adapter_id,
|
|
168
|
+
source=_source_summary(source),
|
|
169
|
+
action=action,
|
|
170
|
+
status=status,
|
|
171
|
+
blockers=blockers,
|
|
172
|
+
planning_import=_planning_summary(planning),
|
|
173
|
+
detected_task_shape=shape["taskShape"],
|
|
174
|
+
recommended_quality_profiles=shape["recommendedQualityProfiles"],
|
|
175
|
+
bug_forensics_advisory=shape["bugForensicsAdvisory"],
|
|
176
|
+
pre_implementation_analysis=shape["preImplementationAnalysis"],
|
|
177
|
+
review_mesh_recommendation=review_mesh_recommendation,
|
|
178
|
+
requires_review=True,
|
|
179
|
+
audit_required=True,
|
|
180
|
+
freeze_blocked=True,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _from_run_request(
|
|
185
|
+
*,
|
|
186
|
+
adapter_id: str,
|
|
187
|
+
request: dict[str, Any],
|
|
188
|
+
source: dict[str, Any],
|
|
189
|
+
descriptor_path: Path | None,
|
|
190
|
+
session_root: Path | None,
|
|
191
|
+
) -> dict[str, Any]:
|
|
192
|
+
blockers = _run_request_blockers(adapter_id, request)
|
|
193
|
+
if blockers:
|
|
194
|
+
return _receipt(adapter_id=adapter_id, source=source, action="BLOCKED", status="BLOCKED", blockers=blockers)
|
|
195
|
+
return _managed_run_receipt(
|
|
196
|
+
adapter_id=adapter_id,
|
|
197
|
+
source=source,
|
|
198
|
+
descriptor_path=descriptor_path,
|
|
199
|
+
session_root=session_root,
|
|
200
|
+
state_path=Path(str(request["state"])),
|
|
201
|
+
manifest_path=Path(str(request["manifest"])),
|
|
202
|
+
lock_path=Path(str(request["lock"])) if request.get("lock") else None,
|
|
203
|
+
task_id=str(request["task"]),
|
|
204
|
+
operation_id=str(request["operationId"]),
|
|
205
|
+
expected_revision=int(request["expectedRevision"]),
|
|
206
|
+
source_revision=str(request["sourceRevision"]),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _from_frozen_manifest(
|
|
211
|
+
*,
|
|
212
|
+
adapter_id: str,
|
|
213
|
+
manifest_path: Path,
|
|
214
|
+
source: dict[str, Any],
|
|
215
|
+
descriptor_path: Path | None,
|
|
216
|
+
session_root: Path | None,
|
|
217
|
+
state_path: Path | None,
|
|
218
|
+
lock_path: Path | None,
|
|
219
|
+
task_id: str | None,
|
|
220
|
+
operation_id: str | None,
|
|
221
|
+
expected_revision: int | None,
|
|
222
|
+
source_revision: str | None,
|
|
223
|
+
) -> dict[str, Any]:
|
|
224
|
+
missing = [
|
|
225
|
+
name
|
|
226
|
+
for name, value in {
|
|
227
|
+
"state": state_path,
|
|
228
|
+
"lock": lock_path,
|
|
229
|
+
"task": task_id,
|
|
230
|
+
"operationId": operation_id,
|
|
231
|
+
"expectedRevision": expected_revision,
|
|
232
|
+
"sourceRevision": source_revision,
|
|
233
|
+
}.items()
|
|
234
|
+
if value in {None, ""}
|
|
235
|
+
]
|
|
236
|
+
if missing:
|
|
237
|
+
return _receipt(
|
|
238
|
+
adapter_id=adapter_id,
|
|
239
|
+
source=source,
|
|
240
|
+
action="BLOCKED",
|
|
241
|
+
status="BLOCKED",
|
|
242
|
+
blockers=[{"code": "adapter-task-frozen-binding-missing", "fields": missing}],
|
|
243
|
+
)
|
|
244
|
+
return _managed_run_receipt(
|
|
245
|
+
adapter_id=adapter_id,
|
|
246
|
+
source=source,
|
|
247
|
+
descriptor_path=descriptor_path,
|
|
248
|
+
session_root=session_root,
|
|
249
|
+
state_path=state_path or Path(""),
|
|
250
|
+
manifest_path=manifest_path,
|
|
251
|
+
lock_path=lock_path,
|
|
252
|
+
task_id=str(task_id),
|
|
253
|
+
operation_id=str(operation_id),
|
|
254
|
+
expected_revision=int(expected_revision or 0),
|
|
255
|
+
source_revision=str(source_revision),
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _managed_run_receipt(
|
|
260
|
+
*,
|
|
261
|
+
adapter_id: str,
|
|
262
|
+
source: dict[str, Any],
|
|
263
|
+
descriptor_path: Path | None,
|
|
264
|
+
session_root: Path | None,
|
|
265
|
+
state_path: Path,
|
|
266
|
+
manifest_path: Path,
|
|
267
|
+
lock_path: Path | None,
|
|
268
|
+
task_id: str,
|
|
269
|
+
operation_id: str,
|
|
270
|
+
expected_revision: int,
|
|
271
|
+
source_revision: str,
|
|
272
|
+
) -> dict[str, Any]:
|
|
273
|
+
try:
|
|
274
|
+
session_receipt = managed_adapter_run(
|
|
275
|
+
adapter_id=adapter_id,
|
|
276
|
+
descriptor_path=descriptor_path,
|
|
277
|
+
session_root=session_root,
|
|
278
|
+
state_path=state_path,
|
|
279
|
+
manifest_path=manifest_path,
|
|
280
|
+
lock_path=lock_path,
|
|
281
|
+
task_id=task_id,
|
|
282
|
+
operation_id=operation_id,
|
|
283
|
+
expected_revision=expected_revision,
|
|
284
|
+
source_revision=source_revision,
|
|
285
|
+
)
|
|
286
|
+
except LifecycleError as exc:
|
|
287
|
+
return _receipt(
|
|
288
|
+
adapter_id=adapter_id,
|
|
289
|
+
source=source,
|
|
290
|
+
action="BLOCKED",
|
|
291
|
+
status="BLOCKED",
|
|
292
|
+
blockers=[{"code": exc.code, "message": exc.message, "context": exc.details}],
|
|
293
|
+
)
|
|
294
|
+
blockers = list(session_receipt.get("blockers", []))
|
|
295
|
+
status = "BLOCKED" if session_receipt.get("status") == "BLOCKED" or blockers else "READY"
|
|
296
|
+
return _receipt(
|
|
297
|
+
adapter_id=adapter_id,
|
|
298
|
+
source=source,
|
|
299
|
+
action="MANAGED_RUN" if status == "READY" else "BLOCKED",
|
|
300
|
+
status=status,
|
|
301
|
+
blockers=blockers,
|
|
302
|
+
adapter_session_receipt=session_receipt,
|
|
303
|
+
execution_started=status == "READY",
|
|
304
|
+
lifecycle_coverage_claimed=bool(session_receipt.get("lifecycleCoverageClaimed")) and status == "READY",
|
|
305
|
+
requires_review=False,
|
|
306
|
+
audit_required=False,
|
|
307
|
+
freeze_blocked=False,
|
|
308
|
+
workflow_binding={
|
|
309
|
+
"state": state_path.as_posix(),
|
|
310
|
+
"manifest": manifest_path.as_posix(),
|
|
311
|
+
"lock": lock_path.as_posix() if lock_path else None,
|
|
312
|
+
"task": task_id,
|
|
313
|
+
"operationId": operation_id,
|
|
314
|
+
"expectedRevision": expected_revision,
|
|
315
|
+
"sourceRevision": source_revision,
|
|
316
|
+
},
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _run_request_blockers(adapter_id: str, request: dict[str, Any]) -> list[dict[str, Any]]:
|
|
321
|
+
blockers: list[dict[str, Any]] = []
|
|
322
|
+
for field in ("state", "manifest", "task", "operationId", "expectedRevision", "sourceRevision"):
|
|
323
|
+
value = request.get(field)
|
|
324
|
+
if value in {None, ""}:
|
|
325
|
+
blockers.append({"code": "adapter-task-run-request-field-missing", "field": field})
|
|
326
|
+
expected_revision = request.get("expectedRevision")
|
|
327
|
+
if not isinstance(expected_revision, int) or isinstance(expected_revision, bool) or expected_revision < 1:
|
|
328
|
+
blockers.append({"code": "adapter-task-run-request-revision-invalid"})
|
|
329
|
+
request_adapter = request.get("adapterId") or request.get("adapter")
|
|
330
|
+
if isinstance(request_adapter, str) and request_adapter and request_adapter != adapter_id:
|
|
331
|
+
blockers.append({"code": "adapter-task-run-request-adapter-mismatch", "expected": adapter_id, "actual": request_adapter})
|
|
332
|
+
if request.get("productionPromotionClaimed") is not False and "productionPromotionClaimed" in request:
|
|
333
|
+
blockers.append({"code": "adapter-task-run-request-production-claim"})
|
|
334
|
+
digest = request.get("requestDigest")
|
|
335
|
+
if digest is not None:
|
|
336
|
+
expected = canonical_digest({key: value for key, value in request.items() if key != "requestDigest"})
|
|
337
|
+
if digest != expected:
|
|
338
|
+
blockers.append({"code": "adapter-task-run-request-digest-mismatch"})
|
|
339
|
+
return blockers
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def _classify_task(text: str) -> dict[str, Any]:
|
|
343
|
+
lowered = text.lower()
|
|
344
|
+
advisory = build_bug_forensics_advisory(text)
|
|
345
|
+
defect = bug_forensics_recommended(advisory)
|
|
346
|
+
analysis = any(marker in lowered for marker in _ANALYSIS_FIRST_MARKERS)
|
|
347
|
+
profiles = list(advisory["recommendedQualityProfiles"]) if defect else []
|
|
348
|
+
task_shape = "bugfix" if defect else ("analysis-first" if analysis else ("feature" if text.strip() else "unknown"))
|
|
349
|
+
purpose = None
|
|
350
|
+
if analysis:
|
|
351
|
+
purpose = "bug-investigation" if defect else "feature-discovery"
|
|
352
|
+
return {
|
|
353
|
+
"taskShape": task_shape,
|
|
354
|
+
"recommendedQualityProfiles": profiles,
|
|
355
|
+
"bugForensicsAdvisory": advisory,
|
|
356
|
+
"preImplementationAnalysis": {
|
|
357
|
+
"required": analysis,
|
|
358
|
+
"purpose": purpose,
|
|
359
|
+
"activeWorkflowGateClaimed": False,
|
|
360
|
+
},
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _planning_summary(planning: dict[str, Any]) -> dict[str, Any]:
|
|
365
|
+
candidate = planning.get("candidatePlan")
|
|
366
|
+
return {
|
|
367
|
+
"schemaVersion": planning.get("schemaVersion"),
|
|
368
|
+
"status": planning.get("status"),
|
|
369
|
+
"candidateLifecycleStatus": planning.get("candidateLifecycleStatus"),
|
|
370
|
+
"requiresReview": planning.get("requiresReview"),
|
|
371
|
+
"auditRequired": planning.get("auditRequired"),
|
|
372
|
+
"freezeBlocked": planning.get("freezeBlocked"),
|
|
373
|
+
"source": planning.get("source"),
|
|
374
|
+
"candidateDigest": canonical_digest(candidate) if isinstance(candidate, dict) else None,
|
|
375
|
+
"importDigest": planning.get("importDigest"),
|
|
376
|
+
"blockerCodes": [item.get("code") for item in planning.get("blockers", []) if isinstance(item, dict)],
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _source_summary(source: dict[str, Any]) -> dict[str, Any]:
|
|
381
|
+
return {
|
|
382
|
+
"type": source["kind"],
|
|
383
|
+
"label": source["label"],
|
|
384
|
+
"digest": sha256_hex(source["data"]),
|
|
385
|
+
"byteCount": len(source["data"]),
|
|
386
|
+
"rawTextStored": False,
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _empty_source() -> dict[str, Any]:
|
|
391
|
+
return {"type": "NONE", "label": None, "digest": sha256_hex(b""), "byteCount": 0, "rawTextStored": False}
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _parse_json(data: bytes) -> dict[str, Any] | None:
|
|
395
|
+
try:
|
|
396
|
+
return load_json_object(data, label="adapter task input")
|
|
397
|
+
except LifecycleError:
|
|
398
|
+
return None
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _receipt(
|
|
402
|
+
*,
|
|
403
|
+
adapter_id: str,
|
|
404
|
+
source: dict[str, Any],
|
|
405
|
+
action: str,
|
|
406
|
+
status: str,
|
|
407
|
+
blockers: list[dict[str, Any]] | None = None,
|
|
408
|
+
planning_import: dict[str, Any] | None = None,
|
|
409
|
+
adapter_session_receipt: dict[str, Any] | None = None,
|
|
410
|
+
detected_task_shape: str = "unknown",
|
|
411
|
+
recommended_quality_profiles: list[str] | None = None,
|
|
412
|
+
pre_implementation_analysis: dict[str, Any] | None = None,
|
|
413
|
+
execution_started: bool = False,
|
|
414
|
+
lifecycle_coverage_claimed: bool = False,
|
|
415
|
+
requires_review: bool = False,
|
|
416
|
+
audit_required: bool = False,
|
|
417
|
+
freeze_blocked: bool = False,
|
|
418
|
+
workflow_binding: dict[str, Any] | None = None,
|
|
419
|
+
review_mesh_recommendation: dict[str, Any] | None = None,
|
|
420
|
+
bug_forensics_advisory: dict[str, Any] | None = None,
|
|
421
|
+
) -> dict[str, Any]:
|
|
422
|
+
body = {
|
|
423
|
+
"schemaVersion": ADAPTER_TASK_START_RECEIPT_SCHEMA,
|
|
424
|
+
"status": status,
|
|
425
|
+
"adapterId": adapter_id,
|
|
426
|
+
"input": source,
|
|
427
|
+
"action": action,
|
|
428
|
+
"detectedTaskShape": detected_task_shape,
|
|
429
|
+
"recommendedQualityProfiles": recommended_quality_profiles or [],
|
|
430
|
+
"preImplementationAnalysis": pre_implementation_analysis
|
|
431
|
+
or {"required": False, "purpose": None, "activeWorkflowGateClaimed": False},
|
|
432
|
+
"executionStarted": execution_started,
|
|
433
|
+
"lifecycleCoverageClaimed": lifecycle_coverage_claimed,
|
|
434
|
+
"requiresReview": requires_review,
|
|
435
|
+
"auditRequired": audit_required,
|
|
436
|
+
"freezeBlocked": freeze_blocked,
|
|
437
|
+
"reviewBlockers": blockers or [],
|
|
438
|
+
"planningImport": planning_import,
|
|
439
|
+
"adapterSessionReceipt": adapter_session_receipt,
|
|
440
|
+
"workflowBinding": workflow_binding,
|
|
441
|
+
"reviewMeshRecommendation": review_mesh_recommendation,
|
|
442
|
+
"bugForensicsAdvisory": bug_forensics_advisory,
|
|
443
|
+
"modelCallsStarted": False,
|
|
444
|
+
"hostLaunchStarted": bool(adapter_session_receipt.get("hostLaunchStarted")) if isinstance(adapter_session_receipt, dict) else False,
|
|
445
|
+
"secretsWritten": False,
|
|
446
|
+
"nativeConfigWritten": False,
|
|
447
|
+
"rawTaskTextStored": False,
|
|
448
|
+
"productionPromotionClaimed": False,
|
|
449
|
+
}
|
|
450
|
+
return {**body, "receiptDigest": canonical_digest(body)}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Composition between managed adapter sessions and ALK workflow state."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from agent_lifecycle.adapter_sessions.contracts import build_adapter_session_receipt, build_resume_receipt
|
|
9
|
+
from agent_lifecycle.adapter_sessions.launcher import load_adapter_descriptor, managed_launch_profile
|
|
10
|
+
from agent_lifecycle.adapter_sessions.session_store import create_session, load_session, update_session
|
|
11
|
+
from agent_lifecycle.contracts import read_json_object
|
|
12
|
+
from agent_lifecycle.workflow import run_managed_lifecycle_step
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def managed_adapter_run(
|
|
16
|
+
*,
|
|
17
|
+
adapter_id: str,
|
|
18
|
+
state_path: Path,
|
|
19
|
+
manifest_path: Path,
|
|
20
|
+
lock_path: Path | None,
|
|
21
|
+
task_id: str,
|
|
22
|
+
operation_id: str,
|
|
23
|
+
expected_revision: int,
|
|
24
|
+
source_revision: str,
|
|
25
|
+
descriptor_path: Path | None = None,
|
|
26
|
+
session_root: Path | None = None,
|
|
27
|
+
) -> dict[str, Any]:
|
|
28
|
+
_descriptor_path, descriptor = load_adapter_descriptor(adapter_id, descriptor_path)
|
|
29
|
+
profile = managed_launch_profile(descriptor)
|
|
30
|
+
runner_receipt = run_managed_lifecycle_step(
|
|
31
|
+
state_path=state_path,
|
|
32
|
+
manifest_path=manifest_path,
|
|
33
|
+
lock_path=lock_path,
|
|
34
|
+
operation_id=operation_id,
|
|
35
|
+
expected_revision=expected_revision,
|
|
36
|
+
source_revision=source_revision,
|
|
37
|
+
reason=f"managed adapter run for {task_id}",
|
|
38
|
+
)
|
|
39
|
+
state_identity = {**_state_identity(state_path), "taskId": task_id}
|
|
40
|
+
proof = _managed_proof("adapter run", adapter_id=adapter_id, task_id=task_id, state_identity=state_identity)
|
|
41
|
+
session = create_session(
|
|
42
|
+
adapter_id=adapter_id,
|
|
43
|
+
mode="MANAGED_TASK",
|
|
44
|
+
status="READY" if runner_receipt["status"] == "PASS" else "BLOCKED",
|
|
45
|
+
launch_profile=profile,
|
|
46
|
+
session_root=session_root,
|
|
47
|
+
state_identity=state_identity,
|
|
48
|
+
managed_workflow_proof=proof,
|
|
49
|
+
)
|
|
50
|
+
return build_adapter_session_receipt(
|
|
51
|
+
status=session["status"],
|
|
52
|
+
session_id=session["sessionId"],
|
|
53
|
+
adapter_id=adapter_id,
|
|
54
|
+
mode="MANAGED_TASK",
|
|
55
|
+
launch_profile=profile,
|
|
56
|
+
state_identity=state_identity,
|
|
57
|
+
managed_workflow_proof=proof,
|
|
58
|
+
progress_hook_default="stderr",
|
|
59
|
+
host_launch_started=False,
|
|
60
|
+
blockers=runner_receipt.get("blockers", []),
|
|
61
|
+
next_action=runner_receipt.get("nextAction"),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def promote_session_to_workflow(
|
|
66
|
+
*,
|
|
67
|
+
session_id: str,
|
|
68
|
+
state_path: Path,
|
|
69
|
+
task_id: str,
|
|
70
|
+
adapter_id: str | None = None,
|
|
71
|
+
session_root: Path | None = None,
|
|
72
|
+
) -> dict[str, Any]:
|
|
73
|
+
session = load_session(session_id, session_root=session_root)
|
|
74
|
+
if adapter_id and session.get("adapterId") != adapter_id:
|
|
75
|
+
return build_resume_receipt(
|
|
76
|
+
session_id=session_id,
|
|
77
|
+
adapter_id=adapter_id,
|
|
78
|
+
expected_identity={"adapterId": adapter_id},
|
|
79
|
+
actual_identity={"adapterId": session.get("adapterId")},
|
|
80
|
+
blockers=[{"code": "adapter-session-adapter-mismatch"}],
|
|
81
|
+
)
|
|
82
|
+
identity = {**_state_identity(state_path), "taskId": task_id}
|
|
83
|
+
proof = _managed_proof("adapter session promote", adapter_id=session["adapterId"], task_id=task_id, state_identity=identity)
|
|
84
|
+
session["mode"] = "PROMOTED"
|
|
85
|
+
session["status"] = "READY"
|
|
86
|
+
session["stateIdentity"] = identity
|
|
87
|
+
session["managedWorkflowProof"] = proof
|
|
88
|
+
update_session(session, session_root=session_root)
|
|
89
|
+
return build_adapter_session_receipt(
|
|
90
|
+
status="READY",
|
|
91
|
+
session_id=session_id,
|
|
92
|
+
adapter_id=session["adapterId"],
|
|
93
|
+
mode="PROMOTED",
|
|
94
|
+
launch_profile=session.get("launchProfile", {}),
|
|
95
|
+
state_identity=identity,
|
|
96
|
+
managed_workflow_proof=proof,
|
|
97
|
+
progress_hook_default="stderr",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def resume_adapter_session(
|
|
102
|
+
*,
|
|
103
|
+
session_id: str,
|
|
104
|
+
session_root: Path | None = None,
|
|
105
|
+
adapter_id: str | None = None,
|
|
106
|
+
state_path: Path | None = None,
|
|
107
|
+
task_id: str | None = None,
|
|
108
|
+
) -> dict[str, Any]:
|
|
109
|
+
session = load_session(session_id, session_root=session_root)
|
|
110
|
+
expected: dict[str, Any] = {}
|
|
111
|
+
blockers: list[dict[str, Any]] = []
|
|
112
|
+
if adapter_id:
|
|
113
|
+
if session.get("adapterId") != adapter_id:
|
|
114
|
+
blockers.append({"code": "adapter-session-adapter-mismatch", "expected": adapter_id, "actual": session.get("adapterId")})
|
|
115
|
+
if task_id:
|
|
116
|
+
expected["taskId"] = task_id
|
|
117
|
+
actual = session.get("stateIdentity") if isinstance(session.get("stateIdentity"), dict) else {}
|
|
118
|
+
if state_path is not None:
|
|
119
|
+
expected.update(_state_identity(state_path))
|
|
120
|
+
for key, expected_value in expected.items():
|
|
121
|
+
if actual.get(key) != expected_value:
|
|
122
|
+
blockers.append({"code": "adapter-session-lineage-mismatch", "field": key, "expected": expected_value, "actual": actual.get(key)})
|
|
123
|
+
return build_resume_receipt(
|
|
124
|
+
session_id=session_id,
|
|
125
|
+
adapter_id=session.get("adapterId", adapter_id or ""),
|
|
126
|
+
expected_identity=expected,
|
|
127
|
+
actual_identity=actual,
|
|
128
|
+
blockers=blockers,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _state_identity(state_path: Path) -> dict[str, Any]:
|
|
133
|
+
state = read_json_object(state_path, label="workflow state")
|
|
134
|
+
return {
|
|
135
|
+
"statePath": state_path.as_posix(),
|
|
136
|
+
"runId": state.get("runId"),
|
|
137
|
+
"packageId": state.get("packageId"),
|
|
138
|
+
"planRevision": state.get("planRevision"),
|
|
139
|
+
"planDigest": state.get("planDigest"),
|
|
140
|
+
"sourceRevision": state.get("sourceRevision"),
|
|
141
|
+
"stateRevision": state.get("stateRevision"),
|
|
142
|
+
"phase": state.get("phase"),
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _managed_proof(command: str, *, adapter_id: str, task_id: str, state_identity: dict[str, Any]) -> dict[str, Any]:
|
|
147
|
+
return {
|
|
148
|
+
"kind": "alk-managed-adapter-session",
|
|
149
|
+
"status": "PASS",
|
|
150
|
+
"command": command,
|
|
151
|
+
"adapterId": adapter_id,
|
|
152
|
+
"taskId": task_id,
|
|
153
|
+
"stateIdentity": state_identity,
|
|
154
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Audit helpers for frozen lifecycle plans."""
|
|
2
|
+
|
|
3
|
+
from agent_lifecycle.audit.ownership import build_ownership_report
|
|
4
|
+
from agent_lifecycle.audit.proof_integrity import (
|
|
5
|
+
build_finding_identity,
|
|
6
|
+
build_fix_impact_receipt,
|
|
7
|
+
build_hash_chain_migration_policy,
|
|
8
|
+
build_proof_integrity_receipt,
|
|
9
|
+
build_receipt_hash_chain,
|
|
10
|
+
build_root_cause_evidence,
|
|
11
|
+
finding_identity_fields,
|
|
12
|
+
require_proof_integrity_pass,
|
|
13
|
+
stable_finding_id,
|
|
14
|
+
validate_finding_identity,
|
|
15
|
+
validate_fix_impact_receipt,
|
|
16
|
+
validate_hash_chain_migration_policy,
|
|
17
|
+
validate_proof_integrity_receipt,
|
|
18
|
+
validate_receipt_hash_chain,
|
|
19
|
+
validate_root_cause_evidence,
|
|
20
|
+
)
|
|
21
|
+
from agent_lifecycle.audit.review_verdict import (
|
|
22
|
+
compact_review_routing,
|
|
23
|
+
require_review_verdict_pass,
|
|
24
|
+
validate_review_verdict,
|
|
25
|
+
)
|
|
26
|
+
from agent_lifecycle.audit.bug_forensics import (
|
|
27
|
+
build_bug_forensics_audit,
|
|
28
|
+
require_bug_forensics_audit_pass,
|
|
29
|
+
validate_bug_forensics_audit,
|
|
30
|
+
)
|
|
31
|
+
from agent_lifecycle.audit.implementation import (
|
|
32
|
+
build_final_implementation_audit,
|
|
33
|
+
build_implementation_audit_report,
|
|
34
|
+
require_implementation_audit_accepted,
|
|
35
|
+
validate_final_implementation_audit,
|
|
36
|
+
validate_implementation_audit_report,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"build_bug_forensics_audit",
|
|
41
|
+
"build_ownership_report",
|
|
42
|
+
"build_final_implementation_audit",
|
|
43
|
+
"build_implementation_audit_report",
|
|
44
|
+
"build_finding_identity",
|
|
45
|
+
"build_fix_impact_receipt",
|
|
46
|
+
"build_hash_chain_migration_policy",
|
|
47
|
+
"build_proof_integrity_receipt",
|
|
48
|
+
"build_receipt_hash_chain",
|
|
49
|
+
"build_root_cause_evidence",
|
|
50
|
+
"compact_review_routing",
|
|
51
|
+
"finding_identity_fields",
|
|
52
|
+
"require_proof_integrity_pass",
|
|
53
|
+
"require_bug_forensics_audit_pass",
|
|
54
|
+
"require_review_verdict_pass",
|
|
55
|
+
"require_implementation_audit_accepted",
|
|
56
|
+
"stable_finding_id",
|
|
57
|
+
"validate_finding_identity",
|
|
58
|
+
"validate_bug_forensics_audit",
|
|
59
|
+
"validate_final_implementation_audit",
|
|
60
|
+
"validate_implementation_audit_report",
|
|
61
|
+
"validate_fix_impact_receipt",
|
|
62
|
+
"validate_hash_chain_migration_policy",
|
|
63
|
+
"validate_proof_integrity_receipt",
|
|
64
|
+
"validate_receipt_hash_chain",
|
|
65
|
+
"validate_root_cause_evidence",
|
|
66
|
+
"validate_review_verdict",
|
|
67
|
+
]
|