Files

11 KiB
Raw Permalink Blame History

name, description
name description
docs-dedupe-verify-campaign Run an exhaustive docs dedupe + fact-verification campaign (command-center or any OKF vault, e.g. franksign): scout cluster ledgers, override scouts with evidence, gate every commit, and sweep scaffolding before PR.

Exhaustive docs dedupe + verification campaign (dank/command-center; transplants to any OKF vault — proven on franksign 2026-10-21, #64 2026-10-21)

Frame

  • Read omp-docs/references/okf-spec.md (or the vault's vendored OKF contract, e.g. franksign-docs/read-only/okf-v0.2-spec.md) + root index.md first; inventory with find <vault> -name '*.md' | wc -l.
  • Run scripts/kb-lint.sh omp-docs baseline; index-coverage gate is scripts/kb-coverage.py omp-docs (each dir's index.md must link every sibling file/subdir). On franksign the whole mechanical gate is one seam: bun tests/lib/okf-lint.mjs (frontmatter, links, index coverage, version-once) — run it before and after.
  • Branch off fresh origin/main in a NEW worktree (git -C ~/.omp worktree add ~/.omp/wt/<name> -b docs/<issue>-slug origin/main) — workspace policy blocks git checkout -b in session worktrees. In a session worktree, git checkout -b is intercepted anyway: commit on the session branch, then named-ref push HEAD:refs/heads/docs/<n>-slug (verify git log origin/main..HEAD shows ONLY your commit first).
  • Open the Gitea issue first (multi-moving-parts law); branch name docs/<issue#>-<slug>.

Scout fleet (overlap detection)

  • One task call, tasks[] batch, agent scout, read-only; one cluster per task. Fan out 2-3 clusters at a time, never seven: task.maxConcurrency is 2 on this fleet, so the excess only queues, and proc:// reports queued tasks as running — identical uptimes with zero deliveries means thrash, not progress (#64: seven scouts, nothing in 17 min; killing the five redundant ones let the two survivors land within minutes).
  • Do NOT scout a cluster you have already audited inline. Kill the redundant jobs early with write proc://<id>/kill — the endpoint is the scarce resource, and your own session shares it.
  • Ledger format per cluster: inventory rows (file | verdict KEEP|MERGE|DELETE|VENDOR|UPDATE | evidence line/command). Demand the ledger as the yield TEXT, never a local:// file reference: #64 produced one 0-byte ledger plus three files whose names contained the scout's own serialized parameter block (gitea-caddy-inventory.md + newline + a parameter tag), recoverable only by ls-ing ~/.omp/agent/sessions/<session>/local/<dir>/.
  • Scouts lie. Verified misses in the 2026-10-19 campaign: fabricated ledger entries ("peer-reviewed BrowseComp" claim that exists in no file), a DELETE verdict for a generated artifact that is checked in by design AND under test (tools/niri/keybindings.md, see scripts/gen-keybinds.sh + tests/gen-keybinds.bats), and a KEEP for a leftover the scout misread its own changelog about. Franksign 2026-10-21: 2 of 3 cluster scouts fabricated — "7 missing component stories" refuted by the pairing-law seam that runs green on every push, invented entry/page counts, DELETE verdicts on live-box census numbers the purpose test KEEPS; a third hit the 30-min runtime cap producing zero output. #64 same day: three pages "missing an H1" that have one on their first heading line; a 215-line omp-docs/AGENTS.md that does not exist; a "wikilinks + 700-char wall" defect in core/settings.md that a commit from that same morning had already removed; core/subagent-limits.md called superseded while agent/config.yml carries the cited maxRuntimeMs / softRequestBudget / maxRecursionDepth values verbatim.
  • Four pre-checks before a scout row enters the diff: (1) the file exists; (2) the named heading/marker is actually absent (grep -c '^# ', grep -c '^# Citations'); (3) git log --oneline -3 -- <file> — a same-day commit may already have fixed it; (4) if the claim is "config supersedes the doc", grep the config for the cited keys.
  • Cluster sizing: for a vault under ~20 pages, scout fleets are net-negative — audit inline yourself (reading 5 pages beats babysitting a scout). Reserve scouts for multi-hundred-page trees.

Mechanical sweeps that pay (run on every vault)

  • Empty-text links: grep -rnE '(^|[ ,])\]\(' <vault> — a generated "See Also" pass left five - ](index.md) links (#64); rendered, an empty bullet reads as style, never as a broken reference.
  • Citation convention census BEFORE adding anything: count grep -rl '^resource:' against grep -rl '^# Citations'. command-center's convention is resource: frontmatter (12 vs 3) — "add Citations to six pages" is a convention change, not a fix; only the pages missing resource: were real hits.
  • Long-line walls: awk 'length>300 {print FILENAME":"NR"("length")"}' — reflow prose to ~100 columns, wording intact; leave tables (they cannot wrap) and the text of verbatim blockquotes alone.
  • Dated log headings: three ## YYYY-MM-DD sections for one day is three logs wearing one date. Collapse to one ## plus one ### per campaign, and write the shape into the spec page so nobody has to infer it.

Fact verification

  • Fleet facts: read-only probes over ssh -o BatchMode=yes dankclaw|dankserver (podman ps/inspect/top, stat, /etc/os-release, curl localhost APIs, podman exec <c> <tool> --version). Live state beats docs even when docs claim recent verification — the 2026-10-18 "audit" still drifted (zealot 27B→9B, build 10754→10777, container census 14→32; #64 then found 8C/16T where SMT is off, a "masked" unit that is simply absent, Pi-hole missing from a DNS list, and a weekly-drifting engine count that became a size class with /config named as the only authority).
  • Local box facts too: pacman -Qs <pkg> / command -v before trusting a page's "installed tool" claim (#64: wlr-randr documented as available, never installed).
  • Unit health is not endpoint health: an :7770 that answers /v1/models while its systemd unit sits inactive Result=exit-code means a container escaped its unit. Report the drift to the operator; never record transient state as docs, and never touch a production unit without a per-run OK.
  • Code-bound facts (franksign-style): every doc claim about routes/columns/shipped status gets grepped against apps/*/src, packages/db/migrations/ — docs narrating features that never shipped ("page ships in the slice" while only the API landed) get truthed with a status pointer to the owning issue.
  • External claims: web_search/web read yourself (no subagents per Frank's rule). Kill fabrications outright (invented distro FreeToken, nonexistent ornith-llama-cpp-setup tree, unattributable "44.5% peer-reviewed CUA") — delete/drop with an explicit note, never keep "plausible" numbers.
  • Policy drift (live ≠ tuned docs): flag in the doc + PR body as an operator decision; NEVER silently re-apply policy.
  • Deletion proposals from scouts die by default: archived trees carrying an honest archive banner (pi/**, banner 2026-10-18) stay, a directory index.md cannot be deleted (index-coverage gate), and incident logs are laws, not bookkeeping. Deletion is a pruning session with Frank present.

OKF §9 / frontmatter audit (cheap wins, check every vault)

  • Log entries filed under the wrong ISO-date heading (crossed midnight): cut the entry (CUT N.=M @reg), insert the new date heading above the old one (newest-first headings), paste the entry under it.
  • Missing trust family (generated on machine-written pages) — lint may not catch it; grep every frontmatter block.
  • Laws living only in log.md: promote each to its owner page (mechanism law → architecture page owning the thing), leave the log entry as the incident record; the HANDOFF/README boundary then points at the vault instead of restating.
  • A law restated in two tiers (vault spec page + always-loaded AGENTS.md) is not a duplicate to cut: name the co-ownership in the spec page ("change one, change the other") instead of silently dropping one copy.

Log compaction (log.md)

  • Entry law: dated entry = what changed + durable lesson + concept-page pointer; narratives recoverable via git log --follow. Record the law at the top of the log. Tag historical-era entries.
  • One ## YYYY-MM-DD per day, ### per campaign. Put the fan-out and ledger-verification lesson in the entry — that is what stops the next campaign from trusting a scout.

Gates + landing

  • Gate every commit: bash scripts/kb-lint.sh omp-docs && python3 scripts/kb-coverage.py omp-docs && bats tests/. Pre-commit hook prints error: command not found: caddy on Caddyfile-touching commits — warning only, commit still lands. On franksign: kill the :3000 demo stack first (a live API hangs the gate ~10 min; law lives in franksign-docs/architecture/testing.md), then bun tests/lib/okf-lint.mjs && tests/run.sh docs.
  • Before opening the PR: git diff --stat origin/main..HEAD | grep -i 'tmp\|scratch\|\.bak' — scaffolding merged under a .tmp- name in the 2026-10-19 campaign and needed a follow-up PR to promote.
  • PR via API (skills gitea-api-pr-operations, gitea-merge-form-encoded): token through a 600-perm -K curl config, never -H (/proc/<pid>/cmdline is world-readable); create/PATCH = JSON WITH Content-Type, merge = form body with NO Content-Type, do=merge&merge_style=no-ff, success = HTTP 200 empty body verified by landed state, not by re-reading the PR. shred -u the cfg and payload afterwards. xdg-open the PR the moment it opens; comment the campaign ledger on the issue — ownership-move table, re-read facts with the command that read them, and rejected findings with their evidence.
  • After Frank's merge OK: propagate the deployment with git -C ~/.omp fetch && git merge --ff-only origin/main, but first prove the FF cannot touch live machine-tier state: comm -12 <(git -C ~/.omp status --porcelain | grep -v '^??' | awk '{print $2}' | sort) <(git diff --name-only HEAD..origin/main | sort) must print nothing, and re-check the dirty count after the merge.
  • Worktree reaping is the live-sync heartbeat's job (wt/* older than 7 days) unless Frank says otherwise — no rm, no deleting a session branch you did not create.

Line-edit op syntax trap (bit five times)

  • Valid ops: PUT N.=M: (body +text lines), CUT N.=M / CUT N.=M @reg, PUT <N @reg, PUT >N: / PUT <N:. There is NO PUT N+=: form — it lands in the file as a literal garbage line and shifts the insert to the wrong position. For gap-insert use a lone PUT >N: or PUT <N: per call; pre-compute line numbers against the file map (ops reference original lines within one call, but a failed op poisons positions).
  • PUT with an empty body DELETES the range (franksign 2026-10-21: a typo-fix PUT 7-7: with empty body deleted the whole entry). Bodyless deletes: use CUT N.=M.
  • A CUT/PUT range outside the file errors cleanly (out of range (file has N lines)) — that is the cheapest way to learn a body was shorter than assumed; re-read the tail rather than guessing offsets.
  • Bare body rows get auto-prefixed with + and a warning — harmless, but never rely on it: prefix every body row yourself.
  • Editing a PUT body that ends adjacent to the next original line can silently consume the closing frontmatter --- — after any frontmatter-range PUT, re-read lines 1–10 of the result.
  • Recovery recipe when a literal op line lands: read exact bounds, CUT N.=N (junk), CUT A.=B @block (misplaced section), then PUT <M @block at the true anchor, re-read tail, add spacing blank if a --- now abuts a list line.