feat(web): keep unattended planner heartbeat active
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-09-03 22:25:01 +08:00
parent 9ec940941d
commit 9ad74fdd4a
3 changed files with 66 additions and 7 deletions

View File

@@ -6,4 +6,4 @@
- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt
- dynamic source inventory: `3745` units; verified `523`; unverified `3222`; planning estimate `5200` (non-binding); this-segment binding delta: `6`
- historical 6900-entry inventory remains read-only; full-family parity: `false`
- nextTask: `NONE`
- nextTask: `WBV2-P1162-000`

View File

@@ -11,6 +11,7 @@ from __future__ import annotations
import argparse
import hashlib
import json
import os
import re
import subprocess
from datetime import datetime, timezone
@@ -19,6 +20,9 @@ from pathlib import Path
from wbv2_runtime import CONTROL_ROOT, INDEX, QUEUE, ROOT, read_json, terminal_pointer
AUTO_PLANNER_STATUS = CONTROL_ROOT / "auto-planner.json"
PREFERRED_BATCHES = [
{
"moduleId": "MODIFIER_READER_BATCH",
@@ -130,6 +134,17 @@ PREFERRED_BATCHES = [
"production": "tests/golden/{task}/shape-key-reader-production.json",
"types": [],
},
{
"moduleId": "MODIFIER_SHAPEKEY_READER_BATCH",
"title": "verify shape key modifier reader dependency",
"owner": "MODIFIER",
"identifiers": ["MOD_shapekey"],
"rna": ["ShapeKeyPoint"],
"fixture": "tests/files/web/rigged_shape_scene.blend",
"test": "web/tests/e2e/wbv2-shape-key-reader-production.spec.ts",
"production": "tests/golden/{task}/shape-key-reader-production.json",
"types": [],
},
{
"moduleId": "LINE_STYLE_READER_BATCH",
"title": "verify line style reader batch",
@@ -267,6 +282,24 @@ def write_text(path: Path, value: str) -> None:
path.write_text(value, encoding="utf-8")
def write_planner_status(payload: dict) -> None:
"""Persist a deduplicated planner heartbeat for unattended observability."""
value = {"schemaVersion": 1, **payload}
try:
current = read_json(AUTO_PLANNER_STATUS)
stable_current = {key: item for key, item in current.items() if key != "updatedAt"}
stable_value = {key: item for key, item in value.items() if key != "updatedAt"}
if stable_current == stable_value:
return
except (OSError, AttributeError):
pass
value["updatedAt"] = datetime.now(timezone.utc).isoformat()
AUTO_PLANNER_STATUS.parent.mkdir(parents=True, exist_ok=True)
temporary = AUTO_PLANNER_STATUS.with_suffix(AUTO_PLANNER_STATUS.suffix + f".tmp-{os.getpid()}")
temporary.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
temporary.replace(AUTO_PLANNER_STATUS)
def rel(path: Path) -> str:
return path.relative_to(ROOT).as_posix()
@@ -331,6 +364,16 @@ def discover_existing_evidence_batch(inventory: dict) -> dict | None:
}
def pending_summary(inventory: dict) -> dict:
pending = [unit for unit in inventory.get("units", []) if isinstance(unit, dict) and unit.get("coverageStatus") != "VERIFIED"]
by_kind: dict[str, int] = {}
by_family: dict[str, int] = {}
for unit in pending:
by_kind[unit.get("kind", "UNKNOWN")] = by_kind.get(unit.get("kind", "UNKNOWN"), 0) + 1
by_family[unit.get("family", "UNKNOWN")] = by_family.get(unit.get("family", "UNKNOWN"), 0) + 1
return {"count": len(pending), "byKind": by_kind, "byFamily": by_family, "sample": [unit.get("id") for unit in pending[:12]]}
def run_node(*args: str) -> None:
result = subprocess.run(["node", *args], cwd=ROOT, text=True, capture_output=True, check=False)
output = result.stdout or result.stderr
@@ -545,7 +588,14 @@ def select_batch(inventory: dict) -> dict:
discovered = discover_existing_evidence_batch(inventory)
if discovered:
return discovered
raise SystemExit("no configured unresolved Blender source batch remains")
summary = pending_summary(inventory)
write_planner_status({
"status": "waiting_for_exact_evidence",
"reason": "no_configured_unresolved_source_batch",
"pending": summary,
"nextAction": "add a real fixture/adapter or exact Chromium receipt; do not fabricate coverage",
})
raise SystemExit(f"no configured unresolved Blender source batch remains; pending={summary['count']} sample={summary['sample']}")
def main() -> int:
@@ -568,6 +618,15 @@ def main() -> int:
batch = select_batch(inventory)
contract = batch_contract(module_task, batch)
batch["batchId"] = contract["batchId"]
write_planner_status({
"status": "ready",
"reason": "source_backed_batch_selected",
"task": module_task,
"moduleId": batch["moduleId"],
"batchId": contract["batchId"],
"selectedRecordIds": contract["selectedRecordIds"],
"nextAction": "scheduler runs the focused module gate",
})
if not args.write:
print(json.dumps({"status": "ready", "rootTask": root_task, "nextTask": module_task, "moduleId": batch["moduleId"], "batchId": contract["batchId"], "batchSize": len(batch["units"]), "selectedRecordIds": contract["selectedRecordIds"], "sourceUnits": [unit["id"] for unit in batch["units"]], "adaptive": {"key": batch.get("adaptiveKey"), "history": batch.get("adaptiveHistory", []), "nextSize": batch.get("adaptiveNextSize", len(batch["units"]))}}, ensure_ascii=False))
return 0

View File

@@ -467,12 +467,12 @@ Recorded: 2026-08-29 Asia/Shanghai
| Field | Value |
| --- | --- |
| Current task when this file was written | `WBV2-P1161-001` |
| Current task state | `done` |
| Parent manifest | `tests/golden/WBV2-P1161-001/manifest.json` |
| Current task card | `docs/tasks/WBV2-P1161-001.md` |
| Current task when this file was written | `WBV2-P1162-001` |
| Current task state | `in_progress` |
| Parent manifest | `tests/golden/WBV2-P1162-000/manifest.json` |
| Current task card | `docs/tasks/WBV2-P1162-001.md` |
| Current task-context nextTask | `NONE` |
| Focused command | `node tools/web/check-wbv2-module-execution.mjs` |
| Focused command | `node tools/web/run-wbv2-module-task.mjs --task WBV2-P1162-001 --write` |
The snapshot is informational and may become stale. On every resume, the queue,
parent manifest, and fresh `print-task-context` output win. Never infer a task