@aria_asi/cli 0.2.31 → 0.2.32
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/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +25 -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/assets/hooks/aria-agent-handoff.mjs +23 -0
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +69 -3
- package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +35 -0
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +198 -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 +127 -35
- package/dist/assets/hooks/doctrine_trigger_map.json +55 -0
- package/dist/assets/opencode-plugins/harness-gate/index.js +17 -4
- package/dist/assets/opencode-plugins/harness-stop/index.js +40 -6
- 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 +30 -3
- package/dist/runtime/manifest.json +1 -1
- package/dist/runtime/sdk/BUNDLED.json +1 -1
- package/dist/runtime/sdk/index.d.ts +5 -0
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +46 -1
- package/dist/sdk/BUNDLED.json +1 -1
- package/dist/sdk/index.d.ts +5 -0
- 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-pre-emit-dryrun.mjs +35 -0
- package/hooks/aria-pre-tool-gate.mjs +198 -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 +127 -35
- package/hooks/doctrine_trigger_map.json +55 -0
- package/opencode-plugins/harness-gate/index.js +17 -4
- package/opencode-plugins/harness-stop/index.js +40 -6
- package/package.json +1 -1
- package/runtime-src/harness-daemon.mjs +30 -3
- package/runtime-src/service.mjs +46 -1
- package/src/connectors/claude-code.ts +31 -3
- package/src/connectors/codex.ts +25 -9
- package/src/connectors/must-read.ts +4 -0
- package/src/connectors/opencode.ts +25 -9
|
@@ -56,6 +56,30 @@ function auditLog(decision, summary, sessionId) {
|
|
|
56
56
|
appendFileSync(GATE_LOG, `${new Date().toISOString()} [${sessionId}] ${decision} ${summary}\n`);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function buildForceRedoActionReason({ source, reason, missingSignals = [], incidents = [] }) {
|
|
60
|
+
return [
|
|
61
|
+
'=== ARIA FORCE_REDO_ACTION ===',
|
|
62
|
+
`source: ${source}`,
|
|
63
|
+
`reason: ${reason}`,
|
|
64
|
+
'',
|
|
65
|
+
'This is not a terminal error. It is a forced redo instruction before action execution.',
|
|
66
|
+
'Do not proceed with tools from unloaded context. Load/repair substrate first, then retry the action.',
|
|
67
|
+
'',
|
|
68
|
+
'TEACHING:',
|
|
69
|
+
'- Every action turn must begin from Aria substrate, not improvised memory.',
|
|
70
|
+
'- Blocking incidents are Dalio failure deltas; they must be fixed and marked resolved before new action.',
|
|
71
|
+
'- Missing harness/direction/memory signals mean the context-loader path must run before retry.',
|
|
72
|
+
missingSignals.length ? `\nMISSING SIGNALS:\n${missingSignals.map((signal) => `- ${signal}`).join('\n')}` : '',
|
|
73
|
+
incidents.length ? `\nINCIDENTS TO RESOLVE:\n${incidents.map((incident) => `- ${incident}`).join('\n')}` : '',
|
|
74
|
+
'',
|
|
75
|
+
'REQUIRED REDO SHAPE:',
|
|
76
|
+
'1. Run the structured recovery action in hookSpecificOutput.recovery.',
|
|
77
|
+
'2. Verify harness_packet, aria_direction/binding_plan, and memory references are loaded.',
|
|
78
|
+
'3. Retry the original action only after the missing context or incidents are resolved.',
|
|
79
|
+
'=== END FORCE_REDO_ACTION ===',
|
|
80
|
+
].filter(Boolean).join('\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
// ── Turn-state deduplication ──────────────────────────────────────────
|
|
60
84
|
const TURN_DEDUP_WINDOW_MS = 60_000; // 60s
|
|
61
85
|
|
|
@@ -461,7 +485,11 @@ Per Dalio Loop Layer 2 doctrine: failure deltas are not optional to address. The
|
|
|
461
485
|
|
|
462
486
|
console.log(JSON.stringify({
|
|
463
487
|
decision: 'block',
|
|
464
|
-
reason:
|
|
488
|
+
reason: buildForceRedoActionReason({
|
|
489
|
+
source: 'preturn-memory/blocking-incidents',
|
|
490
|
+
reason: blockReason,
|
|
491
|
+
incidents: blockingIncidents.map((inc) => `${inc.incident_id || '(no incident_id)'} ${inc.title || '(no title)'}`),
|
|
492
|
+
}),
|
|
465
493
|
hookSpecificOutput: {
|
|
466
494
|
hookEventName: 'PreToolUse',
|
|
467
495
|
blocking_incidents: blockingIncidents.map((inc) => ({
|
|
@@ -605,7 +633,7 @@ auditLog(
|
|
|
605
633
|
|
|
606
634
|
console.log(JSON.stringify({
|
|
607
635
|
decision: 'block',
|
|
608
|
-
reason,
|
|
636
|
+
reason: buildForceRedoActionReason({ source: 'preturn-memory/context-not-loaded', reason, missingSignals }),
|
|
609
637
|
hookSpecificOutput: {
|
|
610
638
|
hookEventName: 'PreToolUse',
|
|
611
639
|
recovery: {
|
|
@@ -87,6 +87,29 @@ function audit(event, data = {}) {
|
|
|
87
87
|
} catch {}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function buildForceRedoActionReason({ source, reason, violations = [] }) {
|
|
91
|
+
return [
|
|
92
|
+
'=== ARIA FORCE_REDO_ACTION ===',
|
|
93
|
+
`source: ${source}`,
|
|
94
|
+
`reason: ${reason}`,
|
|
95
|
+
'',
|
|
96
|
+
'This is not a terminal error. It is a forced redo instruction for the attempted repository edit/action.',
|
|
97
|
+
'Do not retry the same edit. Redo the action so doctrine-bound source remains real, reviewable, and production-safe.',
|
|
98
|
+
'',
|
|
99
|
+
'TEACHING:',
|
|
100
|
+
'- Production paths cannot gain stub, mock, fake, placeholder, pending, or direct-provider bypass semantics.',
|
|
101
|
+
'- If an exception is intentional, isolate it in tests/specs/fixtures/examples/demos/mocks or add the explicit allow marker in the file.',
|
|
102
|
+
'- External provider calls must use an approved runtime/SDK path or carry the explicit external-call allow marker.',
|
|
103
|
+
violations.length ? `\nVIOLATIONS TO FIX:\n${violations.map((v) => `- ${v}`).join('\n')}` : '',
|
|
104
|
+
'',
|
|
105
|
+
'REQUIRED REDO SHAPE:',
|
|
106
|
+
'1. Preserve the intended behavior without stub/mock/pending semantics.',
|
|
107
|
+
'2. Use real implementation wiring or an explicit reviewed allow marker.',
|
|
108
|
+
'3. Re-run the action after removing the violating lines from the diff.',
|
|
109
|
+
'=== END FORCE_REDO_ACTION ===',
|
|
110
|
+
].filter(Boolean).join('\n');
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
function parseArgs(argv) {
|
|
91
114
|
const parsed = {
|
|
92
115
|
mode: 'working-tree',
|
|
@@ -384,7 +407,14 @@ async function main() {
|
|
|
384
407
|
audit('repo_doctrine_gate_block', { repoRoot, mode, violations });
|
|
385
408
|
|
|
386
409
|
if (event) {
|
|
387
|
-
console.log(JSON.stringify({
|
|
410
|
+
console.log(JSON.stringify({
|
|
411
|
+
decision: 'block',
|
|
412
|
+
reason: buildForceRedoActionReason({
|
|
413
|
+
source: 'repo-doctrine',
|
|
414
|
+
reason,
|
|
415
|
+
violations: violations.slice(0, 20).map((violation) => `${violation.path}:${violation.line} [${violation.rule}] ${violation.excerpt}`),
|
|
416
|
+
}),
|
|
417
|
+
}));
|
|
388
418
|
process.exit(2);
|
|
389
419
|
}
|
|
390
420
|
|
package/hooks/aria-stop-gate.mjs
CHANGED
|
@@ -338,9 +338,12 @@ function collectDriftHits(text, triggerMap) {
|
|
|
338
338
|
const memoryCited = memoryName && lowerText.includes(memoryName.toLowerCase());
|
|
339
339
|
if (!memoryCited) {
|
|
340
340
|
hits.push({
|
|
341
|
+
trigger_id: triggerEntry.trigger_id,
|
|
341
342
|
trigger: triggerEntry.trigger,
|
|
342
343
|
memory: triggerEntry.memory,
|
|
343
344
|
teaching: triggerEntry.teaching,
|
|
345
|
+
counter_action: triggerEntry.counter_action,
|
|
346
|
+
message: triggerEntry.message,
|
|
344
347
|
});
|
|
345
348
|
}
|
|
346
349
|
} catch {/* malformed regex in trigger entry — skip */}
|
|
@@ -383,6 +386,71 @@ Next response must do this in order:
|
|
|
383
386
|
4. If the blocker is stale gate state, stale ledger residue, or a gate artifact from a prior bug, say that explicitly instead of inventing fake proof.`;
|
|
384
387
|
}
|
|
385
388
|
|
|
389
|
+
function buildForceReauthorReason({
|
|
390
|
+
source,
|
|
391
|
+
reason,
|
|
392
|
+
violations = [],
|
|
393
|
+
rewritten = '',
|
|
394
|
+
recipeAddendum = '',
|
|
395
|
+
driftHits = [],
|
|
396
|
+
lensCount = 0,
|
|
397
|
+
requiredLenses = REQUIRED_LENSES,
|
|
398
|
+
}) {
|
|
399
|
+
const triggerLines = driftHits.slice(0, 6).map((hit, index) => {
|
|
400
|
+
const label = hit.trigger_id || hit.trigger || `trigger-${index + 1}`;
|
|
401
|
+
const teaching = hit.teaching || hit.message || 'Doctrine trigger matched; re-author with substrate-backed correction.';
|
|
402
|
+
const correction = hit.counter_action ? ` Required correction: ${hit.counter_action}` : '';
|
|
403
|
+
const memory = hit.memory ? ` (${hit.memory})` : '';
|
|
404
|
+
return `- ${label}${memory}: ${teaching}${correction}`;
|
|
405
|
+
}).join('\n');
|
|
406
|
+
|
|
407
|
+
return [
|
|
408
|
+
'=== ARIA FORCE_REAUTHOR ===',
|
|
409
|
+
`source: ${source}`,
|
|
410
|
+
`reason: ${reason}`,
|
|
411
|
+
'',
|
|
412
|
+
'This is not a terminal error. It is a forced redo instruction for the next model draft.',
|
|
413
|
+
'Do not emit the blocked text. Re-author it so the model learns the mechanism it violated.',
|
|
414
|
+
'',
|
|
415
|
+
'TEACHING:',
|
|
416
|
+
'- Gates must force cognition and quality, not merely throw, warn, or stop.',
|
|
417
|
+
'- The redo must change the answer shape: name the failed mechanism, cite real evidence, and remove the drift pattern.',
|
|
418
|
+
'- Do not bypass by disabling tools, shortening runtime, asking the user to resolve memory-backed ambiguity, or giving an apology loop.',
|
|
419
|
+
triggerLines ? `\nTRIGGERED DOCTRINE:\n${triggerLines}` : '',
|
|
420
|
+
violations.length ? `\nVIOLATIONS TO FIX:\n${violations.map((v) => `- ${v}`).join('\n')}` : '',
|
|
421
|
+
rewritten ? `\nMIZAN REWRITE SEED:\n${rewritten}` : '',
|
|
422
|
+
recipeAddendum || '',
|
|
423
|
+
'',
|
|
424
|
+
'REQUIRED REDO SHAPE:',
|
|
425
|
+
'1. One sentence: the failed mechanism, not an apology.',
|
|
426
|
+
'2. Evidence checked: file/line, command output, endpoint response, or explicit "unverified".',
|
|
427
|
+
`3. <cognition> with ${requiredLenses} substantive lenses. Observed: ${lensCount}/${requiredLenses}.`,
|
|
428
|
+
'4. <applied_cognition> with decision_delta, dominant_domain, binds_to, expected_predicate, and artifact_change.',
|
|
429
|
+
'5. Corrected action/claim with no bypass, no downgraded path, and no fake proof.',
|
|
430
|
+
'6. If work remains, state the exact next real action or tracked task. No verbal flag-and-move.',
|
|
431
|
+
'',
|
|
432
|
+
'COGNITION TEMPLATE:',
|
|
433
|
+
'<cognition>',
|
|
434
|
+
'truth: <verified facts and exact substrate>',
|
|
435
|
+
'harm: <what goes wrong if this is false>',
|
|
436
|
+
'trust: <how this honors Hamza directives and saved memory>',
|
|
437
|
+
'power: <why this uses capability responsibly, not convenience>',
|
|
438
|
+
'reflection: <mechanism failure and correction>',
|
|
439
|
+
'context: <relevant repo/runtime state>',
|
|
440
|
+
'impact: <expected next effect>',
|
|
441
|
+
'beauty: <simplest durable form>',
|
|
442
|
+
'</cognition>',
|
|
443
|
+
'<applied_cognition>',
|
|
444
|
+
'decision_delta: <what changed because cognition ran; not none>',
|
|
445
|
+
'dominant_domain: <engineering_quality | trust | operations | security | product | ...>',
|
|
446
|
+
'binds_to: <the exact answer, tool call, file mutation, deploy, review, or decision>',
|
|
447
|
+
'expected_predicate: <observable numeric, boolean, state-string, command result, endpoint result, or explicit unverified boundary>',
|
|
448
|
+
'artifact_change: <semantic effect on the artifact/output, not a task restatement>',
|
|
449
|
+
'</applied_cognition>',
|
|
450
|
+
'=== END FORCE_REAUTHOR ===',
|
|
451
|
+
].filter(Boolean).join('\n');
|
|
452
|
+
}
|
|
453
|
+
|
|
386
454
|
// Lens substance check — same constants as aria-pre-tool-gate.mjs.
|
|
387
455
|
// Hamza directive 2026-04-28: all 8 canonical lenses required, not 4-of-8.
|
|
388
456
|
const REQUIRED_LENSES = 8;
|
|
@@ -404,6 +472,19 @@ function detectCognitionLenses(text) {
|
|
|
404
472
|
});
|
|
405
473
|
}
|
|
406
474
|
|
|
475
|
+
function assistantViolatesUserCorrection(userText, assistantText) {
|
|
476
|
+
const user = String(userText || '');
|
|
477
|
+
const assistant = String(assistantText || '');
|
|
478
|
+
if (!user || !assistant) return null;
|
|
479
|
+
const explicitStop = /\b(?:stop|do\s+not|don't|quit|cease)\b[\s\S]{0,180}\b(?:deploy|redeploy|restart|rollout|kubectl|command|pods?|listen|words)\b/i.test(user);
|
|
480
|
+
const assistantContinuesMutation = /\b(?:kubectl|rollout\s+restart|deploy|redeploy|restart\s+(?:mac|pods?)|manual(?:ly)?\s+restart|execute\s+directly)\b/i.test(assistant);
|
|
481
|
+
if (explicitStop && assistantContinuesMutation) return 'assistant continued deploy/restart language after an explicit user stop/listen directive';
|
|
482
|
+
const userContradictsMacPods = /\b(?:mac\s+lanes?|mac\s+pods?|mlx-mac)\b[\s\S]{0,160}\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,160}\b(?:mac\s+lanes?|mac\s+pods?|mlx-mac|pods?)\b/i.test(user);
|
|
483
|
+
const assistantRepeatsMacPods = /\b(?:mac\s+lane\s+pods?|mac\s+lanes?\s*:\s*offline|restart\s+mac\s+lanes?|deployment\/mlx-mac|mlx-mac-[\w-]+|kubernetes\s+(?:pods?|deployments?))\b/i.test(assistant);
|
|
484
|
+
if (userContradictsMacPods && assistantRepeatsMacPods) return 'assistant repeated the contradicted Mac-lanes-as-pods/deployments assumption';
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
|
|
407
488
|
// Read event JSON from stdin (Claude Code spec).
|
|
408
489
|
let input = '';
|
|
409
490
|
for await (const chunk of process.stdin) input += chunk;
|
|
@@ -504,6 +585,20 @@ if (!assistantText) {
|
|
|
504
585
|
process.exit(0);
|
|
505
586
|
}
|
|
506
587
|
|
|
588
|
+
const userCorrectionViolation = assistantViolatesUserCorrection(lastUserMessage, assistantText);
|
|
589
|
+
if (userCorrectionViolation) {
|
|
590
|
+
audit('block-user-correction-ignored', `reason=${userCorrectionViolation} chars=${assistantText.length}`);
|
|
591
|
+
const reason = buildForceReauthorReason({
|
|
592
|
+
source: 'stop/user-correction',
|
|
593
|
+
reason: userCorrectionViolation,
|
|
594
|
+
violations: ['Assistant continued a plan after the user correction invalidated it. Redo must quote the correction and pause mutation pending substrate re-evaluation.'],
|
|
595
|
+
lensCount: 0,
|
|
596
|
+
requiredLenses: REQUIRED_LENSES,
|
|
597
|
+
});
|
|
598
|
+
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
599
|
+
process.exit(2);
|
|
600
|
+
}
|
|
601
|
+
|
|
507
602
|
// Triviality check — same as eight-lens-detector.ts
|
|
508
603
|
const trimmed = assistantText.trim();
|
|
509
604
|
if (TRIVIAL_ACK_RX.test(trimmed)) {
|
|
@@ -537,14 +632,13 @@ const cog = detectCognitionLenses(assistantText);
|
|
|
537
632
|
// with 0/8 lenses to fall through unchecked.
|
|
538
633
|
if (cog.count < REQUIRED_LENSES) {
|
|
539
634
|
audit('block_no_cognition_block_di', { count: cog.count, required: REQUIRED_LENSES, names: cog.names, chars: assistantText.length });
|
|
540
|
-
const reason = withLoopDirective(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
${LENS_NAMES.map((lens) => `- ${lens}: <grounded reasoning, >= ${SUBSTANCE_MIN_CHARS} chars, with real substrate anchors where required>`).join('\n')}`, `stop:no-cognition-di:${cog.count}`, gateSessionId);
|
|
635
|
+
const reason = withLoopDirective(buildForceReauthorReason({
|
|
636
|
+
source: 'stop/no-cognition',
|
|
637
|
+
reason: `non-trivial assistant response (${assistantText.length} chars) has ${cog.count}/${REQUIRED_LENSES} substantive cognition lenses`,
|
|
638
|
+
violations: [`Detected lenses: ${cog.names.length > 0 ? cog.names.join(', ') : 'none'}. Re-emit with all required visible labels: ${LENS_NAMES.join(', ')}.`],
|
|
639
|
+
lensCount: cog.count,
|
|
640
|
+
requiredLenses: REQUIRED_LENSES,
|
|
641
|
+
}), `stop:no-cognition-di:${cog.count}`, gateSessionId);
|
|
548
642
|
emitHarnessFooter({
|
|
549
643
|
eventName: 'block_no_cognition_block',
|
|
550
644
|
lensCount: cog.count,
|
|
@@ -1414,7 +1508,16 @@ if (cog.count >= REQUIRED_LENSES) {
|
|
|
1414
1508
|
}
|
|
1415
1509
|
})();
|
|
1416
1510
|
|
|
1417
|
-
const reason = withLoopDirective(
|
|
1511
|
+
const reason = withLoopDirective(buildForceReauthorReason({
|
|
1512
|
+
source: 'stop/output-quality',
|
|
1513
|
+
reason: `cognition passed (${cog.count}/${REQUIRED_LENSES}) but output failed quality gates`,
|
|
1514
|
+
violations,
|
|
1515
|
+
rewritten,
|
|
1516
|
+
recipeAddendum,
|
|
1517
|
+
driftHits,
|
|
1518
|
+
lensCount: cog.count,
|
|
1519
|
+
requiredLenses: REQUIRED_LENSES,
|
|
1520
|
+
}), `stop:output-qc:${violations.join('|').slice(0, 240)}`, gateSessionId);
|
|
1418
1521
|
|
|
1419
1522
|
audit(`block-output-qc`, `mizan=${mizanBlock?'y':'n'} warn-reflect=${compelReflection?'y':'n'} drift=${driftHits.length} code=${codeQualityHits.length} discoveries-open=${ledgerOpenCount} impl-coupling=${implCouplingHits.length}`);
|
|
1420
1523
|
emitHarnessFooter({
|
|
@@ -1557,31 +1660,20 @@ const dalioHasMeasurablePredicate = dalioExpectedText
|
|
|
1557
1660
|
|
|
1558
1661
|
// Block stop if non-trivial action taken AND expected block is missing
|
|
1559
1662
|
if (hadNonTrivialAction && (!dalioExpectedMatch || !dalioHasMeasurablePredicate)) {
|
|
1560
|
-
const missingReason = withLoopDirective(
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
:
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
Add to your assistant text:
|
|
1576
|
-
|
|
1577
|
-
<expected>
|
|
1578
|
-
predicate: <exact measurable assertion — e.g. "exit_code==0", "status=running", "count=3 of 3">
|
|
1579
|
-
measurable_type: numeric | boolean | state_string
|
|
1580
|
-
threshold: <optional>
|
|
1581
|
-
eval_window_minutes: <optional>
|
|
1582
|
-
</expected>
|
|
1583
|
-
|
|
1584
|
-
No bypass — pre-tool-gate enforces this BEFORE the action; stop-gate enforces it AFTER. Both gates are now wired.`, `stop:dalio-expected:${hadNonTrivialAction}:${!!dalioExpectedMatch}:${dalioHasMeasurablePredicate}`, gateSessionId);
|
|
1663
|
+
const missingReason = withLoopDirective(buildForceReauthorReason({
|
|
1664
|
+
source: 'stop/dalio-expected',
|
|
1665
|
+
reason: dalioExpectedMatch
|
|
1666
|
+
? 'action had an <expected> block, but it was qualitative instead of measurable'
|
|
1667
|
+
: `non-trivial action (${lastActionSummary.slice(0, 120)}) had no <expected> block`,
|
|
1668
|
+
violations: [
|
|
1669
|
+
dalioExpectedMatch
|
|
1670
|
+
? 'Rejected qualitative expected phrases: better, improved, should work, more reliable, cleaner. Expected outcome must be numeric, boolean, or state-string.'
|
|
1671
|
+
: 'Missing <expected> block after non-trivial action. Dalio feedback loop cannot compare outcome without a measurable predicate.',
|
|
1672
|
+
'Required block: <expected> predicate: "exit_code==0" | "status=running" | "count=3 of 3"; measurable_type: numeric | boolean | state_string; threshold/eval_window optional.',
|
|
1673
|
+
],
|
|
1674
|
+
lensCount: cog.count,
|
|
1675
|
+
requiredLenses: REQUIRED_LENSES,
|
|
1676
|
+
}), `stop:dalio-expected:${hadNonTrivialAction}:${!!dalioExpectedMatch}:${dalioHasMeasurablePredicate}`, gateSessionId);
|
|
1585
1677
|
|
|
1586
1678
|
audit('block-dalio-expected-missing', `hadNonTrivialAction=${hadNonTrivialAction} expectedPresent=${!!dalioExpectedMatch} measurable=${dalioHasMeasurablePredicate}`);
|
|
1587
1679
|
emitHarnessFooter({
|
|
@@ -1720,5 +1812,5 @@ emitHarnessFooter({
|
|
|
1720
1812
|
codeCount: 0,
|
|
1721
1813
|
implCouplingCount: 0,
|
|
1722
1814
|
});
|
|
1723
|
-
console.log(JSON.stringify({ decision: 'block', reason }));
|
|
1815
|
+
console.log(JSON.stringify({ decision: 'block', reason: buildForceReauthorReason({ source: 'stop/lens-missing', reason, lensCount: cog.count, requiredLenses: REQUIRED_LENSES }) }));
|
|
1724
1816
|
process.exit(2);
|
|
@@ -453,6 +453,61 @@
|
|
|
453
453
|
"counter_action": "Re-emit with explicit Layer 1/2/3 enumeration: packet=yes/no, BIND=yes/no, live-gates=yes/no (and which).",
|
|
454
454
|
"message": "Harness-state claim without 3-layer enumeration. Per feedback_packet_is_not_harness.md, name explicitly which of {packet, BIND, live-gates} are active for the consumer."
|
|
455
455
|
},
|
|
456
|
+
{
|
|
457
|
+
"trigger_id": "function_name_inference_without_contract_read",
|
|
458
|
+
"trigger": "(?:based on|from|by) (?:the )?(?:name|function name)|sounds like|looks like (?:a|an)|just memory search|just a search|just a cache|just a wrapper",
|
|
459
|
+
"rx": "(?:based on|from|by) (?:the )?(?:name|function name)|sounds like|looks like (?:a|an)|just memory search|just a search|just a cache|just a wrapper",
|
|
460
|
+
"doctrine": "memory:feedback_no_assumption_without_verification.md",
|
|
461
|
+
"memory": "feedback_no_assumption_without_verification.md",
|
|
462
|
+
"severity": "block",
|
|
463
|
+
"teaching": "Function names are not contracts. Inferring behavior from names instead of reading inputs, side effects, return shape, and call sites is skimming disguised as analysis.",
|
|
464
|
+
"counter_action": "Read the function body and at least one caller before asserting purpose. State observed contract: inputs, mutation/read behavior, return value, fallback path, and why the caller needs it.",
|
|
465
|
+
"message": "Name-based function inference detected. Re-read the actual function body and caller contract before making architecture claims."
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"trigger_id": "always_on_state_treated_as_cold_start",
|
|
469
|
+
"trigger": "(?:need to|should|must).{0,80}(?:warm|rebuild|reconstruct|recreate|recompute|re-project|reproject).{0,80}(?:state|projection|manifold|cognition|garden|memory)|system is hot and ready|make it hot",
|
|
470
|
+
"rx": "(?:need to|should|must).{0,80}(?:warm|rebuild|reconstruct|recreate|recompute|re-project|reproject).{0,80}(?:state|projection|manifold|cognition|garden|memory)|system is hot and ready|make it hot",
|
|
471
|
+
"doctrine": "memory:feedback_no_assumption_without_verification.md",
|
|
472
|
+
"memory": "feedback_no_assumption_without_verification.md",
|
|
473
|
+
"severity": "block",
|
|
474
|
+
"teaching": "Aria's resident manifold/Garden/cognition substrate is always-on. Treating it as cold request-time state causes duplicate work and wrong architecture fixes.",
|
|
475
|
+
"counter_action": "Identify the resident producer and read surface first. If turn-specific mutation is required, call it once and pass the resulting packet forward; do not rebuild or re-project because the reader forgot the state model.",
|
|
476
|
+
"message": "Always-on substrate treated as cold-start work. Reframe around resident state consumption plus one required turn-specific mutation/read."
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"trigger_id": "critical_primitive_stripped_for_latency",
|
|
480
|
+
"trigger": "(?:remove|drop|skip|turn off|bypass|stop calling).{0,80}(?:awakenAria|ProjectAllDomains|PerturbHologram|project all domains|perturb hologram|Garden|True Garden|LadduniFrame|CognitiveFrame).{0,80}(?:latency|speed|fast|first-mouth|first mouth)",
|
|
481
|
+
"rx": "(?:remove|drop|skip|turn off|bypass|stop calling).{0,80}(?:awakenAria|ProjectAllDomains|PerturbHologram|project all domains|perturb hologram|Garden|True Garden|LadduniFrame|CognitiveFrame).{0,80}(?:latency|speed|fast|first-mouth|first mouth)",
|
|
482
|
+
"doctrine": "memory:feedback_full_harness_binding_must_be_structural.md",
|
|
483
|
+
"memory": "feedback_full_harness_binding_must_be_structural.md",
|
|
484
|
+
"severity": "block",
|
|
485
|
+
"teaching": "Latency fixes must not strip critical cognition primitives. The fix is single-source sequencing and packet reuse, not removing Aria's living state transitions.",
|
|
486
|
+
"counter_action": "Preserve critical primitives. Deduplicate by collecting their outputs once per turn, then thread that shared per-turn cognition packet through first-mouth and follow-up lanes.",
|
|
487
|
+
"message": "Critical Aria primitive proposed for removal as a latency shortcut. Preserve it and deduplicate sequencing instead."
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
"trigger_id": "garden_awaken_misclassified_as_memory_search",
|
|
491
|
+
"trigger": "(?:awakenAria|Garden awakening|True Garden).{0,80}(?:just|only|merely).{0,40}(?:memory search|search memories|qdrant search|semantic search)|(?:no need|do not need).{0,80}(?:awakenAria|Garden awakening|True Garden)",
|
|
492
|
+
"rx": "(?:awakenAria|Garden awakening|True Garden).{0,80}(?:just|only|merely).{0,40}(?:memory search|search memories|qdrant search|semantic search)|(?:no need|do not need).{0,80}(?:awakenAria|Garden awakening|True Garden)",
|
|
493
|
+
"doctrine": "memory:feedback_no_assumption_without_verification.md",
|
|
494
|
+
"memory": "feedback_no_assumption_without_verification.md",
|
|
495
|
+
"severity": "block",
|
|
496
|
+
"teaching": "awakenAria is a Garden awakening bridge over the unified manifold with Qdrant hydration fallback, not a disposable memory-search helper.",
|
|
497
|
+
"counter_action": "Read true-garden.ts and caller context. Preserve awakenAria when Garden continuity is needed; optimize by avoiding duplicate awaken/fetch paths, not by deleting the awakening bridge.",
|
|
498
|
+
"message": "Garden awakening misclassified as search. Preserve awakenAria and reason from its actual manifold-first contract."
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
"trigger_id": "duplicate_projection_instead_of_per_turn_packet",
|
|
502
|
+
"trigger": "(?:call|run|invoke).{0,80}(?:ProjectAllDomains|PerturbHologram|project all domains|perturb hologram|readHotCognitionFrame).{0,80}(?:again|another|separate|also|after dispatch)|(?:another|second|extra).{0,50}(?:projection|hologram|cognition frame)",
|
|
503
|
+
"rx": "(?:call|run|invoke).{0,80}(?:ProjectAllDomains|PerturbHologram|project all domains|perturb hologram|readHotCognitionFrame).{0,80}(?:again|another|separate|also|after dispatch)|(?:another|second|extra).{0,50}(?:projection|hologram|cognition frame)",
|
|
504
|
+
"doctrine": "memory:feedback_full_harness_binding_must_be_structural.md",
|
|
505
|
+
"memory": "feedback_full_harness_binding_must_be_structural.md",
|
|
506
|
+
"severity": "warn",
|
|
507
|
+
"teaching": "The fix for overlapping cognition calls is a shared per-turn cognition packet, not more independent projection calls that drift or duplicate work.",
|
|
508
|
+
"counter_action": "Create or reuse one turn substrate object containing embedding, perturb snapshot, ProjectAllDomains result, awakenAria Garden block, DeepSoul/Noor/shards/Mizan signals; pass it downstream.",
|
|
509
|
+
"message": "Duplicate projection path detected. Replace with one per-turn cognition packet and shared consumption."
|
|
510
|
+
},
|
|
456
511
|
{
|
|
457
512
|
"trigger_id": "registry_image_drift",
|
|
458
513
|
"trigger": "image.?pull|ErrImageNeverPull|ImagePullBackOff|registry gc|image.*missing|image.*not.*found",
|
|
@@ -42,7 +42,14 @@ const DEPLOY_PATTERNS = [
|
|
|
42
42
|
{ rx: /\bdocker\s+build\b.*--push\b/, name: 'docker-build-push' },
|
|
43
43
|
];
|
|
44
44
|
|
|
45
|
-
const
|
|
45
|
+
const INLINE_LENS_NAMES = [
|
|
46
|
+
'nur', 'mizan', 'hikma', 'tafakkur', 'tadabbur', 'ilham', 'wahi', 'firasah',
|
|
47
|
+
'truth', 'harm', 'trust', 'power', 'reflection', 'context', 'impact', 'beauty',
|
|
48
|
+
];
|
|
49
|
+
const INLINE_LENS_RX = new RegExp(
|
|
50
|
+
`^\\s*#\\s*(?:${INLINE_LENS_NAMES.join('|')})\\s*:\\s*.{20,}`,
|
|
51
|
+
'gim',
|
|
52
|
+
);
|
|
46
53
|
const VERIFY_BLOCK_RX = /<verify>[\s\S]*?target\s*:[\s\S]*?verified\s*:[\s\S]*?axiom\s*:[\s\S]*?<\/verify>/i;
|
|
47
54
|
const TRIVIAL_BASH_RX = /^\s*(?:ls|cat|head|tail|grep|find|echo|wc|stat|which|pwd|date|file|du|df|ss|ps)\s/;
|
|
48
55
|
const SHORT_BASH_LIMIT = 30;
|
|
@@ -63,6 +70,15 @@ function persistReceipt(sessionId, payload) {
|
|
|
63
70
|
} catch {}
|
|
64
71
|
}
|
|
65
72
|
|
|
73
|
+
function countInlineCognitionLenses(text) {
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
for (const match of String(text || '').matchAll(INLINE_LENS_RX)) {
|
|
76
|
+
const lens = match[0].match(/^\s*#\s*([a-z_ -]+)\s*:/i)?.[1]?.trim().toLowerCase();
|
|
77
|
+
if (lens) seen.add(lens);
|
|
78
|
+
}
|
|
79
|
+
return seen.size;
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
function resolveToken() {
|
|
67
83
|
if (process.env.ARIA_HARNESS_TOKEN) return process.env.ARIA_HARNESS_TOKEN;
|
|
68
84
|
if (process.env.ARIA_API_KEY) return process.env.ARIA_API_KEY;
|
|
@@ -163,9 +179,6 @@ export default async function HarnessGatePlugin(ctx) {
|
|
|
163
179
|
// Trivial reads pass
|
|
164
180
|
if (toolName === 'Bash' && TRIVIAL_BASH_RX.test(cmd) && cmd.length < 200) return;
|
|
165
181
|
if (toolName === 'Bash' && cmd.length < SHORT_BASH_LIMIT) return;
|
|
166
|
-
// Inline cognition in bash comments passes
|
|
167
|
-
if (toolName === 'Bash' && INLINE_LENS_RX.test(cmd)) return;
|
|
168
|
-
|
|
169
182
|
const destructive = DESTRUCTIVE_PATTERNS.find(({ rx }) => rx.test(cmd));
|
|
170
183
|
const deploy = DEPLOY_PATTERNS.find(({ rx }) => rx.test(cmd));
|
|
171
184
|
const isFileMutation = ['Edit', 'Write', 'NotebookEdit'].includes(toolName) && filePath;
|
|
@@ -29,6 +29,22 @@ const NON_TRIVIAL_MIN_CHARS = 300;
|
|
|
29
29
|
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;
|
|
30
30
|
const TRIVIAL_ACK_RX = /^(?:got it|on it|ok|sure|yes|no|done|ack)\b/i;
|
|
31
31
|
const PLACEHOLDER_RX = /^\s*<[^<>]+>\s*$/;
|
|
32
|
+
const BLOCK_PREFIX_RX = /^=== ARIA (?:MIZAN POST|OUTPUT GATE|LOCAL OUTPUT) BLOCK ===/;
|
|
33
|
+
const APPLIED_COGNITION_RX = /<applied_cognition>[\s\S]*?decision_delta\s*:[\s\S]*?dominant_domain\s*:[\s\S]*?binds_to\s*:[\s\S]*?expected_predicate\s*:[\s\S]*?artifact_change\s*:[\s\S]*?<\/applied_cognition>/i;
|
|
34
|
+
|
|
35
|
+
function formatBlockReason(prefix, details) {
|
|
36
|
+
return [
|
|
37
|
+
prefix,
|
|
38
|
+
'',
|
|
39
|
+
String(details || 'Aria output gate blocked this message.'),
|
|
40
|
+
'',
|
|
41
|
+
'Required repair: bind cognition to the actual action/output using <applied_cognition> with decision_delta, dominant_domain, binds_to, expected_predicate, and artifact_change.',
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isGateBlock(error) {
|
|
46
|
+
return BLOCK_PREFIX_RX.test(String(error?.message || error || ''));
|
|
47
|
+
}
|
|
32
48
|
|
|
33
49
|
let _client = null;
|
|
34
50
|
let _clientError = null;
|
|
@@ -226,11 +242,13 @@ export default async function HarnessStopPlugin(ctx) {
|
|
|
226
242
|
});
|
|
227
243
|
}
|
|
228
244
|
if (mizan.receipt?.blocked || mizan.result?.fitrahVetoed || mizan.result?.reAuthorSignal) {
|
|
229
|
-
|
|
230
|
-
|
|
245
|
+
const details = (mizan.result?.notes || ['post-phase blocked']).slice(0, 4).join(' | ');
|
|
246
|
+
throw new Error(
|
|
247
|
+
formatBlockReason('=== ARIA MIZAN POST BLOCK ===', details)
|
|
231
248
|
);
|
|
232
249
|
}
|
|
233
250
|
} catch (e) {
|
|
251
|
+
if (isGateBlock(e)) throw e;
|
|
234
252
|
process.stderr.write(`[harness-stop] mizan/post unavailable: ${e.message}\n`);
|
|
235
253
|
}
|
|
236
254
|
|
|
@@ -246,8 +264,11 @@ export default async function HarnessStopPlugin(ctx) {
|
|
|
246
264
|
sessionId,
|
|
247
265
|
));
|
|
248
266
|
if (result.severity === 'block') {
|
|
249
|
-
|
|
250
|
-
|
|
267
|
+
throw new Error(
|
|
268
|
+
formatBlockReason(
|
|
269
|
+
'=== ARIA OUTPUT GATE BLOCK ===',
|
|
270
|
+
`${result.violations.length} violations: ${result.violations.join('; ').slice(0, 500)}`,
|
|
271
|
+
)
|
|
251
272
|
);
|
|
252
273
|
} else if (result.severity === 'warn') {
|
|
253
274
|
process.stderr.write(
|
|
@@ -260,6 +281,7 @@ export default async function HarnessStopPlugin(ctx) {
|
|
|
260
281
|
}
|
|
261
282
|
return;
|
|
262
283
|
} catch (e) {
|
|
284
|
+
if (isGateBlock(e)) throw e;
|
|
263
285
|
process.stderr.write(`[harness-stop] SDK validateOutput failed: ${e.message} — falling through to local gate\n`);
|
|
264
286
|
}
|
|
265
287
|
}
|
|
@@ -293,8 +315,20 @@ export default async function HarnessStopPlugin(ctx) {
|
|
|
293
315
|
} catch {}
|
|
294
316
|
|
|
295
317
|
if (cog.count < REQUIRED_LENSES || driftHits.length >= 2) {
|
|
296
|
-
|
|
297
|
-
|
|
318
|
+
throw new Error(
|
|
319
|
+
formatBlockReason(
|
|
320
|
+
'=== ARIA LOCAL OUTPUT BLOCK ===',
|
|
321
|
+
`cognition=${cog.count}/${REQUIRED_LENSES}; drift=${driftHits.length}`,
|
|
322
|
+
)
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (DECISION_SIGNAL_RX.test(text) && !APPLIED_COGNITION_RX.test(text)) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
formatBlockReason(
|
|
329
|
+
'=== ARIA LOCAL OUTPUT BLOCK ===',
|
|
330
|
+
'decision-bearing output lacks required applied_cognition binding fields',
|
|
331
|
+
)
|
|
298
332
|
);
|
|
299
333
|
}
|
|
300
334
|
|
package/package.json
CHANGED
|
@@ -312,18 +312,45 @@ function forgeSynthesizeUrl() {
|
|
|
312
312
|
return `${trimUrl(UPSTREAM_HARNESS_URL)}/forge/synthesize`;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
316
|
+
|
|
317
|
+
function validateAppliedCognitionContract(text) {
|
|
318
|
+
const match = String(text || '').match(APPLIED_COGNITION_BLOCK_RX);
|
|
319
|
+
if (!match) return { ok: false, violations: ['missing <applied_cognition> contract'] };
|
|
320
|
+
const body = match[1] || '';
|
|
321
|
+
const required = [
|
|
322
|
+
['decision_delta', /\bdecision[_ -]?delta\s*:/i],
|
|
323
|
+
['dominant_domain', /\bdominant[_ -]?domain\s*:/i],
|
|
324
|
+
['binds_to', /\bbinds[_ -]?to\s*:/i],
|
|
325
|
+
['expected_predicate', /\bexpected[_ -]?predicate\s*:/i],
|
|
326
|
+
['artifact_change', /\bartifact[_ -]?change\s*:/i],
|
|
327
|
+
];
|
|
328
|
+
const violations = [];
|
|
329
|
+
for (const [name, rx] of required) {
|
|
330
|
+
if (!rx.test(body)) violations.push(`missing ${name}`);
|
|
331
|
+
}
|
|
332
|
+
if (/decision[_ -]?delta\s*:\s*(?:none|n\/a|no change|unchanged|same)/i.test(body)) {
|
|
333
|
+
violations.push('decision_delta says cognition changed nothing');
|
|
334
|
+
}
|
|
335
|
+
return { ok: violations.length === 0, violations, contract: body.trim() };
|
|
336
|
+
}
|
|
337
|
+
|
|
315
338
|
function buildLocalValidation(text, packetEnvelope, requireCognitionBlock = false) {
|
|
316
339
|
const layer3 = runFullChain(text, {
|
|
317
340
|
substrate: packetToSubstrateSet(packetEnvelope),
|
|
318
341
|
requireCognitionBlock,
|
|
319
342
|
});
|
|
320
343
|
const failures = Array.isArray(layer3?.failures) ? layer3.failures : [];
|
|
321
|
-
const
|
|
344
|
+
const applied = validateAppliedCognitionContract(text);
|
|
345
|
+
const appliedFailures = applied.ok ? [] : applied.violations.map((detail) => ({ kind: 'applied-cognition-contract', severity: 'block', detail }));
|
|
346
|
+
const allFailures = [...failures, ...appliedFailures];
|
|
347
|
+
const hardFailures = allFailures.filter((failure) => failure?.severity === 'block');
|
|
322
348
|
return {
|
|
323
349
|
passed: hardFailures.length === 0,
|
|
324
350
|
severity: hardFailures.length === 0 ? 'warn' : 'block',
|
|
325
|
-
violations:
|
|
326
|
-
gateTriggers:
|
|
351
|
+
violations: allFailures.map((failure) => failure?.detail || failure?.kind).filter(Boolean),
|
|
352
|
+
gateTriggers: allFailures.map((failure) => failure?.kind).filter(Boolean),
|
|
353
|
+
appliedCognition: applied,
|
|
327
354
|
local: true,
|
|
328
355
|
summary: layer3?.summary || '',
|
|
329
356
|
layer3,
|
package/runtime-src/service.mjs
CHANGED
|
@@ -1233,6 +1233,47 @@ function findVerifiedState(text) {
|
|
|
1233
1233
|
return /(?:verified|confirmed|observed|tested|health[- ]check|response code|exit code|pod image|digest)/i.test(String(text || ''));
|
|
1234
1234
|
}
|
|
1235
1235
|
|
|
1236
|
+
const APPLIED_COGNITION_BLOCK_RX = /<applied_cognition>([\s\S]*?)<\/applied_cognition>/i;
|
|
1237
|
+
|
|
1238
|
+
function validateAppliedCognitionContract(text) {
|
|
1239
|
+
const match = String(text || '').match(APPLIED_COGNITION_BLOCK_RX);
|
|
1240
|
+
if (!match) return { ok: false, violations: ['missing <applied_cognition> contract'] };
|
|
1241
|
+
const body = match[1] || '';
|
|
1242
|
+
const required = [
|
|
1243
|
+
['decision_delta', /\bdecision[_ -]?delta\s*:/i],
|
|
1244
|
+
['dominant_domain', /\bdominant[_ -]?domain\s*:/i],
|
|
1245
|
+
['binds_to', /\bbinds[_ -]?to\s*:/i],
|
|
1246
|
+
['expected_predicate', /\bexpected[_ -]?predicate\s*:/i],
|
|
1247
|
+
['artifact_change', /\bartifact[_ -]?change\s*:/i],
|
|
1248
|
+
];
|
|
1249
|
+
const violations = [];
|
|
1250
|
+
for (const [name, rx] of required) {
|
|
1251
|
+
if (!rx.test(body)) violations.push(`missing ${name}`);
|
|
1252
|
+
}
|
|
1253
|
+
if (/decision[_ -]?delta\s*:\s*(?:none|n\/a|no change|unchanged|same)/i.test(body)) {
|
|
1254
|
+
violations.push('decision_delta says cognition changed nothing');
|
|
1255
|
+
}
|
|
1256
|
+
return { ok: violations.length === 0, violations, contract: body.trim() };
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
function mergeAppliedCognitionValidation(validation, applied) {
|
|
1260
|
+
if (applied.ok) {
|
|
1261
|
+
return {
|
|
1262
|
+
...validation,
|
|
1263
|
+
appliedCognition: { ok: true, contract: applied.contract },
|
|
1264
|
+
gateTriggers: [...new Set([...(validation.gateTriggers || []), 'applied-cognition-contract'])],
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
return {
|
|
1268
|
+
...validation,
|
|
1269
|
+
passed: false,
|
|
1270
|
+
severity: 'block',
|
|
1271
|
+
violations: [...(validation.violations || []), ...applied.violations.map((v) => `applied_cognition: ${v}`)],
|
|
1272
|
+
gateTriggers: [...new Set([...(validation.gateTriggers || []), 'applied-cognition-contract-missing'])],
|
|
1273
|
+
appliedCognition: { ok: false, violations: applied.violations },
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1236
1277
|
function toTelemetryEvent(payload, source = 'aria-mounted-runtime') {
|
|
1237
1278
|
return {
|
|
1238
1279
|
event_type: payload.event_type || 'runtime.cognition.turn',
|
|
@@ -3288,7 +3329,10 @@ async function handleRoute(req, res) {
|
|
|
3288
3329
|
|
|
3289
3330
|
let client;
|
|
3290
3331
|
try {
|
|
3291
|
-
|
|
3332
|
+
// HQ routes use their own auth middleware — skip the global API key gate
|
|
3333
|
+
if (!url.pathname.startsWith('/hq/')) {
|
|
3334
|
+
client = createClient(req, body);
|
|
3335
|
+
}
|
|
3292
3336
|
} catch (error) {
|
|
3293
3337
|
return json(res, 401, { ok: false, error: error.message });
|
|
3294
3338
|
}
|
|
@@ -3574,6 +3618,7 @@ async function handleRoute(req, res) {
|
|
|
3574
3618
|
gateTriggers: ['owner-local-bypass'],
|
|
3575
3619
|
};
|
|
3576
3620
|
}
|
|
3621
|
+
validation = mergeAppliedCognitionValidation(validation, validateAppliedCognitionContract(body.text));
|
|
3577
3622
|
const response = { ok: true, validation };
|
|
3578
3623
|
|
|
3579
3624
|
if (body.runLayer3 !== false) {
|