kingshand

The data index - an index, not a classification

Where this came from

Source
docs/2026-08-30-data-index.md in emgee-labs/kingshand
Mirrored from
commit a9858a6d, dated 2026-09-01

This page is a mirror. The text below is the document as it stands in the repository; edits belong there, and reach this page the next time the site is built. Nothing is rewritten for the web on the way here, so the headings, tables and code below are the ones the repository holds, and a link that points at another record points at the copy served here. Back to all records, or to the install page for the tool these records describe.

The document

2026-08-30

What went wrong

On 2026-08-29 the whole Emgee Labs brand was settled in one session: logo, favicon, tagline, both theme palettes, the homepage headline verbatim, and a list of things never to put on the page. It was written to data\emgee-brand.md, whose own first line says "This is the input to the website brief."

On 2026-08-30 the site was built and shipped live with none of it. No logo, no favicon, no tagline, none of the settled palette. It was found by looking at the page.

Nothing was lost and nothing was overruled. The file was simply never read, because nothing made anyone read it. A worker sees exactly one thing - its brief - and no brief named the file.

The design that was rejected

The first answer was a category: define "a settled decision that a future brief must carry", give it a home at data\decisions\, list it in the digest, and require brief-writing to look for one.

It was rejected, correctly. Classifying a file as important at the moment it is written means guessing what some future task will need. That guess is wrong regularly, and a wrong guess is silent - the file is simply not in the special place, so nothing looks for it and nothing reports that anything is missing. That is the same failure this whole change exists to fix, wearing a different hat.

The design that shipped

An index. Every durable file under data\ gets one line recording where it is and what it is. Nothing is judged important or unimportant at write time; everything is listed. The judgement moves to read time, where the reader knows exactly what they are working on and opens the handful of files their own task touches.

Four things make it work, and removing any one of them puts the failure back.

It is a table of contents, never content. Path, one line, date. A reader pays one line per file, not one file per file. Add-IndexEntry refuses a summary over 160 characters rather than truncating it, because a silently cut summary is a summary that lies, and because a cap is the only thing that keeps a table of contents from growing into a second copy of the data.

It is scoped per project. data\index\<project>.md holds one project's files; data\index.md at the root holds kingshand's own operational files. The project is the cut because the project is the unit a brief is written against - an index spanning every project hands a website worker the aegis reports, and an index nobody can scan is an index nobody reads. The root index is a file beside the directory rather than a reserved name inside it, so no project name can ever collide with it.

Indexing is part of writing, not a separate act of virtue. Write-DataFile writes the file and indexes it in one call, so the two cannot come apart. Where another tool owns the write - tasks-axi writing the backlog, a worker writing its own report.md - Add-IndexEntry records it at the first moment somebody has both the file and the context to describe it, which is why muster indexes a brief in the step that writes it and a report in the step that reads it. A rule that says "remember to add it afterwards" is exactly the rule that was forgotten last time.

The gap is visible. Get-IndexDrift counts the files under data\ that no index lists, and the session-start digest prints that count. This is the part that makes the whole thing self-checking, and it is the reason an index beats a classification: "this file is listed nowhere" is a fact a machine can notice, where "somebody should have realised this mattered" never was.

And it has to be clearable from both ends. The digest also prints STALE:, the entries whose file is gone, and that half had no remover at first - a dated /survey file artefact is written to be deleted, so every deletion cost one permanent line of noise and took the whole number with it. Remove-IndexEntry -Missing -All prunes them. The same argument that says a drift count growing by one per dispatch is a count nobody reads says a count nothing can take to zero is not a signal.

What is deliberately not in it

No exclusion is a judgement about a file's worth. The test each one passes is derivation: the file is produced from something else that is itself listed, so an entry would record the same fact twice. An index does not index itself. A rendered *.html review surface is regenerated from state rather than read as a source. A read-first\ copy is the snapshot dispatch takes of a file that already has its own entry at its own path, so that its worker can reach it at all.

The count is not the rule; the test is. Guarding a number would have taken the drift signal down instead: read-first\ arrived after this note was first written, and with only "there are exactly two" to go on, the choice was between a drift count that grows by one per dispatch forever - a count nobody reads - and indexing each copy, which would put a duplicate entry in the table of contents for a file already listed. An exclusion that cannot answer "derived from what?" is the rejected classification creeping back in one file at a time, and that is what must not be added.

The digest prints counts and the location, never a file list and never a file's contents. The startup-memory budget accounts for king.md and learnings.md only; the index is not printed in full and is not accounted, which is what keeps a growing index from becoming a growing session-start cost.

What still has to move

data\emgee-brand.md is where it was. It is live evidence of the failure and was left alone deliberately. It wants an entry in data\index\emgeelabs-site.md, and until it has one the digest counts it as drift - which is the mechanism working, not a defect.