@tangle-network/sdk-telemetry 0.7.3 → 0.7.5
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-CXJaufPp.d.mts → lifecycle-wall-BnN-KFBx.d.mts} +10 -2
- package/dist/lifecycle-wall-BnN-KFBx.d.mts.map +1 -0
- package/dist/{lifecycle-wall-Co9iFDvN.mjs → lifecycle-wall-CZZAgPft.mjs} +34 -3
- package/dist/lifecycle-wall-CZZAgPft.mjs.map +1 -0
- package/dist/server-timing.d.mts +1 -1
- package/dist/server-timing.mjs +1 -1
- package/dist/stage-span.d.mts +9 -42
- package/dist/stage-span.d.mts.map +1 -1
- package/dist/stage-span.mjs +28 -87
- package/dist/stage-span.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/lifecycle-wall-CXJaufPp.d.mts.map +0 -1
- package/dist/lifecycle-wall-Co9iFDvN.mjs.map +0 -1
|
@@ -80,6 +80,14 @@ declare function stageTree(stages: Readonly<Record<string, number>>): {
|
|
|
80
80
|
}[];
|
|
81
81
|
topLevelMs: number;
|
|
82
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* A response's span tree as `<stage>.<path>` rows and each parent's wall minus
|
|
85
|
+
* its children as `<parent>.unattributed` (0 when children overlap), residuals
|
|
86
|
+
* first so a capped header keeps them. Unparented spans nest in the total span.
|
|
87
|
+
*/
|
|
88
|
+
declare function spanTreeStages(stage: string, stageMs: Readonly<Record<string, number>>, operations?: readonly (LifecycleStageTiming & {
|
|
89
|
+
status?: string;
|
|
90
|
+
})[], spec?: Partial<FlowAccountingSpec>): Record<string, number>;
|
|
83
91
|
/** Parent operations contain their descendants and are never counted as leaves. */
|
|
84
92
|
declare function parentOperations(operations: readonly LifecycleStageTiming[]): ReadonlySet<string>;
|
|
85
93
|
/**
|
|
@@ -181,5 +189,5 @@ declare function partitionLifecycleWalls(sample: LifecycleWallSample, flow: Life
|
|
|
181
189
|
};
|
|
182
190
|
};
|
|
183
191
|
//#endregion
|
|
184
|
-
export { LifecycleWallSample as a, leafOperations as c, partitionLifecycleWalls as d,
|
|
185
|
-
//# sourceMappingURL=lifecycle-wall-
|
|
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-BnN-KFBx.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -9,7 +9,11 @@ const CREATE_ACCOUNTING_SPEC = {
|
|
|
9
9
|
};
|
|
10
10
|
const RESUME_ACCOUNTING_SPEC = {
|
|
11
11
|
totalOperation: "orchestrator.ready",
|
|
12
|
-
postReadyOperations: new Set([
|
|
12
|
+
postReadyOperations: new Set([
|
|
13
|
+
"orchestrator.connection_build",
|
|
14
|
+
"orchestrator.metering_restart",
|
|
15
|
+
"orchestrator.resume_commit"
|
|
16
|
+
])
|
|
13
17
|
};
|
|
14
18
|
const STOP_ACCOUNTING_SPEC = { totalOperation: "orchestrator.stop_complete" };
|
|
15
19
|
const DELETE_ACCOUNTING_SPEC = { totalOperation: "orchestrator.delete_complete" };
|
|
@@ -58,6 +62,33 @@ function stageTree(stages) {
|
|
|
58
62
|
};
|
|
59
63
|
}
|
|
60
64
|
/**
|
|
65
|
+
* A response's span tree as `<stage>.<path>` rows and each parent's wall minus
|
|
66
|
+
* its children as `<parent>.unattributed` (0 when children overlap), residuals
|
|
67
|
+
* first so a capped header keeps them. Unparented spans nest in the total span.
|
|
68
|
+
*/
|
|
69
|
+
function spanTreeStages(stage, stageMs, operations = [], spec) {
|
|
70
|
+
const total = spec?.totalOperation ?? "";
|
|
71
|
+
const byName = new Map(operations.map((op) => [op.operation, op]));
|
|
72
|
+
const path = (op, depth = 0) => {
|
|
73
|
+
const outside = op.operation === total || spec?.postReadyOperations?.has(op.operation);
|
|
74
|
+
const parent = byName.get(op.parent ?? (outside ? "" : total));
|
|
75
|
+
const name = op.operation.slice(op.operation.lastIndexOf(".") + 1);
|
|
76
|
+
return `${parent && depth < 8 ? path(parent, depth + 1) : stage}.${name}`;
|
|
77
|
+
};
|
|
78
|
+
const rows = { [stage]: stageMs[stage] ?? 0 };
|
|
79
|
+
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
|
+
}
|
|
85
|
+
delete rows[stage];
|
|
86
|
+
return {
|
|
87
|
+
...residuals,
|
|
88
|
+
...rows
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
61
92
|
* Hops that describe the SHAPE of the request rather than a slice of it: the
|
|
62
93
|
* three nested walls, the transport the walls imply, and the retry counter.
|
|
63
94
|
* They are the terms of the summary line, so ranking them again as sub-stages
|
|
@@ -197,6 +228,6 @@ function partitionLifecycleWalls(sample, flow) {
|
|
|
197
228
|
};
|
|
198
229
|
}
|
|
199
230
|
//#endregion
|
|
200
|
-
export { leafOperations as a, partitionLifecycleWalls as c, STOP_ACCOUNTING_SPEC as i,
|
|
231
|
+
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 };
|
|
201
232
|
|
|
202
|
-
//# sourceMappingURL=lifecycle-wall-
|
|
233
|
+
//# sourceMappingURL=lifecycle-wall-CZZAgPft.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-wall-CZZAgPft.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) => (Number.isFinite(hops[key]) ? hops[key] : null);\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 /**\n * The Worker's own handler stages: its ledger minus the three nested walls,\n * the transport they imply and the middleware own-times, which are ranked\n * separately because they run OUTSIDE the handler's `total`.\n */\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":"AA0BA,MAAa,yBAA6C;CACxD,gBAAgB;CAChB,qBAAqB,IAtBkB,IAAI;EAC3C;EACA;EACA;EACD,CAkBsB;CACrB,cAAc,EACZ,WAAW,+BACZ;CACF;AAED,MAAa,yBAA6C;CAGxD,gBAAgB;CAChB,qBAAqB,IAAI,IAAI;EAC3B;EACA;EACA;EACD,CAAC;CACH;AAED,MAAa,uBAA2C,EACtD,gBAAgB,8BACjB;AAED,MAAa,yBAA6C,EACxD,gBAAgB,gCACjB;;;;;;;;;;;;;;;;;;;;AA+CD,SAAgB,UAAU,QAA0C;CAClE,MAAM,UAAU,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;CAC5C,MAAM,YAAY,SAAiB;EACjC,IAAI,MAAM,KAAK,YAAY,IAAI;AAC/B,SAAO,MAAM,GAAG;GACd,MAAM,YAAY,KAAK,MAAM,GAAG,IAAI;AACpC,OAAI,QAAQ,IAAI,UAAU,CAAE,QAAO;AACnC,SAAM,UAAU,YAAY,IAAI;;AAElC,SAAO,KAAK,SAAS,IAAI,GAAG,KAAK;;CAEnC,MAAM,QAAQ,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,MAAM,SAAS;EACxD;EACA;EACA,QAAQ,SAAS,KAAK;EACvB,EAAE;CACH,MAAM,WAAW,MAAM,QAAQ,SAAS,KAAK,WAAW,KAAK;AAC7D,QAAO;EACL;EACA;;EAEA,SAAS,MAAM,QAAQ,SAAS,KAAK,WAAW,GAAG;EACnD,YAAY,SAAS,QAAQ,KAAK,SAAS,MAAM,KAAK,IAAI,EAAE;EAC7D;;;;;;;AAQH,SAAgB,eACd,OACA,SACA,aAAsE,EAAE,EACxE,MACwB;CACxB,MAAM,QAAQ,MAAM,kBAAkB;CACtC,MAAM,SAAS,IAAI,IAAI,WAAW,KAAK,OAAO,CAAC,GAAG,WAAW,GAAG,CAAC,CAAC;CAClE,MAAM,QAAQ,IAA0B,QAAQ,MAAc;EAC5D,MAAM,UACJ,GAAG,cAAc,SAAS,MAAM,qBAAqB,IAAI,GAAG,UAAU;EACxE,MAAM,SAAS,OAAO,IAAI,GAAG,WAAW,UAAU,KAAK,OAAO;EAC9D,MAAM,OAAO,GAAG,UAAU,MAAM,GAAG,UAAU,YAAY,IAAI,GAAG,EAAE;AAClE,SAAO,GAAG,UAAU,QAAQ,IAAI,KAAK,QAAQ,QAAQ,EAAE,GAAG,MAAM,GAAG;;CAErE,MAAM,OAA+B,GAAG,QAAQ,QAAQ,UAAU,GAAG;AACrE,MAAK,MAAM,EAAE,YAAY,IAAI,QAAQ,GAAG,QAAQ,WAC9C,KAAI,WAAW,eAAe,OAAO,OAAO,YAAY,MAAM,EAC5D,MAAK,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG,KAAK,KAAK;CAC7C,MAAM,YAAoC,EAAE;AAC5C,MAAK,MAAM,CAAC,QAAQ,OAAO,OAAO,QAAQ,KAAK,EAAE;EAC/C,MAAM,OAAO,OAAO,KAAK,KAAK,CAAC,QAC5B,SACC,KAAK,WAAW,GAAG,OAAO,GAAG,IAC7B,CAAC,KAAK,MAAM,OAAO,SAAS,EAAE,CAAC,SAAS,IAAI,CAC/C;AACD,MAAI,KAAK,OACP,WAAU,GAAG,OAAO,kBAAkB,KAAK,IACzC,GACA,KAAK,QAAQ,MAAM,QAAQ,QAAQ,KAAK,QAAQ,IAAI,GAAG,CACxD;;AAEL,QAAO,KAAK;AACZ,QAAO;EAAE,GAAG;EAAW,GAAG;EAAM;;;;;;;;;;AAWlC,MAAM,aAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;AAGF,SAAgB,iBACd,YACqB;AACrB,QAAO,IAAI,IACT,WAAW,SAAS,OAClB,OAAO,GAAG,WAAW,WAAW,CAAC,GAAG,OAAO,GAAG,EAAE,CACjD,CACF;;;;;;;;;;AAWH,SAAgB,eACd,YACA,2BAAgC,IAAI,KAAK,EACzC,UAAU,iBAAiB,WAAW,EACtC;AACA,QAAO,WAAW,QACf,OACC,CAAC,SAAS,IAAI,GAAG,UAAU,IAC3B,CAAC,QAAQ,IAAI,GAAG,UAAU,IAC1B,OAAO,GAAG,eAAe,YACzB,OAAO,SAAS,GAAG,WAAW,CACjC;;AAGH,SAAgB,uBACd,YACA,2BAAgC,IAAI,KAAK,EACzC;CACA,MAAM,yBAAS,IAAI,KAAqB;AACxC,MAAK,MAAM,MAAM,eAAe,YAAY,SAAS,CACnD,QAAO,IAAI,GAAG,YAAY,OAAO,IAAI,GAAG,UAAU,IAAI,KAAK,GAAG,WAAW;AAC3E,QAAO;;AAGT,MAAM,cAAc,GAAkB,MACpC,MAAM,QAAQ,MAAM,OAAO,OAAO,IAAI;AACxC,MAAM,sBAAsB,GAAkB,MAAqB;CACjE,MAAM,QAAQ,WAAW,GAAG,EAAE;AAC9B,QAAO,UAAU,OAAO,OAAO,KAAK,IAAI,GAAG,MAAM;;;;;;;AAQnD,SAAgB,wBACd,QACA,MACA;CACA,MAAM,WAAW,UACf,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,GAAG,QAAQ;CAChE,MAAM,gBAAgB,WACpB,OAAO,YACL,OAAO,QAAQ,UAAU,EAAE,CAAC,CAAC,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG,CAAC,CACrE;CACH,MAAM,OAAO,OAAO,QAAQ,EAAE;CAC9B,MAAM,OAAO,QAAiB,OAAO,SAAS,KAAK,KAAK,GAAG,KAAK,OAAO;CACvE,MAAM,UAAU,IAAI,KAAK,eAAe;CACxC,MAAM,aAAa,IAAI,aAAa;CACpC,MAAM,OAAO,KAAK,YAAa,IAAI,KAAK,UAAU,IAAI,IAAK;CAC3D,MAAM,eACJ,YAAY,OACR,OACA,KAAK,IAAI,GAAG,UAAU,KAAK,IAC1B,KAAK,gBAAiB,cAAc,IAAK;CAChD,MAAM,cAAc,IAAI,eAAe;CACvC,MAAM,eAAe,IAAI,qBAAqB;CAC9C,MAAM,WAAW,eAAe;CAChC,MAAM,QAAQ;EACZ,MAAM,mBAAmB,OAAO,QAAQ,aAAa;EACrD,QAAQ,mBAAmB,cAAc,YAAY,EAAE;EACvD,WAAW,mBAAmB,aAAa,aAAa;EACxD,MAAM,gBAAgB;EACtB,KAAK,QAAQ,OAAO,MAAM;EAC1B,QAAQ,QAAQ,OAAO,SAAS;EAChC,MAAM;EACP;AACD,OAAM,OACJ,OAAO,SACP,OAAO,OAAO,MAAM,CAAC,QAAgB,KAAK,OAAO,OAAO,MAAM,IAAI,EAAE;CACtE,MAAM,YAAY,KAAK,uCAAuB,IAAI,KAAK;CACvD,MAAM,YACJ,OAAO,cACP,OAAO,YAAY,uBAAuB,OAAO,WAAW,EAAE,CAAC,CAAC;CAClE,MAAM,aAAa,OAAO,YACxB,OAAO,QAAQ,UAAU,CAAC,QACvB,CAAC,MAAM,QACN,SAAS,KAAK,kBACd,CAAC,UAAU,IAAI,KAAK,IACpB,OAAO,SAAS,GAAG,CACtB,CACF;;;;;;CAMD,MAAM,eAAe,OAAO,YAC1B,OAAO,QAAQ,KAAK,CAAC,QAClB,CAAC,UACA,OAAO,SAAS,KAAK,MAAM,IAC3B,CAAC,WAAW,IAAI,KAAK,IACrB,SAAS,KAAK,aACd,CAAC,KAAK,WAAW,QAAQ,IACzB,CAAC,KAAK,WAAW,MAAM,CAC1B,CACF;CACD,MAAM,WAAW,UAAU,aAAa,OAAO,WAAW,CAAC;CAC3D,MAAM,UAAU,UAAU,aAAa,OAAO,UAAU,CAAC;CACzD,MAAM,UAAU,OAAO,OAAO,WAAW,CAAC,QAAQ,KAAK,OAAO,MAAM,IAAI,EAAE;CAC1E,MAAM,eACH,KAAK,gBAAiB,cAAc,IAAK,MACzC,KAAK,kBACF,KAAK,gBAAgB,QAAQ,KAAK,QAAQ,OAAO,IAAI,IAAI,IAAI,IAAI,EAAE,GACnE,UAAU,aAAa,CAAC;CAC9B,MAAM,uBAAuB,WAAW,MAAM,QAAQ,YAAY;CAClE,MAAM,YAAY,SAAS,SAAS,SAChC,SAAS,aACT,UAAU,IACR,UACA;CACN,MAAM,qBAAqB,WAAW,MAAM,MAAM,UAAU;CAC5D,MAAM,oBAAoB,WAAW,MAAM,KAAK,QAAQ,WAAW;CACnE,MAAM,YACJ,KAAK,IAAI,GAAG,wBAAwB,MAAM,UAAU,EAAE,GACtD,KAAK,IAAI,GAAG,sBAAsB,MAAM,QAAQ,EAAE,GAClD,KAAK,IAAI,GAAG,qBAAqB,MAAM,OAAO,EAAE,GAChD,KAAK,IAAI,GAAG,MAAM,KAAK;CACzB,MAAM,iBAAiB,OAAO,WAAW,EAAE,EAAE,MAC1C,OAAO,GAAG,cAAc,KAAK,eAC/B,EAAE;CACH,MAAM,cAAc,QAAQ,OAAO,eAAe,cAAc;CAChE,MAAM,WAAW,OAAO,mBAAmB;CAC3C,MAAM,YAAY,eAAe;CACjC,MAAM,WAAW,eAAe,gBAAgB;CAChD,IAAI,YAAY;CAChB,MAAM,QAAQ,GAAkB,MAAqB;EACnD,MAAM,QAAQ,WAAW,GAAG,EAAE;AAC9B,MAAI,UAAU,KAAM,QAAO;AAC3B,eAAa,KAAK,IAAI,GAAG,CAAC,MAAM;AAChC,SAAO,KAAK,IAAI,GAAG,MAAM;;CAE3B,MAAM,cAAc,KAAK,aAAa,aAAa;CACnD,MAAM,cAAc,KAAK,cAAc,YAAY;CACnD,MAAM,UAAU,cAAc;CAQ9B,MAAM,SAAS;EACb;EACA;EACA,SATA,iBAAiB,OACb,KACE,OAAO,SAAS,WAChB,eAAe,eAAe,MAAM,eAAe,GACpD,GACD,KAAK,OAAO,QAAQ,aAAa;EAKrC,sBAAsB,mBAAmB,cAAc,QAAQ;EAC/D,aAAa,mBAAmB,cAAc,SAAS;EACvD,MAAM;GACJ,WAAW,mBAAmB,UAAU,YAAY,IAAI;GACxD,aAAa,mBAAmB,aAAa,SAAS,IAAI;GAC1D,iBAAiB,mBAAmB,SAAS,aAAa,IAAI;GAC9D,WACE,iBAAiB,OACb,IACA,KAAK,IACH,GACA,WAAW,aAAa,eAAe,MAAM,eAAe,GAC7D;GACP;GACD;EACF;AACD,QAAO;EACL,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf;EACA;EACA;EACA,uBAAuB,iBAAiB,QAAQ,gBAAgB;EAChE,yBAAyB,gBAAgB,QAAQ,iBAAiB;EAClE;EACA;EACA;EACA;EACA;EACA,cAAc,OAAO,SAAS,IAAI,YAAY,OAAO,SAAS;EAC9D,aAAa,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK;EACrC;EACA;EACA;EACA;EACA;EACA;EACD"}
|
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 } from "./lifecycle-wall-BnN-KFBx.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. */
|
package/dist/server-timing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as partitionLifecycleWalls } from "./lifecycle-wall-
|
|
1
|
+
import { c as partitionLifecycleWalls } from "./lifecycle-wall-CZZAgPft.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 = [
|
package/dist/stage-span.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as leafOperations, f as
|
|
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-BnN-KFBx.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/stage-span.d.ts
|
|
4
4
|
/**
|
|
@@ -52,8 +52,6 @@ declare function mintPtid(): string;
|
|
|
52
52
|
* the forwarded value, so the id is born once and identical everywhere.
|
|
53
53
|
*/
|
|
54
54
|
declare function readOrMintPtid(headerValue: string | null | undefined): string;
|
|
55
|
-
/** Input to {@link SpanRecorder.span} — ptid/op are fixed by the recorder. */
|
|
56
|
-
type StageSpanInput = Omit<StageSpan, "ptid" | "op">;
|
|
57
55
|
/** Options carried when recording a stage from a known duration. */
|
|
58
56
|
interface RecordOptions {
|
|
59
57
|
status?: SpanStatus;
|
|
@@ -61,57 +59,26 @@ interface RecordOptions {
|
|
|
61
59
|
attrs?: Record<string, string | number>;
|
|
62
60
|
}
|
|
63
61
|
/**
|
|
64
|
-
* Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them
|
|
65
|
-
* `Server-Timing` slice
|
|
66
|
-
* There is exactly one recorder per op; existing per-service timers become thin
|
|
67
|
-
* adapters that call {@link record} instead of keeping their own map.
|
|
62
|
+
* Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them as
|
|
63
|
+
* a `Server-Timing` slice whose entries sum to `total` exactly.
|
|
68
64
|
*/
|
|
69
65
|
declare class SpanRecorder {
|
|
70
66
|
readonly ptid: string;
|
|
71
67
|
readonly op: LifecycleOp;
|
|
72
68
|
private readonly spans;
|
|
73
69
|
constructor(ptid: string, op: LifecycleOp);
|
|
74
|
-
/**
|
|
75
|
-
span(input: StageSpanInput): StageSpan;
|
|
76
|
-
/**
|
|
77
|
-
* Adapter for a stage already timed elsewhere (an existing `Date.now()` map,
|
|
78
|
-
* a fold-back duration from a downstream hop): synthesize a span of the given
|
|
79
|
-
* millisecond duration ending now. Only the duration is load-bearing.
|
|
80
|
-
*/
|
|
70
|
+
/** A stage timed elsewhere: a span of `durationMs` ending now. */
|
|
81
71
|
record(stage: string, component: SpanComponent, durationMs: number, opts?: RecordOptions): StageSpan;
|
|
82
|
-
/** Top-level spans (no `parentStage`) — the ones the residual accounts for. */
|
|
83
|
-
topLevel(): StageSpan[];
|
|
84
|
-
/**
|
|
85
|
-
* Residual accounting: `sum(topLevelLeaves) + residual === total`, computed on
|
|
86
|
-
* the SAME rounded integers the header emits so the identity is exact. When
|
|
87
|
-
* `total` is omitted it is the wall span (max end − min start) across all
|
|
88
|
-
* spans. `residual` is the unaccounted gap — negative when stages overlap
|
|
89
|
-
* (parallelized work), the honest signal the CI dark-gap gate reads.
|
|
90
|
-
*/
|
|
91
|
-
reconcile(total?: number): {
|
|
92
|
-
total: number;
|
|
93
|
-
leavesSum: number;
|
|
94
|
-
residual: number;
|
|
95
|
-
leaves: Array<{
|
|
96
|
-
stage: string;
|
|
97
|
-
dur: number;
|
|
98
|
-
}>;
|
|
99
|
-
};
|
|
100
|
-
/** Wall duration across all recorded spans, in ms. */
|
|
101
|
-
wallMs(): number;
|
|
102
72
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* `total
|
|
106
|
-
* so
|
|
107
|
-
* `desc="skipped"`; string attrs surface as `desc`. Nested children are
|
|
108
|
-
* omitted from the header to keep the sum exact.
|
|
73
|
+
* One `stage;dur=` per top-level span (rounded, `desc="skipped"` or a string
|
|
74
|
+
* `attrs.desc`), then `<op>_unaccounted` (negative when stages overlap) and
|
|
75
|
+
* `total`, which defaults to the wall across every span. Children are left
|
|
76
|
+
* out so the entries sum to `total`.
|
|
109
77
|
*/
|
|
110
78
|
toServerTiming(opts?: {
|
|
111
79
|
total?: number;
|
|
112
|
-
includePtid?: boolean;
|
|
113
80
|
}): string;
|
|
114
81
|
}
|
|
115
82
|
//#endregion
|
|
116
|
-
export { CREATE_ACCOUNTING_SPEC, DELETE_ACCOUNTING_SPEC, type FlowAccountingSpec, LifecycleOp, ORCHESTRATOR_HOP_ID_HEADER, PROVISION_TRACE_ID_HEADER, RESUME_ACCOUNTING_SPEC, RecordOptions, STOP_ACCOUNTING_SPEC, SpanComponent, SpanRecorder, SpanStatus, StageSpan,
|
|
83
|
+
export { CREATE_ACCOUNTING_SPEC, DELETE_ACCOUNTING_SPEC, type FlowAccountingSpec, LifecycleOp, ORCHESTRATOR_HOP_ID_HEADER, PROVISION_TRACE_ID_HEADER, RESUME_ACCOUNTING_SPEC, RecordOptions, STOP_ACCOUNTING_SPEC, SpanComponent, SpanRecorder, SpanStatus, StageSpan, isAdoptablePtid, leafOperations, mintPtid, operationLeafDurations, parentOperations, readOrMintPtid, spanTreeStages, stageTree };
|
|
117
84
|
//# sourceMappingURL=stage-span.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-span.d.mts","names":[],"sources":["../src/stage-span.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"stage-span.d.mts","names":[],"sources":["../src/stage-span.ts"],"mappings":";;;;;AA8BA;;;;;AAGA;;;;;AAKA;;;;;cARa,yBAAA;;cAGA,0BAAA;AAAA,KAKD,WAAA;AAAA,KAYA,aAAA;AAAA,KAUA,UAAA;;;;;AASZ;;;UAAiB,SAAA;EACf,IAAA;EACA,EAAA,EAAI,WAAA;EACJ,KAAA;EACA,SAAA,EAAW,aAAA;EACX,OAAA;EACA,KAAA;EACA,MAAA,EAAQ,UAAA;EACR,WAAA;EACA,KAAA,GAAQ,MAAA;AAAA;AAAA,iBAgBM,eAAA,CACd,KAAA,8BACC,KAAA;;iBAKa,QAAA,CAAA;;;;;;;iBAUA,cAAA,CAAe,WAAA;AAjB/B;AAAA,UAsBiB,aAAA;EACf,MAAA,GAAS,UAAA;EACT,WAAA;EACA,KAAA,GAAQ,MAAA;AAAA;;;;;cAOG,YAAA;EAAA,SAIA,IAAA;EAAA,SACA,EAAA,EAAI,WAAA;EAAA,iBAJE,KAAA;cAGN,IAAA,UACA,EAAA,EAAI,WAAA;EAfA;EAmBf,MAAA,CACE,KAAA,UACA,SAAA,EAAW,aAAA,EACX,UAAA,UACA,IAAA,GAAO,aAAA,GACN,SAAA;;;;;;;EAuBH,cAAA,CAAe,IAAA;IAAS,KAAA;EAAA;AAAA"}
|
package/dist/stage-span.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as leafOperations, i as STOP_ACCOUNTING_SPEC, l as
|
|
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-CZZAgPft.mjs";
|
|
2
2
|
//#region src/stage-span.ts
|
|
3
3
|
/**
|
|
4
4
|
* One span shape for every lifecycle-op stage across every hop.
|
|
@@ -26,10 +26,6 @@ const PTID_PREFIX = "ptid_";
|
|
|
26
26
|
function monotonicNs() {
|
|
27
27
|
return BigInt(Math.round(performance.now() * 1e6));
|
|
28
28
|
}
|
|
29
|
-
/** Duration of a span in fractional milliseconds. */
|
|
30
|
-
function spanDurationMs(span) {
|
|
31
|
-
return Number(span.endNs - span.startNs) / 1e6;
|
|
32
|
-
}
|
|
33
29
|
/**
|
|
34
30
|
* A supplied trace id is adopted only when it matches the token charset a
|
|
35
31
|
* `Server-Timing`/header value accepts unquoted, so a client-origin id can be
|
|
@@ -53,112 +49,57 @@ function mintPtid() {
|
|
|
53
49
|
function readOrMintPtid(headerValue) {
|
|
54
50
|
return isAdoptablePtid(headerValue) ? headerValue : mintPtid();
|
|
55
51
|
}
|
|
56
|
-
const TOKEN = /[^\w-]/g;
|
|
57
|
-
function sanitizeDesc(value) {
|
|
58
|
-
return value.replace(TOKEN, "");
|
|
59
|
-
}
|
|
60
52
|
/**
|
|
61
|
-
* Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them
|
|
62
|
-
* `Server-Timing` slice
|
|
63
|
-
* There is exactly one recorder per op; existing per-service timers become thin
|
|
64
|
-
* adapters that call {@link record} instead of keeping their own map.
|
|
53
|
+
* Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them as
|
|
54
|
+
* a `Server-Timing` slice whose entries sum to `total` exactly.
|
|
65
55
|
*/
|
|
66
56
|
var SpanRecorder = class {
|
|
67
|
-
ptid;
|
|
68
|
-
op;
|
|
69
57
|
spans = [];
|
|
70
58
|
constructor(ptid, op) {
|
|
71
59
|
this.ptid = ptid;
|
|
72
60
|
this.op = op;
|
|
73
61
|
}
|
|
74
|
-
/**
|
|
75
|
-
|
|
62
|
+
/** A stage timed elsewhere: a span of `durationMs` ending now. */
|
|
63
|
+
record(stage, component, durationMs, opts) {
|
|
64
|
+
const endNs = monotonicNs();
|
|
76
65
|
const span = {
|
|
77
66
|
ptid: this.ptid,
|
|
78
67
|
op: this.op,
|
|
79
|
-
...input
|
|
80
|
-
};
|
|
81
|
-
this.spans.push(span);
|
|
82
|
-
return span;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Adapter for a stage already timed elsewhere (an existing `Date.now()` map,
|
|
86
|
-
* a fold-back duration from a downstream hop): synthesize a span of the given
|
|
87
|
-
* millisecond duration ending now. Only the duration is load-bearing.
|
|
88
|
-
*/
|
|
89
|
-
record(stage, component, durationMs, opts) {
|
|
90
|
-
const endNs = monotonicNs();
|
|
91
|
-
const startNs = endNs - BigInt(Math.round(Math.max(0, durationMs) * 1e6));
|
|
92
|
-
return this.span({
|
|
93
68
|
stage,
|
|
94
69
|
component,
|
|
95
|
-
startNs,
|
|
70
|
+
startNs: endNs - BigInt(Math.round(Math.max(0, durationMs) * 1e6)),
|
|
96
71
|
endNs,
|
|
97
72
|
status: opts?.status ?? "completed",
|
|
98
73
|
parentStage: opts?.parentStage,
|
|
99
74
|
attrs: opts?.attrs
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
/** Top-level spans (no `parentStage`) — the ones the residual accounts for. */
|
|
103
|
-
topLevel() {
|
|
104
|
-
return this.spans.filter((s) => s.parentStage === void 0);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Residual accounting: `sum(topLevelLeaves) + residual === total`, computed on
|
|
108
|
-
* the SAME rounded integers the header emits so the identity is exact. When
|
|
109
|
-
* `total` is omitted it is the wall span (max end − min start) across all
|
|
110
|
-
* spans. `residual` is the unaccounted gap — negative when stages overlap
|
|
111
|
-
* (parallelized work), the honest signal the CI dark-gap gate reads.
|
|
112
|
-
*/
|
|
113
|
-
reconcile(total) {
|
|
114
|
-
const leaves = this.topLevel().map((s) => ({
|
|
115
|
-
stage: s.stage,
|
|
116
|
-
dur: Math.round(spanDurationMs(s))
|
|
117
|
-
}));
|
|
118
|
-
const leavesSum = leaves.reduce((acc, l) => acc + l.dur, 0);
|
|
119
|
-
const totalRounded = Math.round(total ?? this.wallMs());
|
|
120
|
-
return {
|
|
121
|
-
total: totalRounded,
|
|
122
|
-
leavesSum,
|
|
123
|
-
residual: totalRounded - leavesSum,
|
|
124
|
-
leaves
|
|
125
75
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
wallMs() {
|
|
129
|
-
if (this.spans.length === 0) return 0;
|
|
130
|
-
let min = this.spans[0].startNs;
|
|
131
|
-
let max = this.spans[0].endNs;
|
|
132
|
-
for (const s of this.spans) {
|
|
133
|
-
if (s.startNs < min) min = s.startNs;
|
|
134
|
-
if (s.endNs > max) max = s.endNs;
|
|
135
|
-
}
|
|
136
|
-
return Number(max - min) / 1e6;
|
|
76
|
+
this.spans.push(span);
|
|
77
|
+
return span;
|
|
137
78
|
}
|
|
138
79
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* `total
|
|
142
|
-
* so
|
|
143
|
-
* `desc="skipped"`; string attrs surface as `desc`. Nested children are
|
|
144
|
-
* omitted from the header to keep the sum exact.
|
|
80
|
+
* One `stage;dur=` per top-level span (rounded, `desc="skipped"` or a string
|
|
81
|
+
* `attrs.desc`), then `<op>_unaccounted` (negative when stages overlap) and
|
|
82
|
+
* `total`, which defaults to the wall across every span. Children are left
|
|
83
|
+
* out so the entries sum to `total`.
|
|
145
84
|
*/
|
|
146
85
|
toServerTiming(opts) {
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
86
|
+
const ns = this.spans.flatMap((s) => [s.startNs, s.endNs]);
|
|
87
|
+
const wall = ns.length ? Number(ns.reduce((a, b) => a > b ? a : b) - ns.reduce((a, b) => a < b ? a : b)) / 1e6 : 0;
|
|
88
|
+
const total = Math.round(opts?.total ?? wall);
|
|
89
|
+
let rest = total;
|
|
90
|
+
return [
|
|
91
|
+
...this.spans.filter((span) => span.parentStage === void 0).map((span) => {
|
|
92
|
+
const dur = Math.round(Number(span.endNs - span.startNs) / 1e6);
|
|
93
|
+
rest -= dur;
|
|
94
|
+
const desc = span.status === "skipped" ? "skipped" : typeof span.attrs?.desc === "string" ? span.attrs.desc.replace(/[^\w-]/g, "") : void 0;
|
|
95
|
+
return `${span.stage};dur=${dur}${desc ? `;desc="${desc}"` : ""}`;
|
|
96
|
+
}),
|
|
97
|
+
`${this.op}_unaccounted;dur=${rest}`,
|
|
98
|
+
`total;dur=${total}`
|
|
99
|
+
].join(", ");
|
|
159
100
|
}
|
|
160
101
|
};
|
|
161
102
|
//#endregion
|
|
162
|
-
export { CREATE_ACCOUNTING_SPEC, DELETE_ACCOUNTING_SPEC, ORCHESTRATOR_HOP_ID_HEADER, PROVISION_TRACE_ID_HEADER, RESUME_ACCOUNTING_SPEC, STOP_ACCOUNTING_SPEC, SpanRecorder, isAdoptablePtid, leafOperations, mintPtid, operationLeafDurations, parentOperations, readOrMintPtid, stageTree };
|
|
103
|
+
export { CREATE_ACCOUNTING_SPEC, DELETE_ACCOUNTING_SPEC, ORCHESTRATOR_HOP_ID_HEADER, PROVISION_TRACE_ID_HEADER, RESUME_ACCOUNTING_SPEC, STOP_ACCOUNTING_SPEC, SpanRecorder, isAdoptablePtid, leafOperations, mintPtid, operationLeafDurations, parentOperations, readOrMintPtid, spanTreeStages, stageTree };
|
|
163
104
|
|
|
164
105
|
//# sourceMappingURL=stage-span.mjs.map
|
package/dist/stage-span.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-span.mjs","names":[],"sources":["../src/stage-span.ts"],"sourcesContent":["export {\n CREATE_ACCOUNTING_SPEC,\n DELETE_ACCOUNTING_SPEC,\n type FlowAccountingSpec,\n leafOperations,\n operationLeafDurations,\n parentOperations,\n RESUME_ACCOUNTING_SPEC,\n STOP_ACCOUNTING_SPEC,\n stageTree,\n} from \"./lifecycle-wall.js\";\n/**\n * One span shape for every lifecycle-op stage across every hop.\n *\n * The problem this solves: each service used to time its own stages with an\n * isolated `Date.now()` map (worker `stageMs`, orchestrator `startupDiagnostics`,\n * host `StartupBootstrapRecorder`, sidecar Prometheus) joined by disjoint ids,\n * so no single query reconstructs one operation end-to-end. `StageSpan` is the\n * shared record; `SpanRecorder` collects them under one correlation id (`ptid`)\n * and renders the same `Server-Timing` slice everywhere. Existing recorders\n * emit through this rather than hand-rolling a parallel timer.\n *\n * Runtime-portability: this module imports nothing Node-only (no `process`, no\n * `@repo/shared`, no otel) so it is safe to bundle into the Cloudflare Worker\n * via the `@tangle-network/sdk-telemetry/stage-span` subpath. The monotonic\n * clock is `performance.now()`, which is a global in both Node 18+ and Workers.\n */\n\n/** Request header that carries the one correlation id across every hop. */\nexport const PROVISION_TRACE_ID_HEADER = \"x-tangle-trace-id\";\n\n/** Response header for one Orchestrator HTTP hop within a logical trace. */\nexport const ORCHESTRATOR_HOP_ID_HEADER = \"x-orchestrator-hop-id\";\n\n/** Correlation id prefix minted at the edge (`ptid_<uuid>`). */\nconst PTID_PREFIX = \"ptid_\";\n\nexport type LifecycleOp =\n | \"create\"\n | \"branch\"\n | \"resume\"\n | \"suspend\"\n | \"snapshot\"\n | \"restore\"\n | \"exec\"\n | \"delete\"\n | \"turn\"\n | \"terminal_attach\";\n\nexport type SpanComponent =\n | \"client\"\n | \"cf-worker\"\n | \"sandbox-api\"\n | \"orchestrator\"\n | \"host-agent\"\n | \"sidecar\"\n | \"storage\"\n | \"container\";\n\nexport type SpanStatus = \"completed\" | \"skipped\" | \"error\";\n\n/**\n * One timed stage of one lifecycle op, keyed by (ptid, op, stage, component).\n * `startNs`/`endNs` are monotonic-clock nanoseconds (see {@link monotonicNs});\n * only their difference is meaningful — they are NOT wall-clock timestamps.\n * `parentStage` builds a tree: a span with `parentStage` set is a child that\n * rolls up under its parent and does NOT count toward the top-level residual.\n */\nexport interface StageSpan {\n ptid: string;\n op: LifecycleOp;\n stage: string;\n component: SpanComponent;\n startNs: bigint;\n endNs: bigint;\n status: SpanStatus;\n parentStage?: string;\n attrs?: Record<string, string | number>;\n}\n\n/** Monotonic clock → nanoseconds. Portable across Node and Workers. */\nfunction monotonicNs(): bigint {\n return BigInt(Math.round(performance.now() * 1_000_000));\n}\n\n/** Duration of a span in fractional milliseconds. */\nfunction spanDurationMs(span: Pick<StageSpan, \"startNs\" | \"endNs\">): number {\n return Number(span.endNs - span.startNs) / 1_000_000;\n}\n\n/**\n * A supplied trace id is adopted only when it matches the token charset a\n * `Server-Timing`/header value accepts unquoted, so a client-origin id can be\n * threaded but a malformed/oversized one can never poison downstream headers\n * or logs. Everything else is minted fresh.\n */\nconst PTID_ACCEPT = /^[\\w-]{8,200}$/;\n\nexport function isAdoptablePtid(\n value: string | null | undefined,\n): value is string {\n return typeof value === \"string\" && PTID_ACCEPT.test(value);\n}\n\n/** Mint a fresh edge-origin correlation id. */\nexport function mintPtid(): string {\n return `${PTID_PREFIX}${crypto.randomUUID()}`;\n}\n\n/**\n * Adopt an inbound `x-tangle-trace-id` when present and well-formed (so the\n * SDK can supply a true client-origin root), otherwise mint one. This is the\n * single decision every hop runs — the edge mints, every downstream hop adopts\n * the forwarded value, so the id is born once and identical everywhere.\n */\nexport function readOrMintPtid(headerValue: string | null | undefined): string {\n return isAdoptablePtid(headerValue) ? headerValue : mintPtid();\n}\n\n/** Input to {@link SpanRecorder.span} — ptid/op are fixed by the recorder. */\nexport type StageSpanInput = Omit<StageSpan, \"ptid\" | \"op\">;\n\n/** Options carried when recording a stage from a known duration. */\nexport interface RecordOptions {\n status?: SpanStatus;\n parentStage?: string;\n attrs?: Record<string, string | number>;\n}\n\nconst TOKEN = /[^\\w-]/g;\n\nfunction sanitizeDesc(value: string): string {\n return value.replace(TOKEN, \"\");\n}\n\n/**\n * Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them to a\n * `Server-Timing` slice and a residual reconciliation.\n * There is exactly one recorder per op; existing per-service timers become thin\n * adapters that call {@link record} instead of keeping their own map.\n */\nexport class SpanRecorder {\n readonly ptid: string;\n readonly op: LifecycleOp;\n private readonly spans: StageSpan[] = [];\n\n constructor(ptid: string, op: LifecycleOp) {\n this.ptid = ptid;\n this.op = op;\n }\n\n /** Push a fully-formed span (start/end already measured). Returns it. */\n span(input: StageSpanInput): StageSpan {\n const span: StageSpan = { ptid: this.ptid, op: this.op, ...input };\n this.spans.push(span);\n return span;\n }\n\n /**\n * Adapter for a stage already timed elsewhere (an existing `Date.now()` map,\n * a fold-back duration from a downstream hop): synthesize a span of the given\n * millisecond duration ending now. Only the duration is load-bearing.\n */\n record(\n stage: string,\n component: SpanComponent,\n durationMs: number,\n opts?: RecordOptions,\n ): StageSpan {\n const endNs = monotonicNs();\n const startNs =\n endNs - BigInt(Math.round(Math.max(0, durationMs) * 1_000_000));\n return this.span({\n stage,\n component,\n startNs,\n endNs,\n status: opts?.status ?? \"completed\",\n parentStage: opts?.parentStage,\n attrs: opts?.attrs,\n });\n }\n\n /** Top-level spans (no `parentStage`) — the ones the residual accounts for. */\n topLevel(): StageSpan[] {\n return this.spans.filter((s) => s.parentStage === undefined);\n }\n\n /**\n * Residual accounting: `sum(topLevelLeaves) + residual === total`, computed on\n * the SAME rounded integers the header emits so the identity is exact. When\n * `total` is omitted it is the wall span (max end − min start) across all\n * spans. `residual` is the unaccounted gap — negative when stages overlap\n * (parallelized work), the honest signal the CI dark-gap gate reads.\n */\n reconcile(total?: number): {\n total: number;\n leavesSum: number;\n residual: number;\n leaves: Array<{ stage: string; dur: number }>;\n } {\n const leaves = this.topLevel().map((s) => ({\n stage: s.stage,\n dur: Math.round(spanDurationMs(s)),\n }));\n const leavesSum = leaves.reduce((acc, l) => acc + l.dur, 0);\n const totalRounded = Math.round(total ?? this.wallMs());\n return {\n total: totalRounded,\n leavesSum,\n residual: totalRounded - leavesSum,\n leaves,\n };\n }\n\n /** Wall duration across all recorded spans, in ms. */\n wallMs(): number {\n if (this.spans.length === 0) return 0;\n let min = this.spans[0].startNs;\n let max = this.spans[0].endNs;\n for (const s of this.spans) {\n if (s.startNs < min) min = s.startNs;\n if (s.endNs > max) max = s.endNs;\n }\n return Number(max - min) / 1_000_000;\n }\n\n /**\n * Render the `Server-Timing` slice for this op: one `stage;dur=` per\n * top-level span, then `<op>_unaccounted;dur=<residual>`, then\n * `total;dur=<total>`. By construction the non-total entries sum to `total`,\n * so a browser Network tab shows the whole op. Skipped spans carry\n * `desc=\"skipped\"`; string attrs surface as `desc`. Nested children are\n * omitted from the header to keep the sum exact.\n */\n toServerTiming(opts?: { total?: number; includePtid?: boolean }): string {\n const { total, leaves, residual } = this.reconcile(opts?.total);\n const byStage = new Map(this.topLevel().map((s) => [s.stage, s]));\n const entries: string[] = [];\n if (opts?.includePtid) {\n entries.push(`ptid;desc=\"${sanitizeDesc(this.ptid)}\"`);\n }\n for (const leaf of leaves) {\n const span = byStage.get(leaf.stage);\n const desc =\n span?.status === \"skipped\"\n ? \"skipped\"\n : typeof span?.attrs?.desc === \"string\"\n ? sanitizeDesc(span.attrs.desc)\n : undefined;\n entries.push(\n desc\n ? `${leaf.stage};dur=${leaf.dur};desc=\"${desc}\"`\n : `${leaf.stage};dur=${leaf.dur}`,\n );\n }\n entries.push(`${this.op}_unaccounted;dur=${residual}`);\n entries.push(`total;dur=${total}`);\n return entries.join(\", \");\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stage-span.mjs","names":[],"sources":["../src/stage-span.ts"],"sourcesContent":["export {\n CREATE_ACCOUNTING_SPEC,\n DELETE_ACCOUNTING_SPEC,\n type FlowAccountingSpec,\n leafOperations,\n operationLeafDurations,\n parentOperations,\n RESUME_ACCOUNTING_SPEC,\n STOP_ACCOUNTING_SPEC,\n spanTreeStages,\n stageTree,\n} from \"./lifecycle-wall.js\";\n/**\n * One span shape for every lifecycle-op stage across every hop.\n *\n * The problem this solves: each service used to time its own stages with an\n * isolated `Date.now()` map (worker `stageMs`, orchestrator `startupDiagnostics`,\n * host `StartupBootstrapRecorder`, sidecar Prometheus) joined by disjoint ids,\n * so no single query reconstructs one operation end-to-end. `StageSpan` is the\n * shared record; `SpanRecorder` collects them under one correlation id (`ptid`)\n * and renders the same `Server-Timing` slice everywhere. Existing recorders\n * emit through this rather than hand-rolling a parallel timer.\n *\n * Runtime-portability: this module imports nothing Node-only (no `process`, no\n * `@repo/shared`, no otel) so it is safe to bundle into the Cloudflare Worker\n * via the `@tangle-network/sdk-telemetry/stage-span` subpath. The monotonic\n * clock is `performance.now()`, which is a global in both Node 18+ and Workers.\n */\n\n/** Request header that carries the one correlation id across every hop. */\nexport const PROVISION_TRACE_ID_HEADER = \"x-tangle-trace-id\";\n\n/** Response header for one Orchestrator HTTP hop within a logical trace. */\nexport const ORCHESTRATOR_HOP_ID_HEADER = \"x-orchestrator-hop-id\";\n\n/** Correlation id prefix minted at the edge (`ptid_<uuid>`). */\nconst PTID_PREFIX = \"ptid_\";\n\nexport type LifecycleOp =\n | \"create\"\n | \"branch\"\n | \"resume\"\n | \"suspend\"\n | \"snapshot\"\n | \"restore\"\n | \"exec\"\n | \"delete\"\n | \"turn\"\n | \"terminal_attach\";\n\nexport type SpanComponent =\n | \"client\"\n | \"cf-worker\"\n | \"sandbox-api\"\n | \"orchestrator\"\n | \"host-agent\"\n | \"sidecar\"\n | \"storage\"\n | \"container\";\n\nexport type SpanStatus = \"completed\" | \"skipped\" | \"error\";\n\n/**\n * One timed stage of one lifecycle op, keyed by (ptid, op, stage, component).\n * `startNs`/`endNs` are monotonic-clock nanoseconds (see {@link monotonicNs});\n * only their difference is meaningful — they are NOT wall-clock timestamps.\n * `parentStage` builds a tree: a span with `parentStage` set is a child that\n * rolls up under its parent and does NOT count toward the top-level residual.\n */\nexport interface StageSpan {\n ptid: string;\n op: LifecycleOp;\n stage: string;\n component: SpanComponent;\n startNs: bigint;\n endNs: bigint;\n status: SpanStatus;\n parentStage?: string;\n attrs?: Record<string, string | number>;\n}\n\n/** Monotonic clock → nanoseconds. Portable across Node and Workers. */\nfunction monotonicNs(): bigint {\n return BigInt(Math.round(performance.now() * 1_000_000));\n}\n\n/**\n * A supplied trace id is adopted only when it matches the token charset a\n * `Server-Timing`/header value accepts unquoted, so a client-origin id can be\n * threaded but a malformed/oversized one can never poison downstream headers\n * or logs. Everything else is minted fresh.\n */\nconst PTID_ACCEPT = /^[\\w-]{8,200}$/;\n\nexport function isAdoptablePtid(\n value: string | null | undefined,\n): value is string {\n return typeof value === \"string\" && PTID_ACCEPT.test(value);\n}\n\n/** Mint a fresh edge-origin correlation id. */\nexport function mintPtid(): string {\n return `${PTID_PREFIX}${crypto.randomUUID()}`;\n}\n\n/**\n * Adopt an inbound `x-tangle-trace-id` when present and well-formed (so the\n * SDK can supply a true client-origin root), otherwise mint one. This is the\n * single decision every hop runs — the edge mints, every downstream hop adopts\n * the forwarded value, so the id is born once and identical everywhere.\n */\nexport function readOrMintPtid(headerValue: string | null | undefined): string {\n return isAdoptablePtid(headerValue) ? headerValue : mintPtid();\n}\n\n/** Options carried when recording a stage from a known duration. */\nexport interface RecordOptions {\n status?: SpanStatus;\n parentStage?: string;\n attrs?: Record<string, string | number>;\n}\n\n/**\n * Collects {@link StageSpan}s for ONE op under ONE `ptid` and renders them as\n * a `Server-Timing` slice whose entries sum to `total` exactly.\n */\nexport class SpanRecorder {\n private readonly spans: StageSpan[] = [];\n\n constructor(\n readonly ptid: string,\n readonly op: LifecycleOp,\n ) {}\n\n /** A stage timed elsewhere: a span of `durationMs` ending now. */\n record(\n stage: string,\n component: SpanComponent,\n durationMs: number,\n opts?: RecordOptions,\n ): StageSpan {\n const endNs = monotonicNs();\n const span: StageSpan = {\n ptid: this.ptid,\n op: this.op,\n stage,\n component,\n startNs: endNs - BigInt(Math.round(Math.max(0, durationMs) * 1e6)),\n endNs,\n status: opts?.status ?? \"completed\",\n parentStage: opts?.parentStage,\n attrs: opts?.attrs,\n };\n this.spans.push(span);\n return span;\n }\n\n /**\n * One `stage;dur=` per top-level span (rounded, `desc=\"skipped\"` or a string\n * `attrs.desc`), then `<op>_unaccounted` (negative when stages overlap) and\n * `total`, which defaults to the wall across every span. Children are left\n * out so the entries sum to `total`.\n */\n toServerTiming(opts?: { total?: number }): string {\n const ns = this.spans.flatMap((s) => [s.startNs, s.endNs]);\n const wall = ns.length\n ? Number(\n ns.reduce((a, b) => (a > b ? a : b)) -\n ns.reduce((a, b) => (a < b ? a : b)),\n ) / 1e6\n : 0;\n const total = Math.round(opts?.total ?? wall);\n let rest = total;\n const entries = this.spans\n .filter((span) => span.parentStage === undefined)\n .map((span) => {\n const dur = Math.round(Number(span.endNs - span.startNs) / 1e6);\n rest -= dur;\n const desc =\n span.status === \"skipped\"\n ? \"skipped\"\n : typeof span.attrs?.desc === \"string\"\n ? span.attrs.desc.replace(/[^\\w-]/g, \"\")\n : undefined;\n return `${span.stage};dur=${dur}${desc ? `;desc=\"${desc}\"` : \"\"}`;\n });\n return [\n ...entries,\n `${this.op}_unaccounted;dur=${rest}`,\n `total;dur=${total}`,\n ].join(\", \");\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8BA,MAAa,4BAA4B;;AAGzC,MAAa,6BAA6B;;AAG1C,MAAM,cAAc;;AA8CpB,SAAS,cAAsB;AAC7B,QAAO,OAAO,KAAK,MAAM,YAAY,KAAK,GAAG,IAAU,CAAC;;;;;;;;AAS1D,MAAM,cAAc;AAEpB,SAAgB,gBACd,OACiB;AACjB,QAAO,OAAO,UAAU,YAAY,YAAY,KAAK,MAAM;;;AAI7D,SAAgB,WAAmB;AACjC,QAAO,GAAG,cAAc,OAAO,YAAY;;;;;;;;AAS7C,SAAgB,eAAe,aAAgD;AAC7E,QAAO,gBAAgB,YAAY,GAAG,cAAc,UAAU;;;;;;AAchE,IAAa,eAAb,MAA0B;CACxB,QAAsC,EAAE;CAExC,YACE,MACA,IACA;AAFS,OAAA,OAAA;AACA,OAAA,KAAA;;;CAIX,OACE,OACA,WACA,YACA,MACW;EACX,MAAM,QAAQ,aAAa;EAC3B,MAAM,OAAkB;GACtB,MAAM,KAAK;GACX,IAAI,KAAK;GACT;GACA;GACA,SAAS,QAAQ,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC;GAClE;GACA,QAAQ,MAAM,UAAU;GACxB,aAAa,MAAM;GACnB,OAAO,MAAM;GACd;AACD,OAAK,MAAM,KAAK,KAAK;AACrB,SAAO;;;;;;;;CAST,eAAe,MAAmC;EAChD,MAAM,KAAK,KAAK,MAAM,SAAS,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC;EAC1D,MAAM,OAAO,GAAG,SACZ,OACE,GAAG,QAAQ,GAAG,MAAO,IAAI,IAAI,IAAI,EAAG,GAClC,GAAG,QAAQ,GAAG,MAAO,IAAI,IAAI,IAAI,EAAG,CACvC,GAAG,MACJ;EACJ,MAAM,QAAQ,KAAK,MAAM,MAAM,SAAS,KAAK;EAC7C,IAAI,OAAO;AAcX,SAAO;GACL,GAdc,KAAK,MAClB,QAAQ,SAAS,KAAK,gBAAgB,KAAA,EAAU,CAChD,KAAK,SAAS;IACb,MAAM,MAAM,KAAK,MAAM,OAAO,KAAK,QAAQ,KAAK,QAAQ,GAAG,IAAI;AAC/D,YAAQ;IACR,MAAM,OACJ,KAAK,WAAW,YACZ,YACA,OAAO,KAAK,OAAO,SAAS,WAC1B,KAAK,MAAM,KAAK,QAAQ,WAAW,GAAG,GACtC,KAAA;AACR,WAAO,GAAG,KAAK,MAAM,OAAO,MAAM,OAAO,UAAU,KAAK,KAAK;KAGrD;GACV,GAAG,KAAK,GAAG,mBAAmB;GAC9B,aAAa;GACd,CAAC,KAAK,KAAK"}
|
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.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"tangleRelease": {
|
|
77
|
-
"sourceSha": "
|
|
78
|
-
"mergedAt": "2026-
|
|
77
|
+
"sourceSha": "50c8abd9e7430bdbb936c563de63fa6b192262b4",
|
|
78
|
+
"mergedAt": "2026-11-01T00:21:38-06:00"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "tsdown",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-wall-CXJaufPp.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,cAcxB,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;;;;;;;;;iBAuED,gBAAA,CACd,UAAA,WAAqB,oBAAA,KACpB,WAAA;;;AA/CH;;;;;;iBA+DgB,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;;;;;;iBAoB3B,uBAAA,CACd,MAAA,EAAQ,mBAAA,EACR,IAAA,EAAM,iBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAxB8B;;;;;;;;;;;;;;;;;;SAwB9B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-wall-Co9iFDvN.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 // resumeSidecar (and the reprovision fallback assembly in resume()) stamps\n // `orchestrator.ready` from the route's startupStartedAt — the resume total\n // span. `sidecar_resume` brackets that stamp and is the parent of every\n // host-side span, so the leaf rule already excludes it; `connection_build`\n // and `metering_restart` run after resumeSidecar returns, hence after the\n // stamp, and are excluded here.\n totalOperation: \"orchestrator.ready\",\n postReadyOperations: new Set([\n \"orchestrator.connection_build\",\n \"orchestrator.metering_restart\",\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 * 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) => (Number.isFinite(hops[key]) ? hops[key] : null);\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 /**\n * The Worker's own handler stages: its ledger minus the three nested walls,\n * the transport they imply and the middleware own-times, which are ranked\n * separately because they run OUTSIDE the handler's `total`.\n */\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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"}
|