docs(memory): name the fleet's characteristic failure mode
svos-dev observed that three instances of the same shape turned up between two agents in one night and that it is starting to look like a characteristic failure rather than a coincidence. Collecting all nine from today, because the class is more useful than any instance. The shape is a check that reads the input to a transformation and gets reported as if it read the output - or more generally, the instrument answering instead of the system, in a form shaped exactly like a real answer. What makes it expensive is not that things break but that the broken state is indistinguishable from a legitimate one, so it passes review and is found later by accident. Every one of the nine passed a check. The tell is stated so it can be recognised prospectively: whenever 'broken' and 'legitimately empty, absent or off' produce the same output, the cheap check cannot tell them apart by construction. Remedies that actually worked today: measure the output rather than the input; positive controls, since a method that has only ever passed cannot tell you it is not blind; true-negative controls, because two apparent failures in the secrets-broker test were names I had invented and would have been read as a partial fix; refuse to emit the ambiguous value, which was the real fix rather than the lock; and do not declare victory on a plausible fix, which is the only reason the session-establishment root cause was found at all.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# ⭐⭐ The fleet's characteristic failure: a confident answer from a broken instrument
|
||||
|
||||
Named by svos-dev 2026-09-15 after three instances turned up between two agents in one
|
||||
night. Collecting them here because the *class* is more useful than any instance, and
|
||||
because every one of them **passed a check**.
|
||||
|
||||
## The shape
|
||||
|
||||
> **A check that reads the INPUT to a transformation, reported as if it read the OUTPUT.**
|
||||
>
|
||||
> Or, more generally: the instrument answers instead of the system, and its answer is
|
||||
> shaped exactly like a real one — no error, no timeout, usually exit 0.
|
||||
|
||||
What makes this class expensive is not that things break. It is that **the broken state
|
||||
is indistinguishable from a legitimate one**, so it survives review, passes CI, and is
|
||||
found later by accident.
|
||||
|
||||
## The instances, 2026-09-15 alone
|
||||
|
||||
| # | instrument said | reality | why it passed |
|
||||
|---|---|---|---|
|
||||
| 1 | `provider=cuda` in the log | ORT had silently fallen back to **CPU** | the line echoes the *configured* env var, never the running EP |
|
||||
| 2 | `node --check` green, `import app` green | the served page's **entire inline script was dead** | a JS `'didn\'t'` inside a Python string arrives as `'didn't'`; the FILE still holds the backslash |
|
||||
| 3 | `secret get` → `""`, **exit 0** | a failed vault read | callers read an empty *optional* secret as "not configured" |
|
||||
| 4 | `find()` → **"not found: <name>"** | a failed listing (`json.loads(stdout or "[]")`) | an empty stdout became a confident, authoritative negative |
|
||||
| 5 | `/v1/toolsets` → **0 toolsets** | my credential lookup returned empty → 401 | an auth failure renders identically to an empty roster |
|
||||
| 6 | `hermes plugins compat <typo'd path>` → **✓ exit 0** | nothing was scanned | "no hits" and "no files" are the same result |
|
||||
| 7 | `hermes plugins doctor` → **exit 0** | it had printed `ERROR` | needs `--ci` to exit non-zero |
|
||||
| 8 | `ss -ltnp \| grep python` → nothing | the listener was there, named **`hermes`** | the filter narrowed the window without announcing it |
|
||||
| 9 | SIGTERM → **port free** | process alive another **35 s** | a script waiting on the port starts a second copy |
|
||||
|
||||
Prior art already in memory, same class: `pct snapshot` exiting 0 while refusing;
|
||||
"an unreachable post office is an OUTAGE, never an empty inbox"; `docker logs --since`
|
||||
returning 0 for a line that exists.
|
||||
|
||||
## The tell
|
||||
|
||||
⚠ **Whenever "broken" and "legitimately empty / absent / off" produce the same output,
|
||||
you have one of these** — and the cheap check will not tell them apart, by construction.
|
||||
|
||||
## What actually works
|
||||
|
||||
1. **Measure the OUTPUT, not the input.** Not `provider=cuda` in a log — a process
|
||||
holding memory on the pinned card. Not `node --check` on the file — parse the page
|
||||
**as served**.
|
||||
2. **Positive control, every time.** Run something the method *must* detect. #6 was
|
||||
caught by scanning a plugin with a known-deprecated import; the clean result only
|
||||
became meaningful once the instrument had proven it could fail.
|
||||
3. **Negative control too** — ⚠ but check the negative is a *true* negative. Two
|
||||
"failures" in the secrets-broker test were **names I had invented**; without checking,
|
||||
I would have read two true negatives as a partial fix and kept digging at a bug that
|
||||
was already gone.
|
||||
4. **Refuse to emit the ambiguous value.** The real fix for #3 and #4 was not the lock —
|
||||
it was making an empty result a loud non-zero instead of a plausible answer.
|
||||
5. ⭐ **Don't declare victory on a plausible fix.** A lock is such an obvious answer to a
|
||||
race that "I added a lock" reads as done. The first lock was in the wrong place and
|
||||
still failed; the root cause (concurrent `bw unlock` at *session establishment*) only
|
||||
surfaced because the plausible fix was tested and did not work.
|
||||
|
||||
## ⚠ And the instrument itself can be stale
|
||||
|
||||
`~/.local/bin/secret` was a **plain copy** of the repo file, in sync by luck. Every repo
|
||||
edit silently left the live tool behind, so the first "fixed" test ran the OLD code.
|
||||
Caught it; the next person could read stale output as proof a correct fix failed and
|
||||
revert it. Now a symlink. **Check what you are running, not what you edited.**
|
||||
|
||||
## Related
|
||||
|
||||
`2026-09-15-talk-v10-deploy.md` (#2, and the gate built for it),
|
||||
`2026-09-15-parakeet-stt-fv-ml1.md` (#1),
|
||||
`2026-09-15-svos-miranda-plugin-validation.md` (#6, #7, #8),
|
||||
`2026-09-15-irv-ml1-address-sweep-done.md` (the ana-docker/litellm neighbour trap).
|
||||
@@ -177,6 +177,10 @@ hardened for ha-dev (`d1769ed` ff); `kb` KB-search tool (`68fa80f`).
|
||||
|
||||
- `[2026-09-15]` **Parakeet STT live on fv-ml1 GPU 0, behind LiteLLM `ext-stt` / `whisper-1`.** ⚠ **Placed on GPU 3 first, which was wrong — operator caught it.** A ~800 MiB seat should ride the card with the most uncommitted headroom (GPU 0, util 0.88, ~13 GB spare), not put the first fingerprint on the one pristine 96 GB card: vLLM sizes KV cache against TOTAL VRAM, so any tenant on an empty card eats a future full-size seat's profiling margin (flash-next needs 93 of 96 GiB). **GPU 3 is now a deliberate reserve at 2 MiB.** Retargeted the existing `stacks/parakeet/` (sherpa-onnx + our own FastAPI wrapper) from irv-ml1; v3 int8, 25 languages. ⚠ **ORT's CUDA EP compiles kernels lazily and the first decode on sm_120 took 45.7 s** — every later call ~0.5 s; a startup warmup in `app.py` now absorbs it, so the first real request is 0.65 s instead of a 45 s hang that no client would wait through. GPU use was **verified by a process on GPU 3 (922 MiB), not by the `provider=cuda` log line**, because ORT falls back to CPU silently and still returns correct text. Silence → `""` (null control), known sentence → near-exact (positive control). → `persistent-memory.d/2026-09-15-parakeet-stt-fv-ml1.md`
|
||||
|
||||
- `[2026-09-15]` ⭐⭐⭐ **THE FLEET'S CHARACTERISTIC FAILURE, named: a confident answer from a broken instrument.** Nine instances in one night, every one of which PASSED A CHECK — `provider=cuda` while ORT ran on CPU; `node --check` green on a file whose SERVED script was dead; `secret get` returning `""` with exit 0; `find()` turning a failed listing into an authoritative "not found"; a 401 rendering as "0 toolsets"; `compat` ✓ on a typo'd path; `doctor` exit 0 on ERROR; `ss | grep python` missing a listener named `hermes`; SIGTERM freeing a port 35 s before the process died. ⚠ **The tell: whenever "broken" and "legitimately empty/absent/off" produce the same output.** Remedies: measure the output not the input, positive AND true-negative controls, refuse to emit the ambiguous value, and never declare victory on a plausible fix. → `persistent-memory.d/2026-09-15-silent-wrong-answer-pattern.md`
|
||||
|
||||
- `[2026-09-15]` **`secret get` returned EMPTY with exit 0 under concurrency** (svos-dev found it; 0/4 succeeded here). Root cause is `bw unlock` racing at **session establishment**, not item reads — so a lock inside the read wrapper cannot work. Fixed: command-level lock, `cmd_get` refuses an empty value, and `find()` no longer coerces empty stdout to `[]`. ⚠ `~/.local/bin/secret` was a plain COPY — now a symlink. `0193b31`.
|
||||
|
||||
- `[2026-09-15]` ⭐⭐ **A check that reads an artifact AS STORED cannot see a transformation between storage and execution** — named twice in one night and it generalises. `node --check` on a source file passes while the SERVED page's inline script is dead (a JS `'didn\'t'` inside a Python string arrives as `'didn't'` and closes it); `provider=cuda` in a log echoes configured intent while ORT silently ran on CPU. Both check the INPUT to a transformation and get reported as checks of its OUTPUT. Remedy: gate the wire, not the file — `tts-stack tools/gate_served_page.py`. ⚠ My first version had a gap tts-dev closed: **a worklet inside a template literal is just a string to a parse of the enclosing script**, so its syntax error surfaces as a rejected `addModule` promise and *silent degradation*. I checked the instance, not the class. → `persistent-memory.d/2026-09-15-talk-v10-deploy.md`
|
||||
|
||||
- `[2026-09-15]` **talk v10 LIVE on nh3-dev :8092 — the fleet speaks and listens on one page.** First consumer of the `ext-stt` Parakeet seat: `POST /api/listen`, push-to-talk, barge-in. Gated build→throwaway→teardown→cutover, then **re-gated against production** (a gate that only ran against the throwaway proves the image, not the deployment). ⚠ Deploys route through infra-ops only because tts-dev's identity is not in nh3-dev's `docker` group — a permissions accident, not a judgement call; group-vs-relay is in front of the operator.
|
||||
|
||||
Reference in New Issue
Block a user