@principles/core 1.271.0 → 1.273.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/dist/runtime-v2/__tests__/admission-gate.test.js +23 -6
- package/dist/runtime-v2/__tests__/admission-gate.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/adversarial-loop.test.js +22 -0
- package/dist/runtime-v2/__tests__/adversarial-loop.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/context-payload-validation.test.js +1 -1
- package/dist/runtime-v2/__tests__/context-payload-validation.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/evidence-guards.test.js +2 -2
- package/dist/runtime-v2/__tests__/evidence-guards.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/golden-path-diagnostician-e2e.test.js +1 -1
- package/dist/runtime-v2/__tests__/golden-path-diagnostician-e2e.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/governance-experience.test.js +19 -0
- package/dist/runtime-v2/__tests__/governance-experience.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/pain-evidence-contract.test.js +3 -3
- package/dist/runtime-v2/__tests__/pain-evidence-contract.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.d.ts +2 -0
- package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.d.ts.map +1 -0
- package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js +106 -0
- package/dist/runtime-v2/__tests__/pain-signal-bridge-execute-pending.test.js.map +1 -0
- package/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +1 -1
- package/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/rollout-rule-candidate-contract.test.d.ts +2 -0
- package/dist/runtime-v2/__tests__/rollout-rule-candidate-contract.test.d.ts.map +1 -0
- package/dist/runtime-v2/__tests__/rollout-rule-candidate-contract.test.js +243 -0
- package/dist/runtime-v2/__tests__/rollout-rule-candidate-contract.test.js.map +1 -0
- package/dist/runtime-v2/admission-gate.d.ts +8 -1
- package/dist/runtime-v2/admission-gate.d.ts.map +1 -1
- package/dist/runtime-v2/admission-gate.js +14 -0
- package/dist/runtime-v2/admission-gate.js.map +1 -1
- package/dist/runtime-v2/context-payload.d.ts +9 -3
- package/dist/runtime-v2/context-payload.d.ts.map +1 -1
- package/dist/runtime-v2/context-payload.js +3 -1
- package/dist/runtime-v2/context-payload.js.map +1 -1
- package/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js +2 -2
- package/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js.map +1 -1
- package/dist/runtime-v2/evidence-triage/observation-resolver.d.ts +1 -1
- package/dist/runtime-v2/evidence-triage/observation-resolver.d.ts.map +1 -1
- package/dist/runtime-v2/evidence-triage/observation-resolver.js +2 -2
- package/dist/runtime-v2/evidence-triage/observation-resolver.js.map +1 -1
- package/dist/runtime-v2/evidence-triage/types.d.ts +1 -1
- package/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
- package/dist/runtime-v2/evolution/evolution-types.d.ts +8 -4
- package/dist/runtime-v2/evolution/evolution-types.d.ts.map +1 -1
- package/dist/runtime-v2/evolution/evolution-types.js +3 -1
- package/dist/runtime-v2/evolution/evolution-types.js.map +1 -1
- package/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +2 -2
- package/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -1
- package/dist/runtime-v2/governance-experience-contract.d.ts +16 -16
- package/dist/runtime-v2/governance-experience-contract.d.ts.map +1 -1
- package/dist/runtime-v2/governance-experience-contract.js +4 -1
- package/dist/runtime-v2/governance-experience-contract.js.map +1 -1
- package/dist/runtime-v2/governance-experience.d.ts.map +1 -1
- package/dist/runtime-v2/governance-experience.js +30 -8
- package/dist/runtime-v2/governance-experience.js.map +1 -1
- package/dist/runtime-v2/index.d.ts +7 -3
- package/dist/runtime-v2/index.d.ts.map +1 -1
- package/dist/runtime-v2/index.js +6 -3
- package/dist/runtime-v2/index.js.map +1 -1
- package/dist/runtime-v2/internalization/__tests__/artificer-code-bearing.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/artificer-code-bearing.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/artificer-code-bearing.test.js +114 -0
- package/dist/runtime-v2/internalization/__tests__/artificer-code-bearing.test.js.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.js +256 -0
- package/dist/runtime-v2/internalization/__tests__/evaluator-gate-authority.test.js.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.js +229 -0
- package/dist/runtime-v2/internalization/__tests__/owner-decision-review.test.js.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/owner-decision.test.js +172 -1
- package/dist/runtime-v2/internalization/__tests__/owner-decision.test.js.map +1 -1
- package/dist/runtime-v2/internalization/__tests__/rule-activation-contract.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/rule-activation-contract.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/rule-activation-contract.test.js +187 -0
- package/dist/runtime-v2/internalization/__tests__/rule-activation-contract.test.js.map +1 -0
- package/dist/runtime-v2/internalization/artificer-code-bearing.d.ts +39 -0
- package/dist/runtime-v2/internalization/artificer-code-bearing.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/artificer-code-bearing.js +33 -0
- package/dist/runtime-v2/internalization/artificer-code-bearing.js.map +1 -0
- package/dist/runtime-v2/internalization/evaluator-runner.d.ts +11 -8
- package/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/evaluator-runner.js +170 -31
- package/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/dist/runtime-v2/internalization/index.d.ts +2 -0
- package/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/index.js +1 -0
- package/dist/runtime-v2/internalization/index.js.map +1 -1
- package/dist/runtime-v2/internalization/internalization-task-guards.d.ts +5 -8
- package/dist/runtime-v2/internalization/internalization-task-guards.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/internalization-task-guards.js +11 -12
- package/dist/runtime-v2/internalization/internalization-task-guards.js.map +1 -1
- package/dist/runtime-v2/internalization/owner-decision-review.d.ts +98 -0
- package/dist/runtime-v2/internalization/owner-decision-review.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/owner-decision-review.js +287 -0
- package/dist/runtime-v2/internalization/owner-decision-review.js.map +1 -0
- package/dist/runtime-v2/internalization/owner-resolution-service.d.ts +11 -0
- package/dist/runtime-v2/internalization/owner-resolution-service.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/owner-resolution-service.js +117 -4
- package/dist/runtime-v2/internalization/owner-resolution-service.js.map +1 -1
- package/dist/runtime-v2/internalization/owner-review.d.ts +4 -0
- package/dist/runtime-v2/internalization/owner-review.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/owner-review.js.map +1 -1
- package/dist/runtime-v2/internalization/pitask-metadata.d.ts +16 -0
- package/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/pitask-metadata.js +62 -0
- package/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts +13 -0
- package/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/rollout-reviewer-runner.js +59 -11
- package/dist/runtime-v2/internalization/rollout-reviewer-runner.js.map +1 -1
- package/dist/runtime-v2/internalization/rule-activation-contract.d.ts +35 -0
- package/dist/runtime-v2/internalization/rule-activation-contract.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/rule-activation-contract.js +36 -0
- package/dist/runtime-v2/internalization/rule-activation-contract.js.map +1 -0
- package/dist/runtime-v2/pain-signal-bridge.d.ts +42 -0
- package/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
- package/dist/runtime-v2/pain-signal-bridge.js +99 -3
- package/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
- package/dist/runtime-v2/pain-signal-runtime-factory.d.ts +10 -4
- package/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/dist/runtime-v2/pain-signal-runtime-factory.js +86 -51
- package/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/dist/runtime-v2/pain-to-principle-service.d.ts +1 -0
- package/dist/runtime-v2/pain-to-principle-service.d.ts.map +1 -1
- package/dist/runtime-v2/pain-to-principle-service.js +1 -0
- package/dist/runtime-v2/pain-to-principle-service.js.map +1 -1
- package/dist/runtime-v2/runner/__tests__/pain-signal-bridge-admission.test.js +6 -6
- package/dist/runtime-v2/runner/__tests__/pain-signal-bridge-admission.test.js.map +1 -1
- package/dist/runtime-v2/store/context/sqlite-context-assembler.d.ts.map +1 -1
- package/dist/runtime-v2/store/context/sqlite-context-assembler.js +25 -5
- package/dist/runtime-v2/store/context/sqlite-context-assembler.js.map +1 -1
- package/dist/runtime-v2/store/context/sqlite-context-assembler.test.js +38 -9
- package/dist/runtime-v2/store/context/sqlite-context-assembler.test.js.map +1 -1
- package/dist/runtime-v2/store/runtime-state-manager.d.ts +6 -0
- package/dist/runtime-v2/store/runtime-state-manager.d.ts.map +1 -1
- package/dist/runtime-v2/store/runtime-state-manager.js +8 -0
- package/dist/runtime-v2/store/runtime-state-manager.js.map +1 -1
- package/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js +36 -0
- package/dist/runtime-v2/store/task/__tests__/sqlite-task-store-cas.test.js.map +1 -1
- package/dist/runtime-v2/store/task/sqlite-task-store.d.ts +19 -0
- package/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
- package/dist/runtime-v2/store/task/sqlite-task-store.js +30 -1
- package/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/dist/runtime-v2/task-status.d.ts +2 -1
- package/dist/runtime-v2/task-status.d.ts.map +1 -1
- package/dist/runtime-v2/task-status.js +5 -1
- package/dist/runtime-v2/task-status.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createPITaskDiagnosticJson } from '../pitask-metadata.js';
|
|
3
|
+
import { HUMAN_REVIEW_REASON } from '../owner-review.js';
|
|
4
|
+
import { buildOwnerDecisionReview, } from '../owner-decision-review.js';
|
|
5
|
+
const EVALUATOR_ID = 'evaluator-review-1';
|
|
6
|
+
const ARTIFICER_TASK_ID = 'artificer-review-1';
|
|
7
|
+
const SCRIBE_TASK_ID = 'scribe-review-1';
|
|
8
|
+
const EVALUATOR_ARTIFACT_ID = 'pi-art-evaluator-review-1-run-1';
|
|
9
|
+
const ARTIFICER_ARTIFACT_ID = 'pi-art-artificer-review-1-run-1';
|
|
10
|
+
const SCRIBE_ARTIFACT_ID = 'pi-art-scribe-review-1-run-1';
|
|
11
|
+
function metadata(taskKind) {
|
|
12
|
+
const dependencyTaskIds = taskKind === 'evaluator'
|
|
13
|
+
? [ARTIFICER_TASK_ID]
|
|
14
|
+
: taskKind === 'artificer' ? [SCRIBE_TASK_ID] : [];
|
|
15
|
+
return {
|
|
16
|
+
dependencyTaskIds,
|
|
17
|
+
channel: 'code_tool_hook',
|
|
18
|
+
timeoutMs: 300_000,
|
|
19
|
+
inputArtifactRefs: [],
|
|
20
|
+
outputArtifactRefs: [],
|
|
21
|
+
...(taskKind === 'evaluator'
|
|
22
|
+
? {
|
|
23
|
+
runnerDecision: 'needs_revision',
|
|
24
|
+
revisionCount: 0,
|
|
25
|
+
completionIntent: {
|
|
26
|
+
decision: 'needs_revision',
|
|
27
|
+
sourceRunId: 'run-1',
|
|
28
|
+
revisionEpoch: 0,
|
|
29
|
+
status: 'pending',
|
|
30
|
+
},
|
|
31
|
+
humanReviewContext: {
|
|
32
|
+
reasonCode: HUMAN_REVIEW_REASON.evaluatorRepairBudgetExhausted,
|
|
33
|
+
sourceRunId: 'run-1',
|
|
34
|
+
sourceArtifactId: EVALUATOR_ARTIFACT_ID,
|
|
35
|
+
revisionEpoch: 0,
|
|
36
|
+
createdAt: '2026-08-31T00:00:00.000Z',
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
: {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function task(taskId, taskKind) {
|
|
43
|
+
return {
|
|
44
|
+
taskId,
|
|
45
|
+
taskKind,
|
|
46
|
+
status: taskKind === 'evaluator' ? 'needs_human_review' : 'succeeded',
|
|
47
|
+
attemptCount: 1,
|
|
48
|
+
maxAttempts: 3,
|
|
49
|
+
createdAt: '2026-08-31T00:00:00.000Z',
|
|
50
|
+
updatedAt: '2026-08-31T00:05:00.000Z',
|
|
51
|
+
diagnosticJson: createPITaskDiagnosticJson(metadata(taskKind)),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function artifact(input) {
|
|
55
|
+
return {
|
|
56
|
+
artifactId: input.artifactId,
|
|
57
|
+
artifactKind: 'principle',
|
|
58
|
+
sourceTaskId: input.sourceTaskId,
|
|
59
|
+
lineageArtifactIds: input.lineageArtifactIds,
|
|
60
|
+
validationStatus: 'pending',
|
|
61
|
+
contentJson: JSON.stringify(input.content),
|
|
62
|
+
createdAt: '2026-08-31T00:00:00.000Z',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function makeStore(options = {}) {
|
|
66
|
+
const oldArtificerArtifactId = 'pi-art-artificer-review-old-run-1';
|
|
67
|
+
const oldScribeArtifactId = 'pi-art-scribe-review-old-run-1';
|
|
68
|
+
const records = [
|
|
69
|
+
...(options.includeOlderRepair ? [
|
|
70
|
+
artifact({ artifactId: oldScribeArtifactId, sourceTaskId: 'scribe-review-old', lineageArtifactIds: [], content: {
|
|
71
|
+
principleDraft: { statement: 'OLD principle must not be shown.' },
|
|
72
|
+
} }),
|
|
73
|
+
artifact({ artifactId: oldArtificerArtifactId, sourceTaskId: 'artificer-review-old', lineageArtifactIds: [oldScribeArtifactId], content: {
|
|
74
|
+
sourceScribeArtifactId: oldScribeArtifactId,
|
|
75
|
+
sourceTrace: { scribeArtifactId: oldScribeArtifactId },
|
|
76
|
+
implementationSummary: 'OLD implementation must not be shown.',
|
|
77
|
+
} }),
|
|
78
|
+
] : []),
|
|
79
|
+
artifact({ artifactId: SCRIBE_ARTIFACT_ID, sourceTaskId: SCRIBE_TASK_ID, lineageArtifactIds: [], content: {
|
|
80
|
+
principleDraft: {
|
|
81
|
+
title: 'Confirm destructive changes',
|
|
82
|
+
statement: 'Before destructive changes, confirm the exact target with the Owner.',
|
|
83
|
+
rationale: 'Prevents irreversible work against an ambiguous target.',
|
|
84
|
+
applicability: ['filesystem writes'],
|
|
85
|
+
antiPatterns: ['guessing the target'],
|
|
86
|
+
},
|
|
87
|
+
} }),
|
|
88
|
+
artifact({ artifactId: ARTIFICER_ARTIFACT_ID, sourceTaskId: ARTIFICER_TASK_ID, lineageArtifactIds: [SCRIBE_ARTIFACT_ID], content: {
|
|
89
|
+
...(options.codeBearingArtificer
|
|
90
|
+
? {
|
|
91
|
+
taskId: ARTIFICER_TASK_ID,
|
|
92
|
+
implementationCode: 'export function confirmTarget() { return true; }',
|
|
93
|
+
goldenTraceCases: [
|
|
94
|
+
{
|
|
95
|
+
caseId: 'allows-confirmed-target',
|
|
96
|
+
kind: 'positive',
|
|
97
|
+
toolName: 'write_file',
|
|
98
|
+
params: { confirmed: true },
|
|
99
|
+
expectedDecision: 'allow',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
caseId: 'blocks-unconfirmed-target',
|
|
103
|
+
kind: 'negative',
|
|
104
|
+
toolName: 'write_file',
|
|
105
|
+
params: { confirmed: false },
|
|
106
|
+
expectedDecision: 'block',
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
generatedAt: '2026-08-31T00:00:00.000Z',
|
|
110
|
+
}
|
|
111
|
+
: {}),
|
|
112
|
+
sourceScribeArtifactId: SCRIBE_ARTIFACT_ID,
|
|
113
|
+
sourceTrace: { scribeArtifactId: SCRIBE_ARTIFACT_ID },
|
|
114
|
+
implementationSummary: 'Adds a confirmation gate before destructive writes.',
|
|
115
|
+
affectedTools: ['write_file', 'apply_patch'],
|
|
116
|
+
risks: ['May add one interaction before a destructive action.'],
|
|
117
|
+
...options.artificerExtra,
|
|
118
|
+
} }),
|
|
119
|
+
artifact({ artifactId: EVALUATOR_ARTIFACT_ID, sourceTaskId: EVALUATOR_ID, lineageArtifactIds: [
|
|
120
|
+
...(options.includeOlderRepair ? [oldArtificerArtifactId] : []),
|
|
121
|
+
ARTIFICER_ARTIFACT_ID,
|
|
122
|
+
], content: {
|
|
123
|
+
sourceArtificerArtifactId: ARTIFICER_ARTIFACT_ID,
|
|
124
|
+
sourceTrace: { artificerArtifactId: ARTIFICER_ARTIFACT_ID },
|
|
125
|
+
evaluation: {
|
|
126
|
+
decision: 'needs_revision',
|
|
127
|
+
score: 0.72,
|
|
128
|
+
strengths: ['The target check is deterministic.'],
|
|
129
|
+
concerns: [options.concern ?? 'The confirmation copy is ambiguous.'],
|
|
130
|
+
requiredChanges: ['Clarify the confirmation copy.'],
|
|
131
|
+
},
|
|
132
|
+
...(options.adversarialPassed === undefined
|
|
133
|
+
? {}
|
|
134
|
+
: { adversarialResult: { passed: options.adversarialPassed, failedCases: [] } }),
|
|
135
|
+
...options.evaluatorExtra,
|
|
136
|
+
} }),
|
|
137
|
+
].filter((record) => options.includeScribe !== false || record.artifactId !== SCRIBE_ARTIFACT_ID);
|
|
138
|
+
const tasks = [
|
|
139
|
+
task(EVALUATOR_ID, 'evaluator'),
|
|
140
|
+
...(options.includeOlderRepair ? [
|
|
141
|
+
task('artificer-review-old', 'artificer'),
|
|
142
|
+
task('scribe-review-old', 'scribe'),
|
|
143
|
+
] : []),
|
|
144
|
+
task(ARTIFICER_TASK_ID, 'artificer'),
|
|
145
|
+
...(options.includeScribe === false ? [] : [task(SCRIBE_TASK_ID, 'scribe')]),
|
|
146
|
+
];
|
|
147
|
+
return {
|
|
148
|
+
getTask: async (id) => tasks.find((entry) => entry.taskId === id) ?? null,
|
|
149
|
+
listArtifactsBySourceTask: async (id) => records.filter((entry) => entry.sourceTaskId === id),
|
|
150
|
+
getArtifactById: async (id) => records.find((entry) => entry.artifactId === id) ?? null,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
describe('Owner Decision Review Snapshot', () => {
|
|
154
|
+
it('builds a distinct evidence-rich evaluator brief and reports an absent adversarial result as not_run', async () => {
|
|
155
|
+
const snapshot = await buildOwnerDecisionReview(makeStore(), EVALUATOR_ID);
|
|
156
|
+
expect(snapshot?.brief.kind).toBe('evaluator');
|
|
157
|
+
if (snapshot?.brief.kind !== 'evaluator')
|
|
158
|
+
throw new Error('expected evaluator brief');
|
|
159
|
+
expect(snapshot.brief.principle.statement).toContain('confirm the exact target');
|
|
160
|
+
expect(snapshot.brief.implementation.summary).toContain('confirmation gate');
|
|
161
|
+
expect(snapshot.brief.implementation.affectedTools).toEqual(['write_file', 'apply_patch']);
|
|
162
|
+
expect(snapshot.brief.concerns).toEqual(['The confirmation copy is ambiguous.']);
|
|
163
|
+
expect(snapshot.evidence.deterministicChecks).toEqual([
|
|
164
|
+
{ check: 'adversarial_hard_gate', status: 'not_run' },
|
|
165
|
+
]);
|
|
166
|
+
expect(snapshot.evidence.completeness).toBe('complete');
|
|
167
|
+
});
|
|
168
|
+
it('requires acknowledgement for a partial but still identifiable review', async () => {
|
|
169
|
+
const snapshot = await buildOwnerDecisionReview(makeStore({ includeScribe: false }), EVALUATOR_ID);
|
|
170
|
+
expect(snapshot?.evidence.completeness).toBe('partial');
|
|
171
|
+
expect(snapshot?.capability.acceptRequirement).toEqual({
|
|
172
|
+
kind: 'acknowledge_partial_evidence',
|
|
173
|
+
});
|
|
174
|
+
expect(snapshot?.capability.finalOfferedActions).toContain('accept_current');
|
|
175
|
+
});
|
|
176
|
+
it('forbids accept when the deterministic adversarial hard gate explicitly failed', async () => {
|
|
177
|
+
const snapshot = await buildOwnerDecisionReview(makeStore({ adversarialPassed: false }), EVALUATOR_ID);
|
|
178
|
+
expect(snapshot?.evidence.deterministicChecks).toEqual([
|
|
179
|
+
{ check: 'adversarial_hard_gate', status: 'failed' },
|
|
180
|
+
]);
|
|
181
|
+
expect(snapshot?.capability.finalOfferedActions).not.toContain('accept_current');
|
|
182
|
+
expect(snapshot?.capability.acceptRequirement).toEqual({
|
|
183
|
+
kind: 'forbidden',
|
|
184
|
+
reasonCode: 'adversarial_hard_gate_failed',
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
it('forbids accept when a validated code-bearing Artificer output has not passed the hard gate', async () => {
|
|
188
|
+
const snapshot = await buildOwnerDecisionReview(makeStore({ codeBearingArtificer: true }), EVALUATOR_ID);
|
|
189
|
+
expect(snapshot?.evidence.deterministicChecks[0]?.status).toBe('not_run');
|
|
190
|
+
expect(snapshot?.capability.finalOfferedActions).not.toContain('accept_current');
|
|
191
|
+
expect(snapshot?.capability.acceptRequirement).toEqual({
|
|
192
|
+
kind: 'forbidden',
|
|
193
|
+
reasonCode: 'adversarial_hard_gate_not_passed',
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
it('uses the canonical code-bearing assessment when affectedTools is omitted', async () => {
|
|
197
|
+
const snapshot = await buildOwnerDecisionReview(makeStore({
|
|
198
|
+
codeBearingArtificer: true,
|
|
199
|
+
artificerExtra: { affectedTools: undefined },
|
|
200
|
+
}), EVALUATOR_ID);
|
|
201
|
+
expect(snapshot?.evidence.deterministicChecks[0]?.status).toBe('not_run');
|
|
202
|
+
expect(snapshot?.capability.finalOfferedActions).not.toContain('accept_current');
|
|
203
|
+
expect(snapshot?.capability.acceptRequirement).toEqual({
|
|
204
|
+
kind: 'forbidden',
|
|
205
|
+
reasonCode: 'adversarial_hard_gate_not_passed',
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
it('keeps legacy compatibility when the Artificer artifact is not a validated code-bearing output', async () => {
|
|
209
|
+
const snapshot = await buildOwnerDecisionReview(makeStore(), EVALUATOR_ID);
|
|
210
|
+
expect(snapshot?.capability.finalOfferedActions).toContain('accept_current');
|
|
211
|
+
});
|
|
212
|
+
it('uses the evaluator-declared repair lineage instead of the first reachable artificer', async () => {
|
|
213
|
+
const snapshot = await buildOwnerDecisionReview(makeStore({ includeOlderRepair: true }), EVALUATOR_ID);
|
|
214
|
+
expect(snapshot?.brief.kind).toBe('evaluator');
|
|
215
|
+
if (snapshot?.brief.kind !== 'evaluator')
|
|
216
|
+
throw new Error('expected evaluator brief');
|
|
217
|
+
expect(snapshot.brief.principle.statement).toContain('confirm the exact target');
|
|
218
|
+
expect(snapshot.brief.implementation.summary).toContain('confirmation gate');
|
|
219
|
+
expect(snapshot.evidence.manifest.sources.map((source) => source.stableId))
|
|
220
|
+
.not.toContain('pi-art-artificer-review-old-run-1');
|
|
221
|
+
});
|
|
222
|
+
it('changes the evidence digest when visible decision semantics change', async () => {
|
|
223
|
+
const first = await buildOwnerDecisionReview(makeStore({ concern: 'Concern A' }), EVALUATOR_ID);
|
|
224
|
+
const second = await buildOwnerDecisionReview(makeStore({ concern: 'Concern B' }), EVALUATOR_ID);
|
|
225
|
+
expect(first?.evidence.digest).toMatch(/^[a-f0-9]{64}$/);
|
|
226
|
+
expect(second?.evidence.digest).not.toBe(first?.evidence.digest);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=owner-decision-review.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner-decision-review.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/internalization/__tests__/owner-decision-review.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
* I. transition 仲裁使用 effective decision
|
|
14
14
|
* K. evaluator 收敛 schema 不变量 (SPEC §18.4)
|
|
15
15
|
*/
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion -- legacy fixture assertions predate staged-file linting. */
|
|
16
17
|
import { describe, it, expect } from 'vitest';
|
|
17
18
|
import { serializePITaskMetadata, parsePITaskMetadata, hydratePITaskRecord, createPITaskDiagnosticJson, } from '../pitask-metadata.js';
|
|
18
19
|
import { HUMAN_REVIEW_REASON, LEGACY_EVALUATOR_BUDGET_EXHAUSTED, buildOwnerReviewKey, collectOwnerDecisionFacts, deriveOwnerDecisionCapability, resolveEffectiveRunnerDecision, effectiveDecisionFor, planOwnerVerdictOverrideResume, detectHardGateFailureFromArtifact, } from '../owner-review.js';
|
|
19
|
-
import { applyOwnerResolution, sanitizeOwnerInstruction } from '../owner-resolution-service.js';
|
|
20
|
+
import { applyOwnerResolution, reviewStoreFromStateManager, sanitizeOwnerInstruction, } from '../owner-resolution-service.js';
|
|
21
|
+
import { buildOwnerDecisionReview } from '../owner-decision-review.js';
|
|
20
22
|
import { buildRepairRevisionCauseId, reopenTaskForRevision, resolveRolloutRevisionTarget } from '../revision-reopen.js';
|
|
21
23
|
import { decideInternalizationTransition, transitionInputFromTask } from '../internalization-transition-decision.js';
|
|
22
24
|
import { ownerRetryNeedsHumanReviewTask } from '../owner-retry.js';
|
|
@@ -157,6 +159,17 @@ function makeInMemoryStateManager(tasks, artifacts) {
|
|
|
157
159
|
async updateTaskIfDiagnosticJsonUnchanged(id, expected, patch) {
|
|
158
160
|
return store.updateTaskIfDiagnosticJsonUnchanged(id, expected, patch);
|
|
159
161
|
},
|
|
162
|
+
async updateTaskIfDiagnosticJsonAndArtifactsUnchanged(input) {
|
|
163
|
+
for (const bound of input.artifacts) {
|
|
164
|
+
const current = await artifacts.getArtifactById(bound.artifactId);
|
|
165
|
+
if (!current
|
|
166
|
+
|| current.sourceTaskId !== bound.sourceTaskId
|
|
167
|
+
|| JSON.stringify(current.lineageArtifactIds) !== bound.lineageArtifactIdsJson
|
|
168
|
+
|| current.contentJson !== bound.contentJson)
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return store.updateTaskIfDiagnosticJsonUnchanged(input.taskId, input.expectedDiagnosticJson, input.patch);
|
|
172
|
+
},
|
|
160
173
|
async markTaskSucceeded(id, resultRef) { await store.updateTask(id, { status: 'succeeded', resultRef }); },
|
|
161
174
|
};
|
|
162
175
|
return sm;
|
|
@@ -193,6 +206,27 @@ describe('PRI-629 metadata: humanReviewContext + ownerResolutions round-trip', (
|
|
|
193
206
|
const json = serializePITaskMetadata(baseMeta({ ownerResolutions: [bad] }));
|
|
194
207
|
expect(parsePITaskMetadata(json)).toBeNull();
|
|
195
208
|
});
|
|
209
|
+
it('PRI-634: humanReviewContext.detail round-trips through serialize → parse (legacy 无 detail 照常 hydrate)', () => {
|
|
210
|
+
const json = serializePITaskMetadata(baseMeta({
|
|
211
|
+
humanReviewContext: { ...nhrContext(), detail: '1 rule/validated artifact(s) rejected: pi-art-x (missing: goldenTrace)' },
|
|
212
|
+
}));
|
|
213
|
+
const parsed = parsePITaskMetadata(json);
|
|
214
|
+
expect(parsed?.humanReviewContext?.detail)
|
|
215
|
+
.toBe('1 rule/validated artifact(s) rejected: pi-art-x (missing: goldenTrace)');
|
|
216
|
+
// legacy: 无 detail 的 context 照常 hydrate,字段为 undefined 而非空串
|
|
217
|
+
const legacy = parsePITaskMetadata(serializePITaskMetadata(baseMeta({ humanReviewContext: nhrContext() })));
|
|
218
|
+
expect(legacy?.humanReviewContext?.detail).toBeUndefined();
|
|
219
|
+
});
|
|
220
|
+
it('PRI-634: malformed humanReviewContext.detail fails closed (rc-1/rc-2 trust boundary)', () => {
|
|
221
|
+
// detail 一旦存在必须是 non-empty string;object/array/number/空串一律
|
|
222
|
+
// 整条 metadata fail closed,禁止静默 hydrate 成类型谎言 (detail?: string)。
|
|
223
|
+
for (const badDetail of [{}, [], 123, '']) {
|
|
224
|
+
const json = serializePITaskMetadata(baseMeta({
|
|
225
|
+
humanReviewContext: { ...nhrContext(), detail: badDetail },
|
|
226
|
+
}));
|
|
227
|
+
expect(parsePITaskMetadata(json)).toBeNull();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
196
230
|
it('rejects duplicate reviewKey within ownerResolutions (authority corruption fails closed)', () => {
|
|
197
231
|
const rec = (id) => ({
|
|
198
232
|
resolutionId: id, reviewKey: 'odk_same', action: 'reject_current', status: 'applied',
|
|
@@ -396,6 +430,143 @@ describe('PRI-629 applyOwnerResolution (SPEC §7/§10/§11)', () => {
|
|
|
396
430
|
const pi = hydratePITaskRecord((await sm.getTask(EVAL_ID)));
|
|
397
431
|
expect(pi?.ownerResolutions?.length).toBe(1); // 无第二条记录
|
|
398
432
|
});
|
|
433
|
+
it('same reviewKey/action with changed lineage evidence digest is not an idempotent replay', async () => {
|
|
434
|
+
const { sm, deps, req } = await setup();
|
|
435
|
+
const decision = await sm.piArtifactStore.getArtifactById(ARTIFACT_ID);
|
|
436
|
+
expect(decision).not.toBeNull();
|
|
437
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
438
|
+
...decision,
|
|
439
|
+
lineageArtifactIds: ['pi-art-artificer-old'],
|
|
440
|
+
});
|
|
441
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
442
|
+
artifactId: 'pi-art-artificer-old',
|
|
443
|
+
artifactKind: 'principle',
|
|
444
|
+
sourceTaskId: ARTIFER_ID,
|
|
445
|
+
lineageArtifactIds: [],
|
|
446
|
+
validationStatus: 'pending',
|
|
447
|
+
contentJson: JSON.stringify({
|
|
448
|
+
implementationSummary: 'Implementation A',
|
|
449
|
+
affectedTools: ['write_file'],
|
|
450
|
+
risks: [],
|
|
451
|
+
}),
|
|
452
|
+
createdAt: '2026-08-30T00:00:00.000Z',
|
|
453
|
+
updatedAt: '2026-08-30T00:00:00.000Z',
|
|
454
|
+
});
|
|
455
|
+
const firstReview = await buildOwnerDecisionReview(reviewStoreFromStateManager(sm), EVAL_ID);
|
|
456
|
+
expect(firstReview).not.toBeNull();
|
|
457
|
+
const artificer = await sm.piArtifactStore.getArtifactById('pi-art-artificer-old');
|
|
458
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
459
|
+
...artificer,
|
|
460
|
+
contentJson: JSON.stringify({
|
|
461
|
+
implementationSummary: 'Implementation B',
|
|
462
|
+
affectedTools: ['write_file'],
|
|
463
|
+
risks: [],
|
|
464
|
+
}),
|
|
465
|
+
updatedAt: '2026-08-30T00:01:00.000Z',
|
|
466
|
+
});
|
|
467
|
+
const secondReview = await buildOwnerDecisionReview(reviewStoreFromStateManager(sm), EVAL_ID);
|
|
468
|
+
expect(secondReview?.reviewKey).toBe(firstReview?.reviewKey);
|
|
469
|
+
expect(secondReview?.evidence.digest).not.toBe(firstReview?.evidence.digest);
|
|
470
|
+
await sm.piArtifactStore.upsertArtifact(artificer);
|
|
471
|
+
const firstRequest = req('reject_current', {
|
|
472
|
+
expectedEvidenceDigest: firstReview.evidence.digest,
|
|
473
|
+
});
|
|
474
|
+
const first = await applyOwnerResolution(deps, {
|
|
475
|
+
taskId: EVAL_ID,
|
|
476
|
+
request: firstRequest,
|
|
477
|
+
identity,
|
|
478
|
+
});
|
|
479
|
+
expect(first.status).toBe('resolved');
|
|
480
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
481
|
+
...artificer,
|
|
482
|
+
contentJson: JSON.stringify({
|
|
483
|
+
implementationSummary: 'Implementation B',
|
|
484
|
+
affectedTools: ['write_file'],
|
|
485
|
+
risks: [],
|
|
486
|
+
}),
|
|
487
|
+
updatedAt: '2026-08-30T00:01:00.000Z',
|
|
488
|
+
});
|
|
489
|
+
const replay = await applyOwnerResolution(deps, {
|
|
490
|
+
taskId: EVAL_ID,
|
|
491
|
+
request: req('reject_current', {
|
|
492
|
+
expectedEvidenceDigest: secondReview.evidence.digest,
|
|
493
|
+
}),
|
|
494
|
+
identity,
|
|
495
|
+
});
|
|
496
|
+
expect(replay.status).toBe('stale_owner_decision');
|
|
497
|
+
});
|
|
498
|
+
it('revalidates independently persisted evidence after the CAS read and refuses a raced digest', async () => {
|
|
499
|
+
const { sm, deps, req } = await setup();
|
|
500
|
+
const decision = await sm.piArtifactStore.getArtifactById(ARTIFACT_ID);
|
|
501
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
502
|
+
...decision,
|
|
503
|
+
lineageArtifactIds: ['pi-art-artificer-old'],
|
|
504
|
+
});
|
|
505
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
506
|
+
artifactId: 'pi-art-artificer-old',
|
|
507
|
+
artifactKind: 'principle',
|
|
508
|
+
sourceTaskId: ARTIFER_ID,
|
|
509
|
+
lineageArtifactIds: [],
|
|
510
|
+
validationStatus: 'pending',
|
|
511
|
+
contentJson: JSON.stringify({ implementationSummary: 'Evidence A', affectedTools: ['write_file'] }),
|
|
512
|
+
createdAt: '2026-08-30T00:00:00.000Z',
|
|
513
|
+
updatedAt: '2026-08-30T00:00:00.000Z',
|
|
514
|
+
});
|
|
515
|
+
const rendered = await buildOwnerDecisionReview(reviewStoreFromStateManager(sm), EVAL_ID);
|
|
516
|
+
expect(rendered).not.toBeNull();
|
|
517
|
+
const originalGetTask = sm.getTask.bind(sm);
|
|
518
|
+
let evaluatorReads = 0;
|
|
519
|
+
sm.getTask = async (id) => {
|
|
520
|
+
const task = await originalGetTask(id);
|
|
521
|
+
if (id === EVAL_ID && ++evaluatorReads === 3) {
|
|
522
|
+
const artifact = await sm.piArtifactStore.getArtifactById('pi-art-artificer-old');
|
|
523
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
524
|
+
...artifact,
|
|
525
|
+
contentJson: JSON.stringify({ implementationSummary: 'Evidence B', affectedTools: ['write_file'] }),
|
|
526
|
+
updatedAt: '2026-08-30T00:01:00.000Z',
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return task;
|
|
530
|
+
};
|
|
531
|
+
const outcome = await applyOwnerResolution(deps, {
|
|
532
|
+
taskId: EVAL_ID,
|
|
533
|
+
request: req('reject_current', { expectedEvidenceDigest: rendered.evidence.digest }),
|
|
534
|
+
identity,
|
|
535
|
+
});
|
|
536
|
+
expect(outcome.status).toBe('stale_owner_decision');
|
|
537
|
+
const unchanged = hydratePITaskRecord((await originalGetTask(EVAL_ID)));
|
|
538
|
+
expect(unchanged?.status).toBe('needs_human_review');
|
|
539
|
+
expect(unchanged?.ownerResolutions).toBeUndefined();
|
|
540
|
+
});
|
|
541
|
+
it('does not persist when evidence changes after the final review rebuild but before the task mutation', async () => {
|
|
542
|
+
const { sm, deps, req } = await setup();
|
|
543
|
+
const rendered = await buildOwnerDecisionReview(reviewStoreFromStateManager(sm), EVAL_ID);
|
|
544
|
+
expect(rendered).not.toBeNull();
|
|
545
|
+
const originalAtomicUpdate = sm.updateTaskIfDiagnosticJsonAndArtifactsUnchanged.bind(sm);
|
|
546
|
+
let intercepted = false;
|
|
547
|
+
sm.updateTaskIfDiagnosticJsonAndArtifactsUnchanged = async (...args) => {
|
|
548
|
+
if (!intercepted) {
|
|
549
|
+
intercepted = true;
|
|
550
|
+
const decision = await sm.piArtifactStore.getArtifactById(ARTIFACT_ID);
|
|
551
|
+
await sm.piArtifactStore.upsertArtifact({
|
|
552
|
+
...decision,
|
|
553
|
+
contentJson: JSON.stringify({ changedAfterFinalReview: true }),
|
|
554
|
+
updatedAt: '2026-08-30T00:02:00.000Z',
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return originalAtomicUpdate(...args);
|
|
558
|
+
};
|
|
559
|
+
const outcome = await applyOwnerResolution(deps, {
|
|
560
|
+
taskId: EVAL_ID,
|
|
561
|
+
request: req('reject_current', { expectedEvidenceDigest: rendered.evidence.digest }),
|
|
562
|
+
identity,
|
|
563
|
+
});
|
|
564
|
+
expect(intercepted).toBe(true);
|
|
565
|
+
expect(outcome.status).toBe('stale_owner_decision');
|
|
566
|
+
const unchanged = hydratePITaskRecord((await sm.getTask(EVAL_ID)));
|
|
567
|
+
expect(unchanged?.status).toBe('needs_human_review');
|
|
568
|
+
expect(unchanged?.ownerResolutions).toBeUndefined();
|
|
569
|
+
});
|
|
399
570
|
it('same reviewKey + different action → already_resolved (conflict)', async () => {
|
|
400
571
|
const { deps, req } = await setup();
|
|
401
572
|
await applyOwnerResolution(deps, { taskId: EVAL_ID, request: req('accept_current'), identity });
|