Persisted formats

This inventory lists every format Deckard writes and later reads back, so that an upgrade in place keeps reading what the previous release wrote. It names each format, where it is written and read, its version marker, its migrations, and the test that pins it. It was taken at dev 1805a01, before Phase 0 of the refactor plan, and every path:line below is 1-based at that commit.

Summary

“Pinned” means a test asserts the stored shape or the literal key. A test that imports a key constant pins behavior, but it keeps passing if the constant’s value changes. Test files named without a folder are in src/test/.

# Format Store Version marker Pinned by
1 Preferences blob, deckard.preferences globalState and workspaceState version: 1 field, not checked on read preferences.test.ts, preferences-prune.test.ts, pinned-notes.test.ts; partly
2 Handover flag, deckard.preferences.workspaceScoped globalState none preferences-prune.test.ts
3 deckard.lastSeenVersion globalState none whats-new.test.ts, by constant
4 deckard.whatsNewPending globalState none whats-new.test.ts, by constant
5 deckard.openSampleReadme globalState none sample-workspace.test.ts, value only
6 deckard.lastReminderDate globalState none task-status-bar.test.ts, by constant
7 deckard.excludeHintShown workspaceState none none yet
8 deckard.firstIndexSummaryShown workspaceState none first-index.test.ts, by constant
9 deckard.tryNext.retired and deckard.tryNext.snoozed workspaceState none none yet
10 deckard.capture.draft workspaceState none capture.test.ts, shape only
11 Whether any memento key exists (keys()) globalState and workspaceState none none yet
12 MCP server token, deckard.mcpServer.token SecretStorage none mcp-server.test.ts, value only
13 SQLite search cache schema, deckard-search.sqlite storageUri SCHEMA_VERSION = 3 as PRAGMA user_version search-store.test.ts
14 Parse fingerprint, meta row parse SQLite cache the fingerprint is the marker search-store.test.ts, warm-start.test.ts; partly
15 Last scan counts, meta row lastScan SQLite cache none search-store.test.ts, warm-start.test.ts
16 Parsed note encoding, notes.parsed SQLite cache FORMAT = 1 as field v parsed-file-codec.test.ts; partly
17 Preference snapshots, preference-snapshots/*.json storageUri the blob’s version: 1 preference-backups.test.ts
18 Preference export file a file the reader picks deckard.version: 1, not checked on read preference-backups.test.ts
19 Sample workspace folder, deckard-sample globalStorageUri none sample-workspace.test.ts
20 Search page state, view type deckard.tagOverview webview state none search-page-behavior.test.ts, webview-saved-state.test.ts, searchPage.e2e.js
21 Task Board state, view type deckard.taskBoard webview state none taskBoard.e2e.js, webview-saved-state.test.ts
22 Dashboard state, view type deckard.dashboard webview state none dashboard-behavior.test.ts, webview-saved-state.test.ts
23 Notes graph state, view type deckard.notesGraph webview state none notes-graph-behavior.test.ts, parked-views.test.ts, webview-saved-state.test.ts
24 Calendar page state, view type deckard.calendarPage webview state none webview-saved-state.test.ts, calendar.test.ts
24a Help state, view type deckard.help, since Phase 6 step 4.1: { guide?: { page, anchor? }, scrollY, drawn }, read only by the drawing of the page that saved it webview state drawn, a hash of the HTML’s nonce help-page.test.ts
24b Related Notes state, view deckard.relatedNotes, since Phase 6 step 4.6: what the reader chose in it, and its scroll webview state none webview-saved-state.test.ts
24c Stats state, view type deckard.stats, since Phase 6 step 4.2: { showAllOrphans, showUsedOnce, pairsAsTable, scrollY? } webview state none stats.test.ts
25 Entry ids, tag keys, and Find keys stored inside rows 1, 9, and 17 inside other formats none preferences-prune.test.ts, preferences.test.ts; relative only
26 Settings Deckard writes settings.json none exclude-folders.test.ts, settings.test.ts; partly
27 Tag visits, since plan 37: deckard.tagVisits in workspaceState (each tag’s visit time, by tag key, at most 500, the oldest dropped first), each tag’s snapshot in a file of the workspace’s storage folder, tag-visits/<shortHash of the tag key>.json ({ tag, visit: { seenAt, entries, tasks: { open, done }, fields, answered?, ordinals? } }, written beside it and moved over it; a file whose tag is another’s reads as none; a key ending ~n is the n+1th entry, task, or question of its note with the same words, which a visit without ordinals counts as no change; no folder open, no files), and the Hubs view’s sort, deckard.hubs.sort ('new', or nothing for by name); src/core/storage/tagVisits.ts, read by readTagVisit, which reads any other shape as no visit. The snapshots an earlier build kept in workspaceState as deckard.tagVisit:<tag key> are removed at start (dropStoredSnapshots) workspaceState and context.storageUri none since-last-looked.test.ts
28 Not a promise, since plan 41: deckard.notPromises, a list of <note URI>\u0000<hash of the line's words>, the latest last, at most 500; src/core/storage/promiseDismissals.ts, which reads anything but a list of text as none workspaceState none promises.test.ts
29 Questions, since plan 38: deckard.questions.notIt, a list of <question's note>\u0000<hash of the question's words>\u0000<hash of the line's words> set aside with Not it, the latest last, at most 500; and deckard.questions.missedSearches, Find’s searches that found nothing, by their words, each { count, first, last }, at most 200, read into a map, so any words, __proto__ among them, are a key of their own; src/core/storage/questionMemory.ts, which reads anything else as none workspaceState none questions-view.test.ts
30 Written before, since plan 39: deckard.writtenBefore.notSame, a list of <hash of a line's words>\u0000<hash of the older line's> set aside with Not the same, the latest last, at most 500; src/core/storage/writtenBeforeMemory.ts, which reads anything but a list of text as none workspaceState none written-before-editor.test.ts

Deckard calls no setKeysForSync, so no memento key travels with Settings Sync. Deckard uses no logUri. The Deckard output channel (src/extension.ts:214) writes a log that Deckard never reads back.

Out of scope: note syntax

Task metadata, front matter, block ids (^id), query blocks, and every other syntax Deckard writes into notes are the user’s own content. The parser tests cover how they are read, so this inventory leaves them out. Files Deckard writes and never reads back, such as an exported result list (src/ui/commands/exportResults.ts:164), are left out too.

1. Preferences blob

Migration Where it runs What it converts Pinned by
Machine-wide to per-workspace (1.19) constructor :255, initialize :278 The first workspace opened with no blob of its own adopts the workspace keys of the machine-wide blob, then sets the handover flag (row 2) preferences-prune.test.ts:172, :194, :209, :239
Rendered becomes the default normalizePreferences :1244 A stored renderMode: 'markdown' without renderModeChosen: true reads as 'html' preferences.test.ts:99
Dashboard tabs removed normalizeDashboardViewState :1538 Any dashboardViewState.mode other than 'browse', such as 'tasks' or 'notes', reads as 'home'. The other old view-state fields are dropped preferences.test.ts:234, :267
Retired keys normalizePreferences :1189 dashboardTaskLayout, dashboardNoteSortMode, and any other unnamed key are dropped preferences.test.ts:234, :267
Home widgets added normalizePreferences :1299 A blob with no dashboardWidgets array gets DEFAULT_DASHBOARD_WIDGETS (:153) preferences.test.ts:267
Pins by path normalizePinnedNotes :1569 A string pin reads as { filePath } pinned-notes.test.ts:109
Ids widened (1.23) prune :973, carryLegacyIds :1773 taskOrder, sectionAccessCounts, and sectionAccessTimes keyed by an old one-hash id move to the new id whose first half it is (legacyIdOf, src/core/markdown/parser.ts:1880) preferences-prune.test.ts:25
First-seen times prune :1000 A blob with no tagFirstSeen marks every indexed tag as 0, meaning known before times were kept preferences.test.ts:358
Saved filters normalizeSavedFilters :1647 Drops filters with no name, fewer than two tags and no query, or a duplicate id or tag set preferences.test.ts:467

Phase 6 changed no stored shape and no migration. Since step 4.7, normalizeDashboardWidgets (src/core/storage/preferencesSchema.ts) recognizes a stored widget’s kind with isWidgetKind over WIDGET_KINDS in src/domain/dashboard/widgetCatalog.ts, the catalog the Dashboard page reads too, in place of DASHBOARD_WIDGET_KINDS; the kinds and the traits it reads are the same, and widget-catalog.test.ts pins them.

preferences-invariants.test.ts walks random operations over the store with in-memory mementos. It pins what operations keep and remove, and that one workspace never reaches another (:228). It does not pin a stored shape.

Pinned since Phase 3: src/test/preferences-roundtrip.test.ts loads a complete blob, with every field set to a non-default value, split across globalState and workspaceState, and asserts what it normalizes to and the exact bytes written back to each store. It also loads each legacy shape the migrations read (the 1.19 handover, renderMode without renderModeChosen, the removed Dashboard tabs, retired keys, string pins and headings, one-hash ids from before 1.23, a missing tagFirstSeen) and walks every mutator, recording each write’s store, key, order, and digest. The blob is made up rather than captured from a release, so a field 1.23.1 writes that the type does not declare would not be caught.

2. Handover flag

The plan names “its workspace-scoped twin”. The twin is the workspaceState copy of deckard.preferences (row 1). This flag is a separate key.

3. Last version seen

4. What’s new pending

5. Sample README to show

6. Last reminder date

The plan’s list of seven memento keys does not include this one.

7. Exclude hint shown

8. First index summary shown

9. Try next ledger

The plan’s list of seven memento keys does not include these two.

10. Capture draft

The plan’s list of seven memento keys does not include this one.

11. Whether Deckard ran before

12. MCP server token

The plan’s list does not include this store.

13. SQLite search cache schema

14. Parse fingerprint

15. Last scan counts

16. Parsed note encoding

17. Preference snapshots

18. Preference export file

19. Sample workspace

Webview state

This section is as of the end of Phase 6, when every page became a bundle under src/webview/<page>/; its paths name functions rather than lines.

VS Code keeps what a page passes to setState and hands it back when it restores the panel after a reload, through the serializers registerSerializers registers in src/composition/services.ts. A page restored after an upgrade receives state written by the old script. Seven panel view types are serialized: deckard.dashboard, deckard.stats, deckard.help, deckard.notesGraph, deckard.calendarPage, deckard.taskBoard, and deckard.tagOverview; only the last two hand the state to the host’s restore. The sidebar views deckard.relatedNotes and deckard.calendar are webview views (registerViews, the same file); VS Code hands a view’s state back to the page it loads again, though a view has no serializer. The Related Notes debug panel has no serializer and runs no script.

Since decision 0017, which replaced 0006, a page not kept running while hidden is loaded again each time it is shown, so what the reader chose in it must come back from setState. Each page’s controller under src/ui/webview/pages/ sets retainContextWhenHidden:

Page Kept running while hidden What it keeps with setState Row
Dashboard yes its view: mode, columns, tag search, namespace filter, arranging, hint 22
Search page yes its search, origin, tab, and scroll 20
Task Board yes its search and scroll 21
Notes Graph yes its 23 settings and its camera 23
Stats no three choices and its scroll 24c
Help no the guide page shown and its scroll 24a
Calendar page no its layout and scroll 24
Calendar view no nothing  
Related Notes no the reader’s choices and its scroll 24b
Related Notes debug page no nothing; it runs no script  

A page reads what it kept through keptState, src/webview/shared/vscode.ts, which reads anything but a record as nothing kept, and writes through keepState, which merges a change over what was kept; the search page, the Task Board, and the Notes Graph read getState() themselves, as their template scripts did, and Help keeps its own record. The shared scroll helpers rememberScroll and restoreScroll (src/webview/shared/scroll.ts) merge scrollY into a page’s state at most every 200 ms as it scrolls, and scroll back to a number on the first draw. A query editor’s getState option (src/webview/shared/queryEditor.tsx) is a host-state callback, not the VS Code API.

The page harness now seeds kept state: openWebviewPage(html, state, { savedState }) (src/test/webviewPage.ts) loads a page with it and savedState() reads back what the page kept, so the tests below pin both what a page writes and what it reads back. They load the page’s bundle, not the host; the host’s reads are pinned by the e2e suites.

20. Search page

21. Task Board

22. Dashboard

23. Notes graph

24. Calendar page

The sidebar calendar (deckard.calendar) keeps nothing: its own bundle, src/webview/calendar/main.tsx, since Phase 6 step 4.3, never calls setState, and its month is in its HTML.

24a. Help

24c. Stats

25. Keys stored inside other formats

Several formats store Deckard’s own identifiers. If a refactor changes how one is made, the stored value stops matching and is pruned or ignored without an error.

Identifier Made at Stored in Pinned by
Entry ids, <prefix>-<hash>-<hash> createId, src/core/markdown/parser.ts:1862; inputs at :1246, :1375, :1450, :1848 taskOrder, sectionAccessCounts, sectionAccessTimes in row 1 preferences-prune.test.ts:25, relative to the parser’s own output only
Tag keys, such as #project/atlas the parser favoriteTags, tagAccessCounts, savedFilters, tagFirstSeen, and more in row 1; mergeLookalike keys in row 9 the parser tests
Find choice keys, note:[filePath,heading,occurrence], task:[filePath,label], tag:<key>, view:<id> findChoiceKey, src/ui/state/quickFindState.ts:474; pinKey, src/core/storage/preferences.ts:1613 findChoices in row 1; read by findChoiceFilePath (:1341) preferences.test.ts:83

No test pins an entry id’s value. A pinning test would assert createId output for a few fixed inputs, and the id of a heading, a tagged line, and a task in a fixed note. It would catch any change to the text that goes into an id, such as the task-line regex merge of §6 changing match[4].

26. Settings Deckard writes

Deckard writes these settings through writeSetting (src/ui/commands/settings.ts:19) or configuration.update, and reads them back. The package.json inventory owns the setting names. This row is about the value shapes Deckard itself writes.

Setting Value Deckard writes Written at
deckard.exclude Record<string, boolean> of escaped folder globs (withExcludeKey, src/ui/commands/excludeFolders.ts:96) src/ui/commands/excludeFolders.ts:172, :179, :203; src/ui/commands/parking.ts:408
deckard.parked.folders the same map shape src/ui/commands/parking.ts:417, :425, :486
deckard.parked.tags string[] src/ui/commands/parking.ts:547, :558, :616
deckard.board.statuses, deckard.board.statusNamespace string[], string src/ui/commands/taskBoardActions.ts:70
deckard.agenda.query string, or cleared src/extension.ts:856; src/ui/webview/taskBoard.ts:331, :337
deckard.agenda.groupBy, deckard.agenda.groupNamespace string src/ui/views/agendaTree.ts:704, :707, :714
deckard.calendar.dayPanel, .showWeekends, .showRepeats boolean src/extension.ts:829 to :845; src/ui/webview/calendarPage.ts:204, :209
deckard.zenMode boolean, per folder when set per folder src/ui/webview/zenMode.ts:71, :77
deckard.outline.followCursor boolean src/ui/views/outlineTree.ts:397
deckard.tagOverview.includeHubLinks false src/ui/webview/searchPage.ts:780
deckard.theme string src/ui/commands/chooseTheme.ts:64
deckard.mcpServer.enabled true src/ui/commands/mcpServer.ts:176
deckard.taskReminderTime cleared src/ui/views/taskStatusBar.ts:332

VS Code also stores state under Deckard’s identifiers: open panels by view type, view placement by view id, keybindings by command id, and walkthrough progress by deckard.gettingStarted. The package.json inventory of §1.8 covers them.

Differences from the plan’s list

Existing compatibility risks

How to regenerate

Run these from the repository root and check each hit against the rows above.