Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
7315b96d0This file is pinned to the selected release. Download the original to open it in your design tool.
# Self-Healing Architecture
The design for making PCB Flow recover from failures on its own. Four parts: a **logging
schema**, a **failure→recovery matrix**, **retry rules**, and **autonomous resume** —
plus the **human-friendly error** layer that sits on top so an engineer always
understands what happened.
---
## The loop
```
run a step ─► wrap it ─► did it fail?
│ no ──► record success, advance
│ yes
▼
LOG (structured) ─► DIAGNOSE (classify) ─► consult knowledge/learning-db
│
▼
is it safe & known to auto-recover?
│ yes ─► RECOVER (retry / fallback) ─► worked? ─► resume
│ │ no
│ no ─────────────────────────────────►│
▼ ▼
EXPLAIN in plain English + say exactly what manual action is needed
```
The principle: **the AI is a background senior engineer.** It only interrupts the
electronics engineer when recovery is genuinely impossible — and even then it hands
over a plain-English explanation, not a stack trace.
---
## 1. Logging schema
Every automated step emits one **structured log record** (JSON Lines, appendable) to
`projects/<board>/.logs/<phase>.jsonl`, plus a human-readable mirror. One record per
attempt captures exactly the fields an audit needs:
```json
{
"ts": "2026-07-13T18:04:12Z", // timestamp
"project": "door-sensor",
"phase": "04-schematic-generation", // current workflow stage
"step": "wire block U3 (IMU)",
"command": "cdp eval clean_engine.js + s04.js", // what was executed
"script": "s04_imu.js", // generated script (path/name)
"stdout_tail": "...OK U3 <- imu (SPI, CS+INT wired)",
"status": "recovered", // ok | failed | recovered | escalated
"error": { // present only on failure
"class": "EDA-1", // maps to VULNERABILITY_REPORT id
"http": 401,
"message": "Unauthorized",
"stack": "…" // full trace for the AI
},
"recovery": {
"attempted": "re-auth prompt + retry",
"attempts": 1,
"result": "success"
},
"human_message": "The EasyEDA session had expired; you logged back in and the step continued."
}
```
**Two audiences, one record:** the AI reads `error.class`/`stack`; the engineer reads
`human_message` and `status`. A rendered log line looks like:
```
18:04:12 door-sensor · schematic · wire U3 ✅ recovered
→ EasyEDA session had expired; re-authenticated and continued (1 retry).
```
Design rules: **never swallow an error** (every wrapped call returns `{ok,err}` — see
SC-7); log *before* attempting recovery (so a hang still leaves a trace); one file per
phase so resume can find the last good step.
---
## 2. Failure → recovery matrix
The core table the healing engine acts on. (Full per-subsystem steps in
[`RECOVERY_PLAYBOOKS.md`](RECOVERY_PLAYBOOKS.md).)
| Failure | Detection | Auto-recovery | Retry | Fallback | Notify human? |
|---|---|---|---|---|---|
| EDA-1/2 session expired (401) | HTTP 401 / login DOM | prompt re-login, then retry | 1 after login | pause phase, resume on login | **Yes** (login) |
| EDA-5 rate limit (429) | HTTP 429 | exponential backoff | 3× (1s,4s,16s) | slow the part-search cadence | only if exhausted |
| EDA-6 / 500 server | HTTP 5xx | backoff + retry | 3× | wait & resume | only if exhausted |
| EDA-7 renderer hang | eval timeout > N s | `Target.createTarget`+`closeTarget`, reload, resume | 1 | reopen project, replay unsaved step | only if reload fails |
| EDA-10 part not found | empty search / no token match | broaden query; try LCSC id; try alt package | 2 | ask engineer to pick a part | if no match |
| EDA-12 unsaved lost | save失败 / no `done()` ack | save immediately; re-run last block | 1 | replay from manifest checkpoint | only if replay fails |
| EDA-13/14 stale read | FLOAT nets / same-eval read | wait, re-`getAll()` in fresh eval | 2 | — | no |
| BR-2 can't attach | no `:9222` socket | relaunch Chrome with debug flags | 2 | full profile re-clone | if relaunch fails |
| BR-3 logged out | login DOM on load | re-rsync logged-in profile; prompt login | 1 | ask engineer to sign in | **Yes** |
| BR-4 Singleton lock | launch error | `rm Singleton*`, relaunch | 1 | kill stray Chrome, retry | no |
| BR-5 edit-lock | write rejected / lock banner | close the other session, retry | 1 | ask engineer to close duplicates | if unresolved |
| KI-2 dropped footprints | count mismatch | remap known footprints; restore holes | 1 | list missing for engineer | if unmapped remain |
| KI-6 phantom DRC | no `.kicad_pro` sibling | copy ruleset via `drc.sh`, re-run | 1 | — | no |
| SC-2 missing dep | import error | run the install step | 1 | print exact install cmd | if install fails |
| SC-3 timeout | no result in N s | retry once with longer budget | 1 | escalate | if 2nd times out |
| SC-6 retry exhausted | max attempts hit | — | — | stop, checkpoint, explain | **Yes** |
| ST-1 uncommitted | dirty tree at phase end | auto-commit the phase output | — | — | no |
| ST-2 interrupted | manifest phase ≠ done | resume from last good step | — | replay pending step | no |
---
## 3. Retry rules
- **Exponential backoff** for transient/network faults (429, 5xx, timeouts): 1s → 4s
→ 16s, max 3 attempts, with jitter.
- **Idempotency first.** Only auto-retry a step that is safe to repeat. Generation and
placement scripts must be **re-runnable without duplicating** (guard: check if the
block already exists before creating). Non-idempotent steps (SC-8) get a
*checkpoint-and-replay*, not a blind retry.
- **Never auto-retry a live write that could double-apply** without an idempotency
guard — that turns one failure into two problems.
- **Cap and escalate.** After max attempts, stop, write a checkpoint, and explain.
Silent infinite retry (SC-4) is banned — every loop has a max and a timeout.
---
## 4. Autonomous resume
State that survives a crash lives in two places already: the committed **git history**
(geometry) and the **`project.yaml` manifest** (current phase + per-phase verdicts +
open steps). Resume is therefore deterministic:
1. On start, read `project.yaml` → the current phase and the last `PASS` verdict.
2. Compare against the live board / committed files to find the **last completed
step** (the manifest is the checkpoint; the board is the ground truth — verify,
don't trust blindly, per ST-4).
3. Identify **pending** work (a phase started but not `PASS`) and any **temp files**
(`.logs/*.jsonl`, generated scripts) that indicate an in-flight step.
4. **Replay only the incomplete step** — never redo completed, committed work.
5. Announce: *"Resuming door-sensor at Phase 6, step 'place motor block' — the
previous step (schematic audit) passed and is committed."*
The rule that makes this safe: **commit each phase's output when it passes** (ST-1
mitigation). Then "what's committed" == "what's done," and resume can trust it.
---
## 5. Human-friendly errors
Every escalation is translated from a technical fault into the five things an engineer
needs. The template:
> **What happened** · **Why** · **What I tried** · **Did it work** · **What you need
> to do** (if anything).
Examples:
| Raw error | What the engineer sees |
|---|---|
| `HTTP 401 Unauthorized` | *"Your EasyEDA session expired. I paused the schematic step. **Please log back into EasyEDA;** I'll continue automatically from where we stopped — no work is lost."* |
| `ECONNREFUSED :9222` | *"I couldn't connect to the EasyEDA window. I tried relaunching it twice. **Please make sure EasyEDA is open and you're signed in,** then say 'retry'."* |
| `kicad-cli: command not found` | *"KiCad's command-line tool isn't installed or isn't on the PATH. I can't run the design-rule check without it. **Install KiCad (handbook step 2)**, then say 'retry'."* |
| renderer eval timeout | *"The EasyEDA drawing window stopped responding (a known glitch). I restarted it and replayed the last step — **it recovered, nothing lost.**"* |
| `429 Too Many Requests` | *"EasyEDA asked me to slow down. I waited and retried; it's continuing now. No action needed."* |
The engineer **never** sees `401`, a stack trace, or a script path unless they ask —
those go to the log for the AI.
---
## What this buys a non-software engineer
Almost every S1/S2 failure becomes either an **invisible auto-recovery** or a **single
plain-English instruction** ("log back in", "install KiCad", "close the other EasyEDA
tab"). The engineer debugs electronics, not software. The build order to make it real
is in [`ROADMAP.md`](ROADMAP.md).