@principles/core 1.275.1 → 1.276.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.
Files changed (41) hide show
  1. package/dist/runtime-v2/config/__tests__/pd-config-sparse-bootstrap.test.d.ts +2 -0
  2. package/dist/runtime-v2/config/__tests__/pd-config-sparse-bootstrap.test.d.ts.map +1 -0
  3. package/dist/runtime-v2/config/__tests__/pd-config-sparse-bootstrap.test.js +143 -0
  4. package/dist/runtime-v2/config/__tests__/pd-config-sparse-bootstrap.test.js.map +1 -0
  5. package/dist/runtime-v2/feature-flags/__tests__/installer-config-parity.test.js +44 -27
  6. package/dist/runtime-v2/feature-flags/__tests__/installer-config-parity.test.js.map +1 -1
  7. package/dist/runtime-v2/internalization/__tests__/context-resolution.test.d.ts +2 -0
  8. package/dist/runtime-v2/internalization/__tests__/context-resolution.test.d.ts.map +1 -0
  9. package/dist/runtime-v2/internalization/__tests__/context-resolution.test.js +377 -0
  10. package/dist/runtime-v2/internalization/__tests__/context-resolution.test.js.map +1 -0
  11. package/dist/runtime-v2/internalization/__tests__/progressive-disclosure-spike.test.js +8 -8
  12. package/dist/runtime-v2/internalization/__tests__/progressive-disclosure-spike.test.js.map +1 -1
  13. package/dist/runtime-v2/internalization/__tests__/shared-information-plane-runner.test.d.ts +2 -0
  14. package/dist/runtime-v2/internalization/__tests__/shared-information-plane-runner.test.d.ts.map +1 -0
  15. package/dist/runtime-v2/internalization/__tests__/shared-information-plane-runner.test.js +628 -0
  16. package/dist/runtime-v2/internalization/__tests__/shared-information-plane-runner.test.js.map +1 -0
  17. package/dist/runtime-v2/internalization/artificer-runner.d.ts +23 -0
  18. package/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  19. package/dist/runtime-v2/internalization/artificer-runner.js +104 -13
  20. package/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  21. package/dist/runtime-v2/internalization/context-manifests.d.ts +90 -17
  22. package/dist/runtime-v2/internalization/context-manifests.d.ts.map +1 -1
  23. package/dist/runtime-v2/internalization/context-manifests.js +124 -27
  24. package/dist/runtime-v2/internalization/context-manifests.js.map +1 -1
  25. package/dist/runtime-v2/internalization/context-resolution.d.ts +189 -0
  26. package/dist/runtime-v2/internalization/context-resolution.d.ts.map +1 -0
  27. package/dist/runtime-v2/internalization/context-resolution.js +317 -0
  28. package/dist/runtime-v2/internalization/context-resolution.js.map +1 -0
  29. package/dist/runtime-v2/internalization/evaluator-runner.d.ts +32 -0
  30. package/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  31. package/dist/runtime-v2/internalization/evaluator-runner.js +72 -7
  32. package/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  33. package/dist/runtime-v2/runner/base-peer-runner.d.ts +62 -17
  34. package/dist/runtime-v2/runner/base-peer-runner.d.ts.map +1 -1
  35. package/dist/runtime-v2/runner/base-peer-runner.js +116 -10
  36. package/dist/runtime-v2/runner/base-peer-runner.js.map +1 -1
  37. package/dist/telemetry-event.d.ts +2 -2
  38. package/dist/telemetry-event.d.ts.map +1 -1
  39. package/dist/telemetry-event.js +47 -0
  40. package/dist/telemetry-event.js.map +1 -1
  41. package/package.json +1 -1
@@ -0,0 +1,377 @@
1
+ /**
2
+ * PRI-634 PR-B — Shared Information Plane: context-resolution unit tests.
3
+ *
4
+ * Covers the pure composition seam (design §16–§20, §27–§37):
5
+ * - `readRawField` — runtime-safe path reading (rc-1/rc-5)
6
+ * - `resolveAncestryPaths` — stage selection by two-hop taskKind, nearest
7
+ * ancestor wins (design §19/§20)
8
+ * - `resolveRelatedPaths` — related (causal) references, never ancestry
9
+ * - `mergeContextFields` — deterministic first-wins composition
10
+ * - `findUnresolvedRequiredPaths` — the required-evidence gate (design §35)
11
+ */
12
+ import { describe, it, expect } from 'vitest';
13
+ import { findUnresolvedRequiredPaths, mergeContextFields, parseContextPath, partitionTier2Paths, readRawField, resolveAncestryPaths, resolveRelatedPaths, toRawStageSources, } from '../context-resolution.js';
14
+ import { ARTIFICER_MANIFEST, ARTIFICER_REPAIR_MANIFEST, EVALUATOR_STAGE2_MANIFEST, } from '../context-manifests.js';
15
+ // ── parseContextPath ────────────────────────────────────────────────────────
16
+ describe('parseContextPath — grammar', () => {
17
+ it('splits namespace / layer / rest for the three layers', () => {
18
+ expect(parseContextPath('pain.raw.evidence')).toEqual({
19
+ namespace: 'pain', layer: 'raw', rest: ['evidence'],
20
+ });
21
+ expect(parseContextPath('dreamer.summary.betterDecision')).toEqual({
22
+ namespace: 'dreamer', layer: 'summary', rest: ['betterDecision'],
23
+ });
24
+ expect(parseContextPath('philosopher.predecessorSummary.headline')).toEqual({
25
+ namespace: 'philosopher', layer: 'predecessorSummary', rest: ['headline'],
26
+ });
27
+ });
28
+ it('keeps multi-segment rest paths for array addressing', () => {
29
+ expect(parseContextPath('dreamer.raw.candidates.0.betterDecision')).toEqual({
30
+ namespace: 'dreamer', layer: 'raw', rest: ['candidates', '0', 'betterDecision'],
31
+ });
32
+ });
33
+ it('rejects malformed paths instead of guessing', () => {
34
+ expect(parseContextPath('repair.requiredChanges')).toBeNull(); // 2 segments
35
+ expect(parseContextPath('raw.evidence')).toBeNull(); // 2 segments
36
+ expect(parseContextPath('pain.unknown.evidence')).toBeNull(); // bad layer
37
+ expect(parseContextPath('pain.raw.')).toBeNull(); // empty segment
38
+ expect(parseContextPath('.raw.evidence')).toBeNull(); // empty namespace
39
+ });
40
+ });
41
+ // ── readRawField ────────────────────────────────────────────────────────────
42
+ describe('readRawField — runtime-safe raw path reading (rc-1/rc-5)', () => {
43
+ const dreamerJson = {
44
+ valid: true,
45
+ candidates: [
46
+ { badDecision: 'bad', betterDecision: 'better', rationale: 'why', riskLevel: 'high' },
47
+ { badDecision: 'bad2', betterDecision: 'better2', rationale: 'why2', riskLevel: 'low' },
48
+ ],
49
+ };
50
+ it('reads the 5 dimensions through the array element (dreamer shape)', () => {
51
+ expect(readRawField(['candidates', '0', 'betterDecision'], dreamerJson)).toBe('better');
52
+ expect(readRawField(['candidates', '0', 'rationale'], dreamerJson)).toBe('why');
53
+ expect(readRawField(['candidates', '0', 'riskLevel'], dreamerJson)).toBe('high');
54
+ });
55
+ it('reads a whole array as a value (stage2 shape)', () => {
56
+ expect(readRawField(['candidates'], dreamerJson)).toHaveLength(2);
57
+ });
58
+ it('does not default to element 0 — paths must be explicit', () => {
59
+ expect(readRawField(['betterDecision'], dreamerJson)).toBeUndefined();
60
+ expect(readRawField(['candidates', '1', 'betterDecision'], dreamerJson)).toBe('better2');
61
+ });
62
+ it('returns undefined for missing / non-object / out-of-range paths', () => {
63
+ expect(readRawField(['candidates', '9', 'betterDecision'], dreamerJson)).toBeUndefined();
64
+ expect(readRawField(['candidates', '0', 'missing'], dreamerJson)).toBeUndefined();
65
+ // Primitives are terminal: the reader never walks into a string/number's
66
+ // own properties (no `length`, no boxing surprises).
67
+ expect(readRawField(['candidates', '0', 'betterDecision', 'length'], dreamerJson)).toBeUndefined();
68
+ expect(readRawField(['a'], null)).toBeUndefined();
69
+ expect(readRawField(['a'], 'string')).toBeUndefined();
70
+ expect(readRawField(['candidates', 'x'], dreamerJson)).toBeUndefined();
71
+ });
72
+ it('rejects prototype-pollution keys at every segment (rc-5)', () => {
73
+ const poisoned = { __proto__: { polluted: true }, nested: { constructor: 1 } };
74
+ expect(readRawField(['__proto__', 'polluted'], poisoned)).toBeUndefined();
75
+ expect(readRawField(['nested', 'constructor'], poisoned)).toBeUndefined();
76
+ expect(readRawField(['nested', 'prototype'], poisoned)).toBeUndefined();
77
+ });
78
+ it('does not read inherited properties', () => {
79
+ const proto = { inherited: 'yes' };
80
+ const obj = Object.create(proto);
81
+ expect(readRawField(['inherited'], obj)).toBeUndefined();
82
+ });
83
+ it('handles sparse arrays without inventing values', () => {
84
+ const sparse = [];
85
+ sparse[2] = 'third';
86
+ expect(readRawField(['0'], sparse)).toBeUndefined();
87
+ expect(readRawField(['2'], sparse)).toBe('third');
88
+ });
89
+ });
90
+ // ── Ancestry resolution ─────────────────────────────────────────────────────
91
+ describe('resolveAncestryPaths — CandidateLineage stage selection', () => {
92
+ it('resolves the artificer tier2 fields from the dreamer ancestor', () => {
93
+ const sources = toRawStageSources([
94
+ { taskKind: 'artificer', contentJson: { implementationCode: 'x' } },
95
+ { taskKind: 'scribe', contentJson: { principleText: 'p' } },
96
+ {
97
+ taskKind: 'dreamer',
98
+ contentJson: { candidates: [{ betterDecision: 'B', rationale: 'R', riskLevel: 'high' }] },
99
+ },
100
+ ]);
101
+ const resolved = resolveAncestryPaths([...ARTIFICER_MANIFEST.tier2], sources);
102
+ expect(resolved.get('dreamer.raw.candidates.0.betterDecision')).toBe('B');
103
+ expect(resolved.get('dreamer.raw.candidates.0.rationale')).toBe('R');
104
+ expect(resolved.get('dreamer.raw.candidates.0.riskLevel')).toBe('high');
105
+ });
106
+ it('nearest ancestor wins — never a positional/arbitrary pick (design §20)', () => {
107
+ // CandidateLineage walks BFS from the start artifact, so the first node of
108
+ // a stage is the nearest ancestor. Freeze that contract here.
109
+ const sources = toRawStageSources([
110
+ { taskKind: 'dreamer', contentJson: { candidates: [{ betterDecision: 'NEAREST' }] } },
111
+ { taskKind: 'dreamer', contentJson: { candidates: [{ betterDecision: 'FARTHER' }] } },
112
+ ]);
113
+ const resolved = resolveAncestryPaths(['dreamer.raw.candidates.0.betterDecision'], sources);
114
+ expect(resolved.get('dreamer.raw.candidates.0.betterDecision')).toBe('NEAREST');
115
+ });
116
+ it('drops nodes whose stage could not be determined by the two-hop', () => {
117
+ const sources = toRawStageSources([
118
+ { taskKind: 'unknown', contentJson: { candidates: [{ betterDecision: 'NOPE' }] } },
119
+ { taskKind: '', contentJson: { candidates: [{ betterDecision: 'NOPE2' }] } },
120
+ ]);
121
+ expect(sources).toHaveLength(0);
122
+ expect(resolveAncestryPaths([...ARTIFICER_MANIFEST.tier2], sources).size).toBe(0);
123
+ });
124
+ it('omits paths whose stage is absent — they surface as `absent`, never empty strings', () => {
125
+ const sources = toRawStageSources([{ taskKind: 'scribe', contentJson: {} }]);
126
+ const resolved = resolveAncestryPaths([...ARTIFICER_MANIFEST.tier2], sources);
127
+ expect(resolved.size).toBe(0);
128
+ });
129
+ it('resolves stage2 raw fields from the diagnostician + dreamer ancestors', () => {
130
+ const sources = toRawStageSources([
131
+ { taskKind: 'artificer', contentJson: {} },
132
+ { taskKind: 'dreamer', contentJson: { candidates: [{ betterDecision: 'B' }] } },
133
+ {
134
+ taskKind: 'diagnostician',
135
+ contentJson: { evidence: [{ sourceRef: 'tool_call:Edit:auth.ts', note: 'n' }] },
136
+ },
137
+ ]);
138
+ const resolved = resolveAncestryPaths([...EVALUATOR_STAGE2_MANIFEST.tier2], sources);
139
+ expect(resolved.get('diagnostician.raw.evidence')).toEqual([{ sourceRef: 'tool_call:Edit:auth.ts', note: 'n' }]);
140
+ expect(resolved.get('dreamer.raw.candidates')).toHaveLength(1);
141
+ });
142
+ it('resolves ancestor SUMMARY paths — the stage namespace is a real address here', () => {
143
+ // THIS is why the Evaluator needs the ancestry channel: `readSummaryField`
144
+ // strips the namespace and only reads the direct predecessor, so an
145
+ // ancestor-named summary path resolves here or nowhere.
146
+ const envelope = {
147
+ summary: {
148
+ schemaVersion: 1, runnerKind: 'dreamer', headline: 'read first',
149
+ fields: { betterDecision: 'BETTER', badDecision: 'BAD' },
150
+ derivedFrom: 'structured_output', omittedFields: [],
151
+ },
152
+ };
153
+ const sources = toRawStageSources([
154
+ { taskKind: 'artificer', contentJson: {} },
155
+ { taskKind: 'dreamer', contentJson: envelope },
156
+ ]);
157
+ const resolved = resolveAncestryPaths(['dreamer.summary.betterDecision'], sources);
158
+ expect(resolved.get('dreamer.summary.betterDecision')).toBe('BETTER');
159
+ // Wrong namespace → nothing, so the path falls through to `absent`.
160
+ expect(resolveAncestryPaths(['scribe.summary.betterDecision'], sources).size).toBe(0);
161
+ });
162
+ it('never answers predecessorSummary from the ancestry walk', () => {
163
+ // `predecessorSummary` is the direct-predecessor forwarding concept owned
164
+ // by Channel 1; an ancestor node must not be allowed to answer it.
165
+ const sources = toRawStageSources([
166
+ {
167
+ taskKind: 'scribe',
168
+ contentJson: { predecessorSummary: { summary: { headline: 'WRONG' } } },
169
+ },
170
+ ]);
171
+ expect(resolveAncestryPaths(['scribe.predecessorSummary.headline'], sources).size).toBe(0);
172
+ });
173
+ it('SEMANTIC_STAGE_ALIASES: diagnostician.* resolves from the split diag_router producer', () => {
174
+ // Default split-pipeline identity: the durable DiagnosticianOutputV1 is
175
+ // committed by the diag_router SUB-TASK (SplitDiagnosticianRunner stage C).
176
+ // The manifest namespace `diagnostician` must answer from that node.
177
+ const sources = toRawStageSources([
178
+ { taskKind: 'philosopher', contentJson: {} },
179
+ { taskKind: 'diag_rootcause', contentJson: { evidence: [{ ref: 'stage-a' }] } },
180
+ {
181
+ taskKind: 'diag_router',
182
+ contentJson: { evidence: [{ ref: 'tool_call:Edit:auth.ts', note: 'n' }] },
183
+ },
184
+ ]);
185
+ const resolved = resolveAncestryPaths(['diagnostician.raw.evidence'], sources);
186
+ expect(resolved.get('diagnostician.raw.evidence')).toEqual([{ ref: 'tool_call:Edit:auth.ts', note: 'n' }]);
187
+ });
188
+ it('SEMANTIC_STAGE_ALIASES: unrelated diag stages never answer the namespace', () => {
189
+ // Even when a diag_rootcause node appears FIRST (nearest), it is not an
190
+ // alias producer for `diagnostician` — only {diagnostician, diag_router}
191
+ // are. Its stage-A evidence must not masquerade as the final diagnosis.
192
+ const sources = toRawStageSources([
193
+ { taskKind: 'diag_rootcause', contentJson: { evidence: [{ ref: 'stage-a' }] } },
194
+ { taskKind: 'diag_distiller', contentJson: { evidence: [{ ref: 'stage-b' }] } },
195
+ ]);
196
+ expect(resolveAncestryPaths(['diagnostician.raw.evidence'], sources).size).toBe(0);
197
+ expect(resolveAncestryPaths(['diagnostician.summary.rootSymptom'], sources).size).toBe(0);
198
+ });
199
+ it('read-time projection: diagnostician.summary.* derives from a top-level-summary output (no Layer-0 envelope)', () => {
200
+ // DiagnosticianOutputV1 owns a top-level `summary` STRING, so the writer
201
+ // SKIPPED the Layer-0 envelope (output_summary_key_collision). The bounded
202
+ // read-time projection derives {rootSymptom, category} from the unchanged
203
+ // durable output — the review-round contract fix for the always-absent
204
+ // Stage1 pain-summary fields.
205
+ const sources = toRawStageSources([
206
+ {
207
+ taskKind: 'diag_router',
208
+ contentJson: {
209
+ valid: true, diagnosisId: 'd1',
210
+ summary: 'Agent wrote a file without reading it first.',
211
+ rootCause: 'Tooling: write path skipped the read-before-write check.',
212
+ violatedPrinciples: [],
213
+ evidence: [{ ref: 'e1' }],
214
+ recommendations: [{ kind: 'internalize', description: 'read before write' }],
215
+ confidence: 0.9,
216
+ },
217
+ },
218
+ ]);
219
+ const resolved = resolveAncestryPaths(['diagnostician.summary.rootSymptom', 'diagnostician.summary.category'], sources);
220
+ expect(resolved.get('diagnostician.summary.rootSymptom')).toBe('Agent wrote a file without reading it first.');
221
+ expect(resolved.get('diagnostician.summary.category')).toBe('internalize');
222
+ // Not in the diag_router derivation → stays absent (never invented).
223
+ expect(resolveAncestryPaths(['diagnostician.summary.strategicPerspective'], sources).size).toBe(0);
224
+ });
225
+ it('read-time projection also serves the legacy `diagnostician` producer', () => {
226
+ const legacyContent = {
227
+ valid: true, diagnosisId: 'd1',
228
+ summary: 'legacy pain summary',
229
+ rootCause: 'Design: assumption.',
230
+ violatedPrinciples: [],
231
+ evidence: [],
232
+ recommendations: [{ kind: 'defer', description: 'no action' }],
233
+ confidence: 0.8,
234
+ };
235
+ const sources = toRawStageSources([{ taskKind: 'diagnostician', contentJson: legacyContent }]);
236
+ const resolved = resolveAncestryPaths(['diagnostician.raw.evidence', 'diagnostician.summary.rootSymptom'], sources);
237
+ expect(resolved.get('diagnostician.summary.rootSymptom')).toBe('legacy pain summary');
238
+ expect(resolved.get('diagnostician.raw.evidence')).toEqual([]);
239
+ });
240
+ });
241
+ // ── Ancestry vs related separation (INV-LINEAGE-SCOPE, design §33) ──────────
242
+ describe('partitionTier2Paths — ancestry must never absorb a related ref', () => {
243
+ it('routes related namespaces away from the ancestry walk', () => {
244
+ const { ancestry, related } = partitionTier2Paths([...ARTIFICER_REPAIR_MANIFEST.tier2], ['replay', 'repair']);
245
+ expect(ancestry).toEqual([]);
246
+ expect(related).toEqual([...ARTIFICER_REPAIR_MANIFEST.tier2]);
247
+ });
248
+ it('keeps genuine stage raw paths on the ancestry side', () => {
249
+ const { ancestry, related } = partitionTier2Paths([...EVALUATOR_STAGE2_MANIFEST.tier2], ['replay', 'repair']);
250
+ expect(ancestry).toEqual(['diagnostician.raw.evidence', 'dreamer.raw.candidates']);
251
+ expect(related).toEqual([]);
252
+ });
253
+ it('a same-named taskKind still cannot be reached as ancestry (defence in depth)', () => {
254
+ // Even if a taskKind were literally called `replay`, the partition keeps it
255
+ // out of the lineage walk — the caller supplies related refs explicitly.
256
+ const { ancestry } = partitionTier2Paths(['replay.raw.traceFailures'], ['replay']);
257
+ expect(ancestry).toEqual([]);
258
+ const sources = toRawStageSources([
259
+ { taskKind: 'replay', contentJson: { traceFailures: [{ caseId: 'x' }] } },
260
+ ]);
261
+ expect(resolveAncestryPaths(ancestry, sources).size).toBe(0);
262
+ });
263
+ });
264
+ // ── Related references ──────────────────────────────────────────────────────
265
+ describe('resolveRelatedPaths — related (causal) references', () => {
266
+ const sources = [
267
+ {
268
+ namespace: 'replay',
269
+ summary: { passed: false, failedCaseCount: 7, failureTypes: ['runtime_error'] },
270
+ raw: {
271
+ traceFailures: [{ caseId: 'v2-unavailable', errorType: 'runtime_error' }],
272
+ systemFailures: [],
273
+ globalViolations: ['eval('],
274
+ },
275
+ },
276
+ { namespace: 'repair', summary: { requiredChanges: ['fix it'], concerns: ['c1'] } },
277
+ ];
278
+ it('resolves summary and raw keys under the source namespace', () => {
279
+ const paths = [
280
+ 'replay.summary.passed',
281
+ 'replay.summary.failedCaseCount',
282
+ 'replay.summary.failureTypes',
283
+ 'replay.raw.traceFailures',
284
+ 'replay.raw.systemFailures',
285
+ 'replay.raw.globalViolations',
286
+ 'repair.summary.requiredChanges',
287
+ 'repair.summary.concerns',
288
+ ];
289
+ const resolved = resolveRelatedPaths(paths, sources);
290
+ expect(resolved.get('replay.summary.passed')).toBe(false);
291
+ expect(resolved.get('replay.summary.failedCaseCount')).toBe(7);
292
+ expect(resolved.get('replay.summary.failureTypes')).toEqual(['runtime_error']);
293
+ expect(resolved.get('replay.raw.traceFailures')).toHaveLength(1);
294
+ expect(resolved.get('replay.raw.systemFailures')).toEqual([]);
295
+ expect(resolved.get('replay.raw.globalViolations')).toEqual(['eval(']);
296
+ expect(resolved.get('repair.summary.requiredChanges')).toEqual(['fix it']);
297
+ });
298
+ it('resolves every field the repair manifest declares', () => {
299
+ const declared = [
300
+ ...ARTIFICER_REPAIR_MANIFEST.tier0,
301
+ ...ARTIFICER_REPAIR_MANIFEST.tier1,
302
+ ...ARTIFICER_REPAIR_MANIFEST.tier2,
303
+ ].filter((p) => p.startsWith('replay.') || p.startsWith('repair.'));
304
+ const resolved = resolveRelatedPaths(declared, sources);
305
+ for (const path of declared) {
306
+ expect(resolved.has(path), `related source must resolve ${path}`).toBe(true);
307
+ }
308
+ });
309
+ it('skips predecessorSummary — related refs never forward summaries', () => {
310
+ const resolved = resolveRelatedPaths(['replay.predecessorSummary.headline'], [
311
+ { namespace: 'replay', summary: { headline: 'h' } },
312
+ ]);
313
+ expect(resolved.size).toBe(0);
314
+ });
315
+ it('skips unknown namespaces and multi-segment raw paths (ancestry grammar)', () => {
316
+ expect(resolveRelatedPaths(['ghost.raw.x'], sources).size).toBe(0);
317
+ expect(resolveRelatedPaths(['replay.raw.a.b'], sources).size).toBe(0);
318
+ });
319
+ it('never reads inherited or forbidden keys off a related table', () => {
320
+ const table = { safe: 1 };
321
+ Object.setPrototypeOf(table, { inherited: 'leak' });
322
+ const resolved = resolveRelatedPaths(['replay.raw.inherited', 'replay.raw.__proto__'], [
323
+ { namespace: 'replay', raw: table },
324
+ ]);
325
+ expect(resolved.size).toBe(0);
326
+ });
327
+ });
328
+ // ── Composition ─────────────────────────────────────────────────────────────
329
+ describe('mergeContextFields — deterministic composition', () => {
330
+ it('first writer wins, extras only fill gaps', () => {
331
+ const merged = mergeContextFields(new Map([['a', 1]]), [new Map([['a', 2], ['b', 3]]), new Map([['b', 4], ['c', 5]])]);
332
+ expect(merged.get('a')).toBe(1);
333
+ expect(merged.get('b')).toBe(3);
334
+ expect(merged.get('c')).toBe(5);
335
+ });
336
+ it('preserves the base map and never mutates its inputs', () => {
337
+ const base = new Map([['a', 1]]);
338
+ const extra = new Map([['b', 2]]);
339
+ const merged = mergeContextFields(base, [extra]);
340
+ expect(base.size).toBe(1);
341
+ expect([...merged.keys()]).toEqual(['a', 'b']);
342
+ });
343
+ });
344
+ // ── Required-evidence gate ──────────────────────────────────────────────────
345
+ describe('findUnresolvedRequiredPaths — no silent thin context (design §35)', () => {
346
+ it('is empty when every required path reached the prompt', () => {
347
+ expect(findUnresolvedRequiredPaths({
348
+ required: ['pain.raw.evidence'],
349
+ absent: [],
350
+ truncated: [],
351
+ })).toEqual([]);
352
+ });
353
+ it('flags required paths that were absent', () => {
354
+ expect(findUnresolvedRequiredPaths({
355
+ required: ['pain.raw.evidence', 'dreamer.raw.candidates'],
356
+ absent: ['pain.raw.evidence'],
357
+ truncated: [],
358
+ })).toEqual(['pain.raw.evidence']);
359
+ });
360
+ it('flags required paths that the BUDGET dropped or truncated', () => {
361
+ // A truncated required field is still an unmet requirement: the runner's
362
+ // semantic need was not satisfied, even though the field was "present".
363
+ expect(findUnresolvedRequiredPaths({
364
+ required: ['replay.raw.traceFailures'],
365
+ absent: [],
366
+ truncated: [{ fieldPath: 'replay.raw.traceFailures', reason: 'budget_exceeded', remainingBudgetTokens: 0, keptChars: 0, droppedChars: 900 }],
367
+ })).toEqual(['replay.raw.traceFailures']);
368
+ });
369
+ it('ignores non-required paths that happen to be absent', () => {
370
+ expect(findUnresolvedRequiredPaths({
371
+ required: [],
372
+ absent: ['a', 'b'],
373
+ truncated: [],
374
+ })).toEqual([]);
375
+ });
376
+ });
377
+ //# sourceMappingURL=context-resolution.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-resolution.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/internalization/__tests__/context-resolution.test.ts"],"names":[],"mappings":"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"}
@@ -137,6 +137,7 @@ function firstSentence(text) {
137
137
  return clamp(sentence.trim(), SUMMARY_HEADLINE_MAX_CHARS);
138
138
  }
139
139
  /** 派生一个 stage 的摘要:目标键缺失即进 omittedFields(design §6.1)。 */
140
+ // eslint-disable-next-line @typescript-eslint/max-params -- spike fixture DSL mirrors the design §6.1 derivation shape (kind, targetKeys, headlineSource, resolved); grouping into an options object would diverge from the 8 literal call sites below.
140
141
  function deriveSpikeSummary(runnerKind, targetKeys, headlineSource, resolved) {
141
142
  const fields = {};
142
143
  const omittedFields = [];
@@ -181,7 +182,6 @@ function buildChainSummaries(chain) {
181
182
  .filter((id) => id !== null);
182
183
  const recommendations = readArray(router, 'recommendations') ?? [];
183
184
  const firstRecommendationKind = recommendations.length > 0 ? readString(recommendations[0], 'kind') : null;
184
- const goldenTraceCases = readArray(artificer, 'goldenTraceCases') ?? [];
185
185
  const evaluatorEvaluation = readRecord(evaluator, 'evaluation');
186
186
  const evaluatorConcerns = evaluatorEvaluation === null ? null : readArray(evaluatorEvaluation, 'concerns');
187
187
  const evaluatorCodeReview = readRecord(evaluator, 'codeReview');
@@ -265,8 +265,8 @@ const EVALUATOR_STAGE1_PATHS = [
265
265
  'dreamer.summary.betterDecision',
266
266
  'dreamer.summary.rationale',
267
267
  'dreamer.summary.riskLevel',
268
- 'pain.summary.rootSymptom',
269
- 'pain.summary.category',
268
+ 'diagnostician.summary.rootSymptom',
269
+ 'diagnostician.summary.category',
270
270
  ];
271
271
  function buildEvaluatorStage1Context(chain) {
272
272
  const summaries = buildChainSummaries(chain);
@@ -283,8 +283,8 @@ function buildEvaluatorStage1Context(chain) {
283
283
  'dreamer.summary.betterDecision': summaries.dreamer.fields.betterDecision,
284
284
  'dreamer.summary.rationale': summaries.dreamer.fields.rationale,
285
285
  'dreamer.summary.riskLevel': summaries.dreamer.fields.riskLevel,
286
- 'pain.summary.rootSymptom': summaries.diag_rootcause.fields.rootSymptom,
287
- 'pain.summary.category': summaries.diag_rootcause.fields.category,
286
+ 'diagnostician.summary.rootSymptom': summaries.diag_rootcause.fields.rootSymptom,
287
+ 'diagnostician.summary.category': summaries.diag_rootcause.fields.category,
288
288
  };
289
289
  const fields = {};
290
290
  const absent = [];
@@ -836,8 +836,8 @@ function buildRouteBMessage(chain, context) {
836
836
  riskLevel: context.fields['dreamer.summary.riskLevel'],
837
837
  },
838
838
  pain: {
839
- rootSymptom: context.fields['pain.summary.rootSymptom'],
840
- category: context.fields['pain.summary.category'],
839
+ rootSymptom: context.fields['diagnostician.summary.rootSymptom'],
840
+ category: context.fields['diagnostician.summary.category'],
841
841
  },
842
842
  },
843
843
  absentFields: context.absent,
@@ -1009,7 +1009,7 @@ describe('Phase 0 Spike 1.2 — 摘要级上下文的定位能力(阻塞门)
1009
1009
  for (const chain of SPIKE_CHAINS) {
1010
1010
  const context = buildEvaluatorStage1Context(chain);
1011
1011
  const call = await askAgent(`routeB-${chain.chainId}`, buildRouteBMessage(chain, context));
1012
- const rawText = call.rawText;
1012
+ const { rawText } = call;
1013
1013
  const parsed = call.kind === 'reply'
1014
1014
  ? extractJsonObject(rawText) ?? repairMalformedJson(rawText)
1015
1015
  : null;