Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
135 lines
6.1 KiB
Python
135 lines
6.1 KiB
Python
"""Separate verified business progress from supervisor liveness."""
|
|
|
|
import json
|
|
import pathlib
|
|
import re
|
|
from datetime import datetime
|
|
|
|
|
|
def _read(root, relative, maximum=2 * 1024 * 1024):
|
|
if not isinstance(relative, str) or pathlib.Path(relative).is_absolute():
|
|
return {}
|
|
path = root / relative
|
|
try:
|
|
if not path.resolve().is_relative_to(root.resolve()):
|
|
return {}
|
|
current = root
|
|
for part in pathlib.Path(relative).parts:
|
|
current /= part
|
|
if current.is_symlink():
|
|
return {}
|
|
if path.stat().st_size > maximum:
|
|
return {}
|
|
value = json.loads(path.read_text())
|
|
return value if isinstance(value, dict) else {}
|
|
except (OSError, ValueError, TypeError):
|
|
return {}
|
|
|
|
|
|
def business_progress(root, state):
|
|
root = pathlib.Path(root)
|
|
backlog = _read(root, "tests/golden/WBV2/web-product-backlog.json")
|
|
tasks = backlog.get("tasks", [])
|
|
valid = set(state.get("verification", {}).get("validJobs", []))
|
|
stale = set(state.get("verification", {}).get("staleJobs", []))
|
|
assignments = _read(root, "tests/golden/WBV2/autopilot/local-task-assignments.json")
|
|
assignment_map = {item.get("job"): item for item in assignments.get("assignments", [])
|
|
if isinstance(item, dict)}
|
|
blockers = []
|
|
retryable = []
|
|
failures = []
|
|
active = state.get("activeJob")
|
|
records = state.get("jobs", {})
|
|
for task in tasks:
|
|
identifier = task.get("id", "")
|
|
if identifier in valid or identifier == active:
|
|
continue
|
|
record = records.get(identifier, {})
|
|
if record.get("state") == "behavior_pending":
|
|
blockers.append({
|
|
"job": identifier, "module": task.get("module"),
|
|
"category": "behavior_contract_missing", "reason": record.get("reason"),
|
|
"workflow": task.get("implementation"), "commands": task.get("commands", [])[:8],
|
|
"sourceUnits": [], "candidateTests": [],
|
|
"nextActions": ["Implement route-specific assertions and fresh receipt producers"],
|
|
})
|
|
continue
|
|
if record.get("state") in {"blocked", "provider_blocked"}:
|
|
failure = {"job": identifier, "reason": record.get("reason"),
|
|
"runDirectory": record.get("runDirectory")}
|
|
run_directory = record.get("runDirectory")
|
|
if isinstance(run_directory, str):
|
|
diagnostic_path = f"{run_directory}/cases/native-business-diagnostic.json"
|
|
diagnostic = _read(root, diagnostic_path, 128 * 1024)
|
|
if (diagnostic.get("schemaVersion") == 1 and diagnostic.get("job") == identifier
|
|
and diagnostic.get("status") == "FAIL"
|
|
and isinstance(diagnostic.get("findings"), list)):
|
|
failure["diagnostic"] = diagnostic_path
|
|
failure["repairActions"] = [finding for finding in diagnostic["findings"][:8]
|
|
if isinstance(finding, dict)]
|
|
failure["reproduce"] = diagnostic.get("reproduce")
|
|
failures.append(failure)
|
|
continue
|
|
assignment = assignment_map.get(identifier, {})
|
|
if identifier in stale or assignment.get("state") == "ready":
|
|
retryable.append(identifier)
|
|
continue
|
|
preparation = {}
|
|
if re.fullmatch(r"[A-Z0-9][A-Z0-9_-]{0,95}", identifier):
|
|
preparation = _read(root, f"tests/golden/WBV2/autopilot/preparation/{identifier}.json", 128 * 1024)
|
|
blocker = preparation.get("businessBlocker", {})
|
|
blockers.append({
|
|
"job": identifier, "module": task.get("module"),
|
|
"category": blocker.get("category", "preparation_required"),
|
|
"workflow": preparation.get("workflow", task.get("implementation")),
|
|
"firstSeenAt": blocker.get("firstSeenAt"),
|
|
"inputChangedAt": blocker.get("inputChangedAt"),
|
|
"commands": preparation.get("commands", task.get("commands", []))[:8],
|
|
"sourceUnits": [unit.get("id") for unit in preparation.get("sourceUnits", [])[:8]],
|
|
"candidateTests": preparation.get("candidateTests", [])[:4],
|
|
"sourceSearch": blocker.get("sourceSearch"),
|
|
"contractPath": blocker.get("contractPath"),
|
|
"nextActions": preparation.get("nextActions", [])[:4],
|
|
})
|
|
blockers.sort(key=lambda item: (not bool(item["sourceUnits"]),
|
|
not bool(item["candidateTests"]), item["job"]))
|
|
verified_times = []
|
|
for identifier in valid:
|
|
receipt = _read(root, records.get(identifier, {}).get("receipt"))
|
|
timestamp = receipt.get("verifiedAt")
|
|
if receipt.get("status") != "verified" and receipt.get("status") != "PASS":
|
|
continue
|
|
if isinstance(timestamp, str):
|
|
try:
|
|
parsed = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
|
|
if parsed.tzinfo is not None:
|
|
verified_times.append((parsed, timestamp))
|
|
except ValueError:
|
|
pass
|
|
if active:
|
|
phase = "executing"
|
|
elif retryable:
|
|
phase = "ready_for_validation"
|
|
elif failures:
|
|
phase = "waiting_for_failure_repair"
|
|
elif blockers:
|
|
phase = "waiting_for_implementation"
|
|
else:
|
|
phase = "registered_workflows_verified"
|
|
categories = {}
|
|
for blocker in blockers:
|
|
categories[blocker["category"]] = categories.get(blocker["category"], 0) + 1
|
|
return {
|
|
"state": phase,
|
|
"registeredTasks": len(tasks),
|
|
"validWorkflows": len(valid),
|
|
"lastVerifiedAt": max(verified_times)[1] if verified_times else None,
|
|
"activeJob": active,
|
|
"readyForValidation": retryable,
|
|
"validationFailures": failures,
|
|
"needsImplementation": len(blockers),
|
|
"blockerCategories": categories,
|
|
"nextImplementationTasks": blockers[:5],
|
|
"progressBasis": "Hash-valid workflow receipts; heartbeat and input changes are not business completion",
|
|
}
|