Construct integer formats directly while preserving bounds, refinements, metadata and current shared schema owners. Keep Incur-dependent CLI numeric coercion declarations unchanged. Verify canonical advertisements, 126 numeric boundary cases, 974 actual CLI parser cases, broad source tests and real public-artifact SDK workflows. Record 72 normal tasks and 12 separate owned-inspector heap diagnostics with whole-family resource bounds; distinguish SDK spans and asymmetric audit overhead. Generate numerical report sections from receipts and reject stale tables through documentation conformance checks. Closes #6236. Current-head CI and Greptile pass; actionable review findings are addressed. Codex review was unavailable due repository usage limits.
207 lines
6.4 KiB
TypeScript
207 lines
6.4 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import { jsonValueSchema, type JsonValue } from "../jsonValue.js";
|
|
import type {
|
|
TerminalFrame,
|
|
UnverifiedProcessCapture,
|
|
} from "./processCapture.js";
|
|
|
|
/** Project normalized PTY facts without source text used only for audit. */
|
|
export const comparableTerminalFrame = (frame: TerminalFrame) => ({
|
|
sequence: frame.sequence,
|
|
at_ms: frame.at_ms,
|
|
data: frame.data,
|
|
});
|
|
|
|
/** Process-capture observation families shared by live drivers and trace assertions. */
|
|
export const processObservationSourceSchema = z.enum([
|
|
"terminal_raw",
|
|
"terminal_rendered",
|
|
"interaction",
|
|
"lifecycle",
|
|
"process",
|
|
"filesystem",
|
|
]);
|
|
export type ProcessObservationSource = z.infer<
|
|
typeof processObservationSourceSchema
|
|
>;
|
|
|
|
/** Stable raw-record location within one Process Capture observation journal. */
|
|
export const processObservationLocationSchema = z.strictObject({
|
|
collection: z.enum([
|
|
"frames",
|
|
"rendered_frames",
|
|
"interaction_events",
|
|
"lifecycle",
|
|
"process_samples",
|
|
"filesystem_checkpoints",
|
|
]),
|
|
index: z.int().nonnegative(),
|
|
capture_order: z.int().nonnegative(),
|
|
});
|
|
export type ProcessObservationLocation = z.infer<
|
|
typeof processObservationLocationSchema
|
|
>;
|
|
|
|
/** Provider-neutral event projected into an offline trace assertion. */
|
|
export interface ProcessObservation {
|
|
readonly event_id: string;
|
|
readonly source: ProcessObservationSource;
|
|
readonly source_sequence: number;
|
|
readonly capture_order: number;
|
|
readonly captured_at_ms: number | null;
|
|
readonly subject_id: string | null;
|
|
readonly location: ProcessObservationLocation;
|
|
readonly payload: JsonValue;
|
|
}
|
|
|
|
/** Input used by live producers to construct the same observation shape. */
|
|
export interface ProcessObservationInput {
|
|
readonly source: ProcessObservationSource;
|
|
readonly source_sequence: number;
|
|
readonly captured_at_ms: number | null;
|
|
readonly subject_id: string | null;
|
|
readonly location: ProcessObservationLocation;
|
|
readonly payload: unknown;
|
|
}
|
|
|
|
/** Remove only explicitly declared top-level volatile fields before matching. */
|
|
export const comparableProcessObservationPayload = (
|
|
value: unknown,
|
|
ignoredFields: readonly string[] = [],
|
|
): unknown => {
|
|
if (
|
|
ignoredFields.length === 0 ||
|
|
typeof value !== "object" ||
|
|
value === null ||
|
|
Array.isArray(value)
|
|
)
|
|
return value;
|
|
return Object.fromEntries(
|
|
Object.entries(value).filter(([name]) => !ignoredFields.includes(name)),
|
|
);
|
|
};
|
|
|
|
/** Construct a validated observation from one live producer record. */
|
|
export const createProcessObservation = (
|
|
input: ProcessObservationInput,
|
|
): ProcessObservation => ({
|
|
event_id: `obs.${input.location.collection}.${String(input.location.index)}`,
|
|
source: input.source,
|
|
source_sequence: input.source_sequence,
|
|
capture_order: input.location.capture_order,
|
|
captured_at_ms: input.captured_at_ms,
|
|
subject_id: input.subject_id,
|
|
location: input.location,
|
|
payload: jsonValueSchema.parse(input.payload),
|
|
});
|
|
|
|
type ProjectedRecord = Omit<
|
|
ProcessObservation,
|
|
"event_id" | "source_sequence" | "capture_order" | "location"
|
|
>;
|
|
|
|
const atMilliseconds = (value: unknown): number | null => {
|
|
if (typeof value !== "object" || value === null) return null;
|
|
if ("at_ms" in value && isSafeMillisecond(value.at_ms)) return value.at_ms;
|
|
if ("dispatched_at_ms" in value && isSafeMillisecond(value.dispatched_at_ms))
|
|
return value.dispatched_at_ms;
|
|
return null;
|
|
};
|
|
|
|
const isSafeMillisecond = (value: unknown): value is number =>
|
|
typeof value === "number" && Number.isSafeInteger(value);
|
|
|
|
/** Derive the stable capture-local identity for one normalized observation. */
|
|
export const processObservationSubject = (
|
|
source: ProcessObservationSource,
|
|
value: unknown,
|
|
): string | null => {
|
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
return null;
|
|
if (source === "process" && "pid" in value && typeof value.pid === "number")
|
|
return `process:${String(value.pid)}`;
|
|
if (
|
|
source === "filesystem" &&
|
|
"name" in value &&
|
|
typeof value.name === "string"
|
|
)
|
|
return `checkpoint:${value.name}`;
|
|
return null;
|
|
};
|
|
|
|
const projectedRecord = (
|
|
capture: UnverifiedProcessCapture,
|
|
location: ProcessObservationLocation,
|
|
): ProjectedRecord | null => {
|
|
const projected = (() => {
|
|
switch (location.collection) {
|
|
case "frames": {
|
|
const frame = capture.frames[location.index];
|
|
return {
|
|
source: "terminal_raw" as const,
|
|
value:
|
|
frame === undefined ? undefined : comparableTerminalFrame(frame),
|
|
};
|
|
}
|
|
case "rendered_frames":
|
|
return {
|
|
source: "terminal_rendered" as const,
|
|
value: capture.rendered_frames[location.index],
|
|
};
|
|
case "interaction_events":
|
|
return {
|
|
source: "interaction" as const,
|
|
value: capture.interaction_events[location.index],
|
|
};
|
|
case "lifecycle":
|
|
return location.index === 0
|
|
? {
|
|
source: "lifecycle" as const,
|
|
value: { event: "exit", ...capture.exit },
|
|
}
|
|
: location.index === 1
|
|
? {
|
|
source: "lifecycle" as const,
|
|
value: { event: "settlement", ...capture.settlement },
|
|
}
|
|
: null;
|
|
case "process_samples":
|
|
return {
|
|
source: "process" as const,
|
|
value: capture.process_samples[location.index],
|
|
};
|
|
case "filesystem_checkpoints":
|
|
return {
|
|
source: "filesystem" as const,
|
|
value: capture.filesystem_checkpoints[location.index],
|
|
};
|
|
}
|
|
})();
|
|
if (projected === null || projected.value === undefined) return null;
|
|
const payload = jsonValueSchema.parse(projected.value);
|
|
return {
|
|
source: projected.source,
|
|
captured_at_ms: atMilliseconds(payload),
|
|
subject_id: processObservationSubject(projected.source, payload),
|
|
payload,
|
|
};
|
|
};
|
|
|
|
/** Project one validated capture-journal reference into the shared observation shape. */
|
|
export const projectProcessObservation = (
|
|
capture: UnverifiedProcessCapture,
|
|
location: ProcessObservationLocation,
|
|
): ProcessObservation | null => {
|
|
const projected = projectedRecord(capture, location);
|
|
if (projected === null) return null;
|
|
return createProcessObservation({
|
|
source: projected.source,
|
|
source_sequence: location.index,
|
|
captured_at_ms: projected.captured_at_ms,
|
|
subject_id: projected.subject_id,
|
|
location,
|
|
payload: projected.payload,
|
|
});
|
|
};
|