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>
79 lines
3.7 KiB
Python
79 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Prepare actionable repair tasks from declared workflow inputs and failures."""
|
|
import json
|
|
from pathlib import Path
|
|
from wbv2_autopilot import ROOT, read_json, write_json
|
|
|
|
REQUIRED = {
|
|
"positive": ["before", "after"],
|
|
"negative": ["before", "after"],
|
|
"undo_redo": ["before", "after", "undo", "redo"],
|
|
"save_reopen": ["saved", "reopened"],
|
|
"determinism": ["first", "second"],
|
|
}
|
|
|
|
|
|
def prepare(root=ROOT):
|
|
root = Path(root)
|
|
backlog = read_json(root / "tests/golden/WBV2/web-product-backlog.json", {})
|
|
records = read_json(root / "tests/golden/WBV2/autopilot/state.json", {}).get("jobs", {})
|
|
tasks = []
|
|
for job in backlog.get("tasks", []):
|
|
identifier = job["id"]
|
|
path = root / "my-tools/local-workflows" / (identifier + ".json")
|
|
if not path.is_file():
|
|
path = root / "tests/golden/WBV2/autopilot/local-plans" / (identifier + ".json")
|
|
contract = read_json(path, {})
|
|
result = contract.get("result", {})
|
|
record = records.get(identifier, {})
|
|
incomplete = result.get("contractKind") == "compilation_only" or not result.get("cases")
|
|
failed = record.get("state") in {"blocked", "provider_blocked", "needs_reconcile"} or (
|
|
record.get("state") == "retry_pending" and bool(record.get("reason")))
|
|
if not incomplete and not failed:
|
|
continue
|
|
declared = sorted(set(result.get("dependencies", [])))
|
|
fixtures = [p for p in declared if p.endswith(".blend") and (root / p).is_file()]
|
|
specs = sorted({p for check in result.get("checks", []) for p in check.get("argv", [])
|
|
if p.endswith(".spec.ts")})
|
|
specs = [p if p.startswith("web/") else "web/" + p for p in specs]
|
|
category = "behavior_contract_missing" if incomplete else "runtime_failure"
|
|
reason = record.get("reason") or category
|
|
if not incomplete and "receipt" in reason:
|
|
category = "receipt_producer_mismatch"
|
|
if not incomplete and not specs:
|
|
category = "receipt_producer_missing"
|
|
tasks.append({
|
|
"job": identifier, "module": job.get("module"), "workflow": job.get("title"),
|
|
"state": "behavior_pending" if incomplete else "repair_required",
|
|
"category": category, "reason": reason,
|
|
"fixtures": fixtures, "fixtureSelectionRequired": not bool(fixtures),
|
|
"routeIds": result.get("routeIds", []),
|
|
"sourceUnits": result.get("sourceUnits", []),
|
|
"sourceReferences": result.get("sourceReferences", []),
|
|
"candidateTests": [p for p in specs if (root / p).is_file()],
|
|
"missingTests": [p for p in specs if not (root / p).is_file()],
|
|
"requiredObservations": REQUIRED,
|
|
"nextActions": [
|
|
"Inspect the declared native route and fixture data",
|
|
"Implement assertions and independent replay for this workflow",
|
|
"Publish receipts only after assertions; bind exact caseId, kind and unitIds",
|
|
],
|
|
"runDirectory": record.get("runDirectory"),
|
|
})
|
|
destination = root / "tests/golden/WBV2/autopilot/behavior-pending.json"
|
|
document = {"schemaVersion": 2, "policy": "repair plan only; no contract or acceptance mutation", "tasks": tasks}
|
|
if read_json(destination, {}) != document:
|
|
write_json(destination, document)
|
|
return document
|
|
|
|
|
|
def main():
|
|
document = prepare()
|
|
print(json.dumps({"tasks": len(document["tasks"]),
|
|
"behaviorPending": sum(t["state"] == "behavior_pending" for t in document["tasks"]),
|
|
"repairRequired": sum(t["state"] == "repair_required" for t in document["tasks"])}))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|