@bitcobblers/wod-wiki-core 0.1.0

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.
@@ -0,0 +1,1075 @@
1
+ /**
2
+ * Canonical ownership vocabulary for metric visibility decisions.
3
+ *
4
+ * This is intentionally separate from {@link MetricOrigin}, which still carries
5
+ * legacy producer/state detail used by existing callers.
6
+ *
7
+ * Ordered from lowest to highest ownership precedence.
8
+ */
9
+ type MetricOwnershipLayer = 'parser' | 'dialect' | 'user-plan' | 'runtime' | 'user-entry';
10
+ /**
11
+ * Canonical low->high ownership chain used by characterization tests and
12
+ * ownership resolution work.
13
+ */
14
+ declare const METRIC_OWNERSHIP_LAYER_CHAIN: readonly MetricOwnershipLayer[];
15
+ /**
16
+ * Compatibility map from the current mixed-purpose `origin` field into the
17
+ * canonical ownership-layer vocabulary.
18
+ */
19
+ declare const LEGACY_ORIGIN_TO_OWNERSHIP_LAYER: Record<MetricOrigin, MetricOwnershipLayer>;
20
+ interface MetricWithOptionalOwnershipLayer extends IMetric {
21
+ readonly ownershipLayer?: MetricOwnershipLayer;
22
+ }
23
+ interface MetricOwnershipQuery {
24
+ readonly types?: readonly (IMetric['type'])[];
25
+ readonly layers?: readonly MetricOwnershipLayer[];
26
+ }
27
+ type MetricOwnershipOutcome = 'visible' | 'hidden-by-layer' | 'hidden-by-suppressor' | 'suppressor';
28
+ interface MetricOwnershipResolvedContribution {
29
+ readonly metric: IMetric;
30
+ readonly type: IMetric['type'];
31
+ readonly layer: MetricOwnershipLayer;
32
+ readonly outcome: MetricOwnershipOutcome;
33
+ }
34
+ interface MetricOwnershipPromotionCandidate {
35
+ readonly metric: IMetric;
36
+ readonly type: IMetric['type'];
37
+ readonly layer: MetricOwnershipLayer;
38
+ readonly reason: 'shadowed-by-higher-layer' | 'suppressed';
39
+ readonly blockedByLayer?: MetricOwnershipLayer;
40
+ }
41
+ interface MetricOwnershipTypeExplanation {
42
+ readonly type: IMetric['type'];
43
+ readonly winnerLayer?: MetricOwnershipLayer;
44
+ readonly suppressed: boolean;
45
+ readonly entries: readonly MetricOwnershipResolvedContribution[];
46
+ }
47
+ interface MetricOwnershipLedger {
48
+ raw(query?: MetricOwnershipQuery): IMetric[];
49
+ visible(query?: MetricOwnershipQuery): IMetric[];
50
+ byLayer(query?: MetricOwnershipQuery): Partial<Record<MetricOwnershipLayer, IMetric[]>>;
51
+ promotionCandidates(query?: MetricOwnershipQuery): MetricOwnershipPromotionCandidate[];
52
+ explain(query?: MetricOwnershipQuery): MetricOwnershipTypeExplanation[];
53
+ }
54
+ declare function getMetricOwnershipLayer(origin: MetricOrigin | undefined): MetricOwnershipLayer;
55
+
56
+ /**
57
+ * Origin of a metric - where it was created and its current state.
58
+ *
59
+ * Source origins:
60
+ * - 'parser': Created by the parser from source text
61
+ * - 'compiler': Synthesized by a compiler strategy
62
+ * - 'dialect': Synthesized by a dialect policy before runtime
63
+ * - 'runtime': Generated during execution (e.g., elapsed time)
64
+ * - 'user': Collected from user input (e.g., actual reps completed)
65
+ *
66
+ * Value states:
67
+ * - 'collected': Value has been collected and populated
68
+ * - 'hinted': Value is a hint or suggestion not strictly enforced
69
+ * - 'tracked': Value is actively being tracked during execution
70
+ * - 'analyzed': Value is derived from analysis
71
+ * - 'analyzed-estimated': Value is derived from estimation
72
+ * - 'execution': Generated by runtime execution
73
+ * - 'user-plan': Planned override set by user before execution
74
+ */
75
+ type MetricAction = 'suppress';
76
+ type MetricOrigin = 'parser' | 'compiler' | 'dialect' | 'runtime' | 'user' | 'collected' | 'hinted' | 'tracked' | 'analyzed' | 'analyzed-estimated' | 'execution' | 'user-plan';
77
+ type Origin = MetricOrigin;
78
+ interface IMetric {
79
+ readonly image?: string;
80
+ readonly value?: unknown;
81
+ /**
82
+ * The metric type. Use a `MetricType` enum value for standard types, or any
83
+ * string for custom derived metrics produced by enrichment processes
84
+ * (e.g. `'speed'`, `'pace'`, `'rep-rate'`, `'power'`).
85
+ */
86
+ readonly type: MetricType | string;
87
+ /** Backward-compatible alias for type */
88
+ readonly metricType?: MetricType | string;
89
+ readonly origin: MetricOrigin;
90
+ readonly unit?: string;
91
+ /**
92
+ * Visibility instruction. The only live value is `'suppress'`, which hides
93
+ * all metrics of this type from display (resolved by the ownership ledger).
94
+ * Most metrics carry no action (undefined = passive).
95
+ */
96
+ readonly action?: MetricAction;
97
+ /**
98
+ * Block key that created/owns this metric.
99
+ * Present for runtime and user-collected metrics.
100
+ */
101
+ readonly sourceBlockKey?: string;
102
+ /**
103
+ * Timestamp when this metric was created/recorded.
104
+ * Present for runtime and user-collected metrics.
105
+ */
106
+ readonly timestamp?: Date;
107
+ /**
108
+ * Processor-attached structured payload. Summary processors (e.g. TIS) hang
109
+ * derivation metadata (effortSlug, effortDiscipline, effortIntensityTier,
110
+ * component scores) on the projection value metric; fact normalization reads
111
+ * it back out. Pure data — survives the stored-logs round-trip.
112
+ */
113
+ readonly metadata?: Record<string, unknown>;
114
+ /** Optional explicit ownership layer for legacy compatibility */
115
+ readonly ownershipLayer?: MetricOwnershipLayer;
116
+ /** Optional human-readable name or label */
117
+ readonly name?: string;
118
+ }
119
+ /**
120
+ * Metric type enumeration.
121
+ *
122
+ * Time-related terms follow the glossary in docs/architecture/time-terminology.md:
123
+ * - **Duration** (Parser) — planned target from the script (e.g., "5:00" -> 300 000 ms)
124
+ * - **Time / Spans** (Block) — the raw TimeSpan[] start/stop recordings a block tracks
125
+ * - **TimeStamp** (Runtime) — system Date.now() when a message is logged
126
+ * - **Elapsed** (Runtime) — Σ(end - start) of each span segment (active time, excludes pauses)
127
+ * - **Total** (Runtime) — lastEnd - firstStart (wall-clock bracket, includes pauses)
128
+ */
129
+ declare enum MetricType {
130
+ /**
131
+ * **Duration** (Core) — parser-defined planned target.
132
+ *
133
+ * A metric defined by the CodeStatement during parsing (e.g., "5:00" -> 300 000 ms).
134
+ * It can be a time (duration) or a placeholder to be resolved.
135
+ * Owned by the parser — the runtime reads it but never computes it.
136
+ */
137
+ Duration = "duration",
138
+ /**
139
+ * **Spans** (Core) — raw start/stop TimeSpan[] recordings.
140
+ *
141
+ * Source-of-truth data recorded using the runtime clock.
142
+ * Each span represents a continuous period of active (unpaused) execution.
143
+ * These can be recorded at runtime or back-filled during analytics.
144
+ */
145
+ Spans = "spans",
146
+ /**
147
+ * **SystemTime** (Core) — real system time (Date.now()) when a message is logged.
148
+ *
149
+ * Ground-truth wall-clock reference (timestamp) associated with system time metrics.
150
+ * Independent of the runtime clock.
151
+ */
152
+ SystemTime = "system-time",
153
+ /** Live timer state written into block memory by the count-up/count-down timer behaviors. */
154
+ Time = "time",
155
+ /** Active elapsed time — Σ(end - start) of active spans; derived during analytics. */
156
+ Elapsed = "elapsed",
157
+ /** Total wall-clock bracket (lastEnd - firstStart) for a block; derived during analytics. */
158
+ Total = "total",
159
+ Rep = "rep",
160
+ Effort = "effort",
161
+ Distance = "distance",
162
+ Rounds = "rounds",
163
+ CurrentRound = "current-round",
164
+ Action = "action",
165
+ Increment = "increment",
166
+ Group = "group",
167
+ Text = "text",
168
+ Resistance = "resistance",
169
+ Sound = "sound",
170
+ System = "system",
171
+ Label = "label",
172
+ Lap = "lap",
173
+ Metric = "metric",
174
+ /**
175
+ * **Hint** (Core) — a semantic marker emitted by a dialect or the parser.
176
+ *
177
+ * Dot-namespaced string markers (e.g. `workout.amrap`, `behavior.required_timer`)
178
+ * that strategies and the label composer query to drive compilation decisions.
179
+ * Hints are metrics so they flow through the single ownership channel, but they
180
+ * are excluded from display resolution and from runtime block fragments.
181
+ */
182
+ Hint = "hint",
183
+ /** Generic custom metric bucket for parser-owned property metrics. */
184
+ Custom = "custom",
185
+ Volume = "volume",
186
+ Intensity = "intensity",
187
+ Load = "load",
188
+ Work = "work",
189
+ /** Per-set Reps in Reserve (real-time, strength) */
190
+ RIR = "rir",
191
+ /** Post-session subjective effort rating (0–10) */
192
+ SessionRPE = "session-rpe",
193
+ /** Session RPE x total minutes */
194
+ SessionLoad = "session-load",
195
+ /** Normalized MET ((Activity METs ÷ METmax) x 100) */
196
+ METScore = "met-score",
197
+ /** Training Intensity Score (composite) */
198
+ TIS = "tis",
199
+ /** Runtime-layer calculated metric emitted from declarative formulas */
200
+ Calculated = "calculated",
201
+ /**
202
+ * **Choice** (Parser) — a pipe-separated OR expression.
203
+ *
204
+ * Emitted by Fusion when a pipe separates two homogeneous alternatives
205
+ * (same MetricType on both sides). Carries `alternatives: IMetric[]`.
206
+ * Resolved in the Pre-Run Wizard before the JIT compiles: the chosen
207
+ * alternative is written at origin `user-plan` into the Statement's
208
+ * MetricContainer, shadowing this group via ownership-layer precedence.
209
+ * Never reaches compiled Blocks or display output once resolved.
210
+ */
211
+ Choice = "choice"
212
+ }
213
+ /**
214
+ * Concrete helper class implementing IMetric
215
+ */
216
+ declare class Metric implements IMetric {
217
+ readonly type: MetricType | string;
218
+ readonly metricType?: MetricType | string;
219
+ readonly value?: unknown;
220
+ readonly origin: MetricOrigin;
221
+ readonly unit?: string;
222
+ readonly action?: MetricAction;
223
+ readonly image?: string;
224
+ readonly sourceBlockKey?: string;
225
+ readonly timestamp?: Date;
226
+ readonly metadata?: Record<string, unknown>;
227
+ readonly name?: string;
228
+ readonly ownershipLayer?: MetricOwnershipLayer;
229
+ constructor(typeOrName: MetricType | string, valueOrType?: unknown, originOrValue?: unknown, unit?: string, origin?: MetricOrigin | string, action?: MetricAction | string, image?: string);
230
+ toNumber(): number;
231
+ }
232
+
233
+ /**
234
+ * Filter configuration for metric retrieval.
235
+ */
236
+ interface MetricFilter {
237
+ /** Only include metrics with these origins */
238
+ origins?: MetricOrigin[];
239
+ /** Only include these metric types */
240
+ types?: (MetricType | string)[];
241
+ /** Exclude these metric types */
242
+ excludeTypes?: (MetricType | string)[];
243
+ }
244
+ /**
245
+ * Unified contract for any data object that provides displayable metrics.
246
+ *
247
+ * Implemented by CodeStatement, OutputStatement, and MetricContainer.
248
+ * Consumed directly by UI components.
249
+ *
250
+ * All metric access goes through this interface, ensuring:
251
+ * 1. Consistent precedence resolution
252
+ * 2. Multi-metric-per-type support
253
+ * 3. Origin-aware filtering
254
+ * 4. Source-type-agnostic UI rendering
255
+ */
256
+ interface IMetricSource {
257
+ /**
258
+ * Unique identifier for React keys and tracking.
259
+ */
260
+ readonly id: string | number;
261
+ /**
262
+ * Get the "display-ready" metrics after precedence resolution.
263
+ *
264
+ * For each MetricType present, returns metrics from the highest-
265
+ * precedence origin tier. Multiple metrics of the same type within
266
+ * the winning tier are preserved (e.g., 3 rep metrics for 21-15-9).
267
+ *
268
+ * @param filter Optional filter to restrict which metrics are returned
269
+ */
270
+ getDisplayMetrics(filter?: MetricFilter): IMetric[];
271
+ /**
272
+ * Get the highest-precedence single metric of a given type.
273
+ *
274
+ * Precedence order: user-entry > runtime > user-plan > dialect > parser
275
+ *
276
+ * @param type The metric type to look up
277
+ * @returns The winning metric, or undefined if none exist
278
+ */
279
+ getMetric(type: MetricType | string): IMetric | undefined;
280
+ /**
281
+ * Get ALL metrics of a given type, ordered by precedence (highest first).
282
+ *
283
+ * Use when multiple metrics of the same type are meaningful
284
+ * (e.g., rep scheme 21-15-9, multiple actions in a complex).
285
+ */
286
+ getAllMetricsByType(type: MetricType | string): IMetric[];
287
+ /**
288
+ * Check if any metric of this type exists (at any precedence level).
289
+ */
290
+ hasMetric(type: MetricType | string): boolean;
291
+ /**
292
+ * Access the raw, unfiltered metrics for debugging or advanced use.
293
+ * No precedence resolution applied.
294
+ */
295
+ readonly rawMetrics: IMetric[];
296
+ }
297
+
298
+ interface ICodeMetadata {
299
+ line: number;
300
+ startOffset: number;
301
+ endOffset: number;
302
+ columnStart: number;
303
+ columnEnd: number;
304
+ length: number;
305
+ raw?: string;
306
+ }
307
+ declare class CodeMetadata implements ICodeMetadata {
308
+ line: number;
309
+ startOffset: number;
310
+ endOffset: number;
311
+ length: number;
312
+ columnStart: number;
313
+ columnEnd: number;
314
+ raw: string;
315
+ constructor(line: number, startOffset: number, endOffset: number, length: number, columnStart?: number, columnEnd?: number, raw?: string);
316
+ }
317
+
318
+ /**
319
+ * MetricContainer — a typed collection for `IMetric` objects.
320
+ *
321
+ * Provides lookup, add, remove, merge, and iteration operations over a
322
+ * flat `IMetric[]` array. Standard way to work with metric collections on
323
+ * `ICodeStatement`, `IRuntimeBlock`, and `OutputStatement`.
324
+ *
325
+ * Numeric indexes are mirrored for backwards compatibility with legacy
326
+ * `metrics[0]` call sites.
327
+ */
328
+ declare class MetricContainer implements IMetricSource, Iterable<IMetric> {
329
+ [index: number]: IMetric;
330
+ private _metrics;
331
+ private _indexedLength;
332
+ private readonly _resolver;
333
+ readonly id: string | number;
334
+ constructor(metrics?: IMetric[] | MetricContainer, id?: string | number);
335
+ /**
336
+ * Create a container from an existing metric array, MetricContainer, or
337
+ * a deserialized plain object.
338
+ */
339
+ static from(metrics: IMetric[] | MetricContainer | undefined | unknown, id?: string | number): MetricContainer;
340
+ /** Create an empty container. */
341
+ static empty(id?: string | number): MetricContainer;
342
+ /** Create a defensive copy of this container. */
343
+ clone(id?: string | number): MetricContainer;
344
+ /** All metrics in insertion order. Returns a defensive copy. */
345
+ get all(): readonly IMetric[];
346
+ /** Number of metrics in the container. */
347
+ get length(): number;
348
+ /** Alias for length */
349
+ get size(): number;
350
+ /** Whether the container has no metrics. */
351
+ get isEmpty(): boolean;
352
+ /**
353
+ * Get all metrics of a given MetricType / name, sorted by ownership layer
354
+ * (highest precedence first).
355
+ */
356
+ getByType(type: MetricType | string): IMetric[];
357
+ /**
358
+ * Get the highest-precedence metric of a given type/name, or undefined.
359
+ */
360
+ getFirst(type: MetricType | string): IMetric | undefined;
361
+ /**
362
+ * Lookup a metric by type or name.
363
+ */
364
+ get(type: MetricType | string): IMetric | undefined;
365
+ /** Whether any metric of the given type/name exists. */
366
+ has(type: MetricType | string): boolean;
367
+ hasMetric(type: MetricType | string): boolean;
368
+ getDisplayMetrics(filter?: MetricFilter): IMetric[];
369
+ getMetric(type: MetricType | string): IMetric | undefined;
370
+ getAllMetricsByType(type: MetricType | string): IMetric[];
371
+ get rawMetrics(): IMetric[];
372
+ getAll(): IMetric[];
373
+ /**
374
+ * Get all metrics matching the given origin.
375
+ */
376
+ getByOrigin(origin: MetricOrigin): IMetric[];
377
+ /**
378
+ * Apply the standard precedence resolution algorithm.
379
+ */
380
+ resolve(filter?: MetricFilter): IMetric[];
381
+ /** Append one or more metrics. */
382
+ add(...metrics: IMetric[]): this;
383
+ /**
384
+ * Remove metrics matching a predicate.
385
+ * Returns the removed metrics.
386
+ */
387
+ remove(predicate: (m: IMetric) => boolean): IMetric[];
388
+ /**
389
+ * Remove all metrics of a given type.
390
+ * Returns the removed metrics.
391
+ */
392
+ removeByType(type: MetricType | string): IMetric[];
393
+ /** Remove all metrics. */
394
+ clear(): this;
395
+ /**
396
+ * Replace all metrics of a given type with new ones.
397
+ */
398
+ replaceByType(type: MetricType | string, ...replacements: IMetric[]): IMetric[];
399
+ /**
400
+ * Merge another container (or raw array) into this one.
401
+ */
402
+ merge(other: MetricContainer | IMetric[] | {
403
+ metrics: MetricContainer;
404
+ }): this;
405
+ /** Iterate over all metrics. */
406
+ [Symbol.iterator](): Iterator<IMetric>;
407
+ /** Filter metrics, returning a new array. */
408
+ filter(predicate: (m: IMetric) => boolean): IMetric[];
409
+ /** Map metrics to a new array. */
410
+ map<T>(fn: (m: IMetric, index: number) => T): T[];
411
+ /** Flat-map metrics to a new array. */
412
+ flatMap<T>(fn: (m: IMetric, index: number) => T | readonly T[]): T[];
413
+ /** Find the first metric matching a predicate. */
414
+ find(predicate: (m: IMetric) => boolean): IMetric | undefined;
415
+ /** Whether any metric matches the predicate. */
416
+ some(predicate: (m: IMetric) => boolean): boolean;
417
+ /** Whether all metrics match the predicate. */
418
+ every(predicate: (m: IMetric) => boolean): boolean;
419
+ /** Return a mutable copy of the underlying array. */
420
+ toArray(): IMetric[];
421
+ /** Spread-friendly: returns the underlying array (no copy). */
422
+ get raw(): IMetric[];
423
+ private syncIndexProperties;
424
+ toString(): string;
425
+ }
426
+
427
+ interface ICodeStatement extends IMetricSource {
428
+ id: number;
429
+ parent?: number;
430
+ children: number[][];
431
+ exerciseId?: string;
432
+ metrics: MetricContainer;
433
+ isLeaf?: boolean;
434
+ meta: CodeMetadata;
435
+ metricMeta: Map<IMetric, CodeMetadata>;
436
+ line?: number;
437
+ text?: string;
438
+ raw?: string;
439
+ dialect?: string;
440
+ }
441
+ declare abstract class CodeStatement implements ICodeStatement, IMetricSource {
442
+ abstract id: number;
443
+ abstract parent?: number;
444
+ abstract children: number[][];
445
+ abstract meta: CodeMetadata;
446
+ abstract metrics: MetricContainer;
447
+ abstract metricMeta: Map<IMetric, CodeMetadata>;
448
+ abstract isLeaf?: boolean;
449
+ exerciseId?: string;
450
+ line?: number;
451
+ text?: string;
452
+ raw?: string;
453
+ dialect?: string;
454
+ hasMetric(type: MetricType | string): boolean;
455
+ getDisplayMetrics(filter?: MetricFilter): IMetric[];
456
+ getMetric(type: MetricType | string): IMetric | undefined;
457
+ getAllMetricsByType(type: MetricType | string): IMetric[];
458
+ get rawMetrics(): IMetric[];
459
+ private get metricContainer();
460
+ }
461
+ declare class ParsedCodeStatement extends CodeStatement {
462
+ id: number;
463
+ parent?: number;
464
+ children: number[][];
465
+ meta: CodeMetadata;
466
+ private _metrics;
467
+ metricMeta: Map<IMetric, CodeMetadata>;
468
+ isLeaf?: boolean;
469
+ get metrics(): MetricContainer;
470
+ set metrics(metrics: MetricContainer | IMetric[]);
471
+ constructor(init?: Partial<ParsedCodeStatement>);
472
+ }
473
+
474
+ /**
475
+ * TimeSpan represents a discrete start/stop segment of time.
476
+ *
477
+ * Core keeps this as a pure data shape with zero runtime dependencies.
478
+ */
479
+ interface TimeSpan {
480
+ started: number;
481
+ ended?: number;
482
+ }
483
+
484
+ /**
485
+ * Output statement types indicating what kind of result this represents.
486
+ *
487
+ * - 'segment': A timed portion of execution (e.g., a round, an effort interval)
488
+ * - 'milestone': A notable event during execution (e.g., halfway point, personal record)
489
+ * - 'system': Debug/diagnostic output from lifecycle events
490
+ * - 'event': Tracks external stimuli or internal triggers
491
+ * - 'group': Identified segment with children
492
+ * - 'load': Initial script state
493
+ * - 'compiler': Behavior configuration and setup
494
+ * - 'analytics': Output generated by the analytics engine
495
+ */
496
+ type OutputStatementType = 'segment' | 'milestone' | 'completion' | 'metric' | 'system' | 'event' | 'group' | 'load' | 'compiler' | 'analytics';
497
+ /**
498
+ * IOutputStatement extends ICodeStatement to represent runtime-generated output.
499
+ *
500
+ * This is the return type of execution — what "came out" of running a statement.
501
+ */
502
+ interface IOutputStatement extends ICodeStatement, IMetricSource {
503
+ readonly id: number;
504
+ readonly outputType: OutputStatementType;
505
+ readonly timeSpan: TimeSpan;
506
+ readonly sourceStatementId?: number;
507
+ readonly sourceBlockKey: string;
508
+ readonly stackLevel: number;
509
+ readonly metrics: MetricContainer;
510
+ readonly metricMeta: Map<IMetric, CodeMetadata>;
511
+ readonly completionReason?: string;
512
+ readonly statement?: ICodeStatement;
513
+ readonly timestamp?: number;
514
+ }
515
+ /**
516
+ * Options for creating an OutputStatement.
517
+ */
518
+ interface OutputStatementOptions {
519
+ /** Output type classification */
520
+ outputType: OutputStatementType;
521
+ /** Execution timing */
522
+ timeSpan: TimeSpan;
523
+ /** The block key that produced this output */
524
+ sourceBlockKey?: string;
525
+ /** Stack level (depth) when this output was emitted */
526
+ stackLevel?: number;
527
+ /** The source statement ID (optional) */
528
+ sourceStatementId?: number;
529
+ /** Runtime-collected metrics */
530
+ metrics?: MetricContainer | IMetric[];
531
+ /** Map of metrics to metadata */
532
+ metricMeta?: Map<IMetric, CodeMetadata>;
533
+ /** Reason the block completed (e.g., 'user-advance', 'forced-pop') */
534
+ completionReason?: string;
535
+ /** Parent output statement ID (for hierarchy) */
536
+ parent?: number;
537
+ /** Child output statement groups (for hierarchy) */
538
+ children?: number[][];
539
+ }
540
+ /**
541
+ * Concrete implementation of IOutputStatement.
542
+ */
543
+ declare class OutputStatement implements IOutputStatement, IMetricSource {
544
+ private static nextId;
545
+ readonly id: number;
546
+ readonly outputType: OutputStatementType;
547
+ readonly timeSpan: TimeSpan;
548
+ readonly sourceStatementId?: number;
549
+ readonly sourceBlockKey: string;
550
+ readonly stackLevel: number;
551
+ readonly metrics: MetricContainer;
552
+ readonly metricMeta: Map<IMetric, CodeMetadata>;
553
+ readonly completionReason?: string;
554
+ readonly parent?: number;
555
+ readonly children: number[][];
556
+ readonly isLeaf: boolean;
557
+ readonly meta: CodeMetadata;
558
+ readonly statement?: ICodeStatement;
559
+ readonly timestamp?: number;
560
+ constructor(optionsOrStatement: OutputStatementOptions | ICodeStatement, metricsArg?: MetricContainer | IMetric[], timestamp?: number);
561
+ getDisplayMetrics(filter?: MetricFilter): IMetric[];
562
+ getMetric(type: MetricType | string): IMetric | undefined;
563
+ getAllMetricsByType(type: MetricType | string): IMetric[];
564
+ hasMetric(type: MetricType | string): boolean;
565
+ get rawMetrics(): IMetric[];
566
+ /**
567
+ * Reset the ID counter (useful for testing)
568
+ */
569
+ static resetIdCounter(startAt?: number): void;
570
+ }
571
+
572
+ interface IMetricContainer extends IMetricSource {
573
+ metrics: MetricContainer;
574
+ clone(): IMetricContainer;
575
+ merge(other: IMetricContainer | MetricContainer): this;
576
+ }
577
+ type SummaryStage = 'estimate' | 'summary';
578
+ interface IMetricSummary extends IMetricContainer {
579
+ readonly stage: SummaryStage;
580
+ readonly sourceId: string | number;
581
+ readonly producedAt: Date;
582
+ }
583
+ interface IEstimate extends IMetricSummary {
584
+ readonly stage: 'estimate';
585
+ }
586
+ interface ISummary extends IMetricSummary {
587
+ readonly stage: 'summary';
588
+ readonly spans: IOutputStatement[];
589
+ }
590
+
591
+ /**
592
+ * Unified resolver for metric ownership precedence.
593
+ *
594
+ * Implements the canonical 5-tier ownership ledger resolution:
595
+ * parser -> dialect -> user-plan -> runtime -> user-entry
596
+ */
597
+ interface IMetricOwnershipResolver {
598
+ /** Resolve display-ready metrics, applying optional type/layer filters. */
599
+ resolve(metrics: readonly IMetric[], filter?: MetricFilter): IMetric[];
600
+ /** Resolve the single winning metric of a given type, or undefined. */
601
+ resolveOne(metrics: readonly IMetric[], type: MetricType | string): IMetric | undefined;
602
+ /** Resolve all metrics of a given type, sorted by ownership tier (highest first). */
603
+ resolveAll?(metrics: readonly IMetric[], type: MetricType | string): IMetric[];
604
+ }
605
+
606
+ /**
607
+ * Tag-Identity Registry Contract
608
+ *
609
+ * Single source of truth for dialect fence tags and runnable state,
610
+ * as defined in docs/adr/dialect-block-alignment.md and docs/adr/language-pack-api.md.
611
+ */
612
+ interface IDialectTagDescriptor {
613
+ /** Canonical fence tag (e.g. 'time', 'climb', 'wod') */
614
+ readonly tag: string;
615
+ /** Optional fence aliases (e.g. ['whiteboard', 'wod']) */
616
+ readonly aliases?: readonly string[];
617
+ /** Optional human-readable name */
618
+ readonly name?: string;
619
+ /** Whether blocks using this dialect produce runnable executions */
620
+ readonly runnable?: boolean;
621
+ }
622
+
623
+ declare function createMetricOwnershipLedger(metrics: readonly IMetric[]): MetricOwnershipLedger;
624
+
625
+ /**
626
+ * Ownership layer rank for a metric (0 = lowest = parser, 4 = highest = user-entry).
627
+ * Higher rank wins.
628
+ */
629
+ declare function ownershipRank(metric: IMetric): number;
630
+ /**
631
+ * Single-path resolver wrapping `MetricOwnershipLedger` + legacy filter translation.
632
+ */
633
+ declare class OwnershipResolver implements IMetricOwnershipResolver {
634
+ resolve(metrics: readonly IMetric[], filter?: MetricFilter): IMetric[];
635
+ resolveOne(metrics: readonly IMetric[], type: MetricType | string): IMetric | undefined;
636
+ resolveAll(metrics: readonly IMetric[], type: MetricType | string): IMetric[];
637
+ }
638
+
639
+ interface IDuration {
640
+ days?: number;
641
+ hours?: number;
642
+ minutes?: number;
643
+ seconds?: number;
644
+ milliseconds?: number;
645
+ original?: number;
646
+ }
647
+ declare class Duration implements IDuration {
648
+ original?: number | undefined;
649
+ days?: number;
650
+ hours?: number;
651
+ minutes?: number;
652
+ seconds?: number;
653
+ milliseconds?: number;
654
+ constructor(original?: number | undefined);
655
+ }
656
+ declare class SpanDuration extends Duration {
657
+ constructor(spans: TimeSpan[]);
658
+ }
659
+
660
+ interface IBlockKey {
661
+ readonly value: string;
662
+ toString(): string;
663
+ valueOf(): string;
664
+ equals(other: IBlockKey): boolean;
665
+ }
666
+ declare class BlockKey implements IBlockKey {
667
+ readonly value: string;
668
+ constructor(value?: string);
669
+ toString(): string;
670
+ valueOf(): string;
671
+ equals(other: IBlockKey): boolean;
672
+ }
673
+
674
+ /**
675
+ * Result of dialect analysis on a statement.
676
+ */
677
+ interface DialectAnalysis {
678
+ /**
679
+ * Metrics emitted by the dialect: hint markers plus any dialect-specific
680
+ * values.
681
+ */
682
+ metrics?: MetricContainer;
683
+ }
684
+ /**
685
+ * Dialect interface for semantic marker generation.
686
+ */
687
+ interface IDialect {
688
+ /** Unique dialect identifier */
689
+ id: string;
690
+ /** Display name */
691
+ name: string;
692
+ /**
693
+ * Optionally rewrite the statement's metrics in place before analyze.
694
+ */
695
+ transform?(statement: ICodeStatement): void;
696
+ /**
697
+ * Analyze a statement and return emitted metrics (hint markers + values).
698
+ */
699
+ analyze(statement: ICodeStatement): DialectAnalysis;
700
+ }
701
+
702
+ /**
703
+ * Status of a display entry in the execution lifecycle
704
+ */
705
+ type DisplayStatus = 'pending' | 'active' | 'completed' | 'failed' | 'skipped';
706
+ /**
707
+ * Visual size configurations for display components
708
+ */
709
+ type VisualizerSize = 'compact' | 'normal' | 'focused';
710
+ /**
711
+ * Filter configuration for metrics within display entries
712
+ */
713
+ interface VisualizerFilter {
714
+ /** Only show metrics with these origins. If undefined, show all. */
715
+ allowedOrigins?: MetricOrigin[];
716
+ /** Hide metrics of these types (overrides allowedOrigins) */
717
+ typeOverrides?: Record<string, boolean>;
718
+ /** Hide specific named metrics (overrides everything) */
719
+ nameOverrides?: Record<string, boolean>;
720
+ }
721
+
722
+ /**
723
+ * Configuration for a single graph/metric to be displayed
724
+ */
725
+ interface AnalyticsGraphConfig {
726
+ id: string;
727
+ label: string;
728
+ unit: string;
729
+ color: string;
730
+ dataKey: string;
731
+ icon?: string;
732
+ }
733
+ /**
734
+ * Grouping of analytics graphs
735
+ */
736
+ interface AnalyticsGroup {
737
+ id: string;
738
+ name: string;
739
+ icon?: string;
740
+ graphs: AnalyticsGraphConfig[];
741
+ }
742
+ interface Segment {
743
+ id: number;
744
+ name: string;
745
+ type: string;
746
+ startTime: number;
747
+ endTime: number;
748
+ /** Wall-clock start time in milliseconds since epoch */
749
+ absoluteStartTime?: number;
750
+ /** Duration (Intent) - Parser-defined planned target in seconds */
751
+ duration?: number;
752
+ /** Elapsed (Active) - pause-aware active time in seconds */
753
+ elapsed: number;
754
+ /** Total (Wall-clock) - total time from first start to last end in seconds */
755
+ total: number;
756
+ parentId: number | null;
757
+ depth: number;
758
+ metric: Record<string, number>;
759
+ lane: number;
760
+ /** Raw time spans from the output statement (seconds relative to workout start) */
761
+ spans?: {
762
+ started: number;
763
+ ended?: number;
764
+ }[];
765
+ /** Optional metrics carried from runtime spans for visualization */
766
+ metrics?: MetricContainer;
767
+ }
768
+
769
+ /**
770
+ * Plain-data snapshot of a runtime OutputStatement safe for JSON / IndexedDB
771
+ * round-trips. Class methods and non-serialisable fields (Set, Map,
772
+ * MetricContainer instances) are intentionally excluded.
773
+ *
774
+ * The live->stored converter `toStoredOutputStatement` lives in `@bitcobblers/wod-wiki-lang`
775
+ * because it requires the hint evaluation protocol.
776
+ */
777
+ interface StoredOutputStatement {
778
+ readonly id?: number;
779
+ readonly line?: number;
780
+ readonly text?: string;
781
+ readonly dialect?: string;
782
+ readonly outputType?: OutputStatementType;
783
+ readonly timeSpan?: {
784
+ started: number;
785
+ ended?: number;
786
+ };
787
+ /** Flat IMetric array — MetricContainer class not needed after serialisation. */
788
+ readonly metrics: IMetric[] | {
789
+ name?: string;
790
+ type?: string;
791
+ value?: unknown;
792
+ unit?: string;
793
+ origin?: string;
794
+ }[];
795
+ /** Plain string array — Set<string> does not survive JSON serialisation. */
796
+ readonly hints?: string[];
797
+ readonly sourceBlockKey?: string;
798
+ readonly stackLevel?: number;
799
+ readonly parent?: number;
800
+ readonly sourceStatementId?: number;
801
+ readonly completionReason?: string;
802
+ readonly timestamp?: number;
803
+ }
804
+ /**
805
+ * Results from a completed workout.
806
+ */
807
+ interface WorkoutResults {
808
+ /** When workout started */
809
+ startTime: number;
810
+ /** When workout ended */
811
+ endTime: number;
812
+ /** Total elapsed time (ms) */
813
+ duration?: number;
814
+ /** Rounds completed (for rounds-based workouts) */
815
+ roundsCompleted?: number;
816
+ /** Total rounds (for rounds-based workouts) */
817
+ totalRounds?: number;
818
+ /** Reps completed (for rep-based workouts) */
819
+ repsCompleted?: number;
820
+ /**
821
+ * Plain-data runtime output log — safe for IndexedDB storage and JSON
822
+ * round-trips. Populated by serialising live IOutputStatement values via
823
+ * `toStoredOutputStatement()` at workout completion.
824
+ *
825
+ * Single stream holding ALL tiers: Tier 0 (raw tracking) + Tier 1 (inline
826
+ * annotations) + Tier 2 (summary outputs, outputType 'analytics').
827
+ */
828
+ logs?: StoredOutputStatement[];
829
+ /** Whether workout was completed or stopped early */
830
+ completed: boolean;
831
+ }
832
+
833
+ type SegmentDataType = 'script' | 'youtube' | 'markdown' | 'header' | 'frontmatter' | 'wod' | 'title' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
834
+ type NoteKind = 'note' | 'template' | 'playground' | 'journal';
835
+ interface Note {
836
+ id: string;
837
+ title: string;
838
+ slug?: string;
839
+ pageId?: string;
840
+ createdAt: number;
841
+ type?: NoteKind;
842
+ sourceId?: string;
843
+ catalog?: string;
844
+ tags?: string[];
845
+ }
846
+ interface Page {
847
+ id: string;
848
+ date?: string;
849
+ slug?: string;
850
+ title?: string;
851
+ createdAt: number;
852
+ }
853
+ type TagType = 'template' | 'playground' | 'qualification' | 'notebook' | 'general';
854
+ interface Tag {
855
+ id: string;
856
+ label: string;
857
+ type?: TagType;
858
+ createdAt: number;
859
+ }
860
+ interface NoteTag {
861
+ id: string;
862
+ noteId: string;
863
+ tagId: string;
864
+ }
865
+ interface NoteSegment {
866
+ id: string;
867
+ version: number;
868
+ noteId: string;
869
+ position?: number;
870
+ pageId?: string;
871
+ dataType: SegmentDataType;
872
+ data: unknown;
873
+ rawContent: string;
874
+ createdAt: number;
875
+ updatedAt?: number;
876
+ isHistory?: boolean;
877
+ }
878
+ interface BlockIndexRow {
879
+ /** Composite key: `${noteId}:${segmentId}:${segmentVersion}` */
880
+ id: string;
881
+ noteId: string;
882
+ segmentId: string;
883
+ segmentVersion: number;
884
+ position?: number;
885
+ dataType: string;
886
+ blockContentId?: string;
887
+ rawContent: string;
888
+ noteTitle: string;
889
+ createdAt: number;
890
+ isStatic?: boolean;
891
+ sourceId?: string;
892
+ }
893
+ type ResultOrigin = 'journal' | 'playground';
894
+ interface WorkoutResult {
895
+ id: string;
896
+ segmentId?: string;
897
+ segmentVersion?: number;
898
+ noteId: string;
899
+ blockId?: string;
900
+ blockContentId?: string;
901
+ version?: number;
902
+ origin?: ResultOrigin;
903
+ pageId?: string;
904
+ data: WorkoutResults;
905
+ createdAt: number;
906
+ }
907
+ interface Attachment {
908
+ id: string;
909
+ noteId: string;
910
+ pageId?: string;
911
+ resultId?: string;
912
+ mimeType: string;
913
+ label: string;
914
+ data: ArrayBuffer | string;
915
+ timeSpan: {
916
+ start: number;
917
+ end: number;
918
+ };
919
+ createdAt: number;
920
+ }
921
+ interface AnalyticsDataPoint {
922
+ id: string;
923
+ noteId: string;
924
+ blockContentId?: string;
925
+ origin?: ResultOrigin;
926
+ pageId?: string;
927
+ grain?: 'segment' | 'summary' | 'rollup';
928
+ effortSlug?: string;
929
+ discipline?: string;
930
+ intensityTier?: string;
931
+ grade?: string;
932
+ segmentId: string;
933
+ segmentVersion: number;
934
+ resultId: string;
935
+ type: string;
936
+ value: unknown;
937
+ unit?: string;
938
+ label: string;
939
+ metricKey?: string;
940
+ metricLabel?: string;
941
+ metricUnit?: string;
942
+ timestamp: number;
943
+ createdAt: number;
944
+ }
945
+
946
+ /**
947
+ * State of a WOD block
948
+ */
949
+ type ScriptBlockState = 'idle' | 'parsing' | 'parsed' | 'error' | 'starting' | 'running' | 'paused' | 'completed' | 'stopped';
950
+ /**
951
+ * Parse error information
952
+ */
953
+ interface ParseError {
954
+ message: string;
955
+ line?: number;
956
+ column?: number;
957
+ token?: unknown;
958
+ excerpt?: string;
959
+ severity?: 'error' | 'warning' | 'info';
960
+ }
961
+ /** Workout fence tags — `time` is runnable, `log` is recorded */
962
+ type FenceDialect = 'time' | 'log';
963
+ /** Ordered list of recognised workout fence tags */
964
+ declare const VALID_FENCE_DIALECTS: FenceDialect[];
965
+ /**
966
+ * Run affordance for a fence base tag:
967
+ * `'time'` -> `'run'` (runnable) · `'log'` -> `'log'` (log-mode runtime) · else `null`.
968
+ */
969
+ declare function runAffordance(baseTag: string): 'run' | 'log' | null;
970
+ /** Section types the editor can parse and render */
971
+ type SectionType = 'title' | 'markdown' | 'time' | 'log' | 'frontmatter' | 'embed';
972
+ /** Workout section types — the runnable/recorded fence tags */
973
+ type WorkoutSectionType = Extract<SectionType, FenceDialect>;
974
+ /** Type guard for workout sections */
975
+ declare function isWorkoutSectionType(type: SectionType): type is WorkoutSectionType;
976
+ /** Typed front matter subtypes */
977
+ type FrontMatterSubtype = 'default' | 'youtube' | 'strava' | 'amazon' | 'file' | 'effort';
978
+ /**
979
+ * Represents a single WOD block within the markdown document
980
+ */
981
+ interface ScriptBlock {
982
+ /** Unique identifier for this block */
983
+ id: string;
984
+ /** Content-stable identity */
985
+ contentId?: string;
986
+ /** Workout fence tag ('time' runnable / 'log' recorded) */
987
+ dialect?: FenceDialect;
988
+ /** Sport suffix from the fence */
989
+ sport?: string;
990
+ /** Line number where ```time/```log appears (0-indexed) */
991
+ startLine: number;
992
+ /** Line number where closing ``` appears (0-indexed) */
993
+ endLine: number;
994
+ /** Raw text content of the WOD block */
995
+ content: string;
996
+ /** Parsed statements (populated after parsing) */
997
+ statements?: ICodeStatement[];
998
+ /** Parse errors, if any */
999
+ errors?: ParseError[];
1000
+ /** Execution state */
1001
+ state: ScriptBlockState;
1002
+ /** Collected workout data (after completion) */
1003
+ results?: WorkoutResults;
1004
+ /** Block version */
1005
+ version: number;
1006
+ /** Creation timestamp */
1007
+ createdAt: number;
1008
+ }
1009
+ /**
1010
+ * A single section in the document — the atomic unit of display and editing.
1011
+ */
1012
+ interface Section {
1013
+ id: string;
1014
+ contentId?: string;
1015
+ type: SectionType;
1016
+ rawContent: string;
1017
+ displayContent: string;
1018
+ startLine: number;
1019
+ endLine: number;
1020
+ lineCount: number;
1021
+ level?: number;
1022
+ sport?: string;
1023
+ scriptBlock?: ScriptBlock;
1024
+ properties?: Record<string, string>;
1025
+ frontmatterType?: FrontMatterSubtype;
1026
+ embed?: {
1027
+ type: 'image' | 'link' | 'youtube';
1028
+ label: string;
1029
+ url: string;
1030
+ isImage: boolean;
1031
+ };
1032
+ version: number;
1033
+ createdAt: number;
1034
+ deleted?: boolean;
1035
+ }
1036
+ /**
1037
+ * The full document as an ordered section list.
1038
+ */
1039
+ interface SectionDocument {
1040
+ sections: Section[];
1041
+ totalLines: number;
1042
+ activeSectionId: string | null;
1043
+ }
1044
+
1045
+ /**
1046
+ * Notebook Types
1047
+ *
1048
+ * A notebook is a named, tag-based collection of workout entries.
1049
+ */
1050
+ interface Notebook {
1051
+ id: string;
1052
+ name: string;
1053
+ description: string;
1054
+ icon: string;
1055
+ createdAt: number;
1056
+ lastEditedAt: number;
1057
+ }
1058
+ declare const NOTEBOOK_TAG_PREFIX = "notebook:";
1059
+ declare const toNotebookTag: (notebookId: string) => string;
1060
+ declare const fromNotebookTag: (tag: string) => string | null;
1061
+ declare const isNotebookTag: (tag: string) => boolean;
1062
+
1063
+ /**
1064
+ * Represents a parsed workout script
1065
+ */
1066
+ interface IScript {
1067
+ source: string;
1068
+ statements: ICodeStatement[];
1069
+ errors?: ParseError[];
1070
+ getIds(ids: (number | string)[]): ICodeStatement[];
1071
+ getId(id: number | string): ICodeStatement | undefined;
1072
+ getAt(index: number): ICodeStatement | undefined;
1073
+ }
1074
+
1075
+ export { type AnalyticsDataPoint, type AnalyticsGraphConfig, type AnalyticsGroup, type Attachment, type BlockIndexRow, BlockKey, CodeMetadata, CodeStatement, type DialectAnalysis, type DisplayStatus, Duration, type FenceDialect, type FrontMatterSubtype, type IBlockKey, type ICodeMetadata, type ICodeStatement, type IDialect, type IDialectTagDescriptor, type IDuration, type IEstimate, type IMetric, type IMetricContainer, type IMetricOwnershipResolver, type IMetricSource, type IMetricSummary, type IOutputStatement, type IScript, type ISummary, LEGACY_ORIGIN_TO_OWNERSHIP_LAYER, METRIC_OWNERSHIP_LAYER_CHAIN, Metric, type MetricAction, MetricContainer, type MetricFilter, type MetricOrigin, type MetricOwnershipLayer, type MetricOwnershipLedger, type MetricOwnershipOutcome, type MetricOwnershipPromotionCandidate, type MetricOwnershipQuery, type MetricOwnershipResolvedContribution, type MetricOwnershipTypeExplanation, MetricType, type MetricWithOptionalOwnershipLayer, NOTEBOOK_TAG_PREFIX, type Note, type NoteKind, type NoteSegment, type NoteTag, type Notebook, type Origin, OutputStatement, type OutputStatementOptions, type OutputStatementType, OwnershipResolver, type Page, type ParseError, ParsedCodeStatement, type ResultOrigin, type ScriptBlock, type ScriptBlockState, type Section, type SectionDocument, type SectionType, type Segment, type SegmentDataType, SpanDuration, type StoredOutputStatement, type SummaryStage, type Tag, type TagType, type TimeSpan, VALID_FENCE_DIALECTS, type VisualizerFilter, type VisualizerSize, type WorkoutResult, type WorkoutResults, type WorkoutSectionType, createMetricOwnershipLedger, fromNotebookTag, getMetricOwnershipLayer, isNotebookTag, isWorkoutSectionType, ownershipRank, runAffordance, toNotebookTag };