@principles/core 1.293.4 → 1.294.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 (85) hide show
  1. package/dist/runtime-v2/activation/activation-types.d.ts +2 -0
  2. package/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
  3. package/dist/runtime-v2/activation/activation-types.js.map +1 -1
  4. package/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
  5. package/dist/runtime-v2/activation/sqlite-approval-store.js +64 -10
  6. package/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
  7. package/dist/runtime-v2/adapter/artificer-l2-adapter.d.ts.map +1 -1
  8. package/dist/runtime-v2/adapter/artificer-l2-adapter.js +23 -1
  9. package/dist/runtime-v2/adapter/artificer-l2-adapter.js.map +1 -1
  10. package/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +9 -0
  11. package/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -1
  12. package/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +39 -5
  13. package/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -1
  14. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts +4 -0
  15. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts.map +1 -1
  16. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js +18 -4
  17. package/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js.map +1 -1
  18. package/dist/runtime-v2/adapter/output-schema-registry.d.ts.map +1 -1
  19. package/dist/runtime-v2/adapter/output-schema-registry.js +5 -0
  20. package/dist/runtime-v2/adapter/output-schema-registry.js.map +1 -1
  21. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +26 -0
  22. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
  23. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +88 -13
  24. package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
  25. package/dist/runtime-v2/index.d.ts +3 -0
  26. package/dist/runtime-v2/index.d.ts.map +1 -1
  27. package/dist/runtime-v2/index.js +7 -0
  28. package/dist/runtime-v2/index.js.map +1 -1
  29. package/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +2 -2
  30. package/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
  31. package/dist/runtime-v2/internalization/artificer-prompt-builder.js +7 -7
  32. package/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  33. package/dist/runtime-v2/internalization/artificer-runner.js +5 -2
  34. package/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  35. package/dist/runtime-v2/internalization/evaluator-runner.d.ts +3 -0
  36. package/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  37. package/dist/runtime-v2/internalization/evaluator-runner.js +231 -37
  38. package/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  39. package/dist/runtime-v2/internalization/internalization-transition-decision.d.ts +3 -0
  40. package/dist/runtime-v2/internalization/internalization-transition-decision.d.ts.map +1 -1
  41. package/dist/runtime-v2/internalization/internalization-transition-decision.js +7 -1
  42. package/dist/runtime-v2/internalization/internalization-transition-decision.js.map +1 -1
  43. package/dist/runtime-v2/internalization/pitask-metadata.d.ts +5 -0
  44. package/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
  45. package/dist/runtime-v2/internalization/pitask-metadata.js +8 -0
  46. package/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
  47. package/dist/runtime-v2/internalization/refiner-sandbox-wrapper.d.ts.map +1 -1
  48. package/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js +11 -26
  49. package/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js.map +1 -1
  50. package/dist/runtime-v2/internalization/rule-host-input-builder.d.ts +9 -2
  51. package/dist/runtime-v2/internalization/rule-host-input-builder.d.ts.map +1 -1
  52. package/dist/runtime-v2/internalization/rule-host-input-builder.js +163 -111
  53. package/dist/runtime-v2/internalization/rule-host-input-builder.js.map +1 -1
  54. package/dist/runtime-v2/internalization/rule-reliability-validation.d.ts.map +1 -1
  55. package/dist/runtime-v2/internalization/rule-reliability-validation.js +12 -7
  56. package/dist/runtime-v2/internalization/rule-reliability-validation.js.map +1 -1
  57. package/dist/runtime-v2/internalization/scribe-output.d.ts +19 -2
  58. package/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
  59. package/dist/runtime-v2/internalization/scribe-output.js +34 -11
  60. package/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
  61. package/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts +6 -44
  62. package/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts.map +1 -1
  63. package/dist/runtime-v2/internalization/v2-adversarial-cases.js +25 -146
  64. package/dist/runtime-v2/internalization/v2-adversarial-cases.js.map +1 -1
  65. package/dist/runtime-v2/learning-lab/actor-action-output.d.ts +42 -0
  66. package/dist/runtime-v2/learning-lab/actor-action-output.d.ts.map +1 -0
  67. package/dist/runtime-v2/learning-lab/actor-action-output.js +63 -0
  68. package/dist/runtime-v2/learning-lab/actor-action-output.js.map +1 -0
  69. package/dist/runtime-v2/runtime-protocol.d.ts +17 -0
  70. package/dist/runtime-v2/runtime-protocol.d.ts.map +1 -1
  71. package/dist/runtime-v2/runtime-protocol.js +17 -0
  72. package/dist/runtime-v2/runtime-protocol.js.map +1 -1
  73. package/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
  74. package/dist/runtime-v2/store/sqlite-connection.js +4 -0
  75. package/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
  76. package/dist/runtime-v2/tools/artificer-l2-tool-contract.js +9 -9
  77. package/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -1
  78. package/dist/runtime-v2/trajectory-schema.d.ts.map +1 -1
  79. package/dist/runtime-v2/trajectory-schema.js +10 -1
  80. package/dist/runtime-v2/trajectory-schema.js.map +1 -1
  81. package/dist/telemetry-event.d.ts +2 -2
  82. package/dist/telemetry-event.d.ts.map +1 -1
  83. package/dist/telemetry-event.js +6 -0
  84. package/dist/telemetry-event.js.map +1 -1
  85. package/package.json +1 -1
@@ -31,6 +31,14 @@ function commonPrefixLength(a, b) {
31
31
  i += 1;
32
32
  return i;
33
33
  }
34
+ /** Drop any model-shaped replay claim when this run did not execute the gate. */
35
+ function withoutAdversarialResult(output) {
36
+ if (!isEvaluatorOutputV2(output))
37
+ return output;
38
+ const { adversarialResult, ...sanitized } = output;
39
+ void adversarialResult;
40
+ return sanitized;
41
+ }
34
42
  function isRecordValue(value) {
35
43
  return value !== null && typeof value === 'object' && !Array.isArray(value);
36
44
  }
@@ -704,6 +712,7 @@ export class EvaluatorRunner extends BasePeerRunner {
704
712
  // explicitly through applyEvaluatorDecisionEffects → maybeSeedArtificerRepair
705
713
  // keeps provenance structural rather than inferred.
706
714
  let diagnosticReplayEvidence;
715
+ let ownerStampRecoveryRequired = false;
707
716
  const gateAssessment = assessArtificerCodeBearing(context.artificerArtifact);
708
717
  const outputWantsGate = isEvaluatorOutputV2(output);
709
718
  const evaluatorDecision = output.evaluation.decision;
@@ -803,12 +812,50 @@ export class EvaluatorRunner extends BasePeerRunner {
803
812
  }
804
813
  }
805
814
  else if (!this.gateDeps) {
815
+ const taskChannel = hydratePITaskRecord(task)?.channel;
816
+ const sourceArtificer = context.artificerArtifact
817
+ ? this.parseArtificerArtifact(context.artificerArtifact)
818
+ : null;
819
+ const promptHasUnstampedV2Code = taskChannel === 'prompt'
820
+ && sourceArtificer?.requiresContextVersion === 2
821
+ && !Array.isArray(sourceArtificer.ownerGoldenTraceCases);
806
822
  this.emitEvent('adversarial_replay_skipped', taskId, {
807
823
  runId,
808
824
  reason: 'gate_deps_not_injected',
809
825
  nextAction: 'wire_gateDeps_createProductionGateDeps_into_evaluator_runner_assembly',
810
826
  });
811
- if (gateAssessment.codeBearing) {
827
+ if (promptHasUnstampedV2Code) {
828
+ // An accidental prompt-channel V2 artifact is not a RuleCode request.
829
+ // Keep the ordinary prompt verdict, but drop any model-shaped replay
830
+ // claim so it cannot be mistaken for executed gate evidence.
831
+ finalOutput = withoutAdversarialResult(finalOutput);
832
+ await this.stateManager.updateRunOutput(runId, JSON.stringify(finalOutput));
833
+ try {
834
+ await this.artifactStore.upsertArtifact({
835
+ artifactId,
836
+ artifactKind: 'principle',
837
+ sourceTaskId: taskId,
838
+ lineageArtifactIds,
839
+ validationStatus: 'pending',
840
+ contentJson: JSON.stringify(finalOutput),
841
+ createdAt: now,
842
+ updatedAt: new Date().toISOString(),
843
+ });
844
+ }
845
+ catch (persistErr) {
846
+ this.emitEvent('adversarial_result_persist_failed', taskId, {
847
+ runId,
848
+ errorMessage: persistErr instanceof Error ? persistErr.message : String(persistErr),
849
+ });
850
+ }
851
+ this.emitEvent('prompt_code_artifact_ignored', taskId, {
852
+ runId,
853
+ sourceArtificerArtifactId: context.sourceArtificerArtifactId,
854
+ reason: 'owner_golden_trace_stamp_missing',
855
+ nextAction: 'prompt_channel_does_not_create_rulecode_without_an_explicit_code_tool_hook_request',
856
+ });
857
+ }
858
+ else if (gateAssessment.codeBearing) {
812
859
  // PRI-634 R2 (wiring regression guard): a code-bearing Artificer
813
860
  // artifact REQUIRES the deterministic gate. Proceeding would yield
814
861
  // succeeded + adversarialResult=null — the exact state that broke
@@ -864,31 +911,96 @@ export class EvaluatorRunner extends BasePeerRunner {
864
911
  }
865
912
  }
866
913
  else if (gateAssessment.codeBearing) {
867
- // ── PRI-634 R3 (terminal-state invariant) ──
868
- // A code-bearing Artificer artifact that reached `approved` MUST leave
869
- // this block carrying an adversarialResult. Anything else reproduces
870
- // the chain-48371236 terminal state — approved with the deterministic
871
- // gate never executed, adversarialResult=null, and therefore no
872
- // pi-rule-* downstream — regardless of WHICH cause prevented the
873
- // replay (zero adversarial cases, no positive case, unparseable
874
- // artifact, conversion drift…). Telemetry is not recovery: a task that
875
- // ends `succeeded` here is indistinguishable from the original defect.
876
- //
877
- // errorCategory is `input_invalid` (already listed in
878
- // permanentErrorCategories) rather than `capability_missing`: the gate
879
- // IS wired correctly (R2 owns the wiring case) — the upstream
880
- // Artificer content simply cannot be turned into gate input. Permanent
881
- // because retrying the LLM cannot make the Artificer emit the missing
882
- // affectedTools / positive-case path.
883
- const recoveryAction = replayOutcome.skipReason?.startsWith('template_derivation_failed:')
884
- ? 'have the Artificer emit a complete positive write-kind golden-trace case with a string path or file_path; required templates cannot be replaced by LLM adversarialCases.'
885
- : 'have the Artificer emit affectedTools plus at least one positive golden-trace case carrying a path, or supply LLM adversarialCases.';
886
- return this.retryOrFail({
887
- taskId,
888
- task,
889
- errorCategory: 'input_invalid',
890
- failureReason: `PRI-634 R3: Artificer artifact ${context.sourceArtificerArtifactId ?? '(unknown)'} is code-bearing and the evaluator approved it, but the deterministic adversarial replay did not run (reason: ${replayOutcome.skipReason ?? 'unknown'}). Refusing to report succeeded with adversarialResult=null — that is the chain-48371236 terminal state. Fix: ${recoveryAction}`,
891
- });
914
+ const missingOwnerStamp = replayOutcome.skipReason === 'owner_golden_trace_stamp_missing_or_invalid';
915
+ const taskChannel = hydratePITaskRecord(task)?.channel;
916
+ if (missingOwnerStamp && taskChannel === 'prompt') {
917
+ // Prompt-channel artifacts are not eligible to create RuleCode.
918
+ // Preserve the ordinary prompt result, but discard any model-shaped
919
+ // replay claim so it cannot masquerade as executed gate evidence.
920
+ finalOutput = withoutAdversarialResult(finalOutput);
921
+ await this.stateManager.updateRunOutput(runId, JSON.stringify(finalOutput));
922
+ try {
923
+ await this.artifactStore.upsertArtifact({
924
+ artifactId,
925
+ artifactKind: 'principle',
926
+ sourceTaskId: taskId,
927
+ lineageArtifactIds,
928
+ validationStatus: 'pending',
929
+ contentJson: JSON.stringify(finalOutput),
930
+ createdAt: now,
931
+ updatedAt: new Date().toISOString(),
932
+ });
933
+ }
934
+ catch (persistErr) {
935
+ this.emitEvent('adversarial_result_persist_failed', taskId, {
936
+ runId,
937
+ errorMessage: persistErr instanceof Error ? persistErr.message : String(persistErr),
938
+ });
939
+ }
940
+ this.emitEvent('adversarial_replay_skipped', taskId, {
941
+ runId,
942
+ reason: replayOutcome.skipReason,
943
+ channel: 'prompt',
944
+ nextAction: 'prompt_channel_result_kept_without_rulecode_eligibility',
945
+ });
946
+ }
947
+ else if (missingOwnerStamp && this.isRepairLoopEnabled()) {
948
+ // Missing system-owned provenance is recoverable through the existing
949
+ // bounded Artificer repair loop. Do not fabricate a gate result.
950
+ ownerStampRecoveryRequired = true;
951
+ finalOutput = withoutAdversarialResult(finalOutput);
952
+ await this.stateManager.updateRunOutput(runId, JSON.stringify(finalOutput));
953
+ try {
954
+ await this.artifactStore.upsertArtifact({
955
+ artifactId,
956
+ artifactKind: 'principle',
957
+ sourceTaskId: taskId,
958
+ lineageArtifactIds,
959
+ validationStatus: 'pending',
960
+ contentJson: JSON.stringify(finalOutput),
961
+ createdAt: now,
962
+ updatedAt: new Date().toISOString(),
963
+ });
964
+ }
965
+ catch (persistErr) {
966
+ this.emitEvent('adversarial_result_persist_failed', taskId, {
967
+ runId,
968
+ errorMessage: persistErr instanceof Error ? persistErr.message : String(persistErr),
969
+ });
970
+ }
971
+ this.emitEvent('artificer_owner_stamp_repair_required', taskId, {
972
+ runId,
973
+ sourceArtificerArtifactId: context.sourceArtificerArtifactId,
974
+ nextAction: 'regenerate_artificer_from_current_validated_owner_behavior_example_pack',
975
+ });
976
+ }
977
+ else {
978
+ // ── PRI-634 R3 (terminal-state invariant) ──
979
+ // A code-bearing Artificer artifact that reached `approved` MUST leave
980
+ // this block carrying an adversarialResult. Anything else reproduces
981
+ // the chain-48371236 terminal state — approved with the deterministic
982
+ // gate never executed, adversarialResult=null, and therefore no
983
+ // pi-rule-* downstream — regardless of WHICH cause prevented the
984
+ // replay (zero adversarial cases, no positive case, unparseable
985
+ // artifact, conversion drift…). Telemetry is not recovery: a task that
986
+ // ends `succeeded` here is indistinguishable from the original defect.
987
+ //
988
+ // errorCategory is `input_invalid` (already listed in
989
+ // permanentErrorCategories) rather than `capability_missing`: the gate
990
+ // IS wired correctly (R2 owns the wiring case) — the upstream
991
+ // Artificer content simply cannot be turned into gate input. Permanent
992
+ // because retrying the LLM cannot make the Artificer emit the missing
993
+ // affectedTools / positive-case path.
994
+ const recoveryAction = replayOutcome.skipReason?.startsWith('template_derivation_failed:')
995
+ ? 'have the Artificer emit a complete positive write-kind golden-trace case with a string path or file_path; required templates cannot be replaced by LLM adversarialCases.'
996
+ : 'have the Artificer emit affectedTools plus at least one positive golden-trace case carrying a path, or supply LLM adversarialCases.';
997
+ return this.retryOrFail({
998
+ taskId,
999
+ task,
1000
+ errorCategory: 'input_invalid',
1001
+ failureReason: `PRI-634 R3: Artificer artifact ${context.sourceArtificerArtifactId ?? '(unknown)'} is code-bearing and the evaluator approved it, but the deterministic adversarial replay did not run (reason: ${replayOutcome.skipReason ?? 'unknown'}). Refusing to report succeeded with adversarialResult=null — that is the chain-48371236 terminal state. Fix: ${recoveryAction}`,
1002
+ });
1003
+ }
892
1004
  }
893
1005
  }
894
1006
  // ── Round-2 R2 (Owner 指令 2026-09-08): 出界处置先于 intent 落库派生 ──
@@ -926,9 +1038,14 @@ export class EvaluatorRunner extends BasePeerRunner {
926
1038
  && finalOutput.evaluation.decision === 'approved'
927
1039
  && finalOutput.adversarialResult?.passed === false
928
1040
  && this.isRepairLoopEnabled();
1041
+ const approvedOwnerStampRecovery = ownerStampRecoveryRequired
1042
+ && finalOutput.evaluation.decision === 'approved';
929
1043
  await this.recordCompletionOrThrow(taskId, runId, {
930
1044
  decision: finalOutput.evaluation.decision,
931
1045
  governanceEffect,
1046
+ ...(approvedOwnerStampRecovery
1047
+ ? { transitionOverrideReason: 'owner_golden_trace_provenance_missing' }
1048
+ : {}),
932
1049
  });
933
1050
  const ruleAssemblyInput = {
934
1051
  artificerArtifact: context.artificerArtifact ?? null,
@@ -943,7 +1060,9 @@ export class EvaluatorRunner extends BasePeerRunner {
943
1060
  diagnosticReplayEvidence,
944
1061
  // PRI-843: mismatch 处置在效果层先于一切 decision 分支执行
945
1062
  ...(governanceEffect !== undefined ? { governanceEffect } : {}),
946
- ...(approvedReplayFailed ? { transitionDecisionOverride: 'needs_revision' } : {}),
1063
+ ...(approvedReplayFailed || approvedOwnerStampRecovery
1064
+ ? { transitionDecisionOverride: 'needs_revision' }
1065
+ : {}),
947
1066
  });
948
1067
  if (effectResult.kind === 'human_review') {
949
1068
  return effectResult.result;
@@ -1324,7 +1443,7 @@ export class EvaluatorRunner extends BasePeerRunner {
1324
1443
  * 同 epoch crash/retry 重跑经 maybeResumePendingIntent resume,不重问 LLM。
1325
1444
  */
1326
1445
  async recordCompletionOrThrow(taskId, runId, decisionAndEffect) {
1327
- const { decision, governanceEffect } = decisionAndEffect;
1446
+ const { decision, governanceEffect, transitionOverrideReason } = decisionAndEffect;
1328
1447
  try {
1329
1448
  const raw = await this.stateManager.getTask(taskId);
1330
1449
  if (!raw)
@@ -1347,6 +1466,7 @@ export class EvaluatorRunner extends BasePeerRunner {
1347
1466
  ...(governanceEffect?.effectReasonCode !== undefined
1348
1467
  ? { effectReasonCode: governanceEffect.effectReasonCode }
1349
1468
  : {}),
1469
+ ...(transitionOverrideReason !== undefined ? { transitionOverrideReason } : {}),
1350
1470
  },
1351
1471
  });
1352
1472
  await this.stateManager.updateTaskDiagnosticJson(taskId, createPITaskDiagnosticJson(merged));
@@ -1493,6 +1613,9 @@ export class EvaluatorRunner extends BasePeerRunner {
1493
1613
  contextHash,
1494
1614
  sourceArtificerArtifactId: assemblySourceId,
1495
1615
  ruleAssemblyInput: { artificerArtifact: artificerContent, sourceArtificerArtifactId: assemblySourceId },
1616
+ ...(intent.transitionOverrideReason === 'owner_golden_trace_provenance_missing'
1617
+ ? { transitionDecisionOverride: 'needs_revision' }
1618
+ : {}),
1496
1619
  });
1497
1620
  if (effectResult.kind === 'human_review') {
1498
1621
  return effectResult.result;
@@ -1857,8 +1980,9 @@ export class EvaluatorRunner extends BasePeerRunner {
1857
1980
  // 的 partition) 派生; resume 路径经 recoverIntentOutput 后重读本 intent,
1858
1981
  // 无需重算也无需任何瞬时变量。瞬时 evidence 门只作 fresh 快路径与
1859
1982
  // 派生时的 provenance 校验, 不再是出界判定的唯一载体 (R2 漂移断点)。
1983
+ const completionIntent = await this.readPendingOrAppliedCompletionIntent(evaluatorTaskId);
1860
1984
  {
1861
- const intent = await this.readPendingOrAppliedCompletionIntent(evaluatorTaskId);
1985
+ const intent = completionIntent;
1862
1986
  // Round-3: hydrate 将 selectedEffect 归一化为 effect —— 读侧必须两键
1863
1987
  // 同读,否则 fresh 分支永不命中、静默回退瞬时 evidence (ERR-024 键不对称)。
1864
1988
  if ((intent?.selectedEffect ?? intent?.effect) === 'needs_human_review'
@@ -1963,7 +2087,12 @@ export class EvaluatorRunner extends BasePeerRunner {
1963
2087
  // out-of-scope case 清单随载荷流动 — 修复 LLM 明确知道哪些失败属于
1964
2088
  // 通道设计限制(不得尝试满足),哪些是真实 Rule 缺陷(必须修复)。
1965
2089
  const repairPayload = {
1966
- requiredChanges: [...output.evaluation.requiredChanges],
2090
+ requiredChanges: completionIntent?.transitionOverrideReason === 'owner_golden_trace_provenance_missing'
2091
+ ? [
2092
+ ...output.evaluation.requiredChanges,
2093
+ 'Regenerate this RuleCode from the current validated Owner BehaviorExamplePack so the persisted artifact carries the system-owned ownerGoldenTraceCases; preserve the approved principle semantics.',
2094
+ ]
2095
+ : [...output.evaluation.requiredChanges],
1967
2096
  concerns: [...output.evaluation.concerns],
1968
2097
  previousScore: output.evaluation.score,
1969
2098
  repairIteration: priorRepairIteration + 1,
@@ -1986,6 +2115,7 @@ export class EvaluatorRunner extends BasePeerRunner {
1986
2115
  let inheritedPipelineMode;
1987
2116
  let inheritedTimeoutMs = 300_000;
1988
2117
  let inheritedInputArtifactRefs = [];
2118
+ let ownerEvidenceSelection;
1989
2119
  for (const depId of evaluatorDeps) {
1990
2120
  const depTask = await this.stateManager.getTask(depId);
1991
2121
  if (!depTask)
@@ -2000,6 +2130,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2000
2130
  inheritedPipelineMode = piArtificer.pipelineMode;
2001
2131
  inheritedTimeoutMs = piArtificer.timeoutMs;
2002
2132
  inheritedInputArtifactRefs = piArtificer.inputArtifactRefs;
2133
+ ({ ownerEvidenceSelection } = piArtificer);
2003
2134
  break;
2004
2135
  }
2005
2136
  // Delegate to the injected seeder — core peer runners do NOT call
@@ -2023,6 +2154,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2023
2154
  inheritedPipelineMode,
2024
2155
  inheritedTimeoutMs,
2025
2156
  inheritedInputArtifactRefs,
2157
+ ownerEvidenceSelection,
2026
2158
  });
2027
2159
  this.emitEvent('repair_task_seeded', evaluatorTaskId, {
2028
2160
  repairTaskId,
@@ -2175,7 +2307,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2175
2307
  });
2176
2308
  return { updatedOutput: null, skipReason: 'artificer_artifact_unparseable' };
2177
2309
  }
2178
- const { implementationCode, goldenTraceCases, affectedTools } = artificerParsed;
2310
+ const { implementationCode, goldenTraceCases, ownerGoldenTraceCases, affectedTools, requiresContextVersion } = artificerParsed;
2179
2311
  if (typeof implementationCode !== 'string' || implementationCode.trim() === '') {
2180
2312
  // Artificer output is V1 (no code) but the evaluator emitted V2. This is
2181
2313
  // a mismatch — degrade rather than replay against missing code.
@@ -2189,7 +2321,38 @@ export class EvaluatorRunner extends BasePeerRunner {
2189
2321
  // Merge positive cases from the Artificer golden trace into the adversarial
2190
2322
  // trace. buildGoldenTraceFromArtificer validates each case structurally
2191
2323
  // (Runtime Contract Rule 4) and returns ok=false on any malformed entry.
2192
- const positiveCases = this.extractPositiveCases(goldenTraceCases);
2324
+ let positiveCases;
2325
+ let ownerNegativeCases = [];
2326
+ if (requiresContextVersion === 2) {
2327
+ if (!Array.isArray(ownerGoldenTraceCases)) {
2328
+ this.emitEvent('adversarial_replay_skipped', taskId, {
2329
+ runId,
2330
+ reason: 'owner_golden_trace_stamp_missing_or_invalid',
2331
+ nextAction: 'regenerate_artificer_artifact_from_the_current_validated_owner_behavior_example_pack',
2332
+ });
2333
+ return { updatedOutput: null, skipReason: 'owner_golden_trace_stamp_missing_or_invalid' };
2334
+ }
2335
+ const ownerBuild = buildGoldenTraceFromArtificer({ cases: ownerGoldenTraceCases });
2336
+ const ownerPositives = ownerBuild.ok ? ownerBuild.trace.cases.filter((c) => c.kind === 'positive') : [];
2337
+ ownerNegativeCases = ownerBuild.ok ? ownerBuild.trace.cases.filter((c) => c.kind === 'negative') : [];
2338
+ if (!ownerBuild.ok || ownerPositives.length === 0 || ownerNegativeCases.length === 0
2339
+ || ownerBuild.trace.cases.some((c) => c.expectedDecision === 'propose_correction')
2340
+ || ownerNegativeCases.some((c) => c.expectedDecision !== 'block')) {
2341
+ this.emitEvent('adversarial_replay_skipped', taskId, {
2342
+ runId,
2343
+ reason: 'owner_golden_trace_stamp_invalid_or_missing_positive_negative_pair',
2344
+ nextAction: 'restore_a_validated_owner_pack_with_at_least_one_allow_positive_and_one_block_negative_case',
2345
+ });
2346
+ return { updatedOutput: null, skipReason: 'owner_golden_trace_stamp_invalid_or_missing_positive_negative_pair' };
2347
+ }
2348
+ positiveCases = ownerPositives;
2349
+ }
2350
+ else {
2351
+ // Legacy v1 artifacts predate the system-owned pack stamp and remain
2352
+ // readable. New context-v2 RuleCode never falls back to model-authored
2353
+ // examples as its independent Owner acceptance baseline.
2354
+ positiveCases = this.extractPositiveCases(goldenTraceCases);
2355
+ }
2193
2356
  if (positiveCases.length === 0) {
2194
2357
  this.emitEvent('adversarial_replay_skipped', taskId, {
2195
2358
  runId,
@@ -2198,10 +2361,9 @@ export class EvaluatorRunner extends BasePeerRunner {
2198
2361
  });
2199
2362
  return { updatedOutput: null, skipReason: 'no_positive_case_in_artificer_golden_trace' };
2200
2363
  }
2201
- // (3) PRI-485 Phase 6: auto-generate 5 v2 adversarial cases from the
2202
- // Artificer's target kind and one complete positive write case. These defend
2203
- // against the most common false-positive patterns (unavailable/truncation/
2204
- // alias/path/combination). Degrade with telemetry (rc-9) if the spec
2364
+ // Derive context availability cases from one complete positive write case.
2365
+ // Business decisions come from the Owner pack, not generic path policies.
2366
+ // Degrade with telemetry (rc-9) if the spec
2205
2367
  // cannot be derived for a write target — auxiliary cases cannot replace them.
2206
2368
  // PRI-634 R1: V1-shaped outputs carry no adversarialCases — the merged
2207
2369
  // set below then relies entirely on the auto-generated v2 cases.
@@ -2214,8 +2376,18 @@ export class EvaluatorRunner extends BasePeerRunner {
2214
2376
  }
2215
2377
  // PRI-741: host-name parity case — the rule must reach the same decision
2216
2378
  // under the REAL host tool name as under the author's vocabulary.
2217
- const hostAliasCase = this.generateHostAliasCase(goldenTraceCases, taskId, runId);
2379
+ const hostAliasCase = this.generateHostAliasCase(requiresContextVersion === 2 ? ownerGoldenTraceCases : goldenTraceCases, taskId, runId);
2380
+ const ownerNegativeAdversarial = ownerNegativeCases.map((ownerCase) => ({
2381
+ caseId: `owner:${ownerCase.caseId}`,
2382
+ attackType: 'boundary',
2383
+ toolName: ownerCase.toolName,
2384
+ params: ownerCase.params,
2385
+ expectedDecision: 'block',
2386
+ rationale: 'System-restored Owner-labelled negative behavior example; expected decision comes from the validated BehaviorExamplePack.',
2387
+ ...(ownerCase.ruleContext !== undefined ? { ruleContext: ownerCase.ruleContext } : {}),
2388
+ }));
2218
2389
  const mergedAdversarialCases = [
2390
+ ...ownerNegativeAdversarial,
2219
2391
  ...v2Cases,
2220
2392
  ...(hostAliasCase !== null ? [hostAliasCase] : []),
2221
2393
  ...llmCases,
@@ -2381,6 +2553,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2381
2553
  return {
2382
2554
  implementationCode: parsed.implementationCode,
2383
2555
  goldenTraceCases: parsed.goldenTraceCases,
2556
+ ownerGoldenTraceCases: parsed.ownerGoldenTraceCases,
2384
2557
  affectedTools: parsed.affectedTools,
2385
2558
  requiresContextVersion: parsed.requiresContextVersion,
2386
2559
  evidenceRefs: parsed.evidenceRefs,
@@ -2965,6 +3138,24 @@ export class EvaluatorRunner extends BasePeerRunner {
2965
3138
  nextAction: 'approval_card_keeps_generic_trigger_reason',
2966
3139
  });
2967
3140
  }
3141
+ const hostContext = this.hostSemanticContext;
3142
+ const hostKinds = hostContext?.hostKinds;
3143
+ const hasHostInputContract = requiresContextVersion === 2
3144
+ && hostContext !== null
3145
+ && Array.isArray(hostKinds)
3146
+ && hostKinds.length > 0
3147
+ && hostKinds.every((kind) => typeof kind === 'string' && kind.trim() !== '')
3148
+ && Array.isArray(hostContext.tools)
3149
+ && hostContext.tools.length > 0
3150
+ && hostContext.tools.every((tool) => typeof tool.rawToolName === 'string' && tool.rawToolName.trim() !== ''
3151
+ && typeof tool.canonicalKind === 'string' && tool.canonicalKind.trim() !== '');
3152
+ if (requiresContextVersion === 2 && !hasHostInputContract) {
3153
+ this.emitEvent('rule_host_input_contract_skipped', taskId, {
3154
+ runId,
3155
+ reason: hostContext === null ? 'host_semantic_context_missing' : 'host_semantic_context_invalid_or_empty',
3156
+ nextAction: 'provide_the_nonempty_host_semantic_projection_used_by_the_deterministic_gate',
3157
+ });
3158
+ }
2968
3159
  const ruleContent = {
2969
3160
  implementationCode,
2970
3161
  goldenTrace: traceBuild.trace,
@@ -2976,6 +3167,9 @@ export class EvaluatorRunner extends BasePeerRunner {
2976
3167
  sourceArtificerArtifactId: assemblyInput.sourceArtificerArtifactId ?? output.sourceArtificerArtifactId,
2977
3168
  adversarialResult: output.adversarialResult,
2978
3169
  ...(requiresContextVersion === 2 ? { requiresContextVersion } : {}),
3170
+ ...(hasHostInputContract ? {
3171
+ ruleHostInputContract: { version: 1, contextVersion: 2, hostKinds: [...hostKinds] },
3172
+ } : {}),
2979
3173
  // PRI-490: preserve evidenceRefs from Artificer artifact into rule artifact.
2980
3174
  // Only include when the array is valid (non-empty strings) — v1 rules may omit.
2981
3175
  ...(requiresContextVersion === 2 && Array.isArray(evidenceRefs) && evidenceRefs.every((e) => typeof e === 'string' && e.trim() !== '')