MemPalace mining design — docs-site + ordna tasks (S518)
Point-in-time report, authored S518 (2026-07-31/08-01). Ratified rulings are in section 11 and in DR-112; where the two differ the decision record wins. The
removal-*.txtpath lists referenced below were a 2026-07-31 snapshot in an ephemeral scratchpad and are not committed — regenerate them from the queries in section 0.1 against current palace state before executing anything, which the execution sequence already requires as its step 2.
Design only. Nothing executed. No palace writes. All palace access was lock-free sqlite
(mode=ro&immutable=1). The vector layer was never opened; no MCP mempalace tool and no
mempalace CLI invocation was made.
0. Method, and what changed versus the brief
Section titled “0. Method, and what changed versus the brief”0.1 Queries run
Section titled “0.1 Queries run”All against file:$HOME/.mempalace/palace/chroma.sqlite3?mode=ro&immutable=1.
| # | Purpose | Shape |
|---|---|---|
| Q1 | Family rollup | source_file LIKE '%/knowledge-hub-docs-site/src/content/docs/%', family = first path segment after /src/content/docs/ via substr(...,instr(...,'/src/content/docs/')+18), grouped with COUNT(*) and COUNT(DISTINCT string_value) |
| Q2 | Wing / room / mode crosstabs | family CTE LEFT JOIN a per-key CTE on id, for wing, room, extract_mode, ingest_mode, normalize_version, added_by |
| Q3 | Value-column audit | SUM(string_value IS NOT NULL), int_value, float_value, bool_value per key — corrected Q2, which had missed int-typed keys |
| Q4 | Multi-wing test | SELECT nw, COUNT(*) FROM (SELECT path, COUNT(*) nw FROM (SELECT DISTINCT path, wing …) GROUP BY path) |
| Q5 | Date-signal coverage | per-family presence of content_date, source_mtime, authored_at, id_recipe, entities |
| Q6 | Extension split | distinct source_file piped through sed 's/.*\.//' | sort | uniq -c |
| Q7 | Collections / segments | collections, segments, embeddings JOIN segments JOIN collections |
| Q8 | Closet (KG) contents | metadata keys + chroma:document samples restricted to the mempalace_closets collection id |
| Q9 | Entity quality | all entities values split on ;, frequency-ranked; then regex-tested for DR-, id-, S###, fr- |
| Q10 | Wing hygiene | GROUP BY wing HAVING COUNT(*) < 50 |
| Q11 | Unmined gap | comm -23 of on-disk .md set against mined .md set |
| Q12 | Removal-set sizing | python sqlite3 with a TEMP table of candidate paths, JOIN on string_value |
Non-palace evidence: on-disk find/stat over $KH_PRIVATE_DOCS_DIR; git log; and reads of
the installed miner source at
~/.local/share/uv/tools/mempalace/lib/python3.12/site-packages/mempalace/ (read-only).
0.2 Corrections to the brief’s given facts
Section titled “0.2 Corrections to the brief’s given facts”Three of the inherited numbers did not survive verification. None invalidate the brief’s direction, but two change the design.
- docs-site total is 107,938 drawers, not 109,162 (Q1). The delta (1,224) is unexplained;
the likely cause is a join that double-counted. I have used 107,938 throughout. There are
zero mined docs-site paths outside
src/content/docs/, so nothing is hiding elsewhere. extract_mode/ingest_mode/authored_atdo not exist on the docs-site corpus at all — not “distributed somehow”, but 0/107,938 for each (Q5). Q3 shows both mode keys are written only on the convos path (sessionswing, valueexchange, 225,940 drawers). The brief asked for their distributions; the correct answer is not applicable to projects mode, and no proposal should attempt to set them.content_dateandsource_mtimeDO exist on projects-mode drawers — 90,782 (84%) and 106,847 (99%) of docs-site drawers respectively (Q5). The brief stated chronology must come entirely from the register/ordna/git because projects mode “gets noauthored_at”. That is true ofauthored_atspecifically, butsource_mtimeis a real, populated, per-file recency signal already in the palace, spread across 46 distinct days from 2026-04-28 to 2026-07-24 and matching on-disk mtime patterns. §5 is built on it.
I also confirmed the brief’s load-bearing claims that did hold: 480 orphans all genuinely
absent from disk; tasks/ mined zero times; authored_at 0/107,938 on docs-site;
exclude_patterns is projects-mode only.
0.3 Mechanism facts established from the miner source
Section titled “0.3 Mechanism facts established from the miner source”These are what make the proposal actionable rather than speculative.
mempalace.yamlin the project root supplieswing,rooms: [{name, description, keywords}], andexclude_patterns(miner.py:484,:1780).detect_room(miner.py:552) routes by path, outermost-segment-first. It walkspath_parts[:-1]and, for each part, tests every room’s name and keywords; first match wins. Only then does it try filename, then content keyword scoring, thengeneral.- Matching is token-based (
_tokenssplits on-,_,.,/), so keywordthemesmatches path partthemes, and keywordpromptsmatchescontinuation-prompts. exclude_patternsuses the same parser as.gitignore, including!negation and**globs (miner.py:308)..gitignorefiles in the tree are also honoured independently (load_gitignore_matcher,miner.py:386).content_date(_extract_content_date,miner.py:1290) resolves in strict order: filename date → YAML frontmatterdate/created/published→ first ISO date in the first 10 body lines → filesystem mtime. It is computed once per file and stamped identically on every chunk of that file (miner.py:1499).source_mtimeis rawos.getmtimeas a float (miner.py:1383).- Chunking:
CHUNK_SIZE=800,CHUNK_OVERLAP=100,MIN_CHUNK_SIZE=50. Observed mean drawer length on surviving spec markdown is 679 chars. - A
--wingoverride exists (wing_override,miner.py:1778) — this is how the ad-hocspecs/runbooks/reference/handoffswings were created.
Assumption (stated, not verified): I could not execute the miner, so room routing, exclusion matching and drawer counts are reasoned from source, not observed. Every proposed config change below therefore carries a dry-run checkpoint in §7.
1. Inventory refinement
Section titled “1. Inventory refinement”1.1 Per-family, layered onto the given file counts
Section titled “1.1 Per-family, layered onto the given file counts”All docs-site drawers share normalize_version = 2, added_by = mempalace (with a small
(none) tail from an older writer), room = general, and no extract_mode / ingest_mode /
authored_at. Those columns are therefore omitted; they are constant.
| family | drawers | mined files | drawers/file | wings (drawers) | on-disk .md | orphans | unmined .md |
|---|---|---|---|---|---|---|---|
| workflow-evaluation | 43,887 | 265 | 165.6 | wing_canonical 43,887 | 6 | 0 | 0 |
| specs | 24,212 | 572 | 42.3 | specs 14,272 / wing_canonical 9,940 | 589 | 1 | 110 |
| ledgers | 16,182 | 511 | 31.7 | wing_canonical 16,182 | 244 | 290 | 23 |
| initiatives | 7,077 | 110 | 64.3 | wing_canonical 7,077 | 109 | 0 | 0 |
| themes | 6,583 | 98 | 67.2 | wing_canonical 6,583 | 0 | 98 | 0 |
| continuation-prompts | 3,537 | 275 | 12.9 | wing_canonical 2,708 / handoffs 829 | 228 | 70 | 23 |
| reference | 2,305 | 34 | 67.8 | wing_canonical 1,946 / reference 359 | 144 | 10 | 120 |
| runbooks | 2,001 | 49 | 40.8 | wing_canonical 1,396 / runbooks 605 | 40 | 12 | 3 |
| product-functionality | 1,379 | 28 | 49.3 | wing_canonical 1,379 | 28 | 0 | 0 |
| ontology | 452 | 39 | 11.6 | wing_canonical 452 | 39 | 0 | 0 |
| reports | 142 | 6 | 23.7 | wing_canonical 142 | 37 | 0 | 31 |
| design | 140 | 6 | 23.3 | wing_canonical 140 | 6 | 0 | 0 |
| handover-guides | 39 | 2 | 19.5 | wing_canonical 39 | 2 | 0 | 0 |
| (root) | 2 | 1 | 2.0 | wing_canonical 2 | — | 0 | 0 |
| total | 107,938 | 1,996 | 54.1 | — | 1,473 | 480 | 310 |
1.2 The five findings that drive the whole design
Section titled “1.2 The five findings that drive the whole design”F1 — 41% of the corpus is machine telemetry, not documents.
workflow-evaluation is 43,887 drawers from 265 files, of which only 6 files (208 drawers)
are markdown. The rest:
| ext | drawers | files |
|---|---|---|
.jsonl | 42,430 | 92 |
.yaml | 1,130 | 75 |
.json | 119 | 92 |
.md | 208 | 6 |
These are sessions/session-<uuid>/<run>/events.jsonl machine event streams. The repo already
ruled on them: .gitignore line 47–48 excludes src/content/docs/workflow-evaluation/sessions/
with the comment “eval-run artefacts; not canonical docs — S396”. The palace is holding 43,679
drawers of content the project has already classified as non-canonical.
F2 — a mempalace.yaml already exists, and its exclusion is both partial and unenforced.
$KH_PRIVATE_DOCS_DIR/mempalace.yaml (411 bytes, 2026-07-28) sets wing: wing_canonical and one
exclusion:
exclude_patterns: - src/content/docs/workflow-evaluation/sessions/**/events.jsonlTwo gaps. (a) It matches 42,430 drawers / 92 files — leaving 1,457 drawers / 173 files of
.yaml and .json in the same tree unexcluded. (b) It has no rooms: key, which is the
direct and complete explanation for why all 107,938 drawers are room = general: load_config
falls back to a single {name: general} room. The exclusion prevents future re-mining; it never
removed what was already filed (filed_at for this family is 2026-07-03 and 2026-07-24 only —
no mine has run since the yaml landed).
F3 — the Decision Register’s individual records are entirely absent from the palace.
src/content/docs/reference/decisions/ holds 114 DR files on disk and 0 are mined (Q11). So
does reference/change-log/ (2 files, 0 mined). The only decision content in the palace is the
82-drawer rollup reference/decision-register.md. Under DR-010, the register is the “what was
decided” leg of the three-way routing — and it is the single least-represented surface in the
palace. This is a larger correctness problem than the orphans.
More broadly, 310 on-disk markdown files have never been mined: reference 120, specs 110,
reports 31, ledgers 23, continuation-prompts 23, runbooks 3. reports is 31 unmined of 37 on
disk — the family the owner called “incredibly valuable context” is ~84% absent.
F4 — the orphan set is almost entirely superseded predecessors of the two corpora being mined.
| orphan family | files | what superseded it |
|---|---|---|
| ledgers | 290 (backlog 142, tasks 127, roadmap 16, top-level 5) | Corpus B — tasks/id-N.md |
| themes | 98 (all of them) | initiatives/ — deleted in commit fa71b6bf “chore: repurpose roadmap ledger to be initiative-focused” |
| continuation-prompts | 70 | rotated out point-in-time |
| runbooks | 12 | rewritten |
| reference | 10 | rewritten |
| specs | 1 | — |
The themes question the brief flagged has a clean answer: themes/ is the predecessor of
initiatives/, removed wholesale by a single deliberate commit. 100% orphaning is not decay,
it is a rename-and-restructure. Likewise ledgers/tasks/ + ledgers/backlog/ (269 files) are
the pre-ordna per-item ledger — the exact content Corpus B replaces.
F5 — no file is double-mined; the wings are merely incoherent.
Q4 is unambiguous: all 1,996 files sit in exactly one wing each. The specs (259 files),
handoffs (70), runbooks (19) and reference (8) wings are disjoint subsets, not
duplicates — the residue of ad-hoc --wing mines. So there is no content-level dedup problem
inside the docs-site corpus; there is a routing problem. Any recall filtered to
wing_canonical silently misses 356 files, and any filtered to wing=specs misses 313 of the
572 mined specs.
1.3 Non-markdown load outside workflow-evaluation
Section titled “1.3 Non-markdown load outside workflow-evaluation”| path class | drawers | files |
|---|---|---|
ledgers/task-list.json | 3,996 | 1 |
ledgers/product-retros.json | 770 | 1 |
ledgers/product-backlog.json | 280 | 1 |
ledgers/product-roadmap.json | 52 | 1 |
ledgers/umbrellas.json | 3 | 1 |
specs/**/*.versions.jsonl, *.line-attribution.json, plan-subtasks.json | 1,401 | 93 |
initiatives/**/corpus-reframe-review.html | 75 | 1 |
ledgers/task-list.json alone is 3,996 drawers — one machine-readable array of the pre-ordna
task list, chunked at 800 chars into ~4,000 fragments of JSON syntax. All five ledger JSON files
are already orphaned (gone from disk). The specs sidecars are spec-authoring machinery
(.versions.jsonl, .line-attribution.json), not prose.
2. Dedup / removal set
Section titled “2. Dedup / removal set”delete_by_source is exact-match on the full stored path, so the deliverable is explicit path
lists. These files are produced but NOT executed.
| file | class | files | drawers |
|---|---|---|---|
removal-R1-orphans.txt | Gone from disk (independently verified) | 481 | 18,037 |
removal-R2-workflow-eval-telemetry.txt | Machine telemetry, all non-.md under workflow-evaluation/ | 259 | 43,679 |
removal-R3-legacy-json-ledgers.txt | Pre-ordna machine ledgers (*.json) | 5 | 5,101 |
removal-R4-spec-sidecars.txt | Spec-authoring machinery (.versions.jsonl, .line-attribution.json, plan-subtasks.json) | 93 | 1,401 |
removal-R5-stray-binary.txt | Stray rendered HTML | 1 | 75 |
removal-UNION.txt | de-duplicated union | 833 | 63,153 |
Overlap is small and accounted for: all 5 R3 files and 1 R4 file are also in R1. Union impact: 63,153 of 107,938 docs-site drawers removed (58.5%), 44,785 survive. As a share of the whole 402,267-drawer palace, this is a 15.7% reduction.
All paths are absolute and in the exact form stored in source_file, e.g.
/Users/liamj/Documents/development/knowledge-hub-docs-site/src/content/docs/ledgers/task-list.json.
2.1 The DR-010 judgement: what gets deleted vs re-homed vs retained
Section titled “2.1 The DR-010 judgement: what gets deleted vs re-homed vs retained”The brief asks specifically whether the 290 orphaned ledgers and 98 orphaned themes should be deleted, given DR-010 says the palace uniquely holds “what was argued”. My recommendation splits them, because they are not the same kind of thing.
Delete outright — no argument content is lost:
- R2 (43,679 drawers). Machine event streams. There is no argument in an
events.jsonlchunk; DR-010’s “what was argued” protection does not attach to telemetry. The project already ruled these non-canonical in.gitignoreat S396. This is the single highest-value deletion in the whole plan and it is uncontroversial. - R3 (5,101 drawers).
task-list.jsonand friends are serialisations of state, not discussion. Their human-readable successor — the ordna task files, with the## Progressjournal that actually holds the reasoning — is Corpus B and is being mined for the first time. Deleting the JSON while adding the markdown is a strict information gain. - R4 + R5 (1,476 drawers). Authoring machinery and a rendered HTML duplicate.
- The 269
ledgers/tasks/+ledgers/backlog/orphans inside R1. Same argument as R3: superseded item-by-item bytasks/id-N.md. Caveat below.
Re-home, do not delete — this is where I disagree with a blanket orphan purge:
- The 98
themes/orphans (6,583 drawers). These are not decayed; they were deleted by commitfa71b6bfwhen the roadmap ledger was repurposed toward initiatives. They are the only surviving record of the pre-initiative framing, and under DR-010 they are precisely “what was argued”. They are also, notably, the reasoninitiatives/looks the way it does. Recommendation: retain the drawers, and re-home them by re-mining from git (see §4) so they carry an explicit superseded marker. Deleting them destroys lineage the register does not hold. - The 70 orphaned
continuation-prompts(subset of R1). The owner explicitly values these for lineage. They are transitory by design but their sequence is the lineage. Retain.
The caveat I want the owner to rule on (see §9, Q1): R1 as delivered is the whole 481-path
orphan set, including themes and continuation-prompts. If my re-homing recommendation is
accepted, R1 should be split before execution into R1a-supersessions (the 269 ledger
tasks/backlog files — delete) and R1b-lineage (themes + continuation-prompts + the rest —
retain and re-mine from git). I have deliberately not pre-split it, because “delete the
lineage” vs “preserve the lineage” is an owner decision under DR-010, not mine. Executing
removal-UNION.txt as-is deletes the lineage.
2.2 What is NOT a dedup problem
Section titled “2.2 What is NOT a dedup problem”Worth stating because the brief anticipated one: there is no duplicate-content problem within
the docs-site corpus. Q4 proved one-wing-per-file. The palace-wide duplicate head documented in
runbooks/mempalace-repair.md §10.3 (89,053 redundant copies) is agent-brief and dispatch-
template boilerplate on the convos path, out of scope here.
3. Tier table
Section titled “3. Tier table”Four tiers. The tier determines mine/don’t-mine, room, and cadence.
- T1 Authoritative — kept current, re-mined on change. Citable as authority.
- T2 Lineage — one-shot, point-in-time. Valuable as “what was argued”; never citable as current state.
- T3 Stale-marked — mined, but explicitly marked so recall can down-rank it (§4).
- T4 Excluded — never mined.
3.1 Corpus A — src/content/docs/
Section titled “3.1 Corpus A — src/content/docs/”| family / subtree | tier | mine | room | cadence | justification |
|---|---|---|---|---|---|
reference/decisions/** (114 files) | T1 | YES — currently 0 | decisions | kept current | DR-010 “what was decided” leg. Owner: reference must be “the most accurate record”. F3: the biggest gap in the palace. |
reference/*.md, reference/change-log/ | T1 | yes | decisions | kept current | Same owner ranking. Routing note below. |
runbooks/ | T1 | yes | runbooks | kept current | Owner: “most accurate record of something”. Operational truth. |
specs/**/*.md (id ≥ 130) | T1 | yes | specs | kept current | Owner: high-value, should be kept up to date. |
specs/**/*.md (id < 130) | T3 | yes | archive | one-shot | DR-106: specs below ~130 not citable unless re-affirmed. |
ontology/ | T1 | yes | reference | kept current | Unnamed by owner. Schema/taxonomy definitions — behaves like reference, small (452 drawers), low risk. |
initiatives/ (except below) | T1 | yes | initiatives | kept current | Owner: intended home for initiative substrate. |
initiatives/core-product/canonical-pipeline/intended-architecture/** except 01-vision.md | T3 | yes | archive | one-shot | DR-106 names it stale explicitly. |
initiatives/**/phase-0-investigation/** | T3 | yes | archive | one-shot | DR-106: the whole OQ-resolution chain. |
ledgers/initiatives/ (12 files) | T1 | yes | initiatives | kept current | DR-101 canonical store for task placement (Linked tasks:). Load-bearing for Corpus B cross-links. |
ledgers/retros/ (127 files) | T1 | yes | retros | kept current | S### retro records — the session leg of the cross-link web. |
ledgers/archive/ (105 files) | T2 | yes | archive | one-shot | Owner: should move to co-locate with ordna tasks. See §9 Q2 — the move is a docs-site refactor, not a mining decision; mine in place now, re-point after. |
continuation-prompts/ | T2 | yes | lineage | one-shot per file, append-only | Owner: transitory but show lineage. Never authority. |
reports/ | T2 | yes — currently 6 of 37 | lineage | one-shot | Owner: point-in-time, “incredibly valuable context”. 84% missing today. |
handover-guides/ (2 files) | T2 | yes | lineage | one-shot | Unnamed by owner. Tiny, handoff-shaped — same class as continuation-prompts. |
design/ (6 files) | T1 | yes | reference | kept current | Unnamed by owner. Warm Meridian design system is live and cited from CLAUDE.md. |
product-functionality/ | T3 | yes | archive | one-shot | Owner: “almost all current docs outdated”. Mined-but-marked, not deleted — under DR-010 the arguments retain value. |
themes/ (98, orphaned) | T3 | yes — re-mine from git | archive | one-shot, frozen | Predecessor of initiatives/. Lineage under DR-010. See §4.2. |
workflow-evaluation/*.md (6 files: friction-register.md, s-number-crosswalk.md, …) | T2 | yes | lineage | one-shot | Prose in a telemetry tree. The existing yaml comment already says “prose docs in the same tree stay mined” — preserve that. |
workflow-evaluation/sessions/**, reports/** (non-.md) | T4 | NO | — | — | F1. Already gitignored as non-canonical (S396). |
**/*.json, **/*.jsonl, **/*.yaml anywhere under src/content/docs/ | T4 | NO | — | — | R2+R3+R4. Machine serialisations; the prose successor is mined instead. |
**/*.html | T4 | NO | — | — | R5. |
3.2 Corpus B — tasks/
Section titled “3.2 Corpus B — tasks/”| subtree | tier | mine | room | cadence | justification |
|---|---|---|---|---|---|
tasks/id-N.md where status ∈ {backlog, todo, doing} | T1 | yes | tasks | kept current | Live work. |
tasks/id-N.md where status = done | T1 | yes | tasks | kept current | The ## Progress journal is the richest “what was argued” surface in the repo. Done ≠ stale. |
tasks/id-N.md where status = archived (139 files) | T2 | yes | tasks | one-shot | Retain — DR-010. Distinguished at recall time by the status: line inside the drawer text, not by room. |
tasks/AGENTS.md | T1 | yes | tasks | kept current | Conventions home. |
tasks/ID-CROSSWALK.md | T1 | yes | tasks | kept current | The bl-* → id-N map — required to resolve historical references. |
Sizing. 376 task files, 2,166,668 bytes total (median 2,041 B, p90 12,930 B, max 87,576 B). At the observed 679 chars/drawer this is ≈3,190 drawers — 2.9% of the current docs-site footprint, for the corpus that ties everything together. Cheap.
3.3 Proposed mempalace.yaml
Section titled “3.3 Proposed mempalace.yaml”One project, one config, both corpora — tasks/ sits at the docs-site repo root, so a single
root-scoped mine covers both. This replaces the ad-hoc per-subdirectory --wing mines that
produced the incoherent wings in F5.
wing: wing_canonical
# Rooms route by PATH, outermost segment first, first match wins# (miner.py:552 detect_room). Keywords must never include 'src',# 'content' or 'docs' — those segments precede every family and would# capture the entire corpus into one room.rooms: - name: decisions description: Decision Register, individual DR records, change-log keywords: [reference, decisions, change-log] - name: runbooks description: Operational runbooks keywords: [runbooks] - name: specs description: Task spec chain (RESEARCH/PRODUCT/TECH) keywords: [specs] - name: tasks description: ordna task ledger keywords: [tasks] - name: initiatives description: Initiative substrate and initiative ledger records keywords: [initiatives] - name: retros description: Session retro records keywords: [retros] - name: reference description: Ontology and design-system reference keywords: [ontology, design] - name: lineage description: Point-in-time handoffs, continuation prompts, reports keywords: [continuation-prompts, reports, handover-guides, workflow-evaluation] - name: archive description: Superseded — retained for lineage, never citable as current keywords: [ archive, _archive, themes, product-functionality, intended-architecture, phase-0-investigation, ]
exclude_patterns: # F1 — machine telemetry (belt-and-braces; .gitignore also covers sessions/) - src/content/docs/workflow-evaluation/** - "!src/content/docs/workflow-evaluation/*.md" # R3/R4/R5 — machine serialisations everywhere in the docs tree - src/content/docs/**/*.json - src/content/docs/**/*.jsonl - src/content/docs/**/*.yaml - src/content/docs/**/*.html # keep the mine to the two corpora - src/** - "!src/content/docs/**" - public/** - node_modules/** - .astro/**Three routing constraints I verified and had to design around, stated plainly:
reference/decisions/cannot get its own room whilereference/also has one. Path parts are walked outermost-first, soreference(depth 3) is always tested beforedecisions(depth 4). I therefore named the roomdecisionsand gave it thereferencekeyword, folding the whole reference tree into it. Rationale: under DR-010 the register is the reference surface’s reason for existing, and 114 of 144 files in that tree are DRs. The DR-vs-prose distinction remains recoverable fromsource_file.specsid ≥ 130 vs id < 130 cannot be split by directory keyword — both arespecs/id-N-…. Splitting requires enumerating the ~60 stale spec dirs asarchivekeywords. Each dir name (id-61-bid-rename) matches its path part exactly, so it works, but the block is long and needs regenerating as tasks age. I have not inlined it; §7 step 4 generates it. This is the one place the design needs maintenance, and §9 Q3 asks whether it is worth it.ledgers/deliberately has no room keyword. Its three children (initiatives,retros,archive) each match a room at depth 4 — but only becauseledgersat depth 3 matches nothing. Adding aledgerskeyword anywhere would capture all three. Fragile but correct; flagged in §7’s dry-run checkpoint.
4. Stale-family handling (DR-106)
Section titled “4. Stale-family handling (DR-106)”Under DR-010, stale ≠ don’t-mine: “what was argued” is exactly what the palace uniquely holds, and DR-106’s stale families are dense with argument. The requirement is that recall can tell.
4.1 Mechanism: the archive room is the marker
Section titled “4.1 Mechanism: the archive room is the marker”The only metadata dimension that is (a) settable at mine time with no code change, (b) available
as a recall filter, and (c) currently entirely wasted, is room. Every one of the 107,938
docs-site drawers is room = general today, so the room dimension carries zero information and
is free to repurpose.
Concretely: room = archive is the stale marker. DR-106’s named families
(intended-architecture/** minus 01-vision.md, phase-0-investigation/**, sub-130 specs),
plus product-functionality/ and themes/, route there by path keyword. Recall then has a
one-token discriminator: room != archive for authority questions, room = archive when
deliberately asking what was argued before.
This is preferable to the alternatives:
- A separate wing (
wing_stale) would work, but wings are the coarse project axis and the palace already suffers from wing sprawl (§8). Adding one compounds F5. - A metadata key (
stale: true) requires a miner code change —_build_drawer_metadata(miner.py:1327) writes a fixed key set with no passthrough for custom fields. - Content prefixing would pollute the embedded text and shift similarity.
Known limitation, stated: 01-vision.md is DR-106’s explicit exception inside an otherwise
stale tree, and path-keyword routing cannot exempt a single file — intended-architecture matches
at directory depth before the filename is ever considered. 01-vision.md will land in archive
with its siblings. Options: accept it (it is one file, and it is findable, just under-ranked);
or move it up one directory in the docs-site, which is a content change outside this design’s
remit. Flagged in §9 Q4.
4.2 themes/ — re-mine from git, frozen
Section titled “4.2 themes/ — re-mine from git, frozen”themes/ is gone from disk, so it cannot be re-mined in place, and the brief correctly forbids
staging directories (the miner skips symlinks, and hardlinks record the staging path as
source_file, recreating the orphan class).
The clean route: git worktree add the parent commit of fa71b6bf into a path, mine it, and
remove the worktree. That records real file paths at a real checkout — but they are the
worktree’s paths, which is the same orphan problem one step removed.
I therefore recommend the honest alternative: leave the existing 6,583 themes drawers in place
and do not delete them, accepting that their source_file points at a path that no longer
exists. An orphaned source_file is only a problem for re-mine dedup and for “open the source”
affordances; it does not degrade recall. Re-mining themes to fix the path is not worth a
worktree dance. What it does need is the stale marker — and since the drawers already exist
with room = general, that requires a post-mine metadata write (§5.3), not a re-mine.
This is the one place where my recommendation cannot be delivered by mine-time config alone.
5. Supersession / recency mechanism
Section titled “5. Supersession / recency mechanism”The failure mode to defeat, from S517: a 1 July proposal out-ranked the DR-023/DR-025 ruling that superseded it two days later, with nothing in the result marking the supersession.
5.1 What is settable at mine time — no code change
Section titled “5.1 What is settable at mine time — no code change”source_mtime (float, unix epoch) is already written on 99% of projects-mode drawers and is
the recency signal the brief assumed did not exist. It is real os.getmtime, spread over 46
distinct days, and it tracks on-disk edit time. For a corpus edited in place in a working
checkout — which the docs-site is — it is a faithful “when was this last touched”.
content_date is also written (84% coverage) but must be treated with suspicion. Its
resolution order is filename → frontmatter date/created/published → first ISO date in the
first 10 body lines → mtime. Observed range on docs-site is 2011-09-10 to 2026-12-07 — a
14-year span including a date four months in the future, on a corpus that is at most two years
old. Those are dates mentioned in text, not authorship. It is a useful tiebreaker and a bad
sort key.
Two mine-time consequences worth acting on:
- ordna task files will get
content_date= mtime._try_frontmatter_datereads onlydate,created,published— not ordna’screated_at/updated_at. And_try_content_body_datescans only the first 10 lines after frontmatter, which for a task file is## Goalprose. So both earlier rungs miss and it falls through to mtime. That is accidentally the right answer, and it means no ledger schema change is needed. I considered recommending adate:alias key in task frontmatter (ordna round-trips extra keys untouched per AGENTS.md §3) and recommend against it: it would makecontent_dateequalupdated_at, which is day-granularity and bumped by every CLI write — no better than mtime, at the cost of polluting the ledger schema. content_dateis stamped once per file (miner.py:1499) and applied identically to every chunk. So per-section or per-## Progressdrawer granularity does not buy per-entry dates. This is a direct input to §6.
5.2 What the mine-time story cannot do
Section titled “5.2 What the mine-time story cannot do”source_mtime answers when. It does not answer what replaced this. Nothing in the metadata
schema expresses supersession, and _build_drawer_metadata has no custom-key passthrough, so a
superseded_by field is a miner code change, not a config change.
The room = archive marker from §4 is the available approximation: it is coarse (family-level,
not document-level) but it is free and it defeats the specific S517 failure for the DR-106
families, which is where the brief says the risk concentrates.
5.3 What needs a post-mine metadata write
Section titled “5.3 What needs a post-mine metadata write”Two things, both writes to embedding_metadata after mining, not miner changes:
- Re-room the retained orphans (themes, and any other lineage kept under §2.1) from
generaltoarchive. They cannot be re-mined, so config cannot reach them. - Optionally stamp
superseded_byon specific drawers where a DR explicitly supersedes a named document. This is the only mechanism that gets document-level supersession, and it requires a curated input list — realistically the[RATIFIED-RETIRE]rows of07-collapse-list.md, which the brief notes are usually sound.
I am not proposing (1) or (2) as part of the initial execution. Both are palace mutations beyond delete-and-re-mine, both need the vector layer healthy, and (2) needs owner input on the supersession list. They are follow-on work. §9 Q5.
5.4 The honest limitation
Section titled “5.4 The honest limitation”None of this makes vector search rank the ratified ruling above the superseded proposal.
Similarity scoring is unchanged. What it provides is a filter (room != archive) and a
sort key (source_mtime) that a disciplined recall path can apply. Per
runbooks/mempalace-repair.md §10.5 — “the recall path is tuned in the hook, not in the tool” —
the place to apply them is the recall wrapper, not the miner. The mining design can only make
the discriminators exist; it cannot make recall use them. That is a recall-grounding skill
change and is out of scope here, but the design is worthless without it. §9 Q6.
6. ordna task structure proposal
Section titled “6. ordna task structure proposal”6.1 Recommendation up front
Section titled “6.1 Recommendation up front”Mine tasks/ as part of the same docs-site project, into wing_canonical / room = tasks,
one drawer per ~800-char chunk of the whole file (i.e. the default chunker, no custom
granularity). Do not build a knowledge-graph layer. Make the cross-links traversable by relying
on the identifiers already present in the text.
The reasoning follows.
6.2 Wing and room
Section titled “6.2 Wing and room”Same wing (wing_canonical), own room (tasks). Rationale: the task ledger is not a separate
project — its entire value is being cross-referenced against specs, DRs and retros in the same
repo. Putting it in a separate wing would repeat exactly the mistake of F5, where filtering to
one wing silently hides related content. A room is the right granularity: it segments without
isolating.
tasks/ sits at the docs-site repo root, so a root-scoped mine picks it up with no extra
invocation, and the tasks keyword matches path part tasks at depth 1.
6.3 Granularity: whole file, default chunking
Section titled “6.3 Granularity: whole file, default chunking”The brief asks whether to split per-section or per-## Progress entry. Whole file, default
chunker. Three reasons, in order of weight:
- Per-entry drawers would not gain per-entry dates.
content_dateis computed once per file (§5.1). A## Progressentry from May and one from July would carry the identicalcontent_dateand identicalsource_mtime. The main reason to split — chronological precision — does not materialise. - The corpus is small enough that splitting solves no cost problem. 376 files, 2.17 MB,
≈3,190 drawers. Median file is 2,041 bytes — three drawers. Splitting a 3-drawer file by
section produces sub-
MIN_CHUNK_SIZEfragments that the chunker would merge back anyway. - Dated
## Progressheaders survive into the drawer text. The chronology is in the content, where a reader (human or model) can see it — which is more robust than metadata that recall may not filter on.
The p90 is 12,930 bytes (≈19 drawers) and the max 87,576 bytes (≈129 drawers). Even the largest
task file is a rounding error against task-list.json’s 3,996. There is no volume argument for
splitting.
Where I’d revisit this: if the owner wants recall to answer “what happened on task 163 in
S499 specifically”, per-## Progress-entry drawers with the entry date pushed into
content_date would help — but that needs the miner change from §5.2, so it is the same
follow-on decision.
6.4 Cross-link traversability — and why the KG tools are the wrong vehicle
Section titled “6.4 Cross-link traversability — and why the KG tools are the wrong vehicle”Assessment: the KG tools are not the right vehicle. I recommend against them. The brief asked me to judge from documented semantics plus the palace’s actual KG contents. Both point the same way.
Evidence 1 — the KG is empty. ~/.mempalace/knowledge_graph.sqlite3 holds 74 entities and
37 triples. Against a 402,267-drawer palace and a 376-task ledger, this is an unused feature,
not a substrate. Nothing has been invested that would be lost by not using it.
Evidence 2 — the auto-extracted entities are path noise and cannot carry the links that
matter. The mempalace_closets collection (4,611 closets) stores documents shaped
<label>|<entities>|<date>:<line-range>|→<drawer ids>. Ranking every entity value across the
palace:
| rank | entity | count |
|---|---|---|
| 1 | Status | 22,086 |
| 2 | canonical | 20,309 |
| 3 | Supabase | 15,291 |
| … | … | … |
| — | Users | 5,523 |
| — | Documents | 5,401 |
| — | Bash | 4,919 |
Users and Documents are segments of /Users/liamj/Documents/…. The top entity in the entire
palace is the word Status. Now the decisive test — do the identifiers the owner actually wants
to tie together appear?
| identifier class | distinct captured | universe |
|---|---|---|
DR-NNN | 44 | 114 DR files on disk |
id-N | 148 | 376 task files |
S### | 14 | ~500 sessions |
fr-NNN | 0 | friction register |
And the single most frequent DR-shaped entity is the literal placeholder string DR-NNN (189
occurrences) — more than any real DR (DR-081 at 26). The extractor is capturing template text.
An auto-built graph over these entities cannot express task ↔ spec ↔ DR ↔ session ↔ retro.
Evidence 3 — the existing tunnels confirm it. ~/.mempalace/tunnels.json is 228 KB of
auto-generated kind: entity tunnels linking wing_canonical ↔ sessions on shared entity
names. Samples: entity:AccordionItem, entity:AccordionTrigger — React component names. Every
one carries access_count: 0. The mechanism works and produces nothing anyone has used.
Evidence 4 — the links are already deterministic, so a probabilistic graph is the wrong tool. This is the real argument. The cross-links the owner wants are not latent facts needing extraction; they are declared in frontmatter and enforced by a documented convention:
| tie | where it is already declared |
|---|---|
| task → initiative | initiative: frontmatter (170/376 files), resolving to ledgers/initiatives/<N>.md via kebab(title) — DR-101 |
| initiative → tasks | Linked tasks: line in the initiative record — DR-101 requires both halves |
| task → session | session_refs: [S491, S492] (240/376) |
| task → docs | cross_doc_links: (108/376) |
| task → git | commit_refs: (52/376) |
| task → task | depends_on: (89/376) |
| task → spec dir | naming convention specs/id-N-<slug>/ — 100 of 124 spec dirs match id-* |
| session → retro | ledgers/retros/S###.md naming convention |
These are exact string keys. A vector-similarity graph is strictly worse than grep at
following them.
What I recommend instead: mine the task files whole (§6.3), so every one of those frontmatter
keys lands inside drawer text and is both semantically searchable and lexically exact-matchable
via embedding_fulltext_search. Traversal is then a deterministic two-step available to any
agent, with no palace feature involved:
- Recall on the task room to find the relevant
id-N. - Resolve its declared links by direct file read —
tasks/id-N.mdfrontmatter →specs/id-N-<slug>/,ledgers/initiatives/<N>.md,ledgers/retros/S###.md,git show <sha>.
This is the DR-010 three-way routing working as designed: the palace answers what was argued, the frontmatter and git answer when and where, the register answers what was decided. The KG would be a fourth, lossier copy of ties that are already exact.
Caveat on my confidence: I could not call kg_add / kg_query / create_tunnel /
follow_tunnels, so this judgement rests on stored state and documented semantics, not on
observed behaviour. If the owner has seen kg_query do something useful that these 37 triples
do not reflect, that would change the assessment.
7. Execution sequence
Section titled “7. Execution sequence”Precondition: the vector layer is deadlocked and must be repaired first. Per
runbooks/mempalace-repair.md §12.1 the cause is hnsw:sync_threshold: 2, written by
repair --mode from-sqlite, which sets divergence tolerance to 2 × threshold = 4; the fix is
pinning it to 1000. Nothing below runs until a mempalace status returns OK.
Two operational rules from the runbook govern every mutating step:
- §10.3a — bulk writes cannot get a clean window on a live machine.
mempal-stop-hook.shspawns a palace writer at the end of every turn of every live Claude session, including the one running the repair. A process sitting at 0% CPU is blocked onmine_palace_lock, not working. Quiesce all sessions first. - §12.3 — route bulk deletes through a warm MCP server, never a cold script. A cold client
deadlocks in
chromadb_rust_bindingsbefore opening any palace file. This is the same pathology that blocked this design session.
| # | Step | Checkpoint / rollback |
|---|---|---|
| 0 | Repair the vector layer (runbook §12.1): rollback artefact first, quiesce per §12.2, pin hnsw:sync_threshold: 1000, restore, verify. | mempalace status OK at unchanged divergence. Stop if not. |
| 1 | .backup snapshot of chroma.sqlite3. | Snapshot exists and is non-zero. Restore point for everything below. |
| 2 | Re-run the §0.1 census from lock-free sqlite; regenerate removal-*.txt against current state. | Counts match this document (107,938 / 833 / 63,153) or the delta is explained. The lists here are a 2026-07-31 snapshot. |
| 3 | Owner decision gate — split R1 per §2.1 (delete supersessions vs retain lineage). | Explicit owner sign-off on which of themes / continuation-prompts are deleted. Blocking: this is irreversible. |
| 4 | Generate the sub-130 stale-spec keyword block for the archive room (§3.3 constraint 2). | Enumerated dir list reviewed. Or skip per §9 Q3. |
| 5 | Land the new mempalace.yaml (§3.3). | Config only, no palace effect. Reversible by git. |
| 6 | Dry-run the mine (no writes) and dump the projected file→room mapping. | The critical checkpoint. Verify: tasks/ present; reference/decisions/** present; DR-106 families → archive; ledgers’ three children → correct rooms (§3.3 constraint 3); zero .json/.jsonl/.yaml/.html; src/ code absent. Iterate on the yaml until clean — no palace state has changed yet. |
| 7 | Pilot delete: 10 paths from removal-R2 via warm MCP. | sqlite row counts drop to 0 for exactly those paths. Per §11 the metadata segment applies deletes even when the job reports failure — verify sqlite, not the job’s exit status. |
| 8 | Full delete wave, class by class, R2 → R3 → R4 → R5 → R1(as gated at step 3). | Per-class sqlite verification against the §2 manifest. Existing tooling: ~/.mempalace/tools/prune-stage.py. |
| 9 | repair --mode from-sqlite in a solo window, then runbook §6 verify. | Re-pin sync_threshold: 1000 afterwards — the rebuild writes 2 (§12.1). This is the step that most recently broke the palace; do not skip the re-pin. |
| 10 | Mine the docs-site root (both corpora, one pass). | Expect ≈44,785 surviving + ≈3,190 tasks + the 310-file backfill. Verify room distribution is no longer 100% general. |
| 11 | Post-mine verification census. | reference/decisions = 114 files mined; tasks room ≈3,190 drawers; archive room populated; no family still 100% general. |
| 12 | (Deferred) Re-room retained orphans to archive (§5.3). | Separate window, separate decision. |
Ordering rationale: delete before re-mine, because re-mining first would leave both the old
and new drawers present with no way to tell them apart (filed_at would differ, but §2 shows
past mines already span three dates). The repair at step 9 sits between delete and mine
because it is what makes the vector-side deletion real (§11) — mining into a store with pending
un-applied delete logs is how the poisoned WAL happened.
8. Wing hygiene
Section titled “8. Wing hygiene”Flagging, not solving — but it is smaller than the brief’s estimate suggests.
158 distinct wings exist. The junk tail is 147 wings holding 722 drawers between them — 0.18%
of the palace. Named examples: wing_dataflow (38), wing_subo_backlog (35), wing_audit (34),
wing_subo_147_waves (28), wing_id104 (24), wing_off (19), wing_35 (11). The pattern is
clear: ad-hoc --wing values from sub-agent dispatches, mostly wing_subo_*.
Recommendation, in priority order:
- Fix the cause first. These come from
--wingoverrides on ad-hoc mines. The §3.3 config removes the need for overrides on this repo by making one root mine correct. Any remaining dispatch that passes--wingshould be found and stopped, or the tail regrows. - The high-value merge is not the tail — it is F5. Folding
specs(14,272),handoffs(829),runbooks(605) andreference(359) back intowing_canonicalfixes a correctness problem: today, recall filtered towing_canonicalmisses 356 docs-site files, and recall filtered towing=specsmisses 313 of 572 mined specs. This happens automatically as a consequence of the §7 re-mine — those files are deleted or re-mined intowing_canonicalwith the config wing. No separate merge step needed. - The 722-drawer tail is genuinely low priority. It is small enough to leave. The runbook already documents a “wing-name normalisation sweep” (§5) if the owner wants it swept; it is not worth a dedicated window on its own and should ride along with a future repair.
9. Open questions for the owner
Section titled “9. Open questions for the owner”Q1 — Delete or retain the orphaned lineage? (blocking, §2.1, §7 step 3)
removal-UNION.txt as delivered deletes all 481 orphans, including 98 themes/ files (6,583
drawers) and 70 continuation-prompts. I recommend retaining both under DR-010 — themes is the
predecessor of initiatives/, deleted by one deliberate commit, and is the only surviving record
of that framing. But 290 orphaned ledgers/ files that ordna superseded should go. I have not
pre-split the list because “delete the lineage” is your call, not mine. Executing the union
as-is destroys the themes lineage.
Q2 — ledgers/archive co-location (§3.1).
You said ledgers/archive should move to co-locate with the ordna tasks. That is a docs-site
content refactor, not a mining decision, and doing it after mining creates 105 fresh orphans.
Do you want the move done first, or should I mine in place and accept re-pointing later?
Q3 — Is the sub-130 spec split worth its maintenance cost? (§3.3 constraint 2)
Routing stale specs to archive requires enumerating ~60 spec directories as room keywords, and
regenerating that block as tasks age. The alternative is one specs room where DR-106’s
“below ~130 unless re-affirmed” rule stays a matter of reader discipline. I lean toward
skipping it — the rule has an “unless re-affirmed” clause that no static config can evaluate
anyway — but it is your stale-content risk.
Q4 — 01-vision.md (§4.1).
DR-106 exempts it from an otherwise-stale tree, but path-keyword routing cannot exempt one file:
it will land in archive with its siblings. Accept, or move it up a directory in the docs-site?
Q5 — Post-mine metadata writes (§5.3).
Re-rooming retained orphans to archive, and stamping document-level superseded_by from
07-collapse-list.md’s [RATIFIED-RETIRE] rows, are both palace mutations beyond
delete-and-re-mine. I have deliberately excluded them from §7. Do you want them scoped as
follow-on work?
Q6 — Who applies the discriminators? (§5.4)
This design makes room != archive and source_mtime exist. It cannot make recall use them.
Per runbook §10.5 the recall path is tuned in the hook, not the tool. Without a matching
recall-grounding / hook change, the supersession mechanism has no effect on what you actually
see. Is that in scope for the same initiative?
Q7 — Confirm the KG verdict (§6.4).
I recommend against the KG tools based on 74 entities / 37 triples, entity extraction whose top
result is the word Status and whose most common DR is the literal string DR-NNN, and 228 KB
of tunnels with access_count: 0. I could not call kg_query to test it live. If you have seen
it work, say so — it is the one conclusion here I could not verify by execution.
Q8 — reports/ and the 310-file backfill (§1.2 F3).
120 unmined reference files (114 of them DRs), 31 of 37 reports/, 110 specs. I have tiered all
of them as mine-me. Is any of that deliberately withheld — anything with client IP or otherwise
not wanted in the palace?
Appendix — artefacts written
Section titled “Appendix — artefacts written”All in
/private/tmp/claude-501/-Users-liamj-Documents-development-canonical/46f450b2-86bd-4602-b2da-8d0097252e2a/scratchpad/:
| file | contents |
|---|---|
mine-design-docs-site-and-ordna.md | this document |
removal-R1-orphans.txt | 481 paths — gone from disk |
removal-R2-workflow-eval-telemetry.txt | 259 paths — machine telemetry |
removal-R3-legacy-json-ledgers.txt | 5 paths — pre-ordna JSON ledgers |
removal-R4-spec-sidecars.txt | 93 paths — spec authoring machinery |
removal-R5-stray-binary.txt | 1 path — stray HTML |
removal-UNION.txt | 833 de-duplicated paths, 63,153 drawers |
gap-unmined-md.txt | 310 on-disk markdown files never mined |
ondisk_md.txt, mined_md.txt | inputs to the gap comparison |
Pre-existing from the salvaged session: mined_paths.txt, orphan_paths.txt,
prune-targets.txt, prune-backup-s355-stage.jsonl.
10. S518 deltas — owner rulings and corrected preconditions
Section titled “10. S518 deltas — owner rulings and corrected preconditions”Added by the main session after the design was written. Two owner rulings and three corrections. Where this section conflicts with anything above, this section wins.
10.1 Owner ruling — workflow-evaluation/ is pruned entirely, not tiered
Section titled “10.1 Owner ruling — workflow-evaluation/ is pruned entirely, not tiered”Owner, S518: “where we’ve changed our dev-workflow and no longer use cmux — the previous content can now be pruned, with no current requirement to mine until we update our docs-site workflow evaluator agent, based on the new dev workflow.”
This supersedes §3.1’s T2 row for workflow-evaluation/*.md. The 6 markdown files
(208 drawers) join the telemetry in the removal set rather than being mined as lineage.
- New list:
removal-R6-workflow-eval-all.txt— 265 paths, 43,887 drawers (the whole family, not just the non-.mdtelemetry). - New union:
removal-UNION-v2.txt— 839 paths (was 832). - §3.3 yaml changes: drop the
!src/content/docs/workflow-evaluation/*.mdnegation and exclude the tree outright. Dropworkflow-evaluationfrom thelineageroom keywords. - Re-mining is gated on the workflow-evaluator agent being rebuilt for the new dev workflow — not on this design.
One narrow exception flagged for owner confirmation, deliberately NOT actioned:
workflow-evaluation/s-number-crosswalk.md is an S-number crosswalk, and §6.4 names
S### as one of the six cross-link legs that make the ordna structure traversable.
friction-register.md is likewise the home of the fr-NNN identifier class. Both are
prose reference material that happens to sit in a telemetry tree. Pruning them is
consistent with the ruling as stated; re-homing them (e.g. to reference/) before the
prune would preserve two load-bearing crosswalks. Owner’s call — the default here is
prune, per the ruling.
10.2 Owner ruling — themes/ → initiatives/ was a rename
Section titled “10.2 Owner ruling — themes/ → initiatives/ was a rename”Owner, S518: “themes/ was renamed to initiatives/.” This confirms §1.2 F4, which
reached the same conclusion independently from commit fa71b6bf.
It does not settle §9 Q1. If the rename carried the content forward, the 98 orphaned
themes/ files are a duplicate of initiatives/ under an old name and the DR-010 lineage
argument for retaining them weakens considerably. If it was a restructure that dropped
material, the argument stands. Q1 remains open, with that framing added.
10.3 Correction — §7 step 0’s stated precondition is wrong
Section titled “10.3 Correction — §7 step 0’s stated precondition is wrong”§7 step 0 says the vector layer is fixed by pinning hnsw:sync_threshold to 1000, citing
runbook §12.1. That is no longer the operative diagnosis, and S518 disproved it directly:
the threshold was reverted 1000 → 2 and back, and the deadlock was unchanged either way.
The pin is still required (DR-110) but it is not the fix for the current fault.
The current fault is a deadlock — every operation that opens the chroma collection hangs
in chromadb_rust_bindings (_pthread_cond_wait/__psynch_cvwait), reproduced six ways:
warm MCP search, warm MCP delete dry-run, cold client with the daemon up, cold client with
zero palace holders, cold client with device=cpu, cold client with sync_threshold=2.
Step 0 is therefore: run ~/repair-palace-s518.sh — a from-sqlite rebuild with the
DR-110 re-pin built in as a verified step, plus smoke tests on both broken paths. It is not
a confirmed fix for this failure mode (S506 proved the rebuild against the segfault
pathology, not this one); if its smoke tests fail, pgvector migration is the standing
escalation per id-299’s S452 ruling.
10.4 Correction — §7’s two operational rules are both stale
Section titled “10.4 Correction — §7’s two operational rules are both stale”- “§12.3 — route bulk deletes through a warm MCP server, never a cold script.” S518 disproved this: the main session’s warm MCP server deadlocked identically to a cold one. Warm-vs-cold is not the variable. Until the repair lands and its smoke tests pass, no route works and no delete step below can be attempted.
- §7 step 8 cites
~/.mempalace/tools/prune-stage.pyas the tooling. That script doesfrom mempalace.mcp_server import tool_delete_by_sourcein a fresh process — it is the cold-client shape §12.3 warns against. Do not use it as written.
10.5 Correction — runbook §12.2’s stale-lock guard has never worked
Section titled “10.5 Correction — runbook §12.2’s stale-lock guard has never worked”The lock file ~/.mempalace/locks/mine_palace_<hash>.lock begins with a NUL byte, so
§12.2’s P=$(awk '{print $1}' "$L") always returns empty, ps -p "" always fails, and the
lock is cleared unconditionally — including when a live writer holds it. The guard has never
fired. Correct parse: tr -d '\0' < "$L" | awk '{print $1}', refusing on an empty result.
Fixed in ~/repair-palace-s518.sh; the runbook still needs patching.
11. Ratified — S518 owner decisions (board s518-mine-design-oq-board)
Section titled “11. Ratified — S518 owner decisions (board s518-mine-design-oq-board)”Eight of nine ratified by the owner. These are binding; where they conflict with §3–§9, these win.
| Q | Ruling | vs recommendation |
|---|---|---|
| Q1 | Delete all 481 orphans, including themes/ | overridden (rec: split) |
| Q2 | Do the ledgers/archive move as a docs-site refactor before the mine | as recommended |
| Q3 | Skip the sub-130 spec split — one specs room; DR-106 stays reader discipline | as recommended |
| Q4 | Move 01-vision.md up a directory so path routing keeps it out of archive | as recommended |
| Q5 | Scope both post-mine metadata writes as follow-on after the mine lands | as recommended |
| Q6 | In scope for id-383 — update recall-grounding + the recall hook in the same initiative | as recommended |
| Q7 | NOT RATIFIED — see §11.2 | reframed by owner |
| Q8 | Nothing withheld — mine all 310 backfill files | as recommended |
| Q9 | Prune the entire workflow-evaluation/ tree, both crosswalks included | overridden (rec: re-home) |
11.1 Reversibility corrections to the two overrides
Section titled “11.1 Reversibility corrections to the two overrides”Both overrides are cheaper than the board implied. Verified S518:
- Q1 /
themes/— the board card said “no on-disk copy exists”. Literally true, but it understated recoverability:git ls-tree fa71b6bf^ -- src/content/docs/themes/returns all 105 files. The lineage is fully recoverable from git and can be re-mined from a worktree at that ref if it is ever wanted. §4.2 already assumed exactly that mechanism. Deleting is reversible; the correction does not change the ruling, and it removes the stated risk. - Q9 / crosswalks —
friction-register.md(31 KB) ands-number-crosswalk.md(6 KB) are still on disk;workflow-evaluationhas zero orphans. Pruning removes them from the palace only. Re-mining restores them when the evaluator agent is rebuilt for the new dev workflow.
Net effect on the removal set: removal-UNION-v2.txt is executed as delivered, unsplit —
839 paths. Q1 requires no sub-setting of R1, and Q9 is already folded in as R6.
11.2 Q7 — the KG verdict is NOT ratified; owner reframed the question
Section titled “11.2 Q7 — the KG verdict is NOT ratified; owner reframed the question”Owner, S518: “The intent is to be able to use the KG, stripping back redundancy and duplication, to reveal what’s valuable.”
This inverts §6.4’s framing. §6.4 read the KG’s current state (74 entities / 37 triples, top
entity Status, path segments as entities) as evidence the feature is unusable. The owner’s
position is that those symptoms are downstream of the palace’s redundancy, and that the
prune is the precondition for evaluating the KG, not a reason to abandon it.
That is a materially better read than §6.4’s, and the ordering favours it: every input to §6.4’s verdict changes under the ratified plan.
| §6.4 evidence | what the ratified plan does to it |
|---|---|
Top entities are Status, Users, Documents, Bash — path/telemetry noise | Q9 removes 43,887 telemetry drawers; R3/R4 remove machine serialisations. The dominant noise source is deleted. |
Only 44 of 114 DR-NNN captured | Q8 mines all 114 DR files — currently 0 are mined. The register cannot be in the graph because it was never in the palace. |
Only 14 of ~500 S### captured | Retros + session_refs frontmatter enter via the tasks corpus (≈3,190 drawers, currently 0). |
id-N: 148 of 376 | All 376 task files mined for the first time. |
Revised recommendation: do not rule on the KG now. Re-run the §6.4 entity census after step 11 of the execution sequence and rule on the post-prune, post-backfill numbers.
Two caveats that the prune does not fix, and which must be checked in that re-census:
- The extractor captures template text. The most frequent DR-shaped entity is the literal
placeholder string
DR-NNN(189×) — it out-ranks every real DR. Pruning duplication does not stop the extractor matching placeholders in doc templates; mining 114 real DR files should swamp it, but verify rather than assume. access_count: 0across 228 KB of tunnels. Nothing has ever read them. Even a clean graph is inert without a consumer — which is the same dependency as Q6. The KG question and the recall-path question resolve together, or neither does.
Action: §6.4’s “recommend against” is withdrawn and replaced by a deferred re-evaluation gate at step 11. Q7 stays open.