create-principles-disciple 1.79.0 → 1.81.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 (196) hide show
  1. package/console/package.json +1 -0
  2. package/core/dist/runtime-v2/__tests__/admission-gate.test.js +6 -6
  3. package/core/dist/runtime-v2/__tests__/admission-gate.test.js.map +1 -1
  4. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +39 -0
  5. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  6. package/core/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js +52 -0
  7. package/core/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js.map +1 -1
  8. package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice.test.js +245 -1
  9. package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice.test.js.map +1 -1
  10. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js +131 -1
  11. package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js.map +1 -1
  12. package/core/dist/runtime-v2/__tests__/fixtures/llm-e2e-config.d.ts.map +1 -1
  13. package/core/dist/runtime-v2/__tests__/fixtures/llm-e2e-config.js +4 -2
  14. package/core/dist/runtime-v2/__tests__/fixtures/llm-e2e-config.js.map +1 -1
  15. package/core/dist/runtime-v2/__tests__/scribe-runner-vslice.test.js +425 -2
  16. package/core/dist/runtime-v2/__tests__/scribe-runner-vslice.test.js.map +1 -1
  17. package/core/dist/runtime-v2/__tests__/telemetry-event.test.d.ts +2 -0
  18. package/core/dist/runtime-v2/__tests__/telemetry-event.test.d.ts.map +1 -0
  19. package/core/dist/runtime-v2/__tests__/telemetry-event.test.js +69 -0
  20. package/core/dist/runtime-v2/__tests__/telemetry-event.test.js.map +1 -0
  21. package/core/dist/runtime-v2/admission-gate.d.ts.map +1 -1
  22. package/core/dist/runtime-v2/admission-gate.js +0 -8
  23. package/core/dist/runtime-v2/admission-gate.js.map +1 -1
  24. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.d.ts +15 -0
  25. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.d.ts.map +1 -0
  26. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +685 -0
  27. package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -0
  28. package/core/dist/runtime-v2/config/index.d.ts +14 -0
  29. package/core/dist/runtime-v2/config/index.d.ts.map +1 -0
  30. package/core/dist/runtime-v2/config/index.js +16 -0
  31. package/core/dist/runtime-v2/config/index.js.map +1 -0
  32. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +14 -0
  33. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -0
  34. package/core/dist/runtime-v2/config/pd-config-defaults.js +74 -0
  35. package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -0
  36. package/core/dist/runtime-v2/config/pd-config-effective.d.ts +14 -0
  37. package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -0
  38. package/core/dist/runtime-v2/config/pd-config-effective.js +118 -0
  39. package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -0
  40. package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts +35 -0
  41. package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -0
  42. package/core/dist/runtime-v2/config/pd-config-feature-flags.js +99 -0
  43. package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -0
  44. package/core/dist/runtime-v2/config/pd-config-redaction.d.ts +22 -0
  45. package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -0
  46. package/core/dist/runtime-v2/config/pd-config-redaction.js +179 -0
  47. package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -0
  48. package/core/dist/runtime-v2/config/pd-config-types.d.ts +124 -0
  49. package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -0
  50. package/core/dist/runtime-v2/config/pd-config-types.js +35 -0
  51. package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -0
  52. package/core/dist/runtime-v2/config/pd-config-validate.d.ts +16 -0
  53. package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -0
  54. package/core/dist/runtime-v2/config/pd-config-validate.js +443 -0
  55. package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -0
  56. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +10 -10
  57. package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -1
  58. package/core/dist/runtime-v2/feedback/index.d.ts +1 -1
  59. package/core/dist/runtime-v2/feedback/index.d.ts.map +1 -1
  60. package/core/dist/runtime-v2/feedback/index.js +1 -1
  61. package/core/dist/runtime-v2/feedback/index.js.map +1 -1
  62. package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts +2 -0
  63. package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts.map +1 -1
  64. package/core/dist/runtime-v2/feedback/redact-sensitive.js +32 -3
  65. package/core/dist/runtime-v2/feedback/redact-sensitive.js.map +1 -1
  66. package/core/dist/runtime-v2/index.d.ts +5 -1
  67. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  68. package/core/dist/runtime-v2/index.js +9 -1
  69. package/core/dist/runtime-v2/index.js.map +1 -1
  70. package/core/dist/runtime-v2/internalization/__tests__/peer-runner-lineage-injection.test.d.ts +2 -0
  71. package/core/dist/runtime-v2/internalization/__tests__/peer-runner-lineage-injection.test.d.ts.map +1 -0
  72. package/core/dist/runtime-v2/internalization/__tests__/peer-runner-lineage-injection.test.js +95 -0
  73. package/core/dist/runtime-v2/internalization/__tests__/peer-runner-lineage-injection.test.js.map +1 -0
  74. package/core/dist/runtime-v2/internalization/__tests__/philosopher-runner-trust-boundary.test.d.ts +2 -0
  75. package/core/dist/runtime-v2/internalization/__tests__/philosopher-runner-trust-boundary.test.d.ts.map +1 -0
  76. package/core/dist/runtime-v2/internalization/__tests__/philosopher-runner-trust-boundary.test.js +398 -0
  77. package/core/dist/runtime-v2/internalization/__tests__/philosopher-runner-trust-boundary.test.js.map +1 -0
  78. package/core/dist/runtime-v2/internalization/artificer-output.d.ts +3 -2
  79. package/core/dist/runtime-v2/internalization/artificer-output.d.ts.map +1 -1
  80. package/core/dist/runtime-v2/internalization/artificer-output.js +40 -31
  81. package/core/dist/runtime-v2/internalization/artificer-output.js.map +1 -1
  82. package/core/dist/runtime-v2/internalization/artificer-runner.d.ts +59 -38
  83. package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  84. package/core/dist/runtime-v2/internalization/artificer-runner.js +122 -394
  85. package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  86. package/core/dist/runtime-v2/internalization/dreamer-output.d.ts +4 -3
  87. package/core/dist/runtime-v2/internalization/dreamer-output.d.ts.map +1 -1
  88. package/core/dist/runtime-v2/internalization/dreamer-output.js +11 -9
  89. package/core/dist/runtime-v2/internalization/dreamer-output.js.map +1 -1
  90. package/core/dist/runtime-v2/internalization/dreamer-runner.d.ts +31 -92
  91. package/core/dist/runtime-v2/internalization/dreamer-runner.d.ts.map +1 -1
  92. package/core/dist/runtime-v2/internalization/dreamer-runner.js +80 -492
  93. package/core/dist/runtime-v2/internalization/dreamer-runner.js.map +1 -1
  94. package/core/dist/runtime-v2/internalization/evaluator-output.d.ts +2 -2
  95. package/core/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
  96. package/core/dist/runtime-v2/internalization/evaluator-output.js +29 -23
  97. package/core/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
  98. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +74 -48
  99. package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  100. package/core/dist/runtime-v2/internalization/evaluator-runner.js +165 -443
  101. package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  102. package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts +14 -0
  103. package/core/dist/runtime-v2/internalization/peer-runner-contracts.d.ts.map +1 -1
  104. package/core/dist/runtime-v2/internalization/peer-runner-contracts.js +21 -0
  105. package/core/dist/runtime-v2/internalization/peer-runner-contracts.js.map +1 -1
  106. package/core/dist/runtime-v2/internalization/philosopher-output.d.ts +8 -2
  107. package/core/dist/runtime-v2/internalization/philosopher-output.d.ts.map +1 -1
  108. package/core/dist/runtime-v2/internalization/philosopher-output.js +16 -11
  109. package/core/dist/runtime-v2/internalization/philosopher-output.js.map +1 -1
  110. package/core/dist/runtime-v2/internalization/philosopher-runner.d.ts +36 -55
  111. package/core/dist/runtime-v2/internalization/philosopher-runner.d.ts.map +1 -1
  112. package/core/dist/runtime-v2/internalization/philosopher-runner.js +118 -400
  113. package/core/dist/runtime-v2/internalization/philosopher-runner.js.map +1 -1
  114. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.d.ts.map +1 -1
  115. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js +3 -1
  116. package/core/dist/runtime-v2/internalization/rollout-reviewer-runner.js.map +1 -1
  117. package/core/dist/runtime-v2/internalization/scribe-output.d.ts +8 -2
  118. package/core/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
  119. package/core/dist/runtime-v2/internalization/scribe-output.js +33 -17
  120. package/core/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
  121. package/core/dist/runtime-v2/internalization/scribe-runner.d.ts +56 -49
  122. package/core/dist/runtime-v2/internalization/scribe-runner.d.ts.map +1 -1
  123. package/core/dist/runtime-v2/internalization/scribe-runner.js +117 -397
  124. package/core/dist/runtime-v2/internalization/scribe-runner.js.map +1 -1
  125. package/core/dist/runtime-v2/internalization/trainer-runner.d.ts.map +1 -1
  126. package/core/dist/runtime-v2/internalization/trainer-runner.js +3 -1
  127. package/core/dist/runtime-v2/internalization/trainer-runner.js.map +1 -1
  128. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-trust-boundary.test.d.ts +2 -0
  129. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-trust-boundary.test.d.ts.map +1 -0
  130. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-trust-boundary.test.js +379 -0
  131. package/core/dist/runtime-v2/runner/__tests__/base-peer-runner-trust-boundary.test.js.map +1 -0
  132. package/core/dist/runtime-v2/runner/base-peer-runner.d.ts +122 -0
  133. package/core/dist/runtime-v2/runner/base-peer-runner.d.ts.map +1 -0
  134. package/core/dist/runtime-v2/runner/base-peer-runner.js +528 -0
  135. package/core/dist/runtime-v2/runner/base-peer-runner.js.map +1 -0
  136. package/core/dist/runtime-v2/runner/peer-runner-types.d.ts +107 -0
  137. package/core/dist/runtime-v2/runner/peer-runner-types.d.ts.map +1 -0
  138. package/core/dist/runtime-v2/runner/peer-runner-types.js +13 -0
  139. package/core/dist/runtime-v2/runner/peer-runner-types.js.map +1 -0
  140. package/core/dist/telemetry-event.d.ts +2 -2
  141. package/core/dist/telemetry-event.d.ts.map +1 -1
  142. package/core/dist/telemetry-event.js +89 -0
  143. package/core/dist/telemetry-event.js.map +1 -1
  144. package/dist/installer.d.ts +1 -1
  145. package/dist/installer.d.ts.map +1 -1
  146. package/dist/installer.js +39 -10
  147. package/dist/installer.js.map +1 -1
  148. package/dist/mvp-config.d.ts +33 -0
  149. package/dist/mvp-config.d.ts.map +1 -1
  150. package/dist/mvp-config.js +174 -0
  151. package/dist/mvp-config.js.map +1 -1
  152. package/package.json +3 -3
  153. package/pd-cli/dist/commands/config-doctor.d.ts +17 -0
  154. package/pd-cli/dist/commands/config-doctor.d.ts.map +1 -0
  155. package/pd-cli/dist/commands/config-doctor.js +143 -0
  156. package/pd-cli/dist/commands/config-doctor.js.map +1 -0
  157. package/pd-cli/dist/commands/console.d.ts +18 -0
  158. package/pd-cli/dist/commands/console.d.ts.map +1 -1
  159. package/pd-cli/dist/commands/console.js +439 -0
  160. package/pd-cli/dist/commands/console.js.map +1 -1
  161. package/pd-cli/dist/commands/runtime-features.d.ts +23 -8
  162. package/pd-cli/dist/commands/runtime-features.d.ts.map +1 -1
  163. package/pd-cli/dist/commands/runtime-features.js +72 -31
  164. package/pd-cli/dist/commands/runtime-features.js.map +1 -1
  165. package/pd-cli/dist/index.d.ts +1 -1
  166. package/pd-cli/dist/index.js +83 -31
  167. package/pd-cli/dist/index.js.map +1 -1
  168. package/pd-cli/dist/services/config-doctor.d.ts +102 -0
  169. package/pd-cli/dist/services/config-doctor.d.ts.map +1 -0
  170. package/pd-cli/dist/services/config-doctor.js +426 -0
  171. package/pd-cli/dist/services/config-doctor.js.map +1 -0
  172. package/pd-cli/dist/services/console-launcher.d.ts +110 -0
  173. package/pd-cli/dist/services/console-launcher.d.ts.map +1 -0
  174. package/pd-cli/dist/services/console-launcher.js +282 -0
  175. package/pd-cli/dist/services/console-launcher.js.map +1 -0
  176. package/pd-cli/dist/services/pd-config-loader.d.ts +64 -0
  177. package/pd-cli/dist/services/pd-config-loader.d.ts.map +1 -0
  178. package/pd-cli/dist/services/pd-config-loader.js +156 -0
  179. package/pd-cli/dist/services/pd-config-loader.js.map +1 -0
  180. package/pd-cli/package.json +3 -1
  181. package/plugin/dist/core/event-log.d.ts +10 -0
  182. package/plugin/dist/core/event-log.js +85 -1
  183. package/plugin/dist/core/pd-config-loader.d.ts +96 -0
  184. package/plugin/dist/core/pd-config-loader.js +307 -0
  185. package/plugin/dist/core/runtime-v2-prompt-activation-reader.d.ts +4 -0
  186. package/plugin/dist/core/runtime-v2-prompt-activation-reader.js +12 -56
  187. package/plugin/dist/core/surface-guard.d.ts +12 -8
  188. package/plugin/dist/core/surface-guard.js +51 -2
  189. package/plugin/dist/hooks/gate.js +3 -0
  190. package/plugin/dist/hooks/prompt.js +4 -5
  191. package/plugin/dist/index.d.ts +4 -0
  192. package/plugin/dist/index.js +70 -94
  193. package/plugin/dist/service/correction-observer-service.d.ts +8 -0
  194. package/plugin/dist/service/correction-observer-service.js +48 -29
  195. package/plugin/dist/utils/workspace-resolver.d.ts +33 -1
  196. package/plugin/dist/utils/workspace-resolver.js +182 -3
@@ -1,8 +1,9 @@
1
- import { PDRuntimeError } from '../error-categories.js';
1
+ import { PDRuntimeError, isPDErrorCategory } from '../error-categories.js';
2
2
  import { hydratePITaskRecord } from './pitask-metadata.js';
3
- import { RunnerPhase } from '../runner/runner-phase.js';
4
3
  import { EvaluatorPromptBuilder } from './evaluator-prompt-builder.js';
5
- const DEFAULT_EVALUATOR_RUNNER_OPTIONS = {
4
+ import { injectRunnerLineageIfAbsent } from './peer-runner-contracts.js';
5
+ import { BasePeerRunner } from '../runner/base-peer-runner.js';
6
+ export const DEFAULT_EVALUATOR_RUNNER_OPTIONS = {
6
7
  pollIntervalMs: 5_000,
7
8
  timeoutMs: 300_000,
8
9
  defaultMaxAttempts: 3,
@@ -18,118 +19,22 @@ export function resolveEvaluatorRunnerOptions(options) {
18
19
  agentId: options.agentId ?? DEFAULT_EVALUATOR_RUNNER_OPTIONS.agentId,
19
20
  };
20
21
  }
21
- const EVALUATOR_PERMANENT_ERROR_CATEGORIES = new Set([
22
- 'storage_unavailable', 'workspace_invalid', 'capability_missing', 'cancelled', 'input_invalid', 'output_invalid',
23
- ]);
24
- export class EvaluatorRunner {
25
- phase = RunnerPhase.Idle;
26
- resolvedOptions;
27
- stateManager;
28
- runtimeAdapter;
29
- eventEmitter;
22
+ // ── EvaluatorRunner ───────────────────────────────────────────────────────────
23
+ export class EvaluatorRunner extends BasePeerRunner {
30
24
  validator;
31
- artifactStore;
32
25
  constructor(deps, options) {
33
- this.stateManager = deps.stateManager;
34
- this.runtimeAdapter = deps.runtimeAdapter;
35
- this.eventEmitter = deps.eventEmitter;
36
- this.validator = deps.validator;
37
- this.artifactStore = deps.artifactStore;
38
- this.resolvedOptions = resolveEvaluatorRunnerOptions(options);
39
- }
40
- get currentPhase() {
41
- return this.phase;
42
- }
43
- emitEvaluatorEvent(eventType, taskId, payload) {
44
- this.eventEmitter.emitTelemetry({
45
- eventType: eventType,
46
- traceId: taskId,
47
- timestamp: new Date().toISOString(),
48
- sessionId: this.resolvedOptions.owner,
49
- agentId: this.resolvedOptions.agentId,
50
- payload,
26
+ super(deps, options, {
27
+ runnerName: 'evaluator',
28
+ expectedTaskKind: 'evaluator',
29
+ defaultAgentId: 'evaluator',
30
+ resultRefPrefix: 'evaluator',
51
31
  });
32
+ this.validator = deps.validator;
52
33
  }
53
- async run(taskId) {
54
- this.phase = RunnerPhase.Idle;
55
- // eslint-disable-next-line @typescript-eslint/init-declarations
56
- let leasedTask;
57
- try {
58
- leasedTask = await this.stateManager.acquireLease({
59
- taskId,
60
- owner: this.resolvedOptions.owner,
61
- runtimeKind: this.resolvedOptions.runtimeKind,
62
- });
63
- }
64
- catch (error) {
65
- return await this.handleLeaseOrPhaseError(taskId, error);
66
- }
67
- if (leasedTask.taskKind !== 'evaluator') {
68
- this.emitEvaluatorEvent('evaluator_wrong_task_kind', taskId, {
69
- expectedKind: 'evaluator',
70
- actualKind: leasedTask.taskKind,
71
- });
72
- return this.retryOrFail({
73
- taskId,
74
- task: leasedTask,
75
- errorCategory: 'input_invalid',
76
- failureReason: `Task kind must be 'evaluator', got '${leasedTask.taskKind}'`,
77
- });
78
- }
79
- this.emitEvaluatorEvent('evaluator_task_leased', taskId, {
80
- taskKind: 'evaluator',
81
- attemptCount: leasedTask.attemptCount,
82
- });
83
- try {
84
- const storeRunId = await this.resolveStoreRunId(taskId);
85
- this.phase = RunnerPhase.BuildingContext;
86
- const { contextHash, artificerArtifact, sourceArtificerArtifactId } = await this.buildContext(taskId);
87
- if (!artificerArtifact || !sourceArtificerArtifactId) {
88
- return this.retryOrFail({
89
- taskId,
90
- task: leasedTask,
91
- errorCategory: 'input_invalid',
92
- failureReason: sourceArtificerArtifactId ? 'Artificer dependency artifact not found' : 'Artificer dependency artifact ID not resolved',
93
- });
94
- }
95
- this.emitEvaluatorEvent('evaluator_context_built', taskId, { contextHash });
96
- this.phase = RunnerPhase.Invoking;
97
- const runHandle = await this.invokeRuntime({ taskId, contextHash, artificerArtifact, sourceArtificerArtifactId });
98
- this.emitEvaluatorEvent('evaluator_run_started', taskId, {
99
- runtimeKind: this.resolvedOptions.runtimeKind,
100
- });
101
- this.phase = RunnerPhase.Polling;
102
- const finalStatus = await this.pollUntilTerminal(runHandle);
103
- if (finalStatus.status !== 'succeeded') {
104
- return await this.handleRuntimeFailure(taskId, leasedTask, finalStatus);
105
- }
106
- this.phase = RunnerPhase.FetchingOutput;
107
- const output = await this.fetchAndParseOutput(runHandle.runId);
108
- this.phase = RunnerPhase.Validating;
109
- const validationResult = await this.validator.validate(output, taskId, sourceArtificerArtifactId ?? undefined);
110
- if (!validationResult.valid) {
111
- return await this.handleValidationError({
112
- taskId,
113
- task: leasedTask,
114
- errors: validationResult.errors,
115
- errorCategory: validationResult.errorCategory,
116
- });
117
- }
118
- this.emitEvaluatorEvent('evaluator_output_validated', taskId, {
119
- evaluationDecision: output.evaluation.decision,
120
- evaluationScore: output.evaluation.score,
121
- });
122
- return await this.succeedTask({
123
- taskId,
124
- runId: storeRunId,
125
- output,
126
- task: leasedTask,
127
- contextHash,
128
- });
129
- }
130
- catch (error) {
131
- return await this.handlePostLeaseError(taskId, leasedTask, error);
132
- }
34
+ // ── Abstract implementations ────────────────────────────────────────────────
35
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
36
+ get permanentErrorCategories() {
37
+ return new Set(['storage_unavailable', 'workspace_invalid', 'capability_missing', 'cancelled', 'input_invalid', 'output_invalid']);
133
38
  }
134
39
  async buildContext(taskId) {
135
40
  const task = await this.stateManager.getTask(taskId);
@@ -139,8 +44,8 @@ export class EvaluatorRunner {
139
44
  const piTask = hydratePITaskRecord(task);
140
45
  const deps = piTask?.dependencyTaskIds ?? [];
141
46
  if (deps.length === 0) {
142
- this.emitEvaluatorEvent('evaluator_no_dependencies', taskId, {});
143
- return { contextHash: 'empty', artificerArtifact: null, sourceArtificerArtifactId: null };
47
+ this.emitEvent('no_dependencies', taskId, {});
48
+ throw new PDRuntimeError('input_invalid', 'Artificer dependency artifact ID not resolved');
144
49
  }
145
50
  for (const depId of deps) {
146
51
  const depTask = await this.stateManager.getTask(depId);
@@ -149,7 +54,7 @@ export class EvaluatorRunner {
149
54
  if (depTask.taskKind !== 'artificer')
150
55
  continue;
151
56
  if (depTask.status !== 'succeeded') {
152
- this.emitEvaluatorEvent('evaluator_dependency_not_succeeded', taskId, {
57
+ this.emitEvent('dependency_not_succeeded', taskId, {
153
58
  depTaskId: depId,
154
59
  depStatus: depTask.status,
155
60
  });
@@ -161,170 +66,149 @@ export class EvaluatorRunner {
161
66
  if (!firstArtifact)
162
67
  continue;
163
68
  const artifactRef = firstArtifact.artifactId;
164
- this.emitEvaluatorEvent('evaluator_artificer_dep_selected', taskId, {
69
+ this.emitEvent('artificer_dep_selected', taskId, {
165
70
  depTaskId: depId,
166
71
  artifactId: firstArtifact.artifactId,
167
72
  });
168
73
  return {
169
- contextHash: EvaluatorRunner.hashContextRefs([artifactRef]),
74
+ contextHash: BasePeerRunner.hashContextRefs([artifactRef]),
170
75
  artificerArtifact: firstArtifact.contentJson,
171
76
  sourceArtificerArtifactId: firstArtifact.artifactId,
172
77
  };
173
78
  }
174
79
  }
175
- this.emitEvaluatorEvent('evaluator_no_artificer_artifact', taskId, {});
176
- return { contextHash: 'empty', artificerArtifact: null, sourceArtificerArtifactId: null };
177
- }
178
- static hashContextRefs(refs) {
179
- if (refs.length === 0)
180
- return 'empty';
181
- const str = refs.join('|');
182
- let hash = 0;
183
- for (let i = 0; i < str.length; i++) {
184
- hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;
185
- }
186
- return `ctx-${Math.abs(hash).toString(16)}`;
187
- }
188
- async resolveStoreRunId(taskId) {
189
- const runs = await this.stateManager.getRunsByTask(taskId);
190
- const latestRun = runs[runs.length - 1];
191
- if (!latestRun) {
192
- throw new PDRuntimeError('execution_failed', `No run records found for task ${taskId} after lease acquisition`);
193
- }
194
- return latestRun.runId;
80
+ this.emitEvent('no_artificer_artifact', taskId, {});
81
+ throw new PDRuntimeError('input_invalid', 'Artificer dependency artifact not found');
195
82
  }
196
- async invokeRuntime(params) {
83
+ async invokeRuntime(taskId, context) {
197
84
  let parsedArtificerArtifact = null;
198
- if (params.artificerArtifact) {
85
+ if (context.artificerArtifact) {
199
86
  try {
200
- parsedArtificerArtifact = JSON.parse(params.artificerArtifact);
87
+ parsedArtificerArtifact = JSON.parse(context.artificerArtifact);
201
88
  }
202
89
  catch {
203
- parsedArtificerArtifact = params.artificerArtifact;
90
+ parsedArtificerArtifact = context.artificerArtifact;
204
91
  }
205
92
  }
206
93
  const builder = new EvaluatorPromptBuilder();
207
94
  const { message } = builder.buildPrompt({
208
- taskId: params.taskId,
209
- contextHash: params.contextHash,
95
+ taskId,
96
+ contextHash: context.contextHash,
210
97
  artificerArtifact: parsedArtificerArtifact,
211
- sourceArtificerArtifactId: params.sourceArtificerArtifactId,
98
+ sourceArtificerArtifactId: context.sourceArtificerArtifactId ?? '',
212
99
  });
213
- const startInput = {
100
+ return this.runtimeAdapter.startRun({
214
101
  agentSpec: { agentId: this.resolvedOptions.agentId, schemaVersion: 'v1' },
215
- taskRef: { taskId: params.taskId },
102
+ taskRef: { taskId },
216
103
  inputPayload: message,
217
104
  contextItems: [],
218
105
  outputSchemaRef: 'evaluator-output-v1',
219
106
  timeoutMs: this.resolvedOptions.timeoutMs,
220
- };
221
- return this.runtimeAdapter.startRun(startInput);
107
+ });
222
108
  }
223
- async pollUntilTerminal(runHandle) {
224
- const deadline = Date.now() + this.resolvedOptions.timeoutMs;
225
- const terminalStatuses = ['succeeded', 'failed', 'timed_out', 'cancelled'];
226
- while (Date.now() < deadline) {
227
- const status = await this.runtimeAdapter.pollRun(runHandle.runId);
228
- if (terminalStatuses.includes(status.status)) {
229
- return status;
230
- }
231
- await this.sleep(this.resolvedOptions.pollIntervalMs);
232
- }
233
- try {
234
- const finalPoll = await this.runtimeAdapter.pollRun(runHandle.runId);
235
- if (terminalStatuses.includes(finalPoll.status)) {
236
- return finalPoll;
237
- }
238
- }
239
- catch { /* fall through to cancel/timeout */ }
240
- let cancelFailed = false;
241
- try {
242
- await this.runtimeAdapter.cancelRun(runHandle.runId);
243
- }
244
- catch (cancelErr) {
245
- cancelFailed = true;
246
- this.emitEvaluatorEvent('evaluator_cancel_run_failed', runHandle.runId, {
247
- runId: runHandle.runId,
248
- errorMessage: cancelErr instanceof Error ? cancelErr.message : String(cancelErr),
249
- });
109
+ async validateOutput(output, taskId, context) {
110
+ const result = await this.validator.validate(output, taskId, context.sourceArtificerArtifactId ?? undefined);
111
+ // Trust-boundary: validator is an injected dependency returning `string | undefined`
112
+ // for errorCategory. We must not `as`-cast; validate at runtime (ERR-001, ERR-005).
113
+ const rawCategory = result.errorCategory;
114
+ let errorCategory;
115
+ if (rawCategory == null) {
116
+ errorCategory = undefined;
117
+ }
118
+ else if (isPDErrorCategory(rawCategory)) {
119
+ errorCategory = rawCategory;
120
+ }
121
+ else {
122
+ // Invalid errorCategory from validator — fail loud, do not pass through
123
+ return {
124
+ valid: false,
125
+ errors: [...result.errors, `invalid errorCategory: ${rawCategory}`],
126
+ errorCategory: 'output_invalid',
127
+ };
250
128
  }
251
- const cancelNote = cancelFailed ? ' (cancelRun also failed)' : '';
252
- throw new PDRuntimeError('timeout', `Run ${runHandle.runId} timed out after ${this.resolvedOptions.timeoutMs}ms${cancelNote}`);
129
+ return {
130
+ valid: result.valid,
131
+ errors: result.errors,
132
+ errorCategory,
133
+ };
253
134
  }
254
- async fetchAndParseOutput(runId) {
255
- const result = await this.runtimeAdapter.fetchOutput(runId);
256
- if (!result || !result.payload) {
257
- throw new PDRuntimeError('output_invalid', `No output available for run ${runId}`);
135
+ // eslint-disable-next-line @typescript-eslint/max-params
136
+ async succeedTask(taskId, runId, output, task, contextHash, context) {
137
+ // Lineage consistency: sourceArtificerArtifactId must match buildContext result (ERR-004).
138
+ if (context.sourceArtificerArtifactId && output.sourceArtificerArtifactId !== context.sourceArtificerArtifactId) {
139
+ throw new PDRuntimeError('output_invalid', `sourceArtificerArtifactId mismatch: expected ${context.sourceArtificerArtifactId}, got ${output.sourceArtificerArtifactId}`);
258
140
  }
259
- const payload = result.payload;
260
- if (typeof payload !== 'object' || payload === null) {
261
- throw new PDRuntimeError('output_invalid', `Output payload is not an object for run ${runId}`);
262
- }
263
- if (typeof payload.evaluation !== 'object' || payload.evaluation === null) {
264
- throw new PDRuntimeError('output_invalid', `Output payload missing evaluation object for run ${runId}`);
265
- }
266
- return result.payload;
267
- }
268
- async succeedTask(ctx) {
141
+ // Store output before marking succeeded
269
142
  try {
270
- await this.stateManager.updateRunOutput(ctx.runId, JSON.stringify(ctx.output));
143
+ await this.stateManager.updateRunOutput(runId, JSON.stringify(output));
271
144
  }
272
145
  catch (updateErr) {
273
- this.emitEvaluatorEvent('evaluator_update_output_failed', ctx.taskId, {
274
- runId: ctx.runId,
146
+ this.emitEvent('update_output_failed', taskId, {
147
+ runId,
275
148
  errorMessage: updateErr instanceof Error ? updateErr.message : String(updateErr),
276
149
  });
277
150
  throw updateErr;
278
151
  }
279
- const artifactId = `pi-art-${ctx.taskId}-${ctx.runId}`;
280
- const now = new Date().toISOString();
152
+ // Resolve lineage artifact IDs
281
153
  let lineageArtifactIds = [];
154
+ let lineageHasRejected = false;
282
155
  try {
283
- const piTask = hydratePITaskRecord(ctx.task);
284
- const deps = piTask?.dependencyTaskIds ?? [];
285
- const results = await Promise.allSettled(deps.map((depId) => this.artifactStore.listBySourceTaskId(depId)));
286
- for (const result of results) {
287
- if (result.status === 'fulfilled') {
288
- for (const artifact of result.value) {
289
- lineageArtifactIds.push(artifact.artifactId);
290
- }
291
- }
292
- }
156
+ const lineageResult = await this.resolveLineageArtifactIds(taskId);
157
+ lineageArtifactIds = lineageResult.ids;
158
+ lineageHasRejected = lineageResult.hasRejected;
159
+ }
160
+ catch (lineageErr) {
161
+ this.emitEvent('lineage_resolve_failed', taskId, {
162
+ runId,
163
+ errorMessage: lineageErr instanceof Error ? lineageErr.message : String(lineageErr),
164
+ });
293
165
  }
294
- catch { /* lineage resolution failure is non-fatal */ }
166
+ if (lineageHasRejected) {
167
+ this.emitEvent('lineage_partial', taskId, {
168
+ runId,
169
+ resolvedCount: lineageArtifactIds.length,
170
+ warning: 'Some dependency artifact queries were rejected; lineage may be incomplete',
171
+ });
172
+ }
173
+ // Write PIArtifact via artifactStore (idempotent upsert)
174
+ const artifactId = `pi-art-${taskId}-${runId}`;
175
+ const now = new Date().toISOString();
295
176
  try {
296
177
  await this.artifactStore.upsertArtifact({
297
178
  artifactId,
298
179
  artifactKind: 'principle',
299
- sourceTaskId: ctx.taskId,
180
+ sourceTaskId: taskId,
300
181
  lineageArtifactIds,
301
182
  validationStatus: 'pending',
302
- contentJson: JSON.stringify(ctx.output),
183
+ contentJson: JSON.stringify(output),
303
184
  createdAt: now,
304
185
  updatedAt: now,
305
186
  });
306
187
  }
307
188
  catch (artifactErr) {
308
- this.emitEvaluatorEvent('evaluator_artifact_write_failed', ctx.taskId, {
309
- runId: ctx.runId,
189
+ this.emitEvent('artifact_write_failed', taskId, {
190
+ runId,
310
191
  errorMessage: artifactErr instanceof Error ? artifactErr.message : String(artifactErr),
311
192
  });
312
193
  return this.retryOrFail({
313
- taskId: ctx.taskId,
314
- task: ctx.task,
194
+ taskId,
195
+ task,
315
196
  errorCategory: 'artifact_commit_failed',
316
197
  failureReason: `PIArtifact write failed: ${artifactErr instanceof Error ? artifactErr.message : String(artifactErr)}`,
317
198
  });
318
199
  }
319
- const resultRef = `evaluator://${ctx.runId}`;
320
- if (ctx.output.evaluation.decision === 'approved') {
321
- const principleArtifactId = await this.resolvePrincipleBearerArtifact(ctx.output, ctx.taskId);
200
+ // ── Evaluator-specific: validate principle-bearing Scribe artifact ──
201
+ // This is the critical business logic: approved evaluator must validate
202
+ // the Scribe principle artifact, NOT the Artificer plan artifact.
203
+ if (output.evaluation.decision === 'approved') {
204
+ const principleArtifactId = await this.resolvePrincipleBearerArtifact(output, taskId);
322
205
  if (principleArtifactId) {
323
206
  try {
324
207
  const updated = await this.artifactStore.updateValidationStatus(principleArtifactId, 'validated');
325
208
  if (!updated) {
326
- this.emitEvaluatorEvent('evaluator_source_validation_update_not_found', ctx.taskId, {
327
- runId: ctx.runId,
209
+ // updateValidationStatus returned false — fail loud with structured telemetry (ERR-018)
210
+ this.emitEvent('source_validation_update_not_found', taskId, {
211
+ runId,
328
212
  sourceArtifactId: principleArtifactId,
329
213
  reason: 'principle_artifact_not_found_in_store',
330
214
  nextAction: 'verify_artifact_lineage_and_store_consistency',
@@ -332,228 +216,88 @@ export class EvaluatorRunner {
332
216
  }
333
217
  }
334
218
  catch (updateErr) {
335
- this.emitEvaluatorEvent('evaluator_source_validation_update_failed', ctx.taskId, {
336
- runId: ctx.runId,
219
+ this.emitEvent('source_validation_update_failed', taskId, {
220
+ runId,
337
221
  sourceArtifactId: principleArtifactId,
338
222
  errorMessage: updateErr instanceof Error ? updateErr.message : String(updateErr),
339
223
  });
340
224
  }
341
225
  }
342
226
  }
227
+ // Mark task succeeded
228
+ const resultRef = `${this.config.resultRefPrefix}://${runId}`;
343
229
  try {
344
- await this.stateManager.markTaskSucceeded(ctx.taskId, resultRef);
230
+ await this.stateManager.markTaskSucceeded(taskId, resultRef);
345
231
  }
346
232
  catch (stateErr) {
347
- this.emitEvaluatorEvent('evaluator_mark_succeeded_failed', ctx.taskId, {
348
- taskId: ctx.taskId,
349
- runId: ctx.runId,
233
+ this.emitEvent('mark_succeeded_failed', taskId, {
234
+ taskId,
235
+ runId,
350
236
  errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
351
237
  });
352
238
  throw stateErr;
353
239
  }
354
- this.emitEvaluatorEvent('evaluator_task_succeeded', ctx.taskId, {
355
- attemptCount: ctx.task.attemptCount,
240
+ this.emitEvent('task_succeeded', taskId, {
241
+ attemptCount: task.attemptCount,
356
242
  resultRef,
357
- evaluationDecision: ctx.output.evaluation.decision,
358
- evaluationScore: ctx.output.evaluation.score,
243
+ evaluationDecision: output.evaluation.decision,
244
+ evaluationScore: output.evaluation.score,
359
245
  });
360
- this.phase = RunnerPhase.Completed;
361
246
  return {
362
247
  status: 'succeeded',
363
- taskId: ctx.taskId,
364
- runId: ctx.runId,
248
+ taskId,
249
+ runId,
365
250
  artifactId,
366
251
  resultRef,
367
- contextHash: ctx.contextHash,
368
- output: ctx.output,
369
- attemptCount: ctx.task.attemptCount,
252
+ contextHash,
253
+ output,
254
+ attemptCount: task.attemptCount,
370
255
  };
371
256
  }
372
- async handleRuntimeFailure(taskId, task, runStatus) {
373
- const errorCategory = this.mapRunStatusToErrorCategory(runStatus.status);
374
- this.emitEvaluatorEvent('evaluator_run_failed', taskId, {
375
- runStatus: runStatus.status,
376
- errorCategory,
377
- });
378
- return this.retryOrFail({
379
- taskId,
380
- task,
381
- errorCategory,
382
- failureReason: `Runtime execution ended with status: ${runStatus.status}`,
383
- });
384
- }
385
- async handleValidationError(ctx) {
386
- const category = (ctx.errorCategory ?? 'output_invalid');
387
- this.emitEvaluatorEvent('evaluator_output_invalid', ctx.taskId, {
388
- errorCount: ctx.errors.length,
389
- errorCategory: category,
390
- });
391
- return this.retryOrFail({
392
- taskId: ctx.taskId,
393
- task: ctx.task,
394
- errorCategory: category,
395
- failureReason: `Validation failed: ${ctx.errors.join('; ')}`,
396
- });
397
- }
398
- async handleLeaseOrPhaseError(taskId, error) {
399
- const classified = this.classifyError(error);
400
- if (classified.category === 'lease_conflict') {
401
- this.emitEvaluatorEvent('evaluator_run_failed', taskId, {
402
- errorCategory: 'lease_conflict',
403
- errorMessage: classified.message,
404
- });
405
- return {
406
- status: 'failed',
407
- taskId,
408
- errorCategory: 'lease_conflict',
409
- failureReason: classified.message,
410
- attemptCount: 1,
411
- };
412
- }
413
- this.emitEvaluatorEvent('evaluator_run_failed', taskId, {
414
- errorCategory: classified.category,
415
- errorMessage: classified.message,
416
- });
417
- const task = {
418
- taskId,
419
- taskKind: 'evaluator',
420
- status: 'leased',
421
- createdAt: new Date().toISOString(),
422
- updatedAt: new Date().toISOString(),
423
- attemptCount: 1,
424
- maxAttempts: this.resolvedOptions.defaultMaxAttempts,
425
- };
426
- return this.retryOrFail({ taskId, task, errorCategory: classified.category, failureReason: classified.message });
257
+ // ── Optional hooks ──────────────────────────────────────────────────────────
258
+ /**
259
+ * Re-inject taskId if stripped by stripLineageFields (PRI-272 / ERR-008).
260
+ * Only fill when absent via Object.hasOwn — present-but-falsy values
261
+ * must reach validation and fail loud (Runtime Contract Rule 3).
262
+ */
263
+ // eslint-disable-next-line @typescript-eslint/class-methods-use-this
264
+ postFetchTransform(taskId, untrustedOutput) {
265
+ injectRunnerLineageIfAbsent(untrustedOutput, 'taskId', taskId);
427
266
  }
428
- async handlePostLeaseError(taskId, task, error) {
429
- const classified = this.classifyError(error);
430
- this.emitEvaluatorEvent('evaluator_run_failed', taskId, {
431
- errorCategory: classified.category,
432
- errorMessage: classified.message,
267
+ emitSuccessTelemetry(taskId, output) {
268
+ this.emitEvent('decision_recorded', taskId, {
269
+ evaluationDecision: output.evaluation.decision,
270
+ evaluationScore: output.evaluation.score,
433
271
  });
434
- return this.retryOrFail({ taskId, task, errorCategory: classified.category, failureReason: classified.message });
435
272
  }
436
- async retryOrFail(ctx) {
437
- if (this.isPermanentError(ctx.errorCategory)) {
438
- try {
439
- await this.stateManager.markTaskFailed(ctx.taskId, ctx.errorCategory);
440
- }
441
- catch (stateErr) {
442
- this.emitEvaluatorEvent('evaluator_mark_failed_error', ctx.taskId, {
443
- errorCategory: 'storage_unavailable',
444
- attemptCount: ctx.task.attemptCount,
445
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
446
- });
447
- return {
448
- status: 'failed',
449
- taskId: ctx.taskId,
450
- errorCategory: 'storage_unavailable',
451
- failureReason: `State manager error: ${ctx.failureReason}`,
452
- attemptCount: ctx.task.attemptCount,
453
- };
454
- }
455
- this.emitEvaluatorEvent('evaluator_task_failed', ctx.taskId, {
456
- errorCategory: ctx.errorCategory,
457
- attemptCount: ctx.task.attemptCount,
458
- failureReason: ctx.failureReason,
459
- });
460
- this.phase = RunnerPhase.Failed;
461
- return {
462
- status: 'failed',
463
- taskId: ctx.taskId,
464
- errorCategory: ctx.errorCategory,
465
- failureReason: ctx.failureReason,
466
- attemptCount: ctx.task.attemptCount,
467
- };
468
- }
469
- const shouldRetry = this.stateManager.getRetryPolicy().shouldRetry(ctx.task);
470
- if (shouldRetry) {
471
- try {
472
- await this.stateManager.markTaskRetryWait(ctx.taskId, ctx.errorCategory);
473
- }
474
- catch (stateErr) {
475
- this.emitEvaluatorEvent('evaluator_mark_retry_error', ctx.taskId, {
476
- errorCategory: 'storage_unavailable',
477
- attemptCount: ctx.task.attemptCount,
478
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
479
- });
480
- return {
481
- status: 'failed',
482
- taskId: ctx.taskId,
483
- errorCategory: 'storage_unavailable',
484
- failureReason: `State manager error: ${ctx.failureReason}`,
485
- attemptCount: ctx.task.attemptCount,
486
- };
487
- }
488
- this.emitEvaluatorEvent('evaluator_task_retried', ctx.taskId, {
489
- errorCategory: ctx.errorCategory,
490
- attemptCount: ctx.task.attemptCount,
273
+ /**
274
+ * Check lineage strip contract after validation passes.
275
+ * Validates sourceTrace.scribeArtifactId consistency (ERR-004, ERR-008).
276
+ */
277
+ checkLineageIntegrity(taskId, output) {
278
+ // sourceTrace.artificerArtifactId must match sourceArtificerArtifactId
279
+ if (output.sourceTrace.artificerArtifactId !== output.sourceArtificerArtifactId) {
280
+ this.emitEvent('lineage_integrity_violation', taskId, {
281
+ sourceArtificerArtifactId: output.sourceArtificerArtifactId,
282
+ traceArtificerArtifactId: output.sourceTrace.artificerArtifactId,
283
+ reason: 'sourceArtificerArtifactId_and_sourceTrace_artificerArtifactId_mismatch',
491
284
  });
492
- this.phase = RunnerPhase.RetryWaiting;
493
- return {
494
- status: 'retried',
495
- taskId: ctx.taskId,
496
- errorCategory: ctx.errorCategory,
497
- failureReason: ctx.failureReason,
498
- attemptCount: ctx.task.attemptCount,
499
- };
500
- }
501
- try {
502
- await this.stateManager.markTaskFailed(ctx.taskId, 'max_attempts_exceeded');
503
- }
504
- catch (stateErr) {
505
- this.emitEvaluatorEvent('evaluator_mark_failed_error', ctx.taskId, {
506
- errorCategory: 'storage_unavailable',
507
- attemptCount: ctx.task.attemptCount,
508
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
509
- });
510
- return {
511
- status: 'failed',
512
- taskId: ctx.taskId,
513
- errorCategory: 'storage_unavailable',
514
- failureReason: `State manager error: ${ctx.failureReason}`,
515
- attemptCount: ctx.task.attemptCount,
516
- };
517
- }
518
- this.emitEvaluatorEvent('evaluator_task_failed', ctx.taskId, {
519
- errorCategory: 'max_attempts_exceeded',
520
- attemptCount: ctx.task.attemptCount,
521
- failureReason: `Max attempts exceeded: ${ctx.failureReason}`,
522
- });
523
- this.phase = RunnerPhase.Failed;
524
- return {
525
- status: 'failed',
526
- taskId: ctx.taskId,
527
- errorCategory: 'max_attempts_exceeded',
528
- failureReason: `Max attempts exceeded: ${ctx.failureReason}`,
529
- attemptCount: ctx.task.attemptCount,
530
- };
531
- }
532
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
533
- isPermanentError(category) {
534
- return EVALUATOR_PERMANENT_ERROR_CATEGORIES.has(category);
535
- }
536
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
537
- classifyError(error) {
538
- if (error instanceof PDRuntimeError) {
539
- return { category: error.category, message: error.message };
540
- }
541
- if (error instanceof Error) {
542
- return { category: 'execution_failed', message: error.message };
543
- }
544
- return { category: 'execution_failed', message: String(error) };
545
- }
546
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
547
- mapRunStatusToErrorCategory(status) {
548
- switch (status) {
549
- case 'failed': return 'execution_failed';
550
- case 'timed_out': return 'timeout';
551
- case 'cancelled': return 'cancelled';
552
- default: return 'execution_failed';
553
285
  }
554
286
  }
287
+ // ── Evaluator-specific: principle bearer resolution ─────────────────────────
288
+ /**
289
+ * Resolve the principle-bearing artifact that the evaluator should validate.
290
+ *
291
+ * Strategy 1: Use scribeArtifactId from sourceTrace (the Scribe artifact
292
+ * carries principleDraft).
293
+ * Strategy 2: Search lineage for principle-kind artifacts with principleDraft.
294
+ * Strategy 3: No principle-bearing artifact found → telemetry, return null.
295
+ *
296
+ * Ambiguous candidates (more than 1) → fail loud with telemetry, return null.
297
+ * Never silently pick the first candidate (ERR-018, ERR-019).
298
+ */
555
299
  async resolvePrincipleBearerArtifact(output, taskId) {
556
- // Strategy 1: Use scribeArtifactId from sourceTrace (the Scribe artifact carries principleDraft)
300
+ // Strategy 1: Use scribeArtifactId from sourceTrace
557
301
  const scribeArtifactId = output.sourceTrace?.scribeArtifactId;
558
302
  if (typeof scribeArtifactId === 'string' && scribeArtifactId.trim() !== '') {
559
303
  const scribeArtifact = await this.artifactStore.getArtifactById(scribeArtifactId);
@@ -561,13 +305,13 @@ export class EvaluatorRunner {
561
305
  return scribeArtifactId;
562
306
  }
563
307
  // Scribe artifact not found or wrong kind — fall through to lineage search
564
- this.emitEvaluatorEvent('evaluator_scribe_artifact_not_principle', taskId, {
308
+ this.emitEvent('scribe_artifact_not_principle', taskId, {
565
309
  scribeArtifactId,
566
310
  actualKind: scribeArtifact?.artifactKind ?? 'not_found',
567
311
  });
568
312
  }
569
313
  // Strategy 2: Search lineage for all principle-kind artifacts with principleDraft content
570
- const lineageArtifactIds = await this.resolveLineageArtifactIds(taskId);
314
+ const { ids: lineageArtifactIds } = await this.resolveLineageArtifactIds(taskId);
571
315
  const candidates = [];
572
316
  for (const lineageId of lineageArtifactIds) {
573
317
  const artifact = await this.artifactStore.getArtifactById(lineageId);
@@ -584,15 +328,16 @@ export class EvaluatorRunner {
584
328
  return only ?? null;
585
329
  }
586
330
  if (candidates.length > 1) {
587
- this.emitEvaluatorEvent('evaluator_principle_bearer_ambiguous', taskId, {
331
+ // Ambiguous — fail loud, do NOT silently pick first (ERR-018)
332
+ this.emitEvent('principle_bearer_ambiguous', taskId, {
588
333
  candidateArtifactIds: candidates,
589
334
  reason: 'multiple_principle_bearing_artifacts_in_lineage',
590
335
  nextAction: 'disambiguate_principle_source_or_fix_lineage',
591
336
  });
592
337
  return null;
593
338
  }
594
- // Strategy 3: Fallback — no principle-bearing artifact found
595
- this.emitEvaluatorEvent('evaluator_no_principle_bearer_found', taskId, {
339
+ // Strategy 3: No principle-bearing artifact found
340
+ this.emitEvent('no_principle_bearer_found', taskId, {
596
341
  runId: output.taskId,
597
342
  scribeArtifactId: scribeArtifactId ?? 'not_provided',
598
343
  lineageCount: lineageArtifactIds.length,
@@ -601,28 +346,10 @@ export class EvaluatorRunner {
601
346
  });
602
347
  return null;
603
348
  }
604
- async resolveLineageArtifactIds(taskId) {
605
- try {
606
- const task = await this.stateManager.getTask(taskId);
607
- if (!task)
608
- return [];
609
- const piTask = hydratePITaskRecord(task);
610
- const deps = piTask?.dependencyTaskIds ?? [];
611
- const results = await Promise.allSettled(deps.map((depId) => this.artifactStore.listBySourceTaskId(depId)));
612
- const ids = [];
613
- for (const result of results) {
614
- if (result.status === 'fulfilled') {
615
- for (const artifact of result.value) {
616
- ids.push(artifact.artifactId);
617
- }
618
- }
619
- }
620
- return ids;
621
- }
622
- catch {
623
- return [];
624
- }
625
- }
349
+ /**
350
+ * Check if an artifact's contentJson contains principle-bearing content.
351
+ * Uses Object.hasOwn (ERR-013) and runtime type checks (ERR-001, ERR-005).
352
+ */
626
353
  // eslint-disable-next-line @typescript-eslint/class-methods-use-this
627
354
  hasPrincipleDraftContent(contentJson) {
628
355
  try {
@@ -652,10 +379,5 @@ export class EvaluatorRunner {
652
379
  static isRecord(value) {
653
380
  return value !== null && typeof value === 'object' && !Array.isArray(value);
654
381
  }
655
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
656
- sleep(ms) {
657
- return new Promise((resolve) => setTimeout(resolve, ms));
658
- }
659
382
  }
660
- export { DEFAULT_EVALUATOR_RUNNER_OPTIONS };
661
383
  //# sourceMappingURL=evaluator-runner.js.map