From 62b3b92e696b9839b3f176fe661748a4e2219279 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 19 Oct 2026 11:18:41 -0700 Subject: [PATCH] live: heartbeat sync 2026-10-19T11:18:41-07:00 (Refs #11) --- .../docs-point-of-use-destruction/SKILL.md | 70 +++++++++++++++++++ .../omp-extension-stale-module-audit/SKILL.md | 29 ++++++++ .../red-verify-without-stash/SKILL.md | 29 ++++++++ .../vault-one-fact-one-owner-dedupe/SKILL.md | 47 +++++++++++-- .../sharpshooter/tmp-1tpw73408x3e/state.json | 2 +- .../state.json | 4 +- .../state.json | 6 +- .../state.json | 6 +- .../.local/state/noctalia/settings.toml | 8 +-- 9 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 agent/managed-skills/docs-point-of-use-destruction/SKILL.md create mode 100644 agent/managed-skills/omp-extension-stale-module-audit/SKILL.md create mode 100644 agent/managed-skills/red-verify-without-stash/SKILL.md diff --git a/agent/managed-skills/docs-point-of-use-destruction/SKILL.md b/agent/managed-skills/docs-point-of-use-destruction/SKILL.md new file mode 100644 index 0000000..346eb63 --- /dev/null +++ b/agent/managed-skills/docs-point-of-use-destruction/SKILL.md @@ -0,0 +1,70 @@ +--- +name: docs-point-of-use-destruction +description: "Documentation exists for point of use, not archival. Use before any dedupe/compact/verify-docs job, and whenever a census or \"only copy\" argument is being used to KEEP documentation: apply the purpose test and destroy obsolete measurements. Supersedes the preservation conclusions of vault-one-fact-one-owner-dedupe §3/§12." +--- + +# Documentation exists for point of use + +**Supersedes** `vault-one-fact-one-owner-dedupe` §3 ("port before cut") and §12 +("expect docs flat") wherever those conclude a page must be *kept*. Sole custody of a +useless fact is still useless. + +## The test, before you write and again before you keep + +- Would the reader, doing a real task tomorrow, **act differently** because of this + line? No → delete it. +- Is it a measured rate (t/s, tok/s, ms, MiB-of-pool, acceptance %, a bench ladder) for + a model / runtime / layout that is **not running now and not being compared now**? + Destroy it. Not "file it in an Eras row", not "preserve it for history". AI moves + faster than the vault: the number is wrong before anyone reads it, and a wrong number + in a runbook gets believed. +- Keep the **law** the measurement taught; drop the measurement. Qualitative causal + stories survive; numbers do not. +- What survives: live config and its exact numbers, procedures, failure signatures, + security posture, interface contracts, rollback pointers. +- **Losing information is an acceptable, usually correct outcome.** Frank said so + explicitly on 2026-10-19 after rejecting a PR that had preserved 53 ledgers. + +## Traps that lead agents to preserve junk + +- **A census cannot decide what to keep.** `port-census.py`-style tools answer "where + does this fact live", never "does anyone need it". "14–63 sole-record lines per page" + was read as *irreplaceable* when the fact was *obsolete*. Ask usefulness, not custody. +- **A census that includes the file under test proves the page is held by itself.** + Exclude it, print the corpus size, assert absence; treat `0 unheld` on a long page as + a tool bug until proven otherwise. +- **"One fact, one owner" is a placement rule, not a preservation rule.** It says where + a surviving fact lives; it never says the fact must survive. +- **A change diary (`log.md`) is the largest archive in most vaults** (this one: 2,380 + lines, ~8 % of the vault). Git holds the chronology; a causal law belongs on the page + that owns the thing it governs. Retire the diary. + +## Execution that worked (2026-10-19, −13.7k lines) + +1. Write the kill list as a reviewed artifact, one path per line, grouped by *why it is + dead* — that list becomes the PR's argument and the trash manifest. +2. Destroy whole pages first (`scripts/destroy-vault.py `): move to + `.AGENTTRASH/-destruction/`, then delete every reference from survivors, whole + line included when the dead link was its only content. Do not compare link targets + with `pathlib.Path.stem` — it strips real suffixes (`sd.cpp`). +3. Then strip numbers from what remains (`scripts/axe-measurements.py`): delete ledger + sections (noun-LEDS the heading, nothing instructional after it), blank any table cell + reporting a rate, fold Eras older than the current one into a single row pointing at + git. Never touch a shape number or a Laws/Wire/Rollback section. +4. Sweep indices (generator must exclude the trash dir, drop rows whose page cell became + empty), re-lint, re-check links. +5. Rewrite the governing policy in the same PR, or the next agent re-grows the vault: + project `AGENTS.md` *Documentation Policy* + the global agent settings. + +## Report honestly, per area + +docs / scripts / operator-doc separately, measured against the merge-base. The tools are +a cost that must be named, not hidden inside a headline "net" number — that is what got +the previous pass rejected. + +## Verify the repair tools themselves + +One repair pass matched "line ends with a comma" and deleted the trailing comma from 660 +wrapped prose lines. Restore by matching lines that are byte-identical to `HEAD` except +for trailing punctuation (`restore-punctuation.py`), keep the destructive rule out of the +tool, and record the incident in its docstring. diff --git a/agent/managed-skills/omp-extension-stale-module-audit/SKILL.md b/agent/managed-skills/omp-extension-stale-module-audit/SKILL.md new file mode 100644 index 0000000..277b75f --- /dev/null +++ b/agent/managed-skills/omp-extension-stale-module-audit/SKILL.md @@ -0,0 +1,29 @@ +--- +name: omp-extension-stale-module-audit +description: "Diagnose recurring omp extension handler timeouts/silence when the on-disk fix is already deployed: harness has no extension hot-reload, so running sessions freeze the module at session start (zombie modules)." +--- + +Use when a fix for an omp extension is merged/deployed yet the SAME errors persist ("handler timed out after 30000ms", silence, wrong behavior) in running sessions. + +**Core fact:** the harness loads extension `.ts` modules at session start and never reloads them (no `/reload` for extensions; bundle `reload` hits are LSP/MCP/browser only). A session older than the fix keeps executing stale code regardless of the file on disk. + +**Procedure:** +1. Census the errors from logs, not guesses — timeout lines carry the culprit pids: + `grep -h "handler timed out" ~/.omp/logs/omp.*.log | python3 -c 'import sys,json; rows=[json.loads(l) for l in sys.stdin]; rows.sort(key=lambda r:r["timestamp"]); [print(r["timestamp"], r["event"], r["pid"]) for r in rows]'` + (`~/.omp/logs/omp...log` — the pid in the filename is the session.) +2. Session start times vs deployed file versions: + `ps -eo pid,lstart,args | grep '[o]mp'` + `git log --format='%h %ad %s' --date=format:'%m-%d %H:%M' -- ` + `git reflog --format='%gd %ad %gs' --date=format:'%m-%d %H:%M' | grep merge` (live-sync pull times = when the file content changed). + Any session whose start time precedes the fix's arrival has the stale module. +3. Confirm the stale revision actually contains the bad pattern — read what that session loaded, not HEAD: + `git show : | grep -n 'await speak\|async (event'` + (e.g. an `async agent_end` awaiting a >30 s chain is exactly what the harness's per-handler `Kzc` 30 s race logs; fire-and-forget `void` is fine — detached promises are NOT tracked by the dispatch window.) +4. Optional empirical proof when static analysis says "impossible": probe extensions through the real harness: + `omp -p --no-extensions -e /tmp/probe.ts "Reply OK"` with a probe that logs handler start/return and `void`s a 40 s detached promise + spawns a long child. Fast exit + no timeout log ⇒ detachment is untracked ⇒ blame stale modules, not the harness. +5. Remediation: restart the affected sessions (kill the listed pids or their terminals — the operator session itself may be one of the zombies; say so explicitly). There is no other fix. + +**Gotchas:** +- Per-handler attribution in the log is accurate per dispatch; don't blame other extensions before checking the pid's start time. +- Endpoints healthy + silence persisting usually means TWO stacked bugs (e.g. stale awaiting module in old sessions AND a mute bug in current code) — diagnose each pid cohort separately. +- Extension chain code must use self-owned `AbortSignal.timeout(...)`, never a ctx-scoped signal: harness dispatch signals die when the dispatch window closes. diff --git a/agent/managed-skills/red-verify-without-stash/SKILL.md b/agent/managed-skills/red-verify-without-stash/SKILL.md new file mode 100644 index 0000000..178b78e --- /dev/null +++ b/agent/managed-skills/red-verify-without-stash/SKILL.md @@ -0,0 +1,29 @@ +--- +name: red-verify-without-stash +description: "Prove a regression test is red-capable against pre-fix code in a shared worktree where git stash/checkout are policy-blocked, via git-show blob swap with md5-verified restore." +--- + +# Red-verifying tests without `git stash` + +## When +You fixed a file and added tests that should have failed before the fix, but workspace policy blocks `git stash` (and `git checkout -- file`) in shared worktrees (e.g. `~/.omp` shared-workspace policy). Needed to prove red-capture instead of asserting it. + +## Recipe +One `bash` call — swap the fixed file for the HEAD (pre-fix) blob, run only the fix-relevant tests, restore, verify byte-identity: + +```bash +cd "$WT" +md5sum path/to/fixed.file > /tmp/file-hash +cp path/to/fixed.file /tmp/fixed.file.bak +git show HEAD:path/to/fixed.file > path/to/fixed.file # pre-fix content; new tests now exercise old code +bats -f "test name A|test name B" tests/suite.bats # expect: not ok for every fix-relevant test +cp /tmp/fixed.file.bak path/to/fixed.file +md5sum -c /tmp/file-hash && echo RESTORED +``` + +## Notes +- `git show HEAD:path > path` truncates-and-refills the file in place; safe because you hold the md5 and a backup copy, and the restore check proves the fixed bytes are back. +- Run only the fix-relevant tests via the runner's name filter (`bats -f` regex); a full suite wastes time and old tests pass on both versions. +- Expect exactly the tests that pin the fix's behavior to fail pre-fix; tests unrelated to the change (pure coverage of old behavior) pass on both versions — don't count them as red evidence. +- `bats` pipelines mask exit codes without `pipefail`; judge by the `ok`/`not ok` lines, not the shell status. +- For non-test proof of endpoint behavior (live A/B of an HTTP request body), replay the exact body with `curl` against the live endpoint instead of speculating; keep both timings. diff --git a/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md index ce57051..989646b 100644 --- a/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md +++ b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md @@ -1,6 +1,6 @@ --- name: vault-one-fact-one-owner-dedupe -description: "\"Collapse per-payload/per-attempt vault pages into one owner page per endpoint without losing a fact: port-before-cut orphan census, doubled-page repair, trash-aware tools, delegated-write verification, index regeneration, and the merge-resolution order.\"" +description: "\"Collapse per-payload/per-attempt vault pages into one owner page per endpoint without losing a fact: port-before-cut orphan census (corpus must exclude the file under test), doubled-page repair, trash-aware tools, delegated-write verification, honest per-area line accounting, index regeneration, and the merge-resolution order.\"" --- # One fact, one owner: dedupe the vault without losing a fact @@ -37,12 +37,19 @@ file being rewritten. Any line with **no** surviving key is an orphan → port, deliberately and say so. Use `scripts/port-census.py ` (numbers with ≥ 4 int digits, decimals, flags, paths, backticked spans, `--`, ALL-CAPS, or ≥ 2 hyphens). -Two calibration traps: +Three calibration traps: - **Prose words are not facts.** A hyphen or trailing period inside a word (`long-standing`, `deployed:`) was counted as a tracked token while real identifiers hid behind it; that noise buried 300 real lines under 979 fake ones. Strip punctuation, require fact shape. - **The corpus decides the question.** Corpus = the new file only → "what did this rewrite drop?" Corpus = whole vault → "is the dropped fact orphaned repo-wide?" Ask one at a time. +- **The corpus MUST exclude the file under test, and you must assert it.** A census pointed at + the directory that *contains* the page proves the page is held by itself: ten era pages + reported `0 sole-record lines`, which reads as "pure duplication, trash it". With the file + excluded, the same pages held **14–63 sole-record lines each** — campaign ledgers that exist + nowhere else. A tool's own docstring promise ("excluding it") is not a check: print the + corpus size, assert the target is absent, and treat `0 unheld` on a long page as a tool bug + until proven otherwise. A mechanical census is a scout: its verdict is a lead, not a finding. Also grep `AGENTS.md` separately — a fact it carries is not an orphan. @@ -52,7 +59,7 @@ Signature: a page whose `wc -l` is ~2× its `HEAD` size, with a **second frontma the body** whose closing `---` is glued onto the end of a body/timestamp line. Cause chain: a frontmatter rewrite that re-reads the file it just wrote (so its own output becomes the body), then a fence-repair pass keyed on `line == "---"` that cannot see a glued fence and inserts a -fence mid-page, so the next pass treats the tail as a new document. +fence mid-page, so the next page-tail becomes a new document. Un-double rule that worked: find the first frontmatter's close (accepting a glued fence), then the first `type:` line after it that has more keys (`title|description|tags|timestamp`) behind @@ -82,9 +89,10 @@ grep -rnoE "\((page-a|page-b|...)\.md\)" --include="*.md" serverAppConfigs-docs Both wikilinks and markdown path refs must be repointed (Research `See Also` lists and bench pages are where path refs hide). Then **regenerate** index rows with a script, never by hand. -The generator bug to check for: presence tested as a **bare stem substring** — a page whose -name prefixes another's (`frank-medium` inside `frank-medium-rocmfpx`) then silently never -gets a row. Test the wikilink form `[[]]`. +Generator bugs to check for: presence tested as a **bare stem substring** — a page whose name +prefixes another's (`frank-medium` inside `frank-medium-rocmfpx`) then silently never gets a +row (test the wikilink form `[[]]`); and **no dead-row sweep**, so deleting a page leaves +an index row that fails the link check — the generator must drop rows for absent pages too. ## 7. Enforce the law with a seam @@ -96,6 +104,12 @@ re-created era page then cannot pass tests. For the length hint, prefer **derive owned by the page that measured it) plus one documented per-page opt-out; never let a size ceiling force a ledger to be split across two owners. +Splitting an over-long page to satisfy a ceiling is usually line-NEGATIVE: one measured split +turned a 700-line page into 488 + 306 across five files (+23 for the folder net of stub +deletions), because frontmatter blocks, pointer sections and connective prose are charged per +file while the facts move for free. Roll the split back, carry `okf-exempt: length` with the +reason, and keep the stub pages deleted. + ## 8. Edit-tool hazard (costs the most time) Body rows beginning with `-` or `+` are op markers. The documented `+-` escape **writes a @@ -104,6 +118,10 @@ line untouched and PUT only the indented continuation lines, or convert the note bullet whose body lines start with two/four spaces. If a wrapped `[[Two Word Page]]` shows up as an unresolved link, the target was hard-wrapped across lines — unwrap it. +A `PUT` that spans a multi-line statement can silently drop neighbouring assignments +(auto-repaired boundary echo); after editing a constants block, `grep -n "^[A-Z_]* = "` and +run a syntax probe before executing. + ## 9. Delegated writes: verify bytes, never narrative Measured in one campaign, all four failure modes live: @@ -146,7 +164,24 @@ matter how concrete they read; and re-read the source bullet before trusting a t - Open the PR through the API with a 600-perm curl config (managed skill `gitea-api-pr-operations`), end the body with the `cwd:` / `session:` footer, then `xdg-open ` the instant it exists. Never merge without Frank's current explicit OK. + Push with an explicit refspec (`HEAD:refs/heads/`) — a worktree's own branch name + is not the PR branch, and `git push origin HEAD` opens a stray branch. - Docs-only change ⇒ **no deploy**. Fast-forward the deploy checkout only (`git -C ~/Projects/serverAppConfig merge --ff-only origin/main`). - Say what was NOT done, in the PR body: soft lint tallies left (missing `## Citations`), conflicts left standing, repo config that was never installed on a host. + +## 12. Report line counts per area, never one net + +"Compaction" measured against the merge-base **per area**: docs / `scripts/` / `AGENTS.md`. +A single headline number hides that tooling and prose move in opposite directions — one +campaign reported "−1,849 vault lines" while the vault was flat and the growth was the two +enforcement scripts that made the law mechanical. Expect a mature one-owner vault to land +**docs flat**: the reductions available are deletions of *restatement* (duplicated pages, +transient deploy chatter in `log.md`, `AGENTS.md` bullets whose numbers an endpoint page owns) +and they are roughly cancelled by the cost of the citations the verification pass adds. When +asked to shrink further, show the menu — drop the tools, drop the citations, or accept content +loss — instead of inventing cuts. `log.md` compaction rule that survived census: drop a line +only when it matches a transient shape (`/health`, `deployed`, `restart`, `systemctl start`) +**and** every fact token in it is held by an owner page; a token-held line can still be the +only record of *when* an incident happened. diff --git a/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json b/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json index 0f98aa3..30f8d28 100644 --- a/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json +++ b/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json @@ -1,4 +1,4 @@ { "v": 1, - "lastConsolidatedAt": 1792398289746 + "lastConsolidatedAt": 1792432172049 } diff --git a/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json index 893629c..dbc798d 100644 --- a/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json +++ b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json @@ -1,8 +1,8 @@ { "v": 1, - "lastConsolidatedAt": 1792430072641, + "lastConsolidatedAt": 1792433858713, "lastResult": { - "at": 1792429115686, + "at": 1792433135862, "sessions": 1, "deltas": 1, "model": "frank-zealot" diff --git a/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json b/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json index 5d10fcf..6fbbdc1 100644 --- a/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json +++ b/agent/memories/sharpshooter/wt-20261019-020309-6d1fc1f-8knxmfcrfa1k/state.json @@ -1,10 +1,10 @@ { "v": 1, - "lastConsolidatedAt": 1792430229908, + "lastConsolidatedAt": 1792433709913, "lastResult": { - "at": 1792402864677, + "at": 1792433353188, "sessions": 1, - "deltas": 8, + "deltas": 1, "model": "frank-zealot" } } diff --git a/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json b/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json index a7673c1..2a7f596 100644 --- a/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json +++ b/agent/memories/sharpshooter/wt-20261019-021028-6d1fc1f-3p69q8c3d94kw/state.json @@ -1,10 +1,10 @@ { "v": 1, - "lastConsolidatedAt": 1792430069015, + "lastConsolidatedAt": 1792433789051, "lastResult": { - "at": 1792428814873, + "at": 1792432178813, "sessions": 1, - "deltas": 1, + "deltas": 2, "model": "frank-zealot" } } diff --git a/dotfiles/noctalia/.local/state/noctalia/settings.toml b/dotfiles/noctalia/.local/state/noctalia/settings.toml index 1b0be25..b93317f 100644 --- a/dotfiles/noctalia/.local/state/noctalia/settings.toml +++ b/dotfiles/noctalia/.local/state/noctalia/settings.toml @@ -275,13 +275,13 @@ transition = [ "fade" ] interval_seconds = 1200 [wallpaper.default] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" [wallpaper.last] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" [wallpaper.monitors.DP-1] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" [wallpaper.monitors.DP-2] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_oxex69.jpg" @@ -290,7 +290,7 @@ transition = [ "fade" ] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_v9e2w3.jpg" [wallpaper.monitors.eDP-1] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" [weather] unit = "imperial"