# CLAUDE.md Guidance for Claude Code (claude.ai/code) working in this subdirectory. ## What this is A deterministic pipeline that converts FRET natural-language requirements into a reactive controller and a state-machine diagram. Implements Thrust 1 + 2 of the HAHACS methodology (`../thesis/3-research-approach/approach.tex`). The pipeline is four stages: ``` FRET JSON --> fret_to_synth.py --> synthesis config JSON synthesis config --> synthesize.sh --> AIGER circuit (.aag) AIGER circuit --> trace_aiger.py --> DOT + PNG + SVG state machine AIGER circuit --> aag2dot.py --> gate-level circuit diagram ``` ## Running ```bash python3 scripts/fret_to_synth.py pwr_hybrid_3.json specs/synthesis_config_v3.json bash scripts/synthesize.sh specs/synthesis_config_v3.json circuits python3 scripts/trace_aiger.py circuits/PWR_HYBRID_3_DRC.aag diagrams dot -Tpng diagrams/PWR_HYBRID_3_DRC_states.dot -o diagrams/PWR_HYBRID_3_DRC_states.png ``` All scripts are pure Python 3 stdlib + bash. External binaries required: - `ltlsynt` (Spot) — `brew install spot` - `dot` (Graphviz) — `brew install graphviz` ## Architecture **`scripts/fret_to_synth.py`** — Auto-discovers mode groups by regex-scanning LTL formulas for `(control_X = q_Y)` patterns. Decomposes multi-valued mode variables into independent booleans and generates mutual-exclusion constraints so the synthesizer can't assert two modes simultaneously. Classifies every other variable as an environment input. See `docs/fret_to_synth.md`. **`scripts/synthesize.sh`** — Thin wrapper around `ltlsynt` that reads the synthesis config, extracts inputs/outputs/formula, and calls ltlsynt with AIGER output. Strips the `REALIZABLE` header line from the output. See `docs/synthesize.md`. **`scripts/trace_aiger.py`** — Exhaustive circuit evaluation: enumerates all reachable latch states, extracts guard conditions on transitions via boolean function simplification, emits DOT. See `docs/trace_aiger.md`. **`scripts/aag2dot.py`** — Gate-level diagram of the AIGER circuit (wires, AND gates, latches). Useful for debugging unexpectedly large circuits. See `docs/aag2dot.md`. ## Key design decisions - **Mode decomposition with mutex constraint.** FRET's `control_mode = q_X` is a single integer variable that inherently holds one value. ltlsynt works over independent booleans. So we decompose into `in_mode_shutdown`, `in_mode_heatup`, etc., and add a "G(exactly one active)" constraint. The mutex is a *synthesis encoding artifact*, not a missing FRET requirement. - **Prefer `ftInfAUExpanded` over `ft`.** FRET emits multiple LTL forms; we use the expanded infinite-horizon form because ltlsynt works over infinite traces. The `ft` form can contain LAST operators that bias toward finite traces. - **Regex-based mode discovery.** Fully automatic — no hardcoded variable lists. Add a new mode in FRET and re-export; the script picks it up. - **Strict sanity check.** If any `control_` or `q_` token survives the boolean encoding, the script errors out rather than producing silent bugs. ## FRET naming conventions Enforced by `fret_to_synth.py`. See `README.md` for the full rules. - Mode variables: `control_` with values `q_`. Decomposed to `in__`. - Environment inputs: anything else. Assumed boolean; continuous quantities should be abstracted to predicates at the FRET level (e.g., `t_avg_above_min`). ## Extending - **New requirement.** Add it in FRET, re-export JSON, re-run the pipeline. No code changes needed as long as the new variables follow the naming rule. - **New mode group.** Same as above — `fret_to_synth.py` auto-discovers. - **Unrealizable spec.** Use FRET's realizability checking first to isolate the conflicting requirement. `synthesize.sh` will print `UNREALIZABLE` if the full spec is inconsistent. - **Output format.** Current targets are DOT and AIGER. Translating AIGER to Stateflow is the next planned extension (see parent `CLAUDE.md` — this is flagged as the known pain point in the thesis workflow). ## Conventions in this subtree - Scripts are self-contained and take explicit I/O paths as args — no global config file, no env vars. - Generated artifacts live in `circuits/`, `diagrams/`, and `specs/`. Treat them as derived; regenerate rather than hand-edit. - `pwr_hybrid_3.json` is the source of truth. Never hand-edit the generated `synthesis_config_v3.json`.