@bitcobblers/wod-wiki-wql 0.6.32 → 0.6.36

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.cts CHANGED
@@ -2,7 +2,7 @@ import { LRParser } from '@lezer/lr';
2
2
  import { LanguageSupport, HighlightStyle, LRLanguage } from '@codemirror/language';
3
3
  import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
4
4
  import { Extension } from '@codemirror/state';
5
- import { ResultOrigin, AnalyticsDataPoint, BlockIndexRow, Note, WorkoutResult, StoredOutputStatement } from '@bitcobblers/wod-wiki-core';
5
+ import { ResultOrigin, AnalyticsDataPoint, UnifiedEventRecord, StoredOutputStatement, BlockIndexRow, Note } from '@bitcobblers/wod-wiki-core';
6
6
 
7
7
  /**
8
8
  * WQL vocabulary — the single owner of the WQL dictionary: aggregators,
@@ -50,7 +50,10 @@ declare const WQL_CALC_TARGETS: readonly ["calc.metMinutes", "calc.acwr", "calc.
50
50
  type WqlCalcTarget = (typeof WQL_CALC_TARGETS)[number];
51
51
  declare const WQL_INTENSITY_TIERS: readonly ["low", "moderate", "high"];
52
52
  type WqlIntensityTier = (typeof WQL_INTENSITY_TIERS)[number];
53
- declare const WQL_GRAINS: readonly ["segment", "summary", "rollup"];
53
+ /** Unified store grains (ticket 003): 'summary' | 'event'. The legacy
54
+ * 'segment' grain was renamed to 'event' (ticket 002); 'rollup' is retired —
55
+ * rollups are computed at read time via the .rollup suffix, never stored. */
56
+ declare const WQL_GRAINS: readonly ["summary", "event"];
54
57
  type WqlGrain = (typeof WQL_GRAINS)[number];
55
58
  /** Content-discovery query targets (find:<target>). */
56
59
  declare const WQL_FIND_TARGETS: readonly ["note", "block", "effort"];
@@ -460,6 +463,29 @@ interface SummaryFactSourceOutput {
460
463
  * into persisted fact rows — one row per result × Canonical Metric Key.
461
464
  */
462
465
  declare function normalizeSummaryFacts(logs: readonly SummaryFactSourceOutput[], identity: SummaryFactIdentity): AnalyticsDataPoint[];
466
+ /** Identity for unified event-row emission — same fields as the fact identity. */
467
+ type EventRowIdentity = SummaryFactIdentity;
468
+ /**
469
+ * Logs → event rows, 1:1 per statement (ticket 002). Deterministic ids
470
+ * `${resultId}:${seq}`; canonical workout time wins over the statement's own
471
+ * timeSpan; query-critical scalars promoted top-level.
472
+ */
473
+ declare function toEventRows(logs: readonly StoredOutputStatement[], identity: SummaryFactIdentity): UnifiedEventRecord[];
474
+ /**
475
+ * Tier-2 analytics outputs → deterministic summary event rows (tickets
476
+ * 002/004): id `${resultId}:summary:${rowKey}` — no timestamp salt, so
477
+ * re-finalize overwrites cleanly. Fold identity lives in metrics[0].metadata
478
+ * (canonicalKey, effort metadata, groupTags) — shape-uniform with events.
479
+ */
480
+ declare function toSummaryEventRows(logs: readonly StoredOutputStatement[], identity: SummaryFactIdentity): UnifiedEventRecord[];
481
+ /**
482
+ * Event row → flat fact currency for the four-stage plan (ticket 003):
483
+ * one AnalyticsDataPoint per numeric metric. Canonical key resolution
484
+ * mirrors the summary fold — metadata.canonicalKey first, name-derived
485
+ * from the row's label metric as fallback. Deterministic fact ids:
486
+ * `${record.id}:${factOrdinal}`.
487
+ */
488
+ declare function projectEventToFacts(record: UnifiedEventRecord): AnalyticsDataPoint[];
463
489
 
464
490
  /**
465
491
  * Pure projection of a block_index into static Notes — one Note per distinct
@@ -480,18 +506,42 @@ declare function staticTagIndexFromBlocks(blocks: BlockIndexRow[]): Map<string,
480
506
  /**
481
507
  * Injected store interfaces for WQL QueryService.
482
508
  * Zero database/storage dependencies — 100% pure abstractions.
509
+ *
510
+ * Ticket 003: FactQueryStore + ResultLogStore collapsed into the single
511
+ * UnifiedEventStore — two names for one data source. The content plane
512
+ * (notes / blocks / efforts) is unchanged by workout-data unification.
483
513
  */
484
514
 
485
- /** Store surface the Query Service needs for fact rows. */
486
- interface FactQueryStore {
487
- getFactsByMetric(metricKey: string): Promise<AnalyticsDataPoint[]>;
488
- getFactsByTimeRange(start: number, end: number): Promise<AnalyticsDataPoint[]>;
489
- getNoteTagLabels(noteId: string): Promise<string[]>;
515
+ /**
516
+ * Store surface for the unified event table — every workout-data read the
517
+ * Query Service needs, plus the write contract owned by the write-path
518
+ * lifecycle (ticket 005).
519
+ */
520
+ interface UnifiedEventStore {
521
+ /** Windowed fetch — the one proven culling index (ticket 001). */
522
+ getEventsByTimeRange(start: number, end: number): Promise<UnifiedEventRecord[]>;
523
+ /** Per-result fetch (rows:{result:…}, re-finalize, orphan inspection). */
524
+ getEventsByResult(resultId: string): Promise<UnifiedEventRecord[]>;
525
+ /** Note-scoped fetch (rows:{note:…}). */
526
+ getEventsForNote(noteId: string): Promise<UnifiedEventRecord[]>;
527
+ /** Content-scoped fetch — the cross-store join hot path (indexed). */
528
+ getEventsByContent(blockContentId: string): Promise<UnifiedEventRecord[]>;
529
+ /** Full scan — all-time SELECT leg (ticket 001: scan beats non-selective indexes). */
530
+ scanAll(): Promise<UnifiedEventRecord[]>;
531
+ /** Append event rows (per-statement flush; same-tick coalescing allowed). */
532
+ appendEvents(rows: UnifiedEventRecord[]): Promise<void>;
533
+ /** Atomic finalize: clear the result's engine-authored summaries, write finals. */
534
+ finalizeSummaries(resultId: string, rows: UnifiedEventRecord[]): Promise<void>;
535
+ /** Reconcile deletes (wellness note-save) + GC sweeps. */
536
+ deleteEvents(ids: string[]): Promise<void>;
490
537
  }
491
538
  /** Store surface for content queries (`find:note`). */
492
539
  interface NoteQueryStore {
493
540
  getAllNotes(): Promise<Note[]>;
494
541
  getNoteIdsForTag(label: string): Promise<Set<string>>;
542
+ /** Note-tags label set of one note (moved here from FactQueryStore — it
543
+ * reads note tags, not facts). */
544
+ getNoteTagLabels(noteId: string): Promise<string[]>;
495
545
  }
496
546
  /** Store surface for block-index queries (`find:block`). */
497
547
  interface BlockQueryStore {
@@ -516,39 +566,33 @@ interface IEffort {
516
566
  interface EffortQueryStore {
517
567
  getAllEfforts(): Promise<IEffort[]>;
518
568
  }
519
- /** Store surface for raw WorkoutResult logs — the cross-store join & rows source. */
520
- interface ResultLogStore {
521
- getResultsByContentId(blockContentId: string): Promise<WorkoutResult[]>;
522
- /** Rows plane (#949): single-result scope (`rows:{result:…}`). */
523
- getResultById(resultId: string): Promise<WorkoutResult | undefined>;
524
- /** Rows plane (#949): whole-note scope (`rows:{note:…}`). */
525
- getResultsForNote(noteId: string): Promise<WorkoutResult[]>;
526
- }
527
569
  /** Optional bundle of stores for QueryService initialization. */
528
570
  interface QueryServiceStores {
529
- factStore?: FactQueryStore;
571
+ eventStore?: UnifiedEventStore;
530
572
  noteStore?: NoteQueryStore;
531
573
  blockStore?: BlockQueryStore;
532
- resultStore?: ResultLogStore;
533
574
  effortStore?: EffortQueryStore;
534
575
  staticNoteStore?: NoteQueryStore;
535
576
  staticBlockStore?: BlockQueryStore;
536
577
  }
537
578
 
538
579
  /**
539
- * Query Service — the executor of WQL against the Analytics Store
540
- * (CONTEXT.md glossary). Four-stage physical plan:
580
+ * Query Service — the executor of WQL against the unified event store.
581
+ * Four-stage physical plan:
541
582
  *
542
- * SELECT (index-first: by-metric + by-timestamp IDBKeyRange fetches,
543
- * intersected in memory)
583
+ * SELECT (window-first hybrid, ticket 003: windowed queries fetch through
584
+ * by-timestamp — the one proven culling index; all-time queries
585
+ * scan; by-metric is never used. Event rows are flattened to the
586
+ * legacy flat-fact currency by projectEventToFacts.)
544
587
  * BUCKET (time dim or rollup period)
545
588
  * AGGREGATE (per bucket)
546
589
  * GROUP (tag-dimension fan-out)
547
590
  *
548
591
  * Inputs are uncapped — personal-journal scale; widgets and tables are dumb
549
- * consumers of QueryResult. Fact rows are summary-grain AnalyticsDataPoint
550
- * rows; Tags are query-time dimensions read off the row (effort, discipline,
551
- * note, intensity, …) — 'tags' resolves through the note_tags store.
592
+ * consumers of QueryResult. The store serves UnifiedEventRecord rows
593
+ * (grain 'event' | 'summary'); Tags are query-time dimensions read off the
594
+ * projected fact row (effort, discipline, note, intensity, …) — 'tags'
595
+ * resolves through the note_tags store.
552
596
  *
553
597
  * Fully inverted dependencies: zero IndexedDB/storage module-level imports.
554
598
  */
@@ -600,11 +644,14 @@ interface QueryResult {
600
644
  /** Result display unit, if determined by directive, preference, or fact metadata. */
601
645
  unit?: string;
602
646
  }
603
- /** One run in a rows result: the stored result plus the output statements
604
- * that survived the optional output-type narrowing (`rows:segment{…}`). */
647
+ /** One run in a rows result: the canonical result identity plus the event
648
+ * rows that survived the optional output-type narrowing (`rows:segment{…}`). */
605
649
  interface RowsRun {
606
- result: WorkoutResult;
607
- logs: StoredOutputStatement[];
650
+ resultId: string;
651
+ noteId: string;
652
+ /** Canonical workout time (result.createdAt under the unified model). */
653
+ timestamp: number;
654
+ events: UnifiedEventRecord[];
608
655
  }
609
656
  interface RowsQueryResult {
610
657
  parsed: ParsedRowsQuery;
@@ -615,17 +662,17 @@ declare class QueryService {
615
662
  private readonly store;
616
663
  private readonly noteStore;
617
664
  private readonly blockStore;
618
- private readonly resultStore;
619
665
  private readonly effortStore;
620
666
  private readonly staticNoteStore?;
621
667
  private readonly staticBlockStore?;
622
- constructor(storesOrFactStore?: QueryServiceStores | FactQueryStore, noteStore?: NoteQueryStore, blockStore?: BlockQueryStore, resultStore?: ResultLogStore, effortStore?: EffortQueryStore, staticNoteStore?: NoteQueryStore, staticBlockStore?: BlockQueryStore);
668
+ constructor(storesOrEventStore?: QueryServiceStores | UnifiedEventStore, noteStore?: NoteQueryStore, blockStore?: BlockQueryStore, effortStore?: EffortQueryStore, staticNoteStore?: NoteQueryStore, staticBlockStore?: BlockQueryStore);
669
+ /** Windowed flat-fact fetch — the projected view over the event store. */
623
670
  getFactsByTimeRange(start: number, end: number): Promise<AnalyticsDataPoint[]>;
624
671
  runQuery(raw: string, options?: QueryOptions): Promise<QueryResult>;
625
672
  /**
626
673
  * Execute a rows query (rows:{…}, #949) — the session results table plane.
627
- * Re-derives output statements from raw WorkoutResult logs through the
628
- * ResultLogStore seam ("logs win" — facts are never read for this path).
674
+ * Reads event rows directly over the unified store (ticket 003): no
675
+ * WorkoutResult blob parsing; outputType narrowing hits the promoted column.
629
676
  */
630
677
  runRows(parsed: ParsedRowsQuery, options?: {
631
678
  anchorNow?: number;
@@ -663,9 +710,10 @@ declare class QueryService {
663
710
  /** Filter per-effort vs un-attributed overall summary rows to avoid
664
711
  * double-counting. */
665
712
  private applyEffortScope;
666
- /** Re-derive summary facts for one Canonical Metric Key from RAW WorkoutResult
667
- * logs across the given content ids — the cross-store join source. One fact
668
- * row per result (normalizeSummaryFacts dedupes within a result). */
713
+ /** Summary facts for one Canonical Metric Key across the given content ids —
714
+ * the cross-store join source. Reads finalize-written summary rows straight
715
+ * off the content index (ticket 003: the store is authoritative; the old
716
+ * freshness re-derivation is moot). One fact row per result × rowKey. */
669
717
  private deriveMetricFacts;
670
718
  /** All content blocks across the journal + static corpus. */
671
719
  private allContentBlocks;
@@ -897,13 +945,13 @@ declare function parseFrontmatterProps(lines: string[]): Record<string, string>;
897
945
  * Auto-generated build version metadata.
898
946
  * Do not edit directly; updated by scripts/stamp-version.ts
899
947
  */
900
- declare const VERSION = "0.6.32";
901
- declare const GIT_SHA = "bc13c0f";
902
- declare const BUILD_TIME = "2026-08-21T20:12:50.453Z";
948
+ declare const VERSION = "0.6.36";
949
+ declare const GIT_SHA = "c5ad2b0";
950
+ declare const BUILD_TIME = "2026-08-24T20:14:33.951Z";
903
951
  declare const SEMVER: {
904
- readonly version: "0.6.32";
905
- readonly gitSha: "bc13c0f";
906
- readonly buildTime: "2026-08-21T20:12:50.453Z";
952
+ readonly version: "0.6.36";
953
+ readonly gitSha: "c5ad2b0";
954
+ readonly buildTime: "2026-08-24T20:14:33.951Z";
907
955
  };
908
956
 
909
- export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, 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, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type FactQueryStore, type FindOptions, type FindPredicate, type FindQueryResult, GIT_SHA, type IEffort, KG_PER_LB, type LinkWidget, type MetricPredicate, type NoteQueryStore, PLANNED_WIDGET_TYPES, type ParsedFindQuery, type ParsedFrontmatter, type ParsedQuery, type ParsedRowsQuery, type ParsedWqlLastSuffix, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type ResultLogStore, type RowsQueryResult, type RowsRun, SEMVER, type Series, type SeriesPoint, type SummaryFactIdentity, type SummaryFactSourceOutput, type TagFilter, type TagValue, UNIT_FAMILIES, type UnitFamily, type UnitFamilyDef, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_DISPLAY_UNITS, WQL_FIND_TARGETS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_ROLLUP_PERIODS, WQL_SCOPES, WQL_SOURCES, WQL_TAG_KEYS, WQL_VIRTUAL_DIMS, type WqlAggregator, type WqlCalcTarget, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlFindTarget, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlRollupPeriod, type WqlScope, type WqlSource, type WqlTagKey, type WqlVirtualDim, buildDashboardDocument, buildDashboardScaffold, convert, dashboardSlug, defaultTokenValues, disciplineFactorFor, extractDashboardTokens, extractFrontmatterTags, getList, getScalar, getUnitFamily, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isProposedMetric, isRowsQuery, normalizeSummaryFacts, parseDashboardNote, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, referencedTokens, resolveCanonicalMetricKey, resolveDisplayUnit, resolveWidgetType, serializeFrontmatter, setDashboardTokenValue, splitAtWhere, splitWidgetBody, staticNotesFromBlocks, staticTagIndexFromBlocks, stripFrontmatter, substituteTokens, unknownTokensMessage, unknownWidgetTypeMessage, wql, wqlCompletion, wqlCompletionSource, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms };
957
+ export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, 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, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type EventRowIdentity, type FindOptions, type FindPredicate, type FindQueryResult, GIT_SHA, type IEffort, KG_PER_LB, type LinkWidget, type MetricPredicate, type NoteQueryStore, PLANNED_WIDGET_TYPES, type ParsedFindQuery, type ParsedFrontmatter, type ParsedQuery, type ParsedRowsQuery, type ParsedWqlLastSuffix, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type RowsQueryResult, type RowsRun, SEMVER, type Series, type SeriesPoint, type SummaryFactIdentity, type SummaryFactSourceOutput, type TagFilter, type TagValue, UNIT_FAMILIES, type UnifiedEventStore, type UnitFamily, type UnitFamilyDef, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_DISPLAY_UNITS, WQL_FIND_TARGETS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_ROLLUP_PERIODS, WQL_SCOPES, WQL_SOURCES, WQL_TAG_KEYS, WQL_VIRTUAL_DIMS, type WqlAggregator, type WqlCalcTarget, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlFindTarget, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlRollupPeriod, type WqlScope, type WqlSource, type WqlTagKey, type WqlVirtualDim, buildDashboardDocument, buildDashboardScaffold, convert, dashboardSlug, defaultTokenValues, disciplineFactorFor, extractDashboardTokens, extractFrontmatterTags, getList, getScalar, getUnitFamily, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isProposedMetric, isRowsQuery, normalizeSummaryFacts, parseDashboardNote, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, projectEventToFacts, referencedTokens, resolveCanonicalMetricKey, resolveDisplayUnit, resolveWidgetType, serializeFrontmatter, setDashboardTokenValue, splitAtWhere, splitWidgetBody, staticNotesFromBlocks, staticTagIndexFromBlocks, stripFrontmatter, substituteTokens, toEventRows, toSummaryEventRows, unknownTokensMessage, unknownWidgetTypeMessage, wql, wqlCompletion, wqlCompletionSource, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { LRParser } from '@lezer/lr';
2
2
  import { LanguageSupport, HighlightStyle, LRLanguage } from '@codemirror/language';
3
3
  import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
4
4
  import { Extension } from '@codemirror/state';
5
- import { ResultOrigin, AnalyticsDataPoint, BlockIndexRow, Note, WorkoutResult, StoredOutputStatement } from '@bitcobblers/wod-wiki-core';
5
+ import { ResultOrigin, AnalyticsDataPoint, UnifiedEventRecord, StoredOutputStatement, BlockIndexRow, Note } from '@bitcobblers/wod-wiki-core';
6
6
 
7
7
  /**
8
8
  * WQL vocabulary — the single owner of the WQL dictionary: aggregators,
@@ -50,7 +50,10 @@ declare const WQL_CALC_TARGETS: readonly ["calc.metMinutes", "calc.acwr", "calc.
50
50
  type WqlCalcTarget = (typeof WQL_CALC_TARGETS)[number];
51
51
  declare const WQL_INTENSITY_TIERS: readonly ["low", "moderate", "high"];
52
52
  type WqlIntensityTier = (typeof WQL_INTENSITY_TIERS)[number];
53
- declare const WQL_GRAINS: readonly ["segment", "summary", "rollup"];
53
+ /** Unified store grains (ticket 003): 'summary' | 'event'. The legacy
54
+ * 'segment' grain was renamed to 'event' (ticket 002); 'rollup' is retired —
55
+ * rollups are computed at read time via the .rollup suffix, never stored. */
56
+ declare const WQL_GRAINS: readonly ["summary", "event"];
54
57
  type WqlGrain = (typeof WQL_GRAINS)[number];
55
58
  /** Content-discovery query targets (find:<target>). */
56
59
  declare const WQL_FIND_TARGETS: readonly ["note", "block", "effort"];
@@ -460,6 +463,29 @@ interface SummaryFactSourceOutput {
460
463
  * into persisted fact rows — one row per result × Canonical Metric Key.
461
464
  */
462
465
  declare function normalizeSummaryFacts(logs: readonly SummaryFactSourceOutput[], identity: SummaryFactIdentity): AnalyticsDataPoint[];
466
+ /** Identity for unified event-row emission — same fields as the fact identity. */
467
+ type EventRowIdentity = SummaryFactIdentity;
468
+ /**
469
+ * Logs → event rows, 1:1 per statement (ticket 002). Deterministic ids
470
+ * `${resultId}:${seq}`; canonical workout time wins over the statement's own
471
+ * timeSpan; query-critical scalars promoted top-level.
472
+ */
473
+ declare function toEventRows(logs: readonly StoredOutputStatement[], identity: SummaryFactIdentity): UnifiedEventRecord[];
474
+ /**
475
+ * Tier-2 analytics outputs → deterministic summary event rows (tickets
476
+ * 002/004): id `${resultId}:summary:${rowKey}` — no timestamp salt, so
477
+ * re-finalize overwrites cleanly. Fold identity lives in metrics[0].metadata
478
+ * (canonicalKey, effort metadata, groupTags) — shape-uniform with events.
479
+ */
480
+ declare function toSummaryEventRows(logs: readonly StoredOutputStatement[], identity: SummaryFactIdentity): UnifiedEventRecord[];
481
+ /**
482
+ * Event row → flat fact currency for the four-stage plan (ticket 003):
483
+ * one AnalyticsDataPoint per numeric metric. Canonical key resolution
484
+ * mirrors the summary fold — metadata.canonicalKey first, name-derived
485
+ * from the row's label metric as fallback. Deterministic fact ids:
486
+ * `${record.id}:${factOrdinal}`.
487
+ */
488
+ declare function projectEventToFacts(record: UnifiedEventRecord): AnalyticsDataPoint[];
463
489
 
464
490
  /**
465
491
  * Pure projection of a block_index into static Notes — one Note per distinct
@@ -480,18 +506,42 @@ declare function staticTagIndexFromBlocks(blocks: BlockIndexRow[]): Map<string,
480
506
  /**
481
507
  * Injected store interfaces for WQL QueryService.
482
508
  * Zero database/storage dependencies — 100% pure abstractions.
509
+ *
510
+ * Ticket 003: FactQueryStore + ResultLogStore collapsed into the single
511
+ * UnifiedEventStore — two names for one data source. The content plane
512
+ * (notes / blocks / efforts) is unchanged by workout-data unification.
483
513
  */
484
514
 
485
- /** Store surface the Query Service needs for fact rows. */
486
- interface FactQueryStore {
487
- getFactsByMetric(metricKey: string): Promise<AnalyticsDataPoint[]>;
488
- getFactsByTimeRange(start: number, end: number): Promise<AnalyticsDataPoint[]>;
489
- getNoteTagLabels(noteId: string): Promise<string[]>;
515
+ /**
516
+ * Store surface for the unified event table — every workout-data read the
517
+ * Query Service needs, plus the write contract owned by the write-path
518
+ * lifecycle (ticket 005).
519
+ */
520
+ interface UnifiedEventStore {
521
+ /** Windowed fetch — the one proven culling index (ticket 001). */
522
+ getEventsByTimeRange(start: number, end: number): Promise<UnifiedEventRecord[]>;
523
+ /** Per-result fetch (rows:{result:…}, re-finalize, orphan inspection). */
524
+ getEventsByResult(resultId: string): Promise<UnifiedEventRecord[]>;
525
+ /** Note-scoped fetch (rows:{note:…}). */
526
+ getEventsForNote(noteId: string): Promise<UnifiedEventRecord[]>;
527
+ /** Content-scoped fetch — the cross-store join hot path (indexed). */
528
+ getEventsByContent(blockContentId: string): Promise<UnifiedEventRecord[]>;
529
+ /** Full scan — all-time SELECT leg (ticket 001: scan beats non-selective indexes). */
530
+ scanAll(): Promise<UnifiedEventRecord[]>;
531
+ /** Append event rows (per-statement flush; same-tick coalescing allowed). */
532
+ appendEvents(rows: UnifiedEventRecord[]): Promise<void>;
533
+ /** Atomic finalize: clear the result's engine-authored summaries, write finals. */
534
+ finalizeSummaries(resultId: string, rows: UnifiedEventRecord[]): Promise<void>;
535
+ /** Reconcile deletes (wellness note-save) + GC sweeps. */
536
+ deleteEvents(ids: string[]): Promise<void>;
490
537
  }
491
538
  /** Store surface for content queries (`find:note`). */
492
539
  interface NoteQueryStore {
493
540
  getAllNotes(): Promise<Note[]>;
494
541
  getNoteIdsForTag(label: string): Promise<Set<string>>;
542
+ /** Note-tags label set of one note (moved here from FactQueryStore — it
543
+ * reads note tags, not facts). */
544
+ getNoteTagLabels(noteId: string): Promise<string[]>;
495
545
  }
496
546
  /** Store surface for block-index queries (`find:block`). */
497
547
  interface BlockQueryStore {
@@ -516,39 +566,33 @@ interface IEffort {
516
566
  interface EffortQueryStore {
517
567
  getAllEfforts(): Promise<IEffort[]>;
518
568
  }
519
- /** Store surface for raw WorkoutResult logs — the cross-store join & rows source. */
520
- interface ResultLogStore {
521
- getResultsByContentId(blockContentId: string): Promise<WorkoutResult[]>;
522
- /** Rows plane (#949): single-result scope (`rows:{result:…}`). */
523
- getResultById(resultId: string): Promise<WorkoutResult | undefined>;
524
- /** Rows plane (#949): whole-note scope (`rows:{note:…}`). */
525
- getResultsForNote(noteId: string): Promise<WorkoutResult[]>;
526
- }
527
569
  /** Optional bundle of stores for QueryService initialization. */
528
570
  interface QueryServiceStores {
529
- factStore?: FactQueryStore;
571
+ eventStore?: UnifiedEventStore;
530
572
  noteStore?: NoteQueryStore;
531
573
  blockStore?: BlockQueryStore;
532
- resultStore?: ResultLogStore;
533
574
  effortStore?: EffortQueryStore;
534
575
  staticNoteStore?: NoteQueryStore;
535
576
  staticBlockStore?: BlockQueryStore;
536
577
  }
537
578
 
538
579
  /**
539
- * Query Service — the executor of WQL against the Analytics Store
540
- * (CONTEXT.md glossary). Four-stage physical plan:
580
+ * Query Service — the executor of WQL against the unified event store.
581
+ * Four-stage physical plan:
541
582
  *
542
- * SELECT (index-first: by-metric + by-timestamp IDBKeyRange fetches,
543
- * intersected in memory)
583
+ * SELECT (window-first hybrid, ticket 003: windowed queries fetch through
584
+ * by-timestamp — the one proven culling index; all-time queries
585
+ * scan; by-metric is never used. Event rows are flattened to the
586
+ * legacy flat-fact currency by projectEventToFacts.)
544
587
  * BUCKET (time dim or rollup period)
545
588
  * AGGREGATE (per bucket)
546
589
  * GROUP (tag-dimension fan-out)
547
590
  *
548
591
  * Inputs are uncapped — personal-journal scale; widgets and tables are dumb
549
- * consumers of QueryResult. Fact rows are summary-grain AnalyticsDataPoint
550
- * rows; Tags are query-time dimensions read off the row (effort, discipline,
551
- * note, intensity, …) — 'tags' resolves through the note_tags store.
592
+ * consumers of QueryResult. The store serves UnifiedEventRecord rows
593
+ * (grain 'event' | 'summary'); Tags are query-time dimensions read off the
594
+ * projected fact row (effort, discipline, note, intensity, …) — 'tags'
595
+ * resolves through the note_tags store.
552
596
  *
553
597
  * Fully inverted dependencies: zero IndexedDB/storage module-level imports.
554
598
  */
@@ -600,11 +644,14 @@ interface QueryResult {
600
644
  /** Result display unit, if determined by directive, preference, or fact metadata. */
601
645
  unit?: string;
602
646
  }
603
- /** One run in a rows result: the stored result plus the output statements
604
- * that survived the optional output-type narrowing (`rows:segment{…}`). */
647
+ /** One run in a rows result: the canonical result identity plus the event
648
+ * rows that survived the optional output-type narrowing (`rows:segment{…}`). */
605
649
  interface RowsRun {
606
- result: WorkoutResult;
607
- logs: StoredOutputStatement[];
650
+ resultId: string;
651
+ noteId: string;
652
+ /** Canonical workout time (result.createdAt under the unified model). */
653
+ timestamp: number;
654
+ events: UnifiedEventRecord[];
608
655
  }
609
656
  interface RowsQueryResult {
610
657
  parsed: ParsedRowsQuery;
@@ -615,17 +662,17 @@ declare class QueryService {
615
662
  private readonly store;
616
663
  private readonly noteStore;
617
664
  private readonly blockStore;
618
- private readonly resultStore;
619
665
  private readonly effortStore;
620
666
  private readonly staticNoteStore?;
621
667
  private readonly staticBlockStore?;
622
- constructor(storesOrFactStore?: QueryServiceStores | FactQueryStore, noteStore?: NoteQueryStore, blockStore?: BlockQueryStore, resultStore?: ResultLogStore, effortStore?: EffortQueryStore, staticNoteStore?: NoteQueryStore, staticBlockStore?: BlockQueryStore);
668
+ constructor(storesOrEventStore?: QueryServiceStores | UnifiedEventStore, noteStore?: NoteQueryStore, blockStore?: BlockQueryStore, effortStore?: EffortQueryStore, staticNoteStore?: NoteQueryStore, staticBlockStore?: BlockQueryStore);
669
+ /** Windowed flat-fact fetch — the projected view over the event store. */
623
670
  getFactsByTimeRange(start: number, end: number): Promise<AnalyticsDataPoint[]>;
624
671
  runQuery(raw: string, options?: QueryOptions): Promise<QueryResult>;
625
672
  /**
626
673
  * Execute a rows query (rows:{…}, #949) — the session results table plane.
627
- * Re-derives output statements from raw WorkoutResult logs through the
628
- * ResultLogStore seam ("logs win" — facts are never read for this path).
674
+ * Reads event rows directly over the unified store (ticket 003): no
675
+ * WorkoutResult blob parsing; outputType narrowing hits the promoted column.
629
676
  */
630
677
  runRows(parsed: ParsedRowsQuery, options?: {
631
678
  anchorNow?: number;
@@ -663,9 +710,10 @@ declare class QueryService {
663
710
  /** Filter per-effort vs un-attributed overall summary rows to avoid
664
711
  * double-counting. */
665
712
  private applyEffortScope;
666
- /** Re-derive summary facts for one Canonical Metric Key from RAW WorkoutResult
667
- * logs across the given content ids — the cross-store join source. One fact
668
- * row per result (normalizeSummaryFacts dedupes within a result). */
713
+ /** Summary facts for one Canonical Metric Key across the given content ids —
714
+ * the cross-store join source. Reads finalize-written summary rows straight
715
+ * off the content index (ticket 003: the store is authoritative; the old
716
+ * freshness re-derivation is moot). One fact row per result × rowKey. */
669
717
  private deriveMetricFacts;
670
718
  /** All content blocks across the journal + static corpus. */
671
719
  private allContentBlocks;
@@ -897,13 +945,13 @@ declare function parseFrontmatterProps(lines: string[]): Record<string, string>;
897
945
  * Auto-generated build version metadata.
898
946
  * Do not edit directly; updated by scripts/stamp-version.ts
899
947
  */
900
- declare const VERSION = "0.6.32";
901
- declare const GIT_SHA = "bc13c0f";
902
- declare const BUILD_TIME = "2026-08-21T20:12:50.453Z";
948
+ declare const VERSION = "0.6.36";
949
+ declare const GIT_SHA = "c5ad2b0";
950
+ declare const BUILD_TIME = "2026-08-24T20:14:33.951Z";
903
951
  declare const SEMVER: {
904
- readonly version: "0.6.32";
905
- readonly gitSha: "bc13c0f";
906
- readonly buildTime: "2026-08-21T20:12:50.453Z";
952
+ readonly version: "0.6.36";
953
+ readonly gitSha: "c5ad2b0";
954
+ readonly buildTime: "2026-08-24T20:14:33.951Z";
907
955
  };
908
956
 
909
- export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, 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, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type FactQueryStore, type FindOptions, type FindPredicate, type FindQueryResult, GIT_SHA, type IEffort, KG_PER_LB, type LinkWidget, type MetricPredicate, type NoteQueryStore, PLANNED_WIDGET_TYPES, type ParsedFindQuery, type ParsedFrontmatter, type ParsedQuery, type ParsedRowsQuery, type ParsedWqlLastSuffix, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type ResultLogStore, type RowsQueryResult, type RowsRun, SEMVER, type Series, type SeriesPoint, type SummaryFactIdentity, type SummaryFactSourceOutput, type TagFilter, type TagValue, UNIT_FAMILIES, type UnitFamily, type UnitFamilyDef, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_DISPLAY_UNITS, WQL_FIND_TARGETS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_ROLLUP_PERIODS, WQL_SCOPES, WQL_SOURCES, WQL_TAG_KEYS, WQL_VIRTUAL_DIMS, type WqlAggregator, type WqlCalcTarget, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlFindTarget, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlRollupPeriod, type WqlScope, type WqlSource, type WqlTagKey, type WqlVirtualDim, buildDashboardDocument, buildDashboardScaffold, convert, dashboardSlug, defaultTokenValues, disciplineFactorFor, extractDashboardTokens, extractFrontmatterTags, getList, getScalar, getUnitFamily, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isProposedMetric, isRowsQuery, normalizeSummaryFacts, parseDashboardNote, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, referencedTokens, resolveCanonicalMetricKey, resolveDisplayUnit, resolveWidgetType, serializeFrontmatter, setDashboardTokenValue, splitAtWhere, splitWidgetBody, staticNotesFromBlocks, staticTagIndexFromBlocks, stripFrontmatter, substituteTokens, unknownTokensMessage, unknownWidgetTypeMessage, wql, wqlCompletion, wqlCompletionSource, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms };
957
+ export { type Aggregator, type AnyParsedQuery, BUILD_TIME, type BlockQueryStore, 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, EFFORT_DISCIPLINES, type EffortDiscipline, type EffortQueryStore, type EventRowIdentity, type FindOptions, type FindPredicate, type FindQueryResult, GIT_SHA, type IEffort, KG_PER_LB, type LinkWidget, type MetricPredicate, type NoteQueryStore, PLANNED_WIDGET_TYPES, type ParsedFindQuery, type ParsedFrontmatter, type ParsedQuery, type ParsedRowsQuery, type ParsedWqlLastSuffix, type ParsedWqlRollupSuffix, type ParsedWqlSuffixes, type QueryOptions, type QueryResult, QueryService, type QueryServiceStores, type QueryWidgetSuffix, type RowsQueryResult, type RowsRun, SEMVER, type Series, type SeriesPoint, type SummaryFactIdentity, type SummaryFactSourceOutput, type TagFilter, type TagValue, UNIT_FAMILIES, type UnifiedEventStore, type UnitFamily, type UnitFamilyDef, VERSION, WQL_AGGREGATORS, WQL_CALC_TARGETS, WQL_COMPARISON_OPS, WQL_CONTENT_FILTER_KEYS, WQL_DISPLAY_UNITS, WQL_FIND_TARGETS, WQL_GRAINS, WQL_INTENSITY_TIERS, WQL_KEYWORDS, WQL_METRIC_AGGREGATES, WQL_METRIC_FAMILIES, WQL_ROLLUP_PERIODS, WQL_SCOPES, WQL_SOURCES, WQL_TAG_KEYS, WQL_VIRTUAL_DIMS, type WqlAggregator, type WqlCalcTarget, type WqlComparisonOp, type WqlCompletionOptions, type WqlContentFilterKey, type WqlDisplayUnit, type WqlFindTarget, type WqlGrain, type WqlIntensityTier, type WqlKeyword, type WqlMetricAggregate, type WqlMetricFamily, type WqlRollupPeriod, type WqlScope, type WqlSource, type WqlTagKey, type WqlVirtualDim, buildDashboardDocument, buildDashboardScaffold, convert, dashboardSlug, defaultTokenValues, disciplineFactorFor, extractDashboardTokens, extractFrontmatterTags, getList, getScalar, getUnitFamily, isDashboardMeta, isDashboardWidgetType, isEffortDiscipline, isFindQuery, isProposedMetric, isRowsQuery, normalizeSummaryFacts, parseDashboardNote, parseFlatProperties, parseFrontmatter, parseFrontmatterBody, parseFrontmatterCategories, parseFrontmatterProps, parseQuery, parseQueryWidgetSuffix, parseWqlSuffixes, projectEventToFacts, referencedTokens, resolveCanonicalMetricKey, resolveDisplayUnit, resolveWidgetType, serializeFrontmatter, setDashboardTokenValue, splitAtWhere, splitWidgetBody, staticNotesFromBlocks, staticTagIndexFromBlocks, stripFrontmatter, substituteTokens, toEventRows, toSummaryEventRows, unknownTokensMessage, unknownWidgetTypeMessage, wql, wqlCompletion, wqlCompletionSource, wqlHighlightStyle, wqlLanguage, parser as wqlParser, wql_parser_terms as wqlTerms };