@bitcobblers/wod-wiki-wql 0.44.2159 → 0.45.2166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,8 +2,10 @@ import { LRParser } from '@lezer/lr';
2
2
  import { LanguageSupport, HighlightStyle, LRLanguage } from '@codemirror/language';
3
3
  import { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
4
4
  import { Extension } from '@codemirror/state';
5
- import { SummaryCoverage, BlockIndexRow, Note, EventRecord, PageNote, Page, AnalyticsDataPoint, NotebookId, ResultOrigin, StoredOutputStatement, NoteBlockChange } from '@bitcobblers/wod-wiki-core';
6
- export { DEFAULT_NOTEBOOK_SLUGS, DefaultNotebookSlug, NotebookId, SYSTEM_DEFAULT_OUTPUT_UNIT, UnitConversionError, convertViaCatalog, dimensionKeyOf, isNoteEditable, lookupUnit, notebookSlugFromId, systemDefaultUnit, toNotebookId } from '@bitcobblers/wod-wiki-core';
5
+ import { SummaryCoverage, BlockIndexRow, Note, EventRecord, PageNote, Page, NotePlacement, AnalyticsDataPoint, FeedId, NotebookId, NotebookOrigin, ResultOrigin, StoredOutputStatement, NoteBlockChange } from '@bitcobblers/wod-wiki-core';
6
+ export { DEFAULT_NOTEBOOK_SLUGS, DefaultNotebookSlug, FeedId, NotebookId, NotebookOrigin, SYSTEM_DEFAULT_OUTPUT_UNIT, UnitConversionError, convertViaCatalog, dimensionKeyOf, isNoteEditable, lookupUnit, notebookSlugFromId, systemDefaultUnit, toNotebookId } from '@bitcobblers/wod-wiki-core';
7
+ import { IEffort } from '@bitcobblers/wod-wiki-lang';
8
+ export { IEffort } from '@bitcobblers/wod-wiki-lang';
7
9
 
8
10
  /**
9
11
  * WQL vocabulary — the single owner of the WQL dictionary: aggregators,
@@ -38,8 +40,11 @@ declare const WQL_TAG_KEYS: readonly ["domain", "format", "equipment", "quality"
38
40
  type WqlTagKey = (typeof WQL_TAG_KEYS)[number];
39
41
  /** Content-plane keys — meaningful only on find:/rows:. On an aggregate
40
42
  * they are a category error (a fact row has no note text or source);
41
- * every other non-structural key is a candidate custom dimension. */
42
- declare const WQL_CONTENT_ONLY_KEYS: readonly ["type", "text", "has", "source", "catalog", "notebook"];
43
+ * every other non-structural key is a candidate custom dimension.
44
+ * `catalog:` is retired (ticket 08 — the notebook plane and the
45
+ * `notebook:` filter replace it) and `has:` was removed from the
46
+ * declared vocabulary: it had no executor and the composer withheld it. */
47
+ declare const WQL_CONTENT_ONLY_KEYS: readonly ["type", "text", "source", "notebook", "contributes"];
43
48
  /** Filter keys the effort registry can resolve (runFindEffort) — anything
44
49
  * else on find:effort is ignored and reported as an advisory. */
45
50
  declare const WQL_EFFORT_FILTER_KEYS: readonly ["effort", "discipline", "intensity", "origin", "text"];
@@ -67,24 +72,32 @@ type WqlIntensityTier = (typeof WQL_INTENSITY_TIERS)[number];
67
72
  * rollups are computed at read time via the .rollup suffix, never stored. */
68
73
  declare const WQL_GRAINS: readonly ["summary", "event"];
69
74
  type WqlGrain = (typeof WQL_GRAINS)[number];
70
- /** Content-discovery query targets (find:<target>). */
71
- declare const WQL_FIND_TARGETS: readonly ["note", "block", "effort", "session", "segment", "event"];
75
+ /** Content-discovery query targets (find:<target>). The four container
76
+ * planes (ticket 08) are first-class targets: `:notebook{}` lists the
77
+ * notes across every notebook, `:page{}` the page placements, `:tag{}` the tags,
78
+ * `:equipment{}` the equipment notes — the latter two resolve to notes. */
79
+ declare const WQL_FIND_TARGETS: readonly ["note", "block", "effort", "session", "segment", "event", "notebook", "page", "tag", "equipment"];
72
80
  type WqlFindTarget = (typeof WQL_FIND_TARGETS)[number];
73
- /** Canonical source filter values: the allowed storage locations (the
74
- * former `collections` spelling is retired — renamed to feeds; storage
75
- * identities keep their `collection:` prefixes). Seed corpus locations
76
- * joined the note plane: prebuilt dashboards, the effort library and the
77
- * equipment library. */
78
- declare const WQL_SOURCE_VALUES: readonly ["journal", "feeds", "guides", "playground", "dashboards", "efforts", "equipment"];
81
+ /** Canonical source filter values: the allowed storage locations. Corpus-
82
+ * delivered notes carry `notebook:<slug>` source ids, so `notebooks` spans
83
+ * the seeded notebooks. Seed corpus locations joined the note
84
+ * plane: prebuilt dashboards, the effort library and the equipment library. */
85
+ declare const WQL_SOURCE_VALUES: readonly ["journal", "notebooks", "guides", "playground", "dashboards", "efforts", "equipment"];
79
86
  type WqlSourceValue = (typeof WQL_SOURCE_VALUES)[number];
80
87
  /** Colon source heads — the unprefixed `:<head>` names. Find targets map
81
- * 1:1 to the content planes; journal/feed(s)/catalog(s)/playground are
82
- * source-scoped note heads (they parse to target 'note' plus an injected
83
- * `source:` filter). */
84
- declare const WQL_SOURCE_HEADS: readonly ["note", "notes", "block", "effort", "session", "segment", "event", "journal", "notebook", "notebooks", "feed", "feeds", "catalog", "catalogs", "playground", "dashboard"];
88
+ * 1:1 to the content planes; journal/notebooks/playground are source-scoped
89
+ * note heads (they parse to target 'note' plus an injected `source:`
90
+ * filter). `:notebook{}` / `:page{}` / `:tag{}` / `:equipment{}` are the
91
+ * container planes (targets of their own name). `:notebook{}` stays a NOTE
92
+ * plane (ticket 05): it returns every notebook's notes, delegating to the
93
+ * note executor. */
94
+ declare const WQL_SOURCE_HEADS: readonly ["note", "notes", "block", "effort", "session", "segment", "event", "journal", "notebook", "notebooks", "playground", "page", "tag", "equipment", "dashboard"];
85
95
  type WqlSourceHead = (typeof WQL_SOURCE_HEADS)[number];
86
96
  /** Storage scope a source-scoped note head binds (undefined = plain target). */
87
97
  declare const WQL_SOURCE_HEAD_SCOPES: Readonly<Record<string, WqlSourceValue>>;
98
+ /** Note-head aliases — `:<head>` parses to target 'note' with NO injected
99
+ * scope (the note plane is inclusive; authored filters narrow it). */
100
+ declare const WQL_NOTE_HEAD_ALIASES: readonly ["notes"];
88
101
  /** Type-alias note heads — `:<head>` parses to target 'note' plus an injected
89
102
  * `type:` filter (no storage scope, so the head never narrows by source).
90
103
  * `:dashboard` is the canonical member: dashboards are notes typed
@@ -113,8 +126,11 @@ type WqlStandardDataset = (typeof WQL_STANDARD_DATASETS)[number];
113
126
  * stay addressable programmatically via hand-built ASTs. */
114
127
  declare const WQL_RESULT_PLANES: readonly ["segment", "system", "load", "event", "compiler", "completion", "analytics", "wellness"];
115
128
  type WqlResultPlane = (typeof WQL_RESULT_PLANES)[number];
116
- /** Content-specific filter keys (beyond the analytics tag keys). */
117
- declare const WQL_CONTENT_FILTER_KEYS: readonly ["type", "text", "has", "source", "catalog", "notebook", "domain", "format", "equipment", "quality", "intent", "effort", "discipline", "intensity", "grade", "note", "page", "origin", "grain", "metric", "block", "result", "tags"];
129
+ /** Content-specific filter keys (beyond the analytics tag keys). `catalog:`
130
+ * and `has:` are gone (ticket 08): `catalog:` → `notebook:`, `has:` had no
131
+ * executor. `contributes:` is the tag plane's contribution filter — a
132
+ * contribution is never a `tags:` label filter. */
133
+ declare const WQL_CONTENT_FILTER_KEYS: readonly ["type", "text", "source", "notebook", "page", "contributes", "domain", "format", "equipment", "quality", "intent", "effort", "discipline", "intensity", "grade", "note", "page", "origin", "grain", "metric", "block", "result", "tags"];
118
134
  type WqlContentFilterKey = (typeof WQL_CONTENT_FILTER_KEYS)[number];
119
135
  /**
120
136
  * Composer source planes (issue #838, decision #836): the single `source`
@@ -125,8 +141,8 @@ type WqlContentFilterKey = (typeof WQL_CONTENT_FILTER_KEYS)[number];
125
141
  * deliberately absent — it needs new grammar/engine semantics and is
126
142
  * deferred to its own ticket.
127
143
  */
128
- declare const WQL_SOURCES: readonly ["note", "block", "effort", "session", "segment", "event"];
129
- type WqlSource = (typeof WQL_SOURCES)[number];
144
+ declare const WQL_SOURCES: readonly ["note", "block", "effort", "session", "segment", "event", "notebook", "page", "tag", "equipment"];
145
+ type WqlSource = WqlFindTarget;
130
146
  /** Rollup periods the aggregate grammar accepts (wql.ts: N > 1, unit d|w). */
131
147
  declare const WQL_ROLLUP_PERIODS: readonly ["2w", "4w"];
132
148
  type WqlRollupPeriod = (typeof WQL_ROLLUP_PERIODS)[number];
@@ -1008,7 +1024,16 @@ interface NoteQueryStore {
1008
1024
  * ORs; `negate` excludes any row matching any value.
1009
1025
  */
1010
1026
  type WqlDomainPredicate = {
1011
- field: 'id' | 'noteId' | 'type' | 'catalog' | 'source' | 'tags' | 'effort';
1027
+ field: 'id' | 'noteId' | 'type' | 'source' | 'tags' | 'effort';
1028
+ values: string[];
1029
+ negate?: boolean;
1030
+ }
1031
+ /** Typed-tag narrow — notes carrying a tag of this type and one of these
1032
+ * labels (pushes down through the tags by-type index). Mirror of the
1033
+ * storage wire's typedTag predicate (ticket 08). */
1034
+ | {
1035
+ field: 'typedTag';
1036
+ tagType: string;
1012
1037
  values: string[];
1013
1038
  negate?: boolean;
1014
1039
  } | {
@@ -1023,13 +1048,13 @@ type WqlDomainPredicate = {
1023
1048
  field: 'page';
1024
1049
  value: boolean;
1025
1050
  }
1026
- /** The :note default page-exclusion stage (notes plan only). `feeds`
1027
- * = an authored feed source clause rides along: true drops literal
1051
+ /** The :note default page-exclusion stage (notes plan only). `nonPages`
1052
+ * = an authored notebook source clause rides along: true drops literal
1028
1053
  * type 'page' rows; false drops isPage rows (page-like kinds or page:/
1029
1054
  * guides: source prefixes on non-note kinds). */
1030
1055
  | {
1031
1056
  field: 'defaultNotes';
1032
- feeds: boolean;
1057
+ nonPages: boolean;
1033
1058
  } | {
1034
1059
  field: 'sourceFence';
1035
1060
  };
@@ -1072,21 +1097,8 @@ interface BlockQueryStore {
1072
1097
  limit?: number;
1073
1098
  }): Promise<WqlDomainReadResult | undefined>;
1074
1099
  }
1075
- /** Pure effort model interface for `:effort` queries. */
1076
- interface IEffort {
1077
- id: string;
1078
- slug: string;
1079
- label: string;
1080
- aliases: string[];
1081
- baseAttributes: {
1082
- met?: number;
1083
- discipline?: string;
1084
- intensityTier?: string;
1085
- [key: string]: unknown;
1086
- };
1087
- registrySource?: 'bundled' | 'user' | string;
1088
- [key: string]: unknown;
1089
- }
1100
+ /** Effort definition records for `:effort` queries — the language package's
1101
+ * IEffort (single authoritative definition; re-exported above). */
1090
1102
  interface EffortQueryStore {
1091
1103
  getAllEfforts(): Promise<IEffort[]>;
1092
1104
  }
@@ -1120,19 +1132,25 @@ interface QueryServiceStores {
1120
1132
  blockEffortsStore?: {
1121
1133
  getAllFromIndex(index: string, key: string): Promise<any[]>;
1122
1134
  };
1123
- /** Serves tag records (`tags` store). */
1135
+ /** Serves tag records (`tags` store). `getAll` backs the `:tag{}` plane;
1136
+ * absent → the plane resolves to no rows. */
1124
1137
  tagsStore?: {
1125
1138
  getAllFromIndex(index: string, key: string): Promise<any[]>;
1139
+ getAll?(): Promise<any[]>;
1126
1140
  };
1127
1141
  /** Serves note-tag junction rows (`note_tags` store). */
1128
1142
  noteTagsStore?: {
1129
1143
  getAllFromIndex(index: string, key: string): Promise<any[]>;
1130
1144
  };
1131
1145
  /** Canonical page_notes junction reads for container resolution — a
1132
- * note's parent Page wins over a standalone Note container. */
1146
+ * note's parent Page wins over a standalone Note container. The two
1147
+ * getAll* seams back the `:page{}` placement plane; absent → the plane
1148
+ * resolves to no rows. */
1133
1149
  pageStore?: {
1134
1150
  getNotePages(noteId: string): Promise<PageNote[]>;
1135
1151
  getPage(pageId: string): Promise<Page | undefined>;
1152
+ getAllPages?(): Promise<Page[]>;
1153
+ getAllLinks?(): Promise<PageNote[]>;
1136
1154
  };
1137
1155
  /** Batched relation reads for the hydration paths (containers, run
1138
1156
  * tags) — one bundle per distinct note id instead of a page/tag read
@@ -1173,22 +1191,37 @@ interface QueryServiceStores {
1173
1191
  * Fully inverted dependencies: zero IndexedDB/storage module-level imports.
1174
1192
  */
1175
1193
 
1176
- /** Extract the catalog directory id from a Note or BlockIndexRow.
1177
- * Uses explicit `catalog` when present; falls back to parsing `sourceId`
1178
- * (stripping `collection:`/`feed:` prefixes and `feeds/` path components) or `noteId`.
1179
- * Exported so host mappers (Entry derivation) carry the exact field the
1180
- * `catalog:` filter matches — presentation catalogs must not diverge. */
1181
- declare function catalogOfItem(item: {
1182
- id?: string;
1183
- noteId?: string;
1184
- sourceId?: string;
1185
- catalog?: string;
1186
- }): string | undefined;
1187
-
1194
+ /** The notebook slug a `notebook:<slug>[/<item>]` source id names — the
1195
+ * first path segment; README/root landings (`notebook:<slug>` bare or
1196
+ * `notebook:_root`) name no item. UUID and non-notebook source ids name
1197
+ * no notebook. */
1198
+ declare function notebookSlugOfSourceId(sourceId: string | undefined): string | undefined;
1199
+ /**
1200
+ * The feed that delivered a note — the resolver's feed answer.
1201
+ *
1202
+ * Read from the note's OWN feed stamp (`feedSourceId`), never from the seed
1203
+ * stamps (`seedOrigin`, `seedVersion`, `seedChunkId`): a note that no feed
1204
+ * delivered has no feed, whatever its seed stamps say. A feed id and the
1205
+ * source id of the same registered source agree, so the answer names the
1206
+ * registered feed the note arrived from.
1207
+ */
1208
+ declare function feedOfItem(item: {
1209
+ feedSourceId?: string | null;
1210
+ }): FeedId | undefined;
1188
1211
  /**
1189
1212
  * Resolve the canonical `notebook/{slug}` container for any Note or BlockIndexRow.
1190
- * Unifies explicit `notebookId`, default notebooks (`notebook/journal`, `notebook/playground`,
1191
- * `notebook/guides`), `notebook:{slug}` tags, and seed catalogs (`notebook/{catalog}`).
1213
+ *
1214
+ * Fallback precedence (first match wins), shared by every consumer — the WQL
1215
+ * query layer, the host entry mapper, and the storage projections:
1216
+ * 1. explicit `notebookId` (user-created notebooks),
1217
+ * 2. the `notebook:{slug}` tag convention (user notebook membership),
1218
+ * 3. the corpus path (`markdown/<family>/…` sourcePath),
1219
+ * 4. the source-id prefix (`notebook:`, `guides:`, `playground`,
1220
+ * and the `efforts`/`equipment`/`dashboards` corpus literals),
1221
+ * 5. the journal fallback.
1222
+ * Tiers 3 and 4 agree for every corpus note: the seed writer
1223
+ * (`seedNoteSourceId`/`chunkIdFor`) derives the sourceId from the same path
1224
+ * the importer stamps as `sourcePath`.
1192
1225
  */
1193
1226
  declare function notebookOfItem(item: {
1194
1227
  id?: string;
@@ -1197,27 +1230,62 @@ declare function notebookOfItem(item: {
1197
1230
  type?: string;
1198
1231
  seedOrigin?: string;
1199
1232
  seedChunkId?: string;
1233
+ feedOrigin?: string;
1234
+ feedSourceId?: string;
1200
1235
  sourcePath?: string;
1201
- catalog?: string;
1202
1236
  notebookId?: string;
1203
1237
  tags?: readonly string[];
1204
1238
  }): NotebookId | undefined;
1205
- /** Match a single row against one source filter value. The `journal` kind matches
1206
- * rows with no sourceId, the literal 'journal', or UUID / journal/date lineage
1207
- * pointing to the original note. Lineage also passes corpus exclusions below.
1208
- * The feed / guide kinds match
1209
- * rows whose sourceId starts with the kind (storage identities keep their
1210
- * `collection:`/`page:collection:` prefixes — only the query vocabulary
1211
- * was renamed). A `kind:id` literal matches the
1212
- * exact id. `playground` matches the playground intake's sourceId convention
1239
+ /**
1240
+ * Who owns the notebook a row resolves to — the editability key (ticket 05).
1241
+ * Pure over the row's own fields, and exact for every reachable state:
1242
+ * - explicit `notebookId` / `notebook:` tag membership → `'user'` (moves
1243
+ * into feed-delivered notebooks are forbidden and the importer never
1244
+ * stamps either field, so this tier is always user-managed),
1245
+ * - corpus path or feed/corpus sourceId shapes → `'feed'`
1246
+ * (the delivering feed wrote these rows; guides included — the core
1247
+ * feed delivers the canvas),
1248
+ * - the playground and journal fallbacks → `'default'`.
1249
+ * A user-owned copy (clone) keeps its provenance stamps but resolves through
1250
+ * tier 1, so it is editable while its origin stays visible.
1251
+ */
1252
+ declare function notebookOriginOfItem(item: Parameters<typeof notebookOfItem>[0]): NotebookOrigin | undefined;
1253
+ /**
1254
+ * Storage-identity shape per WQL source kind — THE one table of `sourceId`
1255
+ * prefixes and exact literals. The JS residual filter (`sourceMatches`) and
1256
+ * the storage wire's SQL projection (`sourceKindSql` in
1257
+ * @bitcobblers/wod-wiki-storage) both derive from this table, so the two
1258
+ * planes cannot disagree, and the source-id tier of {@link notebookOfItem}
1259
+ * agrees with both by construction. `journal` is absent on purpose: it is
1260
+ * the resolver's fallback decision, materialized as the computed `journal`
1261
+ * column, not a sourceId shape.
1262
+ */
1263
+ declare const SOURCE_ID_SHAPES: Readonly<Record<string, {
1264
+ /** sourceIds exactly equal to one of these match the kind. */
1265
+ exact?: readonly string[];
1266
+ /** sourceIds starting with one of these match the kind. */
1267
+ prefixes?: readonly string[];
1268
+ /** Legacy rows that predate the sourceId convention match via note `type`. */
1269
+ legacyType?: string;
1270
+ }>>;
1271
+ /** The storage-identity shape for a WQL source kind (aliases resolved), or
1272
+ * undefined for kinds that are not pure sourceId shapes (`journal`, `all`,
1273
+ * plain sourceId literals). The storage wire's SQL
1274
+ * projection reads the same accessor. */
1275
+ declare function sourceShape(kind: string): (typeof SOURCE_ID_SHAPES)[string] | undefined;
1276
+ /** Match a single row against one source filter value. The `journal` kind is
1277
+ * the resolver's own answer: a row journals exactly when
1278
+ * {@link notebookOfItem} places it in `notebook/journal` — no sourceId
1279
+ * identity, no corpus path, no notebookId, no `notebook:` tag (see
1280
+ * {@link isJournalRow} for the fallback's shape exclusions).
1281
+ * The feed / guide / page / playground / corpus kinds read the shared
1282
+ * {@link SOURCE_ID_SHAPES} table — the same sourceId prefixes/exact literals
1283
+ * the storage wire's SQL projection is built from. A `kind:id` literal matches
1284
+ * the exact id. `playground` matches the playground intake's sourceId convention
1213
1285
  * and, on the note plane, legacy rows typed 'playground' (playground pages
1214
1286
  * saved before the sourceId convention existed — their sourceId is absent).
1215
1287
  * `all` spans exactly the WQL source domain plus sourceless rows — identical
1216
- * to the source fence. `journal` rejects the rest of the seed corpus: rows
1217
- * with seed provenance (importer stamps, or surviving seedChunkId /
1218
- * markdown/ sourcePath / catalog on legacy user-edited rows whose
1219
- * seedOrigin flipped to 'user') and typed dashboards never journal — a user
1220
- * journal note carries none of those markers. Exported so host mappers
1288
+ * to the source fence. Exported so host mappers
1221
1289
  * classify result rows with the exact predicate the `source:` filter
1222
1290
  * applies. */
1223
1291
  declare function sourceMatches(item: {
@@ -1227,9 +1295,11 @@ declare function sourceMatches(item: {
1227
1295
  type?: string;
1228
1296
  seedOrigin?: string;
1229
1297
  seedChunkId?: string;
1298
+ feedOrigin?: string;
1299
+ feedSourceId?: string;
1230
1300
  sourcePath?: string;
1231
- catalog?: string;
1232
1301
  notebookId?: string;
1302
+ tags?: readonly string[];
1233
1303
  }, kind: string): boolean;
1234
1304
  interface FindQueryResult {
1235
1305
  parsed: ParsedFindQuery;
@@ -1248,13 +1318,18 @@ interface FindQueryResult {
1248
1318
  * page_notes junction links one, else the standalone Note. Present only
1249
1319
  * when a pageStore is injected and notes were matched. */
1250
1320
  containers?: Record<string, NoteContainer>;
1321
+ /** Every page a matched note is placed on, keyed by note id — the
1322
+ * many-to-many membership itself. `containers` is the deterministic
1323
+ * primary projection of this map. Present only when a pageStore or
1324
+ * relationStore is injected and notes were matched. */
1325
+ placements?: Record<string, NotePlacement[]>;
1251
1326
  stages: {
1252
1327
  selected: number;
1253
1328
  matched: number;
1254
1329
  };
1255
1330
  }
1256
1331
  /** Highest-container link for a matched note (parent Page wins). `slug` and
1257
- * `date` route app URLs (/p/:slug, /journal/:date). Core Page has no type —
1332
+ * `date` route app URLs (/page/:slug, /day/:date). Core Page has no type —
1258
1333
  * the parent is never classified by the note's kind. */
1259
1334
  type NoteContainer = {
1260
1335
  kind: 'page';
@@ -1287,6 +1362,8 @@ interface PipelineResult {
1287
1362
  runs?: RowsRun[];
1288
1363
  /** Highest container per note id (see FindQueryResult.containers). */
1289
1364
  containers?: Record<string, NoteContainer>;
1365
+ /** Every page a matched note is placed on (see FindQueryResult.placements). */
1366
+ placements?: Record<string, NotePlacement[]>;
1290
1367
  unit?: string;
1291
1368
  chart?: PipelineSink;
1292
1369
  error?: string;
@@ -1414,19 +1491,26 @@ declare class QueryService {
1414
1491
  * time filters.
1415
1492
  */
1416
1493
  runFind(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1417
- /** Highest container per note id: the parent Page from the canonical
1418
- * page_notes junction (first link by position) wins; a note with no page
1419
- * link stays a standalone Note container. Batched when a relationStore
1420
- * is injected — one bundle read per run instead of a link/page read per
1421
- * matched note. */
1422
- private containersForNotes;
1494
+ /** The container projection and the full placement set per note id.
1495
+ *
1496
+ * The container is the parent Page from the canonical page_notes junction
1497
+ * (the primary placement wins); a note with no page link stays a
1498
+ * standalone Note container. Batched when a relationStore is injected —
1499
+ * one bundle read per run instead of a link/page read per matched note.
1500
+ *
1501
+ * The same read resolves EVERY page the note is placed on: the junction
1502
+ * is many-to-many, so the container is a projection of that set, not the
1503
+ * set itself. */
1504
+ private containersAndPlacements;
1423
1505
  private hydrateBlocks;
1424
1506
  /**
1425
1507
  * Execute a :block query against the derived block_index store.
1426
1508
  */
1427
1509
  runFindBlock(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1428
1510
  /**
1429
- * Execute a :effort query against the effort registry.
1511
+ * Execute a :effort query: the registry is the filter plane (discipline,
1512
+ * intensity, origin, text), the note plane is the result plane — matched
1513
+ * projections resolve to their owning definition notes.
1430
1514
  */
1431
1515
  runFindEffort(parsed: ParsedFindQuery): Promise<FindQueryResult>;
1432
1516
  run(parsed: AnyParsedQuery, options?: QueryOptions): Promise<QueryResult>;
@@ -1491,10 +1575,43 @@ declare class QueryService {
1491
1575
  /** Resolve matching note IDs for a canonical typed tag (e.g. equipment:kettlebell). */
1492
1576
  private getNoteIdsForTypedTag;
1493
1577
  /**
1494
- * Find catalogs: identifies catalogs whose member notes (or catalog landing
1495
- * notes) match the authored criteria (effort, tags, text, typed tags, etc.).
1578
+ * Execute a :notebook query (ticket 08) — the notebook plane is a NOTE
1579
+ * plane (ticket 05 semantics preserved): bare `:notebook{}` returns the
1580
+ * notes of every notebook — journal, playground, defaults, user-created,
1581
+ * feed-delivered. `notebook:{slug}` narrows to members of those
1582
+ * notebooks and `!notebook:` excludes them; the result shape never
1583
+ * changes with polarity, and container criteria (tags:, effort:, typed
1584
+ * tags, text:) narrow the members exactly like the note plane — this
1585
+ * delegates to it. The notebook CONTAINER listing (the /notebooks
1586
+ * management surface) is the app's NotebookService model, not WQL rows.
1587
+ */
1588
+ runFindNotebook(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1589
+ /**
1590
+ * Execute a :page query (ticket 08) — the placement plane. Results are
1591
+ * the placed notes; `placements` carries every page each note sits on
1592
+ * (many-to-many) and `containers` the primary projection. `page:{slug}`
1593
+ * (or a `YYYY-MM-DD` date, or a page id) narrows the placements.
1594
+ */
1595
+ runFindPage(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1596
+ /**
1597
+ * Execute a :tag query (ticket 08) — the tag plane. Every tag record
1598
+ * surfaces as one synthetic note row, so results are notes end to end.
1599
+ * `tag:{label}` narrows; `type:` narrows by the tag's configured type;
1600
+ * `contributes:` narrows by what a tag contributes (`metric`,
1601
+ * `metric:<type>`, `tag:<slug>`, `function:<name>`) — a contribution is
1602
+ * exposed here, never as a `tags:` label filter. The synthetic row's body
1603
+ * summarizes the contributions so `text:` reaches them too.
1604
+ */
1605
+ runFindTag(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1606
+ /**
1607
+ * Execute an :equipment query (ticket 08) — the equipment plane. Results
1608
+ * are the equipment notes (the equipment notebook's members, typed
1609
+ * 'equipment' rows included). `equipment:{label}` narrows by the
1610
+ * equipment typed tag ("every equipment note tagged kettlebell" is
1611
+ * `:equipment{equipment:kettlebell}`); `tags:` and `text:` narrow like
1612
+ * the note plane.
1496
1613
  */
1497
- private runFindCatalog;
1614
+ runFindEquipment(parsed: ParsedFindQuery, options?: FindOptions): Promise<FindQueryResult>;
1498
1615
  }
1499
1616
 
1500
1617
  /**
@@ -1569,6 +1686,8 @@ interface DocumentOutput {
1569
1686
  efforts?: unknown[];
1570
1687
  /** Highest-container page/note links keyed by note id. */
1571
1688
  containers?: Record<string, NoteContainer>;
1689
+ /** Every page a matched note is placed on, keyed by note id. */
1690
+ placements?: Record<string, NotePlacement[]>;
1572
1691
  /** Session run cards (find:session / session-source pipelines). */
1573
1692
  runs?: RowsRun[];
1574
1693
  /** Terminal chart sink of a pipeline output (renderer dispatch). */
@@ -1587,6 +1706,7 @@ interface FamilyRunPayload {
1587
1706
  blocks?: BlockIndexRow[];
1588
1707
  efforts?: unknown[];
1589
1708
  containers?: Record<string, NoteContainer>;
1709
+ placements?: Record<string, NotePlacement[]>;
1590
1710
  runs?: RowsRun[];
1591
1711
  unit?: string;
1592
1712
  chart?: PipelineSink;
@@ -1816,6 +1936,38 @@ declare function projectEventToFacts(record: EventRecord): AnalyticsDataPoint[];
1816
1936
  */
1817
1937
  declare function eventsToStoredLogs(events: readonly EventRecord[]): StoredOutputStatement[];
1818
1938
 
1939
+ /**
1940
+ * Notebook vocabulary migration (ticket 12) — the pure rewrite from the
1941
+ * retired collection/feed wire identities to the notebook vocabulary.
1942
+ *
1943
+ * The retired spellings persist in older IndexedDB/SQL rows and checkpoints:
1944
+ * - chunk ids `collection.<slug>` / `feed.<slug>` → `notebook.<slug>`
1945
+ * - sourcePaths `markdown/collections/…` / `markdown/feeds/…` → `markdown/notebooks/…`
1946
+ * - sourceIds `collection:<slug>[/<item>]`, `feed:feeds/<slug>/<rest>`,
1947
+ * `page:collection:<slug>` → `notebook:<slug>[/<item>]`, `page:<slug>`
1948
+ * - the retired `catalog` note field is dropped; note `type: 'feed'` folds
1949
+ * into `'note'` (a note in a notebook is one kind).
1950
+ *
1951
+ * Pure and idempotent: already-migrated values pass through unchanged, so
1952
+ * callers may run the migration on every boot and persist only what changed.
1953
+ */
1954
+ /** Rewrite a retired chunk id; anything else passes through. */
1955
+ declare function migrateLegacyChunkId(chunkId: string): string;
1956
+ /** Rewrite a retired corpus path; anything else passes through. */
1957
+ declare function migrateLegacySourcePath(path: string): string;
1958
+ /** Rewrite a retired sourceId; anything else passes through. */
1959
+ declare function migrateLegacySourceId(sourceId: string): string;
1960
+ /** Rewrite a retired block routeId (`feeds/<slug>/<date>/<item>` or
1961
+ * `<catalog>/<item>`) to the notebook form `<slug>[/<date>]/<item>`;
1962
+ * anything else passes through. */
1963
+ declare function migrateLegacyRouteId(routeId: string): string;
1964
+ /** A note/block-index row (or any record carrying the retired fields) with
1965
+ * the notebook vocabulary applied. Idempotent; returns the input record
1966
+ * unchanged (same reference) when nothing migrates. */
1967
+ declare function migrateLegacyRow<T extends Record<string, unknown>>(row: T): T;
1968
+ /** True when a row still carries a retired identity worth persisting over. */
1969
+ declare function hasLegacyIdentity(row: Record<string, unknown>): boolean;
1970
+
1819
1971
  /**
1820
1972
  * Dashboard Note model (#898 map, format locked in #899).
1821
1973
  *
@@ -2136,13 +2288,13 @@ declare function migrateLegacyDashboardBodies(raw: string): string;
2136
2288
  * Auto-generated build version metadata.
2137
2289
  * Do not edit directly; updated by scripts/stamp-version.ts
2138
2290
  */
2139
- declare const VERSION = "0.44.2159";
2140
- declare const GIT_SHA = "30e43c7";
2141
- declare const BUILD_TIME = "2026-10-24T23:07:22.311Z";
2291
+ declare const VERSION = "0.45.2166";
2292
+ declare const GIT_SHA = "32bda10";
2293
+ declare const BUILD_TIME = "2026-10-26T20:01:09.868Z";
2142
2294
  declare const SEMVER: {
2143
- readonly version: "0.44.2159";
2144
- readonly gitSha: "30e43c7";
2145
- readonly buildTime: "2026-10-24T23:07:22.311Z";
2295
+ readonly version: "0.45.2166";
2296
+ readonly gitSha: "32bda10";
2297
+ readonly buildTime: "2026-10-26T20:01:09.868Z";
2146
2298
  };
2147
2299
 
2148
- export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, CONTENT_GROUPING_DIMENSIONS, type CatalogFieldSuggestion, type CatalogValueSuggestion, type ComparisonOp, DASHBOARD_GRID_MAX_COLS, DASHBOARD_WIDGET_TYPES, DEFAULT_DASHBOARD_TITLE, DISCIPLINE_FACTORS, type DashboardDocument, type DashboardMeta, type DashboardParsedSection, type DashboardSectionInput, type DashboardToken, type DashboardWidget, type DashboardWidgetType, type DocumentAssignment, type DocumentDefaults, type DocumentFormula, type DocumentOutput, type DocumentResult, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type EventRowIdentity, type EventStore, type ExecutionContext, type FamilyRunPayload, type FindOptions, type FindPredicate, type FindQueryResult, type FormulaEvaluation, type FormulaEvaluator, GIT_SHA, type IEffort, type IFieldCatalog, type LinkWidget, type MetricPredicate, type NoteContainer, type NoteQueryStore, type NoteRelationBundle, type OperandValue, type OutputUnitResolution, PLANNED_WIDGET_TYPES, type PageSourceEntry, PageSourceRegistry, type ParsedAggregateQuery, type ParsedDocument, type ParsedFindQuery, type ParsedFrontmatter, type ParsedPipelineQuery, type ParsedRowsQuery, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type ParsedWqlWindowSuffix, type PipelineOptions, type PipelineResult, type PipelineSink, type PipelineSource, type PointwiseInputs, type QueryDocument, QueryDocumentRunner$1 as QueryDocumentRunner, type QueryDocumentRunnerHost, type QueryDocumentRunnerOptions, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type QueryWindow, type ResolvedRange, type RowsPipes, type RowsQueryResult, type RowsRun, SEMVER, type Series, type SeriesPoint, QueryDocumentRunner as SharedQueryDocumentRunner, type SharedRunnerOptions, type SummaryFactIdentity, type SummaryFactSourceOutput, type TabularColumn, type TabularGroup, type TabularResult, type TagFilter, type TagValue, UNASSIGNED, type UnitBearingFact, type UnitFamily, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_CHART_HEADS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_CONTENT_ONLY_KEYS, WQL_DISPLAY_UNITS, WQL_EFFORT_FILTER_KEYS, WQL_FIND_TARGETS, WQL_FUNCTION_HEADS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_NOTE_DEFAULT_SOURCES, WQL_RESULT_PLANES, WQL_ROLLUP_PERIODS, WQL_SOURCES, WQL_SOURCE_HEADS, WQL_SOURCE_HEAD_SCOPES, WQL_SOURCE_VALUES, WQL_STANDARD_DATASETS, WQL_TAG_KEYS, WQL_TYPED_TAG_KEYS, WQL_TYPE_HEADS, WQL_VIRTUAL_DIMS, type WidgetOpResult, type WidgetSpan, type WidgetSpec, type WqlAggregator, type WqlCalcTarget, type WqlChartHead, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlDomainOrder, type WqlDomainPredicate, type WqlDomainReadResult, type WqlFindTarget, type WqlFunctionHead, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlResultPlane, type WqlRollupPeriod, type WqlSource, type WqlSourceHead, type WqlSourceValue, type WqlStandardDataset, type WqlTagKey, type WqlTypedTagKey, type WqlVirtualDim, allowedFilterTypesForTarget, appendSuffixes, appendWidget, buildDashboardDocument, buildDashboardScaffold, buildDrillDownQuery, captureContext, catalogOfItem, civilDateAdd, civilDateDiff, civilDateOf, civilDatesCoveredByRange, civilMonday, consumesRollupFacts, convertDisplay, createBuiltinFormulaEvaluator, dashboardSlug, defaultTokenValues, disciplineFactorFor, duplicateWidget, eventsToStoredLogs, extractDashboardTokens, extractFrontmatterTags, findTargetAdvisories, getList, getScalar, getUnitFamily, inRange, isAggregateQuery, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isPipelineQuery, isProposedMetric, migrateLegacyDashboardBodies, moveWidget, normalizeSummaryFacts, normalizeWql, notebookOfItem, parseDashboardNote, parseDocument, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, projectEventToFacts, referencedTokens, removeWidget, renderWidgetGroup, resizeWidget, resolveCanonicalMetricKey, resolveOutputUnit, resolveWidgetType, resolveWindowRange, rowsParseError, serialize, serializeDocument, serializeFrontmatter, setDashboardTokenValue, sourceMatches, splitAtWhere, stripFrontmatter, substituteTokens, substituteTokens$1 as substituteTokensRaw, supportsWqlFilterKey, systemTimeZone, toEventRows, toSummaryEventRows, unknownTokensMessage, unknownWidgetTypeMessage, updateWidget, widgetBodyLine, widgetFenceTag, wql, wqlCompletion, wqlCompletionSource, wqlFilterKeys, wqlGroupingDimensions, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms, zonedNoon, zonedStartOfDay };
2300
+ export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, CONTENT_GROUPING_DIMENSIONS, type CatalogFieldSuggestion, type CatalogValueSuggestion, type ComparisonOp, DASHBOARD_GRID_MAX_COLS, DASHBOARD_WIDGET_TYPES, DEFAULT_DASHBOARD_TITLE, DISCIPLINE_FACTORS, type DashboardDocument, type DashboardMeta, type DashboardParsedSection, type DashboardSectionInput, type DashboardToken, type DashboardWidget, type DashboardWidgetType, type DocumentAssignment, type DocumentDefaults, type DocumentFormula, type DocumentOutput, type DocumentResult, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type EventRowIdentity, type EventStore, type ExecutionContext, type FamilyRunPayload, type FindOptions, type FindPredicate, type FindQueryResult, type FormulaEvaluation, type FormulaEvaluator, GIT_SHA, type IFieldCatalog, type LinkWidget, type MetricPredicate, type NoteContainer, type NoteQueryStore, type NoteRelationBundle, type OperandValue, type OutputUnitResolution, PLANNED_WIDGET_TYPES, type PageSourceEntry, PageSourceRegistry, type ParsedAggregateQuery, type ParsedDocument, type ParsedFindQuery, type ParsedFrontmatter, type ParsedPipelineQuery, type ParsedRowsQuery, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type ParsedWqlWindowSuffix, type PipelineOptions, type PipelineResult, type PipelineSink, type PipelineSource, type PointwiseInputs, type QueryDocument, QueryDocumentRunner$1 as QueryDocumentRunner, type QueryDocumentRunnerHost, type QueryDocumentRunnerOptions, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type QueryWindow, type ResolvedRange, type RowsPipes, type RowsQueryResult, type RowsRun, SEMVER, SOURCE_ID_SHAPES, type Series, type SeriesPoint, QueryDocumentRunner as SharedQueryDocumentRunner, type SharedRunnerOptions, type SummaryFactIdentity, type SummaryFactSourceOutput, type TabularColumn, type TabularGroup, type TabularResult, type TagFilter, type TagValue, UNASSIGNED, type UnitBearingFact, type UnitFamily, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_CHART_HEADS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_CONTENT_ONLY_KEYS, WQL_DISPLAY_UNITS, WQL_EFFORT_FILTER_KEYS, WQL_FIND_TARGETS, WQL_FUNCTION_HEADS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_NOTE_DEFAULT_SOURCES, WQL_NOTE_HEAD_ALIASES, WQL_RESULT_PLANES, WQL_ROLLUP_PERIODS, WQL_SOURCES, WQL_SOURCE_HEADS, WQL_SOURCE_HEAD_SCOPES, WQL_SOURCE_VALUES, WQL_STANDARD_DATASETS, WQL_TAG_KEYS, WQL_TYPED_TAG_KEYS, WQL_TYPE_HEADS, WQL_VIRTUAL_DIMS, type WidgetOpResult, type WidgetSpan, type WidgetSpec, type WqlAggregator, type WqlCalcTarget, type WqlChartHead, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlDomainOrder, type WqlDomainPredicate, type WqlDomainReadResult, type WqlFindTarget, type WqlFunctionHead, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlResultPlane, type WqlRollupPeriod, type WqlSource, type WqlSourceHead, type WqlSourceValue, type WqlStandardDataset, type WqlTagKey, type WqlTypedTagKey, type WqlVirtualDim, allowedFilterTypesForTarget, appendSuffixes, appendWidget, buildDashboardDocument, buildDashboardScaffold, buildDrillDownQuery, captureContext, civilDateAdd, civilDateDiff, civilDateOf, civilDatesCoveredByRange, civilMonday, consumesRollupFacts, convertDisplay, createBuiltinFormulaEvaluator, dashboardSlug, defaultTokenValues, disciplineFactorFor, duplicateWidget, eventsToStoredLogs, extractDashboardTokens, extractFrontmatterTags, feedOfItem, findTargetAdvisories, getList, getScalar, getUnitFamily, hasLegacyIdentity, inRange, isAggregateQuery, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isPipelineQuery, isProposedMetric, migrateLegacyChunkId, migrateLegacyDashboardBodies, migrateLegacyRouteId, migrateLegacyRow, migrateLegacySourceId, migrateLegacySourcePath, moveWidget, normalizeSummaryFacts, normalizeWql, notebookOfItem, notebookOriginOfItem, notebookSlugOfSourceId, parseDashboardNote, parseDocument, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, projectEventToFacts, referencedTokens, removeWidget, renderWidgetGroup, resizeWidget, resolveCanonicalMetricKey, resolveOutputUnit, resolveWidgetType, resolveWindowRange, rowsParseError, serialize, serializeDocument, serializeFrontmatter, setDashboardTokenValue, sourceMatches, sourceShape, splitAtWhere, stripFrontmatter, substituteTokens, substituteTokens$1 as substituteTokensRaw, supportsWqlFilterKey, systemTimeZone, toEventRows, toSummaryEventRows, unknownTokensMessage, unknownWidgetTypeMessage, updateWidget, widgetBodyLine, widgetFenceTag, wql, wqlCompletion, wqlCompletionSource, wqlFilterKeys, wqlGroupingDimensions, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms, zonedNoon, zonedStartOfDay };