diff --git a/docs/status/WBV2-P1161-001.md b/docs/status/WBV2-P1161-001.md index aa451af30..ad48d4a64 100644 --- a/docs/status/WBV2-P1161-001.md +++ b/docs/status/WBV2-P1161-001.md @@ -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` diff --git a/my-tools/authorize_next_wbv2_task.py b/my-tools/authorize_next_wbv2_task.py index 3154fa0df..7971bddb4 100644 --- a/my-tools/authorize_next_wbv2_task.py +++ b/my-tools/authorize_next_wbv2_task.py @@ -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 diff --git a/nextTask.md b/nextTask.md index aa4d042b9..61c0d5084 100644 --- a/nextTask.md +++ b/nextTask.md @@ -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