Skip to content

Commit 6d640a6

Browse files
fix(memory-wiki): honor durable: true frontmatter in stale pages report
The Stale Pages report previously flagged every non-report page whose updatedAt was older than 30 days, including intentionally durable references such as concept and synthesis pages. Bridge-mode vaults typically have many such pages, drowning out real staleness signal. This change adds a strict boolean `durable` frontmatter marker. Pages with `durable: true` are excluded from the stale-pages filter at compile time. The marker is strict (asBoolean only accepts real booleans, not string literals), is opt-in, and does not touch updatedAt, so other freshness signals remain accurate. Lint and agent-digest callers are unaffected; the change is scoped to the dashboard report filter. Fixes #93485 Co-Authored-By: Claude Opus 4.8 <[email protected]>
1 parent 60d6a8a commit 6d640a6

5 files changed

Lines changed: 151 additions & 0 deletions

File tree

docs/plugins/memory-wiki.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,24 @@ These reports track things like:
311311
- evidence class coverage
312312
- non-public privacy tiers that need review before use
313313

314+
### Opting pages out of the Stale Pages report
315+
316+
Concept, synthesis, and other intentionally durable reference pages should
317+
not be flagged by the 30-day / 90-day freshness thresholds in
318+
`reports/stale-pages.md`. Mark any such page with a strict boolean frontmatter
319+
field:
320+
321+
```yaml
322+
---
323+
durable: true
324+
---
325+
```
326+
327+
`memory-wiki` excludes pages where `durable: true` is set from the Stale Pages
328+
report. Use this for concepts, syntheses, and other reference material whose
329+
value comes from durability rather than recency. The marker does not change
330+
`updatedAt`, so other freshness signals remain accurate.
331+
314332
## Search and retrieval
315333

316334
`memory-wiki` supports two search backends:

extensions/memory-wiki/src/compile.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,67 @@ describe("compileMemoryWikiVault", () => {
559559
);
560560
});
561561

562+
it("excludes durable pages from the Stale Pages report", async () => {
563+
const { rootDir, config } = await createVault({
564+
rootDir: nextCaseRoot(),
565+
initialize: true,
566+
});
567+
568+
const oldTimestamp = "2024-01-01T00:00:00.000Z";
569+
570+
await fs.writeFile(
571+
path.join(rootDir, "concepts", "alpha-concept.md"),
572+
renderWikiMarkdown({
573+
frontmatter: {
574+
pageType: "concept",
575+
id: "concept.alpha",
576+
title: "Alpha Concept",
577+
updatedAt: oldTimestamp,
578+
durable: true,
579+
},
580+
body: "# Alpha Concept\n",
581+
}),
582+
"utf8",
583+
);
584+
await fs.writeFile(
585+
path.join(rootDir, "syntheses", "alpha-synthesis.md"),
586+
renderWikiMarkdown({
587+
frontmatter: {
588+
pageType: "synthesis",
589+
id: "synthesis.alpha",
590+
title: "Alpha Synthesis",
591+
updatedAt: oldTimestamp,
592+
durable: true,
593+
},
594+
body: "# Alpha Synthesis\n",
595+
}),
596+
"utf8",
597+
);
598+
await fs.writeFile(
599+
path.join(rootDir, "concepts", "beta-concept.md"),
600+
renderWikiMarkdown({
601+
frontmatter: {
602+
pageType: "concept",
603+
id: "concept.beta",
604+
title: "Beta Concept",
605+
updatedAt: oldTimestamp,
606+
},
607+
body: "# Beta Concept\n",
608+
}),
609+
"utf8",
610+
);
611+
612+
await compileMemoryWikiVault(config);
613+
614+
const stalePages = await fs.readFile(
615+
path.join(rootDir, "reports", "stale-pages.md"),
616+
"utf8",
617+
);
618+
expect(stalePages).not.toContain("Alpha Concept");
619+
expect(stalePages).not.toContain("Alpha Synthesis");
620+
expect(stalePages).toContain("Beta Concept");
621+
});
622+
562623
it("skips dashboard report pages when createDashboards is disabled", async () => {
563624
const { rootDir, config } = await createVault({
564625
rootDir: nextCaseRoot(),

extensions/memory-wiki/src/compile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const DASHBOARD_PAGES: DashboardPageDefinition[] = [
214214
.filter(
215215
(page) =>
216216
page.kind !== "report" &&
217+
page.durable !== true &&
217218
!(
218219
isUnmanagedRawSourceSummary(page) &&
219220
!managedImportedSourcePagePaths.has(page.relativePath)

extensions/memory-wiki/src/markdown.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,74 @@ describe("toWikiPageSummary", () => {
325325
expect(crlfStructuredSource?.pageType).toBe("source");
326326
});
327327

328+
it("parses the durable opt-in flag from frontmatter strictly", () => {
329+
const trueDurable = toWikiPageSummary({
330+
absolutePath: "/tmp/wiki/concepts/concept-durable-true.md",
331+
relativePath: "concepts/concept-durable-true.md",
332+
raw: renderWikiMarkdown({
333+
frontmatter: {
334+
pageType: "concept",
335+
title: "Concept Durable True",
336+
updatedAt: "2024-01-01T00:00:00.000Z",
337+
durable: true,
338+
},
339+
body: "# Concept Durable True\n\ndurable reference",
340+
}),
341+
});
342+
expect(trueDurable?.durable).toBe(true);
343+
344+
const falseDurable = toWikiPageSummary({
345+
absolutePath: "/tmp/wiki/concepts/concept-durable-false.md",
346+
relativePath: "concepts/concept-durable-false.md",
347+
raw: renderWikiMarkdown({
348+
frontmatter: {
349+
pageType: "concept",
350+
title: "Concept Durable False",
351+
updatedAt: "2024-01-01T00:00:00.000Z",
352+
durable: false,
353+
},
354+
body: "# Concept Durable False\n\ndurable opt-out",
355+
}),
356+
});
357+
expect(falseDurable?.durable).toBe(false);
358+
359+
const stringDurable = toWikiPageSummary({
360+
absolutePath: "/tmp/wiki/concepts/concept-durable-string.md",
361+
relativePath: "concepts/concept-durable-string.md",
362+
raw: renderWikiMarkdown({
363+
frontmatter: {
364+
pageType: "concept",
365+
title: "Concept Durable String",
366+
updatedAt: "2024-01-01T00:00:00.000Z",
367+
durable: "true",
368+
},
369+
body: "# Concept Durable String\n\ndurable opt-in via string is not honored",
370+
}),
371+
});
372+
expect(stringDurable?.durable).toBeUndefined();
373+
374+
const missingDurable = toWikiPageSummary({
375+
absolutePath: "/tmp/wiki/concepts/concept-durable-missing.md",
376+
relativePath: "concepts/concept-durable-missing.md",
377+
raw: renderWikiMarkdown({
378+
frontmatter: {
379+
pageType: "concept",
380+
title: "Concept Durable Missing",
381+
updatedAt: "2024-01-01T00:00:00.000Z",
382+
},
383+
body: "# Concept Durable Missing\n\ndurable opt-in missing",
384+
}),
385+
});
386+
expect(missingDurable?.durable).toBeUndefined();
387+
388+
const noFrontmatterDurable = toWikiPageSummary({
389+
absolutePath: "/tmp/wiki/concepts/concept-durable-no-frontmatter.md",
390+
relativePath: "concepts/concept-durable-no-frontmatter.md",
391+
raw: "# Concept Durable No Frontmatter\n\nno frontmatter block",
392+
});
393+
expect(noFrontmatterDurable?.durable).toBeUndefined();
394+
});
395+
328396
it("normalizes agent-facing people wiki metadata", () => {
329397
const raw = renderWikiMarkdown({
330398
frontmatter: {

extensions/memory-wiki/src/markdown.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { createHash } from "node:crypto";
33
import path from "node:path";
44
import {
5+
asBoolean,
56
asFiniteNumber,
67
normalizeLowercaseStringOrEmpty,
78
normalizeOptionalString,
@@ -107,6 +108,7 @@ export type WikiPageSummary = {
107108
unsafeLocalRelativePath?: string;
108109
lastRefreshedAt?: string;
109110
updatedAt?: string;
111+
durable?: boolean;
110112
};
111113

112114
const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
@@ -626,5 +628,6 @@ export function toWikiPageSummary(params: {
626628
unsafeLocalRelativePath: normalizeOptionalString(parsed.frontmatter.unsafeLocalRelativePath),
627629
lastRefreshedAt: normalizeOptionalString(parsed.frontmatter.lastRefreshedAt),
628630
updatedAt: normalizeOptionalString(parsed.frontmatter.updatedAt),
631+
durable: asBoolean(parsed.frontmatter.durable),
629632
};
630633
}

0 commit comments

Comments
 (0)