TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.
Install with Tessl CLI
npx tessl i github:santosomar/general-secure-coding-agent-skills --skill tlaplus-guided-code-repair90
Quality
88%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Specialization of → model-guided-code-repair for TLC. The general loop is the same; this skill covers the TLC-specific mechanics: reading error traces, understanding action enablement, and the .cfg levers.
TLC prints the trace as numbered states. Between states, it names which Next disjunct fired:
Error: Invariant Inv is violated.
State 1: <Initial predicate>
pc = [p1 |-> "start", p2 |-> "start"]
lock = "free"
...
State 2: <Read(p1) line 42, col 3 ...>
pc = [p1 |-> "locked", p2 |-> "start"]
...
State 3: <Read(p2) line 42, col 3 ...>
...
State 4: <Write(p1) line 50, col 3 ...> ← invariant fails hereKey TLC-specific info:
Next disjunct.-difftrace).\E p : Foo(p) — TLC tells you which p.In TLA+, every action is guard /\ effect. The guard is the conjunction of all unprimed conjuncts. The culprit's guard was true when it shouldn't have been.
At the culprit step, ask: what unprimed predicate, if added to this action's guard, would have been FALSE in the pre-state? That predicate is your fix candidate.
Extracting the candidate from the pre-state:
Inv is about to be violated?| TLC error | Likely culprit | Typical fix |
|---|---|---|
| Invariant violated | Action that wrote the invariant-breaking value | Add guard preventing that write |
| Deadlock | All actions' guards are false — none can fire | Weaken a guard, or add a recovery action |
| Temporal property violated (liveness) | Missing fairness, or an action that blocks progress | Add WF_vars(Action) or fix the blocker |
Action property [][A]_v violated | Some Next step changed v in a way A forbids | That disjunct needs to respect A |
Deadlock is the opposite of invariant violation. For invariants, guards are too weak. For deadlock, guards are too strong. Don't tighten guards after a deadlock.
TLA+ spec: Two-phase commit coordinator. Invariant: Inv == committed => \A p \in Participants : vote[p] = "yes".
TLC trace:
State 1: <Init>
vote = [p1 |-> "none", p2 |-> "none"]
committed = FALSE
State 2: <Vote(p1) ...>
vote = [p1 |-> "yes", p2 |-> "none"]
State 3: <Commit ...> ← Inv violated: committed=TRUE but vote[p2]="none"
committed = TRUECulprit: Commit at step 2→3. Its pre-state: vote = [p1 |-> "yes", p2 |-> "none"]. Commit fired with p2 un-voted.
Current action:
Commit ==
/\ committed = FALSE
/\ committed' = TRUE
/\ UNCHANGED voteNo check on votes at all. Missing guard: all participants voted yes.
Fix:
Commit ==
/\ committed = FALSE
/\ \A p \in Participants : vote[p] = "yes" \* NEW
/\ committed' = TRUE
/\ UNCHANGED voteRe-run TLC: Inv holds. Deadlock check: Commit is now disabled when p2 votes "no" — is there an Abort action? If not, add one (this is the "add missing action" repair).
Code mapping: Commit ↔ Coordinator.finalize(). The code:
def finalize(self):
if not self.committed:
self.committed = True
self.broadcast("COMMIT")Missing the vote check. Fix:
def finalize(self):
if not self.committed and all(v == "yes" for v in self.votes.values()):
self.committed = True
self.broadcast("COMMIT")Sometimes the model's action was wrong, not the code. Two cases:
Before touching code, verify: does the TLA+ action actually match the code? Go look.
Commit == /\ Inv /\ ... makes Inv vacuously preserved by Commit. That's cheating — and usually causes deadlock.Next for every disjunct that writes the variables in the violated clause.UNCHANGED when adding new variables during repair. Every action must account for every variable.Commit is one TLA+ step but three code statements, the code fix might need a lock.## TLC trace (relevant steps)
State <i>: <vars>
→ <Action(params)> [<file:line>]
State <i+1>: <vars>
## Culprit
Action: <name>
Pre-state: <the vars that mattered>
Missing guard: <predicate>
## TLA+ fix
```tla
<before>
--- becomes ---
<after>Invariant: <pass/fail> Deadlock: <pass/fail> Other properties: <status>
file:function — the TLA+ action's code counterpart Before/after: <diff> Atomicity note: <does the code need additional synchronization to match the TLA+ atomicity?>
47d56bb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.