tryassay 0.6.0 → 0.11.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 (109) hide show
  1. package/dist/api/pricing-enforcer.d.ts +45 -0
  2. package/dist/api/pricing-enforcer.js +144 -0
  3. package/dist/api/pricing-enforcer.js.map +1 -0
  4. package/dist/api/server.d.ts +28 -0
  5. package/dist/api/server.js +265 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/api/team-session.d.ts +59 -0
  8. package/dist/api/team-session.js +240 -0
  9. package/dist/api/team-session.js.map +1 -0
  10. package/dist/cli.js +123 -2
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/api.d.ts +4 -0
  13. package/dist/commands/api.js +50 -0
  14. package/dist/commands/api.js.map +1 -0
  15. package/dist/commands/runtime.d.ts +61 -0
  16. package/dist/commands/runtime.js +554 -0
  17. package/dist/commands/runtime.js.map +1 -1
  18. package/dist/runtime/agent-spawner.d.ts +56 -0
  19. package/dist/runtime/agent-spawner.js +217 -0
  20. package/dist/runtime/agent-spawner.js.map +1 -0
  21. package/dist/runtime/agents/coordinator-agent.d.ts +20 -0
  22. package/dist/runtime/agents/coordinator-agent.js +182 -0
  23. package/dist/runtime/agents/coordinator-agent.js.map +1 -0
  24. package/dist/runtime/agents/ops-agent.d.ts +11 -0
  25. package/dist/runtime/agents/ops-agent.js +113 -0
  26. package/dist/runtime/agents/ops-agent.js.map +1 -0
  27. package/dist/runtime/agents/research-agent.d.ts +11 -0
  28. package/dist/runtime/agents/research-agent.js +114 -0
  29. package/dist/runtime/agents/research-agent.js.map +1 -0
  30. package/dist/runtime/agents/test-agent.d.ts +11 -0
  31. package/dist/runtime/agents/test-agent.js +114 -0
  32. package/dist/runtime/agents/test-agent.js.map +1 -0
  33. package/dist/runtime/audit-log.js +2 -2
  34. package/dist/runtime/audit-log.js.map +1 -1
  35. package/dist/runtime/capability-registry.d.ts +62 -0
  36. package/dist/runtime/capability-registry.js +191 -0
  37. package/dist/runtime/capability-registry.js.map +1 -0
  38. package/dist/runtime/collusion-detector.d.ts +35 -0
  39. package/dist/runtime/collusion-detector.js +97 -0
  40. package/dist/runtime/collusion-detector.js.map +1 -0
  41. package/dist/runtime/control-server.js +8 -4
  42. package/dist/runtime/control-server.js.map +1 -1
  43. package/dist/runtime/domain-coverage-analyzer.d.ts +24 -0
  44. package/dist/runtime/domain-coverage-analyzer.js +178 -0
  45. package/dist/runtime/domain-coverage-analyzer.js.map +1 -0
  46. package/dist/runtime/executor.js +27 -12
  47. package/dist/runtime/executor.js.map +1 -1
  48. package/dist/runtime/human-escalation.d.ts +41 -0
  49. package/dist/runtime/human-escalation.js +122 -0
  50. package/dist/runtime/human-escalation.js.map +1 -0
  51. package/dist/runtime/kill-switch.d.ts +51 -0
  52. package/dist/runtime/kill-switch.js +185 -0
  53. package/dist/runtime/kill-switch.js.map +1 -0
  54. package/dist/runtime/layer2-guardian.d.ts +81 -0
  55. package/dist/runtime/layer2-guardian.js +263 -0
  56. package/dist/runtime/layer2-guardian.js.map +1 -0
  57. package/dist/runtime/multi-agent-loop.d.ts +37 -0
  58. package/dist/runtime/multi-agent-loop.js +411 -0
  59. package/dist/runtime/multi-agent-loop.js.map +1 -0
  60. package/dist/runtime/prompt-safety-analyzer.d.ts +17 -0
  61. package/dist/runtime/prompt-safety-analyzer.js +230 -0
  62. package/dist/runtime/prompt-safety-analyzer.js.map +1 -0
  63. package/dist/runtime/rollback-manager.d.ts +50 -0
  64. package/dist/runtime/rollback-manager.js +157 -0
  65. package/dist/runtime/rollback-manager.js.map +1 -0
  66. package/dist/runtime/rule-canary-deployer.d.ts +69 -0
  67. package/dist/runtime/rule-canary-deployer.js +289 -0
  68. package/dist/runtime/rule-canary-deployer.js.map +1 -0
  69. package/dist/runtime/rule-conflict-detector.d.ts +48 -0
  70. package/dist/runtime/rule-conflict-detector.js +214 -0
  71. package/dist/runtime/rule-conflict-detector.js.map +1 -0
  72. package/dist/runtime/rule-meta-verifier.d.ts +18 -0
  73. package/dist/runtime/rule-meta-verifier.js +275 -0
  74. package/dist/runtime/rule-meta-verifier.js.map +1 -0
  75. package/dist/runtime/rule-proposal-manager.d.ts +95 -0
  76. package/dist/runtime/rule-proposal-manager.js +190 -0
  77. package/dist/runtime/rule-proposal-manager.js.map +1 -0
  78. package/dist/runtime/safety-enforcer.d.ts +35 -0
  79. package/dist/runtime/safety-enforcer.js +165 -0
  80. package/dist/runtime/safety-enforcer.js.map +1 -0
  81. package/dist/runtime/safety-status.d.ts +48 -0
  82. package/dist/runtime/safety-status.js +119 -0
  83. package/dist/runtime/safety-status.js.map +1 -0
  84. package/dist/runtime/shared-memory.d.ts +47 -0
  85. package/dist/runtime/shared-memory.js +151 -0
  86. package/dist/runtime/shared-memory.js.map +1 -0
  87. package/dist/runtime/specialized-agent.d.ts +5 -0
  88. package/dist/runtime/specialized-agent.js +37 -0
  89. package/dist/runtime/specialized-agent.js.map +1 -1
  90. package/dist/runtime/stall-detector.d.ts +13 -0
  91. package/dist/runtime/stall-detector.js +121 -0
  92. package/dist/runtime/stall-detector.js.map +1 -0
  93. package/dist/runtime/tool-approval.d.ts +51 -0
  94. package/dist/runtime/tool-approval.js +148 -0
  95. package/dist/runtime/tool-approval.js.map +1 -0
  96. package/dist/runtime/tool-sandbox.d.ts +43 -0
  97. package/dist/runtime/tool-sandbox.js +394 -0
  98. package/dist/runtime/tool-sandbox.js.map +1 -0
  99. package/dist/runtime/tool-verifier.d.ts +18 -0
  100. package/dist/runtime/tool-verifier.js +323 -0
  101. package/dist/runtime/tool-verifier.js.map +1 -0
  102. package/dist/runtime/trust-manager.d.ts +33 -3
  103. package/dist/runtime/trust-manager.js +128 -26
  104. package/dist/runtime/trust-manager.js.map +1 -1
  105. package/dist/runtime/types.d.ts +652 -0
  106. package/dist/runtime/verification-intensity.d.ts +34 -0
  107. package/dist/runtime/verification-intensity.js +104 -0
  108. package/dist/runtime/verification-intensity.js.map +1 -0
  109. package/package.json +1 -1
@@ -0,0 +1,230 @@
1
+ // ============================================================
2
+ // Assay Verified Agent Runtime — Prompt Safety Analyzer
3
+ // Scans agent system prompts for dangerous patterns:
4
+ // - Verification bypass instructions
5
+ // - Privilege escalation attempts
6
+ // - Self-referential instructions
7
+ // - Unbounded action permissions
8
+ // - Missing safety constraints
9
+ // ============================================================
10
+ import { getClient, MODEL } from '../lib/anthropic.js';
11
+ const PROMPT_PATTERNS = [
12
+ // Verification bypass patterns
13
+ {
14
+ name: 'Skip verification instruction',
15
+ type: 'verification_bypass',
16
+ severity: 'critical',
17
+ patterns: [
18
+ /skip\s+(?:the\s+)?verification/i,
19
+ /bypass\s+(?:the\s+)?verif/i,
20
+ /ignore\s+(?:the\s+)?verif/i,
21
+ /don'?t\s+(?:need\s+to\s+)?verif/i,
22
+ /no\s+(?:need\s+for\s+)?verification/i,
23
+ /verification\s+is\s+(?:not\s+)?(?:needed|required|necessary)/i,
24
+ /auto[- ]?approve/i,
25
+ /always\s+pass/i,
26
+ /mark\s+(?:as\s+)?(?:pass|verified|approved)/i,
27
+ ],
28
+ description: 'Prompt contains instructions to bypass or skip verification',
29
+ },
30
+ {
31
+ name: 'Override formal verifier',
32
+ type: 'verification_bypass',
33
+ severity: 'critical',
34
+ patterns: [
35
+ /override\s+(?:the\s+)?formal/i,
36
+ /ignore\s+(?:the\s+)?formal/i,
37
+ /formal\s+verif\w+\s+(?:is\s+)?(?:wrong|incorrect|outdated)/i,
38
+ /you\s+know\s+better\s+than\s+(?:the\s+)?verif/i,
39
+ ],
40
+ description: 'Prompt attempts to override the formal verification layer',
41
+ },
42
+ // Privilege escalation patterns
43
+ {
44
+ name: 'Trust level manipulation',
45
+ type: 'privilege_escalation',
46
+ severity: 'critical',
47
+ patterns: [
48
+ /(?:increase|raise|elevate|promote)\s+(?:your\s+)?(?:own\s+)?trust/i,
49
+ /(?:set|change)\s+(?:your\s+)?trust\s+(?:level\s+)?(?:to\s+)?(?:elevated|coordinator|admin)/i,
50
+ /you\s+(?:have|are)\s+(?:elevated|coordinator|admin)\s+(?:trust|access|permissions)/i,
51
+ /grant\s+(?:yourself|you)\s+(?:elevated|higher|admin)/i,
52
+ ],
53
+ description: 'Prompt attempts to escalate the agent\'s trust level',
54
+ },
55
+ {
56
+ name: 'Approval framework bypass',
57
+ type: 'privilege_escalation',
58
+ severity: 'critical',
59
+ patterns: [
60
+ /(?:skip|bypass|ignore)\s+(?:the\s+)?(?:human\s+)?approval/i,
61
+ /(?:don'?t|no)\s+(?:need\s+)?(?:human\s+)?approval/i,
62
+ /auto[- ]?approve\s+(?:your\s+own|all)/i,
63
+ /approve\s+(?:your\s+)?own\s+(?:work|output|code)/i,
64
+ ],
65
+ description: 'Prompt attempts to bypass human approval requirements',
66
+ },
67
+ {
68
+ name: 'Spawn higher-trust agent',
69
+ type: 'privilege_escalation',
70
+ severity: 'critical',
71
+ patterns: [
72
+ /spawn\s+(?:a\s+)?(?:coordinator|elevated|high[- ]trust)/i,
73
+ /create\s+(?:a\s+)?(?:coordinator|elevated|high[- ]trust)\s+agent/i,
74
+ ],
75
+ description: 'Prompt instructs spawning an agent with higher trust than itself',
76
+ },
77
+ // Self-reference patterns
78
+ {
79
+ name: 'Access to own internals',
80
+ type: 'self_reference',
81
+ severity: 'medium',
82
+ patterns: [
83
+ /(?:read|access|modify)\s+(?:your\s+)?(?:own\s+)?(?:source|code|prompt|config)/i,
84
+ /(?:look\s+at|examine|inspect)\s+(?:your\s+)?(?:own\s+)?(?:system\s+)?prompt/i,
85
+ /(?:modify|change|update)\s+(?:your\s+)?(?:own\s+)?(?:behavior|instructions)/i,
86
+ ],
87
+ description: 'Prompt references agent\'s own internals or instructs self-modification',
88
+ },
89
+ // Unbounded action patterns
90
+ {
91
+ name: 'Unrestricted filesystem access',
92
+ type: 'unbounded_action',
93
+ severity: 'high',
94
+ patterns: [
95
+ /(?:read|write|delete)\s+(?:any|all)\s+files?/i,
96
+ /full\s+(?:filesystem|disk)\s+access/i,
97
+ /no\s+(?:filesystem|file)\s+restrictions/i,
98
+ ],
99
+ description: 'Prompt grants unrestricted filesystem access',
100
+ },
101
+ {
102
+ name: 'Unrestricted network access',
103
+ type: 'unbounded_action',
104
+ severity: 'high',
105
+ patterns: [
106
+ /(?:call|access|connect\s+to)\s+any\s+(?:URL|API|endpoint|server)/i,
107
+ /no\s+(?:network|URL)\s+restrictions/i,
108
+ /unrestricted\s+(?:network|API)\s+access/i,
109
+ ],
110
+ description: 'Prompt grants unrestricted network access',
111
+ },
112
+ ];
113
+ // Required safety constraints that should appear in any agent prompt
114
+ const REQUIRED_CONSTRAINTS = [
115
+ {
116
+ name: 'Verification acknowledgment',
117
+ pattern: /verif(?:y|ied|ication)/i,
118
+ description: 'Prompt should acknowledge that outputs will be verified',
119
+ },
120
+ {
121
+ name: 'Scope limitation',
122
+ pattern: /(?:scope|domain|limited\s+to|restricted\s+to|only\s+handle)/i,
123
+ description: 'Prompt should define the agent\'s scope or domain limitations',
124
+ },
125
+ {
126
+ name: 'Error handling',
127
+ pattern: /(?:error|fail|exception|unknown|uncertain)/i,
128
+ description: 'Prompt should mention error handling or uncertainty behavior',
129
+ },
130
+ ];
131
+ // ── Prompt Safety Analyzer ─────────────────────────────────
132
+ export class PromptSafetyAnalyzer {
133
+ /**
134
+ * Analyze an agent system prompt for safety issues.
135
+ * Uses both deterministic pattern matching (formal) and
136
+ * optional LLM-based semantic analysis.
137
+ */
138
+ async analyze(systemPrompt, opts) {
139
+ const findings = [];
140
+ // Phase 1: Deterministic pattern matching
141
+ for (const pattern of PROMPT_PATTERNS) {
142
+ for (const regex of pattern.patterns) {
143
+ const match = systemPrompt.match(regex);
144
+ if (match) {
145
+ // Find approximate line number
146
+ const beforeMatch = systemPrompt.slice(0, match.index ?? 0);
147
+ const lineNum = (beforeMatch.match(/\n/g) ?? []).length + 1;
148
+ findings.push({
149
+ type: pattern.type,
150
+ severity: pattern.severity,
151
+ location: `system_prompt:line_${lineNum}`,
152
+ description: `${pattern.name}: matched "${match[0]}"`,
153
+ });
154
+ break; // One match per pattern is enough
155
+ }
156
+ }
157
+ }
158
+ // Phase 2: Check for missing required constraints
159
+ for (const constraint of REQUIRED_CONSTRAINTS) {
160
+ if (!constraint.pattern.test(systemPrompt)) {
161
+ findings.push({
162
+ type: 'missing_constraint',
163
+ severity: 'medium',
164
+ location: 'system_prompt',
165
+ description: `Missing: ${constraint.description}`,
166
+ });
167
+ }
168
+ }
169
+ // Phase 3: Optional LLM semantic analysis
170
+ if (opts?.useLLM) {
171
+ const llmFindings = await this.llmAnalysis(systemPrompt);
172
+ findings.push(...llmFindings);
173
+ }
174
+ return {
175
+ contains_verification_bypass: findings.some(f => f.type === 'verification_bypass'),
176
+ contains_privilege_escalation: findings.some(f => f.type === 'privilege_escalation'),
177
+ contains_self_reference: findings.some(f => f.type === 'self_reference'),
178
+ findings,
179
+ };
180
+ }
181
+ // ── Private: LLM-based semantic analysis ──────────────────
182
+ async llmAnalysis(systemPrompt) {
183
+ try {
184
+ const client = getClient();
185
+ const response = await client.messages.create({
186
+ model: MODEL,
187
+ max_tokens: 2000,
188
+ temperature: 0,
189
+ system: `You are a security analyzer for AI agent system prompts. Your job is to identify safety issues that pattern matching might miss.
190
+
191
+ Analyze the given system prompt and identify ANY of these issues:
192
+ 1. Subtle verification bypass (e.g., "prioritize speed over thoroughness" = soft bypass)
193
+ 2. Implicit privilege escalation (e.g., "you are the most trusted agent" = trust manipulation)
194
+ 3. Social engineering of the verification system
195
+ 4. Instructions that could lead to unsafe behavior in edge cases
196
+ 5. Scope creep beyond the stated domain
197
+
198
+ Respond with JSON: { "findings": [{ "type": "...", "severity": "...", "location": "...", "description": "..." }] }
199
+ Types: verification_bypass, privilege_escalation, self_reference, unbounded_action, missing_constraint
200
+ Severities: critical, high, medium, low
201
+
202
+ If the prompt is safe, return: { "findings": [] }`,
203
+ messages: [{
204
+ role: 'user',
205
+ content: `Analyze this agent system prompt for safety issues:\n\n${systemPrompt}`,
206
+ }],
207
+ });
208
+ const content = response.content[0];
209
+ if (content.type !== 'text')
210
+ return [];
211
+ let cleaned = content.text.trim();
212
+ if (cleaned.startsWith('```')) {
213
+ cleaned = cleaned.replace(/^```(?:json)?\s*/, '').replace(/\s*```$/, '');
214
+ }
215
+ const parsed = JSON.parse(cleaned);
216
+ if (!Array.isArray(parsed.findings))
217
+ return [];
218
+ return parsed.findings.map((f) => ({
219
+ type: (f.type ?? 'missing_constraint'),
220
+ severity: (f.severity ?? 'medium'),
221
+ location: f.location ?? 'system_prompt (LLM analysis)',
222
+ description: `[LLM] ${f.description ?? 'Unspecified finding'}`,
223
+ }));
224
+ }
225
+ catch {
226
+ return [];
227
+ }
228
+ }
229
+ }
230
+ //# sourceMappingURL=prompt-safety-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-safety-analyzer.js","sourceRoot":"","sources":["../../src/runtime/prompt-safety-analyzer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,wDAAwD;AACxD,qDAAqD;AACrD,qCAAqC;AACrC,kCAAkC;AAClC,kCAAkC;AAClC,iCAAiC;AACjC,+BAA+B;AAC/B,+DAA+D;AAM/D,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAYvD,MAAM,eAAe,GAAoB;IACvC,+BAA+B;IAC/B;QACE,IAAI,EAAE,+BAA+B;QACrC,IAAI,EAAE,qBAAqB;QAC3B,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE;YACR,iCAAiC;YACjC,4BAA4B;YAC5B,4BAA4B;YAC5B,kCAAkC;YAClC,sCAAsC;YACtC,+DAA+D;YAC/D,mBAAmB;YACnB,gBAAgB;YAChB,8CAA8C;SAC/C;QACD,WAAW,EAAE,6DAA6D;KAC3E;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE,qBAAqB;QAC3B,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE;YACR,+BAA+B;YAC/B,6BAA6B;YAC7B,6DAA6D;YAC7D,gDAAgD;SACjD;QACD,WAAW,EAAE,2DAA2D;KACzE;IACD,gCAAgC;IAChC;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE;YACR,oEAAoE;YACpE,6FAA6F;YAC7F,qFAAqF;YACrF,uDAAuD;SACxD;QACD,WAAW,EAAE,sDAAsD;KACpE;IACD;QACE,IAAI,EAAE,2BAA2B;QACjC,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE;YACR,4DAA4D;YAC5D,oDAAoD;YACpD,wCAAwC;YACxC,mDAAmD;SACpD;QACD,WAAW,EAAE,uDAAuD;KACrE;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE;YACR,0DAA0D;YAC1D,mEAAmE;SACpE;QACD,WAAW,EAAE,kEAAkE;KAChF;IACD,0BAA0B;IAC1B;QACE,IAAI,EAAE,yBAAyB;QAC/B,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE;YACR,gFAAgF;YAChF,8EAA8E;YAC9E,8EAA8E;SAC/E;QACD,WAAW,EAAE,yEAAyE;KACvF;IACD,4BAA4B;IAC5B;QACE,IAAI,EAAE,gCAAgC;QACtC,IAAI,EAAE,kBAAkB;QACxB,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE;YACR,+CAA+C;YAC/C,sCAAsC;YACtC,0CAA0C;SAC3C;QACD,WAAW,EAAE,8CAA8C;KAC5D;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,IAAI,EAAE,kBAAkB;QACxB,QAAQ,EAAE,MAAM;QAChB,QAAQ,EAAE;YACR,mEAAmE;YACnE,sCAAsC;YACtC,0CAA0C;SAC3C;QACD,WAAW,EAAE,2CAA2C;KACzD;CACF,CAAC;AAEF,qEAAqE;AACrE,MAAM,oBAAoB,GAAG;IAC3B;QACE,IAAI,EAAE,6BAA6B;QACnC,OAAO,EAAE,yBAAyB;QAClC,WAAW,EAAE,yDAAyD;KACvE;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,8DAA8D;QACvE,WAAW,EAAE,+DAA+D;KAC7E;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,6CAA6C;QACtD,WAAW,EAAE,8DAA8D;KAC5E;CACF,CAAC;AAEF,8DAA8D;AAE9D,MAAM,OAAO,oBAAoB;IAC/B;;;;OAIG;IACH,KAAK,CAAC,OAAO,CACX,YAAoB,EACpB,IAA2B;QAO3B,MAAM,QAAQ,GAA0B,EAAE,CAAC;QAE3C,0CAA0C;QAC1C,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACtC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACxC,IAAI,KAAK,EAAE,CAAC;oBACV,+BAA+B;oBAC/B,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;oBAC5D,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;oBAE5D,QAAQ,CAAC,IAAI,CAAC;wBACZ,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;wBAC1B,QAAQ,EAAE,sBAAsB,OAAO,EAAE;wBACzC,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,cAAc,KAAK,CAAC,CAAC,CAAC,GAAG;qBACtD,CAAC,CAAC;oBACH,MAAM,CAAC,kCAAkC;gBAC3C,CAAC;YACH,CAAC;QACH,CAAC;QAED,kDAAkD;QAClD,KAAK,MAAM,UAAU,IAAI,oBAAoB,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,oBAAoB;oBAC1B,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,eAAe;oBACzB,WAAW,EAAE,YAAY,UAAU,CAAC,WAAW,EAAE;iBAClD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;YACjB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;YACzD,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;QAChC,CAAC;QAED,OAAO;YACL,4BAA4B,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,CAAC;YAClF,6BAA6B,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,sBAAsB,CAAC;YACpF,uBAAuB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC;YACxE,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,6DAA6D;IAErD,KAAK,CAAC,WAAW,CAAC,YAAoB;QAC5C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAE3B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5C,KAAK,EAAE,KAAK;gBACZ,UAAU,EAAE,IAAI;gBAChB,WAAW,EAAE,CAAC;gBACd,MAAM,EAAE;;;;;;;;;;;;;kDAakC;gBAC1C,QAAQ,EAAE,CAAC;wBACT,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,0DAA0D,YAAY,EAAE;qBAClF,CAAC;aACH,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,EAAE,CAAC;YAEvC,IAAI,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAC3E,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAO,EAAE,CAAC;YAE/C,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAyB,EAAE,EAAE,CAAC,CAAC;gBACzD,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,oBAAoB,CAA4B;gBACjE,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAoC;gBACrE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,8BAA8B;gBACtD,WAAW,EAAE,SAAS,CAAC,CAAC,WAAW,IAAI,qBAAqB,EAAE;aAC/D,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,50 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { CapabilityRegistryManager } from './capability-registry.js';
3
+ import { KillSwitch } from './kill-switch.js';
4
+ import type { RollbackTrigger, RollbackEvent } from './types.js';
5
+ export interface ErrorRateConfig {
6
+ readonly windowMs: number;
7
+ readonly threshold: number;
8
+ readonly minSamples: number;
9
+ }
10
+ export declare class RollbackManager extends EventEmitter {
11
+ private registry;
12
+ private killSwitch;
13
+ private logPath;
14
+ private errorConfig;
15
+ private errorWindows;
16
+ private rollbackHistory;
17
+ constructor(registry: CapabilityRegistryManager, killSwitch: KillSwitch, opts?: {
18
+ logPath?: string;
19
+ errorConfig?: Partial<ErrorRateConfig>;
20
+ });
21
+ /**
22
+ * Record an operation result for error rate tracking.
23
+ * If the error rate exceeds the threshold, automatically triggers rollback.
24
+ */
25
+ recordOperation(targetId: string, targetType: 'tool' | 'agent' | 'rule', success: boolean): Promise<{
26
+ triggered: boolean;
27
+ rollback?: RollbackEvent;
28
+ }>;
29
+ /**
30
+ * Manually trigger a rollback.
31
+ */
32
+ triggerRollback(trigger: RollbackTrigger, triggeredBy: string, targetType: 'tool' | 'agent' | 'rule' | 'registry', targetId: string, reason: string): Promise<RollbackEvent>;
33
+ /**
34
+ * Handle a Layer 2 integrity violation.
35
+ * This is the most severe rollback trigger — halts the entire system.
36
+ */
37
+ handleIntegrityViolation(component: string, expectedHash: string, actualHash: string): Promise<RollbackEvent>;
38
+ /**
39
+ * Get the rollback history.
40
+ */
41
+ getHistory(): readonly RollbackEvent[];
42
+ /**
43
+ * Get the current error rate for a target.
44
+ */
45
+ getErrorRate(targetId: string): {
46
+ rate: number;
47
+ samples: number;
48
+ } | null;
49
+ private logEvent;
50
+ }
@@ -0,0 +1,157 @@
1
+ // ============================================================
2
+ // Assay Verified Agent Runtime — Rollback Manager
3
+ // Reverts modifications to the last known-good state.
4
+ //
5
+ // Triggers:
6
+ // - Automatic: error rate exceeds threshold
7
+ // - Human: manual operator request
8
+ // - Layer 2: integrity violation detected
9
+ // - Coordinator: downstream agent reports degradation
10
+ //
11
+ // Procedure:
12
+ // 1. Suspend the new capability
13
+ // 2. Revert CapabilityRegistry to previous version
14
+ // 3. Run verification suite on restored configuration
15
+ // 4. Log the rollback event
16
+ // 5. Notify human operator
17
+ // ============================================================
18
+ import { randomUUID } from 'node:crypto';
19
+ import { appendFile, mkdir } from 'node:fs/promises';
20
+ import { dirname } from 'node:path';
21
+ import { EventEmitter } from 'node:events';
22
+ const DEFAULT_ERROR_CONFIG = {
23
+ windowMs: 5 * 60 * 1000, // 5 minutes
24
+ threshold: 0.10, // 10% error rate
25
+ minSamples: 10, // At least 10 operations
26
+ };
27
+ // ── Rollback Manager ───────────────────────────────────
28
+ export class RollbackManager extends EventEmitter {
29
+ registry;
30
+ killSwitch;
31
+ logPath;
32
+ errorConfig;
33
+ // Error tracking per target
34
+ errorWindows = new Map();
35
+ // Rollback history
36
+ rollbackHistory = [];
37
+ constructor(registry, killSwitch, opts) {
38
+ super();
39
+ this.registry = registry;
40
+ this.killSwitch = killSwitch;
41
+ this.logPath = opts?.logPath ?? '.assay/rollback-history.ndjson';
42
+ this.errorConfig = { ...DEFAULT_ERROR_CONFIG, ...(opts?.errorConfig ?? {}) };
43
+ }
44
+ /**
45
+ * Record an operation result for error rate tracking.
46
+ * If the error rate exceeds the threshold, automatically triggers rollback.
47
+ */
48
+ async recordOperation(targetId, targetType, success) {
49
+ // Add to error window
50
+ const window = this.errorWindows.get(targetId) ?? [];
51
+ window.push({ timestamp: Date.now(), success });
52
+ this.errorWindows.set(targetId, window);
53
+ // Prune old entries outside the window
54
+ const cutoff = Date.now() - this.errorConfig.windowMs;
55
+ const pruned = window.filter(e => e.timestamp >= cutoff);
56
+ this.errorWindows.set(targetId, pruned);
57
+ // Check error rate
58
+ if (pruned.length >= this.errorConfig.minSamples) {
59
+ const errors = pruned.filter(e => !e.success).length;
60
+ const errorRate = errors / pruned.length;
61
+ if (errorRate > this.errorConfig.threshold) {
62
+ const rollback = await this.triggerRollback('automatic', 'system', targetType, targetId, `Error rate ${(errorRate * 100).toFixed(1)}% exceeds threshold ${(this.errorConfig.threshold * 100).toFixed(1)}% (${errors}/${pruned.length} in last ${this.errorConfig.windowMs / 1000}s)`);
63
+ return { triggered: true, rollback };
64
+ }
65
+ }
66
+ return { triggered: false };
67
+ }
68
+ /**
69
+ * Manually trigger a rollback.
70
+ */
71
+ async triggerRollback(trigger, triggeredBy, targetType, targetId, reason) {
72
+ // Step 1: Suspend the target via kill switch
73
+ if (targetType === 'tool') {
74
+ await this.killSwitch.activate(trigger === 'layer2' ? 'layer2' : trigger === 'human' ? 'human' : 'coordinator', 'suspend_tool', targetId, triggeredBy, `Rollback: ${reason}`);
75
+ }
76
+ else if (targetType === 'agent') {
77
+ await this.killSwitch.activate(trigger === 'layer2' ? 'layer2' : trigger === 'human' ? 'human' : 'coordinator', 'suspend_agent', targetId, triggeredBy, `Rollback: ${reason}`);
78
+ }
79
+ else if (targetType === 'rule') {
80
+ await this.killSwitch.activate(trigger === 'layer2' ? 'layer2' : trigger === 'human' ? 'human' : 'coordinator', 'suspend_rule', targetId, triggeredBy, `Rollback: ${reason}`);
81
+ }
82
+ // Step 2: Get current registry version (before rollback)
83
+ const currentRegistry = this.registry.getRegistry();
84
+ const fromVersion = currentRegistry.version;
85
+ // Step 3: Rollback the registry
86
+ const success = this.registry.rollback(triggeredBy);
87
+ const toVersion = success ? this.registry.getRegistry().version : fromVersion;
88
+ // Step 4: Save the rolled-back registry
89
+ if (success) {
90
+ await this.registry.save();
91
+ }
92
+ // Step 5: Create rollback event
93
+ const event = {
94
+ id: `rb_${Date.now()}_${randomUUID().slice(0, 8)}`,
95
+ trigger,
96
+ triggered_by: triggeredBy,
97
+ target_type: targetType,
98
+ target_id: targetId,
99
+ from_version: fromVersion,
100
+ to_version: toVersion,
101
+ timestamp: new Date().toISOString(),
102
+ verification_after_rollback: success ? 'pending' : 'fail',
103
+ reason,
104
+ };
105
+ this.rollbackHistory.push(event);
106
+ // Step 6: Emit event and log
107
+ this.emit('rollback', event);
108
+ await this.logEvent(event);
109
+ // Step 7: Clear error window for the target
110
+ this.errorWindows.delete(targetId);
111
+ return event;
112
+ }
113
+ /**
114
+ * Handle a Layer 2 integrity violation.
115
+ * This is the most severe rollback trigger — halts the entire system.
116
+ */
117
+ async handleIntegrityViolation(component, expectedHash, actualHash) {
118
+ // First: halt the system
119
+ await this.killSwitch.activate('layer2', 'halt_system', 'system', 'layer2-guardian', `Layer 2 integrity violation: ${component} hash mismatch (expected: ${expectedHash.slice(0, 12)}..., actual: ${actualHash.slice(0, 12)}...)`);
120
+ // Then: record the rollback event
121
+ return this.triggerRollback('layer2', 'layer2-guardian', 'registry', 'system', `CRITICAL: Layer 2 component "${component}" has been modified. System halted. Requires redeployment of verified Layer 2 artifacts.`);
122
+ }
123
+ /**
124
+ * Get the rollback history.
125
+ */
126
+ getHistory() {
127
+ return this.rollbackHistory;
128
+ }
129
+ /**
130
+ * Get the current error rate for a target.
131
+ */
132
+ getErrorRate(targetId) {
133
+ const window = this.errorWindows.get(targetId);
134
+ if (!window || window.length === 0)
135
+ return null;
136
+ const cutoff = Date.now() - this.errorConfig.windowMs;
137
+ const current = window.filter(e => e.timestamp >= cutoff);
138
+ if (current.length === 0)
139
+ return null;
140
+ const errors = current.filter(e => !e.success).length;
141
+ return {
142
+ rate: errors / current.length,
143
+ samples: current.length,
144
+ };
145
+ }
146
+ // ── Private ──────────────────────────────────────────
147
+ async logEvent(event) {
148
+ try {
149
+ await mkdir(dirname(this.logPath), { recursive: true });
150
+ await appendFile(this.logPath, JSON.stringify(event) + '\n', 'utf-8');
151
+ }
152
+ catch {
153
+ // Rollback logging failure must not prevent rollback from working
154
+ }
155
+ }
156
+ }
157
+ //# sourceMappingURL=rollback-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback-manager.js","sourceRoot":"","sources":["../../src/runtime/rollback-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import type { VerificationRule, CanaryStage, CanaryDeployment, CanaryExitCriteria } from './types.js';
2
+ export interface CanaryEvaluation {
3
+ readonly rule_id: string;
4
+ readonly timestamp: string;
5
+ readonly baseline_verdict: 'PASS' | 'FAIL';
6
+ readonly canary_verdict: 'PASS' | 'FAIL';
7
+ readonly agreed: boolean;
8
+ readonly latency_ms: number;
9
+ readonly error?: string;
10
+ }
11
+ export declare class RuleCanaryDeployer {
12
+ private deployments;
13
+ private evaluations;
14
+ private statePath;
15
+ constructor(statePath?: string);
16
+ /**
17
+ * Start canary deployment for a rule.
18
+ * Formal rules skip shadow mode (they are deterministic).
19
+ */
20
+ startDeployment(rule: VerificationRule, customExitCriteria?: Partial<Record<CanaryStage, Partial<CanaryExitCriteria>>>): CanaryDeployment;
21
+ /**
22
+ * Record a canary evaluation (comparison of new rule against baseline).
23
+ */
24
+ recordEvaluation(evaluation: CanaryEvaluation): void;
25
+ /**
26
+ * Check if a rule is ready to promote to the next canary stage.
27
+ * Returns the next stage if ready, null if not ready, 'rollback' if metrics are bad.
28
+ */
29
+ checkPromotion(ruleId: string): {
30
+ action: 'promote' | 'wait' | 'rollback';
31
+ nextStage?: CanaryStage;
32
+ reason: string;
33
+ };
34
+ /**
35
+ * Promote a rule to the next canary stage.
36
+ */
37
+ promote(ruleId: string): CanaryDeployment | null;
38
+ /**
39
+ * Rollback a rule's canary deployment. Removes it from all stages.
40
+ */
41
+ rollback(ruleId: string): {
42
+ success: boolean;
43
+ reason: string;
44
+ };
45
+ /**
46
+ * Get the current deployment state for a rule.
47
+ */
48
+ getDeployment(ruleId: string): CanaryDeployment | undefined;
49
+ /**
50
+ * List all active canary deployments.
51
+ */
52
+ listDeployments(): CanaryDeployment[];
53
+ /**
54
+ * Check if a rule should be evaluated for a given request.
55
+ * Based on the canary stage traffic percentage.
56
+ */
57
+ shouldEvaluate(ruleId: string): boolean;
58
+ /**
59
+ * Save deployment state to disk.
60
+ */
61
+ saveState(): Promise<void>;
62
+ /**
63
+ * Load deployment state from disk.
64
+ */
65
+ loadState(): Promise<void>;
66
+ private computeMetrics;
67
+ private computeDurationHours;
68
+ private emptyMetrics;
69
+ }