@aria_asi/cli 0.2.31 → 0.2.33
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.
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +30 -3
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts +8 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.js +126 -71
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +76 -9
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/connectors/must-read.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/must-read.js +4 -0
- package/dist/aria-connector/src/connectors/must-read.js.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +25 -9
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/setup-wizard.d.ts.map +1 -1
- package/dist/aria-connector/src/setup-wizard.js +91 -24
- package/dist/aria-connector/src/setup-wizard.js.map +1 -1
- package/dist/assets/hooks/aria-agent-handoff.mjs +23 -0
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +69 -3
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +10 -5
- package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +35 -0
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +217 -17
- package/dist/assets/hooks/aria-preprompt-consult.mjs +28 -2
- package/dist/assets/hooks/aria-preturn-memory-gate.mjs +30 -2
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +31 -1
- package/dist/assets/hooks/aria-stop-gate.mjs +154 -37
- package/dist/assets/hooks/doctrine_trigger_map.json +55 -0
- package/dist/assets/hooks/lib/domain-output-quality.mjs +103 -0
- package/dist/assets/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +84 -7
- package/dist/assets/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +39 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +101 -7
- package/dist/assets/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/dist/assets/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -0
- package/dist/runtime/codex-bridge.mjs +71 -8
- package/dist/runtime/discipline/CLAUDE.md +16 -0
- package/dist/runtime/discipline/doctrine_trigger_map.json +55 -0
- package/dist/runtime/doctrine_trigger_map.json +55 -0
- package/dist/runtime/harness-daemon.mjs +80 -5
- package/dist/runtime/manifest.json +1 -1
- package/dist/runtime/sdk/BUNDLED.json +1 -1
- package/dist/runtime/sdk/index.d.ts +14 -0
- package/dist/runtime/sdk/index.js +23 -1
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +385 -11
- package/dist/sdk/BUNDLED.json +1 -1
- package/dist/sdk/index.d.ts +14 -0
- package/dist/sdk/index.js +23 -1
- package/dist/sdk/index.js.map +1 -1
- package/hooks/aria-agent-handoff.mjs +23 -0
- package/hooks/aria-cognition-substrate-binding.mjs +69 -3
- package/hooks/aria-harness-via-sdk.mjs +10 -5
- package/hooks/aria-pre-emit-dryrun.mjs +35 -0
- package/hooks/aria-pre-tool-gate.mjs +217 -17
- package/hooks/aria-preprompt-consult.mjs +28 -2
- package/hooks/aria-preturn-memory-gate.mjs +30 -2
- package/hooks/aria-repo-doctrine-gate.mjs +31 -1
- package/hooks/aria-stop-gate.mjs +154 -37
- package/hooks/doctrine_trigger_map.json +55 -0
- package/hooks/lib/domain-output-quality.mjs +103 -0
- package/hooks/lib/skill-autoload-gate.mjs +1 -0
- package/opencode-plugins/harness-gate/index.js +84 -7
- package/opencode-plugins/harness-gate/lib/skill-autoload-gate.js +1 -0
- package/opencode-plugins/harness-outcome/index.js +39 -0
- package/opencode-plugins/harness-stop/index.js +101 -7
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +103 -0
- package/opencode-plugins/harness-stop/lib/skill-autoload-gate.js +1 -0
- package/package.json +1 -1
- package/runtime-src/codex-bridge.mjs +71 -8
- package/runtime-src/harness-daemon.mjs +80 -5
- package/runtime-src/service.mjs +385 -11
- package/src/connectors/claude-code.ts +31 -3
- package/src/connectors/codebase-awareness.ts +141 -77
- package/src/connectors/codex.ts +76 -9
- package/src/connectors/must-read.ts +4 -0
- package/src/connectors/opencode.ts +25 -9
- package/src/setup-wizard.ts +105 -25
|
@@ -72,12 +72,60 @@ const LENS_NAMES = ALL_LENS_NAMES;
|
|
|
72
72
|
const ANCHOR_RX = /\b(axiom|frame|memory|doctrine|packet|language):[a-z0-9_\-./]+/gi;
|
|
73
73
|
|
|
74
74
|
const COGNITION_BLOCK_RX = /<cognition>([\s\S]*?)<\/cognition>/i;
|
|
75
|
+
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
75
76
|
const FIRST_PRINCIPLE_RX = /\b(first[_\s-]?principle[s]?|first_principle=)\b/i;
|
|
76
77
|
const HARNESS_PACKET_PATH = `${HOME}/.claude/.aria-harness-last-packet.json`;
|
|
77
78
|
const MEMORY_DIR = `${HOME}/.claude/projects/-home-hamzaibrahim1/memory`;
|
|
78
79
|
const RECENT_VIOLATIONS_PATH = `${HOME}/.claude/.aria-recent-violations.jsonl`;
|
|
79
80
|
const THRASHING_STATE_PATH = `${HOME}/.claude/.aria-thrashing-state.json`;
|
|
80
81
|
const CLEAR_VIOLATIONS_SCRIPT = `${HOME}/.claude/aria-clear-violations.sh`;
|
|
82
|
+
|
|
83
|
+
function buildForceReauthorReason({ source, reason, violations = [] }) {
|
|
84
|
+
return [
|
|
85
|
+
'=== ARIA FORCE_REAUTHOR ===',
|
|
86
|
+
`source: ${source}`,
|
|
87
|
+
`reason: ${reason}`,
|
|
88
|
+
'',
|
|
89
|
+
'This is not a terminal error. It is a forced redo instruction for cognition substrate binding.',
|
|
90
|
+
'Do not emit the blocked text. Re-author the cognition so every lens is tied to loaded substrate.',
|
|
91
|
+
'',
|
|
92
|
+
'TEACHING:',
|
|
93
|
+
'- Cognition without live anchors is theater; anchors are the proof of thought.',
|
|
94
|
+
'- A valid redo cites only substrate that is actually loaded this turn.',
|
|
95
|
+
'- The cognition block must reference first_principle and must not cite inactive language state.',
|
|
96
|
+
violations.length ? `\nVIOLATIONS TO FIX:\n${violations.map((v) => `- ${v}`).join('\n')}` : '',
|
|
97
|
+
'',
|
|
98
|
+
'REQUIRED REDO SHAPE:',
|
|
99
|
+
'1. Re-emit <cognition> with all required lenses.',
|
|
100
|
+
'2. Each lens cites >=1 loaded anchor: axiom:, frame:, memory:, doctrine:, packet:, or active language:.',
|
|
101
|
+
'3. Include first_principle explicitly.',
|
|
102
|
+
'4. Add <applied_cognition> with decision_delta, dominant_domain, binds_to, expected_predicate, and artifact_change.',
|
|
103
|
+
'5. Remove repeated blocked substrings instead of reusing them.',
|
|
104
|
+
'=== END FORCE_REAUTHOR ===',
|
|
105
|
+
].filter(Boolean).join('\n');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function validateAppliedCognitionContract(text) {
|
|
109
|
+
const match = String(text || '').match(APPLIED_COGNITION_BLOCK_RX);
|
|
110
|
+
if (!match) {
|
|
111
|
+
return { ok: false, violations: ['missing <applied_cognition> contract'] };
|
|
112
|
+
}
|
|
113
|
+
const body = match[1] || '';
|
|
114
|
+
const required = [
|
|
115
|
+
['decision_delta', /\bdecision[_ -]?delta\s*:/i],
|
|
116
|
+
['dominant_domain', /\bdominant[_ -]?domain\s*:/i],
|
|
117
|
+
['binds_to', /\bbinds[_ -]?to\s*:/i],
|
|
118
|
+
['expected_predicate', /\bexpected[_ -]?predicate\s*:/i],
|
|
119
|
+
['artifact_change', /\bartifact[_ -]?change\s*:/i],
|
|
120
|
+
];
|
|
121
|
+
const violations = [];
|
|
122
|
+
for (const [name, rx] of required) {
|
|
123
|
+
if (!rx.test(body)) violations.push(`missing ${name}`);
|
|
124
|
+
}
|
|
125
|
+
const weakDelta = /decision[_ -]?delta\s*:\s*(?:none|n\/a|no change|unchanged|same)/i.test(body);
|
|
126
|
+
if (weakDelta) violations.push('decision_delta says cognition changed nothing');
|
|
127
|
+
return { ok: violations.length === 0, violations };
|
|
128
|
+
}
|
|
81
129
|
const CARRY_FORWARD_WINDOW_MS = 25 * 60 * 1000;
|
|
82
130
|
const CARRY_FORWARD_MAX_ROWS = 200;
|
|
83
131
|
const SYSTEM_REMINDER_RX = /<system-reminder>[\s\S]*?<\/system-reminder>|<task-notification>[\s\S]*?<\/task-notification>|🔐 Aria Harness|task-notification|PreToolUse:[A-Z][A-Za-z]* hook blocking error|Stop hook blocking error/g;
|
|
@@ -422,7 +470,7 @@ Recovery surfaces:
|
|
|
422
470
|
|
|
423
471
|
Per feedback_block_and_force_with_recovery.md, repetition of a recently-blocked phrase is not advisory drift; it is a hard block until the phrase is removed or the carry-forward state is intentionally cleared.`;
|
|
424
472
|
|
|
425
|
-
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
473
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/carry-forward', reason, violations: [`repeated blocked substring: ${carryForwardMatch.substring}`] }) }));
|
|
426
474
|
process.exit(2);
|
|
427
475
|
}
|
|
428
476
|
|
|
@@ -457,11 +505,29 @@ Re-emit with:
|
|
|
457
505
|
|
|
458
506
|
No process-level disable path per Hamza directive 2026-04-27.`;
|
|
459
507
|
audit('block_no_cognition_block', { length: assistantText.length });
|
|
460
|
-
console.log(JSON.stringify({ decision: 'block', reason: noCogReason }));
|
|
508
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/no-cognition-block', reason: noCogReason, violations: ['missing <cognition>...</cognition> block'] }) }));
|
|
461
509
|
process.exit(2);
|
|
462
510
|
}
|
|
463
511
|
|
|
464
512
|
const cognitionInner = cogMatch[1];
|
|
513
|
+
const appliedContract = validateAppliedCognitionContract(assistantText);
|
|
514
|
+
if (!appliedContract.ok) {
|
|
515
|
+
const reason = `Aria substrate-binding gate: cognition was emitted without an applied-cognition execution contract.
|
|
516
|
+
|
|
517
|
+
The harness no longer accepts cognition as prose-only compliance. The response must state what cognition changed and what concrete action/output it binds.
|
|
518
|
+
|
|
519
|
+
Required block:
|
|
520
|
+
<applied_cognition>
|
|
521
|
+
decision_delta: <what changed because cognition ran; not "none">
|
|
522
|
+
dominant_domain: <engineering_quality | trust | product | operations | security | ...>
|
|
523
|
+
binds_to: <next tool/action/output claim this cognition constrains>
|
|
524
|
+
expected_predicate: <numeric, boolean, or state-string predicate proving success>
|
|
525
|
+
artifact_change: <how the produced artifact differs because cognition ran>
|
|
526
|
+
</applied_cognition>`;
|
|
527
|
+
audit('block_applied_cognition_missing', { violations: appliedContract.violations, length: assistantText.length });
|
|
528
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/applied-cognition-contract', reason, violations: appliedContract.violations }) }));
|
|
529
|
+
process.exit(2);
|
|
530
|
+
}
|
|
465
531
|
const lensTexts = extractLensTexts(cognitionInner);
|
|
466
532
|
|
|
467
533
|
// Substance check — replaces char-count with "lens body has substantive
|
|
@@ -691,5 +757,5 @@ Anchor grammar (each anchor must resolve to a real loaded substrate item):
|
|
|
691
757
|
|
|
692
758
|
Re-emit cognition with: every lens citing ≥1 verifiable loaded anchor, the block referencing first_principle, and language: citations only for active language tiers. No process-level disable path; gates are unconditional from the gated process per Hamza directive 2026-04-27.`;
|
|
693
759
|
|
|
694
|
-
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
760
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'substrate-binding/structural-violations', reason, violations: reasonParts }) }));
|
|
695
761
|
process.exit(2);
|
|
@@ -279,6 +279,7 @@ function persistMizanReceipt(sessionId, payload) {
|
|
|
279
279
|
async function runMizanPre(apiKey, packet, sourceLabel) {
|
|
280
280
|
if (!isTurn) return null;
|
|
281
281
|
const sessionId = HOOK_EVENT?.session_id || HOOK_EVENT?.sessionId || 'claude-code';
|
|
282
|
+
const packetHash = createHash('sha256').update(JSON.stringify(packet || {})).digest('hex');
|
|
282
283
|
const response = await fetch(`${DEFAULT_RUNTIME_URL.replace(/\/+$/, '')}/mizan/pre`, {
|
|
283
284
|
method: 'POST',
|
|
284
285
|
headers: {
|
|
@@ -295,6 +296,8 @@ async function runMizanPre(apiKey, packet, sourceLabel) {
|
|
|
295
296
|
rationale: `Claude turn-start harness sync via ${sourceLabel} must mint a canonical Mizan pre receipt for downstream tool and output enforcement.`,
|
|
296
297
|
platform: 'claude-code',
|
|
297
298
|
stage: 'hook-turn-pre',
|
|
299
|
+
packetHash,
|
|
300
|
+
packetSource: sourceLabel,
|
|
298
301
|
},
|
|
299
302
|
}),
|
|
300
303
|
});
|
|
@@ -311,6 +314,8 @@ async function runMizanPre(apiKey, packet, sourceLabel) {
|
|
|
311
314
|
result: payload.result || null,
|
|
312
315
|
contract: payload.contract || null,
|
|
313
316
|
summary: payload.summary || null,
|
|
317
|
+
packetHash,
|
|
318
|
+
packetSource: sourceLabel,
|
|
314
319
|
});
|
|
315
320
|
}
|
|
316
321
|
return payload;
|
|
@@ -449,6 +454,11 @@ function probeUrl(urlStr) {
|
|
|
449
454
|
}
|
|
450
455
|
|
|
451
456
|
async function main() {
|
|
457
|
+
const apiKey = resolveApiKey();
|
|
458
|
+
if (!apiKey) {
|
|
459
|
+
return emitFallback('ARIA_API_KEY not in env and kubectl secret unavailable');
|
|
460
|
+
}
|
|
461
|
+
|
|
452
462
|
// Turn-mode cache hit — don't refetch every keystroke.
|
|
453
463
|
if (isTurn && existsSync(PACKET_CACHE)) {
|
|
454
464
|
try {
|
|
@@ -463,11 +473,6 @@ async function main() {
|
|
|
463
473
|
} catch {}
|
|
464
474
|
}
|
|
465
475
|
|
|
466
|
-
const apiKey = resolveApiKey();
|
|
467
|
-
if (!apiKey) {
|
|
468
|
-
return emitFallback('ARIA_API_KEY not in env and kubectl secret unavailable');
|
|
469
|
-
}
|
|
470
|
-
|
|
471
476
|
const urls = buildUrlList();
|
|
472
477
|
let lastErr = '';
|
|
473
478
|
|
|
@@ -53,7 +53,9 @@ const REQUIRED_LENSES = 8;
|
|
|
53
53
|
const SUBSTANCE_MIN_AFTER_ANCHOR_STRIP = 40;
|
|
54
54
|
const ANCHOR_RX = /\b(axiom|frame|memory|doctrine|packet|language):[a-z0-9_\-./]+/gi;
|
|
55
55
|
const COGNITION_BLOCK_RX = /<cognition>([\s\S]*?)<\/cognition>/i;
|
|
56
|
+
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
56
57
|
const FIRST_PRINCIPLE_RX = /\b(first[_\s-]?principle[s]?|first_principle=)\b/i;
|
|
58
|
+
const DECISION_SIGNAL_RX = /(?:should|recommend|propose|suggest|let'?s|go with|i'd|i would|here'?s the plan|i'll|next step|action item|ship it|yes do|let me)/i;
|
|
57
59
|
|
|
58
60
|
// Drift trigger patterns (mirror aria-stop-gate.mjs canonical list).
|
|
59
61
|
// Keep this conservative — false negatives are tolerable (real gate will
|
|
@@ -138,6 +140,27 @@ function verifyAnchor(anchor, substrate) {
|
|
|
138
140
|
return { ok: true, reason: '' };
|
|
139
141
|
}
|
|
140
142
|
|
|
143
|
+
function validateAppliedCognitionContract(text) {
|
|
144
|
+
const match = String(text || '').match(APPLIED_COGNITION_BLOCK_RX);
|
|
145
|
+
if (!match) return { ok: false, violations: ['missing <applied_cognition> contract'] };
|
|
146
|
+
const body = match[1] || '';
|
|
147
|
+
const required = [
|
|
148
|
+
['decision_delta', /\bdecision[_ -]?delta\s*:/i],
|
|
149
|
+
['dominant_domain', /\bdominant[_ -]?domain\s*:/i],
|
|
150
|
+
['binds_to', /\bbinds[_ -]?to\s*:/i],
|
|
151
|
+
['expected_predicate', /\bexpected[_ -]?predicate\s*:/i],
|
|
152
|
+
['artifact_change', /\bartifact[_ -]?change\s*:/i],
|
|
153
|
+
];
|
|
154
|
+
const violations = [];
|
|
155
|
+
for (const [name, rx] of required) {
|
|
156
|
+
if (!rx.test(body)) violations.push(`missing ${name}`);
|
|
157
|
+
}
|
|
158
|
+
if (/decision[_ -]?delta\s*:\s*(?:none|n\/a|no change|unchanged|same)/i.test(body)) {
|
|
159
|
+
violations.push('decision_delta says cognition changed nothing');
|
|
160
|
+
}
|
|
161
|
+
return { ok: violations.length === 0, violations };
|
|
162
|
+
}
|
|
163
|
+
|
|
141
164
|
// ── Read draft from stdin ─────────────────────────────────────────────
|
|
142
165
|
let stdin = '';
|
|
143
166
|
try {
|
|
@@ -165,6 +188,7 @@ if (draft.length < 10) {
|
|
|
165
188
|
|
|
166
189
|
const substrate = loadSubstrate();
|
|
167
190
|
const failures = [];
|
|
191
|
+
const requiresAppliedCognition = draft.length >= 300 || DECISION_SIGNAL_RX.test(draft) || ['deploy', 'edit', 'bash', 'text'].includes(actionType);
|
|
168
192
|
|
|
169
193
|
// ── Cognition block presence + lens count + substance ─────────────────
|
|
170
194
|
const cogMatch = draft.match(COGNITION_BLOCK_RX);
|
|
@@ -225,6 +249,17 @@ if (cogMatch) {
|
|
|
225
249
|
}
|
|
226
250
|
}
|
|
227
251
|
|
|
252
|
+
if (requiresAppliedCognition) {
|
|
253
|
+
const applied = validateAppliedCognitionContract(draft);
|
|
254
|
+
if (!applied.ok) {
|
|
255
|
+
failures.push({
|
|
256
|
+
kind: 'applied_cognition_contract_invalid',
|
|
257
|
+
violations: applied.violations,
|
|
258
|
+
message: 'Non-trivial drafts must bind cognition to the actual action/output.',
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
228
263
|
// ── Drift triggers ────────────────────────────────────────────────────
|
|
229
264
|
for (const trigger of DRIFT_TRIGGERS) {
|
|
230
265
|
const match = draft.match(trigger.rx);
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
normalizeContent,
|
|
53
53
|
normalizeRole,
|
|
54
54
|
} from './lib/hook-message-window.mjs';
|
|
55
|
+
import { evaluateSkillGate, formatSkillGateBlock } from './lib/skill-autoload-gate.mjs';
|
|
55
56
|
|
|
56
57
|
const HOME = process.env.HOME || '/tmp';
|
|
57
58
|
const LOG = `${HOME}/.claude/aria-pre-tool-gate.log`;
|
|
@@ -332,12 +333,29 @@ function actionMatchesPattern(action, pattern, target) {
|
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
|
|
336
|
+
function isOperationalMaintenanceCommand(command) {
|
|
337
|
+
const cmd = String(command || '').trim().replace(/\s+/g, ' ');
|
|
338
|
+
if (!cmd || /[;&|`$()]/.test(cmd)) return false;
|
|
339
|
+
|
|
340
|
+
// A rollout restart requeues existing pod templates; it does not change images,
|
|
341
|
+
// manifests, or cluster policy. Keep this narrow so deploy/apply/delete still gate.
|
|
342
|
+
const kubectlGlobalFlag = String.raw`(?:--(?:namespace|context|kubeconfig|as|as-group|cluster|user|server|request-timeout|field-manager)(?:=|\s+)\S+|-[A-Za-z](?:\s+\S+)?)`;
|
|
343
|
+
const kubectlTailFlag = String.raw`(?:--(?:namespace|context|request-timeout|field-manager|selector)(?:=|\s+)\S+|-[A-Za-z](?:\s+\S+)?)`;
|
|
344
|
+
const workloadTarget = String.raw`(?:deploy(?:ment)?|statefulset|sts|daemonset|ds)(?:\/[^\s]+|\s+[^\s-][^\s]*)`;
|
|
345
|
+
const rolloutRestartRx = new RegExp(
|
|
346
|
+
String.raw`^kubectl(?:\s+${kubectlGlobalFlag})*\s+rollout\s+restart\s+${workloadTarget}(?:\s+${kubectlTailFlag})*$`,
|
|
347
|
+
'i',
|
|
348
|
+
);
|
|
349
|
+
return rolloutRestartRx.test(cmd);
|
|
350
|
+
}
|
|
351
|
+
|
|
335
352
|
function classifyToolForBinding(toolName, command, filePath) {
|
|
336
353
|
// Map Claude Code tool + payload to a binding-vocabulary action.
|
|
337
354
|
if (toolName === 'Read' || toolName === 'Glob' || toolName === 'Grep') return { action: 'read', target: filePath || '' };
|
|
338
355
|
if (toolName === 'Edit' || toolName === 'Write' || toolName === 'NotebookEdit') return { action: 'edit', target: filePath || '' };
|
|
339
356
|
if (toolName === 'Bash') {
|
|
340
357
|
const cmd = String(command || '');
|
|
358
|
+
if (isOperationalMaintenanceCommand(cmd)) return { action: 'kubectl_maintenance', target: cmd.slice(0, 80) };
|
|
341
359
|
if (/^kubectl\s+(get|describe|logs|exec\s+\S+\s+--\s+printenv|top|version|api-resources)\b/.test(cmd)) return { action: 'kubectl_get', target: cmd.slice(0, 80) };
|
|
342
360
|
if (/^kubectl\s+(apply|delete|set|patch|rollout|scale|drain|cordon)\b/.test(cmd)) return { action: 'kubectl_apply', target: cmd.slice(0, 80) };
|
|
343
361
|
if (/curl\s+.*\/api\/harness\/(delegate|codex|army|plan)/.test(cmd)) return { action: 'consult', target: 'harness' };
|
|
@@ -511,6 +529,7 @@ function docRef(canonicalFilename, genericDescription) {
|
|
|
511
529
|
// colon, not a placeholder template). The substance check (added
|
|
512
530
|
// 2026-04-26) defeats ritual emission — `nur: ok` no longer counts.
|
|
513
531
|
const COGNITION_BLOCK_RX = /<cognition>([\s\S]*?)<\/cognition>/i;
|
|
532
|
+
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
514
533
|
// Hamza directive 2026-04-28: 8-lens enforcement, not 4-of-8. The earlier
|
|
515
534
|
// REQUIRED_LENSES=4 was a regression — owner caught it ("i no longer see
|
|
516
535
|
// 8 lens cognition per turn"). All 8 canonical lenses must appear with
|
|
@@ -554,7 +573,7 @@ const SHORT_BASH_LIMIT = 30;
|
|
|
554
573
|
// (b) Single-line: `# cognition: <label>=<text>; <label>=<text>; ...`
|
|
555
574
|
//
|
|
556
575
|
// Substance check applies (≥SUBSTANCE_MIN_CHARS, not a `<placeholder>`).
|
|
557
|
-
//
|
|
576
|
+
// All required substantive lenses inline → gate passes, no transcript scan
|
|
558
577
|
// needed. Cognition becomes a property of THE ACTION, not of some
|
|
559
578
|
// message somewhere — the deepest reading of "cognition before action."
|
|
560
579
|
//
|
|
@@ -610,6 +629,32 @@ function detectInlineCognition(cmd) {
|
|
|
610
629
|
return { count: names.length, names, hasSubstrateCite };
|
|
611
630
|
}
|
|
612
631
|
|
|
632
|
+
function validateAppliedCognitionContract(text, cmdText = '') {
|
|
633
|
+
const bodyText = `${String(text || '')}\n${String(cmdText || '')}`;
|
|
634
|
+
const block = bodyText.match(APPLIED_COGNITION_BLOCK_RX);
|
|
635
|
+
const inlineBody = String(cmdText || '')
|
|
636
|
+
.split('\n')
|
|
637
|
+
.filter((line) => /^\s*#\s*(?:decision[_ -]?delta|dominant[_ -]?domain|binds[_ -]?to|expected[_ -]?predicate|artifact[_ -]?change)\s*:/i.test(line))
|
|
638
|
+
.join('\n');
|
|
639
|
+
const contractBody = block ? block[1] : inlineBody;
|
|
640
|
+
if (!contractBody) return { ok: false, violations: ['missing <applied_cognition> contract or inline applied-cognition comments'] };
|
|
641
|
+
const required = [
|
|
642
|
+
['decision_delta', /\bdecision[_ -]?delta\s*:/i],
|
|
643
|
+
['dominant_domain', /\bdominant[_ -]?domain\s*:/i],
|
|
644
|
+
['binds_to', /\bbinds[_ -]?to\s*:/i],
|
|
645
|
+
['expected_predicate', /\bexpected[_ -]?predicate\s*:/i],
|
|
646
|
+
['artifact_change', /\bartifact[_ -]?change\s*:/i],
|
|
647
|
+
];
|
|
648
|
+
const violations = [];
|
|
649
|
+
for (const [name, rx] of required) {
|
|
650
|
+
if (!rx.test(contractBody)) violations.push(`missing ${name}`);
|
|
651
|
+
}
|
|
652
|
+
if (/decision[_ -]?delta\s*:\s*(?:none|n\/a|no change|unchanged|same)/i.test(contractBody)) {
|
|
653
|
+
violations.push('decision_delta says cognition changed nothing');
|
|
654
|
+
}
|
|
655
|
+
return { ok: violations.length === 0, violations, body: contractBody.trim() };
|
|
656
|
+
}
|
|
657
|
+
|
|
613
658
|
function normalizeInlineDirectiveBody(rawBody) {
|
|
614
659
|
if (!rawBody) return '';
|
|
615
660
|
const segments = String(rawBody)
|
|
@@ -671,6 +716,65 @@ function extractCurrentTurnAssistantText(event, toolInput) {
|
|
|
671
716
|
return parts.join('\n\n').trim();
|
|
672
717
|
}
|
|
673
718
|
|
|
719
|
+
function extractTextForUserCorrection(content) {
|
|
720
|
+
if (Array.isArray(content)) {
|
|
721
|
+
return content.filter((block) => block && block.type === 'text').map((block) => block.text || '').filter(Boolean).join('\n');
|
|
722
|
+
}
|
|
723
|
+
return typeof content === 'string' ? content : '';
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
function isRuntimeInjectedUserText(text) {
|
|
727
|
+
return /^\s*\[tool_result\b/i.test(text) ||
|
|
728
|
+
/(?:PreToolUse:[A-Za-z]+ hook blocking error|Stop hook feedback:|Aria pre-tool gate:|Aria stop-gate:|<system-reminder>|<task-notification>|task-notification)/i.test(text);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function collectRecentRealUserText(event, transcriptPath, limit = 6) {
|
|
732
|
+
const texts = [];
|
|
733
|
+
const seen = new Set();
|
|
734
|
+
const pushText = (text) => {
|
|
735
|
+
const normalized = String(text || '').trim();
|
|
736
|
+
if (!normalized || seen.has(normalized) || isRuntimeInjectedUserText(normalized)) return;
|
|
737
|
+
seen.add(normalized);
|
|
738
|
+
texts.push(normalized);
|
|
739
|
+
};
|
|
740
|
+
const messages = Array.isArray(event?.messages) ? event.messages : [];
|
|
741
|
+
for (let i = messages.length - 1; i >= 0 && texts.length < limit; i--) {
|
|
742
|
+
const role = messages[i]?.message?.role ?? messages[i]?.role ?? messages[i]?.type;
|
|
743
|
+
if (role !== 'user') continue;
|
|
744
|
+
const content = messages[i]?.message?.content ?? messages[i]?.content ?? [];
|
|
745
|
+
if (Array.isArray(content) && content.length > 0 && content.every((block) => block && block.type === 'tool_result')) continue;
|
|
746
|
+
pushText(extractTextForUserCorrection(content));
|
|
747
|
+
}
|
|
748
|
+
if (transcriptPath && existsSync(transcriptPath) && texts.length < limit) {
|
|
749
|
+
try {
|
|
750
|
+
const lines = readFileSync(transcriptPath, 'utf-8').split('\n').filter(Boolean);
|
|
751
|
+
for (let i = lines.length - 1; i >= 0 && texts.length < limit; i--) {
|
|
752
|
+
let entry;
|
|
753
|
+
try { entry = JSON.parse(lines[i]); } catch { continue; }
|
|
754
|
+
const role = entry?.message?.role ?? entry?.role ?? entry?.type;
|
|
755
|
+
if (role !== 'user') continue;
|
|
756
|
+
const content = entry?.message?.content ?? entry?.content ?? [];
|
|
757
|
+
if (Array.isArray(content) && content.length > 0 && content.every((block) => block && block.type === 'tool_result')) continue;
|
|
758
|
+
pushText(extractTextForUserCorrection(content));
|
|
759
|
+
}
|
|
760
|
+
} catch {}
|
|
761
|
+
}
|
|
762
|
+
return texts.join('\n\n');
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function userCorrectionBlocksCommand(userText, command) {
|
|
766
|
+
const text = String(userText || '');
|
|
767
|
+
const cmd = String(command || '');
|
|
768
|
+
if (!text || !cmd) return null;
|
|
769
|
+
const k8sMutation = /\bkubectl\s+(?:apply|delete|set\s+image|patch|replace|create|scale|rollout\s+(?:restart|undo))\b|scripts\/deploy-|\bdocker\s+push\b/i.test(cmd);
|
|
770
|
+
const explicitStop = /\b(?:stop|do\s+not|don't|quit|cease)\b[\s\S]{0,160}\b(?:deploy|redeploy|restart|rollout|kubectl|command|pods?)\b/i.test(text);
|
|
771
|
+
if (explicitStop && k8sMutation) return 'recent user explicitly told the agent to stop deploy/restart command attempts';
|
|
772
|
+
const macTargetInCommand = /\bmlx-mac\b|\bdeployment\/mlx-mac|\bdeploy(?:ment)?\s+mlx-mac/i.test(cmd);
|
|
773
|
+
const macContradiction = /\b(?:mac\s+lanes?|mac\s+pods?|mlx-mac)\b[\s\S]{0,140}\b(?:not\s+pods?|no\s+such\s+thing|non[-\s]?existent|do(?:es)?\s+not\s+exist|don't\s+exist)\b|\b(?:no\s+such\s+thing|non[-\s]?existent|do(?:es)?\s+not\s+exist|don't\s+exist)\b[\s\S]{0,140}\b(?:mac\s+lanes?|mac\s+pods?|mlx-mac|pods?)\b/i.test(text);
|
|
774
|
+
if (macTargetInCommand && macContradiction) return 'recent user contradicted the mlx-mac Kubernetes-pod/deployment assumption';
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
|
|
674
778
|
// Substance-checking lens detection (added 2026-04-26 per Hamza's
|
|
675
779
|
// gate-improvement doctrine: form-only emission must not satisfy
|
|
676
780
|
// the gate). For each lens, look for `<lens>: <content>` and verify
|
|
@@ -927,6 +1031,7 @@ try {
|
|
|
927
1031
|
|
|
928
1032
|
const toolName = event.tool_name ?? event.toolName ?? '';
|
|
929
1033
|
const toolInput = event.tool_input ?? event.toolInput ?? {};
|
|
1034
|
+
const transcriptPath = event.transcript_path ?? event.transcriptPath;
|
|
930
1035
|
|
|
931
1036
|
// Gate every action tool — every tool that mutates state must go through
|
|
932
1037
|
// cognition challenge. Hamza 2026-04-26: "regardless if u arent even
|
|
@@ -949,6 +1054,26 @@ const cmdPreview = toolName === 'Bash'
|
|
|
949
1054
|
? cmd.slice(0, 80).replace(/\s+/g, ' ')
|
|
950
1055
|
: `${toolName} ${filePath || '(no path)'}`.slice(0, 80);
|
|
951
1056
|
|
|
1057
|
+
if (toolName === 'Bash') {
|
|
1058
|
+
const recentUserText = collectRecentRealUserText(event, transcriptPath);
|
|
1059
|
+
const correctionBlockReason = userCorrectionBlocksCommand(recentUserText, cmd);
|
|
1060
|
+
if (correctionBlockReason) {
|
|
1061
|
+
const reason = `Aria pre-tool gate: USER-CORRECTION hard-block.
|
|
1062
|
+
|
|
1063
|
+
${correctionBlockReason}.
|
|
1064
|
+
|
|
1065
|
+
The next assistant response must stop the command loop, quote the user's correction in one sentence, and re-evaluate the target from substrate before any further mutation. Do not retry this Bash command shape.`;
|
|
1066
|
+
audit('block-user-correction-override', cmdPreview);
|
|
1067
|
+
emitBlock(reason, { source: 'pre-tool/user-correction' });
|
|
1068
|
+
process.exit(2);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
if (toolName === 'Bash' && isOperationalMaintenanceCommand(cmd)) {
|
|
1073
|
+
audit('allow-operational-maintenance kubectl-rollout-restart', cmdPreview);
|
|
1074
|
+
process.exit(0);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
952
1077
|
// V3: per-command bypass removed entirely. The only escape valves are:
|
|
953
1078
|
// (1) Trivial-bash whitelist — short read-only commands pass without cognition
|
|
954
1079
|
// (2) ~/.claude/settings.json hook removal — visible user action Hamza controls
|
|
@@ -1032,7 +1157,6 @@ const HARD_LOOKBACK_CAP = 50;
|
|
|
1032
1157
|
// window since the substance check defends quality regardless.
|
|
1033
1158
|
const USER_BOUNDARIES_TO_CROSS = 5;
|
|
1034
1159
|
|
|
1035
|
-
const transcriptPath = event.transcript_path ?? event.transcriptPath;
|
|
1036
1160
|
const recentAssistantTexts = [];
|
|
1037
1161
|
const recentAssistantTextSet = new Set();
|
|
1038
1162
|
function appendAssistantTexts(texts) {
|
|
@@ -1129,6 +1253,7 @@ const bestVerifyBody = (() => {
|
|
|
1129
1253
|
})();
|
|
1130
1254
|
const hasVerify = scoreVerifyFields(bestVerifyBody, VERIFY_REQUIRED_FIELDS) === VERIFY_REQUIRED_FIELDS.length;
|
|
1131
1255
|
const hasCognition = lensCount >= REQUIRED_LENSES;
|
|
1256
|
+
const appliedContract = validateAppliedCognitionContract(unionText, cmd);
|
|
1132
1257
|
const cognitionSource = inlineCog.count >= REQUIRED_LENSES
|
|
1133
1258
|
? 'inline-command'
|
|
1134
1259
|
: eventCog.count >= REQUIRED_LENSES
|
|
@@ -1163,6 +1288,24 @@ const sessionId =
|
|
|
1163
1288
|
(transcriptPath ? transcriptPath.split('/').pop()?.replace(/\.[^.]+$/, '') : null) ??
|
|
1164
1289
|
'claude-code-unknown';
|
|
1165
1290
|
|
|
1291
|
+
const skillGate = evaluateSkillGate({
|
|
1292
|
+
sessionId,
|
|
1293
|
+
surface: 'claude-pre-tool-gate',
|
|
1294
|
+
text: [JSON.stringify(event.messages || []), unionText, JSON.stringify(toolInput || {})].join('\n'),
|
|
1295
|
+
action: cmd,
|
|
1296
|
+
toolName,
|
|
1297
|
+
filePath,
|
|
1298
|
+
isDeploy: Boolean(deployMatched),
|
|
1299
|
+
isMutation: toolName !== 'Bash',
|
|
1300
|
+
autoLoadAvailable: false,
|
|
1301
|
+
});
|
|
1302
|
+
if (!skillGate.ok) {
|
|
1303
|
+
const reason = formatSkillGateBlock(skillGate);
|
|
1304
|
+
audit('block-missing-skill-receipt', `${skillGate.missingSkills.join(',')} ${cmdPreview}`);
|
|
1305
|
+
emitBlock(reason, { source: 'pre-tool/skill-autoload', tool: toolName, lensCount, requiredLenses: REQUIRED_LENSES });
|
|
1306
|
+
process.exit(2);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1166
1309
|
function pushDecision(decision, reasonText) {
|
|
1167
1310
|
pushCognitionEvent({
|
|
1168
1311
|
sessionId,
|
|
@@ -1181,6 +1324,7 @@ function pushDecision(decision, reasonText) {
|
|
|
1181
1324
|
hasVerify,
|
|
1182
1325
|
hasCognition,
|
|
1183
1326
|
hasSubstrateCite,
|
|
1327
|
+
appliedCognitionContractOk: appliedContract.ok,
|
|
1184
1328
|
},
|
|
1185
1329
|
});
|
|
1186
1330
|
}
|
|
@@ -1204,6 +1348,62 @@ Next response must do this in order:
|
|
|
1204
1348
|
4. If the blocker is stale gate state or ledger residue, say that explicitly instead of inventing fake proof.`;
|
|
1205
1349
|
}
|
|
1206
1350
|
|
|
1351
|
+
function buildForceRedoActionReason(reasonText, { source = 'pre-tool-gate', tool = toolName || 'unknown', lensCount = 0, requiredLenses = REQUIRED_LENSES } = {}) {
|
|
1352
|
+
if (String(reasonText || '').includes('ARIA FORCE_REDO_ACTION')) return reasonText;
|
|
1353
|
+
return [
|
|
1354
|
+
'=== ARIA FORCE_REDO_ACTION ===',
|
|
1355
|
+
`source: ${source}`,
|
|
1356
|
+
`tool: ${tool}`,
|
|
1357
|
+
'',
|
|
1358
|
+
'This is not a terminal error. It is a forced redo instruction before tool execution.',
|
|
1359
|
+
'Do not retry the same tool call unchanged. Re-author the action with cognition, proof, and expected outcome first.',
|
|
1360
|
+
'',
|
|
1361
|
+
'TEACHING:',
|
|
1362
|
+
'- Pre-tool gates exist to make the model think before acting, not to merely throw after a bad action shape.',
|
|
1363
|
+
'- The redo must name the failed mechanism, cite the current substrate, and state why the next action is safe.',
|
|
1364
|
+
'- Do not bypass by disabling tools, changing endpoints from memory, shortening runtime, or asking Hamza to solve saved-memory ambiguity.',
|
|
1365
|
+
'',
|
|
1366
|
+
'ORIGINAL GATE REASON:',
|
|
1367
|
+
String(reasonText || '').trim(),
|
|
1368
|
+
'',
|
|
1369
|
+
'REQUIRED REDO SHAPE:',
|
|
1370
|
+
'1. Emit/attach <cognition> with the required lenses before retrying the tool.',
|
|
1371
|
+
'2. For Bash, prepend inline cognition comments to the command:',
|
|
1372
|
+
' # nur: <observed state and substrate, >=20 chars>',
|
|
1373
|
+
' # mizan: <risk/tradeoff and why this action is balanced, >=20 chars>',
|
|
1374
|
+
' # hikma: <doctrine applied and what it forbids, >=20 chars>',
|
|
1375
|
+
' # tafakkur: <second-order effects and expected result, >=20 chars>',
|
|
1376
|
+
`3. Current cognition count: ${lensCount}/${requiredLenses}.`,
|
|
1377
|
+
'4. If deploy/shared-infra: include <verify> with target, verified evidence, rollback, and axiom.',
|
|
1378
|
+
'5. If non-trivial action: include <expected> with numeric/boolean/state-string predicate.',
|
|
1379
|
+
'=== END FORCE_REDO_ACTION ===',
|
|
1380
|
+
].join('\n');
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function emitBlock(reasonText, meta = {}) {
|
|
1384
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceRedoActionReason(reasonText, meta) }));
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
if (hasCognition && !appliedContract.ok) {
|
|
1388
|
+
const reason = `Aria pre-tool gate: cognition exists but is not applied to the action.
|
|
1389
|
+
|
|
1390
|
+
The harness no longer accepts cognition as decorative preface. Before a mutating tool call, cognition must produce an execution contract that changes or constrains the action.
|
|
1391
|
+
|
|
1392
|
+
Violations:
|
|
1393
|
+
${appliedContract.violations.map((v) => `- ${v}`).join('\n')}
|
|
1394
|
+
|
|
1395
|
+
Required contract, either in the assistant turn as <applied_cognition>...</applied_cognition> or inline Bash comments:
|
|
1396
|
+
decision_delta: <what changed because cognition ran; not "none">
|
|
1397
|
+
dominant_domain: <engineering_quality | trust | operations | security | product | ...>
|
|
1398
|
+
binds_to: <this exact tool call/action>
|
|
1399
|
+
expected_predicate: <numeric, boolean, or state-string predicate proving success>
|
|
1400
|
+
artifact_change: <how the artifact/action is different because cognition ran>`;
|
|
1401
|
+
audit('block-applied-cognition-contract', cmdPreview);
|
|
1402
|
+
pushDecision('block', `applied cognition contract missing: ${appliedContract.violations.join(', ')}`);
|
|
1403
|
+
emitBlock(reason, { source: 'pre-tool/applied-cognition-contract', tool: toolName, lensCount, requiredLenses: REQUIRED_LENSES });
|
|
1404
|
+
process.exit(2);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1207
1407
|
// ── Deploy-specific gate (doctrine #104) ────────────────────────────────
|
|
1208
1408
|
// Per feedback_deploy_requires_verify_cognition.md (Hamza 2026-04-28 after
|
|
1209
1409
|
// consciousness.ts crash took aria-soul into CrashLoopBackOff): deploys
|
|
@@ -1355,7 +1555,7 @@ Re-emit verify+cognition with the missing pieces, then retry the deploy command.
|
|
|
1355
1555
|
cmdPreview,
|
|
1356
1556
|
);
|
|
1357
1557
|
pushDecision('block', `deploy ${deployMatched.name}: ${reasons.join('; ')}`);
|
|
1358
|
-
|
|
1558
|
+
emitBlock(refusal, { source: 'pre-tool/deploy', tool: toolName });
|
|
1359
1559
|
process.exit(2);
|
|
1360
1560
|
}
|
|
1361
1561
|
|
|
@@ -1399,7 +1599,7 @@ At least 4 substantive lenses required.`),
|
|
|
1399
1599
|
`destructive:${matched.name}:${hasVerify ? 'need-cognition' : 'need-verify'}:${toolName}:${filePath || cmdPreview}`);
|
|
1400
1600
|
audit(`block ${matched.name} verify=${hasVerify} cognition=${lensCount}`, cmdPreview);
|
|
1401
1601
|
pushDecision('block', `destructive ${matched.name} missing ${!hasVerify ? 'verify' : 'cognition'}`);
|
|
1402
|
-
|
|
1602
|
+
emitBlock(reason, { source: 'pre-tool/destructive' });
|
|
1403
1603
|
process.exit(2);
|
|
1404
1604
|
}
|
|
1405
1605
|
|
|
@@ -1448,7 +1648,7 @@ No per-tool bypass available (v3 doctrine — the harness's whole purpose is no
|
|
|
1448
1648
|
|
|
1449
1649
|
audit(`block ${toolName.toLowerCase()} cognition=${lensCount}`, cmdPreview);
|
|
1450
1650
|
pushDecision('block', `${toolName.toLowerCase()} missing cognition (${lensCount}/${REQUIRED_LENSES})`);
|
|
1451
|
-
|
|
1651
|
+
emitBlock(reason, { source: 'pre-tool/missing-cognition' });
|
|
1452
1652
|
process.exit(2);
|
|
1453
1653
|
}
|
|
1454
1654
|
|
|
@@ -1479,7 +1679,7 @@ No env-var disable path — gates are unconditional from the gated process per H
|
|
|
1479
1679
|
|
|
1480
1680
|
audit(`block-discovery-unresolved ${toolName.toLowerCase()}`, cmdPreview);
|
|
1481
1681
|
pushDecision('block', `${toolName.toLowerCase()} cognition has unresolved discovery`);
|
|
1482
|
-
|
|
1682
|
+
emitBlock(reason, { source: 'pre-tool/discovery-binding' });
|
|
1483
1683
|
process.exit(2);
|
|
1484
1684
|
}
|
|
1485
1685
|
|
|
@@ -1543,7 +1743,7 @@ No bypass — doctrine:dalio_expected_required is unconditional for non-trivial
|
|
|
1543
1743
|
|
|
1544
1744
|
audit(`block-expected-missing ${toolName.toLowerCase()}`, cmdPreview);
|
|
1545
1745
|
pushDecision('block', `${toolName.toLowerCase()} missing <expected> measurable predicate`);
|
|
1546
|
-
|
|
1746
|
+
emitBlock(reason, { source: 'pre-tool/discovery-binding' });
|
|
1547
1747
|
process.exit(2);
|
|
1548
1748
|
}
|
|
1549
1749
|
}
|
|
@@ -1626,7 +1826,7 @@ Read it first (it is in your environment as ARIA_HARNESS_PACKET_PATH), then refe
|
|
|
1626
1826
|
|
|
1627
1827
|
Cognition-theater rejected per feedback_gates_enforce_form_not_substance.md.`;
|
|
1628
1828
|
audit(`block-subagent-no-packet-cite ${toolName.toLowerCase()}`, cmdPreview);
|
|
1629
|
-
|
|
1829
|
+
emitBlock(reason, { source: 'pre-tool/architecture-facts' });
|
|
1630
1830
|
process.exit(2);
|
|
1631
1831
|
}
|
|
1632
1832
|
})();
|
|
@@ -1669,7 +1869,7 @@ Rule references:
|
|
|
1669
1869
|
R10 no_kubectl_apply_for_image_drift — kubectl apply on aria-soul-stateful (project_forge_psi_oom_cascade.md)
|
|
1670
1870
|
R11 no_console_log_secrets — console.log with TOKEN/PASSWORD/SECRET/API_KEY/JWT/BEARER`;
|
|
1671
1871
|
audit(`block-arch-facts ${toolName.toLowerCase()} path=${filePath}`, `violations=${archResult.violations?.length ?? 0}`);
|
|
1672
|
-
|
|
1872
|
+
emitBlock(archReason, { source: 'pre-tool/architecture-facts' });
|
|
1673
1873
|
process.exit(2);
|
|
1674
1874
|
}
|
|
1675
1875
|
}
|
|
@@ -1771,7 +1971,7 @@ What Claude must do:
|
|
|
1771
1971
|
3. Wait for next user prompt — preprompt-consult will retry; if it succeeds a plan will exist on next tool call
|
|
1772
1972
|
|
|
1773
1973
|
Non-trivial actions are blocked until a plan exists. Trivial reads (ls/cat/grep) bypass automatically per existing whitelist. To temporarily disable binding for emergency: ARIA_BINDING_ENABLED=false (logged).`;
|
|
1774
|
-
|
|
1974
|
+
emitBlock(reason, { source: 'pre-tool/substrate-binding' });
|
|
1775
1975
|
process.exit(2);
|
|
1776
1976
|
}
|
|
1777
1977
|
}
|
|
@@ -1790,7 +1990,7 @@ What Claude must do:
|
|
|
1790
1990
|
3. Don't continue executing actions beyond the issued plan boundary
|
|
1791
1991
|
|
|
1792
1992
|
This prevents Claude from drifting past Aria's authorized scope.`;
|
|
1793
|
-
|
|
1993
|
+
emitBlock(reason, { source: 'pre-tool/substrate-binding' });
|
|
1794
1994
|
process.exit(2);
|
|
1795
1995
|
}
|
|
1796
1996
|
|
|
@@ -1827,7 +2027,7 @@ This prevents Claude from drifting past Aria's authorized scope.`;
|
|
|
1827
2027
|
if (!freshPhaseInfo || freshPhaseInfo.abortedHere) {
|
|
1828
2028
|
bindingAuditAppend({ event: 'block_aborted_phase_post_fallback_still_bad', sessionId, planId: plan.planId });
|
|
1829
2029
|
const reason = `Aria binding gate: aborted phase recovery minted plan ${plan.planId} but new plan also has no usable phase. Manual intervention required.`;
|
|
1830
|
-
|
|
2030
|
+
emitBlock(reason, { source: 'pre-tool/dalio-expected' });
|
|
1831
2031
|
process.exit(2);
|
|
1832
2032
|
}
|
|
1833
2033
|
phaseInfo = freshPhaseInfo;
|
|
@@ -1836,7 +2036,7 @@ This prevents Claude from drifting past Aria's authorized scope.`;
|
|
|
1836
2036
|
const reason = `Aria binding gate: phase ${phaseInfo.phase.id} of plan ${plan.planId} was reported aborted AND inline architect-fallback failed (exit=${architectExit}). Plan progression halted. ${architectStderr ? 'Architect stderr: ' + architectStderr : ''}
|
|
1837
2037
|
|
|
1838
2038
|
What Claude must do: emit [PLAN_BLOCKER reason="<concrete observation>" suggestedAmendment="<if any>"] for Hamza/Aria to issue a corrected plan. Do not continue executing the aborted plan.`;
|
|
1839
|
-
|
|
2039
|
+
emitBlock(reason, { source: 'pre-tool/dalio-expected' });
|
|
1840
2040
|
process.exit(2);
|
|
1841
2041
|
}
|
|
1842
2042
|
}
|
|
@@ -1864,7 +2064,7 @@ Forbidden actions for this phase: ${(phase.forbiddenActions || []).join(', ') ||
|
|
|
1864
2064
|
Allowed actions for this phase: ${(phase.allowedActions || []).join(', ') || '(none)'}
|
|
1865
2065
|
|
|
1866
2066
|
Claude must either: (a) reframe the action to fit allowedActions, OR (b) emit [PLAN_BLOCKER reason="..."] requesting Aria amend the plan.${recipeAddendum}`;
|
|
1867
|
-
|
|
2067
|
+
emitBlock(reason, { source: 'pre-tool/output-claim' });
|
|
1868
2068
|
process.exit(2);
|
|
1869
2069
|
}
|
|
1870
2070
|
|
|
@@ -1883,7 +2083,7 @@ Phase summary: ${phase.summary}
|
|
|
1883
2083
|
Allowed actions: ${(phase.allowedActions || []).join(', ') || '(none — phase is observation-only)'}
|
|
1884
2084
|
|
|
1885
2085
|
Claude must either: (a) reframe action to fit allowedActions, OR (b) emit [PLAN_BLOCKER reason="..."] for plan amendment.${recipeAddendum}`;
|
|
1886
|
-
|
|
2086
|
+
emitBlock(reason, { source: 'pre-tool/output-claim' });
|
|
1887
2087
|
process.exit(2);
|
|
1888
2088
|
}
|
|
1889
2089
|
|
|
@@ -2025,7 +2225,7 @@ try {
|
|
|
2025
2225
|
The substrate's contract gate refused this action. Local doctrine gates passed (cognition lenses, binding plan, drift) but the substrate sees a downstream contract that disallows this tool call. Address the substrate's reason above before retrying.`;
|
|
2026
2226
|
audit(`block-substrate-checkAction ${toolName.toLowerCase()} action=${__action} reason="${(__check.reason || '').slice(0, 80)}"`, cmdPreview);
|
|
2027
2227
|
pushDecision('block', `substrate checkAction denied: ${(__check.reason || 'unspecified').slice(0, 100)}`);
|
|
2028
|
-
|
|
2228
|
+
emitBlock(__reason, { source: 'pre-tool/final' });
|
|
2029
2229
|
process.exit(2);
|
|
2030
2230
|
}
|
|
2031
2231
|
}
|
|
@@ -2218,7 +2418,7 @@ causes merge conflicts and state divergence. Explicit coordination is the only s
|
|
|
2218
2418
|
pushDecision('block', `hive session-lock conflict on ${_lockCheckPath.slice(0, 80)}`);
|
|
2219
2419
|
console.log(JSON.stringify({
|
|
2220
2420
|
decision: 'block',
|
|
2221
|
-
reason: _lockBlockReason,
|
|
2421
|
+
reason: buildForceRedoActionReason(_lockBlockReason, { source: 'pre-tool/hive-lock-conflict', tool: toolName || 'unknown' }),
|
|
2222
2422
|
hookSpecificOutput: {
|
|
2223
2423
|
hookEventName: 'PreToolUse',
|
|
2224
2424
|
conflicting_locks: _conflictingLocks,
|