Wiki State Machines
Every pipeline in the wiki is one machine: capture, judge, write, publish. The mechanical steps have executors and run. The judgment step has none, so it stalls, and the health checks stayed green because they timed the mechanical steps instead of counting the queue.
The Machine
Each lifecycle below is an instance of this machine. Only the nouns change.
| From | Event | To | Executor |
|---|---|---|---|
| (none) | sync | captured | launchd com.kevinliu.wiki-intake, 06:40 daily |
| captured | index | indexed | launchd, same run |
| indexed | harvest and absorb | judged | the kevin-wiki-weekly-harvest scheduled session, Mondays 09:00 (since 2026-11-03; before, a person had to start it) |
| indexed | bulk review stamp | listed | a one-off batch run |
| listed | real absorb | judged | none |
| judged | edit owner page | written | the same session |
| written | push | committed upstream | Kevin approves each push |
| committed upstream | build and deploy | published | Vercel; prebuild runs the privacy tests |
If a transition is not in the table, it does not exist. Until 2026-11-03 two rows had no executor, and both queues grew without limit. The bulk stamp is gone; the judgment step now runs weekly.
Why The Checks Were Green
npm run statusreported each step's last-run time. A sync can run every day while nothing is absorbed.- The bookmark coverage audit counted a generated ledger page and a July transfer snapshot as coverage. That made 2,103 of 2,243 bookmarks look covered.
- Automation files without a
lifecyclefield were parsed as an off-schemalegacystate, and status skipped that state entirely. brain/loops.jsondeclared each loopreadyby hand. Nothing measured it, and nothing had written the file since 2026-08-10. The file retired with the typed brain graph on 2026-11-03.
One fix covers every case: a check must count the queue between states from raw records. A timestamp, a generated listing or a hand-written status field does not count. Since 2026-11-03, scripts/check-freshness.ts counts the bookmark and conversation queues and names automations that declare no lifecycle.
Lifecycles
X bookmarks
ft sync writes raw/x-bookmarks/bookmarks.jsonl. Enrichment adds links, threads and media. Absorption means a topic page cites the post. Source: npm run audit:x-bookmarks, 2026-11-03
| State | Count, 2026-11-03 |
|---|---|
| Synced (last sync 2026-10-26) | 2,243 |
| Absorbed into a topic page | 1,378 |
| Listed only in the reference ledger | 726 |
| Missing from every page | 139 |
Absorption by sync month: July 897 of 1,763, August 32 of 204, September 9 of 186, October 1 of 90. Sync kept running after July; absorption almost stopped. The reference ledger marks 701 rows reviewed with one stock sentence, which recorded a state without doing the work. The audit now counts the ledger as a report, not coverage.
Agent conversations
The daily intake indexes Codex, Cursor and Claude transcripts in place. It copies no bytes. The weekly cross-project-learning harvest is the step that turns conversations into owner-page edits. Source: .brain/sessions/index.json; automations/cross-project-learning.md
| State | Count, 2026-11-03 |
|---|---|
| Traces indexed (conversations, subagents, workflows) | 30,466 |
| Conversations | 685 |
| Changed since the last harvest (2026-10-05) | 680 |
The harvest declared a cron trigger but runner: manual, so its executor was a person remembering; since 2026-11-03 a scheduled session runs it every Monday. Session replay was a side path: it emitted about one candidate signal per message (11,897 from 10 conversations), and nothing read them. It retired with the typed brain graph on 2026-11-03; the harvest reads transcripts at the paths npm run brain -- sessions list prints.
Automations
The V2 contract allows proposed, active, paused and retired. A definition without a lifecycle field predates the contract and is parsed as legacy, a fifth state nothing schedules or watches. Source: automations/_schema.md; scripts/lib/automation-contract.ts
| State | Definitions | Recent runs |
|---|---|---|
| active | 2 | wiki-intake daily; cross-project-learning last 2026-10-05 |
| paused | 7 | source-compile paused 2026-10-26 |
| retired 2026-11-03 | 14 | none in 90 days; five never ran; moved to ~/repos/_retired/automations-legacy-20261103/ |
| legacy, on demand | 2 | self-heal last 2026-08-12 |
state.json also records runs for three automations with no definition file: mac-app-harvest, fmhy-catalog-harvest and repository-evidence-capture. npm run status still names any definition that declares no lifecycle and stops running.
Privacy
Every surface asks one gate, ui/src/lib/privacy-gate.mjs: runtime pages, listings, search, the sitemap, llms.txt, the build bundle and the OKF export. First match wins:
- frontmatter
private: truemakes a page private. - A sensitive-subject tag (investor, fundraising, recruiting, job search, interview) makes it private.
- A slug listed in
publicSlugs, or the README of a public category, makes it public. Until 2026-11-03 a public brain object did too; that override nearly published three private pages on 2026-11-02 and retired with the graph. - A proprietary tag, a private slug token, a listed private slug or a private category makes it private.
- Anything else is public.
Before 2026-11-03 the rule lived in three copies, and step 2 did not exist. A page in a public folder with investor tags was public. ui/scripts/test-privacy-gating.ts pins both sides: sensitive pages stay private, and look-alike tags such as career on an essay stay public.
Gating a page was not enough, because other pages name it. A link prints its target's title, and for people and investor pages the slug is the name. On 2026-11-03, many public pages linked private ones, and the generated _index listed every page by title. The second rule, ui/src/lib/private-links.mjs, masks every reference to a page the viewer cannot open. The reference renders as "private page", with no link. Kevin and the public figures on the policy's publicNames list keep their names as plain text. It covers article HTML and markdown, metadata, related pages and backlinks, the /api/wiki JSON, the Wikibot's context, the search index and the OKF export.
Access itself has two parts:
- Unlock cookie. It is an HMAC-signed, expiring token. Before 2026-11-03 it was the constant
1, so anyone could set it. - Private app routes.
/me,/brief,/system/sessionsand/auditare gated inui/src/proxy.ts, before any page renders. A layout-only gate still let Next serialize the page.
The public brain graph shows only public objects, and it names nothing else by id.
Deploy
Commit, Kevin's push approval, the Vercel build, then live. Builds fail closed: prebuild runs the privacy tests before bundling. Site deploys failed from 2026-10-30 to 2026-11-02 because .vercelignore dropped files the build needed, and nothing reported the failures until a session looked. Source: .state/RESUME-overhaul.md pnpm --dir ui test:vercel-upload fails when the upload would drop a file the build reads. It runs as a closeout command, and in the pre-commit hook when deploy inputs change once bash scripts/install-git-hooks.sh reinstalls the hooks. Source: commit dae63152a, 2026-11-03
Pages
A page carries updated:, but until 2026-11-03 nothing re-read it when its sources changed. Kevin's user-model pages kept July facts until a session rewrote them on 2026-10-30, and the Claude of Tanks page described July until the projects lane on 2026-11-03.
Since 2026-11-03 a project page binds its repo (repo:) and site (url:). kb stale counts the pages whose repo has a commit newer than the page's updated:, npm run status lists them, the card flags them, and the weekly harvest refreshes them. Facts learned in other directories queue as kb note files in ~/.local/share/kevin-wiki/inbox/, and the same harvest writes them in. The table is in Wiki Brain Operating Model. Pages that bind nothing still have no executor. Source: scripts/kb.mjs, 2026-11-03
| State | Count, 2026-11-03 |
|---|---|
| Project pages that bind a repo | 51 |
| Of those, older than the repo's newest commit | 5 |
| Project pages that bind nothing | 23 |
Bookmarks, after the lane
The 2026-11-03 bookmarks lane synced 61 new posts and absorbed the backlog. Coverage rose from 1,378 of 2,243 to 2,285 of 2,304, with 0 missing. 19 were left out on privacy or funding grounds. The reference ledger shrank from 732 rows to 38 parked sources. Source: npm run audit:x-bookmarks, 2026-11-03
Rules For Any New Pipeline
- Write the transition table first. A transition that is not in the table does not exist.
- Name an executor for every transition. "Manual" is a stall unless a schedule starts the session.
- Have status count each queue from raw records. Never infer progress from a timestamp, a generated listing or a declared field.
- Make a missing state field an error. Never give it a default state.
Open Fixes
- Done 2026-11-03: the judgment step has a weekly scheduled session, and the 14 dead automations are retired.
- Done 2026-11-03: the hand-written loop statuses retired with the typed brain graph.
Timeline
- 2026-11-05 | Removed a count of public pages that linked private ones, because a public page states no number taken over private pages. Dropped the stale count of public figures; Kevin added the 57 designers from Flo Guo's public list to
publicNames. Source: UI privacy lane review, 2026-11-05; Kevin, chat 2026-11-05 - 2026-11-03 | Retired the typed brain graph: loop statuses, session replay and the brain-object privacy override are gone; no page changed visibility. Source: Kevin, 2026-11-03
- 2026-11-03 | Pages gained an executor: repo bindings,
kb stale, thekb noteinbox and the weekly harvest. Source: Wiki Brain Operating Model, 2026-11-03 - 2026-11-03 | Kevin approved the open fixes: a weekly scheduled harvest session now runs the judgment step, the 14 dead automations are retired, and the two funding pages left the wiki. Source: Kevin, 2026-11-03
- 2026-11-03 | Deploy gained a pre-commit check and a closeout command (
pnpm --dir ui test:vercel-upload) for files the upload drops. Source: commit dae63152a - 2026-11-03 | Added the link mask, signed unlock cookies, the proxy gate and the scrubbed brain graph to Privacy; recorded the bookmarks lane's result. Source: commits de5560217, 2d264edf3, 73dbb8261, c7b655d19
- 2026-11-03 | Mapped the machine and its six lifecycles from raw counts. Status now counts the bookmark and conversation queues and names undeclared automations; the bookmark audit stopped counting the reference ledger and the transfer snapshot; the privacy rule became one shared gate. Source: npm run status, 2026-11-03