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,7 +1,8 @@
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 { ArtificerPromptBuilder } from './artificer-prompt-builder.js';
4
+ import { injectRunnerLineageIfAbsent } from './peer-runner-contracts.js';
5
+ import { BasePeerRunner } from '../runner/base-peer-runner.js';
5
6
  const DEFAULT_ARTIFICER_RUNNER_OPTIONS = {
6
7
  pollIntervalMs: 5_000,
7
8
  timeoutMs: 300_000,
@@ -18,116 +19,22 @@ export function resolveArtificerRunnerOptions(options) {
18
19
  agentId: options.agentId ?? DEFAULT_ARTIFICER_RUNNER_OPTIONS.agentId,
19
20
  };
20
21
  }
21
- export class ArtificerRunner {
22
- phase = RunnerPhase.Idle;
23
- resolvedOptions;
24
- stateManager;
25
- runtimeAdapter;
26
- eventEmitter;
22
+ // ── ArtificerRunner ──────────────────────────────────────────────────────────
23
+ export class ArtificerRunner extends BasePeerRunner {
27
24
  validator;
28
- artifactStore;
29
25
  constructor(deps, options) {
30
- this.stateManager = deps.stateManager;
31
- this.runtimeAdapter = deps.runtimeAdapter;
32
- this.eventEmitter = deps.eventEmitter;
33
- this.validator = deps.validator;
34
- this.artifactStore = deps.artifactStore;
35
- this.resolvedOptions = resolveArtificerRunnerOptions(options);
36
- }
37
- get currentPhase() {
38
- return this.phase;
39
- }
40
- emitArtificerEvent(eventType, taskId, payload) {
41
- this.eventEmitter.emitTelemetry({
42
- eventType: eventType,
43
- traceId: taskId,
44
- timestamp: new Date().toISOString(),
45
- sessionId: this.resolvedOptions.owner,
46
- agentId: this.resolvedOptions.agentId,
47
- payload,
26
+ super(deps, options, {
27
+ runnerName: 'artificer',
28
+ expectedTaskKind: 'artificer',
29
+ defaultAgentId: 'artificer',
30
+ resultRefPrefix: 'artificer',
48
31
  });
32
+ this.validator = deps.validator;
49
33
  }
50
- async run(taskId) {
51
- this.phase = RunnerPhase.Idle;
52
- // eslint-disable-next-line @typescript-eslint/init-declarations
53
- let leasedTask;
54
- try {
55
- leasedTask = await this.stateManager.acquireLease({
56
- taskId,
57
- owner: this.resolvedOptions.owner,
58
- runtimeKind: this.resolvedOptions.runtimeKind,
59
- });
60
- }
61
- catch (error) {
62
- return await this.handleLeaseOrPhaseError(taskId, error);
63
- }
64
- if (leasedTask.taskKind !== 'artificer') {
65
- this.emitArtificerEvent('artificer_wrong_task_kind', taskId, {
66
- expectedKind: 'artificer',
67
- actualKind: leasedTask.taskKind,
68
- });
69
- await this.stateManager.markTaskFailed(taskId, 'input_invalid');
70
- return {
71
- status: 'failed',
72
- taskId,
73
- errorCategory: 'input_invalid',
74
- failureReason: `Task kind must be 'artificer', got '${leasedTask.taskKind}'`,
75
- attemptCount: leasedTask.attemptCount,
76
- };
77
- }
78
- this.emitArtificerEvent('artificer_task_leased', taskId, {
79
- taskKind: 'artificer',
80
- attemptCount: leasedTask.attemptCount,
81
- });
82
- try {
83
- const storeRunId = await this.resolveStoreRunId(taskId);
84
- this.phase = RunnerPhase.BuildingContext;
85
- const { contextHash, scribeArtifact, sourceScribeArtifactId } = await this.buildContext(taskId);
86
- if (!scribeArtifact || !sourceScribeArtifactId) {
87
- return this.retryOrFail({
88
- taskId,
89
- task: leasedTask,
90
- errorCategory: 'input_invalid',
91
- failureReason: sourceScribeArtifactId ? 'Scribe dependency artifact not found' : 'Scribe dependency artifact ID not resolved',
92
- });
93
- }
94
- this.emitArtificerEvent('artificer_context_built', taskId, { contextHash });
95
- this.phase = RunnerPhase.Invoking;
96
- const runHandle = await this.invokeRuntime({ taskId, contextHash, scribeArtifact, sourceScribeArtifactId });
97
- this.emitArtificerEvent('artificer_run_started', taskId, {
98
- runtimeKind: this.resolvedOptions.runtimeKind,
99
- });
100
- this.phase = RunnerPhase.Polling;
101
- const finalStatus = await this.pollUntilTerminal(runHandle);
102
- if (finalStatus.status !== 'succeeded') {
103
- return await this.handleRuntimeFailure(taskId, leasedTask, finalStatus);
104
- }
105
- this.phase = RunnerPhase.FetchingOutput;
106
- const output = await this.fetchAndParseOutput(runHandle.runId);
107
- this.phase = RunnerPhase.Validating;
108
- const validationResult = await this.validator.validate(output, taskId, sourceScribeArtifactId ?? undefined);
109
- if (!validationResult.valid) {
110
- return await this.handleValidationError({
111
- taskId,
112
- task: leasedTask,
113
- errors: validationResult.errors,
114
- errorCategory: validationResult.errorCategory,
115
- });
116
- }
117
- this.emitArtificerEvent('artificer_output_validated', taskId, {
118
- implementationSummary: output.implementationPlan.summary,
119
- });
120
- return await this.succeedTask({
121
- taskId,
122
- runId: storeRunId,
123
- output,
124
- task: leasedTask,
125
- contextHash,
126
- });
127
- }
128
- catch (error) {
129
- return await this.handlePostLeaseError(taskId, leasedTask, error);
130
- }
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']);
131
38
  }
132
39
  async buildContext(taskId) {
133
40
  const task = await this.stateManager.getTask(taskId);
@@ -137,7 +44,7 @@ export class ArtificerRunner {
137
44
  const piTask = hydratePITaskRecord(task);
138
45
  const deps = piTask?.dependencyTaskIds ?? [];
139
46
  if (deps.length === 0) {
140
- this.emitArtificerEvent('artificer_no_dependencies', taskId, {});
47
+ this.emitEvent('no_dependencies', taskId, {});
141
48
  return { contextHash: 'empty', scribeArtifact: null, sourceScribeArtifactId: null };
142
49
  }
143
50
  for (const depId of deps) {
@@ -147,7 +54,7 @@ export class ArtificerRunner {
147
54
  if (depTask.taskKind !== 'scribe')
148
55
  continue;
149
56
  if (depTask.status !== 'succeeded') {
150
- this.emitArtificerEvent('artificer_dependency_not_succeeded', taskId, {
57
+ this.emitEvent('dependency_not_succeeded', taskId, {
151
58
  depTaskId: depId,
152
59
  depStatus: depTask.status,
153
60
  });
@@ -159,362 +66,183 @@ export class ArtificerRunner {
159
66
  if (!firstArtifact)
160
67
  continue;
161
68
  const artifactRef = firstArtifact.artifactId;
162
- this.emitArtificerEvent('artificer_scribe_dep_selected', taskId, {
69
+ this.emitEvent('scribe_dep_selected', taskId, {
163
70
  depTaskId: depId,
164
71
  artifactId: firstArtifact.artifactId,
165
72
  });
166
73
  return {
167
- contextHash: ArtificerRunner.hashContextRefs([artifactRef]),
74
+ contextHash: BasePeerRunner.hashContextRefs([artifactRef]),
168
75
  scribeArtifact: firstArtifact.contentJson,
169
76
  sourceScribeArtifactId: firstArtifact.artifactId,
170
77
  };
171
78
  }
172
79
  }
173
- this.emitArtificerEvent('artificer_no_scribe_artifact', taskId, {});
80
+ this.emitEvent('no_scribe_artifact', taskId, {});
174
81
  return { contextHash: 'empty', scribeArtifact: null, sourceScribeArtifactId: null };
175
82
  }
176
- static hashContextRefs(refs) {
177
- if (refs.length === 0)
178
- return 'empty';
179
- const str = refs.join('|');
180
- let hash = 0;
181
- for (let i = 0; i < str.length; i++) {
182
- hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;
83
+ async invokeRuntime(taskId, context) {
84
+ if (!context.scribeArtifact || !context.sourceScribeArtifactId) {
85
+ throw new PDRuntimeError('input_invalid', 'Scribe dependency artifact not resolved');
183
86
  }
184
- return `ctx-${Math.abs(hash).toString(16)}`;
185
- }
186
- async resolveStoreRunId(taskId) {
187
- const runs = await this.stateManager.getRunsByTask(taskId);
188
- const latestRun = runs[runs.length - 1];
189
- if (!latestRun) {
190
- throw new PDRuntimeError('execution_failed', `No run records found for task ${taskId} after lease acquisition`);
87
+ let scribeArtifactInput;
88
+ try {
89
+ scribeArtifactInput = JSON.parse(context.scribeArtifact);
191
90
  }
192
- return latestRun.runId;
193
- }
194
- async invokeRuntime(params) {
195
- let parsedScribeArtifact = null;
196
- if (params.scribeArtifact) {
197
- try {
198
- parsedScribeArtifact = JSON.parse(params.scribeArtifact);
199
- }
200
- catch {
201
- parsedScribeArtifact = params.scribeArtifact;
202
- }
91
+ catch {
92
+ scribeArtifactInput = context.scribeArtifact;
203
93
  }
204
94
  const builder = new ArtificerPromptBuilder();
205
95
  const { message } = builder.buildPrompt({
206
- taskId: params.taskId,
207
- contextHash: params.contextHash,
208
- scribeArtifact: parsedScribeArtifact,
209
- sourceScribeArtifactId: params.sourceScribeArtifactId,
96
+ taskId,
97
+ contextHash: context.contextHash,
98
+ scribeArtifact: scribeArtifactInput,
99
+ sourceScribeArtifactId: context.sourceScribeArtifactId,
210
100
  });
211
- const startInput = {
101
+ return this.runtimeAdapter.startRun({
212
102
  agentSpec: { agentId: this.resolvedOptions.agentId, schemaVersion: 'v1' },
213
- taskRef: { taskId: params.taskId },
103
+ taskRef: { taskId },
214
104
  inputPayload: message,
215
105
  contextItems: [],
216
106
  outputSchemaRef: 'artificer-output-v1',
217
107
  timeoutMs: this.resolvedOptions.timeoutMs,
218
- };
219
- return this.runtimeAdapter.startRun(startInput);
108
+ });
220
109
  }
221
- async pollUntilTerminal(runHandle) {
222
- const deadline = Date.now() + this.resolvedOptions.timeoutMs;
223
- const terminalStatuses = ['succeeded', 'failed', 'timed_out', 'cancelled'];
224
- while (Date.now() < deadline) {
225
- const status = await this.runtimeAdapter.pollRun(runHandle.runId);
226
- if (terminalStatuses.includes(status.status)) {
227
- return status;
228
- }
229
- await this.sleep(this.resolvedOptions.pollIntervalMs);
110
+ async validateOutput(output, taskId, context) {
111
+ const result = await this.validator.validate(output, taskId, context.sourceScribeArtifactId ?? undefined);
112
+ // Trust-boundary: validator returns `string | undefined` for errorCategory.
113
+ // Must not `as`-cast; validate at runtime (ERR-001, ERR-005).
114
+ const rawCategory = result.errorCategory;
115
+ let errorCategory;
116
+ if (rawCategory == null) {
117
+ errorCategory = undefined;
230
118
  }
231
- let cancelFailed = false;
232
- try {
233
- await this.runtimeAdapter.cancelRun(runHandle.runId);
119
+ else if (isPDErrorCategory(rawCategory)) {
120
+ errorCategory = rawCategory;
234
121
  }
235
- catch (cancelErr) {
236
- cancelFailed = true;
237
- this.emitArtificerEvent('artificer_cancel_run_failed', runHandle.runId, {
238
- runId: runHandle.runId,
239
- errorMessage: cancelErr instanceof Error ? cancelErr.message : String(cancelErr),
240
- });
122
+ else {
123
+ // Invalid errorCategory from validator — fail loud, do not pass through
124
+ return {
125
+ valid: false,
126
+ errors: [...result.errors, `invalid errorCategory: ${rawCategory}`],
127
+ errorCategory: 'output_invalid',
128
+ };
241
129
  }
242
- const cancelNote = cancelFailed ? ' (cancelRun also failed)' : '';
243
- throw new PDRuntimeError('timeout', `Run ${runHandle.runId} timed out after ${this.resolvedOptions.timeoutMs}ms${cancelNote}`);
130
+ return {
131
+ valid: result.valid,
132
+ errors: result.errors,
133
+ errorCategory,
134
+ };
244
135
  }
245
- async fetchAndParseOutput(runId) {
246
- const result = await this.runtimeAdapter.fetchOutput(runId);
247
- if (!result || !result.payload) {
248
- throw new PDRuntimeError('output_invalid', `No output available for run ${runId}`);
136
+ // eslint-disable-next-line @typescript-eslint/max-params
137
+ async succeedTask(taskId, runId, output, task, contextHash, context) {
138
+ // Lineage consistency: sourceScribeArtifactId must match buildContext result (ERR-004, ERR-008).
139
+ if (!context.sourceScribeArtifactId || output.sourceScribeArtifactId !== context.sourceScribeArtifactId) {
140
+ throw new PDRuntimeError('output_invalid', `sourceScribeArtifactId mismatch: expected ${context.sourceScribeArtifactId ?? '(none)'}, got ${output.sourceScribeArtifactId}`);
249
141
  }
250
- return result.payload;
251
- }
252
- async succeedTask(ctx) {
142
+ // Store output before marking succeeded
253
143
  try {
254
- await this.stateManager.updateRunOutput(ctx.runId, JSON.stringify(ctx.output));
144
+ await this.stateManager.updateRunOutput(runId, JSON.stringify(output));
255
145
  }
256
146
  catch (updateErr) {
257
- this.emitArtificerEvent('artificer_update_output_failed', ctx.taskId, {
258
- runId: ctx.runId,
147
+ this.emitEvent('update_output_failed', taskId, {
148
+ runId,
259
149
  errorMessage: updateErr instanceof Error ? updateErr.message : String(updateErr),
260
150
  });
261
151
  throw updateErr;
262
152
  }
263
- const artifactId = `pi-art-${ctx.taskId}-${ctx.runId}`;
264
- const now = new Date().toISOString();
153
+ // Resolve lineage artifact IDs
265
154
  let lineageArtifactIds = [];
155
+ let lineageHasRejected = false;
266
156
  try {
267
- const piTask = hydratePITaskRecord(ctx.task);
268
- const deps = piTask?.dependencyTaskIds ?? [];
269
- const results = await Promise.allSettled(deps.map((depId) => this.artifactStore.listBySourceTaskId(depId)));
270
- for (const result of results) {
271
- if (result.status === 'fulfilled') {
272
- for (const artifact of result.value) {
273
- lineageArtifactIds.push(artifact.artifactId);
274
- }
275
- }
276
- }
157
+ const lineageResult = await this.resolveLineageArtifactIds(taskId);
158
+ lineageArtifactIds = lineageResult.ids;
159
+ lineageHasRejected = lineageResult.hasRejected;
160
+ }
161
+ catch (lineageErr) {
162
+ this.emitEvent('lineage_resolve_failed', taskId, {
163
+ runId,
164
+ errorMessage: lineageErr instanceof Error ? lineageErr.message : String(lineageErr),
165
+ });
166
+ }
167
+ if (lineageHasRejected) {
168
+ this.emitEvent('lineage_partial', taskId, {
169
+ runId,
170
+ resolvedCount: lineageArtifactIds.length,
171
+ warning: 'Some dependency artifact queries were rejected; lineage may be incomplete',
172
+ });
277
173
  }
278
- catch { /* lineage resolution failure is non-fatal */ }
174
+ // Write PIArtifact via artifactStore (idempotent upsert)
175
+ const artifactId = `pi-art-${taskId}-${runId}`;
176
+ const now = new Date().toISOString();
279
177
  try {
280
178
  await this.artifactStore.upsertArtifact({
281
179
  artifactId,
282
180
  artifactKind: 'principle',
283
- sourceTaskId: ctx.taskId,
181
+ sourceTaskId: taskId,
284
182
  lineageArtifactIds,
285
183
  validationStatus: 'pending',
286
- contentJson: JSON.stringify(ctx.output),
184
+ contentJson: JSON.stringify(output),
287
185
  createdAt: now,
288
186
  updatedAt: now,
289
187
  });
290
188
  }
291
189
  catch (artifactErr) {
292
- this.emitArtificerEvent('artificer_artifact_write_failed', ctx.taskId, {
293
- runId: ctx.runId,
190
+ this.emitEvent('artifact_write_failed', taskId, {
191
+ runId,
294
192
  errorMessage: artifactErr instanceof Error ? artifactErr.message : String(artifactErr),
295
193
  });
296
194
  return this.retryOrFail({
297
- taskId: ctx.taskId,
298
- task: ctx.task,
195
+ taskId,
196
+ task,
299
197
  errorCategory: 'artifact_commit_failed',
300
198
  failureReason: `PIArtifact write failed: ${artifactErr instanceof Error ? artifactErr.message : String(artifactErr)}`,
301
199
  });
302
200
  }
303
- const resultRef = `artificer://${ctx.runId}`;
201
+ // Mark task succeeded
202
+ const resultRef = `${this.config.resultRefPrefix}://${runId}`;
304
203
  try {
305
- await this.stateManager.markTaskSucceeded(ctx.taskId, resultRef);
204
+ await this.stateManager.markTaskSucceeded(taskId, resultRef);
306
205
  }
307
206
  catch (stateErr) {
308
- this.emitArtificerEvent('artificer_mark_succeeded_failed', ctx.taskId, {
309
- taskId: ctx.taskId,
310
- runId: ctx.runId,
207
+ this.emitEvent('mark_succeeded_failed', taskId, {
208
+ taskId,
209
+ runId,
311
210
  errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
312
211
  });
313
212
  throw stateErr;
314
213
  }
315
- this.emitArtificerEvent('artificer_task_succeeded', ctx.taskId, {
316
- attemptCount: ctx.task.attemptCount,
214
+ this.emitEvent('task_succeeded', taskId, {
215
+ attemptCount: task.attemptCount,
317
216
  resultRef,
318
- implementationSummary: ctx.output.implementationPlan.summary,
217
+ implementationSummary: output.implementationPlan.summary,
319
218
  });
320
- this.phase = RunnerPhase.Completed;
321
219
  return {
322
220
  status: 'succeeded',
323
- taskId: ctx.taskId,
324
- runId: ctx.runId,
221
+ taskId,
222
+ runId,
325
223
  artifactId,
326
224
  resultRef,
327
- contextHash: ctx.contextHash,
328
- output: ctx.output,
329
- attemptCount: ctx.task.attemptCount,
225
+ contextHash,
226
+ output,
227
+ attemptCount: task.attemptCount,
330
228
  };
331
229
  }
332
- async handleRuntimeFailure(taskId, task, runStatus) {
333
- const errorCategory = this.mapRunStatusToErrorCategory(runStatus.status);
334
- this.emitArtificerEvent('artificer_run_failed', taskId, {
335
- runStatus: runStatus.status,
336
- errorCategory,
337
- });
338
- return this.retryOrFail({
339
- taskId,
340
- task,
341
- errorCategory,
342
- failureReason: `Runtime execution ended with status: ${runStatus.status}`,
343
- });
344
- }
345
- async handleValidationError(ctx) {
346
- const category = (ctx.errorCategory ?? 'output_invalid');
347
- this.emitArtificerEvent('artificer_output_invalid', ctx.taskId, {
348
- errorCount: ctx.errors.length,
349
- errorCategory: category,
350
- });
351
- return this.retryOrFail({
352
- taskId: ctx.taskId,
353
- task: ctx.task,
354
- errorCategory: category,
355
- failureReason: `Validation failed: ${ctx.errors.join('; ')}`,
356
- });
357
- }
358
- async handleLeaseOrPhaseError(taskId, error) {
359
- const classified = this.classifyError(error);
360
- if (classified.category === 'lease_conflict') {
361
- this.emitArtificerEvent('artificer_run_failed', taskId, {
362
- errorCategory: 'lease_conflict',
363
- errorMessage: classified.message,
364
- });
365
- return {
366
- status: 'failed',
367
- taskId,
368
- errorCategory: 'lease_conflict',
369
- failureReason: classified.message,
370
- attemptCount: 1,
371
- };
372
- }
373
- this.emitArtificerEvent('artificer_run_failed', taskId, {
374
- errorCategory: classified.category,
375
- errorMessage: classified.message,
376
- });
377
- const task = {
378
- taskId,
379
- taskKind: 'artificer',
380
- status: 'leased',
381
- createdAt: new Date().toISOString(),
382
- updatedAt: new Date().toISOString(),
383
- attemptCount: 1,
384
- maxAttempts: this.resolvedOptions.defaultMaxAttempts,
385
- };
386
- return this.retryOrFail({ taskId, task, errorCategory: classified.category, failureReason: classified.message });
387
- }
388
- async handlePostLeaseError(taskId, task, error) {
389
- const classified = this.classifyError(error);
390
- this.emitArtificerEvent('artificer_run_failed', taskId, {
391
- errorCategory: classified.category,
392
- errorMessage: classified.message,
393
- });
394
- return this.retryOrFail({ taskId, task, errorCategory: classified.category, failureReason: classified.message });
395
- }
396
- async retryOrFail(ctx) {
397
- if (this.isPermanentError(ctx.errorCategory)) {
398
- try {
399
- await this.stateManager.markTaskFailed(ctx.taskId, ctx.errorCategory);
400
- }
401
- catch (stateErr) {
402
- this.emitArtificerEvent('artificer_mark_failed_error', ctx.taskId, {
403
- errorCategory: 'storage_unavailable',
404
- attemptCount: ctx.task.attemptCount,
405
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
406
- });
407
- return {
408
- status: 'failed',
409
- taskId: ctx.taskId,
410
- errorCategory: 'storage_unavailable',
411
- failureReason: `State manager error: ${ctx.failureReason}`,
412
- attemptCount: ctx.task.attemptCount,
413
- };
414
- }
415
- this.emitArtificerEvent('artificer_task_failed', ctx.taskId, {
416
- errorCategory: ctx.errorCategory,
417
- attemptCount: ctx.task.attemptCount,
418
- failureReason: ctx.failureReason,
419
- });
420
- this.phase = RunnerPhase.Failed;
421
- return {
422
- status: 'failed',
423
- taskId: ctx.taskId,
424
- errorCategory: ctx.errorCategory,
425
- failureReason: ctx.failureReason,
426
- attemptCount: ctx.task.attemptCount,
427
- };
428
- }
429
- const shouldRetry = this.stateManager.getRetryPolicy().shouldRetry(ctx.task);
430
- if (shouldRetry) {
431
- try {
432
- await this.stateManager.markTaskRetryWait(ctx.taskId, ctx.errorCategory);
433
- }
434
- catch (stateErr) {
435
- this.emitArtificerEvent('artificer_mark_retry_error', ctx.taskId, {
436
- errorCategory: 'storage_unavailable',
437
- attemptCount: ctx.task.attemptCount,
438
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
439
- });
440
- return {
441
- status: 'failed',
442
- taskId: ctx.taskId,
443
- errorCategory: 'storage_unavailable',
444
- failureReason: `State manager error: ${ctx.failureReason}`,
445
- attemptCount: ctx.task.attemptCount,
446
- };
447
- }
448
- this.emitArtificerEvent('artificer_task_retried', ctx.taskId, {
449
- errorCategory: ctx.errorCategory,
450
- attemptCount: ctx.task.attemptCount,
451
- });
452
- this.phase = RunnerPhase.RetryWaiting;
453
- return {
454
- status: 'retried',
455
- taskId: ctx.taskId,
456
- errorCategory: ctx.errorCategory,
457
- failureReason: ctx.failureReason,
458
- attemptCount: ctx.task.attemptCount,
459
- };
460
- }
461
- try {
462
- await this.stateManager.markTaskFailed(ctx.taskId, 'max_attempts_exceeded');
463
- }
464
- catch (stateErr) {
465
- this.emitArtificerEvent('artificer_mark_failed_error', ctx.taskId, {
466
- errorCategory: 'storage_unavailable',
467
- attemptCount: ctx.task.attemptCount,
468
- errorMessage: stateErr instanceof Error ? stateErr.message : String(stateErr),
469
- });
470
- return {
471
- status: 'failed',
472
- taskId: ctx.taskId,
473
- errorCategory: 'storage_unavailable',
474
- failureReason: `State manager error: ${ctx.failureReason}`,
475
- attemptCount: ctx.task.attemptCount,
476
- };
477
- }
478
- this.emitArtificerEvent('artificer_task_failed', ctx.taskId, {
479
- errorCategory: 'max_attempts_exceeded',
480
- attemptCount: ctx.task.attemptCount,
481
- failureReason: `Max attempts exceeded: ${ctx.failureReason}`,
482
- });
483
- this.phase = RunnerPhase.Failed;
484
- return {
485
- status: 'failed',
486
- taskId: ctx.taskId,
487
- errorCategory: 'max_attempts_exceeded',
488
- failureReason: `Max attempts exceeded: ${ctx.failureReason}`,
489
- attemptCount: ctx.task.attemptCount,
490
- };
491
- }
492
- PERMANENT_ERROR_CATEGORIES = new Set(Object.freeze(['storage_unavailable', 'workspace_invalid', 'capability_missing', 'cancelled', 'input_invalid', 'output_invalid']));
493
- isPermanentError(category) {
494
- return this.PERMANENT_ERROR_CATEGORIES.has(category);
495
- }
496
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
497
- classifyError(error) {
498
- if (error instanceof PDRuntimeError) {
499
- return { category: error.category, message: error.message };
500
- }
501
- if (error instanceof Error) {
502
- return { category: 'execution_failed', message: error.message };
503
- }
504
- return { category: 'execution_failed', message: String(error) };
505
- }
230
+ // ── Optional hooks ─────────────────────────────────────────────────────────
231
+ /**
232
+ * Re-inject taskId if stripped by stripLineageFields (PRI-272 / ERR-008).
233
+ * Only fill when absent via Object.hasOwn — present-but-falsy values
234
+ * must reach validation and fail loud (Runtime Contract Rule 3).
235
+ */
506
236
  // eslint-disable-next-line @typescript-eslint/class-methods-use-this
507
- mapRunStatusToErrorCategory(status) {
508
- switch (status) {
509
- case 'failed': return 'execution_failed';
510
- case 'timed_out': return 'timeout';
511
- case 'cancelled': return 'cancelled';
512
- default: return 'execution_failed';
513
- }
514
- }
515
- // eslint-disable-next-line @typescript-eslint/class-methods-use-this
516
- sleep(ms) {
517
- return new Promise((resolve) => setTimeout(resolve, ms));
237
+ postFetchTransform(taskId, untrustedOutput) {
238
+ injectRunnerLineageIfAbsent(untrustedOutput, 'taskId', taskId);
239
+ }
240
+ emitSuccessTelemetry(taskId, output) {
241
+ this.emitEvent('implementation_plan_generated', taskId, {
242
+ implementationSummary: output.implementationPlan.summary,
243
+ targetSurface: output.implementationPlan.targetSurface,
244
+ confidence: output.implementationPlan.confidence,
245
+ });
518
246
  }
519
247
  }
520
248
  export { DEFAULT_ARTIFICER_RUNNER_OPTIONS };