Self-healing autopoietic shell: f(), tests, docs, interactive demo, fx fix-source layer
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# Design notes
|
||||
|
||||
## The mechanism
|
||||
|
||||
`f()` wraps a command in a loop with one job: don't fail the same way twice.
|
||||
|
||||
1. Look up whether this exact command line has a known fix, keyed by the
|
||||
literal string of the command and its arguments.
|
||||
2. If it does, `eval` the fix first (a precondition — create a file, export
|
||||
a variable, start a dependency, whatever the fix needs to do), then run
|
||||
the command itself.
|
||||
3. If the command still fails, prompt for a fix, log `command=fix` to `p`,
|
||||
apply it, and retry.
|
||||
4. Repeat until the command succeeds or the user gives up (blank input).
|
||||
|
||||
The state file `p` is the entire "memory" of the system. It's line-oriented,
|
||||
grep-able, diffable, and mergeable — ordinary Unix text, not a database.
|
||||
|
||||
## Why "autopoietic"
|
||||
|
||||
Maturana and Varela coined *autopoiesis* to describe systems that continuously
|
||||
produce the components that make up the system itself — a living cell doesn't
|
||||
consult an external blueprint; the process of metabolizing *is* the process
|
||||
that rebuilds the cell's own boundary and machinery.
|
||||
|
||||
`f()` is a deliberately tiny analogy: the artifact it produces (`p`) is fed
|
||||
back into how the function behaves on its next invocation. There's no
|
||||
separation between "the program" and "the program's own history of repairs" —
|
||||
the history *is* part of the program's behavior from that point on. It's a
|
||||
toy, not a claim that a shell function is alive — but the self-referential
|
||||
loop (behavior → artifact → behavior) is the same shape.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **Fixes are preconditions, not replacements.** `f cmd` always re-runs
|
||||
`cmd` verbatim; the learned fix only gets to run *before* it. If the
|
||||
actual problem is that `cmd` itself was wrong (a typo, wrong flag), no
|
||||
precondition can save it — you'd loop forever re-typing the same fix.
|
||||
This is intentional: you're teaching the environment to accommodate the
|
||||
command, not rewriting the command.
|
||||
- **Keying is exact-string.** `f ls foo` and `f ls foo` (two spaces) are
|
||||
different keys. There's no fuzzy matching or parameterization.
|
||||
- **No expiry or invalidation.** A fix that made sense once (e.g. "install
|
||||
a package that existed at the time") can go stale, and `f` has no way to
|
||||
know that. `p` is meant to be reviewed and edited by hand like any other
|
||||
config file.
|
||||
- **Shared `p` across unrelated commands is a security surface.** Anyone who
|
||||
can write to `p` can get arbitrary code `eval`'d the next time a matching
|
||||
command runs. Treat `p` with the same trust level as a shell rc file —
|
||||
don't pull one from an untrusted source and source it blind.
|
||||
- **The 41-byte original recurses instead of looping**, and re-reads no
|
||||
per-command key — it only remembers the *last* fix, for whatever command
|
||||
most recently failed. `src/f.sh` fixes both, at the cost of a few more
|
||||
lines.
|
||||
|
||||
## Where this is used
|
||||
|
||||
The hardened version boots inside AdaptiveOS — a minimal Alpine-based live
|
||||
ISO that drops you into a shell with `f()` and its `p` file living on a
|
||||
tmpfs workspace, so the loop can learn and forget freely within a session.
|
||||
Reference in New Issue
Block a user