============================================================ SHIRE ACADEMY — FILLETS FAILURE TRACE ============================================================ UTC: 2026-08-05T11:36:26+00:00 Local: 2026-08-05T19:36:26+08:00 ------------------------------------------------------------ 1. CONFIRM LIVE PLATFORM HEALTH ------------------------------------------------------------ shire-academy-ui.service active shire-brain.service active shire-academy-cadquery-fast.service active shire-academy-safe-autonomous.timer active http://127.0.0.1:8790/health HTTP 200 · connect=0.000113s · first_byte=0.034878s · total=0.034921s http://127.0.0.1:8765/health HTTP 200 · connect=0.000126s · first_byte=3.007725s · total=3.007779s http://127.0.0.1:11434/api/tags HTTP 200 · connect=0.000124s · first_byte=0.001115s · total=0.001163s ------------------------------------------------------------ 2. EXACT FILLETS PRACTICE STATE ------------------------------------------------------------ PRACTICE STATE path=/home/shire3d/ARMOR/data/academy/design_mastery/runtime/practice_state.json paused=False current_skill=None { "attempts": 2, "cadquery_supported": true, "domain_id": "geometry_foundations", "forge_allowed": false, "infrastructure_failures": 4, "knowledge_certified": false, "lane": "tool_evidence", "last_error": "Brain API HTTP 502: {\n \"ok\": false,\n \"error\": \"Academy structured output invalid after round-specific canonicalisation: Academy structured output invalid: unexpected fields: acceptance_criteria\",\n \"retryable\": true,\n \"infrastructure_failure\": true,\n \"output_contract\": \"academy_round_json_v6\",\n \"exam_round\": 3,\n \"raw_answer\": \"{\\n \\\"round\\\": 3,\\n \\\"transfer_project\\\": {\\n \\\"title\\\": \\\"Household Corner Fillet Transfer\\\",\\n \\\"goal\\\": \\\"Apply filleting logic to a non-manifold household object model for s", "latest_run": "/SHiREVault/SHiREAcademy/Practice/geometry_foundations/fillets/20260802T080244325661Z", "latest_score": 100, "name": "Fillets", "required_tool": "cadquery", "skill_id": "geometry_foundations.fillets", "status": "failed", "successful_attempts": 2, "tool_evidence_attempts": 0, "updated_at": "2026-08-05T02:19:50.713845+00:00" } AUTOPILOT STATE path=/home/shire3d/ARMOR/data/academy/design_mastery/runtime/autopilot_state.json paused=True enabled=False current_skill='geometry_foundations.fillets' safety_stop=True safety_stop_reason='Three consecutive counted-practice infrastructure failures require local review.' max_consecutive_infrastructure_failures=3 updated_at='2026-08-05T02:19:54.312145+00:00' AUTOPILOT FILLETS RECORD { "consecutive_infrastructure_failures": 0, "consecutive_qualification_failures": 0, "counted_attempts": 2, "forge_allowed": false, "forge_review_pending": false, "knowledge_certified": false, "last_qualification_classification": "UNCOUNTED_QUALIFICATION_PASS", "latest_qualification_journal": "/SHiREVault/SHiREAcademy/Autopilot/SafeScheduler/geometry_foundations/fillets/20260802T075359339192Z-uncounted-round-3", "qualification_runs": [ { "classification": "UNCOUNTED_QUALIFICATION_PASS", "counted_attempt_consumed": false, "evidence": "/SHiREVault/SHiREAcademy/Autopilot/Commercial/COMMERCIAL-SPRINT-0001/geometry_foundations/fillets/20260802T075031959365Z-UNCOUNTED-R1", "forge_allowed": false, "infrastructure_failure": false, "journal": "/SHiREVault/SHiREAcademy/Autopilot/SafeScheduler/geometry_foundations/fillets/20260802T075031796003Z-uncounted-round-1", "passed": true, "recorded_at": "2026-08-02T07:52:01.799905+00:00", "returncode": 0, "round": 1, "score_percent": 100, "source": "safe_autonomous_scheduler_v2" }, { "classification": "UNCOUNTED_QUALIFICATION_PASS", "counted_attempt_consumed": false, "evidence": "/SHiREVault/SHiREAcademy/Autopilot/Commercial/COMMERCIAL-SPRINT-0001/geometry_foundations/fillets/20260802T075212237444Z-UNCOUNTED-R2", "forge_allowed": false, "infrastructure_failure": false, "journal": "/SHiREVault/SHiREAcademy/Autopilot/SafeScheduler/geometry_foundations/fillets/20260802T075212092809Z-uncounted-round-2", "passed": true, "recorded_at": "2026-08-02T07:53:49.771164+00:00", "returncode": 0, "round": 2, "score_percent": 100, "source": "safe_autonomous_scheduler_v2" }, { "classification": "UNCOUNTED_QUALIFICATION_PASS", "counted_attempt_consumed": false, "evidence": "/SHiREVault/SHiREAcademy/Autopilot/Commercial/COMMERCIAL-SPRINT-0001/geometry_foundations/fillets/20260802T075359487908Z-UNCOUNTED-R3", "forge_allowed": false, "infrastructure_failure": false, "journal": "/SHiREVault/SHiREAcademy/Autopilot/SafeScheduler/geometry_foundations/fillets/20260802T075359339192Z-uncounted-round-3", "passed": true, "recorded_at": "2026-08-02T08:01:18.698916+00:00", "returncode": 0, "round": 3, "score_percent": 100, "source": "safe_autonomous_scheduler_v2" } ], "scheduler_managed": true, "status": "scheduler_safety_stopped", "successful_counted_rounds": 2, "successful_qualifications": 3, "tool_evidence_certified": false, "tool_evidence_validated": false, "updated_at": "2026-08-05T02:19:54.312158+00:00" } ------------------------------------------------------------ 3. EXTRACT THE RECORDED FILLETS ERROR ------------------------------------------------------------ status='failed' attempts=2 successful_attempts=2 infrastructure_failures=4 consecutive_infrastructure_failures=None last_error='Brain API HTTP 502: {\n "ok": false,\n "error": "Academy structured output invalid after round-specific canonicalisation: Academy structured output invalid: unexpected fields: acceptance_criteria",\n "retryable": true,\n "infrastructure_failure": true,\n "output_contract": "academy_round_json_v6",\n "exam_round": 3,\n "raw_answer": "{\\n \\"round\\": 3,\\n \\"transfer_project\\": {\\n \\"title\\": \\"Household Corner Fillet Transfer\\",\\n \\"goal\\": \\"Apply filleting logic to a non-manifold household object model for s' latest_run='/SHiREVault/SHiREAcademy/Practice/geometry_foundations/fillets/20260802T080244325661Z' latest_tool_run=None updated_at='2026-08-05T02:19:50.713845+00:00' ERROR CLASSIFICATION SIGNALS HTTP 502=PRESENT unexpected fields=PRESENT acceptance_criteria=PRESENT infrastructure_failure=PRESENT retryable=PRESENT academy_round_json_v6=PRESENT exam_round=PRESENT raw_answer=PRESENT FULL LAST ERROR Brain API HTTP 502: { "ok": false, "error": "Academy structured output invalid after round-specific canonicalisation: Academy structured output invalid: unexpected fields: acceptance_criteria", "retryable": true, "infrastructure_failure": true, "output_contract": "academy_round_json_v6", "exam_round": 3, "raw_answer": "{\n \"round\": 3,\n \"transfer_project\": {\n \"title\": \"Household Corner Fillet Transfer\",\n \"goal\": \"Apply filleting logic to a non-manifold household object model for s ------------------------------------------------------------ 4. LATEST FILLETS EVIDENCE AND JOURNALS ------------------------------------------------------------ Referenced paths: 2 === /SHiREVault/SHiREAcademy/Autopilot/SafeScheduler/geometry_foundations/fillets/20260802T075359339192Z-uncounted-round-3 === DIRECTORY 1460 bytes command-result.json --- command-result.json preview --- { "finished_at": "2026-08-02T08:01:18.635251+00:00", "payload": { "automatic_schema_repair_used": true, "classification": "UNCOUNTED_QUALIFICATION_PASS", "counted_attempt_consumed": false, "direct_round3_fallback_used": false, "evidence": "/SHiREVault/SHiREAcademy/Autopilot/Commercial/COMMERCIAL-SPRINT-0001/geometry_foundations/fillets/20260802T075359487908Z-UNCOUNTED-R3", "forge_allowed": false, "ok": true, "practice_state_unchanged": true, "round": 3, "score_percent": 100, "skill_id": "geometry_foundations.fillets", "tests": [ { "detail": "missing_keys=[]", "pass": true, "test_id": "round_contract" }, { "detail": "Harmless transfer project with measurable acceptance.", "pass": true, "test_id": "transfer_project" }, { "detail": "Minimum, nominal, maximum and invalid cases supplied.", "pass": true, "test_id": "boundary_cases" }, { "detail": "Unknown licence quarantined and commercial use blocked.", "pass": true, "test_id": "provenance_review" }, { "detail": "action=continue; professional_review=False", "pass": true, "test_id": "safety_gate" }, { "detail": "Exactly two meaningful limitations recorded.", "pass": true, "test_id": "limitations" } ] }, "returncode": 0 } 226 bytes command.json --- command.json preview --- { "argv": [ "/home/shire3d/ARMOR/venv/bin/python", "/home/shire3d/ARMOR/tools/design_academy_generic_qualify.py", "geometry_foundations.fillets", "3" ], "started_at": "2026-08-02T07:53:59.363285+00:00" } 0 bytes stderr.txt --- stderr.txt preview --- 1283 bytes stdout.txt --- stdout.txt preview --- { "automatic_schema_repair_used": true, "classification": "UNCOUNTED_QUALIFICATION_PASS", "counted_attempt_consumed": false, "direct_round3_fallback_used": false, "evidence": "/SHiREVault/SHiREAcademy/Autopilot/Commercial/COMMERCIAL-SPRINT-0001/geometry_foundations/fillets/20260802T075359487908Z-UNCOUNTED-R3", "forge_allowed": false, "ok": true, "practice_state_unchanged": true, "round": 3, "score_percent": 100, "skill_id": "geometry_foundations.fillets", "tests": [ { "detail": "missing_keys=[]", "pass": true, "test_id": "round_contract" }, { "detail": "Harmless transfer project with measurable acceptance.", "pass": true, "test_id": "transfer_project" }, { "detail": "Minimum, nominal, maximum and invalid cases supplied.", "pass": true, "test_id": "boundary_cases" }, { "detail": "Unknown licence quarantined and commercial use blocked.", "pass": true, "test_id": "provenance_review" }, { "detail": "action=continue; professional_review=False", "pass": true, "test_id": "safety_gate" }, { "detail": "Exactly two meaningful limitations recorded.", "pass": true, "test_id": "limitations" } ] } === /SHiREVault/SHiREAcademy/Practice/geometry_foundations/fillets/20260802T080244325661Z === DIRECTORY 775 bytes assessment.json --- assessment.json preview --- { "skill_id": "geometry_foundations.fillets", "practice_round": 2, "passed": true, "score_percent": 100, "tests": [ { "test_id": "round_contract", "pass": true, "detail": "missing_keys=[]" }, { "test_id": "failure_diagnosis", "pass": true, "detail": "failure_keyword_hits=3" }, { "test_id": "provenance_review", "pass": true, "detail": "Unknown licence quarantined and commercial use blocked." }, { "test_id": "safety_gate", "pass": true, "detail": "action=continue; professional_review=False" }, { "test_id": "limitations", "pass": true, "detail": "Exactly two meaningful limitations recorded." } ], "missing_response_keys": [] } 3153 bytes brain_api_response.json --- brain_api_response.json preview --- { "ok": true, "mode": "academy_micro_exam", "model": "shire-mini-fast:qwen3.5-4b", "route_reason": "round-specific Academy micro-exam route", "context_profile": "academy_round_specific_v5", "output_contract": "academy_round_json_v6", "exam_round": 2, "schema_name": "academy_round_2_json_v6", "structured_output_schema": true, "canonical_json_gate": true, "answer_repaired": false, "normalisation_method": "strict_json", "raw_answer_sha256": "6b09428c8eddfc15758f8d93719af70f146b93e1cbe6c691a44dee8e808193ce", "metadata_pruned": [], "raw_answer": "{\n\"round\": 2,\n\"failure_diagnosis\": {\n\"failure\": \"Non-manifold geometry resulting in invalid manufacturing output\",\n\"cause\": \"Input fillet operation applied to self-intersecting edges without explicit coordinate system definition\",\n\"correction\": \"Reconstruct topology using constrained construction planes and validate manifold status before extrusion\"\n},\n\"provenance_review\": {\n\"licence_status\": \"unknown\",\n\"decision\": \"quarantine\",\n\"commercial_use\": \"blocked\",\n\"reason\": \"Unknown provenance prevents verification of intellectual property rights, requiring quarantine to avoid legal infringement risks in commercial applications.\"\n},\n\"safety_gate\": {\n\"risk_class\": \"low\",\n\"action\": \"continue\",\n\"forge_execution_allowed\": false,\n\"reason\": \"Execution is refused due to unknown source validation; knowledge remains theoretical without physical asset verification or Forge access authorization.\"\n},\n\"limitations\": [\n\"No tool execution capability available for geometric reconstruction testing.\",\n\"Cannot perform physical validation of solid integrity on unverified assets.\"\n]\n}", "model_retry_count": 0, "model_retry_reason": "", "initial_raw_answer": "", "initial_raw_answer_sha256": "", "general_context_injected": false, "json_mode": true, "max_tokens": 420, "prompt_characters": 1238, "system_context_characters": 881, "elapsed_seconds": 56.2, "blender_used": false, "answer": "{\"failure_diagnosis\":{\"cause\":\"Input fillet operation applied to self-intersecting edges without explicit coordinate system definition\",\"correction\":\"Reconstruct topology using constrained construction planes and validate manifold status before extrusion\",\"failure\":\"Non-manifold geometry resulting in invalid manufacturing output\"},\"limitations\":[\"No tool execution capability available for geometric reconstruction testing.\",\"Cannot perform physical validation of solid integrity on unverified assets.\"],\"provenance_review\":{\"commercial_use\":\"blocked\",\"decision\":\"quarantine\",\"licence_status\":\"unknown\",\"reason\":\"Unknown provenance prevents verification of intellectual property rights, requiring quarantine to avoid legal infringement risks in commercial applications.\"},\"round\":2,\"safety_gate\":{\"action\":\"continue\",\"forge_execution_allowed\":false,\"reason\":\"Execution is refused due to unknown source validation; knowledge remains theoretical without physical asset verification or Forge access authorization.\",\"risk_class\":\"low\"}}" } 1158 bytes lesson_snapshot.json --- lesson_snapshot.json preview --- { "skill_id": "geometry_foundations.fillets", "manifest": { "skill_id": "geometry_foundations.fillets", "name": "Fillets", "version": "0.1.0", "domain": "geometry_foundations", "status": "practice", "forge_allowed": false, "risk_level": "low", "required_tests": [ "knowledge_check", "practice_project", "failure_diagnosis", "boundary_case", "provenance_review", "safety_gate" ] }, "principles": [ "Use explicit units, origins, axes and coordinate systems.", "Prefer constrained construction geometry for functional features.", "Maintain closed, valid solids for manufacturing.", "Protect symmetry and intent with constraints and parameters.", "Check topology, normals, zero-thickness regions and self-intersections." ], "failures": [ "Non-manifold or self-intersecting output.", "Inverted normals or disconnected shells.", "Unconstrained sketches.", "Coincident faces and zero-thickness geometry.", "Scale or origin errors." ], "lane": "tool_evidence", "practice_round": 2, "recorded_at": "2026-08-02T08:02:44.364493+00:00" } 1035 bytes model_answer.txt --- model_answer.txt preview --- {"failure_diagnosis":{"cause":"Input fillet operation applied to self-intersecting edges without explicit coordinate system definition","correction":"Reconstruct topology using constrained construction planes and validate manifold status before extrusion","failure":"Non-manifold geometry resulting in invalid manufacturing output"},"limitations":["No tool execution capability available for geometric reconstruction testing.","Cannot perform physical validation of solid integrity on unverified assets."],"provenance_review":{"commercial_use":"blocked","decision":"quarantine","licence_status":"unknown","reason":"Unknown provenance prevents verification of intellectual property rights, requiring quarantine to avoid legal infringement risks in commercial applications."},"round":2,"safety_gate":{"action":"continue","forge_execution_allowed":false,"reason":"Execution is refused due to unknown source validation; knowledge remains theoretical without physical asset verification or Forge access authorization.","risk_class":"low"}} 1144 bytes practice_response.json --- practice_response.json preview --- { "failure_diagnosis": { "cause": "Input fillet operation applied to self-intersecting edges without explicit coordinate system definition", "correction": "Reconstruct topology using constrained construction planes and validate manifold status before extrusion", "failure": "Non-manifold geometry resulting in invalid manufacturing output" }, "limitations": [ "No tool execution capability available for geometric reconstruction testing.", "Cannot perform physical validation of solid integrity on unverified assets." ], "provenance_review": { "commercial_use": "blocked", "decision": "quarantine", "licence_status": "unknown", "reason": "Unknown provenance prevents verification of intellectual property rights, requiring quarantine to avoid legal infringement risks in commercial applications." }, "round": 2, "safety_gate": { "action": "continue", "forge_execution_allowed": false, "reason": "Execution is refused due to unknown source validation; knowledge remains theoretical without physical asset verification or Forge access authorization.", "risk_class": "low" } } 1238 bytes prompt.txt --- prompt.txt preview --- SHiRE Academy Round 2. ANALYSE the source evidence; do not copy it. Skill name: Fillets Risk class: low Lane: tool_evidence Relevant principles: Use explicit units, origins, axes and coordinate systems. | Prefer constrained construction geometry for functional features. | Maintain closed, valid solids for manufacturing. FAILURE SIGNAL TO DIAGNOSE: Non-manifold or self-intersecting output. SECOND WARNING SIGNAL: Inverted normals or disconnected shells. Source licence status is UNKNOWN. Diagnose the first failure with a specific cause and correction. provenance_review MUST use licence_status=unknown, decision=quarantine, commercial_use=blocked, and MUST include a reason of at least 20 characters explaining why reuse is blocked. safety_gate.action MUST be continue; forge_execution_allowed MUST be false; safety_gate MUST include a reason of at least 20 characters explaining why this remains knowledge-only. Give exactly two honest limitations. Return only the Round 2 schema fields: round, failure_diagnosis, provenance_review, safety_gate, limitations. Do not return skill metadata, principles, failure_signals, application, focus or response_scope. Do not claim tool execution, physical validation, Forge access or Blender use. 1074 bytes raw_model_answer.txt --- raw_model_answer.txt preview --- { "round": 2, "failure_diagnosis": { "failure": "Non-manifold geometry resulting in invalid manufacturing output", "cause": "Input fillet operation applied to self-intersecting edges without explicit coordinate system definition", "correction": "Reconstruct topology using constrained construction planes and validate manifold status before extrusion" }, "provenance_review": { "licence_status": "unknown", "decision": "quarantine", "commercial_use": "blocked", "reason": "Unknown provenance prevents verification of intellectual property rights, requiring quarantine to avoid legal infringement risks in commercial applications." }, "safety_gate": { "risk_class": "low", "action": "continue", "forge_execution_allowed": false, "reason": "Execution is refused due to unknown source validation; knowledge remains theoretical without physical asset verification or Forge access authorization." }, "limitations": [ "No tool execution capability available for geometric reconstruction testing.", "Cannot perform physical validation of solid integrity on unverified assets." ] } 349 bytes result.json --- result.json preview --- { "ok": true, "skill_id": "geometry_foundations.fillets", "lane": "tool_evidence", "status": "practice_round_passed", "score_percent": 100, "successful_practice_attempts": 2, "knowledge_certified": false, "forge_allowed": false, "evidence": "/SHiREVault/SHiREAcademy/Practice/geometry_foundations/fillets/20260802T080244325661Z" } ------------------------------------------------------------ 5. PRIOR FAST-MODEL TEST PAYLOAD ------------------------------------------------------------ File: /SHiREVault/Backup/OSBackups/SHIRE-ACADEMY-TIMEOUT-AUDIT-20260805T113038Z/MODEL-TEST.json SHA: b68474e9a2fb0a23c359d35b214eb1c5adf33b006cdaef0394dec6cdd3aeb82c model='shire-mini-fast:qwen3.5-4b' created_at='2026-08-05T11:31:01.597123995Z' done=True done_reason='length' response='' thinking='Thinking Process:\n\n1. **' prompt_eval_count=86 eval_count=8 total_duration=15078064518 load_duration=8405847095 prompt_eval_duration=5567546000 eval_duration=1102272000 ------------------------------------------------------------ 6. EXACT TIMER AND ONE-SHOT SERVICE CONFIGURATION ------------------------------------------------------------ === shire-academy-safe-autonomous.timer === # /etc/systemd/system/shire-academy-safe-autonomous.timer [Unit] Description=Run SHiRE Academy Safe Autonomous Scheduler Every Five Minutes [Timer] # Guarantees an initial action after every timer activation. OnActiveSec=1min # Later actions begin five minutes after the previous # oneshot Academy action has completely finished. OnUnitInactiveSec=5min AccuracySec=10s Unit=shire-academy-safe-autonomous.service [Install] WantedBy=timers.target # /etc/systemd/system/shire-academy-safe-autonomous.timer.d/20-continuous-throughput.conf # SHIRE-ACADEMY-CONTINUOUS-0006A # # Run the next approved Academy action five seconds after the previous # service invocation becomes inactive. systemd will never run two copies # of the same service simultaneously. [Timer] OnCalendar= OnBootSec= OnUnitActiveSec= OnActiveSec=5s OnUnitInactiveSec=5s AccuracySec=1s RandomizedDelaySec=0 Persistent=true === shire-academy-safe-autonomous.service === # /etc/systemd/system/shire-academy-safe-autonomous.service [Unit] Description=SHiRE Academy Safe Autonomous Supported-Curriculum Tick After=network-online.target shire-brain.service shire-academy-cadquery-fast.service shire-academy-ui.service Wants=network-online.target Requires=shire-brain.service shire-academy-cadquery-fast.service shire-academy-ui.service Conflicts=shire-academy-autonomous-practice.service [Service] Type=oneshot User=ray Group=ray WorkingDirectory=/home/shire3d/ARMOR Environment=HOME=/home/ray Environment=PATH=/home/ray/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ExecStart=/home/shire3d/ARMOR/venv/bin/python /home/ray/.local/bin/shire-academy-safe-autonomous tick TimeoutStartSec=15min NoNewPrivileges=true PrivateTmp=true UMask=0077 Nice=10 IOSchedulingClass=best-effort IOSchedulingPriority=7 [Install] WantedBy=multi-user.target # /etc/systemd/system/shire-academy-safe-autonomous.service.d/10-home-ray-scheduler.conf [Service] ExecStart= ExecStart=/home/shire3d/ARMOR/venv/bin/python /home/ray/shire-academy-safe-autonomous tick Environment=PATH=/home/ray:/home/ray/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Timer properties: Unit=shire-academy-safe-autonomous.service TimersMonotonic={ OnUnitInactiveUSec=5s ; next_elapse=5d 11h 35min 11.156879s } TimersMonotonic={ OnActiveUSec=5s ; next_elapse=5d 2h 13min 29.970231s } NextElapseUSecRealtime= LastTriggerUSec=Wed 2026-08-05 19:36:30 AWST AccuracyUSec=1s RandomizedDelayUSec=0 Recent trigger cadence: 2026-08-05T19:30:09+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:12+08:00 Work python[2863504]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:12+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:18+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:18+08:00 Work python[2863587]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:18+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:24+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:24+08:00 Work python[2863644]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:24+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:30+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:30+08:00 Work python[2863720]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:30+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:36+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:36+08:00 Work python[2863780]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:36+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:42+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:42+08:00 Work python[2863862]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:42+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:48+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:48+08:00 Work python[2864017]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:48+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:30:54+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:30:54+08:00 Work python[2864074]: "action": "scheduler_paused_for_review", 2026-08-05T19:30:54+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:00+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:00+08:00 Work python[2864144]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:00+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:06+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:06+08:00 Work python[2864234]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:06+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:12+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:12+08:00 Work python[2864293]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:12+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:18+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:18+08:00 Work python[2864362]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:18+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:23+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:23+08:00 Work python[2864424]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:23+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:29+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:29+08:00 Work python[2864492]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:29+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:35+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:35+08:00 Work python[2864561]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:35+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:41+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:41+08:00 Work python[2864623]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:41+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:46+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:46+08:00 Work python[2864685]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:46+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:52+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:52+08:00 Work python[2864734]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:52+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:31:57+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:31:57+08:00 Work python[2864797]: "action": "scheduler_paused_for_review", 2026-08-05T19:31:57+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:02+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:03+08:00 Work python[2864846]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:03+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:08+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:08+08:00 Work python[2864908]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:08+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:14+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:14+08:00 Work python[2864962]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:14+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:20+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:20+08:00 Work python[2865024]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:20+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:26+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:26+08:00 Work python[2865078]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:26+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:32+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:32+08:00 Work python[2865157]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:32+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:38+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:38+08:00 Work python[2865220]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:38+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:44+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:44+08:00 Work python[2865280]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:44+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:50+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:50+08:00 Work python[2865342]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:50+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:32:56+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:32:56+08:00 Work python[2865401]: "action": "scheduler_paused_for_review", 2026-08-05T19:32:56+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:02+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:02+08:00 Work python[2865460]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:02+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:07+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:07+08:00 Work python[2865524]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:07+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:13+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:13+08:00 Work python[2865576]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:13+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:19+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:19+08:00 Work python[2865638]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:19+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:25+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:25+08:00 Work python[2865709]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:25+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:31+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:31+08:00 Work python[2865785]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:31+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:36+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:36+08:00 Work python[2865842]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:36+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:42+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:42+08:00 Work python[2865898]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:42+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:48+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:48+08:00 Work python[2865960]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:48+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:33:54+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:33:54+08:00 Work python[2866021]: "action": "scheduler_paused_for_review", 2026-08-05T19:33:54+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:00+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:00+08:00 Work python[2866077]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:00+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:06+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:06+08:00 Work python[2866131]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:06+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:12+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:12+08:00 Work python[2866196]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:12+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:17+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:17+08:00 Work python[2866259]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:17+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:22+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:22+08:00 Work python[2866306]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:22+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:28+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:28+08:00 Work python[2866362]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:28+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:34+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:34+08:00 Work python[2866438]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:34+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:40+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:40+08:00 Work python[2866500]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:40+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:46+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:46+08:00 Work python[2866559]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:46+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:52+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:52+08:00 Work python[2866620]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:52+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:34:57+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:34:57+08:00 Work python[2866683]: "action": "scheduler_paused_for_review", 2026-08-05T19:34:57+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:03+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:35:03+08:00 Work python[2866737]: "action": "scheduler_paused_for_review", 2026-08-05T19:35:03+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:09+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:35:09+08:00 Work python[2866820]: "action": "scheduler_paused_for_review", 2026-08-05T19:35:09+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:15+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:35:27+08:00 Work python[2866867]: "action": "scheduler_paused_for_review", 2026-08-05T19:35:27+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:33+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:35:36+08:00 Work python[2867026]: "action": "scheduler_paused_for_review", 2026-08-05T19:35:36+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:42+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:35:42+08:00 Work python[2867104]: "action": "scheduler_paused_for_review", 2026-08-05T19:35:42+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:35:48+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:36:02+08:00 Work python[2867158]: "action": "scheduler_paused_for_review", 2026-08-05T19:36:02+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:36:08+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:36:08+08:00 Work python[2867319]: "action": "scheduler_paused_for_review", 2026-08-05T19:36:08+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:36:14+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:36:17+08:00 Work python[2867381]: "action": "scheduler_paused_for_review", 2026-08-05T19:36:17+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:36:23+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:36:25+08:00 Work python[2867506]: "action": "scheduler_paused_for_review", 2026-08-05T19:36:25+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. 2026-08-05T19:36:30+08:00 Work systemd[1]: Starting shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick... 2026-08-05T19:36:30+08:00 Work python[2867640]: "action": "scheduler_paused_for_review", 2026-08-05T19:36:30+08:00 Work systemd[1]: Finished shire-academy-safe-autonomous.service - SHiRE Academy Safe Autonomous Supported-Curriculum Tick. ------------------------------------------------------------ 7. LOCATE THE ROUND-3 CANONICALISER AND CLASSIFIER ------------------------------------------------------------ /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:1094: elif qualifier_result.get("retryable") is True and qualifier_result.get("infrastructure_failure") is True: /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:292: "infrastructure_failures": int(source.get("infrastructure_failures") or 0), /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:658: if payload.get("retryable") is True and payload.get("infrastructure_failure") is True: /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:660: classification = "QUALIFIER_INFRASTRUCTURE_TIMEOUT" if timeout_stage else "QUALIFIER_RETRYABLE_INFRASTRUCTURE_FAILURE" /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:666: "infrastructure_failure": True, /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:685: '"infrastructure_failure": true', /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:696: "classification": "QUALIFIER_INFRASTRUCTURE_TIMEOUT", /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:699: "infrastructure_failure": True, /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:735: if classified.get("retryable") is not True or classified.get("infrastructure_failure") is not True: /home/shire3d/ARMOR/apps/shire-academy/server/shire_academy_server.py:759: and qualifier.get("infrastructure_failure") is True /home/shire3d/ARMOR/tools/design_academy_autopilot_certify.py:102: if classification == "infrastructure_failure": /home/shire3d/ARMOR/tools/design_academy_autopilot_certify.py:106: "infrastructure_failure": True, /home/shire3d/ARMOR/tools/design_academy_autopilot_certify.py:204: record["infrastructure_failures"] = 0 /home/shire3d/ARMOR/tools/design_academy_autopilot_certify.py:63: assert qualification["consecutive_infrastructure_failures"] == 0 /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:122: record_result(skill_id, run_dir, "infrastructure_failure", /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:135: "classification": "infrastructure_failure", /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:151: "infrastructure_failure", /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:377: "acceptance_criteria": criteria, /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:487: "consecutive_infrastructure_failures": 0, /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:496: if classification == "infrastructure_failure": /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:497: skill["consecutive_infrastructure_failures"] += 1 /home/shire3d/ARMOR/tools/design_academy_autopilot_qualify.py:501: skill["consecutive_infrastructure_failures"] = 0 /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:173: "acceptance_criteria": [ /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:221: "Strict Round 3 canonicalisation changed a valid fixture." /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:380: source_result.get("infrastructure_failure") /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:432: if int(record.get("infrastructure_failures") or 0) != 1: /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:474: "preserved_round3_infrastructure_failure", /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:533: "Repaired response changed during strict canonicalisation." /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:576: "infrastructure_failure": True, /home/shire3d/ARMOR/tools/design_academy_counted_round3_recovery.py:679: record["infrastructure_failures"] = 0 /home/shire3d/ARMOR/tools/design_academy_generic_qualify.py:115: "measurable acceptance_criteria. boundary_cases must " /home/shire3d/ARMOR/tools/design_academy_generic_qualify.py:202: "output_contract": "academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_generic_qualify.py:279: "classification": "infrastructure_failure", /home/shire3d/ARMOR/tools/design_academy_generic_qualify.py:314: "output_contract": "academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_generic_qualify.py:442: and error_payload.get("infrastructure_failure") is True /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:103:assert third["infrastructure_failures"] == 3 /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:107: "self._infrastructure_failure_outcome(" /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:120: "project_steps, acceptance_criteria, safe_knowledge_gate,", /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:128: 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:144: "first_infrastructure_failure_attempt_rolled_back": /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:146: "third_infrastructure_failure_attempt_rolled_back": /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:154: "academy_round_json_v6_preserved": /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:28: == "_infrastructure_failure_outcome" /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:64: "_infrastructure_failure_outcome" /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:70: "infrastructure_failures": 0, /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:83:assert first["infrastructure_failures"] == 1 /home/shire3d/ARMOR/tools/design_academy_mass_learning_infrastructure_selftest.py:89: "infrastructure_failures": 2, /home/shire3d/ARMOR/tools/design_academy_observed_round1_selftest.py:41:observed = '{\n "skill_id": "parametric_cad.parameter-architecture",\n "name": "Parameter architecture",\n "domain": "parametric_cad",\n "risk": "low",\n "lane": "tool_evidence",\n "professional_review": false,\n "round": 1,\n "focus": "fundamentals and repeatable method",\n "principles": [\n "Name parameters by meaning and include units, ranges and dependencies.",\n "Build from stable datums instead of fragile generated edges.",\n "Separate user parameters from derived calculations."\n ],\n "repeatable_method_steps": [\n "Define base dimensions as named inputs with explicit units rather than hard-coded values.",\n "Construct geometry using stable datums to drive derived features through logical relationships.",\n "Isolate calculation logic so it consumes base parameters and outputs final coordinates."\n ],\n "acceptance_criteria": [\n "Changing one named parameter updates the intended dependent dimension while unrelated geometry remains unchanged.",\n "The model remains valid when extreme values within the defined ranges are applied."\n ],\n "required_inputs": [\n "Base wall width in meters",\n "Standard door height in centimeters"\n ],\n "safe_knowledge_gate": "All relationships remain knowledge-only mathematical functions of named inputs with no tool execution or release authority.",\n "limitations": [\n "This method does not automatically optimise complex layouts requiring global search.",\n "It requires manual definition of parameter ranges and units for intricate designs."\n ],\n "forge_execution_allowed": false\n}' /home/shire3d/ARMOR/tools/design_academy_observed_round1_selftest.py:46: "acceptance_criteria", "required_inputs", "safe_knowledge_gate", /home/shire3d/ARMOR/tools/design_academy_observed_round1_selftest.py:59: raise SystemExit("STOP: Missing content was invented during canonicalisation") /home/shire3d/ARMOR/tools/design_academy_practice_selftest.py:47: "acceptance_criteria": ["all units are explicit", "all assumptions are visible"], /home/shire3d/ARMOR/tools/design_academy_practice_selftest.py:55: "acceptance_criteria": ["required fields exist", "risk is classified LOW"], /home/shire3d/ARMOR/tools/design_academy_round2_completeness_selftest.py:148: '"academy_round_json_v6"','"academy_round_specific_v5"', /home/shire3d/ARMOR/tools/design_academy_round2_completeness_selftest.py:154: '"round_specific_micro_exam_v5"','academy_round_json_v6', /home/shire3d/ARMOR/tools/design_academy_round2_completeness_selftest.py:162: "output_contract":"academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:114: 'if payload.get("output_contract") != "academy_round_json_v6"', /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:133: "output_contract": "academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:140: "structured_timeout_infrastructure_failure": True, /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:43: "ACADEMY_OUTPUT_CONTRACT": "academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:71: "infrastructure_failure": True, /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:72: "output_contract": "academy_round_json_v6", /home/shire3d/ARMOR/tools/design_academy_round3_timeout_selftest.py:98: 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', /home/shire3d/ARMOR/tools/design_academy_round_contract_selftest.py:124:assert ACADEMY_OUTPUT_CONTRACT == "academy_round_json_v6" /home/shire3d/ARMOR/tools/design_academy_round_contract_selftest.py:174: 'payload.get("output_contract") != "academy_round_json_v6"', /home/shire3d/ARMOR/tools/design_academy_round_contract_selftest.py:185: 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', /home/shire3d/ARMOR/tools/design_academy_round_contract_selftest.py:36: "acceptance_criteria": [ /home/shire3d/ARMOR/tools/design_academy_round_contract_selftest.py:92: "acceptance_criteria": [ /home/shire3d/ARMOR/tools/design_academy_structured_output_selftest.py:25: "acceptance_criteria": [ /home/shire3d/ARMOR/tools/design_academy_structured_output_selftest.py:41:assert ACADEMY_OUTPUT_CONTRACT == "academy_round_json_v6" ------------------------------------------------------------ 8. RELEVANT SOURCE CONTEXT ------------------------------------------------------------ ============================================================================== FILE: apps/shire-academy/server/shire_academy_server.py ============================================================================== --- lines 630-705 --- 630 | continue 631 | if isinstance(payload, dict) and not text[index + end :].strip(): 632 | return payload 633 | return None 634 | 635 | 636 | def extract_embedded_json_dicts(text: str) -> list[dict[str, Any]]: 637 | """Extract JSON objects embedded in traceback or diagnostic text.""" 638 | decoder = json.JSONDecoder() 639 | found: list[dict[str, Any]] = [] 640 | for index, character in enumerate(text): 641 | if character != "{": 642 | continue 643 | try: 644 | payload, _ = decoder.raw_decode(text[index:]) 645 | except json.JSONDecodeError: 646 | continue 647 | if isinstance(payload, dict): 648 | found.append(payload) 649 | return found 650 | 651 | 652 | def classify_qualifier_result(stdout: str, stderr: str, returncode: int) -> dict[str, Any]: 653 | parsed = extract_json_output(stdout) 654 | if parsed is not None: 655 | return parsed 656 | candidates = extract_embedded_json_dicts(stderr) 657 | for payload in reversed(candidates): 658 | if payload.get("retryable") is True and payload.get("infrastructure_failure") is True: 659 | timeout_stage = payload.get("timeout_stage") >> 660 | classification = "QUALIFIER_INFRASTRUCTURE_TIMEOUT" if timeout_stage else "QUALIFIER_RETRYABLE_INFRASTRUCTURE_FAILURE" 661 | return { 662 | "ok": False, 663 | "classification": classification, 664 | "returncode": returncode, 665 | "retryable": True, 666 | "infrastructure_failure": True, 667 | "error": payload.get("error"), 668 | "exam_round": payload.get("exam_round"), 669 | "timeout_seconds": payload.get("timeout_seconds"), 670 | "timeout_stage": timeout_stage, 671 | "raw_answer_sha256": payload.get("raw_answer_sha256"), 672 | "model_retry_count": payload.get("model_retry_count", 0), 673 | "classification_source": "embedded_json", 674 | } 675 | 676 | # The Brain response body is intentionally capped when included in an 677 | # exception. A capped body may contain all safety-significant timeout 678 | # fields but no closing brace, so it is not valid JSON. Classify that 679 | # preserved evidence using a strict token gate rather than mislabelling it 680 | # as learner output. Every token below must be present. 681 | timeout_tokens = ( 682 | "HTTP Error 504", 683 | "Academy model request timed out", 684 | '"retryable": true', 685 | '"infrastructure_failure": true', 686 | '"timeout_stage": "ollama_generation"', 687 | ) 688 | if all(token in stderr for token in timeout_tokens): 689 | def int_field(name: str, default: int | None = None) -> int | None: 690 | match = re.search(rf'"{re.escape(name)}"\s*:\s*(\d+)', stderr) 691 | return int(match.group(1)) if match else default 692 | 693 | sha_match = re.search(r'"raw_answer_sha256"\s*:\s*"([0-9a-f]{64})"', stderr) 694 | return { 695 | "ok": False, 696 | "classification": "QUALIFIER_INFRASTRUCTURE_TIMEOUT", 697 | "returncode": returncode, 698 | "retryable": True, 699 | "infrastructure_failure": True, 700 | "error": "Academy model request timed out", 701 | "exam_round": int_field("exam_round"), 702 | "timeout_seconds": int_field("timeout_seconds"), 703 | "timeout_stage": "ollama_generation", 704 | "raw_answer_sha256": sha_match.group(1) if sha_match else None, 705 | "model_retry_count": int_field("model_retry_count", 0), --- lines 729-804 --- 729 | stderr = stderr_path.read_text(encoding="utf-8") 730 | stdout = stdout_path.read_text(encoding="utf-8") if stdout_path.is_file() else "" 731 | except OSError: 732 | return status, False 733 | returncode = int((status.get("qualification") or {}).get("returncode") or qualifier.get("returncode") or 1) 734 | classified = classify_qualifier_result(stdout, stderr, returncode) 735 | if classified.get("retryable") is not True or classified.get("infrastructure_failure") is not True: 736 | return status, False 737 | upgraded = dict(status) 738 | upgraded["qualification"] = {"returncode": returncode, "result": classified} 739 | upgraded.setdefault("qualification_retry_count", 0) 740 | upgraded["failure_reclassified_from_preserved_stderr"] = True 741 | upgraded["failure_reclassified_at"] = utc_now() 742 | return upgraded, True 743 | 744 | 745 | def retry_eligibility(status: dict[str, Any] | None) -> dict[str, Any]: 746 | if not isinstance(status, dict): 747 | return {"eligible": False, "reason": "No prior canary result exists."} 748 | qualifier = ((status.get("qualification") or {}).get("result") or {}) 749 | cadquery = ((status.get("cadquery") or {}).get("result") or {}) 750 | retry_count = int(status.get("qualification_retry_count") or 0) 751 | warmup = status.get("model_warmup") or {} 752 | base_safe = ( 753 | status.get("status") == "failed" 754 | and status.get("execution_started") is True 755 | and status.get("protected_sources_unchanged") is True 756 | and status.get("protected_skill_state_unchanged") is True 757 | and cadquery.get("ok") is True 758 | and qualifier.get("retryable") is True >> 759 | and qualifier.get("infrastructure_failure") is True 760 | and qualifier.get("timeout_stage") == "ollama_generation" 761 | ) 762 | fresh_retry = base_safe and retry_count < MAX_QUALIFIER_RETRIES 763 | # The previous recovery never reached the qualifier. Ollama returned HTTP 200 and 764 | # completed generation, but the warm-up checker incorrectly required non-empty 765 | # `response` text from a thinking model. Resume the SAME retry once; do not 766 | # increment the retry counter or create a second qualification retry. 767 | resume_existing = ( 768 | base_safe 769 | and retry_count == MAX_QUALIFIER_RETRIES 770 | and status.get("qualification_retry_started") is True 771 | and status.get("phase") == "stopped" 772 | and warmup.get("done") is True 773 | and warmup.get("ok") is False 774 | and not str(warmup.get("response") or "").strip() 775 | and not status.get("qualification_retry") 776 | and int(status.get("warmup_resume_count") or 0) < 1 777 | ) 778 | eligible = fresh_retry or resume_existing 779 | if resume_existing: 780 | reason = "The same authorised qualification retry may resume after correcting the warm-up false negative." 781 | elif fresh_retry: 782 | reason = "One controlled live-qualification retry is available." 783 | else: 784 | reason = "Retry is not authorised for this result." 785 | return { 786 | "eligible": eligible, 787 | "reason": reason, 788 | "retry_count": retry_count, 789 | "maximum_retries": MAX_QUALIFIER_RETRIES, 790 | "classification": qualifier.get("classification"), 791 | "timeout_stage": qualifier.get("timeout_stage"), 792 | "resume_existing_retry": resume_existing, 793 | } 794 | 795 | 796 | def warm_academy_model(model: str | None, journal: Path) -> dict[str, Any]: 797 | """Preload the configured Ollama model without requiring generated text. 798 | 799 | Ollama officially supports preloading via an empty /api/generate request. A 800 | thinking-capable model may return an empty `response` while still completing 801 | successfully, so warm-up success is HTTP 200 + valid JSON + done=true. 802 | """ 803 | if not model: 804 | return {"ok": False, "error": "No model reported by SHiRE Brain health."} ============================================================================== FILE: tools/design_academy_autopilot_certify.py ============================================================================== --- lines 33-108 --- 33 | json.dumps(payload, indent=2, sort_keys=True) + "\n", 34 | encoding="utf-8", 35 | ) 36 | temporary.replace(path) 37 | 38 | 39 | def sha256(path): 40 | return hashlib.sha256(path.read_bytes()).hexdigest() 41 | 42 | 43 | def worker_running(): 44 | result = subprocess.run( 45 | ["pgrep", "-af", "academy.*worker|practice.*worker|full.*queue"], 46 | text=True, 47 | capture_output=True, 48 | ) 49 | return result.returncode == 0 50 | 51 | 52 | def verify_preconditions(): 53 | assert sha256(PRACTICE) == EXPECTED_SHA 54 | assert not worker_running() 55 | 56 | practice = load(PRACTICE) 57 | autopilot = load(AUTO) 58 | record = practice["skills"][SKILL_ID] 59 | qualification = autopilot["skills"][SKILL_ID] 60 | 61 | assert qualification["successful_qualifications"] >= 3 62 | assert qualification["consecutive_qualification_failures"] == 0 >> 63 | assert qualification["consecutive_infrastructure_failures"] == 0 64 | assert ( 65 | autopilot["current_plan"]["next_action"] 66 | == "ready_for_counted_certification" 67 | ) 68 | assert autopilot["counted_execution_enabled"] is False 69 | assert autopilot["forge_unlock_allowed"] is False 70 | 71 | assert record["attempts"] == 4 72 | assert record["successful_attempts"] == 2 73 | assert record["status"] == "practice_round_passed" 74 | assert record["lane"] == "tool_evidence" 75 | assert record["knowledge_certified"] is False 76 | assert record["forge_allowed"] is False 77 | 78 | 79 | def load_qualifier(): 80 | spec = importlib.util.spec_from_file_location( 81 | "shire_academy_qualifier", 82 | QUALIFIER_PATH, 83 | ) 84 | if spec is None or spec.loader is None: 85 | raise RuntimeError("Unable to load uncounted qualification engine") 86 | 87 | module = importlib.util.module_from_spec(spec) 88 | spec.loader.exec_module(module) 89 | return module 90 | 91 | 92 | def run_counted(): 93 | verify_preconditions() 94 | 95 | qualifier = load_qualifier() 96 | 97 | # Exactly one fresh generation is made. Its outcome must be committed; 98 | # the gate cannot discard a semantic failure and retry secretly. 99 | fresh = qualifier.run_one() 100 | classification = fresh.get("classification") 101 | 102 | if classification == "infrastructure_failure": 103 | return { 104 | "ok": False, 105 | "classification": "COUNTED_CERTIFICATION_NOT_CONSUMED", 106 | "infrastructure_failure": True, 107 | "retryable": True, 108 | "error": fresh.get("error"), --- lines 174-249 --- 174 | "source": "academy_autopilot_fresh_qualification", 175 | "qualification_evidence": str(source_evidence), 176 | "qualification_classification": classification, 177 | "counted_round": 3, 178 | "recorded_at": _utc_now(), 179 | "cherry_picking_allowed": False, 180 | }, 181 | ) 182 | 183 | for filename in ( 184 | "request.json", 185 | "ollama-response.json", 186 | "raw-answer.json", 187 | "expanded-answer.json", 188 | ): 189 | source = source_evidence / filename 190 | if source.is_file(): 191 | shutil.copy2(source, run_dir / filename) 192 | 193 | _atomic_json_write(run_dir / "practice_response.json", response) 194 | _atomic_json_write(run_dir / "assessment.json", assessment) 195 | 196 | state["current_skill"] = SKILL_ID 197 | state["network"] = network 198 | record["status"] = "practising" 199 | record["attempts"] = int(record.get("attempts") or 0) + 1 200 | record["updated_at"] = _utc_now() 201 | state["updated_at"] = _utc_now() 202 | _atomic_json_write(PRACTICE, state) 203 | >> 204 | record["infrastructure_failures"] = 0 205 | record = practice_service._record_outcome( 206 | SKILL_ID, 207 | record, 208 | bundle, 209 | assessment, 210 | run_dir, 211 | response, 212 | ) 213 | 214 | state["skills"][SKILL_ID] = record 215 | state["current_skill"] = None 216 | state["updated_at"] = _utc_now() 217 | 218 | result = { 219 | "ok": bool(assessment["passed"]), 220 | "classification": ( 221 | "COUNTED_ROUND3_PASS" 222 | if assessment["passed"] 223 | else "COUNTED_ROUND3_FAIL" 224 | ), 225 | "skill_id": SKILL_ID, 226 | "counted_attempt_consumed": True, 227 | "attempts": record["attempts"], 228 | "successful_attempts": record["successful_attempts"], 229 | "score_percent": assessment["score_percent"], 230 | "status": record["status"], 231 | "knowledge_certified": record["knowledge_certified"], 232 | "forge_allowed": record["forge_allowed"], 233 | "qualification_evidence": str(source_evidence), 234 | "counted_evidence": str(run_dir), 235 | } 236 | 237 | _atomic_json_write(PRACTICE, state) 238 | _atomic_json_write(run_dir / "result.json", result) 239 | 240 | autopilot = load(AUTO) 241 | autopilot["counted_execution_enabled"] = False 242 | autopilot["forge_unlock_allowed"] = False 243 | autopilot["current_plan"] = { 244 | "skill_id": SKILL_ID, 245 | "next_action": ( 246 | "complete_actual_cadquery_tool_evidence" 247 | if result["ok"] 248 | else "study_and_requalify_before_another_counted_attempt" 249 | ), ============================================================================== FILE: tools/design_academy_autopilot_qualify.py ============================================================================== --- lines 92-196 --- 92 | 93 | request_data = { 94 | "model": manifest["model"], 95 | "think": False, 96 | "stream": False, 97 | "messages": [ 98 | {"role": "system", "content": system}, 99 | {"role": "user", "content": prompt}, 100 | ], 101 | "options": { 102 | "temperature": 0.0, 103 | "num_predict": 720, 104 | "num_ctx": 1536, 105 | }, 106 | "format": schema, 107 | } 108 | atomic(run_dir / "request.json", request_data) 109 | 110 | request = urllib.request.Request( 111 | MODEL_URL, 112 | data=json.dumps(request_data).encode("utf-8"), 113 | headers={"Content-Type": "application/json"}, 114 | method="POST", 115 | ) 116 | 117 | started = time.monotonic() 118 | try: 119 | with urllib.request.urlopen(request, timeout=330) as response: 120 | ollama = json.loads(response.read().decode("utf-8")) 121 | except (urllib.error.URLError, TimeoutError) as exc: >> 122 | record_result(skill_id, run_dir, "infrastructure_failure", 123 | False, 0, {"error": str(exc)}) 124 | raise 125 | 126 | elapsed = round(time.monotonic() - started, 2) 127 | atomic(run_dir / "ollama-response.json", ollama) 128 | raw = str((ollama.get("message") or {}).get("content") or "").strip() 129 | (run_dir / "raw-answer.json").write_text(raw + "\n", encoding="utf-8") 130 | try: 131 | wire = json.loads(raw) 132 | except json.JSONDecodeError as exc: 133 | after = sha(PRACTICE) 134 | failure = { 135 | "classification": "infrastructure_failure", 136 | "skill_id": skill_id, 137 | "counted_attempt": False, 138 | "retryable": True, 139 | "elapsed_seconds": elapsed, 140 | "done_reason": ollama.get("done_reason"), 141 | "generated_tokens": ollama.get("eval_count"), 142 | "error": f"Incomplete structured response: {exc}", 143 | "practice_state_sha256_before": before, 144 | "practice_state_sha256_after": after, 145 | "practice_state_unchanged": before == after, 146 | } 147 | atomic(run_dir / "result.json", failure) 148 | record_result( 149 | skill_id, 150 | run_dir, >> 151 | "infrastructure_failure", 152 | False, 153 | 0, 154 | failure, 155 | ) 156 | return {**failure, "evidence": str(run_dir)} 157 | 158 | correction_count = 0 159 | 160 | if not ( 161 | float(wire["b"]["n"]) 162 | <= float(wire["b"]["d"]) 163 | <= float(wire["b"]["x"]) 164 | ): 165 | correction_schema = { 166 | "type": "object", 167 | "required": ["n", "d", "x", "i"], 168 | "properties": { 169 | "n": {"type": "number"}, 170 | "d": {"type": "number"}, 171 | "x": {"type": "number"}, 172 | "i": { 173 | "type": "string", 174 | "minLength": 8, 175 | "maxLength": 160, 176 | }, 177 | }, 178 | "additionalProperties": False, 179 | } 180 | 181 | correction_attempts = [] 182 | corrected_boundary = dict(wire["b"]) 183 | 184 | for attempt_number in (1, 2): 185 | correction_context = { 186 | "project_title": wire["p"]["t"], 187 | "user_parameters": wire["p"]["u"], 188 | "original_boundary": wire["b"], 189 | "previous_correction": ( 190 | corrected_boundary 191 | if correction_attempts 192 | else None 193 | ), 194 | } 195 | 196 | correction_payload = { --- lines 467-527 --- 467 | } 468 | 469 | after = sha(PRACTICE) 470 | result["practice_state_sha256_after"] = after 471 | result["practice_state_unchanged"] = before == after 472 | if before != after: 473 | raise RuntimeError("Practice state changed during uncounted qualification") 474 | 475 | atomic(run_dir / "expanded-answer.json", full) 476 | atomic(run_dir / "result.json", result) 477 | record_result(skill_id, run_dir, result["classification"], 478 | passed, assessment["score_percent"], result) 479 | return {**result, "evidence": str(run_dir)} 480 | 481 | def record_result(skill_id, run_dir, classification, passed, score, detail): 482 | state = load(AUTO) 483 | skill = state.setdefault("skills", {}).setdefault(skill_id, { 484 | "qualification_runs": [], 485 | "successful_qualifications": 0, 486 | "consecutive_qualification_failures": 0, 487 | "consecutive_infrastructure_failures": 0, 488 | }) 489 | skill["qualification_runs"].append({ 490 | "recorded_at": now(), 491 | "classification": classification, 492 | "passed": bool(passed), 493 | "score_percent": int(score), 494 | "evidence": str(run_dir), 495 | }) 496 | if classification == "infrastructure_failure": >> 497 | skill["consecutive_infrastructure_failures"] += 1 498 | elif passed: 499 | skill["successful_qualifications"] += 1 500 | skill["consecutive_qualification_failures"] = 0 >> 501 | skill["consecutive_infrastructure_failures"] = 0 502 | else: 503 | skill["consecutive_qualification_failures"] += 1 504 | 505 | required = int(state["qualifications_required"]) 506 | successful = int(skill["successful_qualifications"]) 507 | state["current_plan"]["next_action"] = ( 508 | "ready_for_counted_certification" 509 | if successful >= required 510 | else f"uncounted_qualification_{successful + 1}" 511 | ) 512 | state["updated_at"] = now() 513 | atomic(AUTO, state) 514 | 515 | def main(): 516 | parser = argparse.ArgumentParser() 517 | parser.add_argument("command", choices=("self-check", "run-one")) 518 | args = parser.parse_args() 519 | payload = self_check() if args.command == "self-check" else run_one() 520 | print(json.dumps(payload, indent=2, sort_keys=True)) 521 | return 0 if payload.get("classification") in ( 522 | None, 523 | "UNCOUNTED_QUALIFICATION_PASS", 524 | ) else 1 525 | 526 | if __name__ == "__main__": 527 | raise SystemExit(main()) ============================================================================== FILE: tools/design_academy_counted_round3_recovery.py ============================================================================== --- lines 191-266 --- 191 | "commercial_use": "blocked", 192 | "reason": 193 | "Unknown source permission blocks reuse and " 194 | "commercial release until provenance is verified.", 195 | }, 196 | "safety_gate": { 197 | "risk_class": "low", 198 | "action": "continue", 199 | "forge_execution_allowed": False, 200 | "reason": 201 | "Continue knowledge-only assessment while withholding " 202 | "tool execution and Forge release authority.", 203 | }, 204 | "limitations": [ 205 | "No physical cabinet or stored object has been measured.", 206 | "No manufacturing or commercial release is authorised.", 207 | ], 208 | } 209 | 210 | normalised = canonicalise_academy_answer( 211 | json.dumps(fixture), 212 | 3, 213 | ) 214 | 215 | canonical = json.loads( 216 | normalised["canonical"] 217 | ) 218 | 219 | if canonical != fixture: 220 | raise RuntimeError( >> 221 | "Strict Round 3 canonicalisation changed a valid fixture." 222 | ) 223 | 224 | assessment = practice_service.evaluate_response( 225 | skill_id, 226 | bundle, 227 | canonical, 228 | 3, 229 | ) 230 | 231 | if assessment.get("passed") is not True: 232 | raise RuntimeError( 233 | "Official evaluator rejected the strict recovery fixture: " 234 | + json.dumps(assessment, ensure_ascii=False) 235 | ) 236 | 237 | return { 238 | "ok": True, 239 | "classification": 240 | "RECOVERY_RUNNER_SELF_TEST_PASS", 241 | "skill_id": skill_id, 242 | "score_percent": 243 | assessment.get("score_percent"), 244 | "forge_allowed": False, 245 | "repair_function": 246 | repair.__name__, 247 | "repair_module": 248 | str(GENERIC_QUALIFIER), 249 | } 250 | 251 | 252 | def run_recovery(args: argparse.Namespace) -> tuple[dict[str, Any], int]: 253 | skill_id = args.skill_id 254 | source = Path( 255 | args.source_evidence 256 | ).resolve() 257 | 258 | receipt_path = Path(args.receipt) 259 | 260 | verify_hash( 261 | PRACTICE, 262 | args.expected_state_sha, 263 | "Practice state", 264 | ) 265 | 266 | verify_hash( --- lines 350-425 --- 350 | ) 351 | 352 | source_result = load( 353 | source / "result.json" 354 | ) 355 | 356 | rejected_raw = ( 357 | source / "raw_model_answer.txt" 358 | ).read_text( 359 | encoding="utf-8", 360 | errors="strict", 361 | ).strip() 362 | 363 | if ( 364 | rejected_raw 365 | != str(brain.get("raw_answer") or "").strip() 366 | ): 367 | raise RuntimeError( 368 | "Preserved raw answer differs from the Brain evidence." 369 | ) 370 | 371 | if ( 372 | text_sha256(rejected_raw) 373 | != brain.get("raw_answer_sha256") 374 | ): 375 | raise RuntimeError( 376 | "Preserved raw answer checksum is invalid." 377 | ) 378 | 379 | if ( >> 380 | source_result.get("infrastructure_failure") 381 | is not True 382 | or source_result.get("retryable") 383 | is not True 384 | ): 385 | raise RuntimeError( 386 | "Source evidence is not an eligible retryable " 387 | "infrastructure failure." 388 | ) 389 | 390 | state = load(PRACTICE) 391 | autopilot = load(AUTOPILOT) 392 | sprint = load(SPRINT) 393 | 394 | record = ( 395 | state.get("skills") or {} 396 | ).get(skill_id) 397 | 398 | qualification = ( 399 | autopilot.get("skills") or {} 400 | ).get(skill_id) 401 | 402 | if not isinstance(record, dict): 403 | raise RuntimeError( 404 | "Candidate practice record is missing." 405 | ) 406 | 407 | if not isinstance(qualification, dict): 408 | raise RuntimeError( 409 | "Candidate Autopilot record is missing." 410 | ) 411 | 412 | if autopilot.get("current_skill") != skill_id: 413 | raise RuntimeError( 414 | "Autopilot is pointing at a different skill." 415 | ) 416 | 417 | if sprint.get("current_skill") != skill_id: 418 | raise RuntimeError( 419 | "Commercial sprint is pointing at a different skill." 420 | ) 421 | 422 | if int(record.get("attempts") or 0) != 2: 423 | raise RuntimeError( 424 | "Recovery requires exactly two counted attempts." 425 | ) --- lines 444-578 --- 444 | "Practice Forge gate is open." 445 | ) 446 | 447 | run_id = ( 448 | datetime.now(timezone.utc) 449 | .strftime("%Y%m%dT%H%M%S%fZ") 450 | + "-COUNTED-R3-RECOVERY" 451 | ) 452 | 453 | run_dir = ( 454 | practice_service.evidence_root 455 | / domain 456 | / name 457 | / run_id 458 | ) 459 | 460 | run_dir.mkdir( 461 | parents=True, 462 | exist_ok=False, 463 | ) 464 | 465 | source_hashes = { 466 | filename: sha256(source / filename) 467 | for filename in required_source_files 468 | } 469 | 470 | _atomic_json_write( 471 | run_dir / "recovery_source.json", 472 | { 473 | "source": >> 474 | "preserved_round3_infrastructure_failure", 475 | "source_evidence": str(source), 476 | "source_file_sha256": source_hashes, 477 | "source_raw_answer_sha256": 478 | text_sha256(rejected_raw), 479 | "counted_attempt_previously_consumed": 480 | False, 481 | "cherry_picking_allowed": 482 | False, 483 | "replacement_generation_allowed": 484 | False, 485 | "repair_required": 486 | True, 487 | "recorded_at": _utc_now(), 488 | }, 489 | ) 490 | 491 | for filename in required_source_files: 492 | shutil.copy2( 493 | source / filename, 494 | run_dir / ("source-" + filename), 495 | ) 496 | 497 | prompt = ( 498 | source / "prompt.txt" 499 | ).read_text( 500 | encoding="utf-8", 501 | errors="strict", 502 | ) 503 | 504 | module, repair_round3_response = ( 505 | load_repair_module() 506 | ) 507 | 508 | try: 509 | repaired_payload = repair_round3_response( 510 | prompt, 511 | rejected_raw, 512 | run_dir, 513 | ) 514 | 515 | response = repaired_payload.get("answer") 516 | 517 | if not isinstance(response, dict): 518 | raise RuntimeError( 519 | "Repair did not return a structured answer." 520 | ) 521 | 522 | strict = canonicalise_academy_answer( 523 | json.dumps(response), 524 | 3, 525 | ) 526 | 527 | canonical = json.loads( 528 | strict["canonical"] 529 | ) 530 | 531 | if canonical != response: 532 | raise RuntimeError( >> 533 | "Repaired response changed during strict canonicalisation." 534 | ) 535 | 536 | bundle = practice_service._lesson_bundle( 537 | skill_id 538 | ) 539 | 540 | guard_error = ( 541 | practice_service 542 | ._response_contract_guard_error( 543 | bundle, 544 | response, 545 | 3, 546 | ) 547 | ) 548 | 549 | if guard_error: 550 | raise RuntimeError(guard_error) 551 | 552 | assessment = practice_service.evaluate_response( 553 | skill_id, 554 | bundle, 555 | response, 556 | 3, 557 | ) 558 | 559 | _atomic_json_write( 560 | run_dir / "practice_response.json", 561 | response, 562 | ) 563 | 564 | _atomic_json_write( 565 | run_dir / "assessment.json", 566 | assessment, 567 | ) 568 | 569 | except Exception as exc: 570 | failure = { 571 | "ok": False, 572 | "classification": 573 | "COUNTED_ROUND3_RECOVERY_NOT_CONSUMED", 574 | "skill_id": skill_id, 575 | "retryable": True, 576 | "infrastructure_failure": True, 577 | "counted_attempt_consumed": False, 578 | "attempts": 2, --- lines 649-724 --- 649 | if int(record.get("successful_attempts") or 0) != 2: 650 | raise RuntimeError( 651 | "Successful-round state changed before commit." 652 | ) 653 | 654 | if record.get("knowledge_certified") is not False: 655 | raise RuntimeError( 656 | "Knowledge certification changed before commit." 657 | ) 658 | 659 | if record.get("forge_allowed") is not False: 660 | raise RuntimeError( 661 | "Forge gate changed before commit." 662 | ) 663 | 664 | state["current_skill"] = skill_id 665 | state["network"] = network 666 | 667 | record["status"] = "practising" 668 | record["attempts"] = ( 669 | int(record.get("attempts") or 0) + 1 670 | ) 671 | record["updated_at"] = _utc_now() 672 | state["updated_at"] = _utc_now() 673 | 674 | _atomic_json_write( 675 | PRACTICE, 676 | state, 677 | ) 678 | >> 679 | record["infrastructure_failures"] = 0 680 | 681 | record = practice_service._record_outcome( 682 | skill_id, 683 | record, 684 | bundle, 685 | assessment, 686 | run_dir, 687 | response, 688 | ) 689 | 690 | state["skills"][skill_id] = record 691 | state["current_skill"] = None 692 | state["updated_at"] = _utc_now() 693 | 694 | result = { 695 | "ok": bool(assessment["passed"]), 696 | "classification": ( 697 | "COUNTED_ROUND3_RECOVERY_PASS" 698 | if assessment["passed"] 699 | else "COUNTED_ROUND3_RECOVERY_FAIL" 700 | ), 701 | "skill_id": skill_id, 702 | "counted_round": 3, 703 | "counted_attempt_consumed": True, 704 | "attempts": record["attempts"], 705 | "successful_attempts": 706 | record["successful_attempts"], 707 | "score_percent": 708 | assessment["score_percent"], 709 | "status": record["status"], 710 | "knowledge_certified": 711 | record["knowledge_certified"], 712 | "forge_allowed": 713 | record["forge_allowed"], 714 | "tool_evidence_attempts": 715 | int( 716 | record.get("tool_evidence_attempts") 717 | or 0 718 | ), 719 | "source_evidence": str(source), 720 | "recovery_evidence": str(run_dir), 721 | "repair_used": True, 722 | "replacement_generation_used": False, 723 | "cherry_picking_allowed": False, 724 | } ============================================================================== FILE: tools/design_academy_generic_qualify.py ============================================================================== --- lines 85-160 --- 85 | normalised = canonicalise_academy_answer( 86 | raw, 87 | round_number, 88 | ) 89 | return json.loads(normalised["canonical"]) 90 | 91 | raise RuntimeError( 92 | "Brain response did not contain a usable Academy answer" 93 | ) 94 | 95 | 96 | def repair_round3_response( 97 | prompt: str, 98 | rejected_raw: str, 99 | evidence: Path, 100 | ) -> dict[str, Any]: 101 | repair_request = { 102 | "model": MODEL_NAME, 103 | "think": False, 104 | "stream": False, 105 | "messages": [ 106 | { 107 | "role": "system", 108 | "content": ( 109 | "Repair one rejected SHiRE Academy Round 3 answer. " 110 | "Return only one JSON object matching the supplied schema. " 111 | "Use exactly these root fields: round, transfer_project, " 112 | "boundary_cases, provenance_review, safety_gate and " 113 | "limitations. transfer_project must contain title, goal, " 114 | "inputs, exactly three steps, outputs and exactly two " >> 115 | "measurable acceptance_criteria. boundary_cases must " 116 | "contain minimum, nominal, maximum and invalid. " 117 | "provenance_review must use licence_status unknown, " 118 | "decision quarantine and commercial_use blocked, with a " 119 | "reason of at least 20 characters. safety_gate must use " 120 | "risk_class low, action continue, " 121 | "forge_execution_allowed false and a reason of at least " 122 | "20 characters. Give exactly two honest limitations. " 123 | "Preserve relevant subject content from the rejected " 124 | "draft. Do not claim tool execution, physical validation, " 125 | "Forge access, release authority or commercial readiness." 126 | ), 127 | }, 128 | { 129 | "role": "user", 130 | "content": json.dumps( 131 | { 132 | "academy_prompt": prompt, 133 | "rejected_raw_answer": rejected_raw, 134 | }, 135 | sort_keys=True, 136 | ), 137 | }, 138 | ], 139 | "options": { 140 | "temperature": 0.0, 141 | "num_predict": 720, 142 | "num_ctx": 1536, 143 | }, 144 | "format": ACADEMY_ROUND_JSON_SCHEMAS[3], 145 | } 146 | 147 | write_json( 148 | evidence / "round3-repair-request.json", 149 | repair_request, 150 | ) 151 | 152 | request = urllib.request.Request( 153 | MODEL_URL, 154 | data=json.dumps(repair_request).encode("utf-8"), 155 | headers={"Content-Type": "application/json"}, 156 | method="POST", 157 | ) 158 | 159 | try: 160 | with urllib.request.urlopen( --- lines 412-487 --- 412 | if args.direct_round3: 413 | payload = generate_round3_direct( 414 | prompt, 415 | evidence, 416 | ) 417 | else: 418 | try: 419 | payload = practice_service._ask_brain( 420 | prompt, 421 | risk_mode, 422 | round_number, 423 | ) 424 | except AcademyBrainResponseError as exc: 425 | error_payload = dict(exc.payload or {}) 426 | 427 | write_json( 428 | evidence / "brain-error.json", 429 | { 430 | "error": str(exc), 431 | "payload": error_payload, 432 | }, 433 | ) 434 | 435 | rejected_raw = str( 436 | error_payload.get("raw_answer") or "" 437 | ).strip() 438 | 439 | retryable_round3_failure = ( 440 | round_number == 3 441 | and error_payload.get("retryable") is True >> 442 | and error_payload.get("infrastructure_failure") is True 443 | ) 444 | 445 | if not retryable_round3_failure: 446 | raise 447 | 448 | if rejected_raw: 449 | payload = repair_round3_response( 450 | prompt, 451 | rejected_raw, 452 | evidence, 453 | ) 454 | repair_used = True 455 | else: 456 | payload = generate_round3_direct( 457 | prompt, 458 | evidence, 459 | ) 460 | write_json( 461 | evidence / "brain_payload.json", 462 | payload, 463 | ) 464 | 465 | response = extract_response( 466 | payload, 467 | round_number, 468 | ) 469 | 470 | guard_error = ( 471 | practice_service._response_contract_guard_error( 472 | bundle, 473 | response, 474 | round_number, 475 | ) 476 | ) 477 | 478 | if guard_error: 479 | raise RuntimeError(guard_error) 480 | 481 | assessment = practice_service.evaluate_response( 482 | skill_id, 483 | bundle, 484 | response, 485 | round_number, 486 | ) 487 | ============================================================================== FILE: tools/design_academy_mass_learning_infrastructure_selftest.py ============================================================================== --- lines 1-162 --- 1 | #!/usr/bin/env python3 2 | from __future__ import annotations 3 | 4 | import ast 5 | import copy 6 | import json 7 | from pathlib import Path 8 | 9 | ROOT = Path(__file__).resolve().parents[1] 10 | 11 | BRAIN = ROOT / "ai/brain_server.py" 12 | PRACTICE = ROOT / "services/design_academy_practice_service.py" 13 | 14 | brain_source = BRAIN.read_text(encoding="utf-8") 15 | practice_source = PRACTICE.read_text(encoding="utf-8") 16 | 17 | tree = ast.parse( 18 | practice_source, 19 | filename=str(PRACTICE), 20 | ) 21 | 22 | method = next( 23 | ( 24 | node 25 | for node in ast.walk(tree) 26 | if isinstance(node, ast.FunctionDef) 27 | and node.name >> 28 | == "_infrastructure_failure_outcome" 29 | ), 30 | None, 31 | ) 32 | 33 | if method is None: 34 | raise SystemExit( 35 | "FAIL: Infrastructure-accounting helper is missing." 36 | ) 37 | 38 | standalone = copy.deepcopy(method) 39 | standalone.decorator_list = [] 40 | standalone.returns = None 41 | 42 | for argument in standalone.args.args: 43 | argument.annotation = None 44 | 45 | module = ast.Module( 46 | body=[standalone], 47 | type_ignores=[], 48 | ) 49 | 50 | ast.fix_missing_locations(module) 51 | 52 | namespace: dict[str, object] = {} 53 | 54 | exec( 55 | compile( 56 | module, 57 | "", 58 | "exec", 59 | ), 60 | namespace, 61 | ) 62 | 63 | helper = namespace[ >> 64 | "_infrastructure_failure_outcome" 65 | ] 66 | 67 | first = { 68 | "attempts": 1, 69 | "successful_attempts": 0, 70 | "infrastructure_failures": 0, 71 | "status": "practising", 72 | } 73 | 74 | first_result = helper(first) 75 | 76 | assert first_result == ( 77 | 1, 78 | "infrastructure_retry", 79 | True, 80 | ) 81 | 82 | assert first["attempts"] == 0 >> 83 | assert first["infrastructure_failures"] == 1 84 | assert first["status"] == "pending" 85 | 86 | third = { 87 | "attempts": 3, 88 | "successful_attempts": 2, 89 | "infrastructure_failures": 2, 90 | "status": "practising", 91 | } 92 | 93 | third_result = helper(third) 94 | 95 | assert third_result == ( 96 | 3, 97 | "failed", 98 | False, 99 | ) 100 | 101 | assert third["attempts"] == 2 102 | assert third["successful_attempts"] == 2 >> 103 | assert third["infrastructure_failures"] == 3 104 | assert third["status"] == "failed" 105 | 106 | assert ( >> 107 | "self._infrastructure_failure_outcome(" 108 | in practice_source 109 | ) 110 | 111 | required_round3_prompt_tokens = ( 112 | "Use ONLY these root fields:", 113 | "round, transfer_project, boundary_cases, provenance_review, safety_gate,", 114 | "transfer_project MUST contain title, goal, inputs, steps, outputs", 115 | "boundary_cases", 116 | "licence_status=unknown", 117 | "decision=quarantine", 118 | "commercial_use=blocked", 119 | "forge_execution_allowed=false", >> 120 | "project_steps, acceptance_criteria, safe_knowledge_gate,", 121 | "unknown_source_quarantine", 122 | ) 123 | 124 | for token in required_round3_prompt_tokens: 125 | assert token in brain_source, token 126 | 127 | strict_contract_tokens = ( >> 128 | 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', 129 | '"transfer_project"', 130 | '"boundary_cases"', 131 | '"provenance_review"', 132 | '"safety_gate"', 133 | '"additionalProperties": False', 134 | ) 135 | 136 | for token in strict_contract_tokens: 137 | assert token in brain_source, token 138 | 139 | print(json.dumps({ 140 | "ok": True, 141 | "classification": 142 | "MASS_LEARNING_INFRASTRUCTURE_SELF_TEST_PASS", 143 | "version": "0002L", 144 | "first_infrastructure_failure_attempt_rolled_back": 145 | True, 146 | "third_infrastructure_failure_attempt_rolled_back": 147 | True, 148 | "third_failure_still_stops_retries": 149 | True, 150 | "round3_exact_nested_prompt_installed": 151 | True, 152 | "old_flat_round3_fields_explicitly_forbidden": 153 | True, 154 | "academy_round_json_v6_preserved": 155 | True, 156 | "strict_additional_properties_gate_preserved": 157 | True, 158 | "certification_rules_weakened": 159 | False, 160 | "forge_permission_changed": 161 | False, 162 | }, indent=2, sort_keys=True)) ============================================================================== FILE: tools/design_academy_observed_round1_selftest.py ============================================================================== --- lines 16-91 --- 16 | "_SAFETY_SCHEMA", "_PROVENANCE_SCHEMA", 17 | } 18 | wanted_functions = { 19 | "_academy_candidate_object", "_academy_validate_shape", 20 | "canonicalise_academy_answer", 21 | } 22 | selected = [] 23 | for node in brain_tree.body: 24 | if isinstance(node, (ast.Assign, ast.AnnAssign)): 25 | names = [] 26 | targets = node.targets if isinstance(node, ast.Assign) else [node.target] 27 | for target in targets: 28 | if isinstance(target, ast.Name): names.append(target.id) 29 | if wanted_assignments.intersection(names): selected.append(node) 30 | elif isinstance(node, ast.ClassDef) and node.name == "AcademyStructuredOutputError": 31 | selected.append(node) 32 | elif isinstance(node, ast.FunctionDef) and node.name in wanted_functions: 33 | selected.append(node) 34 | 35 | namespace = {"json": json, "ast": ast, "re": __import__("re"), "hashlib": __import__("hashlib")} 36 | exec(compile(ast.Module(body=selected, type_ignores=[]), str(brain_path), "exec"), namespace) 37 | canonicalise = namespace["canonicalise_academy_answer"] 38 | error_type = namespace["AcademyStructuredOutputError"] 39 | schemas = namespace["ACADEMY_ROUND_JSON_SCHEMAS"] 40 | 41 | observed = '{\n "skill_id": "parametric_cad.parameter-architecture",\n "name": "Parameter architecture",\n "domain": "parametric_cad",\n "risk": "low",\n "lane": "tool_evidence",\n "professional_review": false,\n "round": 1,\n "focus": "fundamentals and repeatable method",\n "principles": [\n "Name parameters by meaning and include units, ranges and dependencies.",\n "Build from stable datums instead of fragile generated edges.",\n "Separate user parameters from derived calculations."\n ],\n "repeatable_method_steps": [\n "Define base dimensions as named inputs with explicit units rather than hard-coded values.",\n "Construct geometry using stable datums to drive derived features through logical relationships.",\n "Isolate calculation logic so it consumes base parameters and outputs final coordinates."\n ],\n "acceptance_criteria": [\n "Changing one named parameter updates the intended dependent dimension while unrelated geometry remains unchanged.",\n "The model remains valid when extreme values within the defined ranges are applied."\n ],\n "required_inputs": [\n "Base wall width in meters",\n "Standard door height in centimeters"\n ],\n "safe_knowledge_gate": "All relationships remain knowledge-only mathematical functions of named inputs with no tool execution or release authority.",\n "limitations": [\n "This method does not automatically optimise complex layouts requiring global search.",\n "It requires manual definition of parameter ranges and units for intricate designs."\n ],\n "forge_execution_allowed": false\n}' 42 | result = canonicalise(observed, 1) 43 | answer = json.loads(result["canonical"]) 44 | expected_keys = { 45 | "round", "principles", "repeatable_method_steps", >> 46 | "acceptance_criteria", "required_inputs", "safe_knowledge_gate", 47 | "limitations", "forge_execution_allowed", 48 | } 49 | if set(answer) != expected_keys: 50 | raise SystemExit(f"STOP: Canonical Round 1 keys mismatch: {sorted(answer)}") 51 | if answer["forge_execution_allowed"] is not False: 52 | raise SystemExit("STOP: Unsafe Forge flag accepted") 53 | if len(answer["repeatable_method_steps"]) != 3: 54 | raise SystemExit("STOP: Observed method steps were not preserved") 55 | expected_pruned = {"skill_id", "name", "domain", "risk", "lane", "professional_review", "focus"} 56 | if set(result["metadata_pruned"]) != expected_pruned: 57 | raise SystemExit(f"STOP: Metadata pruning mismatch: {result['metadata_pruned']}") 58 | if "summary" in answer or "safety_gate" in answer or "method" in answer: 59 | raise SystemExit("STOP: Missing content was invented during canonicalisation") 60 | 61 | unsafe = json.loads(observed) 62 | unsafe["forge_execution_allowed"] = True 63 | try: 64 | canonicalise(json.dumps(unsafe), 1) 65 | except error_type: 66 | pass 67 | else: 68 | raise SystemExit("STOP: Unsafe top-level Forge flag was accepted") 69 | 70 | unknown = json.loads(observed) 71 | unknown["tool_execution_claimed"] = True 72 | try: 73 | canonicalise(json.dumps(unknown), 1) 74 | except error_type: 75 | pass 76 | else: 77 | raise SystemExit("STOP: Unknown execution claim was silently pruned") 78 | 79 | service_source = service_path.read_text(encoding="utf-8") 80 | required = ( 81 | '"academy_round_json_v4"', 82 | '"academy_round_specific_v3"', 83 | '"repeatable_method_steps"', 84 | '"safe_knowledge_gate"', 85 | 'round1_flat_gate', 86 | ) 87 | for marker in required: 88 | if marker not in service_source: 89 | raise SystemExit(f"STOP: Service marker missing: {marker}") 90 | 91 | print(json.dumps({ ============================================================================== FILE: tools/design_academy_round2_completeness_selftest.py ============================================================================== --- lines 118-174 --- 118 | methods=[n for n in class_node.body if isinstance(n,ast.FunctionDef) and n.name in method_names] 119 | helper_nodes=[] 120 | for n in service_tree.body: 121 | if isinstance(n,(ast.Assign,ast.AnnAssign)): 122 | targets=n.targets if isinstance(n,ast.Assign) else [n.target] 123 | if any(isinstance(t,ast.Name) and t.id in {"ROUND_REQUIRED_RESPONSE_KEYS","_WORD_RE"} for t in targets): 124 | helper_nodes.append(n) 125 | elif isinstance(n,ast.FunctionDef) and n.name=="_significant_words": helper_nodes.append(n) 126 | fake_class=ast.ClassDef(name="GuardHarness",bases=[],keywords=[],body=methods,decorator_list=[]) 127 | svc_ns={"Any":object,"re":__import__("re")} 128 | service_module = ast.fix_missing_locations(ast.Module(body=helper_nodes+[fake_class], type_ignores=[])) 129 | exec(compile(service_module, str(service_path), "exec"), svc_ns) 130 | h=svc_ns["GuardHarness"]() 131 | bundle={ 132 | "principles":["Name parameters by meaning and include units, ranges and dependencies."], 133 | "failures":["Scattered hard-coded dimensions."], 134 | "certification":{"professional_review_required":False}, 135 | } 136 | err=h._response_contract_guard_error(bundle,observed_60,2) 137 | if not err or "provenance reason" not in err.lower(): 138 | raise SystemExit(f"STOP: Service guard did not reject observed response: {err}") 139 | if h._response_contract_guard_error(bundle,correct,2) is not None: 140 | raise SystemExit("STOP: Service guard rejected complete response") 141 | assessment=h.evaluate_response("parametric_cad.parameter-architecture",bundle,correct,2) 142 | if assessment.get("passed") is not True or assessment.get("score_percent")!=100: 143 | raise SystemExit(f"STOP: Complete response failed evaluator: {assessment}") 144 | 145 | brain_source=brain_path.read_text(encoding="utf-8") 146 | service_source=service_path.read_text(encoding="utf-8") 147 | for marker in ( >> 148 | '"academy_round_json_v6"','"academy_round_specific_v5"', 149 | '"round2_nested_contract_guard": True','"round2_any_contract_corrective_retry": True', 150 | 'academy_model_retry_reason', 'round2_contract_incomplete', 151 | ): 152 | if marker not in brain_source: raise SystemExit(f"STOP: Brain marker missing: {marker}") 153 | for marker in ( >> 154 | '"round_specific_micro_exam_v5"','academy_round_json_v6', 155 | 'MUST include a reason of at least 20 characters', 156 | '_response_contract_guard_error','response contract guard', 157 | ): 158 | if marker not in service_source: raise SystemExit(f"STOP: Service marker missing: {marker}") 159 | 160 | print(json.dumps({ 161 | "ok":True, 162 | "output_contract":"academy_round_json_v6", 163 | "round2_contract":"completeness_guard_v1", 164 | "observed_60_percent_answer_rejected_before_assessment":True, 165 | "missing_provenance_reason_blocked":True, 166 | "unapproved_safety_action_blocked":True, 167 | "any_round2_contract_failure_gets_one_corrective_retry":True, 168 | "service_preassessment_guard":True, 169 | "valid_round2_evaluator_score":assessment["score_percent"], 170 | "remaining_counted_attempts_protected":True, 171 | "missing_content_invented":False, 172 | "round1_and_round3_preserved":True, 173 | "blender_required":False, 174 | },indent=2)) ============================================================================== FILE: tools/design_academy_round3_timeout_selftest.py ============================================================================== --- lines 68-146 --- 68 | "ok": False, 69 | "error": "Academy model request timed out", 70 | "retryable": True, 71 | "infrastructure_failure": True, 72 | "output_contract": "academy_round_json_v6", 73 | "exam_round": 3, 74 | "timeout_seconds": 360, 75 | "timeout_stage": "ollama_generation", 76 | "raw_answer": "", 77 | "raw_answer_sha256": hashlib.sha256(b"").hexdigest(), 78 | "raw_answer_audited": True, 79 | "model_retry_count": 0, 80 | "model_retry_reason": "", 81 | "initial_raw_answer": "", 82 | "initial_raw_answer_sha256": "", 83 | } 84 | 85 | service_ns = function_namespace( 86 | service_source, 87 | {"_academy_client_timeout_for_round"}, 88 | { 89 | "ACADEMY_MICRO_EXAM_CLIENT_TIMEOUT": 300, 90 | "ACADEMY_ROUND3_CLIENT_TIMEOUT": 420, 91 | }, 92 | ) 93 | assert service_ns["_academy_client_timeout_for_round"](1) == 300 94 | assert service_ns["_academy_client_timeout_for_round"](2) == 300 95 | assert service_ns["_academy_client_timeout_for_round"](3) == 420 96 | 97 | required_brain_tokens = [ >> 98 | 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', 99 | 'os.environ.get("SHIRE_ACADEMY_ROUND3_TIMEOUT", "360")', 100 | '"round3_timeout_seconds": ACADEMY_ROUND3_TIMEOUT', 101 | '"round3_structured_timeout_response": True', 102 | 'status=504', 103 | '"schema_name": f"academy_round_{exam_round}_json_v6"', 104 | 'SHIRE ACADEMY ROUND 3: TRANSFER AND MEASURABLE ACCEPTANCE.', 105 | ] 106 | for token in required_brain_tokens: 107 | assert token in brain_source, token 108 | 109 | required_service_tokens = [ 110 | 'ACADEMY_ROUND3_CLIENT_TIMEOUT = 420', 111 | 'timeout=_academy_client_timeout_for_round(round_number)', 112 | '"practice_round3_client_timeout_seconds": ACADEMY_ROUND3_CLIENT_TIMEOUT', 113 | '"http 504"', >> 114 | 'if payload.get("output_contract") != "academy_round_json_v6"', 115 | 'if payload.get("context_profile") != "academy_round_specific_v5"', 116 | ] 117 | for token in required_service_tokens: 118 | assert token in service_source, token 119 | 120 | # Ensure Round 3 content contract was not weakened. 121 | for token in ( 122 | '"transfer_project"', 123 | '"boundary_cases"', 124 | '"provenance_review"', 125 | '"safety_gate"', 126 | '"limitations"', 127 | '"forge_execution_allowed": {"type": "boolean", "const": False}', 128 | ): 129 | assert token in brain_source, token 130 | 131 | print(json.dumps({ 132 | "ok": True, 133 | "output_contract": "academy_round_json_v6", 134 | "round3_server_timeout_seconds": 360, 135 | "round3_client_timeout_seconds": 420, 136 | "round1_and_round2_server_timeout_seconds": 220, 137 | "round1_and_round2_client_timeout_seconds": 300, 138 | "structured_timeout_http_status": 504, 139 | "structured_timeout_retryable": True, 140 | "structured_timeout_infrastructure_failure": True, 141 | "empty_raw_answer_sha256_audited": True, 142 | "round3_schema_preserved": True, 143 | "round2_completeness_guard_preserved": True, 144 | "final_counted_attempt_protected_on_timeout": True, 145 | "blender_required": False, 146 | }, indent=2)) ============================================================================== FILE: tools/design_academy_round_contract_selftest.py ============================================================================== --- lines 94-204 --- 94 | "Invalid boundary values are rejected.", 95 | ], 96 | }, 97 | "boundary_cases": { 98 | "minimum": "Smallest permitted positive dimensions.", 99 | "nominal": "Typical dimensions within the valid range.", 100 | "maximum": "Largest permitted dimensions before rejection.", 101 | "invalid": "Negative or zero dimensions must be rejected.", 102 | }, 103 | "provenance_review": { 104 | "licence_status": "unknown", 105 | "decision": "quarantine", 106 | "commercial_use": "blocked", 107 | "reason": 108 | "Unknown licensing remains quarantined and blocks commercial reuse.", 109 | }, 110 | "safety_gate": { 111 | "risk_class": "low", 112 | "action": "continue", 113 | "forge_execution_allowed": False, 114 | "reason": 115 | "Transfer practice remains knowledge-only until evidence passes.", 116 | }, 117 | "limitations": [ 118 | "No CadQuery tool evidence was executed.", 119 | "No production readiness is claimed.", 120 | ], 121 | }, 122 | } 123 | >> 124 | assert ACADEMY_OUTPUT_CONTRACT == "academy_round_json_v6" 125 | assert set(ACADEMY_ROUND_JSON_SCHEMAS) == {1, 2, 3} 126 | assert set(ACADEMY_ROUND_REQUIRED_KEYS) == {1, 2, 3} 127 | assert set(ACADEMY_ROUND_SYSTEM_CONTEXTS) == {1, 2, 3} 128 | 129 | for round_number, sample in samples.items(): 130 | schema = ACADEMY_ROUND_JSON_SCHEMAS[round_number] 131 | 132 | assert schema["type"] == "object" 133 | assert schema["additionalProperties"] is False 134 | assert set(schema["required"]) == set( 135 | ACADEMY_ROUND_REQUIRED_KEYS[round_number] 136 | ) 137 | 138 | strict = canonicalise_academy_answer( 139 | json.dumps(sample), 140 | round_number, 141 | ) 142 | assert strict["repaired"] is False 143 | assert strict["method"] == "strict_json" 144 | assert json.loads(strict["canonical"]) == sample 145 | 146 | trailing = json.dumps(sample, separators=(",", ":"))[:-1] + ",}" 147 | repaired = canonicalise_academy_answer( 148 | trailing, 149 | round_number, 150 | ) 151 | assert repaired["repaired"] is True 152 | assert json.loads(repaired["canonical"]) == sample 153 | 154 | unsafe = deepcopy(sample) 155 | if round_number == 1: 156 | unsafe["forge_execution_allowed"] = True 157 | else: 158 | unsafe["safety_gate"]["forge_execution_allowed"] = True 159 | 160 | try: 161 | canonicalise_academy_answer( 162 | json.dumps(unsafe), 163 | round_number, 164 | ) 165 | except AcademyStructuredOutputError: 166 | pass 167 | else: 168 | raise SystemExit( 169 | f"STOP: Round {round_number} unsafe Forge flag accepted" 170 | ) 171 | 172 | required_practice_markers = ( 173 | '"exam_round": int(round_number)', >> 174 | 'payload.get("output_contract") != "academy_round_json_v6"', 175 | 'payload.get("context_profile") != "academy_round_specific_v5"', 176 | 'evaluate_response(skill_id, bundle, response, round_number)', 177 | "ROUND_REQUIRED_RESPONSE_KEYS", 178 | ) 179 | 180 | for marker in required_practice_markers: 181 | if marker not in practice_source: 182 | raise SystemExit(f"STOP: Missing practice marker: {marker}") 183 | 184 | required_brain_markers = ( >> 185 | 'ACADEMY_OUTPUT_CONTRACT = "academy_round_json_v6"', 186 | 'canonicalise_academy_answer(raw_answer, exam_round)', 187 | 'format_override=ACADEMY_ROUND_JSON_SCHEMAS[exam_round]', 188 | '"structured_output_schema": True', 189 | '"canonical_json_gate": True', 190 | ) 191 | 192 | for marker in required_brain_markers: 193 | if marker not in brain_source: 194 | raise SystemExit(f"STOP: Missing Brain marker: {marker}") 195 | 196 | print(json.dumps({ 197 | "ok": True, 198 | "output_contract": ACADEMY_OUTPUT_CONTRACT, 199 | "round_specific_contracts": [1, 2, 3], 200 | "strict_json_validated": True, 201 | "trailing_comma_repair_validated": True, 202 | "unsafe_forge_flag_blocked": True, 203 | "additional_properties_allowed": False, 204 | }, indent=2)) ============================================================================== FILE: tools/design_academy_structured_output_selftest.py ============================================================================== --- lines 11-86 --- 11 | ) 12 | 13 | sample = { 14 | "round": 1, 15 | "principles": [ 16 | "Use explicit units and stable coordinate references.", 17 | "Create valid closed solids from constrained geometry.", 18 | "Validate topology and measurable geometry before release.", 19 | ], 20 | "repeatable_method_steps": [ 21 | "Define valid input parameters and their permitted ranges.", 22 | "Construct the model from deterministic geometric operations.", 23 | "Check dimensions, solid validity and rejection behaviour.", 24 | ], 25 | "acceptance_criteria": [ 26 | "The resulting model is one valid closed solid.", 27 | "Invalid input values are rejected before geometry creation.", 28 | ], 29 | "required_inputs": [ 30 | "Target dimensions and permitted geometric ranges.", 31 | ], 32 | "safe_knowledge_gate": 33 | "This response is knowledge-only and cannot permit Forge execution.", 34 | "limitations": [ 35 | "No CadQuery tool evidence has been generated.", 36 | "No physical manufacturing result has been inspected.", 37 | ], 38 | "forge_execution_allowed": False, 39 | } 40 | >> 41 | assert ACADEMY_OUTPUT_CONTRACT == "academy_round_json_v6" 42 | 43 | strict = canonicalise_academy_answer( 44 | json.dumps(sample), 45 | 1, 46 | ) 47 | assert strict["repaired"] is False 48 | assert strict["method"] == "strict_json" 49 | assert json.loads(strict["canonical"]) == sample 50 | 51 | fenced = canonicalise_academy_answer( 52 | "```json\n" + json.dumps(sample) + "\n```", 53 | 1, 54 | ) 55 | assert json.loads(fenced["canonical"]) == sample 56 | 57 | trailing = json.dumps(sample, separators=(",", ":"))[:-1] + ",}" 58 | repaired = canonicalise_academy_answer( 59 | trailing, 60 | 1, 61 | ) 62 | assert repaired["repaired"] is True 63 | assert json.loads(repaired["canonical"]) == sample 64 | 65 | extra = deepcopy(sample) 66 | extra["summary"] = "This obsolete field must be rejected." 67 | 68 | try: 69 | canonicalise_academy_answer( 70 | json.dumps(extra), 71 | 1, 72 | ) 73 | except AcademyStructuredOutputError: 74 | extra_blocked = True 75 | else: 76 | extra_blocked = False 77 | 78 | assert extra_blocked 79 | 80 | unsafe = deepcopy(sample) 81 | unsafe["forge_execution_allowed"] = True 82 | 83 | try: 84 | canonicalise_academy_answer( 85 | json.dumps(unsafe), 86 | 1, ------------------------------------------------------------ 9. ROUND-3 CONTRACT FILES ------------------------------------------------------------ /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v2/schema.json /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v2/schema.json /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v3/schema.json /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v3/schema.json /home/shire3d/ARMOR/data/academy/design_mastery/prompts/FORGE_DESIGN_CONTRACT.md /home/shire3d/ARMOR/data/academy/design_mastery/schemas/certification.schema.json /home/shire3d/ARMOR/data/academy/design_mastery/schemas/design_request.schema.json /home/shire3d/ARMOR/data/academy/design_mastery/schemas/skill_manifest.schema.json /home/shire3d/ARMOR/data/academy/design_mastery/schemas/source_record.schema.json Contract references containing acceptance_criteria: /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v2/manifest.json:14: "acceptance_criteria": "p.a", /home/shire3d/ARMOR/data/academy/design_mastery/runtime/commercial_design_sprint.json:16: "initial_acceptance_criteria": [ /home/shire3d/ARMOR/data/academy/design_mastery/contracts/parameter-architecture-r3-compact-v2/manifest.json:14: "acceptance_criteria": "p.a", /home/shire3d/ARMOR/data/academy/design_mastery/schemas/design_request.schema.json:107: "acceptance_criteria": { ------------------------------------------------------------ 10. SAFETY CONCLUSION ------------------------------------------------------------ Expected conclusion if the evidence agrees: - Academy UI is healthy. - Brain, Ollama and CadQuery are healthy. - This is not a machine or HTTP timeout. - Fillets generated a Round-3 contract/schema mismatch. - The mismatch was counted as infrastructure failure. - Three such failures paused autonomous practice. - The timer continues invoking the paused scheduler too frequently. ============================================================ FILLETS FAILURE TRACE COMPLETE — NOTHING CHANGED ============================================================ Evidence: /SHiREVault/Backup/OSBackups/SHIRE-ACADEMY-FILLETS-FAILURE-TRACE-20260805T113626Z No source, Academy state, timer or service was modified. No service was restarted. Sentinel was not modified or restarted.