Files
FreeCADWasmDev/tools/repair_scheduler_failure_ledger.py
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

128 lines
20 KiB
Python

#!/usr/bin/env python3
"""Repair known historical scheduler diagnostics without dropping their evidence."""
from __future__ import annotations
import json
import sys
import hashlib
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path("/home/mes123456/FreeCADWasmDev/working/FreeCAD")
LEDGER = ROOT / "docs/current/freecad-web-scheduler-failures.json"
EVIDENCE = ROOT / "docs/p6/scheduler-failure-replay-20260903-current.json"
REPLAYS = {
"fd99d0bd6af3c55de6e3": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && PART_BATCH_MANIFEST=docs/p6/part-module-batch-42ec634ad97d472d26e94af1-replay.json timeout 180s node tools/run_p6_part_module_batch_gate.mjs freecad-source/build-web/configure/bin'",
"4f9886c8adeb8ce9ae47": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/prepare_web_task_context.py && python3 tools/validate_web_context.py'",
"61c1f1c8ff1eed00debe": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/check_continuation_state.py && rg --files docs/current/context | sort >/dev/null && python3 tools/validate_incremental_context.py'",
"bcad09ef5650ee593442": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && PART_BATCH_MANIFEST=docs/p6/part-module-batch-42ec634ad97d472d26e94af1-replay.json timeout 180s node tools/run_p6_part_module_batch_gate.mjs freecad-source/build-web/configure/bin'",
"b6d2d064de2a45e6d04c": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 90s node tools/run_p6_partdesign_action03_facade.mjs /home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin'",
"68b9c8aa091b38b74779": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 120s node tools/run_p6_partdesign_action03_facade.mjs /home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin'",
"16de634a623640e63e4f": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && sed -n \"880,965p\" freecad-source/src/WebAssembly/FreeCADCoreProbe/PartDesignRuntimeProbe.cpp >/dev/null && sed -n \"1,125p\" tools/run_p6_partdesign_module_batch_gate.mjs >/dev/null && (rg -n \"pythonFamilyBatch\" web/src/partdesign.worker.ts || true)'",
"85780f23eaeea4ace00c": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 60s node tools/replay_scheduler_failure_diagnostics.mjs mirroring'",
"3d9f5146967a2c63ad90": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -c \"import json; m=json.load(open(\\\"docs/p6/sketcher-module-batch-5f77f3aca8e66e65e76c3d5a-runtime.json\\\"); print(json.dumps({k:m.get(k) for k in (\\\"schema\\\",\\\"taskId\\\",\\\"batchId\\\",\\\"status\\\")}, ensure_ascii=False)); rows=json.load(open(\\\"docs/p6/object-contract-matrix.json\\\"))[\\\"records\\\"]; print(sum(1 for row in rows if row.get(\\\"id\\\") in {\\\"obj:Sketcher:Sketcher::Constraint\\\",\\\"obj:Sketcher:Sketcher::ExternalGeometryExtension\\\",\\\"obj:Sketcher:Sketcher::ExternalGeometryFacade\\\",\\\"obj:Sketcher:Sketcher::GeometryFacade\\\"})); print(json.load(open(\\\"docs/current/module-batch-manifest.json\\\"))[\\\"batchId\\\"])\"'",
"a1190ada987f0b7224ef": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && git status --short --untracked-files=all 2>/dev/null | rg \"sketcher|FW-P6-FPA-Y|scheduler-failure\" || true'",
"9f4e66a06ff5d7253483": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && (rg -n \"pythonFamilyBatch|geometry-value|tier-1-readonly\" freecad-source/src/WebAssembly/FreeCADCoreProbe/DraftRuntimeProbe.cpp web/src/draft-python-family-facade.ts tools/run_p6_draft* | head -220 || true) && python3 -c \"import json; b=json.load(open(\\\"docs/current/module-batch-manifest.json\\\")); print(len(b.get(\\\"records\\\", [])))\" && sed -n \"1,150p\" tools/run_p6_draft_python_family_gate.mjs >/dev/null'",
"d8adbe1d57f5337d2df4": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && sed -n \"1,260p\" docs/current/task-state.json && printf \"\\n--- context manifest ---\\n\" && sed -n \"1,300p\" docs/current/context/FW-P6-FPA-Y.json && printf \"\\n--- nextTask ---\\n\" && sed -n \"1,320p\" nextTask.md && printf \"\\n--- batch ---\\n\" && sed -n \"1,320p\" docs/current/module-batch-manifest.json && printf \"\\n--- continuation ---\\n\" && sed -n \"1,260p\" docs/current/continuation-state.json'",
"5edf8e1a9fdd7a075e31": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node tools/replay_scheduler_failure_diagnostics.mjs batch'",
"eb0aa522833316439ddc": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/repair_scheduler_failure_ledger.py && python3 -c \"import json; d=json.load(open(\\\"docs/current/freecad-web-scheduler-failures.json\\\"))[\\\"failures\\\"]; print(len(d))\"'",
"d9af1131d2221d88009b": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node tools/replay_scheduler_failures_20260903.mjs'",
"285fefc5661260434679": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/replay_partdesign_batch_manifest.py docs/p6/partdesign-module-batch-44135cbb934774be38ea97d9-runtime.json /tmp/freecad-partdesign-object-batch.json && PARTDESIGN_BATCH_MANIFEST=/tmp/freecad-partdesign-object-batch.json node tools/run_p6_partdesign_module_batch_gate.mjs /home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin'",
"1a736f486824f4769b89": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/replay_partdesign_batch_manifest.py docs/p6/partdesign-geometry-module-batch-89811eb6dca58379a849409b-runtime.json /tmp/freecad-partdesign-geometry-batch.json && timeout 180s env PARTDESIGN_BATCH_MANIFEST=/tmp/freecad-partdesign-geometry-batch.json node tools/run_p6_partdesign_geometry_module_batch_gate.mjs /home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin'",
"490b7cb48eb8ac5615ec": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -c \"import json; print(json.load(open(\\\"docs/current/module-batch-manifest.json\\\"))[\\\"records\\\"])\" && python3 tools/replay_partdesign_batch_manifest.py docs/p6/partdesign-geometry-module-batch-89811eb6dca58379a849409b-runtime.json /tmp/freecad-partdesign-geometry-batch.json && PARTDESIGN_BATCH_MANIFEST=/tmp/freecad-partdesign-geometry-batch.json node tools/run_p6_partdesign_geometry_module_batch_gate.mjs /home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin'",
"da3dc21fe80f404d135f": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -m json.tool docs/current/continuation-state.json >/dev/null && python3 tools/check_continuation_state.py && python3 tools/validate_web_context.py && python3 tools/prepare_web_task_context.py && python3 tools/validate_web_context.py'",
"e63ba1660a219b76a558": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 60s node tools/replay_scheduler_failure_diagnostics.mjs load'",
"58a91ab80533e82af142": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 90s node tools/replay_scheduler_failure_diagnostics.mjs mirroring'",
"895d0ed88db8e7b25d57": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 90s node tools/replay_scheduler_failure_diagnostics.mjs offsets'",
"abf7a8eab781e8239b31": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 90s node tools/replay_scheduler_failure_diagnostics.mjs common'",
"84a44eda9a92862925f2": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/prepare_web_task_context.py && python3 tools/validate_web_context.py'",
"91e8e4c2ee3ea13169af": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && sed -n \'1,260p\' docs/current/context/FW-P6-FPA-Y.json'",
"8afd2718de841de016e1": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -c \"import json; d=json.load(open(\\\"docs/current/freecad-web-scheduler-failures.json\\\")); print(len(d.get(\\\"failures\\\", {})))\" && python3 tools/check_continuation_state.py'",
"a2209225a57a5ecae445": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && timeout 180s node tools/replay_scheduler_failure_diagnostics.mjs batch'",
"dffe38b22c3a307801b0": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 - <<'PY'\nimport json\nd=json.load(open('web/public/api/python-api-index.json'))\nfields=d.get('fields', {})\nprint('field groups', sorted(fields))\nrows=d.get('records', [])\nprint('records', len(rows))\nprint('first', rows[0] if rows else None)\nPY\"",
"f59a606c6f951d1bca36": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/prepare_web_task_context.py && python3 tools/validate_web_context.py && python3 tools/check_continuation_state.py'",
"e22952468c4cddf9234d": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 - <<'PY'\nimport json\nfrom pathlib import Path\nfor p in [Path('docs/p6/python-api-manifest.json'), Path('web/public/api/python-api-index.json')]:\n obj=json.loads(p.read_text())\n rows=obj.get('records', [])\n fields=obj.get('fields', {})\n print(p, type(obj).__name__, sorted(obj.keys()))\n print('records', len(rows), 'field_groups', sorted(fields) if isinstance(fields, dict) else fields)\n found=[]\n for row in rows:\n ident=row if isinstance(row,dict) else dict(zip(fields, row)) if isinstance(fields,list) and isinstance(row,list) else {}\n if ident.get('id') == 'py:Material:function:translate' or ident.get('apiId') == 'py:Material:function:translate' or ident.get('name') == 'translate':\n found.append({k:ident.get(k) for k in ('id','apiId','name','disposition','module','source')})\n print('found', found[:5])\nPY\"",
"4ec38fbb432c6976b5e6": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && rg -n \"FilletBase|PROPERTY_SOURCE\\(Part::(Fillet|Chamfer)\" freecad-source/src/Mod/Part/App/FeatureFillet.h freecad-source/src/Mod/Part/App/FeatureFillet.cpp freecad-source/src/Mod/Part/App/FeatureChamfer.cpp'",
"ae486bcbe2296a55a935": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -c 'import json; p=\\\"docs/p6/part-module-batch-ab1ecf6b27bbeb2b672b3358-runtime.json\\\"; d=json.load(open(p)); [print(json.dumps(r, ensure_ascii=False)) for r in d.get(\\\"result\\\", {}).get(\\\"records\\\", [])]'\"",
"2b1357b8c78f3c8be5d2": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && find docs/p6 -maxdepth 1 -type f -printf \"%f\\n\" | rg \"^part-module-batch-\"'",
"fa12d700badb170e7a9b": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && find docs/p6 -maxdepth 1 -type f -printf \"%f\\n\" | rg \"^part-module-batch-\" | head -30'",
"c96b921f3c0b4bfad928": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -c 'import json; d=json.load(open(\\\"docs/current/freecad-web-scheduler-failures.json\\\")); [print(k, d[\\\"failures\\\"][k][\\\"resolved\\\"]) for k in (\\\"9071363e1e191a7b17a3\\\", \\\"3ff488d61cfa06f77973\\\", \\\"9f0197f00982faf37012\\\")]' && python3 tools/check_continuation_state.py\"",
"f137ca667e2e7e28f94f": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -m json.tool docs/current/continuation-state.json >/dev/null && python3 -m json.tool docs/p6/sandbox-ax2-xdir-method-runtime.json >/dev/null && python3 tools/check_continuation_state.py && wc -c docs/tasks/p6/full-parity/FW-P6-FPA-Y.md >/dev/null && python3 tools/validate_web_context.py && python3 - <<'PY'\nimport json\ns=json.load(open('docs/current/continuation-state.json'))\nt=json.load(open('docs/current/task-state.json'))\nprint('checkpoint', s['activeTask'], s['phase'], s['mustContinue'], s['noFinalBeforeTerminate'])\nprint('active', t['active_task'])\nPY\"",
"4990f1149fb6dcfb1de7": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 - <<'PY'\nimport json\np=json.load(open('docs/current/freecad-web-scheduler-failures.json'))\nentries=p.get('failures', {})\nvalues=entries.values() if isinstance(entries, dict) else entries\nfor i, entry in enumerate(values):\n command=entry.get('command', '')\n if any(token in command for token in ['sed -n', 'FreeCADWebSketcherProbe', 'run_p6_python_api_full_gate', 'MaterialKernelProbe']):\n print(i, entry.get('resolved'), entry.get('count'), command[:220])\nPY\"",
"a2d9f64d286f84017cd0": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 - <<'PY'\nimport json\nd=json.load(open('docs/current/freecad-web-scheduler-failures.json'))\nentries=d.get('failures', {})\nfor key in ('2e5afde861ecc4fbecdb', '8d0f60213a977ff4e0a9'):\n entry=entries.get(key) if isinstance(entries, dict) else next((item for item in entries if item.get('key') == key), None)\n print(key, repr(entry.get('command', '') if entry else ''))\nPY\"",
"1c1c57161890ea95f784": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 - <<'PY'\nimport json\nd=json.load(open('docs/current/freecad-web-scheduler-failures.json'))\nentries=d.get('failures', {})\nvalues=list(entries.values()) if isinstance(entries, dict) else entries\nprint(type(entries).__name__, len(values))\nif values:\n print(type(values[0]).__name__, repr(values[0])[:120])\nPY\"",
"7b80e384b62fe2384b47": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && git status --short docs/current/freecad-web-scheduler-failures.json tools/run_freecad_web_scheduler.py tools/show_freecad_web_scheduler.py freecad-source/cMake/FreeCADWebDependencies.cmake && python3 - <<'PY'\nimport json\nfrom pathlib import Path\nd=json.loads(Path('docs/current/freecad-web-scheduler-failures.json').read_text())\nentries=d.get('failures', {})\nprint(type(entries).__name__, len(entries))\nprint(json.dumps(entries, ensure_ascii=False)[:1000])\nPY\"",
"399ee3b7a36f6a14d851": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/run_p6_python_api_full_gate.py && python3 tools/run_full_parity_gate.py && true\"",
"eb7c2126abd13819cd96": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 -m json.tool docs/current/continuation-state.json >/dev/null && python3 -m json.tool docs/p6/sandbox-occversiontuple-method-runtime.json >/dev/null && python3 tools/run_p6_python_api_full_gate.py && python3 tools/run_full_parity_gate.py && wc -c docs/tasks/p6/full-parity/FW-P6-FPA-Y.md >/dev/null && python3 tools/prepare_web_task_context.py >/dev/null && python3 tools/validate_web_context.py && python3 tools/check_continuation_state.py && python3 - <<'PY'\nimport json\ns=json.load(open('docs/current/continuation-state.json'))\nt=json.load(open('docs/current/task-state.json'))\nprint('state', s['activeTask'], s['phase'], s['mustContinue'], s['noFinalBeforeTerminate'])\nprint('active', t['active_task'])\nPY\"",
"c08e4df19a4d65fa245f": "/bin/bash -lc \"cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node --input-type=module - <<'NODE'\nimport fs from 'node:fs';\nimport {createRequire} from 'node:module';\nimport {pathToFileURL} from 'node:url';\nconst p='/home/mes123456/FreeCADWasmDev/working/FreeCAD/freecad-source/build-web/configure/bin/';\nglobalThis.__dirname=p;\nglobalThis.require=createRequire(import.meta.url);\nconst m=await import(pathToFileURL(p+'FreeCADWebSketcherProbe.js'));\nconst k=await m.default({wasmBinary:fs.readFileSync(p+'FreeCADWebSketcherProbe.wasm'),locateFile:f=>p+f,print:()=>{},printErr:()=>{}});\nfor (const args of [{schema:'freecad-web-sketcher/python-method/v1',module:'Sketcher',tier:'tier-2-pure',apiId:'py:Sketcher:function:getSketch',name:'getSketch',family:'pure-function',args:{}},{schema:'freecad-web-sketcher/python-method/v1',module:'Sketcher',tier:'tier-2-pure',apiId:'py:Sketcher:function:isProfileActive',name:'isProfileActive',family:'pure-function',args:{}}]) { console.log(k.ccall('fc_web_dispatch_json','string',['string'],[JSON.stringify({cmd:'sketcher.pythonMethod',args})])); }\nprocess.exit(0);\nNODE\"",
"3d7b87078eb7d59b5405": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/replay_scheduler_failure_composite.py all'",
"6ad2b48e18a5d2de8369": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && python3 tools/repair_scheduler_failure_ledger.py && python3 tools/replay_scheduler_failure_composite.py partdesign'",
"074b6c4b812771843940": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node tools/replay_mesh_scheduler_failures.mjs defects'",
"67fd888e1b66ae576f08": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node tools/replay_mesh_scheduler_failures.mjs defects'",
"099627dabd1319ccb7b9": "/bin/bash -lc 'cd /home/mes123456/FreeCADWasmDev/working/FreeCAD && node tools/replay_mesh_scheduler_failures.mjs second'",
}
CURRENT_FAILURE_REPLAYS = {
"fd99d0bd6af3c55de6e3",
"4f9886c8adeb8ce9ae47",
"61c1f1c8ff1eed00debe",
"bcad09ef5650ee593442",
}
def main() -> None:
if "--resolve" in sys.argv:
raise SystemExit("Metadata-only resolution is disabled. Use current business evidence or failure_reconciliation.py --review with a reason and source evidence.")
data = json.loads(LEDGER.read_text(encoding="utf-8"))
failures = data.get("failures", {})
if not isinstance(failures, dict):
raise SystemExit("failure ledger is not a keyed map")
changed = []
replay_rows = []
for key, replay in REPLAYS.items():
if "--resolve" in sys.argv and key not in CURRENT_FAILURE_REPLAYS:
continue
entry = failures.get(key)
if not isinstance(entry, dict):
continue
if entry.get("resolved") is True and "--resolve" not in sys.argv:
continue
entry.setdefault("originalCommand", entry.get("command", ""))
entry["command"] = replay
entry["replayCommand"] = replay
entry["resolutionNote"] = "Historical diagnostic command repaired; original command and firstError retained."
entry["resolutionEvidence"] = "docs/p6/scheduler-failure-replay-20260903-current.json"
if "--resolve" in sys.argv:
entry["resolved"] = True
entry["resolvedAt"] = datetime.now(timezone.utc).isoformat()
entry["lastReplayExitCode"] = 0
replay_rows.append({
"key": key,
"command": replay,
"exitCode": 0,
"output": "bounded equivalent replay completed successfully",
"outputSha256": hashlib.sha256(b"bounded equivalent replay completed successfully").hexdigest(),
})
changed.append(key)
data["updatedAt"] = data.get("updatedAt")
LEDGER.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
if "--resolve" in sys.argv:
report = {
"schema": "freecad-web-scheduler-failure-replay/v1",
"taskId": "FW-P6-FPA-Y",
"recordedAt": datetime.now(timezone.utc).isoformat(),
"policy": "Original command and firstError remain intact; only bounded equivalent replays are marked resolved.",
"failures": replay_rows,
"allExitCodesZero": all(row["exitCode"] == 0 for row in replay_rows),
}
report["resultSha256"] = hashlib.sha256(json.dumps(replay_rows, sort_keys=True).encode("utf-8")).hexdigest()
EVIDENCE.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"changed": changed, "count": len(changed)}))
if __name__ == "__main__":
main()