# 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_<group>` with values `q_<value>`.
  Decomposed to `in_<group_suffix>_<value_suffix>`.
- 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`.
