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>
103 lines
5.6 KiB
Python
103 lines
5.6 KiB
Python
import json
|
|
import pathlib
|
|
import tempfile
|
|
import unittest
|
|
|
|
from wbv2_business_status import business_progress
|
|
|
|
|
|
class BusinessStatusTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.directory = tempfile.TemporaryDirectory()
|
|
self.addCleanup(self.directory.cleanup)
|
|
self.root = pathlib.Path(self.directory.name)
|
|
self.write("tests/golden/WBV2/web-product-backlog.json", {"tasks": [
|
|
{"id": "READY", "commands": ["one"]},
|
|
{"id": "MISSING", "commands": ["two"]},
|
|
]})
|
|
|
|
def write(self, path, value):
|
|
target = self.root / path
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
target.write_text(json.dumps(value))
|
|
|
|
def test_heartbeat_cannot_advance_verified_business_time(self):
|
|
self.write("receipt.json", {"status": "verified", "verifiedAt": "2026-09-09T03:00:00+00:00"})
|
|
state = {"verification": {"validJobs": ["READY"]},
|
|
"jobs": {"READY": {"receipt": "receipt.json"}}, "heartbeatAt": "2026-09-09T03:10:00+00:00"}
|
|
first = business_progress(self.root, state)
|
|
state["heartbeatAt"] = "2026-09-10T03:10:00+00:00"
|
|
self.assertEqual(first, business_progress(self.root, state))
|
|
self.assertEqual(first["lastVerifiedAt"], "2026-09-09T03:00:00+00:00")
|
|
self.assertEqual(first["state"], "waiting_for_implementation")
|
|
|
|
def test_stale_evidence_is_not_progress(self):
|
|
self.write("receipt.json", {"status": "verified", "verifiedAt": "2026-09-09T03:00:00+00:00"})
|
|
result = business_progress(self.root, {"verification": {"staleJobs": ["READY"]},
|
|
"jobs": {"READY": {"receipt": "receipt.json"}}})
|
|
self.assertIsNone(result["lastVerifiedAt"])
|
|
self.assertEqual(result["readyForValidation"], ["READY"])
|
|
self.assertEqual(result["validWorkflows"], 0)
|
|
|
|
def test_blocked_job_does_not_hide_an_independent_runnable_job(self):
|
|
self.write("tests/golden/WBV2/autopilot/local-task-assignments.json", {
|
|
"assignments": [{"job": "READY", "state": "ready"}]})
|
|
result = business_progress(self.root, {"jobs": {"MISSING": {
|
|
"state": "blocked", "reason": "native test failed"}}})
|
|
self.assertEqual(result["state"], "ready_for_validation")
|
|
self.assertEqual(result["readyForValidation"], ["READY"])
|
|
self.assertEqual(result["validationFailures"][0]["job"], "MISSING")
|
|
|
|
def test_missing_recipe_reports_action_and_not_completion(self):
|
|
self.write("tests/golden/WBV2/autopilot/preparation/MISSING.json", {
|
|
"commands": ["two"], "sourceUnits": [{"id": "web-command:two"}],
|
|
"candidateTests": ["web/tests/e2e/two.spec.ts"],
|
|
"nextActions": ["Validate two and bind its native result"],
|
|
"businessBlocker": {"category": "workflow_contract_missing", "contractPath": "my-tools/local-workflows/MISSING.json"}})
|
|
result = business_progress(self.root, {})
|
|
self.assertEqual(result["nextImplementationTasks"][0]["job"], "MISSING")
|
|
self.assertEqual(result["needsImplementation"], 2)
|
|
self.assertEqual(result["validWorkflows"], 0)
|
|
|
|
def test_behavior_pending_is_not_ready_despite_an_old_ready_assignment(self):
|
|
self.write("tests/golden/WBV2/autopilot/local-task-assignments.json", {
|
|
"assignments": [{"job": "MISSING", "state": "ready"}]})
|
|
result = business_progress(self.root, {"jobs": {"MISSING": {
|
|
"state": "behavior_pending", "reason": "compilation-only"}}})
|
|
self.assertNotIn("MISSING", result["readyForValidation"])
|
|
pending = next(item for item in result["nextImplementationTasks"] if item["job"] == "MISSING")
|
|
self.assertEqual(pending["category"], "behavior_contract_missing")
|
|
self.assertEqual(result["validationFailures"], [])
|
|
|
|
def test_external_receipt_cannot_supply_progress(self):
|
|
result = business_progress(self.root, {"verification": {"validJobs": ["READY"]},
|
|
"jobs": {"READY": {"receipt": "../foreign.json"}}})
|
|
self.assertIsNone(result["lastVerifiedAt"])
|
|
|
|
def test_native_failure_exposes_the_current_attempt_repair_action(self):
|
|
run = "tests/golden/WBV2/autopilot/runs/MISSING-attempt"
|
|
self.write(f"{run}/cases/native-business-diagnostic.json", {
|
|
"schemaVersion": 1, "job": "MISSING", "status": "FAIL",
|
|
"findings": [{"assertion": "evaluated_value", "sourceUnit": "web-command:two",
|
|
"symbol": "native_two", "message": "evaluated value differed"}],
|
|
"reproduce": {"argv": ["node", "my-tools/diagnostic.mjs"], "cwd": "."},
|
|
})
|
|
state = {"jobs": {"MISSING": {"state": "blocked", "runDirectory": run}}}
|
|
failure = business_progress(self.root, state)["validationFailures"][0]
|
|
self.assertEqual(failure["repairActions"][0]["sourceUnit"], "web-command:two")
|
|
self.assertEqual(failure["reproduce"]["argv"][0], "node")
|
|
self.assertEqual(business_progress(self.root, state)["validWorkflows"], 0)
|
|
|
|
def test_other_job_or_success_diagnostics_do_not_create_repair_actions(self):
|
|
run = "tests/golden/WBV2/autopilot/runs/MISSING-attempt"
|
|
state = {"jobs": {"MISSING": {"state": "blocked", "runDirectory": run}}}
|
|
for job, status in [("READY", "FAIL"), ("MISSING", "PASS")]:
|
|
self.write(f"{run}/cases/native-business-diagnostic.json", {
|
|
"schemaVersion": 1, "job": job, "status": status, "findings": [{"message": "old"}]})
|
|
failure = business_progress(self.root, state)["validationFailures"][0]
|
|
self.assertNotIn("repairActions", failure)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|