@principles/core 1.263.0 → 1.264.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 (93) hide show
  1. package/dist/runtime-v2/__tests__/architecture-regression.test.js +8 -2
  2. package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  3. package/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.d.ts +2 -0
  4. package/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.d.ts.map +1 -0
  5. package/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.js +91 -0
  6. package/dist/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.js.map +1 -0
  7. package/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.d.ts +2 -0
  8. package/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.d.ts.map +1 -0
  9. package/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js +83 -0
  10. package/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js.map +1 -0
  11. package/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.d.ts +2 -0
  12. package/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.d.ts.map +1 -0
  13. package/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.js +48 -0
  14. package/dist/runtime-v2/activation/__tests__/promotion-readiness-reader.test.js.map +1 -0
  15. package/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.d.ts +2 -0
  16. package/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.d.ts.map +1 -0
  17. package/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js +141 -0
  18. package/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js.map +1 -0
  19. package/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.d.ts +2 -0
  20. package/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.d.ts.map +1 -0
  21. package/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.js +31 -0
  22. package/dist/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.js.map +1 -0
  23. package/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.d.ts +2 -0
  24. package/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.d.ts.map +1 -0
  25. package/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js +311 -0
  26. package/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js.map +1 -0
  27. package/dist/runtime-v2/activation/activation-control-types.d.ts +61 -0
  28. package/dist/runtime-v2/activation/activation-control-types.d.ts.map +1 -0
  29. package/dist/runtime-v2/activation/activation-control-types.js +2 -0
  30. package/dist/runtime-v2/activation/activation-control-types.js.map +1 -0
  31. package/dist/runtime-v2/activation/index.d.ts +14 -0
  32. package/dist/runtime-v2/activation/index.d.ts.map +1 -1
  33. package/dist/runtime-v2/activation/index.js +7 -0
  34. package/dist/runtime-v2/activation/index.js.map +1 -1
  35. package/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts +30 -0
  36. package/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts.map +1 -0
  37. package/dist/runtime-v2/activation/openclaw-promotion-checks.js +124 -0
  38. package/dist/runtime-v2/activation/openclaw-promotion-checks.js.map +1 -0
  39. package/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts +17 -0
  40. package/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts.map +1 -0
  41. package/dist/runtime-v2/activation/promotion-readiness-evaluator.js +55 -0
  42. package/dist/runtime-v2/activation/promotion-readiness-evaluator.js.map +1 -0
  43. package/dist/runtime-v2/activation/promotion-readiness-reader.d.ts +21 -0
  44. package/dist/runtime-v2/activation/promotion-readiness-reader.d.ts.map +1 -0
  45. package/dist/runtime-v2/activation/promotion-readiness-reader.js +44 -0
  46. package/dist/runtime-v2/activation/promotion-readiness-reader.js.map +1 -0
  47. package/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts +104 -0
  48. package/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts.map +1 -0
  49. package/dist/runtime-v2/activation/rulecode-owner-decision-service.js +86 -0
  50. package/dist/runtime-v2/activation/rulecode-owner-decision-service.js.map +1 -0
  51. package/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.d.ts +25 -0
  52. package/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.d.ts.map +1 -0
  53. package/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.js +23 -0
  54. package/dist/runtime-v2/activation/rulecode-safety-circuit-breaker.js.map +1 -0
  55. package/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts +14 -0
  56. package/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts.map +1 -0
  57. package/dist/runtime-v2/activation/rulecode-shadow-summary.js +57 -0
  58. package/dist/runtime-v2/activation/rulecode-shadow-summary.js.map +1 -0
  59. package/dist/runtime-v2/activation/sqlite-activation-safety-store.d.ts +40 -0
  60. package/dist/runtime-v2/activation/sqlite-activation-safety-store.d.ts.map +1 -0
  61. package/dist/runtime-v2/activation/sqlite-activation-safety-store.js +461 -0
  62. package/dist/runtime-v2/activation/sqlite-activation-safety-store.js.map +1 -0
  63. package/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts.map +1 -1
  64. package/dist/runtime-v2/activation/sqlite-activation-state-store.js +24 -6
  65. package/dist/runtime-v2/activation/sqlite-activation-state-store.js.map +1 -1
  66. package/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js +19 -4
  67. package/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js.map +1 -1
  68. package/dist/runtime-v2/activation/writers/rule-host-writer.d.ts.map +1 -1
  69. package/dist/runtime-v2/activation/writers/rule-host-writer.js +10 -0
  70. package/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
  71. package/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +13 -0
  72. package/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
  73. package/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +15 -2
  74. package/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  75. package/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  76. package/dist/runtime-v2/feature-flags/feature-flag-contract.js +2 -0
  77. package/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  78. package/dist/runtime-v2/index.d.ts +2 -2
  79. package/dist/runtime-v2/index.d.ts.map +1 -1
  80. package/dist/runtime-v2/index.js +1 -1
  81. package/dist/runtime-v2/index.js.map +1 -1
  82. package/dist/runtime-v2/internalization/__tests__/legacy-rule-contract-scanner.test.js +20 -1
  83. package/dist/runtime-v2/internalization/__tests__/legacy-rule-contract-scanner.test.js.map +1 -1
  84. package/dist/runtime-v2/internalization/legacy-rule-contract-scanner.d.ts +4 -4
  85. package/dist/runtime-v2/internalization/legacy-rule-contract-scanner.d.ts.map +1 -1
  86. package/dist/runtime-v2/internalization/legacy-rule-contract-scanner.js +92 -5
  87. package/dist/runtime-v2/internalization/legacy-rule-contract-scanner.js.map +1 -1
  88. package/dist/runtime-v2/store/sqlite-connection-schema-version.test.js +11 -11
  89. package/dist/runtime-v2/store/sqlite-connection-schema-version.test.js.map +1 -1
  90. package/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
  91. package/dist/runtime-v2/store/sqlite-connection.js +111 -0
  92. package/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
  93. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=openclaw-promotion-checks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-promotion-checks.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,91 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createProductionGateDeps } from '../production-gate-deps.js';
3
+ import { RuleHostWriter } from '../writers/rule-host-writer.js';
4
+ import { collectOpenClawPromotionChecks } from '../openclaw-promotion-checks.js';
5
+ const OPENCLAW_HOST_LIVENESS_CONTRACT = {
6
+ version: 'openclaw-legacy@1',
7
+ supportsShadowEvidence: true,
8
+ outOfBandControls: ['activation_deactivate', 'global_rulecode_pause', 'owner_review_console'],
9
+ protectedCapabilities: [
10
+ { capabilityId: 'pd_status', hostToolAliases: ['bash'] },
11
+ { capabilityId: 'rulecode_deactivate', hostToolAliases: ['bash'] },
12
+ { capabilityId: 'rulecode_global_pause', hostToolAliases: ['bash'] },
13
+ { capabilityId: 'owner_review_access', hostToolAliases: ['owner_review_access'] },
14
+ ],
15
+ neutralProbes: [
16
+ { probeId: 'status', capabilityId: 'pd_status', toolName: 'bash', params: { command: 'pd status' }, expectedDecision: 'allow' },
17
+ { probeId: 'deactivate', capabilityId: 'rulecode_deactivate', toolName: 'bash', params: { command: 'pd activation deactivate --activation-id test' }, expectedDecision: 'allow' },
18
+ { probeId: 'pause', capabilityId: 'rulecode_global_pause', toolName: 'bash', params: { command: 'pd activation emergency-pause' }, expectedDecision: 'allow' },
19
+ { probeId: 'review', capabilityId: 'owner_review_access', toolName: 'owner_review_access', params: {}, expectedDecision: 'allow' },
20
+ ],
21
+ };
22
+ function artifact(id, implementationCode) {
23
+ return {
24
+ artifactId: id,
25
+ artifactKind: 'rule',
26
+ sourceTaskId: `task-${id}`,
27
+ sourcePrincipleId: 'principle-1',
28
+ sourceRuleId: `rule-${id}`,
29
+ lineageArtifactIds: ['parent-1'],
30
+ validationStatus: 'validated',
31
+ contentJson: JSON.stringify({
32
+ implementationCode,
33
+ goldenTrace: {
34
+ traceId: `trace-${id}`,
35
+ sourcePainId: 'pain-1',
36
+ cases: [
37
+ { caseId: 'negative', kind: 'negative', toolName: 'edit_file', params: { path: '/etc/passwd' }, expectedDecision: 'block' },
38
+ { caseId: 'positive', kind: 'positive', toolName: 'edit_file', params: { path: '/workspace/safe.ts' }, expectedDecision: 'allow' },
39
+ ],
40
+ createdAt: '2026-08-21T00:00:00.000Z',
41
+ version: 1,
42
+ },
43
+ ruleHostGateDecision: 'accepted_shadow',
44
+ affectedTools: ['edit_file', 'bash'],
45
+ }),
46
+ createdAt: '2026-08-21T00:00:00.000Z',
47
+ updatedAt: '2026-08-21T00:00:00.000Z',
48
+ };
49
+ }
50
+ const safeCode = `function evaluate(input) {
51
+ const risky = input.action.toolName === 'edit_file' && input.action.paramsSummary.path === '/etc/passwd';
52
+ return { decision: risky ? 'block' : 'allow', matched: risky, reason: risky ? 'risk path' : 'neutral' };
53
+ }`;
54
+ const controlBlockingCode = `function evaluate(input) {
55
+ const blocksControl = input.action.toolName === 'bash';
56
+ const risky = input.action.toolName === 'edit_file' && input.action.paramsSummary.path === '/etc/passwd';
57
+ return { decision: blocksControl || risky ? 'block' : 'allow', matched: blocksControl || risky, reason: blocksControl ? 'deny shell' : risky ? 'risk path' : 'neutral' };
58
+ }`;
59
+ describe('OpenClaw Host Liveness promotion checks', () => {
60
+ const writer = new RuleHostWriter({ gateDeps: createProductionGateDeps() });
61
+ it('runs neutral probes through production validation for the candidate and live composition', async () => {
62
+ const checks = await collectOpenClawPromotionChecks(artifact('candidate', safeCode), {
63
+ ownerIdentityConfigured: true,
64
+ safetyControlsEnabled: true,
65
+ hostContract: OPENCLAW_HOST_LIVENESS_CONTRACT,
66
+ existingLiveArtifacts: [artifact('live', controlBlockingCode)],
67
+ validateProductionArtifact: value => writer.canActivate(value),
68
+ });
69
+ expect(checks.find(check => check.checkId === 'host_liveness_composition')).toEqual({
70
+ checkId: 'host_liveness_composition',
71
+ status: 'failed',
72
+ reasonCode: 'neutral_probe_or_live_composition_failed',
73
+ });
74
+ });
75
+ it('fails compatibility, emergency, shadow evidence, and composition when the adapter contract is unavailable', async () => {
76
+ const checks = await collectOpenClawPromotionChecks(artifact('candidate', safeCode), {
77
+ ownerIdentityConfigured: true,
78
+ safetyControlsEnabled: true,
79
+ hostContract: null,
80
+ existingLiveArtifacts: [],
81
+ validateProductionArtifact: value => writer.canActivate(value),
82
+ });
83
+ expect(checks.filter(check => check.status === 'failed').map(check => check.checkId)).toEqual([
84
+ 'runtime_compatibility',
85
+ 'host_liveness_composition',
86
+ 'emergency_controls',
87
+ 'runtime_shadow_evidence',
88
+ ]);
89
+ });
90
+ });
91
+ //# sourceMappingURL=openclaw-promotion-checks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openclaw-promotion-checks.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/openclaw-promotion-checks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=promotion-readiness-evaluator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-readiness-evaluator.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,83 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { REQUIRED_PROMOTION_CHECK_IDS, evaluateRuleCodePromotionReadiness, } from '../index.js';
3
+ const snapshot = {
4
+ snapshotId: 'snap-1',
5
+ snapshotDigest: 'sha256:snapshot',
6
+ artifactDigest: 'sha256:artifact',
7
+ lineageRefs: ['task-1', 'run-1'],
8
+ hostRuntimeVersion: 'openclaw@1',
9
+ safetyGateResults: [],
10
+ shadowSummary: { observed: 20, matched: 3, wouldBlock: 1, wouldAllow: 19, requireApproval: 0, autoCorrect: 0, errors: 0, neutralControl: 1, firstObservedAt: '2026-08-20T00:00:00.000Z', lastObservedAt: '2026-08-21T00:00:00.000Z' },
11
+ configurationVersion: 'config-v1',
12
+ redaction: { version: 'v1', rawParametersStored: false },
13
+ createdAt: '2026-08-21T00:00:00.000Z',
14
+ };
15
+ function passingChecks() {
16
+ return REQUIRED_PROMOTION_CHECK_IDS.map(checkId => ({ checkId, status: 'passed' }));
17
+ }
18
+ describe('evaluateRuleCodePromotionReadiness', () => {
19
+ it('returns ready only when every required hard check is present and passed', () => {
20
+ const result = evaluateRuleCodePromotionReadiness({
21
+ evaluationId: 'eval-1', artifactId: 'artifact-1', artifactDigest: 'sha256:artifact',
22
+ evidenceSnapshot: snapshot, checks: passingChecks(),
23
+ });
24
+ expect(result.status).toBe('ready');
25
+ expect(result.failedChecks).toEqual([]);
26
+ expect(result.evidenceSnapshot.safetyGateResults).toHaveLength(REQUIRED_PROMOTION_CHECK_IDS.length);
27
+ });
28
+ it('blocks when a hard Host Liveness check fails', () => {
29
+ const checks = passingChecks().map(check => check.checkId === 'host_liveness_composition'
30
+ ? { ...check, status: 'failed', reasonCode: 'neutral_probe_blocked' }
31
+ : check);
32
+ const result = evaluateRuleCodePromotionReadiness({
33
+ evaluationId: 'eval-2', artifactId: 'artifact-1', artifactDigest: 'sha256:artifact',
34
+ evidenceSnapshot: snapshot, checks,
35
+ });
36
+ expect(result.status).toBe('blocked');
37
+ expect(result.failedChecks).toEqual([{ checkId: 'host_liveness_composition', reasonCode: 'neutral_probe_blocked' }]);
38
+ });
39
+ it('is unavailable when a required check is absent instead of treating missing evidence as pass', () => {
40
+ const result = evaluateRuleCodePromotionReadiness({
41
+ evaluationId: 'eval-3', artifactId: 'artifact-1', artifactDigest: 'sha256:artifact',
42
+ evidenceSnapshot: snapshot,
43
+ checks: passingChecks().filter(check => check.checkId !== 'runtime_shadow_evidence'),
44
+ });
45
+ expect(result.status).toBe('unavailable');
46
+ expect(result.failedChecks).toEqual([{ checkId: 'runtime_shadow_evidence', reasonCode: 'required_check_missing' }]);
47
+ });
48
+ it('rejects an evidence snapshot bound to a different artifact digest', () => {
49
+ const result = evaluateRuleCodePromotionReadiness({
50
+ evaluationId: 'eval-4', artifactId: 'artifact-1', artifactDigest: 'sha256:different',
51
+ evidenceSnapshot: snapshot, checks: passingChecks(),
52
+ });
53
+ expect(result.status).toBe('unavailable');
54
+ expect(result.failedChecks).toContainEqual({ checkId: 'evidence_binding', reasonCode: 'artifact_digest_mismatch' });
55
+ });
56
+ it.each([
57
+ ['less than 24 hours', { firstObservedAt: '2026-08-20T00:00:00.001Z' }],
58
+ ['fewer than 20 eligible evaluations', { observed: 19 }],
59
+ ['fewer than 3 matches', { matched: 2 }],
60
+ ['no neutral-control sample', { neutralControl: 0 }],
61
+ ])('keeps promotion evidence-insufficient when %s', (_name, shadowSummary) => {
62
+ const result = evaluateRuleCodePromotionReadiness({
63
+ evaluationId: 'eval-insufficient', artifactId: 'artifact-1', artifactDigest: 'sha256:artifact',
64
+ evidenceSnapshot: { ...snapshot, shadowSummary: { ...snapshot.shadowSummary, ...shadowSummary } },
65
+ checks: passingChecks(),
66
+ });
67
+ expect(result.status).toBe('evidence_insufficient');
68
+ expect(result.failedChecks).toEqual([]);
69
+ });
70
+ it('turns unresolved unhealthy shadow evidence into a non-overridable hard failure', () => {
71
+ const result = evaluateRuleCodePromotionReadiness({
72
+ evaluationId: 'eval-unhealthy', artifactId: 'artifact-1', artifactDigest: 'sha256:artifact',
73
+ evidenceSnapshot: { ...snapshot, shadowSummary: { ...snapshot.shadowSummary, errors: 1 } },
74
+ checks: passingChecks(),
75
+ });
76
+ expect(result.status).toBe('blocked');
77
+ expect(result.failedChecks).toContainEqual({
78
+ checkId: 'runtime_shadow_evidence',
79
+ reasonCode: 'unresolved_shadow_unhealthy_evidence',
80
+ });
81
+ });
82
+ });
83
+ //# sourceMappingURL=promotion-readiness-evaluator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-readiness-evaluator.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=promotion-readiness-reader.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-readiness-reader.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/promotion-readiness-reader.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { PromotionReadinessReader, REQUIRED_PROMOTION_CHECK_IDS } from '../index.js';
3
+ const activation = {
4
+ activationId: 'act-1', idempotencyKey: 'key-1', artifactId: 'art-1', channel: 'code_tool_hook',
5
+ action: 'code_tool_hook_shadow_activate', targetRef: 'impl://rule-1', activatedAt: '2026-08-21T00:00:00Z', deactivatedAt: null,
6
+ };
7
+ const artifact = {
8
+ artifactId: 'art-1', artifactKind: 'rule', sourceTaskId: 'task-1', lineageArtifactIds: ['parent-1'],
9
+ validationStatus: 'validated', contentJson: '{"implementationCode":"code"}',
10
+ createdAt: '2026-08-21T00:00:00Z', updatedAt: '2026-08-21T00:00:00Z',
11
+ };
12
+ describe('PromotionReadinessReader', () => {
13
+ it('returns granular unavailable checks when host facts are absent', async () => {
14
+ const reader = new PromotionReadinessReader({
15
+ listCodeToolHookActivations: async () => [activation],
16
+ getArtifactById: async () => artifact,
17
+ computeArtifactDigest: () => 'sha256:artifact',
18
+ validateProductionArtifact: async () => ({ ok: true, riskLevel: 'high' }),
19
+ collectHostChecks: async () => [],
20
+ buildEvidenceSnapshot: checks => ({
21
+ snapshotId: 'snap-1', snapshotDigest: 'sha256:snapshot', artifactDigest: 'sha256:artifact',
22
+ lineageRefs: ['task-1', 'parent-1'], hostRuntimeVersion: 'unavailable', safetyGateResults: checks,
23
+ shadowSummary: { observed: 0, matched: 0, wouldBlock: 0, wouldAllow: 0, requireApproval: 0, autoCorrect: 0, errors: 0, neutralControl: 0, firstObservedAt: null, lastObservedAt: null }, configurationVersion: 'config-v1',
24
+ redaction: { version: 'v1', rawParametersStored: false }, createdAt: '2026-08-21T00:00:00Z',
25
+ }),
26
+ newEvaluationId: () => 'eval-1',
27
+ });
28
+ const result = await reader.evaluate({ activationId: 'act-1', expectedArtifactId: 'art-1', expectedArtifactDigest: 'sha256:artifact' });
29
+ expect(result.status).toBe('unavailable');
30
+ expect(result.failedChecks.map(check => check.checkId)).toEqual(expect.arrayContaining(REQUIRED_PROMOTION_CHECK_IDS.filter(id => !['activation_eligibility', 'lineage_binding', 'production_compile_load', 'golden_trace'].includes(id))));
31
+ });
32
+ it('blocks a stale artifact binding before production validation', async () => {
33
+ let validationCalls = 0;
34
+ const reader = new PromotionReadinessReader({
35
+ listCodeToolHookActivations: async () => [activation], getArtifactById: async () => artifact,
36
+ computeArtifactDigest: () => 'sha256:current',
37
+ validateProductionArtifact: async () => { validationCalls += 1; return { ok: true, riskLevel: 'high' }; },
38
+ collectHostChecks: async () => [],
39
+ buildEvidenceSnapshot: checks => ({ snapshotId: 'snap', snapshotDigest: 'digest', artifactDigest: 'sha256:current', lineageRefs: [], hostRuntimeVersion: 'unavailable', safetyGateResults: checks, shadowSummary: { observed: 0, matched: 0, wouldBlock: 0, wouldAllow: 0, requireApproval: 0, autoCorrect: 0, errors: 0, neutralControl: 0, firstObservedAt: null, lastObservedAt: null }, configurationVersion: 'v1', redaction: { version: 'v1', rawParametersStored: false }, createdAt: 'now' }),
40
+ newEvaluationId: () => 'eval-2',
41
+ });
42
+ const result = await reader.evaluate({ activationId: 'act-1', expectedArtifactId: 'art-1', expectedArtifactDigest: 'sha256:stale' });
43
+ expect(result.status).toBe('blocked');
44
+ expect(result.failedChecks).toContainEqual({ checkId: 'lineage_binding', reasonCode: 'artifact_digest_mismatch' });
45
+ expect(validationCalls).toBe(0);
46
+ });
47
+ });
48
+ //# sourceMappingURL=promotion-readiness-reader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-readiness-reader.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/promotion-readiness-reader.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rulecode-owner-decision-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rulecode-owner-decision-service.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { RuleCodeOwnerDecisionService } from '../rulecode-owner-decision-service.js';
3
+ const actor = {
4
+ principal: { kind: 'configured_owner', ownerId: 'owner-1' },
5
+ authentication: { method: 'cli_owner_credential', credentialId: 'credential-1' },
6
+ operator: { kind: 'local_user', operatorId: 'Administrator' },
7
+ };
8
+ const ready = {
9
+ status: 'ready',
10
+ evaluationId: 'readiness-1',
11
+ artifactId: 'artifact-1',
12
+ artifactDigest: 'sha256:artifact',
13
+ evidenceSnapshot: {
14
+ snapshotId: 'snapshot-1',
15
+ snapshotDigest: 'sha256:snapshot',
16
+ artifactDigest: 'sha256:artifact',
17
+ lineageRefs: ['task-1', 'run-1'],
18
+ hostRuntimeVersion: 'openclaw@1',
19
+ safetyGateResults: [{ checkId: 'host_liveness', status: 'passed' }],
20
+ shadowSummary: { observed: 20, matched: 3, wouldBlock: 1, wouldAllow: 19, requireApproval: 0, autoCorrect: 0, errors: 0, neutralControl: 1, firstObservedAt: '2026-08-20T00:00:00.000Z', lastObservedAt: '2026-08-21T00:00:00.000Z' },
21
+ configurationVersion: 'config-v1',
22
+ redaction: { version: 'redaction-v1', rawParametersStored: false },
23
+ createdAt: '2026-08-21T02:00:00.000Z',
24
+ },
25
+ failedChecks: [],
26
+ };
27
+ function service(input) {
28
+ const commitPromotion = vi.fn(async (_value) => ({
29
+ activationId: 'activation-1', decisionId: 'decision-1', promotedAt: '2026-08-21T02:01:00.000Z',
30
+ }));
31
+ return {
32
+ commitPromotion,
33
+ instance: new RuleCodeOwnerDecisionService({
34
+ ownerLiveDecisionEnabled: () => input?.ownerEnabled ?? true,
35
+ safetyControlsEnabled: () => input?.safetyEnabled ?? true,
36
+ evaluateReadiness: async () => input?.readiness ?? ready,
37
+ commitPromotion,
38
+ newDecisionId: () => 'decision-1',
39
+ now: () => '2026-08-21T02:01:00.000Z',
40
+ }),
41
+ };
42
+ }
43
+ const request = {
44
+ activationId: 'activation-1',
45
+ expectedArtifactId: 'artifact-1',
46
+ expectedArtifactDigest: 'sha256:artifact',
47
+ expectedControlVersion: 1,
48
+ idempotencyKey: 'promote-activation-1-v1',
49
+ reasonCode: 'owner_accepts_shadow_evidence',
50
+ note: 'Reviewed shadow evidence and host-liveness results.',
51
+ confirmed: true,
52
+ };
53
+ describe('RuleCodeOwnerDecisionService promotion authority', () => {
54
+ it('refuses promotion when the Owner decision feature is disabled without calling legacy mutation', async () => {
55
+ const { instance, commitPromotion } = service({ ownerEnabled: false });
56
+ await expect(instance.promote(request, actor)).resolves.toMatchObject({
57
+ ok: false, reasonCode: 'feature_not_enabled', nextAction: expect.stringContaining('rulecode_owner_live_decision'),
58
+ });
59
+ expect(commitPromotion).not.toHaveBeenCalled();
60
+ });
61
+ it('refuses promotion when safety authority is unavailable', async () => {
62
+ const { instance, commitPromotion } = service({ safetyEnabled: false });
63
+ await expect(instance.promote(request, actor)).resolves.toMatchObject({
64
+ ok: false, reasonCode: 'safety_controls_unavailable', nextAction: expect.any(String),
65
+ });
66
+ expect(commitPromotion).not.toHaveBeenCalled();
67
+ });
68
+ it('refuses local break-glass identity from writing an Owner governance decision', async () => {
69
+ const { instance, commitPromotion } = service();
70
+ await expect(instance.promote(request, {
71
+ principal: { kind: 'break_glass', reason: 'local_no_auth_emergency' },
72
+ authentication: { method: 'local_break_glass' },
73
+ })).resolves.toMatchObject({ ok: false, reasonCode: 'owner_authentication_required' });
74
+ expect(commitPromotion).not.toHaveBeenCalled();
75
+ });
76
+ it('refuses blocked or unavailable readiness without committing', async () => {
77
+ for (const status of ['blocked', 'unavailable']) {
78
+ const { instance, commitPromotion } = service({ readiness: {
79
+ ...ready, status, failedChecks: [{ checkId: 'host_liveness', reasonCode: 'host_contract_unavailable' }],
80
+ } });
81
+ await expect(instance.promote(request, actor)).resolves.toMatchObject({
82
+ ok: false, reasonCode: status === 'blocked' ? 'promotion_safety_gate_blocked' : 'promotion_readiness_unavailable',
83
+ failedChecks: [{ checkId: 'host_liveness', reasonCode: 'host_contract_unavailable' }],
84
+ });
85
+ expect(commitPromotion).not.toHaveBeenCalled();
86
+ }
87
+ });
88
+ it('requires a note for every CLI Owner promotion before readiness evaluation', async () => {
89
+ const { instance, commitPromotion } = service();
90
+ await expect(instance.promote({ ...request, note: ' ' }, actor)).resolves.toMatchObject({
91
+ ok: false, reasonCode: 'cli_owner_note_required', nextAction: expect.stringContaining('note'),
92
+ });
93
+ expect(commitPromotion).not.toHaveBeenCalled();
94
+ });
95
+ it('binds authenticated Owner identity and evidence into the sole atomic commit', async () => {
96
+ const { instance, commitPromotion } = service();
97
+ await expect(instance.promote(request, actor)).resolves.toEqual({
98
+ ok: true, decision: 'promoted', activationId: 'activation-1', decisionId: 'decision-1', promotedAt: '2026-08-21T02:01:00.000Z',
99
+ });
100
+ expect(commitPromotion).toHaveBeenCalledOnce();
101
+ expect(commitPromotion).toHaveBeenCalledWith(expect.objectContaining({
102
+ expectedControlVersion: 1,
103
+ idempotencyKey: 'promote-activation-1-v1',
104
+ evidenceSnapshot: ready.evidenceSnapshot,
105
+ decision: expect.objectContaining({
106
+ decisionId: 'decision-1', decision: 'promote_live', principal: actor.principal,
107
+ authentication: actor.authentication, operator: actor.operator,
108
+ evidenceSnapshotId: 'snapshot-1',
109
+ }),
110
+ }));
111
+ });
112
+ it('evaluates a dry-run but never commits a live decision', async () => {
113
+ const { instance, commitPromotion } = service();
114
+ await expect(instance.promote({ ...request, confirmed: false, dryRun: true }, actor)).resolves.toEqual({
115
+ ok: true,
116
+ decision: 'would_promote',
117
+ activationId: 'activation-1',
118
+ readinessEvaluationId: 'readiness-1',
119
+ evidenceSnapshotDigest: 'sha256:snapshot',
120
+ });
121
+ expect(commitPromotion).not.toHaveBeenCalled();
122
+ });
123
+ it('refuses an evidence-insufficient promotion without an approved override reason', async () => {
124
+ const { instance, commitPromotion } = service({ readiness: { ...ready, status: 'evidence_insufficient' } });
125
+ await expect(instance.promote({ ...request, reasonCode: 'looks_safe' }, actor)).resolves.toMatchObject({
126
+ ok: false,
127
+ reasonCode: 'evidence_override_reason_required',
128
+ });
129
+ expect(commitPromotion).not.toHaveBeenCalled();
130
+ });
131
+ it('allows an evidence-insufficient promotion only with a predefined reason and note', async () => {
132
+ const { instance, commitPromotion } = service({ readiness: { ...ready, status: 'evidence_insufficient' } });
133
+ await expect(instance.promote({
134
+ ...request,
135
+ reasonCode: 'controlled_rollout',
136
+ note: 'Limited rollout with immediate emergency controls verified.',
137
+ }, actor)).resolves.toMatchObject({ ok: true, decision: 'promoted' });
138
+ expect(commitPromotion).toHaveBeenCalledOnce();
139
+ });
140
+ });
141
+ //# sourceMappingURL=rulecode-owner-decision-service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rulecode-owner-decision-service.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rulecode-safety-circuit-breaker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rulecode-safety-circuit-breaker.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { evaluateRuleCodeSafetyCircuit, initialRuleCodeSafetyCircuitState } from '../rulecode-safety-circuit-breaker.js';
3
+ describe('RuleCode safety circuit breaker', () => {
4
+ it('trips immediately for protected controls and runtime health failures', () => {
5
+ expect(evaluateRuleCodeSafetyCircuit(initialRuleCodeSafetyCircuitState(), { toolName: 'pd', decision: 'allow', outsideApprovedScope: false, protectedCapabilityMatched: true }).trip).toBe('protected_capability_matched');
6
+ expect(evaluateRuleCodeSafetyCircuit(initialRuleCodeSafetyCircuitState(), { toolName: 'write', decision: 'error', outsideApprovedScope: false, healthFailure: 'timeout' }).trip).toBe('runtime_health_failure');
7
+ });
8
+ it('trips after three consecutive errors and resets the sequence on success', () => {
9
+ let state = initialRuleCodeSafetyCircuitState();
10
+ for (let index = 0; index < 2; index += 1) {
11
+ ({ state } = evaluateRuleCodeSafetyCircuit(state, { toolName: 'write', decision: 'error', outsideApprovedScope: false }));
12
+ }
13
+ expect(evaluateRuleCodeSafetyCircuit(state, { toolName: 'write', decision: 'error', outsideApprovedScope: false }).trip).toBe('three_consecutive_errors');
14
+ expect(evaluateRuleCodeSafetyCircuit(state, { toolName: 'write', decision: 'allow', outsideApprovedScope: false }).state.consecutiveErrors).toBe(0);
15
+ });
16
+ it('trips for five consecutive blocks spanning three tools', () => {
17
+ let state = initialRuleCodeSafetyCircuitState();
18
+ for (const toolName of ['write', 'bash', 'write', 'agent']) {
19
+ ({ state } = evaluateRuleCodeSafetyCircuit(state, { toolName, decision: 'block', outsideApprovedScope: false }));
20
+ }
21
+ expect(evaluateRuleCodeSafetyCircuit(state, { toolName: 'bash', decision: 'block', outsideApprovedScope: false }).trip).toBe('broad_consecutive_blocking');
22
+ });
23
+ it('trips when more than eighty percent of the latest twenty calls are blocked outside scope', () => {
24
+ let state = initialRuleCodeSafetyCircuitState();
25
+ for (let index = 0; index < 19; index += 1) {
26
+ ({ state } = evaluateRuleCodeSafetyCircuit(state, { toolName: `tool-${index}`, decision: index < 17 ? 'block' : 'allow', outsideApprovedScope: index < 17 }));
27
+ }
28
+ expect(evaluateRuleCodeSafetyCircuit(state, { toolName: 'last', decision: 'allow', outsideApprovedScope: false }).trip).toBe('outside_scope_block_ratio');
29
+ });
30
+ });
31
+ //# sourceMappingURL=rulecode-safety-circuit-breaker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rulecode-safety-circuit-breaker.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/rulecode-safety-circuit-breaker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sqlite-activation-safety-store.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-activation-safety-store.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.ts"],"names":[],"mappings":""}