@oscharko-dev/keiko-contracts 0.2.6 → 0.2.7

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.
@@ -0,0 +1,148 @@
1
+ export declare const CONTEXT_ENGINEERING_SCHEMA_VERSION: "1";
2
+ export declare const DEFAULT_TOKEN_ESTIMATOR_ID: "keiko-conservative-utf8-v1";
3
+ export type ContextLaneId = "system-contract" | "user-task" | "active-plan" | "repo-evidence" | "tool-observations" | "working-memory" | "history-summary" | "verification-evidence";
4
+ export declare const CONTEXT_LANE_IDS: readonly ContextLaneId[];
5
+ export type ContextEvictionPolicy = "none" | "summarize-then-drop" | "drop-oldest" | "drop-lowest-score";
6
+ export declare const CONTEXT_EVICTION_POLICIES: readonly ContextEvictionPolicy[];
7
+ export type ContextBudgetPressure = "low" | "moderate" | "high" | "exceeded";
8
+ export interface ContextModelMetadata {
9
+ readonly id?: string | undefined;
10
+ readonly provider?: string | undefined;
11
+ readonly notes?: string | undefined;
12
+ }
13
+ export interface ContextProfile {
14
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
15
+ readonly maxInputTokens: number;
16
+ readonly reservedOutputTokens: number;
17
+ readonly safetyMarginTokens: number;
18
+ readonly effectiveInputBudget: number;
19
+ readonly tokenEstimatorId: string;
20
+ readonly model?: ContextModelMetadata | undefined;
21
+ }
22
+ export declare const DEFAULT_CONTEXT_PROFILE: ContextProfile;
23
+ export interface ContextLaneBudget {
24
+ readonly laneId: ContextLaneId;
25
+ readonly priority: number;
26
+ readonly maxTokens: number;
27
+ readonly minReservedTokens: number;
28
+ readonly eviction: ContextEvictionPolicy;
29
+ }
30
+ export interface ContextBudget {
31
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
32
+ readonly profile: ContextProfile;
33
+ readonly lanes: readonly ContextLaneBudget[];
34
+ }
35
+ export interface ContextLane {
36
+ readonly id: ContextLaneId;
37
+ readonly purpose: string;
38
+ readonly priority: number;
39
+ readonly budget: ContextLaneBudget;
40
+ readonly diagnostics?: ContextLaneDiagnostics | undefined;
41
+ }
42
+ export interface ContextLaneDiagnostics {
43
+ readonly laneId: ContextLaneId;
44
+ readonly estimatedTokens: number;
45
+ readonly includedItems: number;
46
+ readonly excludedItems: number;
47
+ readonly budgetPressure: ContextBudgetPressure;
48
+ readonly compactionReason?: string | undefined;
49
+ readonly provenanceCounts?: Readonly<Record<string, number>> | undefined;
50
+ }
51
+ export interface ContextAssemblyDiagnostics {
52
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
53
+ readonly profile: ContextProfile;
54
+ readonly totalEstimatedTokens: number;
55
+ readonly budgetPressure: ContextBudgetPressure;
56
+ readonly lanes: readonly ContextLaneDiagnostics[];
57
+ readonly orderedForRecency: boolean;
58
+ }
59
+ export type ContextProvenanceRefKind = "repo-file" | "tool-result" | "evidence-atom" | "message";
60
+ export interface ContextProvenanceRef {
61
+ readonly kind: ContextProvenanceRefKind;
62
+ readonly stableId: string;
63
+ readonly scopePath?: string | undefined;
64
+ readonly lineRange?: {
65
+ readonly startLine: number;
66
+ readonly endLine: number;
67
+ } | undefined;
68
+ readonly contentHash?: string | undefined;
69
+ readonly evidenceAtomId?: string | undefined;
70
+ readonly notPersistedReason?: string | undefined;
71
+ }
72
+ export interface ContextPreservedFact {
73
+ readonly statement: string;
74
+ readonly sourceRef?: ContextProvenanceRef | undefined;
75
+ readonly inferred?: boolean | undefined;
76
+ readonly corroborating?: readonly ContextProvenanceRef[] | undefined;
77
+ readonly rationale?: never;
78
+ readonly confidence?: never;
79
+ }
80
+ export interface ContextAssumption {
81
+ readonly statement: string;
82
+ readonly rationale: string;
83
+ readonly confidence: "low" | "medium" | "high";
84
+ readonly sourceRef?: never;
85
+ readonly inferred?: never;
86
+ }
87
+ export interface ContextUserConstraint {
88
+ readonly statement: string;
89
+ readonly sourceRef?: ContextProvenanceRef | undefined;
90
+ }
91
+ export interface ContextCommandOutcome {
92
+ readonly command: string;
93
+ readonly exitCode: number;
94
+ readonly summary: string;
95
+ }
96
+ export interface ContextInvalidationKey {
97
+ readonly scopePath: string;
98
+ readonly contentHash: string;
99
+ }
100
+ export interface ContextCompactionRecord {
101
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
102
+ readonly laneId: ContextLaneId;
103
+ readonly reason: string;
104
+ readonly itemsBefore: number;
105
+ readonly itemsAfter: number;
106
+ readonly tokensBefore: number;
107
+ readonly tokensAfter: number;
108
+ readonly summaryRefHash?: string | undefined;
109
+ readonly rehydration?: ContextRehydrationHandle | undefined;
110
+ readonly orderedAt?: number | undefined;
111
+ readonly sourceSpans?: readonly ContextProvenanceRef[] | undefined;
112
+ readonly preservedFacts?: readonly ContextPreservedFact[] | undefined;
113
+ readonly assumptions?: readonly ContextAssumption[] | undefined;
114
+ readonly userConstraints?: readonly ContextUserConstraint[] | undefined;
115
+ readonly decisions?: readonly string[] | undefined;
116
+ readonly openQuestions?: readonly string[] | undefined;
117
+ readonly filesInspected?: readonly string[] | undefined;
118
+ readonly filesChanged?: readonly string[] | undefined;
119
+ readonly commandOutcomes?: readonly ContextCommandOutcome[] | undefined;
120
+ readonly failingTests?: readonly string[] | undefined;
121
+ readonly droppedCategories?: readonly string[] | undefined;
122
+ readonly invalidationKeys?: readonly ContextInvalidationKey[] | undefined;
123
+ }
124
+ export interface ContextRehydrationHandle {
125
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
126
+ readonly laneId: ContextLaneId;
127
+ readonly handleId: string;
128
+ readonly itemCount: number;
129
+ readonly approxTokens: number;
130
+ readonly kind?: ContextProvenanceRefKind | undefined;
131
+ readonly scopePath?: string | undefined;
132
+ readonly lineRange?: {
133
+ readonly startLine: number;
134
+ readonly endLine: number;
135
+ } | undefined;
136
+ readonly contentHash?: string | undefined;
137
+ readonly evidenceAtomId?: string | undefined;
138
+ readonly notPersistedReason?: string | undefined;
139
+ readonly approvedSummary?: string | undefined;
140
+ }
141
+ export declare function estimateTokens(text: string): number;
142
+ export declare function estimateTokensForSegments(segments: readonly string[]): number;
143
+ export declare function deriveContextProfile(input: {
144
+ readonly maxInputTokens: number;
145
+ readonly reservedOutputTokens: number;
146
+ readonly safetyMarginTokens: number;
147
+ }): ContextProfile;
148
+ //# sourceMappingURL=context-engineering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-engineering.d.ts","sourceRoot":"","sources":["../src/context-engineering.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ // Pure readonly contracts for the deterministic context-engineering layer (ADR-0052). No IO,
2
+ // no clock, no randomness, no sibling @oscharko-dev/keiko-* import (contracts is a strict leaf).
3
+ // estimateTokens is the single canonical token currency; the allocator that consumes
4
+ // ContextProfile lives in keiko-workflows. Validators follow the connected-context.ts
5
+ // isRecord + predicate envelope and live in the sibling context-engineering-validation.ts to
6
+ // keep both files under the 400-LOC budget (mirrors the memory-validation.ts split).
7
+ export const CONTEXT_ENGINEERING_SCHEMA_VERSION = "1";
8
+ // Provenance string recording which estimator produced a profile's counts. The estimator
9
+ // function itself cannot be a JSON-serializable contract field, so the id is carried instead.
10
+ export const DEFAULT_TOKEN_ESTIMATOR_ID = "keiko-conservative-utf8-v1";
11
+ export const CONTEXT_LANE_IDS = [
12
+ "system-contract",
13
+ "user-task",
14
+ "active-plan",
15
+ "repo-evidence",
16
+ "tool-observations",
17
+ "working-memory",
18
+ "history-summary",
19
+ "verification-evidence",
20
+ ];
21
+ export const CONTEXT_EVICTION_POLICIES = [
22
+ "none",
23
+ "summarize-then-drop",
24
+ "drop-oldest",
25
+ "drop-lowest-score",
26
+ ];
27
+ // Conservative defaults. 128k window, 8k reserved for output, 4k safety margin =>
28
+ // 116k effective input budget. Frozen. `model` is intentionally omitted (optional).
29
+ export const DEFAULT_CONTEXT_PROFILE = {
30
+ schemaVersion: CONTEXT_ENGINEERING_SCHEMA_VERSION,
31
+ maxInputTokens: 128_000,
32
+ reservedOutputTokens: 8_000,
33
+ safetyMarginTokens: 4_000,
34
+ effectiveInputBudget: 116_000,
35
+ tokenEstimatorId: DEFAULT_TOKEN_ESTIMATOR_ID,
36
+ };
37
+ // ─── Canonical token estimator (the single token currency) ─────────────────── [PR1]
38
+ // Deterministic, conservative (slightly over-estimates), total (never throws), offline.
39
+ //
40
+ // bytes-per-token divisor. Deliberately SMALLER than the repo's looser bytes/4 norm so the
41
+ // estimate over-counts versus a typical provider tokenization. Over-estimation is the safe
42
+ // direction: the allocator fits fewer tokens than the provider would, never more.
43
+ const TOKEN_BYTES_PER_TOKEN_DIVISOR = 3.5;
44
+ // Small fixed structural overhead per segment, modelling per-message framing. Empty input
45
+ // returns exactly this (never 0 / NaN).
46
+ const TOKEN_STRUCTURAL_OVERHEAD = 2;
47
+ // Mirrors conversation-budget.ts utf8ByteLength: TextEncoder when available, char-length
48
+ // fallback for any legacy harness without it. Never throws.
49
+ function utf8ByteLength(text) {
50
+ if (typeof TextEncoder !== "undefined") {
51
+ return new TextEncoder().encode(text).length;
52
+ }
53
+ return text.length;
54
+ }
55
+ export function estimateTokens(text) {
56
+ const bytes = utf8ByteLength(text);
57
+ return TOKEN_STRUCTURAL_OVERHEAD + Math.ceil(bytes / TOKEN_BYTES_PER_TOKEN_DIVISOR);
58
+ }
59
+ // Sum estimateTokens over a set of segments (e.g. messages). The per-segment overhead models
60
+ // per-message framing. Total / never throws on [] or empty segments.
61
+ export function estimateTokensForSegments(segments) {
62
+ let total = 0;
63
+ for (const segment of segments) {
64
+ total += estimateTokens(segment);
65
+ }
66
+ return total;
67
+ }
68
+ // Derives effectiveInputBudget = maxInputTokens − reservedOutputTokens − safetyMarginTokens,
69
+ // clamped to >= 0. Pure. Used to build a ContextProfile from a customer model window override.
70
+ export function deriveContextProfile(input) {
71
+ const effective = Math.max(0, input.maxInputTokens - input.reservedOutputTokens - input.safetyMarginTokens);
72
+ return {
73
+ schemaVersion: CONTEXT_ENGINEERING_SCHEMA_VERSION,
74
+ maxInputTokens: input.maxInputTokens,
75
+ reservedOutputTokens: input.reservedOutputTokens,
76
+ safetyMarginTokens: input.safetyMarginTokens,
77
+ effectiveInputBudget: effective,
78
+ tokenEstimatorId: DEFAULT_TOKEN_ESTIMATOR_ID,
79
+ };
80
+ }
@@ -0,0 +1,9 @@
1
+ import type { ContextValidationResult } from "./context-engineering-validation.js";
2
+ export declare function isContextToolObservationKind(value: unknown): boolean;
3
+ export declare function validateContextToolRehydrationHandle(value: unknown): ContextValidationResult;
4
+ export declare function validateShapedCommandObservation(value: unknown): ContextValidationResult;
5
+ export declare function validateShapedTestObservation(value: unknown): ContextValidationResult;
6
+ export declare function validateShapedSearchObservation(value: unknown): ContextValidationResult;
7
+ export declare function validateShapedBrowserObservation(value: unknown): ContextValidationResult;
8
+ export declare function validateContextToolObservation(value: unknown): ContextValidationResult;
9
+ //# sourceMappingURL=context-observations-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-observations-validation.d.ts","sourceRoot":"","sources":["../src/context-observations-validation.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AA6CnF,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpE;AA0BD,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAE5F;AAqED,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAQxF;AA4DD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAQrF;AA6CD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAQvF;AAwBD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAQxF;AAGD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAgBtF"}
@@ -0,0 +1,252 @@
1
+ // Pure structural validators for the shaped tool-observation contracts (ADR-0054, PR3-W1). No
2
+ // filesystem, no clock, no crypto, no randomness — every helper inspects the structure of an
3
+ // `unknown` payload and reports which invariants failed. Follows the connected-context.ts isRecord
4
+ // + predicate envelope and reuses ContextValidationResult. STRUCTURAL ONLY: shape, finite
5
+ // non-negative numbers, bounded counts within the MAX_* constants, valid stream enum, valid
6
+ // laneId/kind. Policy (e.g. which tools may be shaped) is NOT enforced here.
7
+ //
8
+ // Split from context-observations.ts to keep both files under the 400-LOC budget (mirrors the
9
+ // context-engineering-validation.ts split).
10
+ import { CONTEXT_ENGINEERING_SCHEMA_VERSION } from "./context-engineering.js";
11
+ import { MAX_FAILING_TEST_NAMES, MAX_OBSERVATION_EXCERPT_BYTES, MAX_OBSERVATION_QUERY_BYTES, MAX_STACK_FRAME_LINES, MAX_TOP_RANGES, } from "./context-observations.js";
12
+ import { isContextLaneId } from "./context-engineering-validation.js";
13
+ const TOOL_OBSERVATION_KINDS = ["command", "test", "search", "browser"];
14
+ const STREAMS = ["stdout", "stderr"];
15
+ // ─── Shared primitives (local; contracts is a leaf, no shared-util import) ──────
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null;
18
+ }
19
+ function isFiniteNonNegativeNumber(value) {
20
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
21
+ }
22
+ function isExitCode(value) {
23
+ return value === null || (typeof value === "number" && Number.isFinite(value));
24
+ }
25
+ function isNonEmptyTrimmed(value) {
26
+ return typeof value === "string" && value.trim().length > 0;
27
+ }
28
+ function isOptionalFiniteNonNegativeNumber(value) {
29
+ return value === undefined || isFiniteNonNegativeNumber(value);
30
+ }
31
+ function isOptionalBoolean(value) {
32
+ return value === undefined || typeof value === "boolean";
33
+ }
34
+ function isOptionalNonEmptyString(value) {
35
+ return value === undefined || isNonEmptyTrimmed(value);
36
+ }
37
+ function pushIf(reasons, condition, reason) {
38
+ if (condition) {
39
+ reasons.push(reason);
40
+ }
41
+ }
42
+ function buildResult(reasons) {
43
+ return reasons.length === 0 ? { ok: true } : { ok: false, reasons };
44
+ }
45
+ // ─── Kind guard ──────────────────────────────────────────────────────────────
46
+ export function isContextToolObservationKind(value) {
47
+ return typeof value === "string" && TOOL_OBSERVATION_KINDS.includes(value);
48
+ }
49
+ // ─── ContextToolRehydrationHandle ──────────────────────────────────────────────
50
+ function collectRehydration(value, prefix) {
51
+ if (!isRecord(value)) {
52
+ return [`${prefix} invalid`];
53
+ }
54
+ const reasons = [];
55
+ pushIf(reasons, value.schemaVersion !== CONTEXT_ENGINEERING_SCHEMA_VERSION, `${prefix}.schemaVersion mismatch`);
56
+ pushIf(reasons, !isContextLaneId(value.laneId), `${prefix}.laneId invalid`);
57
+ pushIf(reasons, value.kind !== "tool-result", `${prefix}.kind invalid`);
58
+ pushIf(reasons, !isNonEmptyTrimmed(value.artifactId), `${prefix}.artifactId invalid`);
59
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.itemCount), `${prefix}.itemCount invalid`);
60
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.approxTokens), `${prefix}.approxTokens invalid`);
61
+ pushIf(reasons, !isOptionalNonEmptyString(value.notPersistedReason), `${prefix}.notPersistedReason invalid`);
62
+ return reasons;
63
+ }
64
+ export function validateContextToolRehydrationHandle(value) {
65
+ return buildResult(collectRehydration(value, "rehydration"));
66
+ }
67
+ function collectOptionalRehydration(value, prefix) {
68
+ return value === undefined ? [] : collectRehydration(value, prefix);
69
+ }
70
+ // ─── Shared injection-signal optionals (command/test/search/browser) ────────────
71
+ function collectInjectionOptionals(value, prefix) {
72
+ const reasons = [];
73
+ pushIf(reasons, !isOptionalFiniteNonNegativeNumber(value.injectionSignalCount), `${prefix}.injectionSignalCount invalid`);
74
+ pushIf(reasons, !isOptionalBoolean(value.hasCriticalInjectionSignal), `${prefix}.hasCriticalInjectionSignal invalid`);
75
+ return reasons;
76
+ }
77
+ // ─── ShapedStreamExcerpt ────────────────────────────────────────────────────────
78
+ function collectExcerpts(value, prefix) {
79
+ if (!Array.isArray(value)) {
80
+ return [`${prefix}.excerpts invalid`];
81
+ }
82
+ const reasons = [];
83
+ let totalBytes = 0;
84
+ value.forEach((entry, index) => {
85
+ const at = `${prefix}.excerpts[${String(index)}]`;
86
+ if (!isRecord(entry)) {
87
+ reasons.push(`${at} invalid`);
88
+ return;
89
+ }
90
+ pushIf(reasons, typeof entry.stream !== "string" || !STREAMS.includes(entry.stream), `${at}.stream invalid`);
91
+ pushIf(reasons, !isFiniteNonNegativeNumber(entry.bytes), `${at}.bytes invalid`);
92
+ pushIf(reasons, typeof entry.text !== "string", `${at}.text invalid`);
93
+ if (isFiniteNonNegativeNumber(entry.bytes)) {
94
+ totalBytes += entry.bytes;
95
+ }
96
+ });
97
+ pushIf(reasons, totalBytes > MAX_OBSERVATION_EXCERPT_BYTES, `${prefix}.excerpts exceed byte cap`);
98
+ return reasons;
99
+ }
100
+ // ─── ShapedCommandObservation ───────────────────────────────────────────────────
101
+ function collectCommand(value, prefix) {
102
+ const reasons = [];
103
+ pushIf(reasons, !isNonEmptyTrimmed(value.observationId), `${prefix}.observationId invalid`);
104
+ pushIf(reasons, !isExitCode(value.exitCode), `${prefix}.exitCode invalid`);
105
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.durationMs), `${prefix}.durationMs invalid`);
106
+ pushIf(reasons, typeof value.timedOut !== "boolean", `${prefix}.timedOut invalid`);
107
+ pushIf(reasons, typeof value.truncated !== "boolean", `${prefix}.truncated invalid`);
108
+ pushIf(reasons, !isOptionalFiniteNonNegativeNumber(value.omittedByteCount), `${prefix}.omittedByteCount invalid`);
109
+ reasons.push(...collectExcerpts(value.excerpts, prefix));
110
+ reasons.push(...collectInjectionOptionals(value, prefix));
111
+ reasons.push(...collectOptionalRehydration(value.rehydration, `${prefix}.rehydration`));
112
+ return reasons;
113
+ }
114
+ export function validateShapedCommandObservation(value) {
115
+ if (!isRecord(value)) {
116
+ return buildResult(["command invalid"]);
117
+ }
118
+ const reasons = [];
119
+ pushIf(reasons, value.kind !== "command", "command.kind invalid");
120
+ reasons.push(...collectCommand(value, "command"));
121
+ return buildResult(reasons);
122
+ }
123
+ // ─── ShapedTestObservation ──────────────────────────────────────────────────────
124
+ function collectTestCounts(value, prefix) {
125
+ if (!isRecord(value)) {
126
+ return [`${prefix}.counts invalid`];
127
+ }
128
+ const reasons = [];
129
+ for (const key of ["passed", "failed", "skipped"]) {
130
+ pushIf(reasons, !isFiniteNonNegativeNumber(value[key]), `${prefix}.counts.${key} invalid`);
131
+ }
132
+ return reasons;
133
+ }
134
+ function collectBoundedStringArray(value, prefix, cap) {
135
+ if (!Array.isArray(value)) {
136
+ return [`${prefix} invalid`];
137
+ }
138
+ const reasons = [];
139
+ pushIf(reasons, value.length > cap, `${prefix} exceeds cap`);
140
+ value.forEach((entry, index) => {
141
+ pushIf(reasons, typeof entry !== "string", `${prefix}[${String(index)}] invalid`);
142
+ });
143
+ return reasons;
144
+ }
145
+ function collectTest(value, prefix) {
146
+ const reasons = [];
147
+ pushIf(reasons, !isNonEmptyTrimmed(value.observationId), `${prefix}.observationId invalid`);
148
+ pushIf(reasons, !isNonEmptyTrimmed(value.verificationKind), `${prefix}.verificationKind invalid`);
149
+ pushIf(reasons, !isNonEmptyTrimmed(value.status), `${prefix}.status invalid`);
150
+ pushIf(reasons, !isExitCode(value.exitCode), `${prefix}.exitCode invalid`);
151
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.durationMs), `${prefix}.durationMs invalid`);
152
+ pushIf(reasons, typeof value.truncated !== "boolean", `${prefix}.truncated invalid`);
153
+ pushIf(reasons, !isOptionalFiniteNonNegativeNumber(value.omittedByteCount), `${prefix}.omittedByteCount invalid`);
154
+ reasons.push(...collectTestCounts(value.counts, prefix));
155
+ reasons.push(...collectBoundedStringArray(value.failingTestNames, `${prefix}.failingTestNames`, MAX_FAILING_TEST_NAMES));
156
+ reasons.push(...collectBoundedStringArray(value.stackFrameExcerpts, `${prefix}.stackFrameExcerpts`, MAX_STACK_FRAME_LINES));
157
+ pushIf(reasons, typeof value.outputSummary !== "string", `${prefix}.outputSummary invalid`);
158
+ reasons.push(...collectInjectionOptionals(value, prefix));
159
+ reasons.push(...collectOptionalRehydration(value.rehydration, `${prefix}.rehydration`));
160
+ return reasons;
161
+ }
162
+ export function validateShapedTestObservation(value) {
163
+ if (!isRecord(value)) {
164
+ return buildResult(["test invalid"]);
165
+ }
166
+ const reasons = [];
167
+ pushIf(reasons, value.kind !== "test", "test.kind invalid");
168
+ reasons.push(...collectTest(value, "test"));
169
+ return buildResult(reasons);
170
+ }
171
+ // ─── ShapedSearchObservation ────────────────────────────────────────────────────
172
+ function collectTopRanges(value, prefix) {
173
+ if (!Array.isArray(value)) {
174
+ return [`${prefix}.topRanges invalid`];
175
+ }
176
+ const reasons = [];
177
+ pushIf(reasons, value.length > MAX_TOP_RANGES, `${prefix}.topRanges exceeds cap`);
178
+ value.forEach((entry, index) => {
179
+ const at = `${prefix}.topRanges[${String(index)}]`;
180
+ if (!isRecord(entry)) {
181
+ reasons.push(`${at} invalid`);
182
+ return;
183
+ }
184
+ pushIf(reasons, !isNonEmptyTrimmed(entry.scopePath), `${at}.scopePath invalid`);
185
+ pushIf(reasons, !isFiniteNonNegativeNumber(entry.startLine), `${at}.startLine invalid`);
186
+ pushIf(reasons, !isFiniteNonNegativeNumber(entry.endLine), `${at}.endLine invalid`);
187
+ pushIf(reasons, !isFiniteNonNegativeNumber(entry.score), `${at}.score invalid`);
188
+ });
189
+ return reasons;
190
+ }
191
+ function collectSearch(value, prefix) {
192
+ const reasons = [];
193
+ pushIf(reasons, !isNonEmptyTrimmed(value.observationId), `${prefix}.observationId invalid`);
194
+ const query = value.query;
195
+ pushIf(reasons, typeof query !== "string" || query.length > MAX_OBSERVATION_QUERY_BYTES, `${prefix}.query invalid`);
196
+ pushIf(reasons, !isNonEmptyTrimmed(value.searchKind), `${prefix}.searchKind invalid`);
197
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.candidateCount), `${prefix}.candidateCount invalid`);
198
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.omittedCount), `${prefix}.omittedCount invalid`);
199
+ pushIf(reasons, typeof value.truncated !== "boolean", `${prefix}.truncated invalid`);
200
+ reasons.push(...collectTopRanges(value.topRanges, prefix));
201
+ reasons.push(...collectInjectionOptionals(value, prefix));
202
+ return reasons;
203
+ }
204
+ export function validateShapedSearchObservation(value) {
205
+ if (!isRecord(value)) {
206
+ return buildResult(["search invalid"]);
207
+ }
208
+ const reasons = [];
209
+ pushIf(reasons, value.kind !== "search", "search.kind invalid");
210
+ reasons.push(...collectSearch(value, "search"));
211
+ return buildResult(reasons);
212
+ }
213
+ // ─── ShapedBrowserObservation (forward-defined; still validated) ─────────────────
214
+ function collectBrowser(value, prefix) {
215
+ const reasons = [];
216
+ pushIf(reasons, !isNonEmptyTrimmed(value.observationId), `${prefix}.observationId invalid`);
217
+ pushIf(reasons, !isNonEmptyTrimmed(value.checkDescription), `${prefix}.checkDescription invalid`);
218
+ pushIf(reasons, typeof value.passed !== "boolean", `${prefix}.passed invalid`);
219
+ pushIf(reasons, !isFiniteNonNegativeNumber(value.durationMs), `${prefix}.durationMs invalid`);
220
+ pushIf(reasons, !isOptionalFiniteNonNegativeNumber(value.a11yViolationCount), `${prefix}.a11yViolationCount invalid`);
221
+ pushIf(reasons, !isOptionalNonEmptyString(value.screenshotScopePath), `${prefix}.screenshotScopePath invalid`);
222
+ reasons.push(...collectInjectionOptionals(value, prefix));
223
+ reasons.push(...collectOptionalRehydration(value.rehydration, `${prefix}.rehydration`));
224
+ return reasons;
225
+ }
226
+ export function validateShapedBrowserObservation(value) {
227
+ if (!isRecord(value)) {
228
+ return buildResult(["browser invalid"]);
229
+ }
230
+ const reasons = [];
231
+ pushIf(reasons, value.kind !== "browser", "browser.kind invalid");
232
+ reasons.push(...collectBrowser(value, "browser"));
233
+ return buildResult(reasons);
234
+ }
235
+ // ─── Discriminated dispatch ──────────────────────────────────────────────────────
236
+ export function validateContextToolObservation(value) {
237
+ if (!isRecord(value)) {
238
+ return buildResult(["observation invalid"]);
239
+ }
240
+ switch (value.kind) {
241
+ case "command":
242
+ return validateShapedCommandObservation(value);
243
+ case "test":
244
+ return validateShapedTestObservation(value);
245
+ case "search":
246
+ return validateShapedSearchObservation(value);
247
+ case "browser":
248
+ return validateShapedBrowserObservation(value);
249
+ default:
250
+ return buildResult(["observation.kind invalid"]);
251
+ }
252
+ }
@@ -0,0 +1,88 @@
1
+ import { CONTEXT_ENGINEERING_SCHEMA_VERSION } from "./context-engineering.js";
2
+ import type { ContextLaneId } from "./context-engineering.js";
3
+ export declare const MAX_OBSERVATION_EXCERPT_BYTES = 4096;
4
+ export declare const MAX_FAILING_TEST_NAMES = 16;
5
+ export declare const MAX_OBSERVATION_QUERY_BYTES = 512;
6
+ export declare const MAX_TOP_RANGES = 8;
7
+ export declare const MAX_STACK_FRAME_LINES = 30;
8
+ export interface ShapedStreamExcerpt {
9
+ readonly stream: "stdout" | "stderr";
10
+ readonly bytes: number;
11
+ readonly text: string;
12
+ }
13
+ export interface ShapedCommandObservation {
14
+ readonly kind: "command";
15
+ readonly observationId: string;
16
+ readonly exitCode: number | null;
17
+ readonly durationMs: number;
18
+ readonly timedOut: boolean;
19
+ readonly truncated: boolean;
20
+ readonly omittedByteCount?: number | undefined;
21
+ readonly excerpts: readonly ShapedStreamExcerpt[];
22
+ readonly injectionSignalCount?: number | undefined;
23
+ readonly hasCriticalInjectionSignal?: boolean | undefined;
24
+ readonly rehydration?: ContextToolRehydrationHandle | undefined;
25
+ }
26
+ export interface ShapedTestCounts {
27
+ readonly passed: number;
28
+ readonly failed: number;
29
+ readonly skipped: number;
30
+ }
31
+ export interface ShapedTestObservation {
32
+ readonly kind: "test";
33
+ readonly observationId: string;
34
+ readonly verificationKind: string;
35
+ readonly status: string;
36
+ readonly exitCode: number | null;
37
+ readonly durationMs: number;
38
+ readonly truncated: boolean;
39
+ readonly omittedByteCount?: number | undefined;
40
+ readonly counts: ShapedTestCounts;
41
+ readonly failingTestNames: readonly string[];
42
+ readonly stackFrameExcerpts: readonly string[];
43
+ readonly outputSummary: string;
44
+ readonly injectionSignalCount?: number | undefined;
45
+ readonly hasCriticalInjectionSignal?: boolean | undefined;
46
+ readonly rehydration?: ContextToolRehydrationHandle | undefined;
47
+ }
48
+ export interface ShapedSearchRange {
49
+ readonly scopePath: string;
50
+ readonly startLine: number;
51
+ readonly endLine: number;
52
+ readonly score: number;
53
+ }
54
+ export interface ShapedSearchObservation {
55
+ readonly kind: "search";
56
+ readonly observationId: string;
57
+ readonly query: string;
58
+ readonly searchKind: string;
59
+ readonly candidateCount: number;
60
+ readonly topRanges: readonly ShapedSearchRange[];
61
+ readonly omittedCount: number;
62
+ readonly truncated: boolean;
63
+ readonly injectionSignalCount?: number | undefined;
64
+ readonly hasCriticalInjectionSignal?: boolean | undefined;
65
+ }
66
+ export interface ShapedBrowserObservation {
67
+ readonly kind: "browser";
68
+ readonly observationId: string;
69
+ readonly checkDescription: string;
70
+ readonly passed: boolean;
71
+ readonly durationMs: number;
72
+ readonly a11yViolationCount?: number | undefined;
73
+ readonly screenshotScopePath?: string | undefined;
74
+ readonly injectionSignalCount?: number | undefined;
75
+ readonly hasCriticalInjectionSignal?: boolean | undefined;
76
+ readonly rehydration?: ContextToolRehydrationHandle | undefined;
77
+ }
78
+ export type ContextToolObservation = ShapedCommandObservation | ShapedTestObservation | ShapedSearchObservation | ShapedBrowserObservation;
79
+ export interface ContextToolRehydrationHandle {
80
+ readonly schemaVersion: typeof CONTEXT_ENGINEERING_SCHEMA_VERSION;
81
+ readonly laneId: ContextLaneId;
82
+ readonly kind: "tool-result";
83
+ readonly artifactId: string;
84
+ readonly itemCount: number;
85
+ readonly approxTokens: number;
86
+ readonly notPersistedReason?: string | undefined;
87
+ }
88
+ //# sourceMappingURL=context-observations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-observations.d.ts","sourceRoot":"","sources":["../src/context-observations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ // Shaped observations for the tool-observations context lane (ADR-0054, PR3-W1). Pure readonly
2
+ // contracts, no IO, no clock, no randomness, no sibling @oscharko-dev/keiko-* import (contracts is
3
+ // a strict leaf). Produced by keiko-workflows/src/observations/ (PR3-W3); consumed by the lane
4
+ // assembler (PR4). Each shape is a bounded, redaction-proven, injection-flagged view of a single
5
+ // raw tool result — never the full raw output. The discriminated union ContextToolObservation
6
+ // wraps the three concrete shaped types plus the forward-defined browser type.
7
+ //
8
+ // Validators follow the connected-context.ts isRecord + predicate envelope and live in the sibling
9
+ // context-observations-validation.ts to keep both files under the 400-LOC budget (mirrors the
10
+ // context-engineering-validation.ts split).
11
+ import { CONTEXT_ENGINEERING_SCHEMA_VERSION } from "./context-engineering.js";
12
+ // ─── Size constants (tunable; not part of the public interface shape) ─────── [PR3]
13
+ // Frozen defaults for the shapers. They do not appear in the shaped types themselves so they can
14
+ // be re-tuned without a contract change.
15
+ export const MAX_OBSERVATION_EXCERPT_BYTES = 4_096; // total across all stream excerpts per observation
16
+ export const MAX_FAILING_TEST_NAMES = 16;
17
+ export const MAX_OBSERVATION_QUERY_BYTES = 512;
18
+ export const MAX_TOP_RANGES = 8;
19
+ export const MAX_STACK_FRAME_LINES = 30; // total across all stackFrameExcerpts per observation