@sekiban/dcb-runtime 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +86 -0
- package/README.md +13 -0
- package/dist/allocator/AllocatorDurableObject.d.ts +36 -0
- package/dist/allocator/AllocatorDurableObject.js +658 -0
- package/dist/allocator/IssuanceLedger.d.ts +188 -0
- package/dist/allocator/IssuanceLedger.js +608 -0
- package/dist/allocator/IssuanceReconciler.d.ts +41 -0
- package/dist/allocator/IssuanceReconciler.js +191 -0
- package/dist/allocator/OrderClock.d.ts +41 -0
- package/dist/allocator/OrderClock.js +92 -0
- package/dist/allocator/SortableUniqueId.d.ts +46 -0
- package/dist/allocator/SortableUniqueId.js +156 -0
- package/dist/allocator/types.d.ts +52 -0
- package/dist/allocator/types.js +1 -0
- package/dist/bootstrap/BootstrapCoordinatorDurableObject.d.ts +28 -0
- package/dist/bootstrap/BootstrapCoordinatorDurableObject.js +357 -0
- package/dist/bootstrap/BootstrapStoreAdapter.d.ts +51 -0
- package/dist/bootstrap/BootstrapStoreAdapter.js +162 -0
- package/dist/bootstrap/OperatorBootstrap.d.ts +20 -0
- package/dist/bootstrap/OperatorBootstrap.js +104 -0
- package/dist/bootstrap/manifest.d.ts +9 -0
- package/dist/bootstrap/manifest.js +115 -0
- package/dist/bootstrap/types.d.ts +75 -0
- package/dist/bootstrap/types.js +1 -0
- package/dist/cli/OperatorRepairCli.d.ts +11 -0
- package/dist/cli/OperatorRepairCli.js +108 -0
- package/dist/cloudflare.d.ts +164 -0
- package/dist/cloudflare.js +19487 -0
- package/dist/commit/CommitWorker.d.ts +101 -0
- package/dist/commit/CommitWorker.js +921 -0
- package/dist/commit/types.d.ts +25 -0
- package/dist/commit/types.js +13 -0
- package/dist/completeness/GlobalCompletenessReconciler.d.ts +77 -0
- package/dist/completeness/GlobalCompletenessReconciler.js +572 -0
- package/dist/completeness/types.d.ts +85 -0
- package/dist/completeness/types.js +6 -0
- package/dist/composition.d.ts +123 -0
- package/dist/composition.js +237 -0
- package/dist/cosmos.d.ts +11 -0
- package/dist/cosmos.js +1411 -0
- package/dist/d1-mv.d.ts +8 -0
- package/dist/d1-mv.js +2001 -0
- package/dist/d1.d.ts +16 -0
- package/dist/d1.js +3418 -0
- package/dist/diagnostics/G60DurableHop.d.ts +99 -0
- package/dist/diagnostics/G60DurableHop.js +248 -0
- package/dist/diagnostics/G65Admission.d.ts +23 -0
- package/dist/diagnostics/G65Admission.js +43 -0
- package/dist/diagnostics/G65DirectRing.d.ts +33 -0
- package/dist/diagnostics/G65DirectRing.js +85 -0
- package/dist/diagnostics/G69AdmissionAttempt.d.ts +43 -0
- package/dist/diagnostics/G69AdmissionAttempt.js +22 -0
- package/dist/downstream/DeliveryCore.d.ts +127 -0
- package/dist/downstream/DeliveryCore.js +304 -0
- package/dist/downstream/Doorbell.d.ts +43 -0
- package/dist/downstream/Doorbell.js +137 -0
- package/dist/downstream/DownstreamAdapter.d.ts +52 -0
- package/dist/downstream/DownstreamAdapter.js +299 -0
- package/dist/downstream/ExclusionLookup.d.ts +36 -0
- package/dist/downstream/ExclusionLookup.js +50 -0
- package/dist/downstream/InconsistencyDetector.d.ts +27 -0
- package/dist/downstream/InconsistencyDetector.js +82 -0
- package/dist/downstream/OutboxDrain.d.ts +35 -0
- package/dist/downstream/OutboxDrain.js +126 -0
- package/dist/downstream/types.d.ts +77 -0
- package/dist/downstream/types.js +64 -0
- package/dist/eventIdentity.d.ts +30 -0
- package/dist/eventIdentity.js +49 -0
- package/dist/eventRecord.d.ts +26 -0
- package/dist/eventRecord.js +53 -0
- package/dist/g42-probe.d.ts +9 -0
- package/dist/g42-probe.js +9 -0
- package/dist/http/SerializedQueryWorker.d.ts +58 -0
- package/dist/http/SerializedQueryWorker.js +497 -0
- package/dist/http/commitResponse.d.ts +46 -0
- package/dist/http/commitResponse.js +80 -0
- package/dist/http/testServiceId.d.ts +17 -0
- package/dist/http/testServiceId.js +14 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.js +19926 -0
- package/dist/journal/JournalDurableObject.d.ts +30 -0
- package/dist/journal/JournalDurableObject.js +481 -0
- package/dist/journal/JournalFirstTouchProbe.d.ts +190 -0
- package/dist/journal/JournalFirstTouchProbe.js +375 -0
- package/dist/journal/types.d.ts +116 -0
- package/dist/journal/types.js +52 -0
- package/dist/mv/MaterializedViewCatchUp.d.ts +60 -0
- package/dist/mv/MaterializedViewCatchUp.js +353 -0
- package/dist/mv/MaterializedViewRuntime.d.ts +80 -0
- package/dist/mv/MaterializedViewRuntime.js +328 -0
- package/dist/mv/MaterializedViewStore.d.ts +257 -0
- package/dist/mv/MaterializedViewStore.js +875 -0
- package/dist/mv/UnsafeWindowMaterializedView.d.ts +112 -0
- package/dist/mv/UnsafeWindowMaterializedView.js +495 -0
- package/dist/mv/index.d.ts +8 -0
- package/dist/mv/index.js +2357 -0
- package/dist/projection/LiveProjectionWorker.d.ts +86 -0
- package/dist/projection/LiveProjectionWorker.js +240 -0
- package/dist/projection/ProjectionRuntime.d.ts +113 -0
- package/dist/projection/ProjectionRuntime.js +346 -0
- package/dist/projection/ProjectorRegistry.d.ts +51 -0
- package/dist/projection/ProjectorRegistry.js +116 -0
- package/dist/query/ProjectionQueryStore.d.ts +102 -0
- package/dist/query/ProjectionQueryStore.js +185 -0
- package/dist/query/QueryRegistry.d.ts +22 -0
- package/dist/query/QueryRegistry.js +36 -0
- package/dist/read/SerializedReadWorker.d.ts +36 -0
- package/dist/read/SerializedReadWorker.js +225 -0
- package/dist/repair/RepairWorker.d.ts +72 -0
- package/dist/repair/RepairWorker.js +461 -0
- package/dist/safeWindow.d.ts +20 -0
- package/dist/safeWindow.js +36 -0
- package/dist/scope/ControlRouteScope.d.ts +22 -0
- package/dist/scope/ControlRouteScope.js +36 -0
- package/dist/scope/ScopeName.d.ts +34 -0
- package/dist/scope/ScopeName.js +67 -0
- package/dist/service/ServiceIdentityProvider.d.ts +35 -0
- package/dist/service/ServiceIdentityProvider.js +56 -0
- package/dist/store/CosmosEventStore.d.ts +126 -0
- package/dist/store/CosmosEventStore.js +950 -0
- package/dist/store/D1EventStore.d.ts +111 -0
- package/dist/store/D1EventStore.js +1111 -0
- package/dist/store/PostgresEventStore.d.ts +35 -0
- package/dist/store/PostgresEventStore.js +811 -0
- package/dist/store/provider.d.ts +25 -0
- package/dist/store/provider.js +32 -0
- package/dist/store/types.d.ts +205 -0
- package/dist/store/types.js +18 -0
- package/dist/tag/EventDigest.d.ts +40 -0
- package/dist/tag/EventDigest.js +158 -0
- package/dist/tag/TagDurableObject.d.ts +286 -0
- package/dist/tag/TagDurableObject.js +4071 -0
- package/dist/tag/TagSqlMeasurement.d.ts +26 -0
- package/dist/tag/TagSqlMeasurement.js +44 -0
- package/dist/tag/TagSqlSchema.d.ts +29 -0
- package/dist/tag/TagSqlSchema.js +211 -0
- package/dist/tag/types.d.ts +173 -0
- package/dist/tag/types.js +3 -0
- package/dist/tagstate/TagStateDurableObject.d.ts +57 -0
- package/dist/tagstate/TagStateDurableObject.js +499 -0
- package/dist/trace/AttributionRatio.d.ts +12 -0
- package/dist/trace/AttributionRatio.js +68 -0
- package/dist/trace/CloudflareTracing.d.ts +7 -0
- package/dist/trace/CloudflareTracing.js +9 -0
- package/dist/trace/CommitTrace.d.ts +405 -0
- package/dist/trace/CommitTrace.js +1008 -0
- package/dist/trace/CommitTraceConsoleSink.d.ts +68 -0
- package/dist/trace/CommitTraceConsoleSink.js +114 -0
- package/dist/trace/CommitTraceVerifier.d.ts +22 -0
- package/dist/trace/CommitTraceVerifier.js +295 -0
- package/dist/trace/ObservationStream.d.ts +118 -0
- package/dist/trace/ObservationStream.js +148 -0
- package/package.json +71 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retained Workers Logs projection for a successful in-process commit trace.
|
|
3
|
+
*
|
|
4
|
+
* This module deliberately projects an already-frozen CommitTraceSnapshot; it
|
|
5
|
+
* neither creates a span nor participates in the commit protocol. Keeping
|
|
6
|
+
* the log schema separate also avoids extending the sealed sdt.commit/v1
|
|
7
|
+
* attribute matrix just to make a console payload queryable.
|
|
8
|
+
*/
|
|
9
|
+
import type { CommitTraceSink, CommitTraceSnapshot, CommitTraceSpan, TraceAttributeValue } from "./CommitTrace";
|
|
10
|
+
export declare const COMMIT_SNAPSHOT_LOG_SCHEMA: "sdt.commit-snapshot/v1";
|
|
11
|
+
export declare const COMMIT_SNAPSHOT_LOG_EVENT: "commit.snapshot";
|
|
12
|
+
/** Leave a substantial margin below the 256 KiB Workers Logs record limit. */
|
|
13
|
+
export declare const COMMIT_SNAPSHOT_LOG_BYTE_BUDGET: number;
|
|
14
|
+
export interface CommitSnapshotLogRow {
|
|
15
|
+
readonly rowId: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
/** Explicit log-only row identity; it does not alter native span attributes. */
|
|
18
|
+
readonly "sdt.row.id": string;
|
|
19
|
+
readonly startOffsetMs: number;
|
|
20
|
+
readonly endOffsetMs: number;
|
|
21
|
+
readonly durationMs: number;
|
|
22
|
+
readonly face: CommitTraceSpan["face"];
|
|
23
|
+
readonly clockDomain: CommitTraceSpan["clockDomain"];
|
|
24
|
+
readonly zeroDurationPlatformLimited: boolean;
|
|
25
|
+
readonly attributes: Readonly<Record<string, TraceAttributeValue>>;
|
|
26
|
+
}
|
|
27
|
+
export interface CommitSnapshotLogRecord {
|
|
28
|
+
readonly schema: typeof COMMIT_SNAPSHOT_LOG_SCHEMA;
|
|
29
|
+
readonly event: typeof COMMIT_SNAPSHOT_LOG_EVENT;
|
|
30
|
+
readonly snapshotSchema: "sdt.commit/v1";
|
|
31
|
+
readonly correlationId: string;
|
|
32
|
+
readonly serviceId: string;
|
|
33
|
+
/** The ingress CF-Ray when the hosting Worker knows it. */
|
|
34
|
+
readonly platformRequestId?: string;
|
|
35
|
+
readonly rootId: string;
|
|
36
|
+
readonly rootStartedAtMs: number;
|
|
37
|
+
readonly rootEndedAtMs: number;
|
|
38
|
+
readonly rows: readonly CommitSnapshotLogRow[];
|
|
39
|
+
readonly provider: CommitTraceSnapshot["provider"];
|
|
40
|
+
readonly runtimeVerification?: CommitTraceSnapshot["runtimeVerification"];
|
|
41
|
+
}
|
|
42
|
+
export interface CommitTraceConsoleSinkOptions {
|
|
43
|
+
readonly platformRequestId?: string;
|
|
44
|
+
/** Test seam; production defaults to the structured Workers Logs transport. */
|
|
45
|
+
readonly log?: (record: CommitSnapshotLogRecord) => void;
|
|
46
|
+
/** A bounded receipt if the deterministic guard refuses an oversized log. */
|
|
47
|
+
readonly reportRejectedSize?: (receipt: Readonly<{
|
|
48
|
+
schema: typeof COMMIT_SNAPSHOT_LOG_SCHEMA;
|
|
49
|
+
event: "commit.snapshot-size-rejected";
|
|
50
|
+
serviceId: string;
|
|
51
|
+
correlationId: string;
|
|
52
|
+
encodedBytes: number;
|
|
53
|
+
byteBudget: number;
|
|
54
|
+
}>) => void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns the one retained-log record for a successful V1 commit. Rejected,
|
|
58
|
+
* no-op, partial, and failed paths deliberately produce no snapshot log.
|
|
59
|
+
*/
|
|
60
|
+
export declare function commitSnapshotLogRecord(snapshot: CommitTraceSnapshot, options?: Pick<CommitTraceConsoleSinkOptions, "platformRequestId">): CommitSnapshotLogRecord | undefined;
|
|
61
|
+
export declare function encodedCommitSnapshotLogBytes(record: CommitSnapshotLogRecord): number;
|
|
62
|
+
export declare function assertCommitSnapshotLogSize(record: CommitSnapshotLogRecord): number;
|
|
63
|
+
/**
|
|
64
|
+
* Observation-only CommitTrace sink used by Cloudflare Worker compositions.
|
|
65
|
+
* Its only side effect is one structured console record for an accepted HTTP
|
|
66
|
+
* 200 commit; failure is rethrown for CommitTrace's existing fail-open receipt.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createCommitTraceConsoleSink(options?: CommitTraceConsoleSinkOptions): CommitTraceSink;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export const COMMIT_SNAPSHOT_LOG_SCHEMA = "sdt.commit-snapshot/v1";
|
|
2
|
+
export const COMMIT_SNAPSHOT_LOG_EVENT = "commit.snapshot";
|
|
3
|
+
/** Leave a substantial margin below the 256 KiB Workers Logs record limit. */
|
|
4
|
+
export const COMMIT_SNAPSHOT_LOG_BYTE_BUDGET = 192 * 1024;
|
|
5
|
+
function successfulRoot(snapshot) {
|
|
6
|
+
if (snapshot.schema !== "sdt.commit/v1")
|
|
7
|
+
return undefined;
|
|
8
|
+
const root = snapshot.spans.find((span) => span.rowId === "S00" && span.logicalParent === null);
|
|
9
|
+
if (root === undefined || root.face !== "accepted")
|
|
10
|
+
return undefined;
|
|
11
|
+
if (typeof root.attributes["attempt.id"] !== "string" || root.attributes["attempt.id"].length === 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
return root.attributes.outcome === "success" && root.attributes["http.status"] === 200 ? root : undefined;
|
|
14
|
+
}
|
|
15
|
+
function nonEmpty(value) {
|
|
16
|
+
const trimmed = value?.trim();
|
|
17
|
+
return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;
|
|
18
|
+
}
|
|
19
|
+
function rowForLog(span, root) {
|
|
20
|
+
const startOffsetMs = span.startMs - root.startMs;
|
|
21
|
+
const endOffsetMs = span.endMs - root.startMs;
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
rowId: span.rowId,
|
|
24
|
+
name: span.span,
|
|
25
|
+
"sdt.row.id": span.rowId,
|
|
26
|
+
startOffsetMs,
|
|
27
|
+
endOffsetMs,
|
|
28
|
+
durationMs: Math.max(0, span.endMs - span.startMs),
|
|
29
|
+
face: span.face,
|
|
30
|
+
clockDomain: span.clockDomain,
|
|
31
|
+
zeroDurationPlatformLimited: span.zeroDurationPlatformLimited,
|
|
32
|
+
attributes: Object.freeze({ ...span.attributes }),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns the one retained-log record for a successful V1 commit. Rejected,
|
|
37
|
+
* no-op, partial, and failed paths deliberately produce no snapshot log.
|
|
38
|
+
*/
|
|
39
|
+
export function commitSnapshotLogRecord(snapshot, options = {}) {
|
|
40
|
+
const root = successfulRoot(snapshot);
|
|
41
|
+
if (root === undefined)
|
|
42
|
+
return undefined;
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
schema: COMMIT_SNAPSHOT_LOG_SCHEMA,
|
|
45
|
+
event: COMMIT_SNAPSHOT_LOG_EVENT,
|
|
46
|
+
snapshotSchema: "sdt.commit/v1",
|
|
47
|
+
correlationId: snapshot.correlationId,
|
|
48
|
+
serviceId: snapshot.serviceId,
|
|
49
|
+
...(nonEmpty(options.platformRequestId) === undefined ? {} : { platformRequestId: nonEmpty(options.platformRequestId) }),
|
|
50
|
+
rootId: snapshot.rootId,
|
|
51
|
+
rootStartedAtMs: root.startMs,
|
|
52
|
+
rootEndedAtMs: root.endMs,
|
|
53
|
+
rows: Object.freeze(snapshot.spans.map((span) => rowForLog(span, root))),
|
|
54
|
+
provider: Object.freeze({ ...snapshot.provider }),
|
|
55
|
+
...(snapshot.runtimeVerification === undefined ? {} : { runtimeVerification: snapshot.runtimeVerification }),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function encodedCommitSnapshotLogBytes(record) {
|
|
59
|
+
return new TextEncoder().encode(JSON.stringify(record)).byteLength;
|
|
60
|
+
}
|
|
61
|
+
export function assertCommitSnapshotLogSize(record) {
|
|
62
|
+
const encodedBytes = encodedCommitSnapshotLogBytes(record);
|
|
63
|
+
if (encodedBytes > COMMIT_SNAPSHOT_LOG_BYTE_BUDGET) {
|
|
64
|
+
const error = new Error(`Commit snapshot log is ${encodedBytes} bytes; budget is ${COMMIT_SNAPSHOT_LOG_BYTE_BUDGET} bytes`);
|
|
65
|
+
error.code = "commit-snapshot-log-size";
|
|
66
|
+
error.encodedBytes = encodedBytes;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
return encodedBytes;
|
|
70
|
+
}
|
|
71
|
+
const workersConsoleLog = (record) => {
|
|
72
|
+
// Workers Logs indexes members of object console records directly.
|
|
73
|
+
console.log(record);
|
|
74
|
+
};
|
|
75
|
+
const workersConsoleRejectedSize = (receipt) => {
|
|
76
|
+
// Never silently truncate a record. This compact, bounded receipt names the
|
|
77
|
+
// observation loss while CommitTrace still returns the original response.
|
|
78
|
+
console.error(receipt);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Observation-only CommitTrace sink used by Cloudflare Worker compositions.
|
|
82
|
+
* Its only side effect is one structured console record for an accepted HTTP
|
|
83
|
+
* 200 commit; failure is rethrown for CommitTrace's existing fail-open receipt.
|
|
84
|
+
*/
|
|
85
|
+
export function createCommitTraceConsoleSink(options = {}) {
|
|
86
|
+
const log = options.log ?? workersConsoleLog;
|
|
87
|
+
const reportRejectedSize = options.reportRejectedSize ?? workersConsoleRejectedSize;
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
record(snapshot) {
|
|
90
|
+
const record = commitSnapshotLogRecord(snapshot, options);
|
|
91
|
+
if (record === undefined)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
assertCommitSnapshotLogSize(record);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const encodedBytes = typeof error === "object" && error !== null && "encodedBytes" in error
|
|
98
|
+
&& typeof error.encodedBytes === "number"
|
|
99
|
+
? error.encodedBytes
|
|
100
|
+
: encodedCommitSnapshotLogBytes(record);
|
|
101
|
+
reportRejectedSize(Object.freeze({
|
|
102
|
+
schema: COMMIT_SNAPSHOT_LOG_SCHEMA,
|
|
103
|
+
event: "commit.snapshot-size-rejected",
|
|
104
|
+
serviceId: record.serviceId,
|
|
105
|
+
correlationId: record.correlationId,
|
|
106
|
+
encodedBytes,
|
|
107
|
+
byteBudget: COMMIT_SNAPSHOT_LOG_BYTE_BUDGET,
|
|
108
|
+
}));
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
log(record);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CommitTraceSnapshot } from "./CommitTrace";
|
|
2
|
+
import { type UnattributedRatio } from "./AttributionRatio";
|
|
3
|
+
export { calculateUnattributedRatio } from "./AttributionRatio";
|
|
4
|
+
export type { UnattributedRatio } from "./AttributionRatio";
|
|
5
|
+
export declare class CommitTraceVerificationError extends Error {
|
|
6
|
+
readonly code: string;
|
|
7
|
+
constructor(code: string, message: string);
|
|
8
|
+
}
|
|
9
|
+
export interface CommitTraceVerificationOptions {
|
|
10
|
+
/** A literal v1 boundary name from the authority manifest. */
|
|
11
|
+
readonly boundary?: string;
|
|
12
|
+
/** Result of every manifest conditional predicate for this trace. */
|
|
13
|
+
readonly conditionals?: Readonly<Record<string, boolean>>;
|
|
14
|
+
/** Exact runtime cardinalities for indexed/fan-out rows. */
|
|
15
|
+
readonly cardinalities?: Readonly<Record<string, number>>;
|
|
16
|
+
/** Enforce the per-request <=5% unattributed gate. */
|
|
17
|
+
readonly accepted?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function verifyCommitTrace(snapshot: CommitTraceSnapshot, options?: CommitTraceVerificationOptions): Readonly<{
|
|
20
|
+
unattributed?: UnattributedRatio;
|
|
21
|
+
rows: number;
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { traceManifest, } from "./CommitTrace";
|
|
2
|
+
import { calculateUnattributedRatio } from "./AttributionRatio";
|
|
3
|
+
export { calculateUnattributedRatio } from "./AttributionRatio";
|
|
4
|
+
export class CommitTraceVerificationError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = "CommitTraceVerificationError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const TRANSITION_PHASE = Object.freeze({
|
|
13
|
+
S05a: 0,
|
|
14
|
+
S05b: 1,
|
|
15
|
+
S05c: 2,
|
|
16
|
+
S05d: 3,
|
|
17
|
+
S05e: 4,
|
|
18
|
+
});
|
|
19
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
20
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
21
|
+
function failure(code, message) {
|
|
22
|
+
throw new CommitTraceVerificationError(code, message);
|
|
23
|
+
}
|
|
24
|
+
function schemaRows(snapshot) {
|
|
25
|
+
const schema = traceManifest().schemas[snapshot.schema];
|
|
26
|
+
if (schema === undefined || !Array.isArray(schema.rows))
|
|
27
|
+
failure("schema-missing", `manifest lacks ${snapshot.schema}`);
|
|
28
|
+
return schema.rows;
|
|
29
|
+
}
|
|
30
|
+
function rowMap(snapshot) {
|
|
31
|
+
return new Map(schemaRows(snapshot).map((row) => [row.rowId, row]));
|
|
32
|
+
}
|
|
33
|
+
function typeCheck(value, type, values, key) {
|
|
34
|
+
if (type === "enum-from-manifest-recovery") {
|
|
35
|
+
if (typeof value !== "string")
|
|
36
|
+
failure("attribute-type", `${key} must be a string`);
|
|
37
|
+
const reconcile = traceManifest().schemas["sdt.commit.reconcile/v1"];
|
|
38
|
+
const recoveryKinds = [
|
|
39
|
+
...Object.keys(reconcile.recoveryDag ?? {}),
|
|
40
|
+
reconcile.terminalAtEntryBoundary?.name,
|
|
41
|
+
].filter((candidate) => typeof candidate === "string");
|
|
42
|
+
if (!recoveryKinds.includes(value)) {
|
|
43
|
+
failure("attribute-enum", `${key} value ${value} is not manifest-declared`);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (type === "string" || type === "string-literal" || type === "enum" || type.startsWith("enum-") || type === "provider-adapter") {
|
|
48
|
+
if (typeof value !== "string")
|
|
49
|
+
failure("attribute-type", `${key} must be a string`);
|
|
50
|
+
if (values !== undefined && !values.includes(value))
|
|
51
|
+
failure("attribute-enum", `${key} value ${value} is not manifest-declared`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (type === "hex64") {
|
|
55
|
+
if (typeof value !== "string" || !HEX64.test(value))
|
|
56
|
+
failure("attribute-hex64", `${key} must be lower-case 64-hex`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (type === "uuid") {
|
|
60
|
+
if (typeof value !== "string" || !UUID.test(value))
|
|
61
|
+
failure("attribute-uuid", `${key} must be a UUID`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (type === "boolean") {
|
|
65
|
+
if (typeof value !== "boolean")
|
|
66
|
+
failure("attribute-boolean", `${key} must be boolean`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (type === "integer" || type === "non-negative-integer") {
|
|
70
|
+
if (typeof value !== "number" || !Number.isInteger(value) || (type === "non-negative-integer" && value < 0)) {
|
|
71
|
+
failure("attribute-integer", `${key} must be ${type}`);
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
failure("attribute-type-unknown", `manifest declares unsupported type ${type} for ${key}`);
|
|
76
|
+
}
|
|
77
|
+
function verifyAttributes(span, row) {
|
|
78
|
+
const matrix = traceManifest().attributeMatrix;
|
|
79
|
+
for (const [key, declaration] of Object.entries(matrix.attributes)) {
|
|
80
|
+
const state = declaration.rowScope !== undefined && !declaration.rowScope.includes(span.rowId)
|
|
81
|
+
? "forbidden"
|
|
82
|
+
: declaration.faces[span.face];
|
|
83
|
+
const present = Object.prototype.hasOwnProperty.call(span.attributes, key);
|
|
84
|
+
if (state === "required" && !present)
|
|
85
|
+
failure("attribute-missing", `${span.rowId} lacks required ${key} on ${span.face}`);
|
|
86
|
+
if (state === "forbidden" && present)
|
|
87
|
+
failure("attribute-forbidden", `${span.rowId} emits forbidden ${key} on ${span.face}`);
|
|
88
|
+
if (present)
|
|
89
|
+
typeCheck(span.attributes[key], declaration.type, declaration.values, key);
|
|
90
|
+
}
|
|
91
|
+
for (const key of Object.keys(span.attributes)) {
|
|
92
|
+
if (!Object.prototype.hasOwnProperty.call(matrix.attributes, key)) {
|
|
93
|
+
failure("attribute-unknown", `${span.rowId} emits unknown attribute ${key}`);
|
|
94
|
+
}
|
|
95
|
+
if (key !== "tag.key_hash" && /(^|[._])tag($|[._])/i.test(key)) {
|
|
96
|
+
failure("raw-tag", `${span.rowId} emits raw tag-like attribute ${key}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (span.attributes.operation !== row.span) {
|
|
100
|
+
failure("operation-row", `${span.rowId} operation must equal the manifest span name`);
|
|
101
|
+
}
|
|
102
|
+
if (span.attributes["span.kind"] !== row.kind) {
|
|
103
|
+
failure("kind-row", `${span.rowId} span.kind must equal the manifest row kind`);
|
|
104
|
+
}
|
|
105
|
+
const expectedPhase = TRANSITION_PHASE[span.rowId];
|
|
106
|
+
if (expectedPhase !== undefined && span.attributes["phase.ordinal"] !== expectedPhase) {
|
|
107
|
+
failure("transition-phase", `${span.rowId} must carry phase.ordinal=${expectedPhase}`);
|
|
108
|
+
}
|
|
109
|
+
// The host-owned rowScope is the authority for member attributes. Do not
|
|
110
|
+
// duplicate a hand-maintained list here: S14 was omitted from such a list
|
|
111
|
+
// once even though it is a real v1 fan-out member. The bundle validator
|
|
112
|
+
// proves rowScope is exactly the complete set of member rows; the runtime
|
|
113
|
+
// verifier therefore uses that same declared scope for the emitted trace.
|
|
114
|
+
const memberIndexScope = matrix.attributes["member.index"]?.rowScope ?? [];
|
|
115
|
+
if (memberIndexScope.includes(span.rowId) && span.attributes["member.index"] === undefined) {
|
|
116
|
+
failure("fanout-member-index", `${span.rowId} must carry member.index`);
|
|
117
|
+
}
|
|
118
|
+
const tagKeyHashScope = matrix.attributes["tag.key_hash"]?.rowScope ?? [];
|
|
119
|
+
if (tagKeyHashScope.includes(span.rowId) && span.attributes["tag.key_hash"] === undefined) {
|
|
120
|
+
failure("fanout-tag-hash", `${span.rowId} must carry tag.key_hash rather than a raw tag`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function instancesByRow(spans) {
|
|
124
|
+
const entries = new Map();
|
|
125
|
+
for (const span of spans) {
|
|
126
|
+
const list = entries.get(span.rowId) ?? [];
|
|
127
|
+
list.push(span);
|
|
128
|
+
entries.set(span.rowId, list);
|
|
129
|
+
}
|
|
130
|
+
return entries;
|
|
131
|
+
}
|
|
132
|
+
function findBoundary(snapshot, name) {
|
|
133
|
+
const boundaries = traceManifest().schemas[snapshot.schema].boundaries;
|
|
134
|
+
const boundary = boundaries?.find((entry) => entry.name === name);
|
|
135
|
+
if (boundary === undefined)
|
|
136
|
+
failure("boundary-missing", `manifest lacks ${snapshot.schema} boundary ${name}`);
|
|
137
|
+
return boundary;
|
|
138
|
+
}
|
|
139
|
+
function expectedConditionalCount(conditional, enabled) {
|
|
140
|
+
const state = enabled ? conditional.whenTrue : conditional.whenFalse;
|
|
141
|
+
if (state === "forbidden")
|
|
142
|
+
return 0;
|
|
143
|
+
return typeof conditional.instanceCount === "number" ? conditional.instanceCount : 1;
|
|
144
|
+
}
|
|
145
|
+
function verifyBoundary(snapshot, options) {
|
|
146
|
+
if (options.boundary === undefined)
|
|
147
|
+
return;
|
|
148
|
+
const boundary = findBoundary(snapshot, options.boundary);
|
|
149
|
+
const instances = instancesByRow(snapshot.spans);
|
|
150
|
+
for (const rowId of boundary.requiredRows) {
|
|
151
|
+
if ((instances.get(rowId)?.length ?? 0) === 0)
|
|
152
|
+
failure("boundary-required", `${boundary.name} requires ${rowId}`);
|
|
153
|
+
}
|
|
154
|
+
for (const rowId of boundary.forbiddenRows) {
|
|
155
|
+
if ((instances.get(rowId)?.length ?? 0) !== 0)
|
|
156
|
+
failure("boundary-forbidden", `${boundary.name} forbids ${rowId}`);
|
|
157
|
+
}
|
|
158
|
+
for (const conditional of boundary.conditionalRows) {
|
|
159
|
+
const enabled = options.conditionals?.[conditional.rowId];
|
|
160
|
+
if (enabled === undefined)
|
|
161
|
+
failure("boundary-conditional-missing", `${boundary.name} needs predicate result for ${conditional.rowId}`);
|
|
162
|
+
const actual = instances.get(conditional.rowId)?.length ?? 0;
|
|
163
|
+
const expected = expectedConditionalCount(conditional, enabled);
|
|
164
|
+
if (actual !== expected) {
|
|
165
|
+
failure("boundary-conditional", `${boundary.name} expects ${conditional.rowId}=${expected}, observed ${actual}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
for (const [rowId, expected] of Object.entries(options.cardinalities ?? {})) {
|
|
169
|
+
const actual = instances.get(rowId)?.length ?? 0;
|
|
170
|
+
if (actual !== expected)
|
|
171
|
+
failure("cardinality", `${rowId} expected ${expected}, observed ${actual}`);
|
|
172
|
+
const members = instances.get(rowId) ?? [];
|
|
173
|
+
if (members.length > 0 && members.every((span) => span.attributes["member.index"] !== undefined)) {
|
|
174
|
+
const indexes = members.map((span) => span.attributes["member.index"]).sort((left, right) => Number(left) - Number(right));
|
|
175
|
+
if (indexes.some((value, index) => value !== index))
|
|
176
|
+
failure("member-index", `${rowId} member.index is not 0..N-1`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function verifyDeclaredCardinality(snapshot) {
|
|
181
|
+
const rows = rowMap(snapshot);
|
|
182
|
+
const instances = instancesByRow(snapshot.spans);
|
|
183
|
+
for (const [rowId, row] of rows) {
|
|
184
|
+
if (!row.successCardinality.startsWith("1"))
|
|
185
|
+
continue;
|
|
186
|
+
const count = instances.get(rowId)?.length ?? 0;
|
|
187
|
+
if (row.successCardinality.includes("per attempt")) {
|
|
188
|
+
const attempts = instances.get(rowId) ?? [];
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
for (const span of attempts) {
|
|
191
|
+
const attempt = span.attributes["attempt.id"];
|
|
192
|
+
if (typeof attempt !== "string")
|
|
193
|
+
failure("attempt-cardinality", `${rowId} needs attempt.id for its per-attempt cardinality`);
|
|
194
|
+
if (seen.has(attempt))
|
|
195
|
+
failure("cardinality-duplicate", `${rowId} repeats attempt ${attempt}`);
|
|
196
|
+
seen.add(attempt);
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
// A conditional/terminal row may legitimately be absent. Repeated
|
|
201
|
+
// caller work is not a duplicate, however, when it is the manifest's
|
|
202
|
+
// explicit retry sequence. In particular S11/S12 can have a second
|
|
203
|
+
// append attempt after a failed member; collapsing it would make the
|
|
204
|
+
// partial-handoff trace lie about the actual remote work.
|
|
205
|
+
if (count > 1) {
|
|
206
|
+
const retryIndexes = instances.get(rowId)
|
|
207
|
+
.map((span) => span.attributes["retry.index"])
|
|
208
|
+
.filter((value) => typeof value === "number");
|
|
209
|
+
const distinct = [...new Set(retryIndexes)].sort((left, right) => left - right);
|
|
210
|
+
const sequential = distinct.length > 0 && distinct.every((value, index) => value === index);
|
|
211
|
+
if (retryIndexes.length !== count || !sequential) {
|
|
212
|
+
failure("cardinality-duplicate", `${rowId} has cardinality ${count} without a 0..n retry.index sequence`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function verifyStructure(snapshot) {
|
|
218
|
+
const rows = rowMap(snapshot);
|
|
219
|
+
const byRoot = new Map();
|
|
220
|
+
for (const span of snapshot.spans) {
|
|
221
|
+
const row = rows.get(span.rowId);
|
|
222
|
+
if (row === undefined)
|
|
223
|
+
failure("row-unknown", `unknown row ${span.rowId}`);
|
|
224
|
+
if (span.schema !== snapshot.schema ||
|
|
225
|
+
span.span !== row.span ||
|
|
226
|
+
span.emitter !== row.emitter ||
|
|
227
|
+
span.logicalParent !== row.logicalParent) {
|
|
228
|
+
failure("row-shape", `row ${span.rowId} differs from the manifest authority`);
|
|
229
|
+
}
|
|
230
|
+
if (span.endMs < span.startMs)
|
|
231
|
+
failure("time-negative", `${span.rowId} ends before it starts`);
|
|
232
|
+
if (span.endMs === span.startMs && (span.zeroDurationPlatformLimited !== true || span.present !== true)) {
|
|
233
|
+
failure("zero-duration-missing", `${span.rowId} needs present=true and zeroDurationPlatformLimited=true for zero duration`);
|
|
234
|
+
}
|
|
235
|
+
verifyAttributes(span, row);
|
|
236
|
+
const list = byRoot.get(span.rootId) ?? [];
|
|
237
|
+
list.push(span);
|
|
238
|
+
byRoot.set(span.rootId, list);
|
|
239
|
+
}
|
|
240
|
+
for (const [rootId, spans] of byRoot) {
|
|
241
|
+
// S16 is a provider-linked remote-invocation universe. It is correlated
|
|
242
|
+
// through Cloudflare's active async context, not a synthetic local root.
|
|
243
|
+
if (spans.every((span) => span.logicalParent === "provider-subrequest"))
|
|
244
|
+
continue;
|
|
245
|
+
for (const child of spans) {
|
|
246
|
+
if (child.logicalParent === null || child.logicalParent === "provider-subrequest")
|
|
247
|
+
continue;
|
|
248
|
+
const parents = spans.filter((candidate) => candidate.rowId === child.logicalParent);
|
|
249
|
+
if (parents.length === 0) {
|
|
250
|
+
const otherRoot = snapshot.spans.find((candidate) => candidate.rootId !== rootId && candidate.rowId === child.logicalParent);
|
|
251
|
+
if (otherRoot !== undefined)
|
|
252
|
+
failure("cross-root-parent", `${child.rowId} points to parent ${child.logicalParent} in another root`);
|
|
253
|
+
failure("parent-missing", `${child.rowId} lacks parent ${child.logicalParent}`);
|
|
254
|
+
}
|
|
255
|
+
const parent = parents.find((candidate) => child.startMs >= candidate.startMs && child.endMs <= candidate.endMs);
|
|
256
|
+
if (parent === undefined) {
|
|
257
|
+
const temporal = parents[0];
|
|
258
|
+
if (child.startMs < temporal.startMs || child.endMs > temporal.endMs) {
|
|
259
|
+
failure("parent-containment", `${child.rowId} is not temporally contained by ${child.logicalParent}`);
|
|
260
|
+
}
|
|
261
|
+
failure("parent-missing", `${child.rowId} cannot resolve parent ${child.logicalParent}`);
|
|
262
|
+
}
|
|
263
|
+
if (parent.clockDomain !== child.clockDomain) {
|
|
264
|
+
failure("clock-domain-mix", `${child.rowId} mixes ${child.clockDomain} with parent ${parent.clockDomain}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const roots = spans.filter((span) => span.logicalParent === null);
|
|
268
|
+
if (roots.length !== 1)
|
|
269
|
+
failure("root-cardinality", `trace root ${rootId} has ${roots.length} roots`);
|
|
270
|
+
}
|
|
271
|
+
const repairLeases = snapshot.spans.filter((span) => span.rowId === "X02");
|
|
272
|
+
for (const item of snapshot.spans.filter((span) => span.rowId === "X03e")) {
|
|
273
|
+
const leaseId = item.attributes["repair.lease.id"];
|
|
274
|
+
const tagHash = item.attributes["tag.key_hash"];
|
|
275
|
+
if (typeof leaseId !== "string" || typeof tagHash !== "string") {
|
|
276
|
+
failure("repair-link-attributes", "X03e needs repair.lease.id and tag.key_hash");
|
|
277
|
+
}
|
|
278
|
+
if (!repairLeases.some((lease) => lease.attributes["repair.lease.id"] === leaseId && lease.attributes["tag.key_hash"] === tagHash)) {
|
|
279
|
+
failure("repair-link", "X03e must link to an X02 lease by repair.lease.id and tag.key_hash");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
export function verifyCommitTrace(snapshot, options = {}) {
|
|
284
|
+
verifyStructure(snapshot);
|
|
285
|
+
verifyDeclaredCardinality(snapshot);
|
|
286
|
+
verifyBoundary(snapshot, options);
|
|
287
|
+
if (options.accepted === true) {
|
|
288
|
+
const unattributed = calculateUnattributedRatio(snapshot);
|
|
289
|
+
if (unattributed.unattributedRatio > 0.05) {
|
|
290
|
+
failure("unattributed-over-budget", `unattributed ratio ${unattributed.unattributedRatio} exceeds 0.05`);
|
|
291
|
+
}
|
|
292
|
+
return Object.freeze({ rows: snapshot.spans.length, unattributed });
|
|
293
|
+
}
|
|
294
|
+
return Object.freeze({ rows: snapshot.spans.length });
|
|
295
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Separate Workers Logs observation stream for SDT-G30.
|
|
3
|
+
*
|
|
4
|
+
* This deliberately is not a CommitTrace span and never adds an attribute to
|
|
5
|
+
* the sealed sdt.commit/v1 matrix. Structured console events carry provider
|
|
6
|
+
* request metadata but Workers Logs does not expose a trace id for them. The
|
|
7
|
+
* exporter joins existing post-admission/attempt correlation to S00 and fails
|
|
8
|
+
* closed when that chain or the client-ledger identity is absent.
|
|
9
|
+
*
|
|
10
|
+
* The stream is observation-only: it does not write Durable Object storage,
|
|
11
|
+
* decide a control branch, or contribute to a public response.
|
|
12
|
+
*/
|
|
13
|
+
import { type CommitTraceActorClass, type DurableObjectActivationObservation } from "./CommitTrace";
|
|
14
|
+
export declare const OBSERVATION_SCHEMA: "sdt.observe/v1";
|
|
15
|
+
export type ObservationActorClass = "WORKER" | Exclude<CommitTraceActorClass, "ROOT" | "REPAIR">;
|
|
16
|
+
export type ObservationEvent = Readonly<{
|
|
17
|
+
schema: typeof OBSERVATION_SCHEMA;
|
|
18
|
+
event: "worker.invocation";
|
|
19
|
+
emittedAtMs: number;
|
|
20
|
+
/** Provider-owned ingress ray retained only in the observation stream. */
|
|
21
|
+
requestId: string;
|
|
22
|
+
/** Existing post-admission trace correlation; not a new wire field. */
|
|
23
|
+
correlationId: string;
|
|
24
|
+
actorClass: "WORKER";
|
|
25
|
+
/**
|
|
26
|
+
* Worker-local native span callbacks entered for this accepted request.
|
|
27
|
+
* This is an observation-only set used to classify a later missing
|
|
28
|
+
* exported row; it never supplies a completeness pass.
|
|
29
|
+
*/
|
|
30
|
+
emittedWorkerRowIds: readonly string[];
|
|
31
|
+
isolateInstanceId: string;
|
|
32
|
+
activationFirst: boolean;
|
|
33
|
+
/** Overlaps S00 and is cross-checked by the exported evidence contract. */
|
|
34
|
+
scriptVersion?: string;
|
|
35
|
+
/** Overlaps S00 and is cross-checked by the exported evidence contract. */
|
|
36
|
+
colo?: string;
|
|
37
|
+
storageWrites: 0;
|
|
38
|
+
usedForControl: false;
|
|
39
|
+
exposedInPublicResponse: false;
|
|
40
|
+
}> | Readonly<{
|
|
41
|
+
schema: typeof OBSERVATION_SCHEMA;
|
|
42
|
+
event: "do.handler";
|
|
43
|
+
emittedAtMs: number;
|
|
44
|
+
/** Existing attempt-derived trace correlation when actor identity exists. */
|
|
45
|
+
correlationId?: string;
|
|
46
|
+
actorClass: Exclude<ObservationActorClass, "WORKER">;
|
|
47
|
+
activationId: string;
|
|
48
|
+
activationFirst: boolean;
|
|
49
|
+
constructorToHandlerMs: number;
|
|
50
|
+
firstStorageReadMs: number | null;
|
|
51
|
+
subrequestWallMs: number | null;
|
|
52
|
+
storageWrites: 0;
|
|
53
|
+
usedForControl: false;
|
|
54
|
+
exposedInPublicResponse: false;
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
schema: typeof OBSERVATION_SCHEMA;
|
|
57
|
+
event: "fault.barrier";
|
|
58
|
+
emittedAtMs: number;
|
|
59
|
+
/** Existing downstream-attempt correlation when the test seam has one. */
|
|
60
|
+
correlationId?: string;
|
|
61
|
+
barrierId: string;
|
|
62
|
+
stage: "started" | "ended" | "drained";
|
|
63
|
+
boundedWindowMs: number;
|
|
64
|
+
storageWrites: 0;
|
|
65
|
+
usedForControl: false;
|
|
66
|
+
exposedInPublicResponse: false;
|
|
67
|
+
}>;
|
|
68
|
+
export interface ObservationLogSink {
|
|
69
|
+
emit(event: ObservationEvent): void;
|
|
70
|
+
}
|
|
71
|
+
/** A log transport failure is itself non-semantic. */
|
|
72
|
+
export declare function emitObservation(event: ObservationEvent, sink?: ObservationLogSink): void;
|
|
73
|
+
export declare function observeWorkerInvocation(input: Readonly<{
|
|
74
|
+
isolateInstanceId: string;
|
|
75
|
+
firstInvocation: boolean;
|
|
76
|
+
requestId: string;
|
|
77
|
+
correlationId: string;
|
|
78
|
+
emittedWorkerRowIds: readonly string[];
|
|
79
|
+
scriptVersion?: string;
|
|
80
|
+
colo?: string;
|
|
81
|
+
}>, sink?: ObservationLogSink): void;
|
|
82
|
+
/**
|
|
83
|
+
* One handler-local stopwatch. It is created after the constructor-derived
|
|
84
|
+
* activation fact and is passed explicitly; there is no module/global
|
|
85
|
+
* request state and no durable persistence.
|
|
86
|
+
*/
|
|
87
|
+
export declare class DurableObjectHandlerObservation {
|
|
88
|
+
private readonly actorClass;
|
|
89
|
+
private readonly activation;
|
|
90
|
+
private readonly sink?;
|
|
91
|
+
private firstStorageReadMs;
|
|
92
|
+
private subrequestWallMs;
|
|
93
|
+
private observedSubrequest;
|
|
94
|
+
private finished;
|
|
95
|
+
private correlationId;
|
|
96
|
+
constructor(actorClass: Exclude<ObservationActorClass, "WORKER">, activation: DurableObjectActivationObservation, sink?: ObservationLogSink | undefined);
|
|
97
|
+
/** Call immediately before the first durable read/transaction starts. */
|
|
98
|
+
markFirstStorageRead(): void;
|
|
99
|
+
/** Measures an actual awaited subrequest, never a declared duration. */
|
|
100
|
+
subrequest<T>(callback: () => Promise<T>): Promise<T>;
|
|
101
|
+
/**
|
|
102
|
+
* Actor identity is decoded from the existing body before the callback.
|
|
103
|
+
* Retaining its established trace correlation in the log avoids a new
|
|
104
|
+
* propagation header, durable write, or public response field.
|
|
105
|
+
*/
|
|
106
|
+
bindCorrelation(correlationId: string | undefined): void;
|
|
107
|
+
/** Emits at most once and only after the native actor callback settles. */
|
|
108
|
+
finish(): void;
|
|
109
|
+
}
|
|
110
|
+
export declare function beginDurableObjectHandlerObservation(actorClass: Exclude<ObservationActorClass, "WORKER">, activation: DurableObjectActivationObservation, sink?: ObservationLogSink): DurableObjectHandlerObservation;
|
|
111
|
+
/** Test seams may record bounded fault lifecycle facts without a V1 extension. */
|
|
112
|
+
export declare function observeFaultBarrier(input: Readonly<{
|
|
113
|
+
barrierId: string;
|
|
114
|
+
stage: "started" | "ended" | "drained";
|
|
115
|
+
boundedWindowMs: number;
|
|
116
|
+
/** Existing downstream attempt identity available only to the test seam. */
|
|
117
|
+
attemptId?: string;
|
|
118
|
+
}>, sink?: ObservationLogSink): void;
|