pipework 0.7.26 → 0.8.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cli/commands/test.d.ts +1 -0
  3. package/dist/cli/commands/test.d.ts.map +1 -1
  4. package/dist/cli/commands/test.js +12 -3
  5. package/dist/cli/commands/test.js.map +1 -1
  6. package/dist/core/config/load.d.ts +6 -0
  7. package/dist/core/config/load.d.ts.map +1 -1
  8. package/dist/core/config/load.js +5 -0
  9. package/dist/core/config/load.js.map +1 -1
  10. package/dist/core/config/namespace.d.ts +5 -0
  11. package/dist/core/config/namespace.d.ts.map +1 -1
  12. package/dist/core/config/schema.d.ts +11 -0
  13. package/dist/core/config/schema.d.ts.map +1 -1
  14. package/dist/core/config/schema.js +6 -0
  15. package/dist/core/config/schema.js.map +1 -1
  16. package/dist/core/logging/redact-match.d.ts +4 -0
  17. package/dist/core/logging/redact-match.d.ts.map +1 -0
  18. package/dist/core/logging/redact-match.js +23 -0
  19. package/dist/core/logging/redact-match.js.map +1 -0
  20. package/dist/data/db/namespace.d.ts +1 -0
  21. package/dist/data/db/namespace.d.ts.map +1 -1
  22. package/dist/data/domain/build-factory.js +2 -0
  23. package/dist/data/domain/build-factory.js.map +1 -1
  24. package/dist/data/domain/build-schema.js +2 -0
  25. package/dist/data/domain/build-schema.js.map +1 -1
  26. package/dist/data/domain/build-table.d.ts.map +1 -1
  27. package/dist/data/domain/build-table.js +86 -12
  28. package/dist/data/domain/build-table.js.map +1 -1
  29. package/dist/data/domain/field.d.ts +2 -0
  30. package/dist/data/domain/field.d.ts.map +1 -1
  31. package/dist/data/domain/field.js +7 -0
  32. package/dist/data/domain/field.js.map +1 -1
  33. package/dist/data/domain/trace-safe-projection.d.ts +12 -0
  34. package/dist/data/domain/trace-safe-projection.d.ts.map +1 -0
  35. package/dist/data/domain/trace-safe-projection.js +25 -0
  36. package/dist/data/domain/trace-safe-projection.js.map +1 -0
  37. package/dist/data/domain/types.d.ts +34 -2
  38. package/dist/data/domain/types.d.ts.map +1 -1
  39. package/dist/data/migrate/diff.d.ts.map +1 -1
  40. package/dist/data/migrate/diff.js +19 -0
  41. package/dist/data/migrate/diff.js.map +1 -1
  42. package/dist/data/migrate/snapshot.d.ts +6 -0
  43. package/dist/data/migrate/snapshot.d.ts.map +1 -1
  44. package/dist/data/migrate/snapshot.js +16 -0
  45. package/dist/data/migrate/snapshot.js.map +1 -1
  46. package/dist/data/migrate/sql-emit.js +4 -1
  47. package/dist/data/migrate/sql-emit.js.map +1 -1
  48. package/dist/trace/annotation/flow-step-annotation.d.ts +51 -0
  49. package/dist/trace/annotation/flow-step-annotation.d.ts.map +1 -0
  50. package/dist/trace/annotation/flow-step-annotation.js +6 -0
  51. package/dist/trace/annotation/flow-step-annotation.js.map +1 -0
  52. package/dist/trace/annotation/parse-error.d.ts +16 -0
  53. package/dist/trace/annotation/parse-error.d.ts.map +1 -0
  54. package/dist/trace/annotation/parse-error.js +5 -0
  55. package/dist/trace/annotation/parse-error.js.map +1 -0
  56. package/dist/trace/annotation/parse.d.ts +21 -0
  57. package/dist/trace/annotation/parse.d.ts.map +1 -0
  58. package/dist/trace/annotation/parse.js +201 -0
  59. package/dist/trace/annotation/parse.js.map +1 -0
  60. package/dist/trace/capture/bounded-serializer.d.ts +21 -0
  61. package/dist/trace/capture/bounded-serializer.d.ts.map +1 -0
  62. package/dist/trace/capture/bounded-serializer.js +107 -0
  63. package/dist/trace/capture/bounded-serializer.js.map +1 -0
  64. package/dist/trace/partition/day.d.ts +7 -0
  65. package/dist/trace/partition/day.d.ts.map +1 -0
  66. package/dist/trace/partition/day.js +39 -0
  67. package/dist/trace/partition/day.js.map +1 -0
  68. package/dist/trace/partition/index.d.ts +11 -0
  69. package/dist/trace/partition/index.d.ts.map +1 -0
  70. package/dist/trace/partition/index.js +8 -0
  71. package/dist/trace/partition/index.js.map +1 -0
  72. package/dist/trace/partition/partition-name.d.ts +8 -0
  73. package/dist/trace/partition/partition-name.d.ts.map +1 -0
  74. package/dist/trace/partition/partition-name.js +23 -0
  75. package/dist/trace/partition/partition-name.js.map +1 -0
  76. package/dist/trace/partition/plan.d.ts +35 -0
  77. package/dist/trace/partition/plan.d.ts.map +1 -0
  78. package/dist/trace/partition/plan.js +39 -0
  79. package/dist/trace/partition/plan.js.map +1 -0
  80. package/dist/trace/partition/schedule.d.ts +14 -0
  81. package/dist/trace/partition/schedule.d.ts.map +1 -0
  82. package/dist/trace/partition/schedule.js +11 -0
  83. package/dist/trace/partition/schedule.js.map +1 -0
  84. package/dist/trace/partition/startup-hook.d.ts +6 -0
  85. package/dist/trace/partition/startup-hook.d.ts.map +1 -0
  86. package/dist/trace/partition/startup-hook.js +15 -0
  87. package/dist/trace/partition/startup-hook.js.map +1 -0
  88. package/dist/trace/partition/sync.d.ts +14 -0
  89. package/dist/trace/partition/sync.d.ts.map +1 -0
  90. package/dist/trace/partition/sync.js +62 -0
  91. package/dist/trace/partition/sync.js.map +1 -0
  92. package/dist/trace/partition/tables.d.ts +8 -0
  93. package/dist/trace/partition/tables.d.ts.map +1 -0
  94. package/dist/trace/partition/tables.js +16 -0
  95. package/dist/trace/partition/tables.js.map +1 -0
  96. package/dist/trace/retain/copy-on-error.d.ts +18 -0
  97. package/dist/trace/retain/copy-on-error.d.ts.map +1 -0
  98. package/dist/trace/retain/copy-on-error.js +62 -0
  99. package/dist/trace/retain/copy-on-error.js.map +1 -0
  100. package/dist/trace/schema/trace-fields.d.ts +18 -0
  101. package/dist/trace/schema/trace-fields.d.ts.map +1 -0
  102. package/dist/trace/schema/trace-fields.js +34 -0
  103. package/dist/trace/schema/trace-fields.js.map +1 -0
  104. package/dist/trace/schema/trace-retained.d.ts +18 -0
  105. package/dist/trace/schema/trace-retained.d.ts.map +1 -0
  106. package/dist/trace/schema/trace-retained.js +11 -0
  107. package/dist/trace/schema/trace-retained.js.map +1 -0
  108. package/dist/trace/schema/trace-step-fields.d.ts +15 -0
  109. package/dist/trace/schema/trace-step-fields.d.ts.map +1 -0
  110. package/dist/trace/schema/trace-step-fields.js +31 -0
  111. package/dist/trace/schema/trace-step-fields.js.map +1 -0
  112. package/dist/trace/schema/trace-step-retained.d.ts +15 -0
  113. package/dist/trace/schema/trace-step-retained.d.ts.map +1 -0
  114. package/dist/trace/schema/trace-step-retained.js +18 -0
  115. package/dist/trace/schema/trace-step-retained.js.map +1 -0
  116. package/dist/trace/schema/trace-step.d.ts +15 -0
  117. package/dist/trace/schema/trace-step.d.ts.map +1 -0
  118. package/dist/trace/schema/trace-step.js +17 -0
  119. package/dist/trace/schema/trace-step.js.map +1 -0
  120. package/dist/trace/schema/trace.d.ts +18 -0
  121. package/dist/trace/schema/trace.d.ts.map +1 -0
  122. package/dist/trace/schema/trace.js +11 -0
  123. package/dist/trace/schema/trace.js.map +1 -0
  124. package/dist/workspace/changed-files.d.ts.map +1 -1
  125. package/dist/workspace/changed-files.js +5 -1
  126. package/dist/workspace/changed-files.js.map +1 -1
  127. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ import type { DB } from '../../data/db/index.js';
2
+ import type { StartupHook } from '../../core/lifecycle/types.js';
3
+ import type { TracePartitionConfig } from './plan.js';
4
+ export declare const TRACE_PARTITION_HOOK_NAME = "trace-partition-maintenance";
5
+ export declare function createTracePartitionStartupHook(db: DB, config: TracePartitionConfig): StartupHook;
6
+ //# sourceMappingURL=startup-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-hook.d.ts","sourceRoot":"","sources":["../../../src/trace/partition/startup-hook.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAErD,eAAO,MAAM,yBAAyB,gCAAgC,CAAA;AAEtE,wBAAgB,+BAA+B,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,oBAAoB,GAAG,WAAW,CAOjG"}
@@ -0,0 +1,15 @@
1
+ // Partition maintenance as a startup hook. Running it at boot guarantees the
2
+ // near-term partitions exist before the app takes its first request — a fresh
3
+ // deploy on a new day must not write a trace into a partition that doesn't
4
+ // exist yet. The cron schedule keeps it current after that.
5
+ import { syncTracePartitions } from './sync.js';
6
+ export const TRACE_PARTITION_HOOK_NAME = 'trace-partition-maintenance';
7
+ export function createTracePartitionStartupHook(db, config) {
8
+ return {
9
+ name: TRACE_PARTITION_HOOK_NAME,
10
+ async execute() {
11
+ await syncTracePartitions(db, config);
12
+ },
13
+ };
14
+ }
15
+ //# sourceMappingURL=startup-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-hook.js","sourceRoot":"","sources":["../../../src/trace/partition/startup-hook.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,4DAA4D;AAI5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAG/C,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAA;AAEtE,MAAM,UAAU,+BAA+B,CAAC,EAAM,EAAE,MAA4B;IAClF,OAAO;QACL,IAAI,EAAE,yBAAyB;QAC/B,KAAK,CAAC,OAAO;YACX,MAAM,mBAAmB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;QACvC,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { DB } from '../../data/db/index.js';
2
+ import { type TracePartitionConfig } from './plan.js';
3
+ export interface PartitionSyncSummary {
4
+ readonly created: readonly string[];
5
+ readonly dropped: readonly string[];
6
+ }
7
+ /**
8
+ * Reconcile the trace tables' day partitions with the retention policy.
9
+ *
10
+ * `now` is injectable so the maintenance window is testable without mocking the
11
+ * clock. Returns the names created and dropped so a job runner can record them.
12
+ */
13
+ export declare function syncTracePartitions(db: DB, config: TracePartitionConfig, now?: Date): Promise<PartitionSyncSummary>;
14
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/trace/partition/sync.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAIhD,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAGrE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,oBAAoB,EAC5B,GAAG,GAAE,IAAiB,GACrB,OAAO,CAAC,oBAAoB,CAAC,CAiC/B"}
@@ -0,0 +1,62 @@
1
+ // The impure half of partition maintenance: read the catalog for partitions
2
+ // that exist, ask the planner what should exist, and apply the difference.
3
+ // Creating and dropping day partitions is idempotent — `IF NOT EXISTS` /
4
+ // `IF EXISTS` make a re-run after a crash a no-op — so this is safe to run on
5
+ // every boot and on a cron without coordination.
6
+ import { sql } from '../../data/db/sql.js';
7
+ import { quoteIdentifier } from '../../data/db/identifiers.js';
8
+ import { getBaseLogger } from '../../core/logging/index.js';
9
+ import { PARTITIONED_TRACE_TABLES } from './tables.js';
10
+ import { planPartitions } from './plan.js';
11
+ import { addDays } from './day.js';
12
+ /**
13
+ * Reconcile the trace tables' day partitions with the retention policy.
14
+ *
15
+ * `now` is injectable so the maintenance window is testable without mocking the
16
+ * clock. Returns the names created and dropped so a job runner can record them.
17
+ */
18
+ export async function syncTracePartitions(db, config, now = new Date()) {
19
+ const existing = await readExistingPartitions(db);
20
+ const plan = planPartitions({ now, config, existing });
21
+ for (const partition of plan.create) {
22
+ const child = quoteIdentifier(partition.name, 'trace partition');
23
+ const parent = quoteIdentifier(partition.parent, 'trace table');
24
+ // addDays re-validates the day; the bound is a generated YYYY-MM-DD literal.
25
+ const upper = addDays(partition.day, 1);
26
+ await db.execute(sql.raw(`CREATE TABLE IF NOT EXISTS ${child} PARTITION OF ${parent} ` +
27
+ `FOR VALUES FROM ('${partition.day}') TO ('${upper}')`));
28
+ }
29
+ for (const partition of plan.drop) {
30
+ const child = quoteIdentifier(partition.name, 'trace partition');
31
+ await db.execute(sql.raw(`DROP TABLE IF EXISTS ${child}`));
32
+ }
33
+ const summary = {
34
+ created: plan.create.map(p => p.name),
35
+ dropped: plan.drop.map(p => p.name),
36
+ };
37
+ if (summary.created.length > 0 || summary.dropped.length > 0) {
38
+ getBaseLogger().info({ created: summary.created, dropped: summary.dropped }, 'Trace partition maintenance applied');
39
+ }
40
+ return summary;
41
+ }
42
+ async function readExistingPartitions(db) {
43
+ const parents = PARTITIONED_TRACE_TABLES.map(t => t.parent);
44
+ const parentList = sql.join(parents.map(p => sql `${p}`), sql `, `);
45
+ const rows = await db.execute(sql `
46
+ SELECT p.relname AS parent, c.relname AS child
47
+ FROM pg_inherits i
48
+ JOIN pg_class c ON c.oid = i.inhrelid
49
+ JOIN pg_class p ON p.oid = i.inhparent
50
+ WHERE p.relname IN (${parentList})
51
+ `);
52
+ const byParent = new Map();
53
+ for (const parent of parents)
54
+ byParent.set(parent, new Set());
55
+ for (const row of rows) {
56
+ const parent = row['parent'];
57
+ const child = row['child'];
58
+ byParent.get(parent)?.add(child);
59
+ }
60
+ return byParent;
61
+ }
62
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/trace/partition/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type RetentionClass = 'hot' | 'cold';
2
+ export interface PartitionedTraceTable {
3
+ /** The parent table's wire name — partitions are children of this. */
4
+ readonly parent: string;
5
+ readonly retention: RetentionClass;
6
+ }
7
+ export declare const PARTITIONED_TRACE_TABLES: readonly PartitionedTraceTable[];
8
+ //# sourceMappingURL=tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/trace/partition/tables.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAE3C,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAA;CACnC;AAED,eAAO,MAAM,wBAAwB,EAAE,SAAS,qBAAqB,EAKpE,CAAA"}
@@ -0,0 +1,16 @@
1
+ // The four partitioned trace tables and the retention window each one obeys.
2
+ // Hot tables (`trace`, `trace_step`) keep `hotRetentionDays` of partitions;
3
+ // cold tables (`trace_retained`, `trace_step_retained`) keep
4
+ // `errorRetentionDays`. Partition creation uses the same lead window for all
5
+ // four — copy-on-error can land a cold row on any day a hot row exists.
6
+ import { trace } from '../schema/trace.js';
7
+ import { traceStep } from '../schema/trace-step.js';
8
+ import { traceRetained } from '../schema/trace-retained.js';
9
+ import { traceStepRetained } from '../schema/trace-step-retained.js';
10
+ export const PARTITIONED_TRACE_TABLES = [
11
+ { parent: trace.$name, retention: 'hot' },
12
+ { parent: traceStep.$name, retention: 'hot' },
13
+ { parent: traceRetained.$name, retention: 'cold' },
14
+ { parent: traceStepRetained.$name, retention: 'cold' },
15
+ ];
16
+ //# sourceMappingURL=tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../src/trace/partition/tables.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,6DAA6D;AAC7D,6EAA6E;AAC7E,wEAAwE;AAExE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AAUpE,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;IACzC,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;IAC7C,EAAE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE;IAClD,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE;CACvD,CAAA"}
@@ -0,0 +1,18 @@
1
+ import type { DB } from '../../data/db/index.js';
2
+ export interface CopyOnErrorResult {
3
+ /** Rows newly inserted into `trace_retained` (rows already retained excluded). */
4
+ readonly traces: number;
5
+ /** Rows newly inserted into `trace_step_retained`. */
6
+ readonly steps: number;
7
+ }
8
+ /**
9
+ * Copy an errored trace and its parent spine into the cold retained tables.
10
+ *
11
+ * `traceId` is the trace that ended badly. Its ancestry is walked through
12
+ * `parent_id` to the root; every trace on that spine, plus all of their steps,
13
+ * is inserted into `trace_retained` / `trace_step_retained`. Returns the count
14
+ * of rows actually inserted — zero for both when everything was already
15
+ * retained, or when `traceId` does not exist.
16
+ */
17
+ export declare function copyTraceOnError(db: DB, traceId: string): Promise<CopyOnErrorResult>;
18
+ //# sourceMappingURL=copy-on-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-on-error.d.ts","sourceRoot":"","sources":["../../../src/trace/retain/copy-on-error.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAMhD,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAUD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2B1F"}
@@ -0,0 +1,62 @@
1
+ // Copy-on-error: when a trace ends badly (error / truncated / expired), the hot
2
+ // `trace` / `trace_step` partitions it lives in will be dropped on the normal
3
+ // `hotRetentionDays` schedule. Before that happens the errored trace — and its
4
+ // ancestry spine up to the root — is copied into the cold `trace_retained` /
5
+ // `trace_step_retained` tables, which keep the longer `errorRetentionDays`
6
+ // window.
7
+ //
8
+ // Only the parent chain is followed (`parent_id`): not siblings, not the step
9
+ // tree (`parent_step_id`). The spine is what you need to read an errored trace
10
+ // in context. Each copied trace brings all of its own steps.
11
+ //
12
+ // The copy is idempotent — `ON CONFLICT DO NOTHING` against each cold table's
13
+ // composite primary key — so re-running after a crash, or copying a trace whose
14
+ // ancestor was already retained by an earlier error, is a no-op.
15
+ import { sql } from '../../data/db/sql.js';
16
+ import { quoteIdentifier } from '../../data/db/identifiers.js';
17
+ import { camelToSnake } from '../../data/domain/naming.js';
18
+ import { traceFields } from '../schema/trace-fields.js';
19
+ import { traceStepFields } from '../schema/trace-step-fields.js';
20
+ function columnList(keys, label, prefix = '') {
21
+ return keys.map(k => `${prefix}${quoteIdentifier(camelToSnake(k), label)}`).join(', ');
22
+ }
23
+ const TRACE_COLUMNS = columnList(Object.keys(traceFields), 'trace column');
24
+ const TRACE_STEP_COLUMNS = columnList(Object.keys(traceStepFields), 'trace step column');
25
+ const TRACE_STEP_COLUMNS_FROM_STEP = columnList(Object.keys(traceStepFields), 'trace step column', 's.');
26
+ /**
27
+ * Copy an errored trace and its parent spine into the cold retained tables.
28
+ *
29
+ * `traceId` is the trace that ended badly. Its ancestry is walked through
30
+ * `parent_id` to the root; every trace on that spine, plus all of their steps,
31
+ * is inserted into `trace_retained` / `trace_step_retained`. Returns the count
32
+ * of rows actually inserted — zero for both when everything was already
33
+ * retained, or when `traceId` does not exist.
34
+ */
35
+ export async function copyTraceOnError(db, traceId) {
36
+ const rows = await db.execute(sql `
37
+ WITH RECURSIVE spine AS (
38
+ SELECT * FROM "trace" WHERE "id" = ${traceId}
39
+ UNION
40
+ SELECT t.* FROM "trace" t JOIN spine ON t."id" = spine."parent_id"
41
+ ),
42
+ copied_traces AS (
43
+ INSERT INTO "trace_retained" (${sql.raw(TRACE_COLUMNS)})
44
+ SELECT ${sql.raw(TRACE_COLUMNS)} FROM spine
45
+ ON CONFLICT ("id", "opened_day") DO NOTHING
46
+ RETURNING "id"
47
+ ),
48
+ copied_steps AS (
49
+ INSERT INTO "trace_step_retained" (${sql.raw(TRACE_STEP_COLUMNS)})
50
+ SELECT ${sql.raw(TRACE_STEP_COLUMNS_FROM_STEP)}
51
+ FROM "trace_step" s JOIN spine ON s."trace_id" = spine."id"
52
+ ON CONFLICT ("id", "trace_day") DO NOTHING
53
+ RETURNING "id"
54
+ )
55
+ SELECT
56
+ (SELECT count(*) FROM copied_traces)::int AS traces,
57
+ (SELECT count(*) FROM copied_steps)::int AS steps
58
+ `);
59
+ const row = rows[0];
60
+ return { traces: row['traces'], steps: row['steps'] };
61
+ }
62
+ //# sourceMappingURL=copy-on-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-on-error.js","sourceRoot":"","sources":["../../../src/trace/retain/copy-on-error.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAC7E,2EAA2E;AAC3E,UAAU;AACV,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,6DAA6D;AAC7D,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,iEAAiE;AAEjE,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAShE,SAAS,UAAU,CAAC,IAAc,EAAE,KAAa,EAAE,MAAM,GAAG,EAAE;IAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACxF,CAAC;AAED,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,cAAc,CAAC,CAAA;AAC1E,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,mBAAmB,CAAC,CAAA;AACxF,MAAM,4BAA4B,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAA;AAExG;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EAAM,EAAE,OAAe;IAC5D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;2CAEQ,OAAO;;;;;sCAKZ,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;eAC7C,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;;;;;2CAKM,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC;eACvD,GAAG,CAAC,GAAG,CAAC,4BAA4B,CAAC;;;;;;;;GAQjD,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAA;IACpB,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAW,EAAE,CAAA;AAC3E,CAAC"}
@@ -0,0 +1,18 @@
1
+ export declare const traceFields: {
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
3
+ openedDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ rootId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ parentId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ entryKind: import("../../data/domain/types.js").FieldDescriptor<"test" | "http" | "job" | "cron"> & import("../../data/domain/field.js").FieldModifiers<"test" | "http" | "job" | "cron">;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "open" | "closed" | "truncated" | "expired"> & import("../../data/domain/field.js").FieldModifiers<"error" | "open" | "closed" | "truncated" | "expired">;
9
+ tenantId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
10
+ requestId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
11
+ sessionId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
12
+ userId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
13
+ openedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
14
+ closedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
15
+ expiresAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
16
+ truncatedAtSeq: import("../../data/domain/types.js").FieldDescriptor<number | null> & import("../../data/domain/field.js").FieldModifiers<number | null>;
17
+ };
18
+ //# sourceMappingURL=trace-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-fields.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace-fields.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;CAwBvB,CAAA"}
@@ -0,0 +1,34 @@
1
+ // The column shape shared by the hot `trace` table and the cold
2
+ // `trace_retained` table. A trace is one execution rooted at an entry point
3
+ // (HTTP request, job, cron tick, test); its steps live in `trace_step`.
4
+ //
5
+ // Field descriptors are immutable, so the same record is handed to both
6
+ // `define()` calls — the hot and retained tables are structurally identical
7
+ // and differ only in retention policy.
8
+ import { field } from '../../data/domain/index.js';
9
+ export const traceFields = {
10
+ id: field.uuid().brand('TraceId').defaultRandom(),
11
+ // Partition key — the calendar day the trace opened. Retention drops whole
12
+ // day-partitions, so every row carries the day it belongs to.
13
+ openedDay: field.date(),
14
+ // The root of the trace tree. Equals `id` for a root trace. No DB foreign
15
+ // key: retention must be free to drop ancestor partitions out from under it.
16
+ rootId: field.uuid().brand('TraceId'),
17
+ parentId: field.uuid().brand('TraceId').nullable(),
18
+ parentStepId: field.uuid().brand('TraceStepId').nullable(),
19
+ entryKind: field.enum(['http', 'job', 'cron', 'test']),
20
+ status: field.enum(['open', 'closed', 'error', 'truncated', 'expired']),
21
+ tenantId: field.uuid().tenant().nullable(),
22
+ requestId: field.text().nullable(),
23
+ sessionId: field.text().nullable(),
24
+ userId: field.text().nullable(),
25
+ openedAt: field.timestamp(),
26
+ closedAt: field.timestamp().nullable(),
27
+ // Force-close deadline: openedAt + hotRetentionDays. A trace must not outlive
28
+ // its own oldest day-partition.
29
+ expiresAt: field.timestamp(),
30
+ // Set when the step cap is hit and the trace is truncated — the seq at which
31
+ // capture stopped.
32
+ truncatedAtSeq: field.integer().nullable(),
33
+ };
34
+ //# sourceMappingURL=trace-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-fields.js","sourceRoot":"","sources":["../../../src/trace/schema/trace-fields.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,4EAA4E;AAC5E,wEAAwE;AACxE,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,uCAAuC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE;IACjD,2EAA2E;IAC3E,8DAA8D;IAC9D,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;IACvB,0EAA0E;IAC1E,6EAA6E;IAC7E,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;IAClD,YAAY,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IAC1D,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IACvE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAClC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;IACtC,8EAA8E;IAC9E,gCAAgC;IAChC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE;IAC5B,6EAA6E;IAC7E,mBAAmB;IACnB,cAAc,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAC3C,CAAA"}
@@ -0,0 +1,18 @@
1
+ export declare const traceRetained: import("../../data/domain/types.js").DefinedTable<{
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
3
+ openedDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ rootId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ parentId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ entryKind: import("../../data/domain/types.js").FieldDescriptor<"test" | "http" | "job" | "cron"> & import("../../data/domain/field.js").FieldModifiers<"test" | "http" | "job" | "cron">;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "open" | "closed" | "truncated" | "expired"> & import("../../data/domain/field.js").FieldModifiers<"error" | "open" | "closed" | "truncated" | "expired">;
9
+ tenantId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
10
+ requestId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
11
+ sessionId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
12
+ userId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
13
+ openedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
14
+ closedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
15
+ expiresAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
16
+ truncatedAtSeq: import("../../data/domain/types.js").FieldDescriptor<number | null> & import("../../data/domain/field.js").FieldModifiers<number | null>;
17
+ }>;
18
+ //# sourceMappingURL=trace-retained.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-retained.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace-retained.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;EAGxB,CAAA"}
@@ -0,0 +1,11 @@
1
+ // The cold `trace_retained` table — structurally identical to `trace`, but
2
+ // holds traces copied out on error so they survive past `hotRetentionDays`.
3
+ // RANGE-partitioned the same way; retention drops day-partitions older than
4
+ // `errorRetentionDays`.
5
+ import { define } from '../../data/domain/index.js';
6
+ import { traceFields } from './trace-fields.js';
7
+ export const traceRetained = define('trace_retained', traceFields, {
8
+ primaryKey: ['id', 'openedDay'],
9
+ partitionBy: { strategy: 'range', column: 'openedDay' },
10
+ });
11
+ //# sourceMappingURL=trace-retained.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-retained.js","sourceRoot":"","sources":["../../../src/trace/schema/trace-retained.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,wBAAwB;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,EAAE,WAAW,EAAE;IACjE,UAAU,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;IAC/B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE;CACxD,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ export declare const traceStepFields: {
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId">>;
3
+ traceDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ traceId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ seq: import("../../data/domain/types.js").FieldDescriptor<number> & import("../../data/domain/field.js").FieldModifiers<number>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ flowStepRef: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "ok"> & import("../../data/domain/field.js").FieldModifiers<"error" | "ok">;
9
+ startedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
10
+ completedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
11
+ durationMicros: import("../../data/domain/types.js").FieldDescriptor<bigint | null> & import("../../data/domain/field.js").FieldModifiers<bigint | null>;
12
+ capturedInputs: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
13
+ error: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
14
+ };
15
+ //# sourceMappingURL=trace-step-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step-fields.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace-step-fields.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAqB3B,CAAA"}
@@ -0,0 +1,31 @@
1
+ // The column shape shared by the hot `trace_step` table and the cold
2
+ // `trace_step_retained` table. One row per flow step that executed under an
3
+ // active Flow.
4
+ //
5
+ // Field descriptors are immutable, so the same record is handed to both
6
+ // `define()` calls.
7
+ import { field } from '../../data/domain/index.js';
8
+ import { schema } from '../../data/schema/namespace.js';
9
+ export const traceStepFields = {
10
+ id: field.uuid().brand('TraceStepId').defaultRandom(),
11
+ // Partition key — the parent trace's `openedDay`, NOT the step's own
12
+ // timestamp. This keeps the foreign key into `trace` partition-local: a
13
+ // step and its trace always sit in the same day-partition, so the two
14
+ // tables' partitions retire together.
15
+ traceDay: field.date(),
16
+ traceId: field.uuid().brand('TraceId'),
17
+ // Spawn order within the trace. Branch vs step is an edge property, not a
18
+ // node property — `seq` only records sequencing.
19
+ seq: field.integer(),
20
+ parentStepId: field.uuid().brand('TraceStepId').nullable(),
21
+ // The `path:symbol` identity of the flow step, matching the annotation's
22
+ // upstream/downstream targets.
23
+ flowStepRef: field.text(),
24
+ status: field.enum(['ok', 'error']),
25
+ startedAt: field.timestamp(),
26
+ completedAt: field.timestamp().nullable(),
27
+ durationMicros: field.bigint().nullable(),
28
+ capturedInputs: field.jsonb(schema.check.json()).nullable(),
29
+ error: field.jsonb(schema.check.json()).nullable(),
30
+ };
31
+ //# sourceMappingURL=trace-step-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step-fields.js","sourceRoot":"","sources":["../../../src/trace/schema/trace-step-fields.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,4EAA4E;AAC5E,eAAe;AACf,EAAE;AACF,wEAAwE;AACxE,oBAAoB;AAEpB,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,aAAa,EAAE;IACrD,qEAAqE;IACrE,wEAAwE;IACxE,sEAAsE;IACtE,sCAAsC;IACtC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE;IACtB,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACtC,0EAA0E;IAC1E,iDAAiD;IACjD,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE;IACpB,YAAY,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IAC1D,yEAAyE;IACzE,+BAA+B;IAC/B,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE;IACzB,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE;IAC5B,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;IACzC,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3D,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;CACnD,CAAA"}
@@ -0,0 +1,15 @@
1
+ export declare const traceStepRetained: import("../../data/domain/types.js").DefinedTable<{
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId">>;
3
+ traceDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ traceId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ seq: import("../../data/domain/types.js").FieldDescriptor<number> & import("../../data/domain/field.js").FieldModifiers<number>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ flowStepRef: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "ok"> & import("../../data/domain/field.js").FieldModifiers<"error" | "ok">;
9
+ startedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
10
+ completedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
11
+ durationMicros: import("../../data/domain/types.js").FieldDescriptor<bigint | null> & import("../../data/domain/field.js").FieldModifiers<bigint | null>;
12
+ capturedInputs: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
13
+ error: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
14
+ }>;
15
+ //# sourceMappingURL=trace-step-retained.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step-retained.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace-step-retained.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;EAQ5B,CAAA"}
@@ -0,0 +1,18 @@
1
+ // The cold `trace_step_retained` table — structurally identical to
2
+ // `trace_step`, holding steps copied out on error. Its foreign key targets
3
+ // `trace_retained`: copy-on-error writes the trace and its steps together, so
4
+ // referential integrity holds in the cold tables exactly as it does in the hot
5
+ // ones.
6
+ import { define } from '../../data/domain/index.js';
7
+ import { traceStepFields } from './trace-step-fields.js';
8
+ import { traceRetained } from './trace-retained.js';
9
+ export const traceStepRetained = define('trace_step_retained', traceStepFields, {
10
+ primaryKey: ['id', 'traceDay'],
11
+ partitionBy: { strategy: 'range', column: 'traceDay' },
12
+ foreignKeys: [{
13
+ columns: ['traceId', 'traceDay'],
14
+ references: { definition: traceRetained, columns: ['id', 'openedDay'] },
15
+ onDelete: 'cascade',
16
+ }],
17
+ });
18
+ //# sourceMappingURL=trace-step-retained.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step-retained.js","sourceRoot":"","sources":["../../../src/trace/schema/trace-step-retained.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,2EAA2E;AAC3E,8EAA8E;AAC9E,+EAA+E;AAC/E,QAAQ;AAER,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,qBAAqB,EAAE,eAAe,EAAE;IAC9E,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC;IAC9B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE;IACtD,WAAW,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;YAChC,UAAU,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;YACvE,QAAQ,EAAE,SAAS;SACpB,CAAC;CACH,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ export declare const traceStep: import("../../data/domain/types.js").DefinedTable<{
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId">>;
3
+ traceDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ traceId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ seq: import("../../data/domain/types.js").FieldDescriptor<number> & import("../../data/domain/field.js").FieldModifiers<number>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ flowStepRef: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "ok"> & import("../../data/domain/field.js").FieldModifiers<"error" | "ok">;
9
+ startedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
10
+ completedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
11
+ durationMicros: import("../../data/domain/types.js").FieldDescriptor<bigint | null> & import("../../data/domain/field.js").FieldModifiers<bigint | null>;
12
+ capturedInputs: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
13
+ error: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType>;
14
+ }>;
15
+ //# sourceMappingURL=trace-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace-step.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS;;;;;;;;;;;;;EAQpB,CAAA"}
@@ -0,0 +1,17 @@
1
+ // The hot `trace_step` table — one row per flow step executed under a Flow.
2
+ // Partitioned by `traceDay` (the parent trace's `openedDay`), so the foreign
3
+ // key into `trace` is partition-local and both tables' partitions retire
4
+ // together.
5
+ import { define } from '../../data/domain/index.js';
6
+ import { traceStepFields } from './trace-step-fields.js';
7
+ import { trace } from './trace.js';
8
+ export const traceStep = define('trace_step', traceStepFields, {
9
+ primaryKey: ['id', 'traceDay'],
10
+ partitionBy: { strategy: 'range', column: 'traceDay' },
11
+ foreignKeys: [{
12
+ columns: ['traceId', 'traceDay'],
13
+ references: { definition: trace, columns: ['id', 'openedDay'] },
14
+ onDelete: 'cascade',
15
+ }],
16
+ });
17
+ //# sourceMappingURL=trace-step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-step.js","sourceRoot":"","sources":["../../../src/trace/schema/trace-step.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,YAAY;AAEZ,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,eAAe,EAAE;IAC7D,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC;IAC9B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE;IACtD,WAAW,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;YAChC,UAAU,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;YAC/D,QAAQ,EAAE,SAAS;SACpB,CAAC;CACH,CAAC,CAAA"}
@@ -0,0 +1,18 @@
1
+ export declare const trace: import("../../data/domain/types.js").DefinedTable<{
2
+ id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
3
+ openedDay: import("../../data/domain/types.js").FieldDescriptor<string> & import("../../data/domain/field.js").FieldModifiers<string>;
4
+ rootId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId">> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId">>;
5
+ parentId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceId"> | null>;
6
+ parentStepId: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null> & import("../../data/domain/field.js").FieldModifiers<import("../../data/domain/brand.js").Branded<string, "TraceStepId"> | null>;
7
+ entryKind: import("../../data/domain/types.js").FieldDescriptor<"test" | "http" | "job" | "cron"> & import("../../data/domain/field.js").FieldModifiers<"test" | "http" | "job" | "cron">;
8
+ status: import("../../data/domain/types.js").FieldDescriptor<"error" | "open" | "closed" | "truncated" | "expired"> & import("../../data/domain/field.js").FieldModifiers<"error" | "open" | "closed" | "truncated" | "expired">;
9
+ tenantId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
10
+ requestId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
11
+ sessionId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
12
+ userId: import("../../data/domain/types.js").FieldDescriptor<string | null> & import("../../data/domain/field.js").FieldModifiers<string | null>;
13
+ openedAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
14
+ closedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null> & import("../../data/domain/field.js").FieldModifiers<Date | null>;
15
+ expiresAt: import("../../data/domain/types.js").FieldDescriptor<Date> & import("../../data/domain/field.js").FieldModifiers<Date>;
16
+ truncatedAtSeq: import("../../data/domain/types.js").FieldDescriptor<number | null> & import("../../data/domain/field.js").FieldModifiers<number | null>;
17
+ }>;
18
+ //# sourceMappingURL=trace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/trace/schema/trace.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;EAGhB,CAAA"}
@@ -0,0 +1,11 @@
1
+ // The hot `trace` table — one row per execution, rooted at an entry point.
2
+ // RANGE-partitioned by `openedDay`; retention drops day-partitions older than
3
+ // `hotRetentionDays`. Errored traces are copied to `trace_retained` before
4
+ // their partition is dropped.
5
+ import { define } from '../../data/domain/index.js';
6
+ import { traceFields } from './trace-fields.js';
7
+ export const trace = define('trace', traceFields, {
8
+ primaryKey: ['id', 'openedDay'],
9
+ partitionBy: { strategy: 'range', column: 'openedDay' },
10
+ });
11
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.js","sourceRoot":"","sources":["../../../src/trace/schema/trace.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,2EAA2E;AAC3E,8BAA8B;AAE9B,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE;IAChD,UAAU,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;IAC/B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE;CACxD,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"changed-files.d.ts","sourceRoot":"","sources":["../../src/workspace/changed-files.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,QAAQ,CAAA;AAE/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAalE;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAoBhD"}
1
+ {"version":3,"file":"changed-files.d.ts","sourceRoot":"","sources":["../../src/workspace/changed-files.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,QAAQ,CAAA;AAE/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAalE;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAwBhD"}
@@ -20,7 +20,11 @@ export function filesToModules(files, modulePaths) {
20
20
  for (const file of files) {
21
21
  let matched = false;
22
22
  for (const modPath of sorted) {
23
- if (file === modPath || file.startsWith(modPath + '/')) {
23
+ // '.' is the synthesized implicit module for a single-package repo — it
24
+ // is the repo root, so it contains every file. git diff paths are
25
+ // repo-relative without a leading './', so the prefix check below can
26
+ // never match '.' on its own.
27
+ if (modPath === '.' || file === modPath || file.startsWith(modPath + '/')) {
24
28
  modules.add(modPath);
25
29
  matched = true;
26
30
  break;