Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ go 1.26
use (
./labs/12-product-engineering-loop/product-engineering-loop
./labs/15-pitot/pitot
./labs/18-settle/settle
)
80 changes: 80 additions & 0 deletions labs/18-settle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Lab 18 — `settle`

> A zero-inference, partial-observation supervisory controller that wraps any
> agent's command execution, detects non-progress with cheap deterministic
> sensors, and intervenes with confidence-proportional, nonblocking force. Net
> effect on task success is measured per model — not claimed.

`settle` watches the stream of `(command → outcome → workspace-state)` an agent
produces and, when its sensors agree the loop has stopped making *observable*
progress, injects a control signal whose force scales with its confidence. It
runs **no model inference**: all detection is hashing, counting, diffing, and
regex on the CPU.

It is the same Ramadge–Wonham supervisory-control theory the repo-root
[`supervisory-control.md`](../../supervisory-control.md) states for Boatstack —
but operating in the regime Boatstack avoids by construction, where the
specification is **unobservable**. That single fact explains everything that
makes `settle` different: why it has an irreducible false-positive rate, why it
uses minimum force, and why it fails *open* where Boatstack fails closed.

## Surface

A standalone, compiled Go binary. Isolated — no runtime dependency on Pitot or
Harbor (it is designed to emit Pitot events later, but stands alone today).

```
settle exec -- <command> [args...] # supervise one command (the atomic unit)
settle run -- <agent> [args...] # wrap an agent; its shell routes through settle exec
settle doctor # self-check
```

The reliable, universal integration is to wire `settle exec` as the harness's
command prefix (or PreToolUse hook). `settle run` is a zero-config convenience
wrapper that installs a shell shim so an agent honouring `$SHELL` is supervised
without any changes to its internals.

## Documentation index

- [`docs/01-theory.md`](docs/01-theory.md) — the control-theory frame: an
approximate belief-state supervisor for an unobservable spec; why the
false-positive rate is a theorem, not a defect; fail-open vs. fail-closed.
- [`docs/02-detection.md`](docs/02-detection.md) — the recurrent-class detector
and how it subsumes all five sensors; the canonicalization contract; the
belief function.
- [`docs/03-intervention.md`](docs/03-intervention.md) — the minimum-force
ladder; the nonblocking and fail-open invariants; the deny-with-recovery
contract.
- [`docs/04-calibration-and-experiment.md`](docs/04-calibration-and-experiment.md)
— deriving the point-of-no-return from real traces; the pre-registered paired
experiment; claim-tier discipline.

## Module layout

```
settle/ Go module: github.com/operatorstack/settle
detector/ pure, deterministic classifier core (no I/O, no os/exec)
exec/ thin host wrapper: runs a command, hashes workspace state
cmd/settle/ the binary
scripts/
calibrate.py mine trajectories -> Recovery Probability Curve -> k
check_import_boundary.sh detector/ must never import exec/
calibration.json the derived point-of-no-return + full curve (transparency)
docs/ theory, detection, intervention, calibration
```

**Relationship to lab 17 (`f-prime-governor`).** `settle` is a new architecture,
not lab 17 shipped. It keeps lab 17's defensible ideas (the EV inequality,
minimum-force under partial observability, weak-sensor agreement) and drops the
`F' = p(1−p)` framing, which was decorative — it is only Bernoulli variance, was
computed offline only, and the live governor actually fired on a hardcoded
"last 3 failed". `settle` also fixes lab 17's `swe_breaker.py exit(1)` hard-block,
which violated the house **nonblocking** invariant. The semantic-signature and
command-normalization logic is ported into a single Go source of truth
(`detector/signature.go`).

## Status

Detection firing correctly on the golden fixtures is **Observed**. Net effect on
task success is **Being-evaluated** until the pre-registered paired run
(docs/04). No invented numbers; no cross-model uplift claims.
129 changes: 129 additions & 0 deletions labs/18-settle/calibration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
"point_of_no_return": 5,
"adopted": "fallback",
"derived_k": 2,
"derived_support": 44,
"fallback_k": 5,
"recovery_floor": 0.15,
"min_support": 20,
"strong_support": 200,
"trajectory_files": 1890,
"curve": [
{
"k": 1,
"reached": 7170,
"recovered": 8,
"p_recovery": 0.0011
},
{
"k": 2,
"reached": 44,
"recovered": 3,
"p_recovery": 0.0682
},
{
"k": 3,
"reached": 12,
"recovered": 2,
"p_recovery": 0.1667
},
{
"k": 4,
"reached": 5,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 5,
"reached": 2,
"recovered": 1,
"p_recovery": 0.5
},
{
"k": 6,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 7,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 8,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 9,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 10,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 11,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 12,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 13,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 14,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 15,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 16,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 17,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 18,
"reached": 1,
"recovered": 0,
"p_recovery": 0.0
},
{
"k": 19,
"reached": 1,
"recovered": 1,
"p_recovery": 1.0
}
],
"reason": "Data hints k=2, but on thin support (44 sequences, need >=200). Real traces rarely contain byte-identical repeated failing commands, so genuine saturated-failure loops are scarce here. Shipping the conservative fallback (5); the redirect rung already covers k=2..4 non-destructively. Being-evaluated pending richer trace data.",
"claim_tier": "Observed (calibration from Harbor traces); not a universal constant."
}
113 changes: 113 additions & 0 deletions labs/18-settle/docs/01-theory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# 01 — Theory: an approximate supervisor for an unobservable spec

`settle` is a supervisory controller in the sense of Ramadge & Wonham (1987).
The canonical statement of that framework for this system is the repo-root
[`supervisory-control.md`](../../../supervisory-control.md); this document places
`settle` inside it. Read that doc first — the objects (`Σ`, `Σ_c/Σ_u`,
`Σ_o/Σ_uo`, `P`, `L_m(G)`, controllability, observability, nonblocking) are used
here without redefinition.

## 1. The one idea

> Boatstack's specification is co-designed to be **observable**, so an exact
> supervisor exists and it has **no** false-positive rate. `settle`'s
> specification is **unobservable**, so by the Existence theorem no exact
> supervisor exists; `settle` runs an **approximate belief-state supervisor** and
> pays for the unobservability with an irreducible false-positive rate.

Everything else in `settle` is a consequence of that sentence.

## 2. The objects, instantiated

- **Plant `G`.** The agent plus its host, generating a stream of events. The
slice `settle` cares about is the command-execution loop.
- **Controllable event.** *Execute the next command.* This is the one event
`settle` can disable — exactly the `Σ_c` events the host presents synchronously
for permission. `settle` may withhold permission for it; it can never force the
agent to think differently (that is `Σ_u`, uncontrollable).
- **Observation projection `P`.** `settle` never sees the agent's intent or its
true progress. It sees a lossy projection: a normalized command, a semantic
error signature, and a workspace state-hash (`detector.Observation`). This is
`P(s)`, and it is deliberately coarse.
- **Marked language `L_m(G)`.** Command outcomes that represent success
(exit 0 / tests passing). A marked symbol is the only positive evidence
`settle` can observe.
- **Specification `K`.** "Do not remain in a non-progressing cycle" — i.e., do
not dwell in a set of observed states that contains no marked symbol and that
the trajectory does not leave.

## 3. Why the spec is unobservable (and why that is the whole point)

The house doc's observability condition (its §2) requires that any two histories
with the same projection demand the same control decision. `settle`'s spec fails
this:

> A genuinely stuck loop and a slow-but-progressing effort can produce the **same
> projection** `P(s)` — identical repeated error text, while the real, unobserved
> state differs (the agent is narrowing a search, warming a cache, making
> progress the sensors cannot see).

Two histories, same projection, opposite correct decisions (deny vs. allow). By
the Existence theorem, **no supervisor achieving exactly `K` exists.** This is not
a limitation to apologize for — it is the theorem that *predicts* the
false-positive rate. `settle` therefore does not compute membership in `K`; it
maintains a **belief** `b ≈ P(stuck | P(s))` and acts on it. See
[02-detection.md](02-detection.md) for how `b` is estimated and
[03-intervention.md](03-intervention.md) for how force is chosen given `b`.

## 4. What survives from the theory, exactly

Three results transfer with full rigor; nothing is borrowed decoratively.

1. **Minimum force = the minimally-restrictive supervisor.** The house doc's
`supC(K)` (disable the minimum necessary) is, verbatim, "minimum-force
intervention." Two independent arguments — the economic `EV > 0` inequality
and the control-theoretic minimally-restrictive supervisor — land on the same
control law. That convergence is the justification.

2. **Nonblocking is a hard invariant.** The house doc requires a blocked state be
blocked *toward* a recovery path, never absorbing. Therefore `settle` may never
disable *every* controllable event: even its highest-confidence deny withholds
one futile command and leaves read-only inspection open. (Lab 17's
`swe_breaker.py exit(1)` violated this.)

3. **Fail-open, inverting Boatstack's fail-closed.** The house doc's fail-closed
corollary — under observation loss, disable all controllable events
(`γ = Σ_u`) — is the unique safe pattern *for a safety spec*, where the cost of
allowing a bad event is unbounded. `settle` is an **optimizer**, not a safety
gate: the cost of *wrongly blocking* a healthy agent is the expensive error,
and the benefit it protects (saved steps) is bounded. So under uncertainty or
sensor loss, `settle` **allows**. This is why `exec.WorkspaceState` returning
"unmeasurable" degrades to allow, never to deny.

## 5. The EV frame (the economic half of §4.1)

An intervention's expected value:

```
EV = P(stuck | signals) · (steps saved by breaking the loop)
− P(not stuck | signals) · (cost of interrupting a good trajectory)
```

Inference cost is ~0, so attempting an intervention is nearly free. There are
exactly two levers, and they are the entire design space:

1. **Raise `P(stuck | signals)`** — more accurate, agreeing sensors.
2. **Lower the cost-when-wrong** — a gentler, reversible intervention.

The governing corollary: **intervention design matters more than detection
accuracy.** A reversible nudge at a 30% false-positive rate is net-positive; a
destructive revert at the same rate is net-negative. That is why the intervention
ladder is designed before the detector is tuned.

## 6. What `settle` explicitly is not

- It does **not** judge correctness. "Is this the right fix" is not in the
observable alphabet; deciding it needs the model or a real verifier. Claiming a
$0 controller judges correctness is the trap `settle` refuses.
- It does **not** act while the trajectory is still emitting *new* observations —
a moving loop is exploring, not stuck. (This replaces lab 17's "F′ is high /
sensitive region" with a directly measurable condition: not yet absorbed into a
recurrent class.)
- It does **not** eliminate false positives. The Existence theorem forbids it. It
makes them cheap.
Loading