@tangle-network/sdk-telemetry 0.7.11 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{lifecycle-wall-BnN-KFBx.d.mts → lifecycle-wall-BL6-gCBp.d.mts} +9 -47
- package/dist/lifecycle-wall-BL6-gCBp.d.mts.map +1 -0
- package/dist/{lifecycle-wall-BeaxDTJ8.mjs → lifecycle-wall-CVuGfuSq.mjs} +23 -52
- package/dist/lifecycle-wall-CVuGfuSq.mjs.map +1 -0
- package/dist/server-timing.d.mts +3 -4
- package/dist/server-timing.d.mts.map +1 -1
- package/dist/server-timing.mjs +5 -3
- package/dist/server-timing.mjs.map +1 -1
- package/dist/stage-span.d.mts +1 -1
- package/dist/stage-span.mjs +1 -1
- package/package.json +3 -3
- package/dist/lifecycle-wall-BeaxDTJ8.mjs.map +0 -1
- package/dist/lifecycle-wall-BnN-KFBx.d.mts.map +0 -1
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
//#region src/lifecycle-wall.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Per-flow shape of the accounting window. `totalOperation` is the span whose
|
|
4
|
-
* wall the named leaves must tile; `postReadyOperations` run AFTER it is
|
|
5
|
-
* stamped (excluded from the leaf sum); `prepUmbrella` is the optional
|
|
6
|
-
* create-style split of an entry umbrella minus its measured leaf children. Absent
|
|
7
|
-
* `prepUmbrella` ⇒ `prepUnaccountedMs` is always 0 and the whole dark falls
|
|
8
|
-
* into `unaccountedMs` (the shape every non-create flow uses).
|
|
9
|
-
*/
|
|
2
|
+
/** Per-flow shape of the accounting window. */
|
|
10
3
|
type FlowAccountingSpec = {
|
|
11
4
|
totalOperation: string;
|
|
12
5
|
postReadyOperations?: ReadonlySet<string>;
|
|
@@ -43,25 +36,7 @@ interface LifecycleWallFlow extends Partial<FlowAccountingSpec> {
|
|
|
43
36
|
settleHop?: string;
|
|
44
37
|
workerNamedHops?: readonly string[];
|
|
45
38
|
}
|
|
46
|
-
/**
|
|
47
|
-
* A flat `{name: ms}` ledger read as the tree its names describe.
|
|
48
|
-
*
|
|
49
|
-
* Every producer in this repo emits nested stages FLAT, with the containment
|
|
50
|
-
* in the name: `capture.<hostPhase>` and `capture.restic_<phase>` inside
|
|
51
|
-
* `capture` (snapshot-helpers.ts), `materialize.parentRead|precreate|
|
|
52
|
-
* branchComplete|host.*|child.*|residual` inside `materialize` (branch.ts),
|
|
53
|
-
* `delete.<hostPhase>` inside `delete` and `restore_workspace.<phase>` inside
|
|
54
|
-
* `restore_workspace` (snapshots.ts). Summing every entry as a sibling counts
|
|
55
|
-
* the children inside their parent a second time and reports a wall the
|
|
56
|
-
* orchestrator never spent.
|
|
57
|
-
*
|
|
58
|
-
* So a dotted name is NEVER top-level. It attaches to the longest prefix that
|
|
59
|
-
* exists as a stage; when no prefix exists — the restore job's `host.<phase>`,
|
|
60
|
-
* which the queue records inside `restore_workspace` without naming it
|
|
61
|
-
* (snapshot-job-queue.ts:394) — it is still excluded from the top-level sum
|
|
62
|
-
* and reported as a child of the ledger at large. Excluding it can only leave
|
|
63
|
-
* MORE time unnamed, never fabricate a reconciliation.
|
|
64
|
-
*/
|
|
39
|
+
/** Longest present prefix owns a dotted stage; orphan detail never enters the root sum. */
|
|
65
40
|
declare function stageTree(stages: Readonly<Record<string, number>>): {
|
|
66
41
|
nodes: {
|
|
67
42
|
name: string;
|
|
@@ -80,33 +55,20 @@ declare function stageTree(stages: Readonly<Record<string, number>>): {
|
|
|
80
55
|
}[];
|
|
81
56
|
topLevelMs: number;
|
|
82
57
|
};
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
* first so a capped header keeps them. Unparented spans nest in the total span.
|
|
87
|
-
*/
|
|
58
|
+
/** Parent minus its direct children; overlapping evidence never invents dark time. */
|
|
59
|
+
declare function unattributedStages(stages: Readonly<Record<string, number>>, parents: Readonly<Record<string, readonly string[]>>): Record<string, number>;
|
|
60
|
+
/** A response's span tree as `<stage>.<path>` rows and each parent's wall minus its children as `<parent>.unattributed` (0 when children overlap), residuals first so a capped header keeps them. Unparented spans nest in the total span. */
|
|
88
61
|
declare function spanTreeStages(stage: string, stageMs: Readonly<Record<string, number>>, operations?: readonly (LifecycleStageTiming & {
|
|
89
62
|
status?: string;
|
|
90
63
|
})[], spec?: Partial<FlowAccountingSpec>): Record<string, number>;
|
|
91
64
|
/** Parent operations contain their descendants and are never counted as leaves. */
|
|
92
65
|
declare function parentOperations(operations: readonly LifecycleStageTiming[]): ReadonlySet<string>;
|
|
93
|
-
/**
|
|
94
|
-
* The measured leaves of one response's span tree, per the flow's own spec.
|
|
95
|
-
*
|
|
96
|
-
* Identical rule to the orchestrator's `computeFlowAccountingResiduals`: drop
|
|
97
|
-
* the total span (it is the window), drop the spans stamped after it closes,
|
|
98
|
-
* and drop any span another span names as its parent (a parent re-measures its
|
|
99
|
-
* children). What is left sums to the window minus its named residual.
|
|
100
|
-
*/
|
|
66
|
+
/** The measured leaves of one response's span tree, per the flow's own spec. */
|
|
101
67
|
declare function leafOperations<T extends LifecycleStageTiming>(operations: readonly T[], excluded?: ReadonlySet<string>, parents?: ReadonlySet<string>): (T & {
|
|
102
68
|
durationMs: number;
|
|
103
69
|
})[];
|
|
104
70
|
declare function operationLeafDurations(operations: readonly LifecycleStageTiming[], excluded?: ReadonlySet<string>): Map<string, number>;
|
|
105
|
-
/**
|
|
106
|
-
* Partition one input before aggregation: null is unavailable; a negative
|
|
107
|
-
* residual is overlapping evidence, never an instruction to publish zero.
|
|
108
|
-
* Callers retain their population grouping, medians and display labels.
|
|
109
|
-
*/
|
|
71
|
+
/** Partition one input before aggregation: null is unavailable; a negative residual is overlapping evidence, never an instruction to publish zero. Callers retain their population grouping, medians and display labels. */
|
|
110
72
|
declare function partitionLifecycleWalls(sample: LifecycleWallSample, flow: LifecycleWallFlow): {
|
|
111
73
|
wallMs: number;
|
|
112
74
|
httpMs: number;
|
|
@@ -189,5 +151,5 @@ declare function partitionLifecycleWalls(sample: LifecycleWallSample, flow: Life
|
|
|
189
151
|
};
|
|
190
152
|
};
|
|
191
153
|
//#endregion
|
|
192
|
-
export { LifecycleWallSample as a, leafOperations as c, partitionLifecycleWalls as d, spanTreeStages as f, LifecycleWallFlow as i, operationLeafDurations as l, DELETE_ACCOUNTING_SPEC as n, RESUME_ACCOUNTING_SPEC as o, stageTree as p, FlowAccountingSpec as r, STOP_ACCOUNTING_SPEC as s, CREATE_ACCOUNTING_SPEC as t, parentOperations as u };
|
|
193
|
-
//# sourceMappingURL=lifecycle-wall-
|
|
154
|
+
export { LifecycleWallSample as a, leafOperations as c, partitionLifecycleWalls as d, spanTreeStages as f, LifecycleWallFlow as i, operationLeafDurations as l, unattributedStages as m, DELETE_ACCOUNTING_SPEC as n, RESUME_ACCOUNTING_SPEC as o, stageTree as p, FlowAccountingSpec as r, STOP_ACCOUNTING_SPEC as s, CREATE_ACCOUNTING_SPEC as t, parentOperations as u };
|
|
155
|
+
//# sourceMappingURL=lifecycle-wall-BL6-gCBp.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-wall-BL6-gCBp.d.mts","names":[],"sources":["../src/lifecycle-wall.ts"],"mappings":";;KAOY,kBAAA;EACV,cAAA;EACA,mBAAA,GAAsB,WAAA;EACtB,YAAA;IAAiB,SAAA;EAAA;AAAA;AAAA,cAGN,sBAAA,EAAwB,kBAAA;AAAA,cAQxB,sBAAA,EAAwB,kBAAA;AAAA,cAWxB,oBAAA,EAAsB,kBAAA;AAAA,cAItB,sBAAA,EAAwB,kBAAA;AAAA,UAIpB,oBAAA;EACf,SAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAEG,MAAA,GAAS,QAAA,CAAS,MAAA;AAAA,UACN,mBAAA;EACf,MAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;EACP,OAAA,YAAmB,oBAAA;EACnB,UAAA,GAAa,MAAA;EACb,WAAA;EACA,UAAA,GAAa,MAAA;EACb,SAAA,GAAY,MAAA;EACZ,KAAA;EACA,QAAA;EACA,eAAA;AAAA;AAAA,UAEe,iBAAA,SAA0B,OAAA,CAAQ,kBAAA;EACjD,cAAA;EACA,aAAA;EACA,SAAA;EACA,eAAA;AAAA;;iBAIc,SAAA,CAAU,MAAA,EAAQ,QAAA,CAAS,MAAA;;;;;;;;;;OAlBlC;;;;;;;;;iBA6CO,kBAAA,CACd,MAAA,EAAQ,QAAA,CAAS,MAAA,mBACjB,OAAA,EAAS,QAAA,CAAS,MAAA,+BACjB,MAAA;;iBA0Ba,cAAA,CACd,KAAA,UACA,OAAA,EAAS,QAAA,CAAS,MAAA,mBAClB,UAAA,aAAsB,oBAAA;EAAyB,MAAA;AAAA,MAC/C,IAAA,GAAO,OAAA,CAAQ,kBAAA,IACd,MAAA;;iBA4Ca,gBAAA,CACd,UAAA,WAAqB,oBAAA,KACpB,WAAA;;iBASa,cAAA,WAAyB,oBAAA,CAAA,CACvC,UAAA,WAAqB,CAAA,IACrB,QAAA,GAAU,WAAA,UACV,OAAA,GAAO,WAAA,YAA+B,CAAA;;;iBAWxB,sBAAA,CACd,UAAA,WAAqB,oBAAA,IACrB,QAAA,GAAU,WAAA,WAA+B,GAAA;;iBAgB3B,uBAAA,CACd,MAAA,EAAQ,mBAAA,EACR,IAAA,EAAM,iBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA1HW;;;;;;;;;;;;;;;;;;SA8BC"}
|
|
@@ -17,25 +17,7 @@ const RESUME_ACCOUNTING_SPEC = {
|
|
|
17
17
|
};
|
|
18
18
|
const STOP_ACCOUNTING_SPEC = { totalOperation: "orchestrator.stop_complete" };
|
|
19
19
|
const DELETE_ACCOUNTING_SPEC = { totalOperation: "orchestrator.delete_complete" };
|
|
20
|
-
/**
|
|
21
|
-
* A flat `{name: ms}` ledger read as the tree its names describe.
|
|
22
|
-
*
|
|
23
|
-
* Every producer in this repo emits nested stages FLAT, with the containment
|
|
24
|
-
* in the name: `capture.<hostPhase>` and `capture.restic_<phase>` inside
|
|
25
|
-
* `capture` (snapshot-helpers.ts), `materialize.parentRead|precreate|
|
|
26
|
-
* branchComplete|host.*|child.*|residual` inside `materialize` (branch.ts),
|
|
27
|
-
* `delete.<hostPhase>` inside `delete` and `restore_workspace.<phase>` inside
|
|
28
|
-
* `restore_workspace` (snapshots.ts). Summing every entry as a sibling counts
|
|
29
|
-
* the children inside their parent a second time and reports a wall the
|
|
30
|
-
* orchestrator never spent.
|
|
31
|
-
*
|
|
32
|
-
* So a dotted name is NEVER top-level. It attaches to the longest prefix that
|
|
33
|
-
* exists as a stage; when no prefix exists — the restore job's `host.<phase>`,
|
|
34
|
-
* which the queue records inside `restore_workspace` without naming it
|
|
35
|
-
* (snapshot-job-queue.ts:394) — it is still excluded from the top-level sum
|
|
36
|
-
* and reported as a child of the ledger at large. Excluding it can only leave
|
|
37
|
-
* MORE time unnamed, never fabricate a reconciliation.
|
|
38
|
-
*/
|
|
20
|
+
/** Longest present prefix owns a dotted stage; orphan detail never enters the root sum. */
|
|
39
21
|
function stageTree(stages) {
|
|
40
22
|
const present = new Set(Object.keys(stages));
|
|
41
23
|
const parentOf = (name) => {
|
|
@@ -61,11 +43,22 @@ function stageTree(stages) {
|
|
|
61
43
|
topLevelMs: topLevel.reduce((sum, node) => sum + node.ms, 0)
|
|
62
44
|
};
|
|
63
45
|
}
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
46
|
+
/** Parent minus its direct children; overlapping evidence never invents dark time. */
|
|
47
|
+
function unattributedStages(stages, parents) {
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const [parent, children] of Object.entries(parents)) {
|
|
50
|
+
const wall = stages[parent];
|
|
51
|
+
if (wall === void 0 || !Number.isFinite(wall)) continue;
|
|
52
|
+
const named = new Set(children.flatMap((child) => {
|
|
53
|
+
if (!child.endsWith(".*")) return [child];
|
|
54
|
+
const prefix = child.slice(0, -1);
|
|
55
|
+
return Object.keys(stages).filter((name) => name.startsWith(prefix) && !name.slice(prefix.length).includes(".") && name !== `${parent}.unattributed`);
|
|
56
|
+
}));
|
|
57
|
+
out[`${parent}.unattributed`] = Math.max(0, [...named].reduce((left, name) => left - (stages[name] ?? 0), wall));
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** A response's span tree as `<stage>.<path>` rows and each parent's wall minus its children as `<parent>.unattributed` (0 when children overlap), residuals first so a capped header keeps them. Unparented spans nest in the total span. */
|
|
69
62
|
function spanTreeStages(stage, stageMs, operations = [], spec) {
|
|
70
63
|
const total = spec?.totalOperation ?? "";
|
|
71
64
|
const byName = new Map(operations.map((op) => [op.operation, op]));
|
|
@@ -77,25 +70,14 @@ function spanTreeStages(stage, stageMs, operations = [], spec) {
|
|
|
77
70
|
};
|
|
78
71
|
const rows = { [stage]: stageMs[stage] ?? 0 };
|
|
79
72
|
for (const { durationMs: ms, status, ...op } of operations) if (status === "completed" && typeof ms === "number" && ms >= 0) rows[path(op)] = (rows[path(op)] ?? 0) + ms;
|
|
80
|
-
const residuals = {};
|
|
81
|
-
for (const [parent, ms] of Object.entries(rows)) {
|
|
82
|
-
const kids = Object.keys(rows).filter((name) => name.startsWith(`${parent}.`) && !name.slice(parent.length + 1).includes("."));
|
|
83
|
-
if (kids.length) residuals[`${parent}.unattributed`] = Math.max(0, kids.reduce((rest, kid) => rest - (rows[kid] ?? 0), ms));
|
|
84
|
-
}
|
|
73
|
+
const residuals = unattributedStages(rows, Object.fromEntries(Object.keys(rows).filter((parent) => Object.keys(rows).some((name) => name.startsWith(`${parent}.`) && !name.slice(parent.length + 1).includes("."))).map((parent) => [parent, [`${parent}.*`]])));
|
|
85
74
|
delete rows[stage];
|
|
86
75
|
return {
|
|
87
76
|
...residuals,
|
|
88
77
|
...rows
|
|
89
78
|
};
|
|
90
79
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Hops that describe the SHAPE of the request rather than a slice of it: the
|
|
93
|
-
* three nested walls, the transport the walls imply, and the retry counter.
|
|
94
|
-
* They are the terms of the summary line, so ranking them again as sub-stages
|
|
95
|
-
* would print the same milliseconds twice under a second name. `preHandler`
|
|
96
|
-
* joins them because it is the umbrella over the `mw.*` own-times, which ARE
|
|
97
|
-
* ranked.
|
|
98
|
-
*/
|
|
80
|
+
/** Hops that describe the SHAPE of the request rather than a slice of it: the three nested walls, the transport the walls imply, and the retry counter. */
|
|
99
81
|
const SHAPE_HOPS = new Set([
|
|
100
82
|
"preHandler",
|
|
101
83
|
"total",
|
|
@@ -109,14 +91,7 @@ const SHAPE_HOPS = new Set([
|
|
|
109
91
|
function parentOperations(operations) {
|
|
110
92
|
return new Set(operations.flatMap((op) => typeof op.parent === "string" ? [op.parent] : []));
|
|
111
93
|
}
|
|
112
|
-
/**
|
|
113
|
-
* The measured leaves of one response's span tree, per the flow's own spec.
|
|
114
|
-
*
|
|
115
|
-
* Identical rule to the orchestrator's `computeFlowAccountingResiduals`: drop
|
|
116
|
-
* the total span (it is the window), drop the spans stamped after it closes,
|
|
117
|
-
* and drop any span another span names as its parent (a parent re-measures its
|
|
118
|
-
* children). What is left sums to the window minus its named residual.
|
|
119
|
-
*/
|
|
94
|
+
/** The measured leaves of one response's span tree, per the flow's own spec. */
|
|
120
95
|
function leafOperations(operations, excluded = /* @__PURE__ */ new Set(), parents = parentOperations(operations)) {
|
|
121
96
|
return operations.filter((op) => !excluded.has(op.operation) && !parents.has(op.operation) && typeof op.durationMs === "number" && Number.isFinite(op.durationMs));
|
|
122
97
|
}
|
|
@@ -130,11 +105,7 @@ const positiveDifference = (a, b) => {
|
|
|
130
105
|
const value = difference(a, b);
|
|
131
106
|
return value === null ? null : Math.max(0, value);
|
|
132
107
|
};
|
|
133
|
-
/**
|
|
134
|
-
* Partition one input before aggregation: null is unavailable; a negative
|
|
135
|
-
* residual is overlapping evidence, never an instruction to publish zero.
|
|
136
|
-
* Callers retain their population grouping, medians and display labels.
|
|
137
|
-
*/
|
|
108
|
+
/** Partition one input before aggregation: null is unavailable; a negative residual is overlapping evidence, never an instruction to publish zero. Callers retain their population grouping, medians and display labels. */
|
|
138
109
|
function partitionLifecycleWalls(sample, flow) {
|
|
139
110
|
const present = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
140
111
|
const finiteStages = (values) => Object.fromEntries(Object.entries(values ?? {}).filter(([, ms]) => Number.isFinite(ms)));
|
|
@@ -223,6 +194,6 @@ function partitionLifecycleWalls(sample, flow) {
|
|
|
223
194
|
};
|
|
224
195
|
}
|
|
225
196
|
//#endregion
|
|
226
|
-
export { leafOperations as a, partitionLifecycleWalls as c, STOP_ACCOUNTING_SPEC as i, spanTreeStages as l, DELETE_ACCOUNTING_SPEC as n, operationLeafDurations as o, RESUME_ACCOUNTING_SPEC as r, parentOperations as s, CREATE_ACCOUNTING_SPEC as t, stageTree as u };
|
|
197
|
+
export { leafOperations as a, partitionLifecycleWalls as c, unattributedStages as d, STOP_ACCOUNTING_SPEC as i, spanTreeStages as l, DELETE_ACCOUNTING_SPEC as n, operationLeafDurations as o, RESUME_ACCOUNTING_SPEC as r, parentOperations as s, CREATE_ACCOUNTING_SPEC as t, stageTree as u };
|
|
227
198
|
|
|
228
|
-
//# sourceMappingURL=lifecycle-wall-
|
|
199
|
+
//# sourceMappingURL=lifecycle-wall-CVuGfuSq.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-wall-CVuGfuSq.mjs","names":[],"sources":["../src/lifecycle-wall.ts"],"sourcesContent":["const CREATE_POST_READY_OPERATIONS = new Set([\n \"orchestrator.container_lookup\",\n \"orchestrator.snapshot_restore_check\",\n \"orchestrator.provision_finalize\",\n]);\n\n/** Per-flow shape of the accounting window. */\nexport type FlowAccountingSpec = {\n totalOperation: string;\n postReadyOperations?: ReadonlySet<string>;\n prepUmbrella?: { operation: string };\n};\n\nexport const CREATE_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.ready\",\n postReadyOperations: CREATE_POST_READY_OPERATIONS,\n prepUmbrella: {\n operation: \"orchestrator.provision_prep\",\n },\n};\n\nexport const RESUME_ACCOUNTING_SPEC: FlowAccountingSpec = {\n // `orchestrator.ready` runs from the request to the sidecar's ready stamp;\n // these run after that stamp.\n totalOperation: \"orchestrator.ready\",\n postReadyOperations: new Set([\n \"orchestrator.connection_build\",\n \"orchestrator.metering_restart\",\n \"orchestrator.resume_commit\",\n ]),\n};\n\nexport const STOP_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.stop_complete\",\n};\n\nexport const DELETE_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.delete_complete\",\n};\n\nexport interface LifecycleStageTiming {\n operation: string;\n durationMs?: number;\n parent?: string | null;\n}\ntype Values = Readonly<Record<string, number>>;\nexport interface LifecycleWallSample {\n wallMs: number;\n httpMs: number;\n hops?: Values;\n spanOps?: readonly LifecycleStageTiming[];\n spanLeaves?: Values;\n spanTotalMs?: number | null;\n orchStages?: Values | null;\n jobPhases?: Values | null;\n jobMs?: number | null;\n settleMs?: number | null;\n spanAccountedMs?: number;\n}\nexport interface LifecycleWallFlow extends Partial<FlowAccountingSpec> {\n workerTotalHop: string;\n addPreHandler: boolean;\n settleHop?: string;\n workerNamedHops?: readonly string[];\n}\n\n/** Longest present prefix owns a dotted stage; orphan detail never enters the root sum. */\nexport function stageTree(stages: Readonly<Record<string, number>>) {\n const present = new Set(Object.keys(stages));\n const parentOf = (name: string) => {\n let cut = name.lastIndexOf(\".\");\n while (cut > 0) {\n const candidate = name.slice(0, cut);\n if (present.has(candidate)) return candidate;\n cut = candidate.lastIndexOf(\".\");\n }\n return name.includes(\".\") ? \"\" : null;\n };\n const nodes = Object.entries(stages).map(([name, ms]) => ({\n name,\n ms,\n parent: parentOf(name),\n }));\n const topLevel = nodes.filter((node) => node.parent === null);\n return {\n nodes,\n topLevel,\n /** Children whose declared parent is not in the ledger; never summed. */\n orphans: nodes.filter((node) => node.parent === \"\"),\n topLevelMs: topLevel.reduce((sum, node) => sum + node.ms, 0),\n };\n}\n\n/** Parent minus its direct children; overlapping evidence never invents dark time. */\nexport function unattributedStages(\n stages: Readonly<Record<string, number>>,\n parents: Readonly<Record<string, readonly string[]>>,\n): Record<string, number> {\n const out: Record<string, number> = {};\n for (const [parent, children] of Object.entries(parents)) {\n const wall = stages[parent];\n if (wall === undefined || !Number.isFinite(wall)) continue;\n const named = new Set(\n children.flatMap((child) => {\n if (!child.endsWith(\".*\")) return [child];\n const prefix = child.slice(0, -1);\n return Object.keys(stages).filter(\n (name) =>\n name.startsWith(prefix) &&\n !name.slice(prefix.length).includes(\".\") &&\n name !== `${parent}.unattributed`,\n );\n }),\n );\n out[`${parent}.unattributed`] = Math.max(\n 0,\n [...named].reduce((left, name) => left - (stages[name] ?? 0), wall),\n );\n }\n return out;\n}\n\n/** A response's span tree as `<stage>.<path>` rows and each parent's wall minus its children as `<parent>.unattributed` (0 when children overlap), residuals first so a capped header keeps them. Unparented spans nest in the total span. */\nexport function spanTreeStages(\n stage: string,\n stageMs: Readonly<Record<string, number>>,\n operations: readonly (LifecycleStageTiming & { status?: string })[] = [],\n spec?: Partial<FlowAccountingSpec>,\n): Record<string, number> {\n const total = spec?.totalOperation ?? \"\";\n const byName = new Map(operations.map((op) => [op.operation, op]));\n const path = (op: LifecycleStageTiming, depth = 0): string => {\n const outside =\n op.operation === total || spec?.postReadyOperations?.has(op.operation);\n const parent = byName.get(op.parent ?? (outside ? \"\" : total));\n const name = op.operation.slice(op.operation.lastIndexOf(\".\") + 1);\n return `${parent && depth < 8 ? path(parent, depth + 1) : stage}.${name}`;\n };\n const rows: Record<string, number> = { [stage]: stageMs[stage] ?? 0 };\n for (const { durationMs: ms, status, ...op } of operations)\n if (status === \"completed\" && typeof ms === \"number\" && ms >= 0)\n rows[path(op)] = (rows[path(op)] ?? 0) + ms;\n const residuals = unattributedStages(\n rows,\n Object.fromEntries(\n Object.keys(rows)\n .filter((parent) =>\n Object.keys(rows).some(\n (name) =>\n name.startsWith(`${parent}.`) &&\n !name.slice(parent.length + 1).includes(\".\"),\n ),\n )\n .map((parent) => [parent, [`${parent}.*`]]),\n ),\n );\n delete rows[stage];\n return { ...residuals, ...rows };\n}\n\n/** Hops that describe the SHAPE of the request rather than a slice of it: the three nested walls, the transport the walls imply, and the retry counter. */\nconst SHAPE_HOPS = new Set([\n \"preHandler\",\n \"total\",\n \"serverWall\",\n \"orchestrator\",\n \"orchestratorServer\",\n \"transportMarkup\",\n \"orchestratorRetries\",\n]);\n\n/** Parent operations contain their descendants and are never counted as leaves. */\nexport function parentOperations(\n operations: readonly LifecycleStageTiming[],\n): ReadonlySet<string> {\n return new Set(\n operations.flatMap((op) =>\n typeof op.parent === \"string\" ? [op.parent] : [],\n ),\n );\n}\n\n/** The measured leaves of one response's span tree, per the flow's own spec. */\nexport function leafOperations<T extends LifecycleStageTiming>(\n operations: readonly T[],\n excluded: ReadonlySet<string> = new Set(),\n parents = parentOperations(operations),\n) {\n return operations.filter(\n (op): op is T & { durationMs: number } =>\n !excluded.has(op.operation) &&\n !parents.has(op.operation) &&\n typeof op.durationMs === \"number\" &&\n Number.isFinite(op.durationMs),\n );\n}\n\nexport function operationLeafDurations(\n operations: readonly LifecycleStageTiming[],\n excluded: ReadonlySet<string> = new Set(),\n) {\n const leaves = new Map<string, number>();\n for (const op of leafOperations(operations, excluded))\n leaves.set(op.operation, (leaves.get(op.operation) ?? 0) + op.durationMs);\n return leaves;\n}\n\nconst difference = (a: number | null, b: number | null) =>\n a === null || b === null ? null : a - b;\nconst positiveDifference = (a: number | null, b: number | null) => {\n const value = difference(a, b);\n return value === null ? null : Math.max(0, value);\n};\n\n/** Partition one input before aggregation: null is unavailable; a negative residual is overlapping evidence, never an instruction to publish zero. Callers retain their population grouping, medians and display labels. */\nexport function partitionLifecycleWalls(\n sample: LifecycleWallSample,\n flow: LifecycleWallFlow,\n) {\n const present = (value: number | null | undefined) =>\n typeof value === \"number\" && Number.isFinite(value) ? value : null;\n const finiteStages = (values?: Values | null) =>\n Object.fromEntries(\n Object.entries(values ?? {}).filter(([, ms]) => Number.isFinite(ms)),\n );\n const hops = sample.hops ?? {};\n const hop = (key: string) => present(hops[key]);\n const handler = hop(flow.workerTotalHop);\n const preHandler = hop(\"preHandler\");\n const hold = flow.settleHop ? (hop(flow.settleHop) ?? 0) : 0;\n const workerWallMs =\n handler === null\n ? null\n : Math.max(0, handler - hold) +\n (flow.addPreHandler ? (preHandler ?? 0) : 0);\n const roundTripMs = hop(\"orchestrator\");\n const orchServerMs = hop(\"orchestratorServer\");\n const orchWall = roundTripMs ?? orchServerMs;\n const terms = {\n edge: positiveDifference(sample.httpMs, workerWallMs),\n worker: positiveDifference(workerWallMs, orchWall ?? 0),\n transport: positiveDifference(roundTripMs, orchServerMs),\n orch: orchServerMs ?? roundTripMs,\n job: present(sample.jobMs),\n settle: present(sample.settleMs),\n dark: 0,\n };\n terms.dark =\n sample.wallMs -\n Object.values(terms).reduce<number>((sum, ms) => sum + (ms ?? 0), 0);\n const postReady = flow.postReadyOperations ?? new Set();\n const rawLeaves =\n sample.spanLeaves ??\n Object.fromEntries(operationLeafDurations(sample.spanOps ?? []));\n const spanLeaves = Object.fromEntries(\n Object.entries(rawLeaves).filter(\n ([name, ms]) =>\n name !== flow.totalOperation &&\n !postReady.has(name) &&\n Number.isFinite(ms),\n ),\n );\n // Exclude nested walls, transport and middleware outside the handler's total.\n const workerStages = Object.fromEntries(\n Object.entries(hops).filter(\n ([name]) =>\n Number.isFinite(hops[name]) &&\n !SHAPE_HOPS.has(name) &&\n name !== flow.settleHop &&\n !name.startsWith(\"orch.\") &&\n !name.startsWith(\"mw.\"),\n ),\n );\n const orchTree = stageTree(finiteStages(sample.orchStages));\n const jobTree = stageTree(finiteStages(sample.jobPhases));\n const spanSum = Object.values(spanLeaves).reduce((sum, ms) => sum + ms, 0);\n const workerNamed =\n (flow.addPreHandler ? (preHandler ?? 0) : 0) +\n (flow.workerNamedHops\n ? flow.workerNamedHops.reduce((sum, key) => sum + (hop(key) ?? 0), 0)\n : stageTree(workerStages).topLevelMs);\n const workerUnattributedMs = difference(terms.worker, workerNamed);\n const orchNamed = orchTree.topLevel.length\n ? orchTree.topLevelMs\n : spanSum > 0\n ? spanSum\n : 0;\n const orchUnattributedMs = difference(terms.orch, orchNamed);\n const jobUnattributedMs = difference(terms.job, jobTree.topLevelMs);\n const unnamedMs =\n Math.max(0, workerUnattributedMs ?? terms.worker ?? 0) +\n Math.max(0, orchUnattributedMs ?? terms.orch ?? 0) +\n Math.max(0, jobUnattributedMs ?? terms.job ?? 0) +\n Math.max(0, terms.dark);\n const measuredTotal = (sample.spanOps ?? []).find(\n (op) => op.operation === flow.totalOperation,\n )?.durationMs;\n const spanTotalMs = present(sample.spanTotalMs ?? measuredTotal);\n const readySum = sample.spanAccountedMs ?? spanSum;\n const readyTerm = spanTotalMs ?? readySum;\n const orchTerm = roundTripMs ?? orchServerMs ?? readyTerm;\n let clampedMs = 0;\n const diff = (a: number | null, b: number | null) => {\n const delta = difference(a, b);\n if (delta === null) return null;\n clampedMs += Math.max(0, -delta);\n return Math.max(0, delta);\n };\n const transportMs = diff(roundTripMs, orchServerMs);\n const afterSpanMs = diff(orchServerMs, spanTotalMs);\n const pathSum = workerNamed + orchTerm;\n const outerMs =\n workerWallMs === null\n ? diff(\n sample.wallMs - readyTerm,\n workerNamed + (transportMs ?? 0) + (afterSpanMs ?? 0),\n )\n : diff(sample.wallMs, workerWallMs);\n const window = {\n transportMs,\n afterSpanMs,\n outerMs,\n workerUnattributedMs: positiveDifference(workerWallMs, pathSum),\n workerOwnMs: positiveDifference(workerWallMs, orchTerm),\n gaps: {\n overlapMs: positiveDifference(readySum, spanTotalMs) ?? 0,\n underTileMs: positiveDifference(spanTotalMs, readySum) ?? 0,\n workerOverlapMs: positiveDifference(pathSum, workerWallMs) ?? 0,\n unrowedMs:\n workerWallMs === null\n ? 0\n : Math.max(\n 0,\n orchTerm - readyTerm - (transportMs ?? 0) - (afterSpanMs ?? 0),\n ),\n clampedMs,\n },\n };\n return {\n wallMs: sample.wallMs,\n httpMs: sample.httpMs,\n workerWallMs,\n roundTripMs,\n orchServerMs,\n orchIncludesTransport: orchServerMs === null && roundTripMs !== null,\n workerIncludesTransport: roundTripMs === null && orchServerMs !== null,\n terms,\n workerUnattributedMs,\n orchUnattributedMs,\n jobUnattributedMs,\n unnamedMs,\n unnamedShare: sample.wallMs > 0 ? unnamedMs / sample.wallMs : 0,\n overcountMs: Math.max(0, -terms.dark),\n spanLeaves,\n workerStages,\n orchTree,\n jobTree,\n spanTotalMs,\n window,\n };\n}\n"],"mappings":"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"}
|
package/dist/server-timing.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as LifecycleWallSample, d as partitionLifecycleWalls, i as LifecycleWallFlow } from "./lifecycle-wall-
|
|
1
|
+
import { a as LifecycleWallSample, d as partitionLifecycleWalls, i as LifecycleWallFlow, m as unattributedStages } from "./lifecycle-wall-BL6-gCBp.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/create-wall.d.ts
|
|
4
4
|
/** Exclusive create-request wall phases; nested service spans are a separate view. */
|
|
@@ -8,10 +8,9 @@ type CreateWallPhases = Record<CreateWallPhase, number>;
|
|
|
8
8
|
interface CreateWallMeasurement {
|
|
9
9
|
phases: CreateWallPhases;
|
|
10
10
|
totalMs: number;
|
|
11
|
-
|
|
11
|
+
offsets?: Record<string, number | null>;
|
|
12
12
|
bookkeepingPostCreateMs: number;
|
|
13
13
|
}
|
|
14
|
-
/** The original other-Worker + post-create budget, including auth/middleware. */
|
|
15
14
|
declare function createBookkeepingPostWall(phases: CreateWallPhases): number;
|
|
16
15
|
/** Sequential cursor; parallel spans stay separate. Invalid or incomplete walls stay unknown. */
|
|
17
16
|
declare function createWallTiming(startedAt: number): {
|
|
@@ -48,5 +47,5 @@ declare const FAILURE_FACT_NAMES: readonly string[];
|
|
|
48
47
|
declare const FAILURE_FACT_CODES: readonly string[];
|
|
49
48
|
declare const FAILURE_FACT_KINDS: readonly string[];
|
|
50
49
|
//#endregion
|
|
51
|
-
export { CREATE_WALL_PHASES, type CreateWallMeasurement, type CreateWallPhase, type CreateWallPhases, FAILURE_FACT_CODES, FAILURE_FACT_KINDS, FAILURE_FACT_NAMES, HTTP_PHASE_COVERAGE_FIELDS, HTTP_REQUEST_PHASE_NAMES, type HttpRequestPhaseName, type LifecycleWallFlow, type LifecycleWallSample, PLATFORM_VERDICT_EVIDENCE_ORDERS, PLATFORM_VERDICT_REUSE_REASONS, PLATFORM_VERDICT_SCOPE_CLASSES, type PlatformVerdictDependencyMismatch, type PlatformVerdictReuseRejection, type ServerTimingEntry, createBookkeepingPostWall, createUpstreamHttpPhaseProjection, createWallTiming, parseServerTiming, parseServerTimingDurations, partitionLifecycleWalls, readCreateWallTiming };
|
|
50
|
+
export { CREATE_WALL_PHASES, type CreateWallMeasurement, type CreateWallPhase, type CreateWallPhases, FAILURE_FACT_CODES, FAILURE_FACT_KINDS, FAILURE_FACT_NAMES, HTTP_PHASE_COVERAGE_FIELDS, HTTP_REQUEST_PHASE_NAMES, type HttpRequestPhaseName, type LifecycleWallFlow, type LifecycleWallSample, PLATFORM_VERDICT_EVIDENCE_ORDERS, PLATFORM_VERDICT_REUSE_REASONS, PLATFORM_VERDICT_SCOPE_CLASSES, type PlatformVerdictDependencyMismatch, type PlatformVerdictReuseRejection, type ServerTimingEntry, createBookkeepingPostWall, createUpstreamHttpPhaseProjection, createWallTiming, parseServerTiming, parseServerTimingDurations, partitionLifecycleWalls, readCreateWallTiming, unattributedStages };
|
|
52
51
|
//# sourceMappingURL=server-timing.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-timing.d.mts","names":["ServerTimingEntry","name","dur","desc","parseServerTiming","header","parseServerTimingDurations","Record","PLATFORM_VERDICT_REUSE_REASONS","PlatformVerdictReuseRejection","HTTP_REQUEST_PHASE_NAMES","HttpRequestPhaseName","httpRequestPhaseFromTimingName","PLATFORM_VERDICT_SCOPE_CLASSES","PLATFORM_VERDICT_EVIDENCE_ORDERS","PlatformVerdictDependencyMismatch","scopeClass","evidenceOrder","createUpstreamHttpPhaseProjection","absorb","entries","HTTP_PHASE_COVERAGE_FIELDS","FAILURE_FACT_NAMES","FAILURE_FACT_CODES","FAILURE_FACT_KINDS"],"sources":["../src/create-wall.ts","../src/server-timing-parser.d.mts"],"mappings":";;;;cACa,kBAAA;AAAA,KAiBD,eAAA,WAA0B,kBAAA;AAAA,KAC1B,gBAAA,GAAmB,MAAA,CAAO,eAAA;AAAA,UACrB,qBAAA;EACf,MAAA,EAAQ,gBAAA;EACR,OAAA;
|
|
1
|
+
{"version":3,"file":"server-timing.d.mts","names":["ServerTimingEntry","name","dur","desc","parseServerTiming","header","parseServerTimingDurations","Record","PLATFORM_VERDICT_REUSE_REASONS","PlatformVerdictReuseRejection","HTTP_REQUEST_PHASE_NAMES","HttpRequestPhaseName","httpRequestPhaseFromTimingName","PLATFORM_VERDICT_SCOPE_CLASSES","PLATFORM_VERDICT_EVIDENCE_ORDERS","PlatformVerdictDependencyMismatch","scopeClass","evidenceOrder","createUpstreamHttpPhaseProjection","absorb","entries","HTTP_PHASE_COVERAGE_FIELDS","FAILURE_FACT_NAMES","FAILURE_FACT_CODES","FAILURE_FACT_KINDS"],"sources":["../src/create-wall.ts","../src/server-timing-parser.d.mts"],"mappings":";;;;cACa,kBAAA;AAAA,KAiBD,eAAA,WAA0B,kBAAA;AAAA,KAC1B,gBAAA,GAAmB,MAAA,CAAO,eAAA;AAAA,UACrB,qBAAA;EACf,MAAA,EAAQ,gBAAA;EACR,OAAA;EACA,OAAA,GAAU,MAAA;EACV,uBAAA;AAAA;AAAA,iBAUc,yBAAA,CAA0B,MAAA,EAAQ,gBAAA;;iBAUlC,gBAAA,CAAiB,SAAA;cAajB,eAAA,EAAe,EAAA;6BAYP,WAAA,WAEjB,qBAAA;AAAA;;iBAsCS,oBAAA,CACd,MAAA,EAAQ,QAAA,CAAS,MAAA,oBAChB,qBAAA;;;UC/GcA,iBAAAA;EACfC,IAAAA;EACAC,GAAAA;EACAC,IAAAA;AAAAA;AAAAA,iBAGcC,iBAAAA,CACdC,MAAAA,8BACCL,iBAAAA;AAAAA,iBAEaM,0BAAAA,CACdD,MAAAA,8BACCE,MAAAA;AAAAA,cAEUC,8BAAAA;AAAAA,KA4BDC,6BAAAA,WACFD,8BAAAA;AAAAA,cAEGE,wBAAAA;AAAAA,KAkCDC,oBAAAA,WAA+BD,wBAAAA;AAAAA,cAI9BG,8BAAAA;AAAAA,cAQAC,gCAAAA;AAAAA,KAMDC,iCAAAA;EACVC,UAAAA,UAAoBH,8BAAAA;EACpBI,aAAAA,UAAuBH,gCAAAA;AAAAA;AAAAA,iBAGTI,iCAAAA,CAAAA;EACdC,MAAAA,CAAOd,MAAAA;EACPe,OAAAA;AAAAA;AAAAA,cAGWC,0BAAAA;AAAAA,cAQAC,kBAAAA;AAAAA,cACAC,kBAAAA;AAAAA,cACAC,kBAAAA"}
|
package/dist/server-timing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as partitionLifecycleWalls } from "./lifecycle-wall-
|
|
1
|
+
import { c as partitionLifecycleWalls, d as unattributedStages } from "./lifecycle-wall-CVuGfuSq.mjs";
|
|
2
2
|
//#region src/create-wall.ts
|
|
3
3
|
/** Exclusive create-request wall phases; nested service spans are a separate view. */
|
|
4
4
|
const CREATE_WALL_PHASES = [
|
|
@@ -18,7 +18,6 @@ const CREATE_WALL_PHASES = [
|
|
|
18
18
|
"response"
|
|
19
19
|
];
|
|
20
20
|
const REQUIRED_PHASES = CREATE_WALL_PHASES.filter((phase) => phase !== "middleware" && phase !== "leaseSelection" && phase !== "tenantCoordination");
|
|
21
|
-
/** The original other-Worker + post-create budget, including auth/middleware. */
|
|
22
21
|
function createBookkeepingPostWall(phases) {
|
|
23
22
|
return CREATE_WALL_PHASES.reduce((sum, phase) => sum + (phase === "preflight" || phase === "orchestrator" ? 0 : phases[phase]), 0);
|
|
24
23
|
}
|
|
@@ -28,6 +27,7 @@ function createWallTiming(startedAt) {
|
|
|
28
27
|
const visited = new Set(["identity"]);
|
|
29
28
|
let current = "identity";
|
|
30
29
|
let cursor = startedAt;
|
|
30
|
+
const starts = { identity: startedAt };
|
|
31
31
|
let valid = Number.isFinite(startedAt);
|
|
32
32
|
let finished = false;
|
|
33
33
|
return {
|
|
@@ -38,6 +38,7 @@ function createWallTiming(startedAt) {
|
|
|
38
38
|
}
|
|
39
39
|
phases[current] += at - cursor;
|
|
40
40
|
cursor = at;
|
|
41
|
+
if (current !== name) starts[name] = visited.has(name) ? null : at;
|
|
41
42
|
current = name;
|
|
42
43
|
visited.add(name);
|
|
43
44
|
},
|
|
@@ -54,6 +55,7 @@ function createWallTiming(startedAt) {
|
|
|
54
55
|
return {
|
|
55
56
|
phases: { ...phases },
|
|
56
57
|
totalMs,
|
|
58
|
+
offsets: Object.fromEntries([["createWall.total", 0], ...CREATE_WALL_PHASES.map((phase) => [`createWall.${phase}`, starts[phase] === null ? null : (starts[phase] ?? receivedAt) - receivedAt])]),
|
|
57
59
|
bookkeepingPostCreateMs: createBookkeepingPostWall(phases)
|
|
58
60
|
};
|
|
59
61
|
}
|
|
@@ -307,6 +309,6 @@ function createUpstreamHttpPhaseProjection() {
|
|
|
307
309
|
};
|
|
308
310
|
}
|
|
309
311
|
//#endregion
|
|
310
|
-
export { CREATE_WALL_PHASES, FAILURE_FACT_CODES, FAILURE_FACT_KINDS, FAILURE_FACT_NAMES, HTTP_PHASE_COVERAGE_FIELDS, HTTP_REQUEST_PHASE_NAMES, PLATFORM_VERDICT_EVIDENCE_ORDERS, PLATFORM_VERDICT_REUSE_REASONS, PLATFORM_VERDICT_SCOPE_CLASSES, createBookkeepingPostWall, createUpstreamHttpPhaseProjection, createWallTiming, parseServerTiming, parseServerTimingDurations, partitionLifecycleWalls, readCreateWallTiming };
|
|
312
|
+
export { CREATE_WALL_PHASES, FAILURE_FACT_CODES, FAILURE_FACT_KINDS, FAILURE_FACT_NAMES, HTTP_PHASE_COVERAGE_FIELDS, HTTP_REQUEST_PHASE_NAMES, PLATFORM_VERDICT_EVIDENCE_ORDERS, PLATFORM_VERDICT_REUSE_REASONS, PLATFORM_VERDICT_SCOPE_CLASSES, createBookkeepingPostWall, createUpstreamHttpPhaseProjection, createWallTiming, parseServerTiming, parseServerTimingDurations, partitionLifecycleWalls, readCreateWallTiming, unattributedStages };
|
|
311
313
|
|
|
312
314
|
//# sourceMappingURL=server-timing.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-timing.mjs","names":[],"sources":["../src/create-wall.ts","../src/server-timing-parser.mjs"],"sourcesContent":["/** Exclusive create-request wall phases; nested service spans are a separate view. */\nexport const CREATE_WALL_PHASES = [\n \"middleware\",\n \"identity\",\n \"preflight\",\n \"tenantCoordination\",\n \"configuration\",\n \"leaseSelection\",\n \"credentialJournal\",\n \"quotaReservation\",\n \"orchestrator\",\n \"provisionResponse\",\n \"responseBody\",\n \"credentialAllocation\",\n \"postCreate\",\n \"response\",\n] as const;\n\nexport type CreateWallPhase = (typeof CREATE_WALL_PHASES)[number];\nexport type CreateWallPhases = Record<CreateWallPhase, number>;\nexport interface CreateWallMeasurement {\n phases: CreateWallPhases;\n totalMs: number;\n /** Includes middleware/auth, preserving the original bookkeeping + post budget. */\n bookkeepingPostCreateMs: number;\n}\n\nconst REQUIRED_PHASES = CREATE_WALL_PHASES.filter(\n (phase) =>\n phase !== \"middleware\" &&\n phase !== \"leaseSelection\" &&\n phase !== \"tenantCoordination\",\n);\n\n/** The original other-Worker + post-create budget, including auth/middleware. */\nexport function createBookkeepingPostWall(phases: CreateWallPhases): number {\n return CREATE_WALL_PHASES.reduce(\n (sum, phase) =>\n sum +\n (phase === \"preflight\" || phase === \"orchestrator\" ? 0 : phases[phase]),\n 0,\n );\n}\n\n/** Sequential cursor; parallel spans stay separate. Invalid or incomplete walls stay unknown. */\nexport function createWallTiming(startedAt: number) {\n const phases = Object.fromEntries(\n CREATE_WALL_PHASES.map((phase) => [phase, 0]),\n ) as CreateWallPhases;\n const visited = new Set<CreateWallPhase>([\"identity\"]);\n let current: CreateWallPhase = \"identity\";\n let cursor = startedAt;\n let valid = Number.isFinite(startedAt);\n let finished = false;\n return {\n phase(name: CreateWallPhase, at: number): void {\n if (finished || !Number.isFinite(at) || at < cursor) {\n valid = false;\n return;\n }\n phases[current] += at - cursor;\n cursor = at;\n current = name;\n visited.add(name);\n },\n finish(\n receivedAt: number,\n respondedAt: number,\n ): CreateWallMeasurement | null {\n if (\n finished ||\n !valid ||\n !Number.isFinite(receivedAt) ||\n !Number.isFinite(respondedAt) ||\n receivedAt > startedAt ||\n respondedAt < cursor ||\n REQUIRED_PHASES.some((phase) => !visited.has(phase))\n ) {\n finished = true;\n return null;\n }\n finished = true;\n phases[current] += respondedAt - cursor;\n phases.middleware = startedAt - receivedAt;\n const totalMs = respondedAt - receivedAt;\n if (Object.values(phases).reduce((sum, ms) => sum + ms, 0) !== totalMs)\n return null;\n return {\n phases: { ...phases },\n totalMs,\n bookkeepingPostCreateMs: createBookkeepingPostWall(phases),\n };\n },\n };\n}\n\n/** Read the already-parsed header. Historical/incomplete/overlapping rows stay unknown. */\nexport function readCreateWallTiming(\n stages: Readonly<Record<string, number>>,\n): CreateWallMeasurement | null {\n const totalMs = stages[\"createWall.total\"];\n if (\n totalMs === undefined ||\n !Number.isFinite(totalMs) ||\n totalMs < 0 ||\n totalMs !== stages.outerWall\n )\n return null;\n const phases = {} as CreateWallPhases;\n for (const phase of CREATE_WALL_PHASES) {\n const value = stages[`createWall.${phase}`];\n if (value === undefined || !Number.isFinite(value) || value < 0)\n return null;\n phases[phase] = value;\n }\n if (Object.values(phases).reduce((sum, ms) => sum + ms, 0) !== totalMs)\n return null;\n return {\n phases,\n totalMs,\n bookkeepingPostCreateMs: createBookkeepingPostWall(phases),\n };\n}\n","// HTTP quoted strings can contain both separators and escaped quotes.\nfunction splitHeader(value, separator) {\n const parts = [];\n let start = 0;\n let quoted = false;\n for (let i = 0; i < value.length; i++) {\n if (quoted && value[i] === \"\\\\\") i++;\n else if (value[i] === '\"') quoted = !quoted;\n else if (!quoted && value[i] === separator) {\n parts.push(value.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(value.slice(start));\n return parts;\n}\n\n/** Missing or malformed durations remain unmeasured, never zero. */\nexport function parseServerTiming(header) {\n if (!header) return [];\n const entries = [];\n for (const metric of splitHeader(header, \",\")) {\n const [rawName, ...params] = splitHeader(metric, \";\");\n const name = rawName.trim();\n if (!/^[!#$%&'*+.^_`|~\\w-]+$/.test(name)) continue;\n const entry = { name };\n const seen = new Set();\n for (const param of params) {\n const eq = param.indexOf(\"=\");\n const key = (eq < 0 ? param : param.slice(0, eq)).trim().toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n if (eq < 0) continue;\n let value = param.slice(eq + 1).trim();\n if (value.startsWith('\"')) {\n if (!/^\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"$/.test(value)) continue;\n value = value.slice(1, -1).replace(/\\\\([\\s\\S])/g, \"$1\");\n }\n if (key === \"desc\") entry.desc = value;\n else if (\n key === \"dur\" &&\n /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[+-]?\\d+)?$/i.test(value)\n ) {\n const duration = Number(value);\n if (Number.isFinite(duration)) entry.dur = duration;\n }\n }\n entries.push(entry);\n }\n return entries;\n}\n\n/** A stage ledger retains only duration-bearing entries; later metrics win. */\nexport function parseServerTimingDurations(header) {\n return Object.fromEntries(\n parseServerTiming(header)\n .filter((entry) => entry.dur !== undefined)\n .map(({ name, dur }) => [name, dur]),\n );\n}\n\n/** Closed wire observations; these names carry no credential or authority values. */\nexport const PLATFORM_VERDICT_REUSE_REASONS = Object.freeze([\n \"entry_changed\",\n \"refusal_observed\",\n \"current_compliance\",\n \"negative_age\",\n \"retention_elapsed\",\n \"key_expired\",\n \"feed_missing\",\n \"feed_stale\",\n \"feed_generation\",\n \"dependencies_empty\",\n \"dependency_revision\",\n \"dependency_floor\",\n \"grant_missing\",\n \"grant_unreadable\",\n \"grant_shape\",\n \"grant_negative_age\",\n \"grant_retention_elapsed\",\n \"shared_refusal_observed\",\n \"shared_refusal_unreadable\",\n \"shared_read_unavailable\",\n \"grant_invalid\",\n \"grant_validation\",\n \"verification_inflight\",\n \"feed_contradiction\",\n \"current_required\",\n \"lkg_retention_elapsed\",\n]);\n\n/** Closed request-phase wire vocabulary, shared by producer and safe consumers. */\nexport const HTTP_REQUEST_PHASE_NAMES = Object.freeze([\n \"external.provision\",\n \"benchmarks.records.load\",\n \"benchmarks.records.build\",\n \"benchmarks.records.page\",\n \"benchmarks.records.json\",\n \"host.records.ready\",\n \"host.records.scan\",\n \"host.records.read\",\n \"host.records.metadata\",\n \"host.records.project\",\n \"host.records.retry\",\n \"admission.placement\",\n \"observability.refresh.wait\",\n \"fleet.sidecars\",\n \"native-export.snapshot.wait\",\n \"native-export.collect.wait\",\n \"scorecard.fleet.wait\",\n \"scorecard.capacity.wait\",\n \"scorecard.coverage.wait\",\n \"scorecard.compose\",\n \"scorecard.json\",\n \"proxy.model_refresh\",\n \"proxy.hub.lock_wait\",\n \"proxy.hub.refresh\",\n \"proxy.hub.state\",\n \"proxy.hub.proof\",\n \"proxy.hub.delivery\",\n \"proxy.runtime_token\",\n \"snapshot.delete.lock\",\n \"snapshot.delete.credentials\",\n \"snapshot.delete.list\",\n \"snapshot.delete.generation\",\n]);\n\nexport function httpRequestPhaseFromTimingName(name) {\n const prefix = name.startsWith(\"orch.phase.\") ? \"orch.phase.\" : \"phase.\";\n if (!name.startsWith(prefix)) return undefined;\n const phase = name.slice(prefix.length);\n return HTTP_REQUEST_PHASE_NAMES.includes(phase) ? phase : undefined;\n}\n\nexport const PLATFORM_VERDICT_SCOPE_CLASSES = Object.freeze([\n \"key\",\n \"identity\",\n \"owner_user\",\n \"owner_team\",\n \"lineage\",\n \"other\",\n]);\nexport const PLATFORM_VERDICT_EVIDENCE_ORDERS = Object.freeze([\n \"feed_before_observation\",\n \"feed_at_observation\",\n \"feed_after_observation\",\n \"unknown\",\n]);\n\n/** Closed failure facts: thrown values can carry credentials or URLs, so only these names leave. */\nexport const FAILURE_FACT_NAMES = Object.freeze([\n \"Error\",\n \"TypeError\",\n \"AbortError\",\n \"TimeoutError\",\n \"RangeError\",\n \"Other\",\n]);\nexport const FAILURE_FACT_CODES = Object.freeze([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"ECONNABORTED\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n \"ENETUNREACH\",\n \"EHOSTUNREACH\",\n \"ENETDOWN\",\n \"EADDRNOTAVAIL\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n \"UND_ERR_HEADERS_TIMEOUT\",\n \"UND_ERR_BODY_TIMEOUT\",\n \"UND_ERR_SOCKET\",\n \"UND_ERR_ABORTED\",\n]);\nexport const FAILURE_FACT_KINDS = Object.freeze([\n \"request-context\",\n \"connection-lost\",\n \"fetch-failed\",\n]);\n\n/** Bounded, closed-schema origin phase projection for the two Worker ledgers.\n * Duplicate observations remain separate; different origins/attempts cannot be summed.\n */\nexport const HTTP_PHASE_COVERAGE_FIELDS = Object.freeze([\n \"stored\",\n \"emitted\",\n \"omitted\",\n \"invalid\",\n \"collisions\",\n \"headerDropped\",\n]);\n\nexport function createUpstreamHttpPhaseProjection() {\n const entries = [];\n let bytes = 0;\n let dropped = 0;\n let rejectedInputs = 0;\n const fields = HTTP_PHASE_COVERAGE_FIELDS;\n const byteLength = (value) => new TextEncoder().encode(value).length;\n const keep = (entry) => {\n // Reserve a bounded forwarding-coverage entry inside this component's 4 KiB.\n const size = byteLength(entry) + 2;\n if (entries.length >= 31 || bytes + size > 3900) {\n dropped++;\n return;\n }\n entries.push(entry);\n bytes += size;\n };\n return {\n absorb(header) {\n if (header == null) return;\n if (\n typeof header !== \"string\" ||\n header.length > 4096 ||\n byteLength(header) > 4096\n ) {\n rejectedInputs++;\n return;\n }\n for (const entry of parseServerTiming(header)) {\n // Only direct origin names enter this fold; never prefix orch. twice.\n if (entry.name === \"phase.coverage\") {\n const counts = {};\n const parts = (entry.desc ?? \"\").split(\",\");\n if (parts.length !== fields.length) {\n dropped++;\n continue;\n }\n for (const part of parts) {\n const [key, value, ...extra] = part.split(\"=\");\n if (\n extra.length ||\n !fields.includes(key) ||\n Object.hasOwn(counts, key) ||\n !/^(?:0|[1-9]\\d*)$/.test(value ?? \"\") ||\n !Number.isSafeInteger(Number(value))\n )\n break;\n counts[key] = Number(value);\n }\n if (Object.keys(counts).length !== fields.length) {\n dropped++;\n continue;\n }\n keep(\n `orch.phase.coverage;desc=\"${fields.map((key) => `${key}=${counts[key]}`).join(\",\")}\"`,\n );\n } else if (entry.name.startsWith(\"phase.\")) {\n if (\n !httpRequestPhaseFromTimingName(entry.name) ||\n !Number.isFinite(entry.dur) ||\n entry.dur < 0 ||\n !/^outcome=(?:completed|error)$/.test(entry.desc ?? \"\")\n ) {\n dropped++;\n continue;\n }\n keep(`orch.${entry.name};dur=${entry.dur};desc=\"${entry.desc}\"`);\n }\n }\n },\n entries() {\n return [\n ...entries,\n ...(dropped || rejectedInputs\n ? [\n `orch.phase.forwarding;desc=\"dropped=${dropped},rejectedInputs=${rejectedInputs}\"`,\n ]\n : []),\n ];\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server-timing.mjs","names":[],"sources":["../src/create-wall.ts","../src/server-timing-parser.mjs"],"sourcesContent":["/** Exclusive create-request wall phases; nested service spans are a separate view. */\nexport const CREATE_WALL_PHASES = [\n \"middleware\",\n \"identity\",\n \"preflight\",\n \"tenantCoordination\",\n \"configuration\",\n \"leaseSelection\",\n \"credentialJournal\",\n \"quotaReservation\",\n \"orchestrator\",\n \"provisionResponse\",\n \"responseBody\",\n \"credentialAllocation\",\n \"postCreate\",\n \"response\",\n] as const;\n\nexport type CreateWallPhase = (typeof CREATE_WALL_PHASES)[number];\nexport type CreateWallPhases = Record<CreateWallPhase, number>;\nexport interface CreateWallMeasurement {\n phases: CreateWallPhases;\n totalMs: number;\n offsets?: Record<string, number | null>;\n bookkeepingPostCreateMs: number;\n}\n\nconst REQUIRED_PHASES = CREATE_WALL_PHASES.filter(\n (phase) =>\n phase !== \"middleware\" &&\n phase !== \"leaseSelection\" &&\n phase !== \"tenantCoordination\",\n);\n\nexport function createBookkeepingPostWall(phases: CreateWallPhases): number {\n return CREATE_WALL_PHASES.reduce(\n (sum, phase) =>\n sum +\n (phase === \"preflight\" || phase === \"orchestrator\" ? 0 : phases[phase]),\n 0,\n );\n}\n\n/** Sequential cursor; parallel spans stay separate. Invalid or incomplete walls stay unknown. */\nexport function createWallTiming(startedAt: number) {\n const phases = Object.fromEntries(\n CREATE_WALL_PHASES.map((phase) => [phase, 0]),\n ) as CreateWallPhases;\n const visited = new Set<CreateWallPhase>([\"identity\"]);\n let current: CreateWallPhase = \"identity\";\n let cursor = startedAt;\n const starts: Partial<Record<CreateWallPhase, number | null>> = {\n identity: startedAt,\n };\n let valid = Number.isFinite(startedAt);\n let finished = false;\n return {\n phase(name: CreateWallPhase, at: number): void {\n if (finished || !Number.isFinite(at) || at < cursor) {\n valid = false;\n return;\n }\n phases[current] += at - cursor;\n cursor = at;\n if (current !== name) starts[name] = visited.has(name) ? null : at;\n current = name;\n visited.add(name);\n },\n finish(\n receivedAt: number,\n respondedAt: number,\n ): CreateWallMeasurement | null {\n if (\n finished ||\n !valid ||\n !Number.isFinite(receivedAt) ||\n !Number.isFinite(respondedAt) ||\n receivedAt > startedAt ||\n respondedAt < cursor ||\n REQUIRED_PHASES.some((phase) => !visited.has(phase))\n ) {\n finished = true;\n return null;\n }\n finished = true;\n phases[current] += respondedAt - cursor;\n phases.middleware = startedAt - receivedAt;\n const totalMs = respondedAt - receivedAt;\n if (Object.values(phases).reduce((sum, ms) => sum + ms, 0) !== totalMs)\n return null;\n return {\n phases: { ...phases },\n totalMs,\n offsets: Object.fromEntries([\n [\"createWall.total\", 0],\n ...CREATE_WALL_PHASES.map((phase) => [\n `createWall.${phase}`,\n starts[phase] === null\n ? null\n : (starts[phase] ?? receivedAt) - receivedAt,\n ]),\n ]),\n bookkeepingPostCreateMs: createBookkeepingPostWall(phases),\n };\n },\n };\n}\n\n/** Read the already-parsed header. Historical/incomplete/overlapping rows stay unknown. */\nexport function readCreateWallTiming(\n stages: Readonly<Record<string, number>>,\n): CreateWallMeasurement | null {\n const totalMs = stages[\"createWall.total\"];\n if (\n totalMs === undefined ||\n !Number.isFinite(totalMs) ||\n totalMs < 0 ||\n totalMs !== stages.outerWall\n )\n return null;\n const phases = {} as CreateWallPhases;\n for (const phase of CREATE_WALL_PHASES) {\n const value = stages[`createWall.${phase}`];\n if (value === undefined || !Number.isFinite(value) || value < 0)\n return null;\n phases[phase] = value;\n }\n if (Object.values(phases).reduce((sum, ms) => sum + ms, 0) !== totalMs)\n return null;\n return {\n phases,\n totalMs,\n bookkeepingPostCreateMs: createBookkeepingPostWall(phases),\n };\n}\n","// HTTP quoted strings can contain both separators and escaped quotes.\nfunction splitHeader(value, separator) {\n const parts = [];\n let start = 0;\n let quoted = false;\n for (let i = 0; i < value.length; i++) {\n if (quoted && value[i] === \"\\\\\") i++;\n else if (value[i] === '\"') quoted = !quoted;\n else if (!quoted && value[i] === separator) {\n parts.push(value.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(value.slice(start));\n return parts;\n}\n\n/** Missing or malformed durations remain unmeasured, never zero. */\nexport function parseServerTiming(header) {\n if (!header) return [];\n const entries = [];\n for (const metric of splitHeader(header, \",\")) {\n const [rawName, ...params] = splitHeader(metric, \";\");\n const name = rawName.trim();\n if (!/^[!#$%&'*+.^_`|~\\w-]+$/.test(name)) continue;\n const entry = { name };\n const seen = new Set();\n for (const param of params) {\n const eq = param.indexOf(\"=\");\n const key = (eq < 0 ? param : param.slice(0, eq)).trim().toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n if (eq < 0) continue;\n let value = param.slice(eq + 1).trim();\n if (value.startsWith('\"')) {\n if (!/^\"(?:[^\"\\\\]|\\\\[\\s\\S])*\"$/.test(value)) continue;\n value = value.slice(1, -1).replace(/\\\\([\\s\\S])/g, \"$1\");\n }\n if (key === \"desc\") entry.desc = value;\n else if (\n key === \"dur\" &&\n /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[+-]?\\d+)?$/i.test(value)\n ) {\n const duration = Number(value);\n if (Number.isFinite(duration)) entry.dur = duration;\n }\n }\n entries.push(entry);\n }\n return entries;\n}\n\n/** A stage ledger retains only duration-bearing entries; later metrics win. */\nexport function parseServerTimingDurations(header) {\n return Object.fromEntries(\n parseServerTiming(header)\n .filter((entry) => entry.dur !== undefined)\n .map(({ name, dur }) => [name, dur]),\n );\n}\n\n/** Closed wire observations; these names carry no credential or authority values. */\nexport const PLATFORM_VERDICT_REUSE_REASONS = Object.freeze([\n \"entry_changed\",\n \"refusal_observed\",\n \"current_compliance\",\n \"negative_age\",\n \"retention_elapsed\",\n \"key_expired\",\n \"feed_missing\",\n \"feed_stale\",\n \"feed_generation\",\n \"dependencies_empty\",\n \"dependency_revision\",\n \"dependency_floor\",\n \"grant_missing\",\n \"grant_unreadable\",\n \"grant_shape\",\n \"grant_negative_age\",\n \"grant_retention_elapsed\",\n \"shared_refusal_observed\",\n \"shared_refusal_unreadable\",\n \"shared_read_unavailable\",\n \"grant_invalid\",\n \"grant_validation\",\n \"verification_inflight\",\n \"feed_contradiction\",\n \"current_required\",\n \"lkg_retention_elapsed\",\n]);\n\n/** Closed request-phase wire vocabulary, shared by producer and safe consumers. */\nexport const HTTP_REQUEST_PHASE_NAMES = Object.freeze([\n \"external.provision\",\n \"benchmarks.records.load\",\n \"benchmarks.records.build\",\n \"benchmarks.records.page\",\n \"benchmarks.records.json\",\n \"host.records.ready\",\n \"host.records.scan\",\n \"host.records.read\",\n \"host.records.metadata\",\n \"host.records.project\",\n \"host.records.retry\",\n \"admission.placement\",\n \"observability.refresh.wait\",\n \"fleet.sidecars\",\n \"native-export.snapshot.wait\",\n \"native-export.collect.wait\",\n \"scorecard.fleet.wait\",\n \"scorecard.capacity.wait\",\n \"scorecard.coverage.wait\",\n \"scorecard.compose\",\n \"scorecard.json\",\n \"proxy.model_refresh\",\n \"proxy.hub.lock_wait\",\n \"proxy.hub.refresh\",\n \"proxy.hub.state\",\n \"proxy.hub.proof\",\n \"proxy.hub.delivery\",\n \"proxy.runtime_token\",\n \"snapshot.delete.lock\",\n \"snapshot.delete.credentials\",\n \"snapshot.delete.list\",\n \"snapshot.delete.generation\",\n]);\n\nexport function httpRequestPhaseFromTimingName(name) {\n const prefix = name.startsWith(\"orch.phase.\") ? \"orch.phase.\" : \"phase.\";\n if (!name.startsWith(prefix)) return undefined;\n const phase = name.slice(prefix.length);\n return HTTP_REQUEST_PHASE_NAMES.includes(phase) ? phase : undefined;\n}\n\nexport const PLATFORM_VERDICT_SCOPE_CLASSES = Object.freeze([\n \"key\",\n \"identity\",\n \"owner_user\",\n \"owner_team\",\n \"lineage\",\n \"other\",\n]);\nexport const PLATFORM_VERDICT_EVIDENCE_ORDERS = Object.freeze([\n \"feed_before_observation\",\n \"feed_at_observation\",\n \"feed_after_observation\",\n \"unknown\",\n]);\n\n/** Closed failure facts: thrown values can carry credentials or URLs, so only these names leave. */\nexport const FAILURE_FACT_NAMES = Object.freeze([\n \"Error\",\n \"TypeError\",\n \"AbortError\",\n \"TimeoutError\",\n \"RangeError\",\n \"Other\",\n]);\nexport const FAILURE_FACT_CODES = Object.freeze([\n \"ECONNRESET\",\n \"ECONNREFUSED\",\n \"ECONNABORTED\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n \"ENOTFOUND\",\n \"EAI_AGAIN\",\n \"ENETUNREACH\",\n \"EHOSTUNREACH\",\n \"ENETDOWN\",\n \"EADDRNOTAVAIL\",\n \"UND_ERR_CONNECT_TIMEOUT\",\n \"UND_ERR_HEADERS_TIMEOUT\",\n \"UND_ERR_BODY_TIMEOUT\",\n \"UND_ERR_SOCKET\",\n \"UND_ERR_ABORTED\",\n]);\nexport const FAILURE_FACT_KINDS = Object.freeze([\n \"request-context\",\n \"connection-lost\",\n \"fetch-failed\",\n]);\n\n/** Bounded, closed-schema origin phase projection for the two Worker ledgers.\n * Duplicate observations remain separate; different origins/attempts cannot be summed.\n */\nexport const HTTP_PHASE_COVERAGE_FIELDS = Object.freeze([\n \"stored\",\n \"emitted\",\n \"omitted\",\n \"invalid\",\n \"collisions\",\n \"headerDropped\",\n]);\n\nexport function createUpstreamHttpPhaseProjection() {\n const entries = [];\n let bytes = 0;\n let dropped = 0;\n let rejectedInputs = 0;\n const fields = HTTP_PHASE_COVERAGE_FIELDS;\n const byteLength = (value) => new TextEncoder().encode(value).length;\n const keep = (entry) => {\n // Reserve a bounded forwarding-coverage entry inside this component's 4 KiB.\n const size = byteLength(entry) + 2;\n if (entries.length >= 31 || bytes + size > 3900) {\n dropped++;\n return;\n }\n entries.push(entry);\n bytes += size;\n };\n return {\n absorb(header) {\n if (header == null) return;\n if (\n typeof header !== \"string\" ||\n header.length > 4096 ||\n byteLength(header) > 4096\n ) {\n rejectedInputs++;\n return;\n }\n for (const entry of parseServerTiming(header)) {\n // Only direct origin names enter this fold; never prefix orch. twice.\n if (entry.name === \"phase.coverage\") {\n const counts = {};\n const parts = (entry.desc ?? \"\").split(\",\");\n if (parts.length !== fields.length) {\n dropped++;\n continue;\n }\n for (const part of parts) {\n const [key, value, ...extra] = part.split(\"=\");\n if (\n extra.length ||\n !fields.includes(key) ||\n Object.hasOwn(counts, key) ||\n !/^(?:0|[1-9]\\d*)$/.test(value ?? \"\") ||\n !Number.isSafeInteger(Number(value))\n )\n break;\n counts[key] = Number(value);\n }\n if (Object.keys(counts).length !== fields.length) {\n dropped++;\n continue;\n }\n keep(\n `orch.phase.coverage;desc=\"${fields.map((key) => `${key}=${counts[key]}`).join(\",\")}\"`,\n );\n } else if (entry.name.startsWith(\"phase.\")) {\n if (\n !httpRequestPhaseFromTimingName(entry.name) ||\n !Number.isFinite(entry.dur) ||\n entry.dur < 0 ||\n !/^outcome=(?:completed|error)$/.test(entry.desc ?? \"\")\n ) {\n dropped++;\n continue;\n }\n keep(`orch.${entry.name};dur=${entry.dur};desc=\"${entry.desc}\"`);\n }\n }\n },\n entries() {\n return [\n ...entries,\n ...(dropped || rejectedInputs\n ? [\n `orch.phase.forwarding;desc=\"dropped=${dropped},rejectedInputs=${rejectedInputs}\"`,\n ]\n : []),\n ];\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/stage-span.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as leafOperations, f as spanTreeStages, l as operationLeafDurations, n as DELETE_ACCOUNTING_SPEC, o as RESUME_ACCOUNTING_SPEC, p as stageTree, r as FlowAccountingSpec, s as STOP_ACCOUNTING_SPEC, t as CREATE_ACCOUNTING_SPEC, u as parentOperations } from "./lifecycle-wall-
|
|
1
|
+
import { c as leafOperations, f as spanTreeStages, l as operationLeafDurations, n as DELETE_ACCOUNTING_SPEC, o as RESUME_ACCOUNTING_SPEC, p as stageTree, r as FlowAccountingSpec, s as STOP_ACCOUNTING_SPEC, t as CREATE_ACCOUNTING_SPEC, u as parentOperations } from "./lifecycle-wall-BL6-gCBp.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/stage-span.d.ts
|
|
4
4
|
/**
|
package/dist/stage-span.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as leafOperations, i as STOP_ACCOUNTING_SPEC, l as spanTreeStages, n as DELETE_ACCOUNTING_SPEC, o as operationLeafDurations, r as RESUME_ACCOUNTING_SPEC, s as parentOperations, t as CREATE_ACCOUNTING_SPEC, u as stageTree } from "./lifecycle-wall-
|
|
1
|
+
import { a as leafOperations, i as STOP_ACCOUNTING_SPEC, l as spanTreeStages, n as DELETE_ACCOUNTING_SPEC, o as operationLeafDurations, r as RESUME_ACCOUNTING_SPEC, s as parentOperations, t as CREATE_ACCOUNTING_SPEC, u as stageTree } from "./lifecycle-wall-CVuGfuSq.mjs";
|
|
2
2
|
//#region src/stage-span.ts
|
|
3
3
|
/**
|
|
4
4
|
* One span shape for every lifecycle-op stage across every hop.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/sdk-telemetry",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"tangleRelease": {
|
|
73
|
-
"sourceSha": "
|
|
74
|
-
"mergedAt": "2026-11-
|
|
73
|
+
"sourceSha": "fda33c937983448c7d72a71ef7ac74f9565504a2",
|
|
74
|
+
"mergedAt": "2026-11-06T11:11:11-08:00"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"build": "tsdown",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-wall-BeaxDTJ8.mjs","names":[],"sources":["../src/lifecycle-wall.ts"],"sourcesContent":["/**\n * The `ready` span carries the end-to-end create wall (caller start → the end\n * of createSidecar). These operations run AFTER `ready` is stamped, so they sit\n * OUTSIDE the ready window and must never be summed into the leaf total or the\n * residual goes negative.\n */\nconst CREATE_POST_READY_OPERATIONS = new Set([\n \"orchestrator.container_lookup\",\n \"orchestrator.snapshot_restore_check\",\n \"orchestrator.provision_finalize\",\n]);\n\n/**\n * Per-flow shape of the accounting window. `totalOperation` is the span whose\n * wall the named leaves must tile; `postReadyOperations` run AFTER it is\n * stamped (excluded from the leaf sum); `prepUmbrella` is the optional\n * create-style split of an entry umbrella minus its measured leaf children. Absent\n * `prepUmbrella` ⇒ `prepUnaccountedMs` is always 0 and the whole dark falls\n * into `unaccountedMs` (the shape every non-create flow uses).\n */\nexport type FlowAccountingSpec = {\n totalOperation: string;\n postReadyOperations?: ReadonlySet<string>;\n prepUmbrella?: { operation: string };\n};\n\nexport const CREATE_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.ready\",\n postReadyOperations: CREATE_POST_READY_OPERATIONS,\n prepUmbrella: {\n operation: \"orchestrator.provision_prep\",\n },\n};\n\nexport const RESUME_ACCOUNTING_SPEC: FlowAccountingSpec = {\n // `orchestrator.ready` runs from the request to the sidecar's ready stamp;\n // these run after that stamp.\n totalOperation: \"orchestrator.ready\",\n postReadyOperations: new Set([\n \"orchestrator.connection_build\",\n \"orchestrator.metering_restart\",\n \"orchestrator.resume_commit\",\n ]),\n};\n\nexport const STOP_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.stop_complete\",\n};\n\nexport const DELETE_ACCOUNTING_SPEC: FlowAccountingSpec = {\n totalOperation: \"orchestrator.delete_complete\",\n};\n\nexport interface LifecycleStageTiming {\n operation: string;\n durationMs?: number;\n parent?: string | null;\n}\ntype Values = Readonly<Record<string, number>>;\nexport interface LifecycleWallSample {\n wallMs: number;\n httpMs: number;\n hops?: Values;\n spanOps?: readonly LifecycleStageTiming[];\n spanLeaves?: Values;\n spanTotalMs?: number | null;\n orchStages?: Values | null;\n jobPhases?: Values | null;\n jobMs?: number | null;\n settleMs?: number | null;\n spanAccountedMs?: number;\n}\nexport interface LifecycleWallFlow extends Partial<FlowAccountingSpec> {\n workerTotalHop: string;\n addPreHandler: boolean;\n settleHop?: string;\n workerNamedHops?: readonly string[];\n}\n\n/**\n * A flat `{name: ms}` ledger read as the tree its names describe.\n *\n * Every producer in this repo emits nested stages FLAT, with the containment\n * in the name: `capture.<hostPhase>` and `capture.restic_<phase>` inside\n * `capture` (snapshot-helpers.ts), `materialize.parentRead|precreate|\n * branchComplete|host.*|child.*|residual` inside `materialize` (branch.ts),\n * `delete.<hostPhase>` inside `delete` and `restore_workspace.<phase>` inside\n * `restore_workspace` (snapshots.ts). Summing every entry as a sibling counts\n * the children inside their parent a second time and reports a wall the\n * orchestrator never spent.\n *\n * So a dotted name is NEVER top-level. It attaches to the longest prefix that\n * exists as a stage; when no prefix exists — the restore job's `host.<phase>`,\n * which the queue records inside `restore_workspace` without naming it\n * (snapshot-job-queue.ts:394) — it is still excluded from the top-level sum\n * and reported as a child of the ledger at large. Excluding it can only leave\n * MORE time unnamed, never fabricate a reconciliation.\n */\nexport function stageTree(stages: Readonly<Record<string, number>>) {\n const present = new Set(Object.keys(stages));\n const parentOf = (name: string) => {\n let cut = name.lastIndexOf(\".\");\n while (cut > 0) {\n const candidate = name.slice(0, cut);\n if (present.has(candidate)) return candidate;\n cut = candidate.lastIndexOf(\".\");\n }\n return name.includes(\".\") ? \"\" : null;\n };\n const nodes = Object.entries(stages).map(([name, ms]) => ({\n name,\n ms,\n parent: parentOf(name),\n }));\n const topLevel = nodes.filter((node) => node.parent === null);\n return {\n nodes,\n topLevel,\n /** Children whose declared parent is not in the ledger; never summed. */\n orphans: nodes.filter((node) => node.parent === \"\"),\n topLevelMs: topLevel.reduce((sum, node) => sum + node.ms, 0),\n };\n}\n\n/**\n * A response's span tree as `<stage>.<path>` rows and each parent's wall minus\n * its children as `<parent>.unattributed` (0 when children overlap), residuals\n * first so a capped header keeps them. Unparented spans nest in the total span.\n */\nexport function spanTreeStages(\n stage: string,\n stageMs: Readonly<Record<string, number>>,\n operations: readonly (LifecycleStageTiming & { status?: string })[] = [],\n spec?: Partial<FlowAccountingSpec>,\n): Record<string, number> {\n const total = spec?.totalOperation ?? \"\";\n const byName = new Map(operations.map((op) => [op.operation, op]));\n const path = (op: LifecycleStageTiming, depth = 0): string => {\n const outside =\n op.operation === total || spec?.postReadyOperations?.has(op.operation);\n const parent = byName.get(op.parent ?? (outside ? \"\" : total));\n const name = op.operation.slice(op.operation.lastIndexOf(\".\") + 1);\n return `${parent && depth < 8 ? path(parent, depth + 1) : stage}.${name}`;\n };\n const rows: Record<string, number> = { [stage]: stageMs[stage] ?? 0 };\n for (const { durationMs: ms, status, ...op } of operations)\n if (status === \"completed\" && typeof ms === \"number\" && ms >= 0)\n rows[path(op)] = (rows[path(op)] ?? 0) + ms;\n const residuals: Record<string, number> = {};\n for (const [parent, ms] of Object.entries(rows)) {\n const kids = Object.keys(rows).filter(\n (name) =>\n name.startsWith(`${parent}.`) &&\n !name.slice(parent.length + 1).includes(\".\"),\n );\n if (kids.length)\n residuals[`${parent}.unattributed`] = Math.max(\n 0,\n kids.reduce((rest, kid) => rest - (rows[kid] ?? 0), ms),\n );\n }\n delete rows[stage];\n return { ...residuals, ...rows };\n}\n\n/**\n * Hops that describe the SHAPE of the request rather than a slice of it: the\n * three nested walls, the transport the walls imply, and the retry counter.\n * They are the terms of the summary line, so ranking them again as sub-stages\n * would print the same milliseconds twice under a second name. `preHandler`\n * joins them because it is the umbrella over the `mw.*` own-times, which ARE\n * ranked.\n */\nconst SHAPE_HOPS = new Set([\n \"preHandler\",\n \"total\",\n \"serverWall\",\n \"orchestrator\",\n \"orchestratorServer\",\n \"transportMarkup\",\n \"orchestratorRetries\",\n]);\n\n/** Parent operations contain their descendants and are never counted as leaves. */\nexport function parentOperations(\n operations: readonly LifecycleStageTiming[],\n): ReadonlySet<string> {\n return new Set(\n operations.flatMap((op) =>\n typeof op.parent === \"string\" ? [op.parent] : [],\n ),\n );\n}\n\n/**\n * The measured leaves of one response's span tree, per the flow's own spec.\n *\n * Identical rule to the orchestrator's `computeFlowAccountingResiduals`: drop\n * the total span (it is the window), drop the spans stamped after it closes,\n * and drop any span another span names as its parent (a parent re-measures its\n * children). What is left sums to the window minus its named residual.\n */\nexport function leafOperations<T extends LifecycleStageTiming>(\n operations: readonly T[],\n excluded: ReadonlySet<string> = new Set(),\n parents = parentOperations(operations),\n) {\n return operations.filter(\n (op): op is T & { durationMs: number } =>\n !excluded.has(op.operation) &&\n !parents.has(op.operation) &&\n typeof op.durationMs === \"number\" &&\n Number.isFinite(op.durationMs),\n );\n}\n\nexport function operationLeafDurations(\n operations: readonly LifecycleStageTiming[],\n excluded: ReadonlySet<string> = new Set(),\n) {\n const leaves = new Map<string, number>();\n for (const op of leafOperations(operations, excluded))\n leaves.set(op.operation, (leaves.get(op.operation) ?? 0) + op.durationMs);\n return leaves;\n}\n\nconst difference = (a: number | null, b: number | null) =>\n a === null || b === null ? null : a - b;\nconst positiveDifference = (a: number | null, b: number | null) => {\n const value = difference(a, b);\n return value === null ? null : Math.max(0, value);\n};\n\n/**\n * Partition one input before aggregation: null is unavailable; a negative\n * residual is overlapping evidence, never an instruction to publish zero.\n * Callers retain their population grouping, medians and display labels.\n */\nexport function partitionLifecycleWalls(\n sample: LifecycleWallSample,\n flow: LifecycleWallFlow,\n) {\n const present = (value: number | null | undefined) =>\n typeof value === \"number\" && Number.isFinite(value) ? value : null;\n const finiteStages = (values?: Values | null) =>\n Object.fromEntries(\n Object.entries(values ?? {}).filter(([, ms]) => Number.isFinite(ms)),\n );\n const hops = sample.hops ?? {};\n const hop = (key: string) => present(hops[key]);\n const handler = hop(flow.workerTotalHop);\n const preHandler = hop(\"preHandler\");\n const hold = flow.settleHop ? (hop(flow.settleHop) ?? 0) : 0;\n const workerWallMs =\n handler === null\n ? null\n : Math.max(0, handler - hold) +\n (flow.addPreHandler ? (preHandler ?? 0) : 0);\n const roundTripMs = hop(\"orchestrator\");\n const orchServerMs = hop(\"orchestratorServer\");\n const orchWall = roundTripMs ?? orchServerMs;\n const terms = {\n edge: positiveDifference(sample.httpMs, workerWallMs),\n worker: positiveDifference(workerWallMs, orchWall ?? 0),\n transport: positiveDifference(roundTripMs, orchServerMs),\n orch: orchServerMs ?? roundTripMs,\n job: present(sample.jobMs),\n settle: present(sample.settleMs),\n dark: 0,\n };\n terms.dark =\n sample.wallMs -\n Object.values(terms).reduce<number>((sum, ms) => sum + (ms ?? 0), 0);\n const postReady = flow.postReadyOperations ?? new Set();\n const rawLeaves =\n sample.spanLeaves ??\n Object.fromEntries(operationLeafDurations(sample.spanOps ?? []));\n const spanLeaves = Object.fromEntries(\n Object.entries(rawLeaves).filter(\n ([name, ms]) =>\n name !== flow.totalOperation &&\n !postReady.has(name) &&\n Number.isFinite(ms),\n ),\n );\n // Exclude nested walls, transport and middleware outside the handler's total.\n const workerStages = Object.fromEntries(\n Object.entries(hops).filter(\n ([name]) =>\n Number.isFinite(hops[name]) &&\n !SHAPE_HOPS.has(name) &&\n name !== flow.settleHop &&\n !name.startsWith(\"orch.\") &&\n !name.startsWith(\"mw.\"),\n ),\n );\n const orchTree = stageTree(finiteStages(sample.orchStages));\n const jobTree = stageTree(finiteStages(sample.jobPhases));\n const spanSum = Object.values(spanLeaves).reduce((sum, ms) => sum + ms, 0);\n const workerNamed =\n (flow.addPreHandler ? (preHandler ?? 0) : 0) +\n (flow.workerNamedHops\n ? flow.workerNamedHops.reduce((sum, key) => sum + (hop(key) ?? 0), 0)\n : stageTree(workerStages).topLevelMs);\n const workerUnattributedMs = difference(terms.worker, workerNamed);\n const orchNamed = orchTree.topLevel.length\n ? orchTree.topLevelMs\n : spanSum > 0\n ? spanSum\n : 0;\n const orchUnattributedMs = difference(terms.orch, orchNamed);\n const jobUnattributedMs = difference(terms.job, jobTree.topLevelMs);\n const unnamedMs =\n Math.max(0, workerUnattributedMs ?? terms.worker ?? 0) +\n Math.max(0, orchUnattributedMs ?? terms.orch ?? 0) +\n Math.max(0, jobUnattributedMs ?? terms.job ?? 0) +\n Math.max(0, terms.dark);\n const measuredTotal = (sample.spanOps ?? []).find(\n (op) => op.operation === flow.totalOperation,\n )?.durationMs;\n const spanTotalMs = present(sample.spanTotalMs ?? measuredTotal);\n const readySum = sample.spanAccountedMs ?? spanSum;\n const readyTerm = spanTotalMs ?? readySum;\n const orchTerm = roundTripMs ?? orchServerMs ?? readyTerm;\n let clampedMs = 0;\n const diff = (a: number | null, b: number | null) => {\n const delta = difference(a, b);\n if (delta === null) return null;\n clampedMs += Math.max(0, -delta);\n return Math.max(0, delta);\n };\n const transportMs = diff(roundTripMs, orchServerMs);\n const afterSpanMs = diff(orchServerMs, spanTotalMs);\n const pathSum = workerNamed + orchTerm;\n const outerMs =\n workerWallMs === null\n ? diff(\n sample.wallMs - readyTerm,\n workerNamed + (transportMs ?? 0) + (afterSpanMs ?? 0),\n )\n : diff(sample.wallMs, workerWallMs);\n const window = {\n transportMs,\n afterSpanMs,\n outerMs,\n workerUnattributedMs: positiveDifference(workerWallMs, pathSum),\n workerOwnMs: positiveDifference(workerWallMs, orchTerm),\n gaps: {\n overlapMs: positiveDifference(readySum, spanTotalMs) ?? 0,\n underTileMs: positiveDifference(spanTotalMs, readySum) ?? 0,\n workerOverlapMs: positiveDifference(pathSum, workerWallMs) ?? 0,\n unrowedMs:\n workerWallMs === null\n ? 0\n : Math.max(\n 0,\n orchTerm - readyTerm - (transportMs ?? 0) - (afterSpanMs ?? 0),\n ),\n clampedMs,\n },\n };\n return {\n wallMs: sample.wallMs,\n httpMs: sample.httpMs,\n workerWallMs,\n roundTripMs,\n orchServerMs,\n orchIncludesTransport: orchServerMs === null && roundTripMs !== null,\n workerIncludesTransport: roundTripMs === null && orchServerMs !== null,\n terms,\n workerUnattributedMs,\n orchUnattributedMs,\n jobUnattributedMs,\n unnamedMs,\n unnamedShare: sample.wallMs > 0 ? unnamedMs / sample.wallMs : 0,\n overcountMs: Math.max(0, -terms.dark),\n spanLeaves,\n workerStages,\n orchTree,\n jobTree,\n spanTotalMs,\n window,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-wall-BnN-KFBx.d.mts","names":[],"sources":["../src/lifecycle-wall.ts"],"mappings":";;AAoBA;;;;;;;KAAY,kBAAA;EACV,cAAA;EACA,mBAAA,GAAsB,WAAA;EACtB,YAAA;IAAiB,SAAA;EAAA;AAAA;AAAA,cAGN,sBAAA,EAAwB,kBAAA;AAAA,cAQxB,sBAAA,EAAwB,kBAAA;AAAA,cAWxB,oBAAA,EAAsB,kBAAA;AAAA,cAItB,sBAAA,EAAwB,kBAAA;AAAA,UAIpB,oBAAA;EACf,SAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAEG,MAAA,GAAS,QAAA,CAAS,MAAA;AAAA,UACN,mBAAA;EACf,MAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;EACP,OAAA,YAAmB,oBAAA;EACnB,UAAA,GAAa,MAAA;EACb,WAAA;EACA,UAAA,GAAa,MAAA;EACb,SAAA,GAAY,MAAA;EACZ,KAAA;EACA,QAAA;EACA,eAAA;AAAA;AAAA,UAEe,iBAAA,SAA0B,OAAA,CAAQ,kBAAA;EACjD,cAAA;EACA,aAAA;EACA,SAAA;EACA,eAAA;AAAA;;;AAjBF;;;;;;;;;;;;;;;;;iBAuCgB,SAAA,CAAU,MAAA,EAAQ,QAAA,CAAS,MAAA;;;;;;;;;;OA1B1B;;;;;;;;;;;;AA0BjB;iBA+BgB,cAAA,CACd,KAAA,UACA,OAAA,EAAS,QAAA,CAAS,MAAA,mBAClB,UAAA,aAAsB,oBAAA;EAAyB,MAAA;AAAA,MAC/C,IAAA,GAAO,OAAA,CAAQ,kBAAA,IACd,MAAA;;iBAkDa,gBAAA,CACd,UAAA,WAAqB,oBAAA,KACpB,WAAA;;;;;;;;;iBAgBa,cAAA,WAAyB,oBAAA,CAAA,CACvC,UAAA,WAAqB,CAAA,IACrB,QAAA,GAAU,WAAA,UACV,OAAA,GAAO,WAAA,YAA+B,CAAA;;;iBAWxB,sBAAA,CACd,UAAA,WAAqB,oBAAA,IACrB,QAAA,GAAU,WAAA,WAA+B,GAAA;;;;;AAzF3C;iBA6GgB,uBAAA,CACd,MAAA,EAAQ,mBAAA,EACR,IAAA,EAAM,iBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAnCgC;;;;;;;;;;;;;;;;;;SAaG"}
|