@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.
Files changed (52) hide show
  1. package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
  2. package/dist/aria-connector/src/connectors/claude-code.js +30 -3
  3. package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
  4. package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
  5. package/dist/aria-connector/src/connectors/codex.js +25 -9
  6. package/dist/aria-connector/src/connectors/codex.js.map +1 -1
  7. package/dist/aria-connector/src/connectors/must-read.d.ts.map +1 -1
  8. package/dist/aria-connector/src/connectors/must-read.js +4 -0
  9. package/dist/aria-connector/src/connectors/must-read.js.map +1 -1
  10. package/dist/aria-connector/src/connectors/opencode.js +25 -9
  11. package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
  12. package/dist/assets/hooks/aria-agent-handoff.mjs +23 -0
  13. package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +69 -3
  14. package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +35 -0
  15. package/dist/assets/hooks/aria-pre-tool-gate.mjs +198 -17
  16. package/dist/assets/hooks/aria-preprompt-consult.mjs +28 -2
  17. package/dist/assets/hooks/aria-preturn-memory-gate.mjs +30 -2
  18. package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +31 -1
  19. package/dist/assets/hooks/aria-stop-gate.mjs +127 -35
  20. package/dist/assets/hooks/doctrine_trigger_map.json +55 -0
  21. package/dist/assets/opencode-plugins/harness-gate/index.js +17 -4
  22. package/dist/assets/opencode-plugins/harness-stop/index.js +40 -6
  23. package/dist/runtime/discipline/CLAUDE.md +16 -0
  24. package/dist/runtime/discipline/doctrine_trigger_map.json +55 -0
  25. package/dist/runtime/doctrine_trigger_map.json +55 -0
  26. package/dist/runtime/harness-daemon.mjs +30 -3
  27. package/dist/runtime/manifest.json +1 -1
  28. package/dist/runtime/sdk/BUNDLED.json +1 -1
  29. package/dist/runtime/sdk/index.d.ts +5 -0
  30. package/dist/runtime/sdk/index.js.map +1 -1
  31. package/dist/runtime/service.mjs +46 -1
  32. package/dist/sdk/BUNDLED.json +1 -1
  33. package/dist/sdk/index.d.ts +5 -0
  34. package/dist/sdk/index.js.map +1 -1
  35. package/hooks/aria-agent-handoff.mjs +23 -0
  36. package/hooks/aria-cognition-substrate-binding.mjs +69 -3
  37. package/hooks/aria-pre-emit-dryrun.mjs +35 -0
  38. package/hooks/aria-pre-tool-gate.mjs +198 -17
  39. package/hooks/aria-preprompt-consult.mjs +28 -2
  40. package/hooks/aria-preturn-memory-gate.mjs +30 -2
  41. package/hooks/aria-repo-doctrine-gate.mjs +31 -1
  42. package/hooks/aria-stop-gate.mjs +127 -35
  43. package/hooks/doctrine_trigger_map.json +55 -0
  44. package/opencode-plugins/harness-gate/index.js +17 -4
  45. package/opencode-plugins/harness-stop/index.js +40 -6
  46. package/package.json +1 -1
  47. package/runtime-src/harness-daemon.mjs +30 -3
  48. package/runtime-src/service.mjs +46 -1
  49. package/src/connectors/claude-code.ts +31 -3
  50. package/src/connectors/codex.ts +25 -9
  51. package/src/connectors/must-read.ts +4 -0
  52. package/src/connectors/opencode.ts +25 -9
@@ -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(`Aria stop-gate: insufficient cognition lenses.
541
-
542
- This non-trivial assistant response (${assistantText.length} chars) has ${cog.count}/${REQUIRED_LENSES} substantive cognition lenses. Per feedback_8lens_before_every_action_including_text.md and Hamza directive 2026-04-28, every non-trivial response must carry <cognition>...</cognition> with ${REQUIRED_LENSES} substantive lenses (each >= ${SUBSTANCE_MIN_CHARS} chars of non-placeholder content).
543
-
544
- Detected lenses: ${cog.names.length > 0 ? cog.names.join(', ') : 'none'}.
545
-
546
- Re-emit with a <cognition> block containing all ${REQUIRED_LENSES} required visible labels for this surface:
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(`Aria Stop-gate output-quality block. Cognition passed (${cog.count}/${REQUIRED_LENSES}) but output failed quality gates:\n\n${violations.join('\n\n')}${rewritten ? `\n\nMizan rewrite suggestion:\n${rewritten}` : ''}\n\nRe-draft addressing the violations above. No process-level disable path — gates are unconditional from the gated process per Hamza directive 2026-04-27.${recipeAddendum}`, `stop:output-qc:${violations.join('|').slice(0, 240)}`, gateSessionId);
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(dalioExpectedMatch
1561
- ? `Aria Stop-gate: action taken in this turn had an <expected> block, but it contains only qualitative drift phrases without a measurable predicate. Qualitative drift is not accountability — it defeats the Dalio feedback loop.
1562
-
1563
- Your <expected> block must contain at least one measurable predicate:
1564
- Numeric: exit_code==0, count>=1, error_rate=0%, latency<200ms
1565
- • Boolean: exit=0, status=healthy, rc=0, file=exists
1566
- • State-string: "status=running", "200 OK", "no_error"
1567
-
1568
- REJECTED phrases: "better", "improved", "should work", "more reliable", "cleaner"
1569
-
1570
- Re-emit with a corrected <expected> block. Per doctrine:dalio_expected_required — no bypass path.`
1571
- : `Aria Stop-gate: a non-trivial action (${lastActionSummary.slice(0, 120)}) was taken in this turn but no <expected> block was found in the assistant text.
1572
-
1573
- Per doctrine:dalio_expected_required, every non-trivial action must declare what measurable outcome it expects BEFORE the action fires. This is Dalio Loop Layer 1 — without it, outcome comparison is impossible and learning collapses.
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 INLINE_LENS_RX = /^\s*#\s*(?:nur|mizan|hikma|tafakkur|tadabbur|ilham|wahi|firasah|truth|harm|trust|power|reflection|context|impact|beauty)\s*:\s*.{20,}/im;
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
- process.stderr.write(
230
- `[harness-stop] MIZAN POST BLOCK — ${(mizan.result?.notes || ['post-phase blocked']).slice(0, 4).join(' | ')}\n`
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
- process.stderr.write(
250
- `[harness-stop] SDK BLOCK — ${result.violations.length} violations: ${result.violations.join('; ').slice(0, 300)}\n`
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
- process.stderr.write(
297
- `[harness-stop] LOCAL GATE — cognition=${cog.count}/${REQUIRED_LENSES} drift=${driftHits.length}\n`
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
 
@@ -164,6 +164,22 @@ Every non-trivial assistant turn must satisfy all three.
164
164
 
165
165
  **REJECTED (qualitative drift):** `better`, `improved`, `should work`, `more reliable`, `cleaner`, `nicer`. These are unmeasurable.
166
166
 
167
+ ### `<applied_cognition>` — required with every non-trivial cognition block
168
+
169
+ The cognition block is not accepted as proof by itself. It must bind to a concrete action or output claim and state what changed because cognition ran.
170
+
171
+ ```
172
+ <applied_cognition>
173
+ decision_delta: <what changed because cognition ran; not "none">
174
+ dominant_domain: <engineering_quality | trust | operations | security | product | ...>
175
+ binds_to: <the next tool/action/output claim this cognition constrains>
176
+ expected_predicate: <numeric, boolean, or state-string predicate proving success>
177
+ artifact_change: <how the produced artifact/action/output differs because cognition ran>
178
+ </applied_cognition>
179
+ ```
180
+
181
+ **Rejected:** missing fields, `decision_delta: none`, or a contract that does not bind to the next action/output. This is the structural enforcement for apply-lenses-don't-perform.
182
+
167
183
  ### `<verify>` — required for deploy commands
168
184
 
169
185
  A deploy is anything matching `deploy-service.sh|kubectl apply -f|kubectl set image|docker push|trivial deploy|fast path deploy`. Without a verify block, the pre-tool-gate hard-blocks.
@@ -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",
@@ -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",
@@ -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 hardFailures = failures.filter((failure) => failure?.severity === 'block');
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: failures.map((failure) => failure?.detail || failure?.kind).filter(Boolean),
326
- gateTriggers: failures.map((failure) => failure?.kind).filter(Boolean),
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,
@@ -1,5 +1,5 @@
1
1
  {
2
- "bundledAt": "2026-04-30T13:56:07.672Z",
2
+ "bundledAt": "2026-05-01T20:07:31.761Z",
3
3
  "sdkFiles": 6,
4
4
  "runtimeTemplate": "/home/hamzaibrahim1/rei-ai-brain/packages/aria-connector/runtime-src",
5
5
  "gateRuntimeSource": "/home/hamzaibrahim1/rei-ai-brain/packages/aria-gate-runtime/dist",
@@ -1,5 +1,5 @@
1
1
  {
2
- "bundledAt": "2026-04-30T13:56:07.664Z",
2
+ "bundledAt": "2026-05-01T20:07:31.757Z",
3
3
  "sdkSource": "/home/hamzaibrahim1/rei-ai-brain/harness/packages/harness-http-client/dist",
4
4
  "files": 6
5
5
  }