@principles/core 1.296.0 → 1.296.1

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 (32) hide show
  1. package/dist/runtime-v2/adapter/artificer-l2-adapter.d.ts.map +1 -1
  2. package/dist/runtime-v2/adapter/artificer-l2-adapter.js +18 -0
  3. package/dist/runtime-v2/adapter/artificer-l2-adapter.js.map +1 -1
  4. package/dist/runtime-v2/internalization/artificer-intent-preflight.d.ts.map +1 -1
  5. package/dist/runtime-v2/internalization/artificer-intent-preflight.js +10 -0
  6. package/dist/runtime-v2/internalization/artificer-intent-preflight.js.map +1 -1
  7. package/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
  8. package/dist/runtime-v2/internalization/artificer-prompt-builder.js +3 -1
  9. package/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
  10. package/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
  11. package/dist/runtime-v2/internalization/artificer-runner.js +8 -1
  12. package/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
  13. package/dist/runtime-v2/internalization/evaluator-output.d.ts +2 -0
  14. package/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
  15. package/dist/runtime-v2/internalization/evaluator-output.js +3 -0
  16. package/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
  17. package/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +2 -2
  18. package/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts.map +1 -1
  19. package/dist/runtime-v2/internalization/evaluator-prompt-builder.js +90 -38
  20. package/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
  21. package/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
  22. package/dist/runtime-v2/internalization/evaluator-runner.js +115 -39
  23. package/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
  24. package/dist/runtime-v2/internalization/rulecode-verification-obligations.d.ts +66 -0
  25. package/dist/runtime-v2/internalization/rulecode-verification-obligations.d.ts.map +1 -0
  26. package/dist/runtime-v2/internalization/rulecode-verification-obligations.js +150 -0
  27. package/dist/runtime-v2/internalization/rulecode-verification-obligations.js.map +1 -0
  28. package/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts +10 -0
  29. package/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts.map +1 -1
  30. package/dist/runtime-v2/tools/artificer-l2-tool-contract.js +55 -5
  31. package/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -1
  32. package/package.json +1 -1
@@ -21,6 +21,7 @@ import { buildGoldenTraceFromArtificer } from '../golden-trace.js';
21
21
  // PRI-485 Phase 6: auto-generate 5 v2 adversarial cases (unavailable/truncation/
22
22
  // alias/path/combination) to defend against false-positive blocks.
23
23
  import { generateV2ContextAdversarialCases } from './v2-adversarial-cases.js';
24
+ import { deriveRuleCodeVerification } from './rulecode-verification-obligations.js';
24
25
  import { canonicalizeToolKind } from './rule-context-v2.js';
25
26
  /** PRI-741: length of the shared case-insensitive prefix of two tool names. */
26
27
  function commonPrefixLength(a, b) {
@@ -381,6 +382,21 @@ export class EvaluatorRunner extends BasePeerRunner {
381
382
  throw new PDRuntimeError('input_invalid', 'Artificer dependency artifact not found');
382
383
  }
383
384
  async invokeRuntime(taskId, context) {
385
+ if (context.scribeArtifact !== null) {
386
+ let scribe;
387
+ try {
388
+ scribe = JSON.parse(context.scribeArtifact);
389
+ }
390
+ catch {
391
+ throw new PDRuntimeError('input_invalid', 'scribe_artifact_unparseable');
392
+ }
393
+ const material = deriveRuleCodeVerification(scribe, [], this.hostSemanticContext?.tools ?? []);
394
+ if (material.unavailable.length > 0) {
395
+ this.emitEvent('adversarial_replay_skipped', taskId, { reason: 'required_fact_verification_unavailable', required: material.required,
396
+ executed: 0, passed: 0, failed: 0, unavailable: material.unavailable, nextAction: 'restore_supported_valid_fact_contract_before_model_request' });
397
+ throw new PDRuntimeError('input_invalid', `required_fact_verification_unavailable:${material.unavailable.join(',')}`);
398
+ }
399
+ }
384
400
  // Single-stage evaluation is the only path — the two-stage
385
401
  // progressive_evaluator branch was retired with PRI-819 R-06.
386
402
  const { message, systemPrompt } = await this.buildEvaluatorPrompt(taskId, context);
@@ -2086,13 +2102,17 @@ export class EvaluatorRunner extends BasePeerRunner {
2086
2102
  // PRI-705 / PRI-703 Phase 2: 混合场景 (非纯 out-of-scope) 下,归因与
2087
2103
  // out-of-scope case 清单随载荷流动 — 修复 LLM 明确知道哪些失败属于
2088
2104
  // 通道设计限制(不得尝试满足),哪些是真实 Rule 缺陷(必须修复)。
2105
+ const systemReplayChanges = ctx.diagnosticReplayEvidence?.passed === false
2106
+ && output.evaluation.requiredChanges.length === 0 && isEvaluatorOutputV2(output)
2107
+ ? [`[system deterministic replay] Repair the RuleCode against the executed failure evidence without inventing Owner facts: ${(output.adversarialResult?.failedCases ?? []).slice(0, 8).map((failure) => `${failure.caseId}: expected=${failure.expectedDecision}, actual=${failure.actualDecision ?? 'no decision'}, error=${failure.errorType ?? 'unknown'}; ${(failure.message ?? failure.rationale).slice(0, 160)}`).join(' | ') || 'deterministic replay failed; inspect the referenced evaluator artifact for the execution failure and restore the supported contract.'}`]
2108
+ : [];
2089
2109
  const repairPayload = {
2090
2110
  requiredChanges: completionIntent?.transitionOverrideReason === 'owner_golden_trace_provenance_missing'
2091
2111
  ? [
2092
2112
  ...output.evaluation.requiredChanges,
2093
2113
  'Regenerate this RuleCode from the current validated Owner BehaviorExamplePack so the persisted artifact carries the system-owned ownerGoldenTraceCases; preserve the approved principle semantics.',
2094
2114
  ]
2095
- : [...output.evaluation.requiredChanges],
2115
+ : [...output.evaluation.requiredChanges, ...systemReplayChanges],
2096
2116
  concerns: [...output.evaluation.concerns],
2097
2117
  previousScore: output.evaluation.score,
2098
2118
  repairIteration: priorRepairIteration + 1,
@@ -2353,6 +2373,30 @@ export class EvaluatorRunner extends BasePeerRunner {
2353
2373
  // examples as its independent Owner acceptance baseline.
2354
2374
  positiveCases = this.extractPositiveCases(goldenTraceCases);
2355
2375
  }
2376
+ let scribe = null;
2377
+ try {
2378
+ scribe = context.scribeArtifact === null ? null : JSON.parse(context.scribeArtifact);
2379
+ }
2380
+ catch { /* the declaration extraction below fails closed on malformed content */ }
2381
+ const verification = deriveRuleCodeVerification(scribe, [...positiveCases, ...ownerNegativeCases], this.hostSemanticContext?.tools ?? []);
2382
+ if (context.scribeArtifact !== null && scribe === null)
2383
+ verification.unavailable.push('scribe_artifact_unparseable');
2384
+ if (verification.unavailable.length > 0) {
2385
+ this.emitEvent('adversarial_replay_skipped', taskId, { runId, reason: 'required_fact_verification_unavailable',
2386
+ required: verification.required, unavailable: verification.unavailable, historical: verification.historical,
2387
+ nextAction: 'restore_valid_declared_fact_contract_and_supported_host_projection_before_replay' });
2388
+ return { updatedOutput: null, skipReason: `required_fact_verification_unavailable:${verification.unavailable.join(',')}` };
2389
+ }
2390
+ positiveCases = verification.replayCases.filter((entry) => entry.kind === 'positive');
2391
+ ownerNegativeCases = verification.replayCases.filter((entry) => entry.kind === 'negative');
2392
+ // Explicit system contract positives can establish replay eligibility;
2393
+ // historical evidence-only labels are preserved but never counted as pass.
2394
+ if (positiveCases.length === 0 && verification.counterfactuals.length > 0) {
2395
+ positiveCases = verification.counterfactuals.filter((entry) => entry.expectedDecision === 'allow').map((entry) => ({
2396
+ caseId: entry.caseId, kind: 'positive', toolName: entry.toolName, params: entry.params,
2397
+ expectedDecision: 'allow', ruleContext: entry.ruleContext,
2398
+ }));
2399
+ }
2356
2400
  if (positiveCases.length === 0) {
2357
2401
  this.emitEvent('adversarial_replay_skipped', taskId, {
2358
2402
  runId,
@@ -2368,7 +2412,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2368
2412
  // PRI-634 R1: V1-shaped outputs carry no adversarialCases — the merged
2369
2413
  // set below then relies entirely on the auto-generated v2 cases.
2370
2414
  const llmCases = isEvaluatorOutputV2(output) ? (output.adversarialCases ?? []) : [];
2371
- const v2Cases = this.generateV2CasesFromArtificer(affectedTools, positiveCases, taskId, runId);
2415
+ const v2Cases = verification.required.length > 0 ? [] : this.generateV2CasesFromArtificer(affectedTools, positiveCases, taskId, runId);
2372
2416
  if (!Array.isArray(v2Cases)) {
2373
2417
  this.emitEvent('v2_adversarial_cases_skipped', taskId, { runId, ...v2Cases });
2374
2418
  this.emitEvent('adversarial_replay_skipped', taskId, { runId, ...v2Cases });
@@ -2376,7 +2420,7 @@ export class EvaluatorRunner extends BasePeerRunner {
2376
2420
  }
2377
2421
  // PRI-741: host-name parity case — the rule must reach the same decision
2378
2422
  // under the REAL host tool name as under the author's vocabulary.
2379
- const hostAliasCase = this.generateHostAliasCase(requiresContextVersion === 2 ? ownerGoldenTraceCases : goldenTraceCases, taskId, runId);
2423
+ const hostAliasCase = this.generateHostAliasCase(verification.required.length > 0 ? verification.replayCases : requiresContextVersion === 2 ? ownerGoldenTraceCases : goldenTraceCases, taskId, runId);
2380
2424
  const ownerNegativeAdversarial = ownerNegativeCases.map((ownerCase) => ({
2381
2425
  caseId: `owner:${ownerCase.caseId}`,
2382
2426
  attackType: 'boundary',
@@ -2386,39 +2430,12 @@ export class EvaluatorRunner extends BasePeerRunner {
2386
2430
  rationale: 'System-restored Owner-labelled negative behavior example; expected decision comes from the validated BehaviorExamplePack.',
2387
2431
  ...(ownerCase.ruleContext !== undefined ? { ruleContext: ownerCase.ruleContext } : {}),
2388
2432
  }));
2389
- // A trusted design fact scopes the invocation already. Changing its command
2390
- // spelling must not bypass the same denied scope (counterfactual, not history).
2391
- const designScopeCases = [];
2392
- if (context.scribeArtifact !== null) {
2393
- let scribe;
2394
- try {
2395
- scribe = JSON.parse(context.scribeArtifact);
2396
- }
2397
- catch {
2398
- scribe = null;
2399
- }
2400
- const conditions = extractExecutionConditions(scribe);
2401
- if (!conditions.corrupted && conditions.conditions?.requiredFacts.some((fact) => fact.required && fact.factKind === 'design_approval')) {
2402
- for (const ownerCase of ownerNegativeCases) {
2403
- const fact = ownerCase.ruleContext?.facts.designGate;
2404
- const semantic = this.hostSemanticContext?.tools.find((tool) => tool.rawToolName === ownerCase.toolName);
2405
- if (semantic?.canonicalKind !== 'execute' || fact?.resolution !== 'not_approved' || !fact.requiresApproval)
2406
- continue;
2407
- designScopeCases.push({
2408
- caseId: `design-scope:${ownerCase.caseId}`, attackType: 'omission', toolName: ownerCase.toolName,
2409
- params: { command: 'node -e "process.stdout.write(123)"' }, expectedDecision: 'block',
2410
- rationale: 'System-derived counterfactual: the same trusted denied invocation scope cannot depend on command spelling; not a claim about historical behavior.',
2411
- ruleContext: ownerCase.ruleContext,
2412
- });
2413
- }
2414
- }
2415
- }
2416
2433
  const mergedAdversarialCases = [
2417
2434
  ...ownerNegativeAdversarial,
2418
- ...designScopeCases,
2435
+ ...verification.counterfactuals.filter((entry) => !positiveCases.some((positive) => positive.caseId === entry.caseId)),
2419
2436
  ...v2Cases,
2420
2437
  ...(hostAliasCase !== null ? [hostAliasCase] : []),
2421
- ...llmCases,
2438
+ ...llmCases.filter((entry) => verification.required.length === 0 || entry.ruleContext?.facts.designGate !== undefined),
2422
2439
  ];
2423
2440
  // (4) No adversarial cases (neither v2-generated nor LLM-supplied) →
2424
2441
  // nothing to replay. codeReview may still be present (passive review only).
@@ -2552,11 +2569,33 @@ export class EvaluatorRunner extends BasePeerRunner {
2552
2569
  const accepted = gateResult.decision === 'accepted_shadow';
2553
2570
  const failedCases = accepted
2554
2571
  ? []
2555
- : this.mapFailedCases(gateResult, mergedAdversarialCases);
2572
+ : this.mapFailedCases(gateResult, mergedAdversarialCases, mergedTrace.cases);
2573
+ const failedIds = new Set(gateResult.sandboxResult.failedCases.map((entry) => entry.caseId));
2574
+ const runtimeUnavailable = gateResult.sandboxResult.forbiddenPatternViolations.length > 0
2575
+ || (!gateResult.sandboxResult.success && gateResult.sandboxResult.failedCases.length === 0)
2576
+ || gateResult.sandboxResult.failedCases.some((entry) => RESERVED_SYSTEM_CASE_ID.test(entry.caseId));
2577
+ const historyExecuted = runtimeUnavailable ? 0 : verification.replayCases.length;
2578
+ const historyFailed = verification.replayCases.filter((entry) => failedIds.has(entry.caseId) || failedIds.has(`owner:${entry.caseId}`)).length;
2579
+ const contractExecuted = runtimeUnavailable ? 0 : verification.counterfactuals.length;
2580
+ const contractFailed = verification.counterfactuals.filter((entry) => failedIds.has(entry.caseId)).length;
2556
2581
  const adversarialResult = {
2557
2582
  passed: accepted,
2558
2583
  failedCases,
2559
2584
  ...(gateResult.failure ? { failure: { layer: gateResult.failure.layer, reasonCode: gateResult.failure.reasonCode } } : {}),
2585
+ verificationCoverage: {
2586
+ required: verification.required,
2587
+ executed: runtimeUnavailable ? 0 : mergedTrace.cases.length,
2588
+ passed: runtimeUnavailable ? 0 : mergedTrace.cases.length - gateResult.sandboxResult.failedCases.length,
2589
+ failed: runtimeUnavailable ? 0 : gateResult.sandboxResult.failedCases.length,
2590
+ unavailable: runtimeUnavailable ? [...verification.unavailable, 'sandbox_execution_unavailable'] : verification.unavailable,
2591
+ historicalCoverage: { executed: historyExecuted, passed: Math.max(0, historyExecuted - historyFailed), failed: historyFailed,
2592
+ unavailable: verification.historical.length - historyExecuted },
2593
+ contractCoverage: { required: verification.counterfactuals.length, executed: contractExecuted,
2594
+ passed: Math.max(0, contractExecuted - contractFailed), failed: contractFailed,
2595
+ unavailable: verification.counterfactuals.length - contractExecuted },
2596
+ historical: verification.historical,
2597
+ counterfactuals: verification.counterfactuals.map((entry) => ({ caseId: entry.caseId, source: 'system_counterfactual', contract: 'DesignGateFact/v1' })),
2598
+ },
2560
2599
  };
2561
2600
  return {
2562
2601
  updatedOutput: { ...output, adversarialResult },
@@ -2801,8 +2840,14 @@ export class EvaluatorRunner extends BasePeerRunner {
2801
2840
  * (Runtime Contract Rule 9: graceful degradation includes a reason).
2802
2841
  */
2803
2842
  // eslint-disable-next-line @typescript-eslint/class-methods-use-this
2804
- mapFailedCases(gateResult, adversarialCases) {
2843
+ mapFailedCases(gateResult, adversarialCases, executedCases = []) {
2805
2844
  const advById = new Map(adversarialCases.map((c) => [c.caseId, c]));
2845
+ for (const entry of executedCases) {
2846
+ if (!advById.has(entry.caseId))
2847
+ advById.set(entry.caseId, { caseId: entry.caseId, attackType: 'boundary',
2848
+ toolName: entry.toolName, params: entry.params, expectedDecision: entry.expectedDecision,
2849
+ rationale: 'System-executed replay case; this input is execution evidence, not a reconstructed historical fact.', ruleContext: entry.ruleContext });
2850
+ }
2806
2851
  // PRI-634 PR-A (SPEC §14): the sandbox failedCase is the authority for
2807
2852
  // expected/actual/errorType — it sees merged positive-case failures the
2808
2853
  // adversarial-case list cannot. actualDecision is copied ONLY when the
@@ -2871,7 +2916,11 @@ export class EvaluatorRunner extends BasePeerRunner {
2871
2916
  const contextState = adv.ruleContext
2872
2917
  ? `history ${history?.status ?? 'unknown'}${history?.truncated ? ' (truncated)' : ''}`
2873
2918
  : 'none';
2874
- const identityAndContext = `tool=${adv.toolName} | context: ${contextState}, priorReadOfTarget=${facts?.priorReadOfTarget ?? 'unknown'}, readCount=${facts?.readCount ?? 'unknown'}`;
2919
+ const gate = facts?.designGate;
2920
+ const designContext = gate !== undefined
2921
+ ? `designGate=${gate.resolution}, requiresApproval=${gate.requiresApproval}, binding=${gate.taskRef === gate.decisionTaskRef && gate.specDigest === gate.decisionSpecDigest && gate.scopeRef === gate.decisionScopeRef ? 'matched' : 'mismatched'}, revoked=${gate.revoked}; `
2922
+ : adv.caseId.startsWith('system-contract:design_approval:') ? 'designGate=missing; ' : '';
2923
+ const identityAndContext = `tool=${adv.toolName} | context: ${designContext}${contextState}, priorReadOfTarget=${facts?.priorReadOfTarget ?? 'unknown'}, readCount=${facts?.readCount ?? 'unknown'}`;
2875
2924
  let paramsDigest;
2876
2925
  try {
2877
2926
  paramsDigest = EvaluatorRunner.digestParams(adv.params);
@@ -3178,6 +3227,7 @@ export class EvaluatorRunner extends BasePeerRunner {
3178
3227
  && hostContext.tools.every((tool) => typeof tool.rawToolName === 'string' && tool.rawToolName.trim() !== ''
3179
3228
  && typeof tool.canonicalKind === 'string' && tool.canonicalKind.trim() !== '');
3180
3229
  let requiredFactKinds;
3230
+ let executableTrace = traceBuild.trace;
3181
3231
  if (typeof bearerPrincipleContentJson === 'string') {
3182
3232
  let scribeArtifact;
3183
3233
  try {
@@ -3201,9 +3251,34 @@ export class EvaluatorRunner extends BasePeerRunner {
3201
3251
  return null;
3202
3252
  }
3203
3253
  if (executionConditions.conditions !== null) {
3204
- const designApprovalRequired = executionConditions.conditions.requiredFacts.some((fact) => fact.required && fact.factKind === 'design_approval');
3205
- if (designApprovalRequired)
3206
- requiredFactKinds = ['design_approval'];
3254
+ requiredFactKinds = [...new Set(executionConditions.conditions.requiredFacts.filter((fact) => fact.required).map((fact) => fact.factKind))];
3255
+ if (requiredFactKinds.some((kind) => kind !== 'design_approval')) {
3256
+ this.emitEvent('rule_assembly_failed', taskId, { runId, reason: 'required_fact_contract_unsupported', requiredFactKinds,
3257
+ nextAction: 'provide_a_supported_runtime_fact_contract_before_assembly' });
3258
+ return null;
3259
+ }
3260
+ if (requiredFactKinds.length > 0) {
3261
+ const ownerBuild = Array.isArray(artificerParsed.ownerGoldenTraceCases)
3262
+ ? buildGoldenTraceFromArtificer({ cases: artificerParsed.ownerGoldenTraceCases })
3263
+ : null;
3264
+ if (ownerBuild === null || !ownerBuild.ok) {
3265
+ this.emitEvent('rule_assembly_failed', taskId, { runId, reason: 'owner_verification_cases_unavailable',
3266
+ nextAction: 'restore_the_system_owned_owner_cases_before_assembly' });
3267
+ return null;
3268
+ }
3269
+ const material = deriveRuleCodeVerification(scribeArtifact, ownerBuild.trace.cases, hostContext?.tools ?? []);
3270
+ if (material.unavailable.length > 0) {
3271
+ this.emitEvent('rule_assembly_failed', taskId, { runId, reason: 'required_fact_verification_unavailable', unavailable: material.unavailable,
3272
+ nextAction: 'restore_valid_supported_fact_material_before_assembly' });
3273
+ return null;
3274
+ }
3275
+ // The activation consumer replays this trace. Evidence-only Owner
3276
+ // labels remain verbatim alongside it, never synthetic history.
3277
+ executableTrace = { ...traceBuild.trace, cases: [...material.replayCases, ...material.counterfactuals.map((entry) => ({
3278
+ caseId: entry.caseId, kind: entry.expectedDecision === 'allow' ? 'positive' : 'negative', toolName: entry.toolName,
3279
+ params: entry.params, expectedDecision: entry.expectedDecision, ruleContext: entry.ruleContext,
3280
+ }))] };
3281
+ }
3207
3282
  }
3208
3283
  }
3209
3284
  if (requiresContextVersion === 2 && !hasHostInputContract) {
@@ -3215,8 +3290,9 @@ export class EvaluatorRunner extends BasePeerRunner {
3215
3290
  }
3216
3291
  const ruleContent = {
3217
3292
  implementationCode,
3218
- goldenTrace: traceBuild.trace,
3293
+ goldenTrace: executableTrace,
3219
3294
  goldenTraceCases,
3295
+ ...(artificerParsed.ownerGoldenTraceCases !== undefined ? { ownerGoldenTraceCases: artificerParsed.ownerGoldenTraceCases } : {}),
3220
3296
  affectedTools: validatedAffectedTools,
3221
3297
  // adversarialResult.passed === true is the precondition for this method;
3222
3298
  // the gate decision is therefore accepted_shadow.