@aria_asi/cli 0.2.40 → 0.2.41
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/bin/aria.js +236 -34
- package/dist/aria-connector/src/action-ledger-core.d.ts +387 -0
- package/dist/aria-connector/src/action-ledger-core.d.ts.map +1 -0
- package/dist/aria-connector/src/action-ledger-core.js +638 -0
- package/dist/aria-connector/src/action-ledger-core.js.map +1 -0
- package/dist/aria-connector/src/chat.d.ts.map +1 -1
- package/dist/aria-connector/src/chat.js +5 -6
- package/dist/aria-connector/src/chat.js.map +1 -1
- package/dist/aria-connector/src/codebase-scanner.d.ts +1 -1
- package/dist/aria-connector/src/codebase-scanner.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.d.ts +1 -0
- package/dist/aria-connector/src/connectors/claude-code.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/claude-code.js +152 -14
- package/dist/aria-connector/src/connectors/claude-code.js.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts +10 -0
- package/dist/aria-connector/src/connectors/codebase-awareness.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codebase-awareness.js +276 -27
- package/dist/aria-connector/src/connectors/codebase-awareness.js.map +1 -1
- package/dist/aria-connector/src/connectors/codex.d.ts +3 -1
- package/dist/aria-connector/src/connectors/codex.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/codex.js +1223 -41
- package/dist/aria-connector/src/connectors/codex.js.map +1 -1
- package/dist/aria-connector/src/connectors/cursor.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/cursor.js +7 -0
- package/dist/aria-connector/src/connectors/cursor.js.map +1 -1
- package/dist/aria-connector/src/connectors/governed-adapter.d.ts +30 -0
- package/dist/aria-connector/src/connectors/governed-adapter.d.ts.map +1 -0
- package/dist/aria-connector/src/connectors/governed-adapter.js +132 -0
- package/dist/aria-connector/src/connectors/governed-adapter.js.map +1 -0
- package/dist/aria-connector/src/connectors/opencode.d.ts +3 -1
- package/dist/aria-connector/src/connectors/opencode.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/opencode.js +18 -2
- package/dist/aria-connector/src/connectors/opencode.js.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/repo-guard.js +25 -14
- package/dist/aria-connector/src/connectors/repo-guard.js.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/runtime.js +92 -2
- package/dist/aria-connector/src/connectors/runtime.js.map +1 -1
- package/dist/aria-connector/src/connectors/shell.d.ts.map +1 -1
- package/dist/aria-connector/src/connectors/shell.js +123 -7
- package/dist/aria-connector/src/connectors/shell.js.map +1 -1
- package/dist/aria-connector/src/cross-cli-hive-binding.d.ts +63 -0
- package/dist/aria-connector/src/cross-cli-hive-binding.d.ts.map +1 -0
- package/dist/aria-connector/src/cross-cli-hive-binding.js +205 -0
- package/dist/aria-connector/src/cross-cli-hive-binding.js.map +1 -0
- package/dist/aria-connector/src/garden-control-plane.d.ts +6 -1
- package/dist/aria-connector/src/garden-control-plane.d.ts.map +1 -1
- package/dist/aria-connector/src/garden-control-plane.js +8 -2
- package/dist/aria-connector/src/garden-control-plane.js.map +1 -1
- package/dist/aria-connector/src/governed-surface-runner.d.ts +189 -0
- package/dist/aria-connector/src/governed-surface-runner.d.ts.map +1 -0
- package/dist/aria-connector/src/governed-surface-runner.js +1022 -0
- package/dist/aria-connector/src/governed-surface-runner.js.map +1 -0
- package/dist/aria-connector/src/index.d.ts +10 -1
- package/dist/aria-connector/src/index.d.ts.map +1 -1
- package/dist/aria-connector/src/index.js +5 -0
- package/dist/aria-connector/src/index.js.map +1 -1
- package/dist/aria-connector/src/task-runner.d.ts +3 -0
- package/dist/aria-connector/src/task-runner.d.ts.map +1 -0
- package/dist/aria-connector/src/task-runner.js +3526 -0
- package/dist/aria-connector/src/task-runner.js.map +1 -0
- package/dist/aria-web/src/lib/codebase-scanner.d.ts +21 -2
- package/dist/aria-web/src/lib/codebase-scanner.d.ts.map +1 -1
- package/dist/aria-web/src/lib/codebase-scanner.js +59 -14
- package/dist/aria-web/src/lib/codebase-scanner.js.map +1 -1
- package/dist/assets/hooks/README.md +58 -0
- package/dist/assets/hooks/aria-agent-handoff.mjs +147 -2
- package/dist/assets/hooks/aria-agent-ledger-merge.mjs +31 -7
- package/dist/assets/hooks/aria-architect-fallback.mjs +10 -2
- package/dist/assets/hooks/aria-claim-evidence-stop-gate.mjs +240 -0
- package/dist/assets/hooks/aria-cognition-substrate-binding.mjs +84 -10
- package/dist/assets/hooks/aria-first-class-coach.mjs +305 -10
- package/dist/assets/hooks/aria-harness-via-sdk.mjs +93 -16
- package/dist/assets/hooks/aria-import-resolution-gate.mjs +106 -20
- package/dist/assets/hooks/aria-outcome-record.mjs +56 -20
- package/dist/assets/hooks/aria-pre-emit-autoload.mjs +1809 -0
- package/dist/assets/hooks/aria-pre-emit-autoload.mjs.before-orchestration-redesign +1400 -0
- package/dist/assets/hooks/aria-pre-emit-dryrun.mjs +22 -3
- package/dist/assets/hooks/aria-pre-text-gate.mjs +11 -2
- package/dist/assets/hooks/aria-pre-tool-gate.mjs +477 -81
- package/dist/assets/hooks/aria-pre-tool-use.mjs +70 -6
- package/dist/assets/hooks/aria-preprompt-consult.mjs +23 -4
- package/dist/assets/hooks/aria-repo-doctrine-gate.mjs +29 -3
- package/dist/assets/hooks/aria-stop-gate.mjs +585 -76
- package/dist/assets/hooks/aria-trigger-autolearn.mjs +17 -3
- package/dist/assets/hooks/aria-universal-turn-packet.mjs +1165 -0
- package/dist/assets/hooks/aria-userprompt-abandon-detect.mjs +9 -1
- package/dist/assets/hooks/canonical-settings-block.json +172 -0
- package/dist/assets/hooks/codex-native/aria-harness-ticker-sidecar.mjs +92 -0
- package/dist/assets/hooks/codex-native/aria-hive-wal-consumer.mjs +86 -0
- package/dist/assets/hooks/codex-native/aria-live-ticker.mjs +38 -0
- package/dist/assets/hooks/codex-native/aria-post-tool-use.mjs +236 -0
- package/dist/assets/hooks/codex-native/aria-pre-tool-use.mjs +362 -0
- package/dist/assets/hooks/codex-native/aria-stop.mjs +691 -0
- package/dist/assets/hooks/codex-native/aria-userprompt-submit.mjs +623 -0
- package/dist/assets/hooks/codex-native/atlas-session-context.mjs +121 -0
- package/dist/assets/hooks/codex-native/lib/evaluate-with-kernel.mjs +257 -0
- package/dist/assets/hooks/codex-native/lib/hive-wal-consumer.mjs +452 -0
- package/dist/assets/hooks/codex-native/lib/kernel/deterministic-cognitive-kernel.mjs +914 -0
- package/dist/assets/hooks/codex-native/lib/project-boundary-cognition.mjs +143 -0
- package/dist/assets/hooks/codex-native/lib/runtime-client.mjs +3567 -0
- package/dist/assets/hooks/codex-native/lib/task-project-ledger.mjs +294 -0
- package/dist/assets/hooks/doctrine_trigger_map.json +236 -25
- package/dist/assets/hooks/doctrine_trigger_map.schema.json +46 -0
- package/dist/assets/hooks/install.sh +84 -0
- package/dist/assets/hooks/lib/action-ledger-core.mjs +269 -0
- package/dist/assets/hooks/lib/aria-gate-ledger.mjs +143 -0
- package/dist/assets/hooks/lib/ast-stub-shape-detector.mjs +107 -0
- package/dist/assets/hooks/lib/atlas-dossier-client.mjs +151 -0
- package/dist/assets/hooks/lib/atlas-orchestrator-postwire.mjs +221 -0
- package/dist/assets/hooks/lib/canonical-lenses.mjs +83 -6
- package/dist/assets/hooks/lib/coach-intent-classifier.mjs +248 -0
- package/dist/assets/hooks/lib/cognitive-block-parser.mjs +111 -0
- package/dist/assets/hooks/lib/doctrine-trigger-map-loader.mjs +137 -0
- package/dist/assets/hooks/lib/domain-output-quality.mjs +132 -3
- package/dist/assets/hooks/lib/empty-catch-scanner.mjs +91 -0
- package/dist/assets/hooks/lib/end-phase-qa-autofire.mjs +426 -0
- package/dist/assets/hooks/lib/evaluate-with-kernel.mjs +133 -0
- package/dist/assets/hooks/lib/first-class-coach.mjs +454 -19
- package/dist/assets/hooks/lib/gate-audit.mjs +12 -2
- package/dist/assets/hooks/lib/gate-loop-state.mjs +11 -2
- package/dist/assets/hooks/lib/goal-contract-quality.mjs +302 -0
- package/dist/assets/hooks/lib/hook-message-window.mjs +101 -9
- package/dist/assets/hooks/lib/invocation-required-verifier.mjs +184 -0
- package/dist/assets/hooks/lib/kernel/deterministic-cognitive-kernel.mjs +906 -0
- package/dist/assets/hooks/lib/obligation-ledger.mjs +147 -0
- package/dist/assets/hooks/lib/orchestration-manifest-extract.mjs +217 -0
- package/dist/assets/hooks/lib/owner-authorizations.mjs +269 -0
- package/dist/assets/hooks/lib/probe-discipline-scanner.mjs +142 -0
- package/dist/assets/hooks/lib/project-boundary-cognition.mjs +143 -0
- package/dist/assets/hooks/lib/recovery-context.mjs +151 -0
- package/dist/assets/hooks/lib/recovery-template-loader.mjs +154 -0
- package/dist/assets/hooks/lib/self-doctrine-check.mjs +321 -0
- package/dist/assets/hooks/lib/sensitive-shape-detector.mjs +64 -0
- package/dist/assets/hooks/lib/skill-autoload-gate-impl.mjs +226 -1
- package/dist/assets/hooks/lib/stop-hook-protocol.mjs +166 -0
- package/dist/assets/hooks/lib/surface-caught.mjs +94 -0
- package/dist/assets/hooks/recovery-templates/force-reauthor.md +67 -0
- package/dist/assets/hooks/recovery-templates/handoff-recovery.md +25 -0
- package/dist/assets/hooks/scripts/check-hard-risk-prefix.mjs +99 -0
- package/dist/assets/hooks/skills/aria-conversational-doctrine-discipline/SKILL.md +101 -0
- package/dist/assets/hooks/test-aria-preturn-memory-gate.mjs +2 -2
- package/dist/assets/hooks/test-tier-lens-labeling.mjs +14 -3
- package/dist/assets/opencode-plugins/harness-context/index.js +39 -6
- package/dist/assets/opencode-plugins/harness-context/task-project-ledger.mjs +5 -1
- package/dist/assets/opencode-plugins/harness-gate/index.js +36 -0
- package/dist/assets/opencode-plugins/harness-gate/lib/atlas-dossier-client.js +1 -0
- package/dist/assets/opencode-plugins/harness-gate/lib/recovery-grants.js +79 -0
- package/dist/assets/opencode-plugins/harness-outcome/index.js +12 -0
- package/dist/assets/opencode-plugins/harness-stop/index.js +97 -2
- package/dist/assets/opencode-plugins/harness-stop/lib/atlas-dossier-client.js +1 -0
- package/dist/assets/opencode-plugins/harness-stop/lib/domain-output-quality.js +15 -2
- package/dist/assets/opencode-plugins/lib/coach.js +148 -0
- package/dist/runtime/coach-kernel.mjs +144 -7
- package/dist/runtime/codex-bridge.mjs +254 -8
- package/dist/runtime/discipline/doctrine_trigger_map.json +236 -25
- package/dist/runtime/discipline/skills/aria-cognition/34-frameworks-unified/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-aristotle-cognitives/SKILL.md +128 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-aristotle-intra-phase/SKILL.md +99 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-aristotle-post-phase/SKILL.md +118 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-aristotle-pre-phase/SKILL.md +117 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-axioms-first-principles/SKILL.md +202 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-axioms-first-principles/agents/openai.yaml +4 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-axioms-first-principles/references/source-map.md +130 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-backend-architect/SKILL.md +124 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-backend-architect/references/backend-cookbook.md +417 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-business-audit/SKILL.md +133 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-business-audit/references/audit-cookbook.md +247 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-business-frame/SKILL.md +138 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-business-frame/references/business-cookbook.md +154 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-chat/SKILL.md +84 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-chat/scripts/aria-chat.sh +57 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-cognition-autofire/SKILL.md +137 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-cognition-batch/SKILL.md +264 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-decision-mizan/SKILL.md +136 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-decision-mizan/references/decision-frameworks.md +287 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-first-class-operating-contract/SKILL.md +104 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-frontend-architect/SKILL.md +123 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-frontend-architect/references/frontend-cookbook.md +358 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-fullstack-orchestrator/SKILL.md +127 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-fullstack-orchestrator/references/fullstack-cookbook.md +383 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-gtm-architect/SKILL.md +126 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-gtm-architect/references/gtm-cookbook.md +235 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-harness-deploy/SKILL.md +145 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-harness-no-stripping/SKILL.md +135 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-harness-onboarding/SKILL.md +130 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-harness-output-discipline/SKILL.md +120 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-harness-substrate-binding/SKILL.md +139 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-http-harness-client/SKILL.md +85 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-http-harness-client/scripts/smoke.mjs +47 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-k8s-deploy/SKILL.md +174 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-k8s-deploy/agents/openai.yaml +3 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-ladduniframe/SKILL.md +60 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-ledger-fleet-execution/SKILL.md +126 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-live-ops/SKILL.md +54 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-mac-ssh-ops/SKILL.md +100 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-memory-index/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-noor-cognitives/SKILL.md +120 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-ops/SKILL.md +60 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-ops/references/live-endpoints.md +59 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-quality-audit/SKILL.md +133 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-readable-output/SKILL.md +239 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-readable-output/references/layout-cookbook.md +366 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-reasoning/SKILL.md +67 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-reasoning/references/core-principles.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-audit/SKILL.md +135 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-repo-audit/references/repo-audit-cookbook.md +375 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-research-orchestrator/SKILL.md +138 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-research-orchestrator/references/research-patterns.md +270 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-retention-engine/SKILL.md +120 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-retention-engine/references/retention-cookbook.md +271 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-revenue-engine/SKILL.md +128 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-revenue-engine/references/revenue-cookbook.md +227 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-senior-code-audit/SKILL.md +233 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-senior-code-audit/references/audit-checklist.md +369 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-senior-code-cookbook/SKILL.md +288 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-senior-code-cookbook/references/engineering-cookbook.md +489 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-soul-principles/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/aria-task-codex-executor/SKILL.md +86 -0
- package/dist/runtime/discipline/skills/aria-cognition/aristotle-engine/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/cross-domain-24/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/deepsoul-emotional/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/fitrah-guard/SKILL.md +78 -0
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/SKILL.md +227 -29
- package/dist/runtime/discipline/skills/aria-cognition/ghazali-8lens/references/ghazali-8lens-cookbook.md +797 -0
- package/dist/runtime/discipline/skills/aria-cognition/ijtihad-novel/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/ilham-intuition/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/never-guess/SKILL.md +77 -0
- package/dist/runtime/discipline/skills/aria-cognition/noor-recognition/SKILL.md +45 -0
- package/dist/runtime/discipline/skills/aria-cognition/qiyas-analogy/SKILL.md +174 -14
- package/dist/runtime/discipline/skills/aria-cognition/ruh-basis/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/tadabbur/SKILL.md +506 -0
- package/dist/runtime/discipline/skills/aria-cognition/tadabbur/references/tadabbur-cookbook.md +921 -0
- package/dist/runtime/discipline/skills/aria-cognition/tadabbur-ops/SKILL.md +42 -0
- package/dist/runtime/discipline/skills/aria-cognition/tafakkur/SKILL.md +104 -0
- package/dist/runtime/doctrine_trigger_map.json +236 -25
- package/dist/runtime/embedded-public-key.mjs +27 -0
- package/dist/runtime/gated-ledger.mjs +41 -14
- package/dist/runtime/harness-daemon.mjs +85 -10
- package/dist/runtime/hive-wal-publisher.mjs +292 -0
- package/dist/runtime/hooks/README.md +58 -0
- package/dist/runtime/hooks/aria-agent-handoff.mjs +147 -2
- package/dist/runtime/hooks/aria-agent-ledger-merge.mjs +31 -7
- package/dist/runtime/hooks/aria-architect-fallback.mjs +10 -2
- package/dist/runtime/hooks/aria-claim-evidence-stop-gate.mjs +240 -0
- package/dist/runtime/hooks/aria-cognition-substrate-binding.mjs +84 -10
- package/dist/runtime/hooks/aria-first-class-coach.mjs +305 -10
- package/dist/runtime/hooks/aria-harness-via-sdk.mjs +93 -16
- package/dist/runtime/hooks/aria-import-resolution-gate.mjs +106 -20
- package/dist/runtime/hooks/aria-outcome-record.mjs +56 -20
- package/dist/runtime/hooks/aria-pre-emit-autoload.mjs +1809 -0
- package/dist/runtime/hooks/aria-pre-emit-autoload.mjs.before-orchestration-redesign +1400 -0
- package/dist/runtime/hooks/aria-pre-emit-dryrun.mjs +22 -3
- package/dist/runtime/hooks/aria-pre-text-gate.mjs +11 -2
- package/dist/runtime/hooks/aria-pre-tool-gate.mjs +477 -81
- package/dist/runtime/hooks/aria-pre-tool-use.mjs +70 -6
- package/dist/runtime/hooks/aria-preprompt-consult.mjs +23 -4
- package/dist/runtime/hooks/aria-repo-doctrine-gate.mjs +29 -3
- package/dist/runtime/hooks/aria-stop-gate.mjs +585 -76
- package/dist/runtime/hooks/aria-trigger-autolearn.mjs +17 -3
- package/dist/runtime/hooks/aria-universal-turn-packet.mjs +1165 -0
- package/dist/runtime/hooks/aria-userprompt-abandon-detect.mjs +9 -1
- package/dist/runtime/hooks/canonical-settings-block.json +172 -0
- package/dist/runtime/hooks/codex-native/aria-harness-ticker-sidecar.mjs +92 -0
- package/dist/runtime/hooks/codex-native/aria-hive-wal-consumer.mjs +86 -0
- package/dist/runtime/hooks/codex-native/aria-live-ticker.mjs +38 -0
- package/dist/runtime/hooks/codex-native/aria-post-tool-use.mjs +236 -0
- package/dist/runtime/hooks/codex-native/aria-pre-tool-use.mjs +362 -0
- package/dist/runtime/hooks/codex-native/aria-stop.mjs +691 -0
- package/dist/runtime/hooks/codex-native/aria-userprompt-submit.mjs +623 -0
- package/dist/runtime/hooks/codex-native/atlas-session-context.mjs +121 -0
- package/dist/runtime/hooks/codex-native/lib/evaluate-with-kernel.mjs +257 -0
- package/dist/runtime/hooks/codex-native/lib/hive-wal-consumer.mjs +452 -0
- package/dist/runtime/hooks/codex-native/lib/kernel/deterministic-cognitive-kernel.mjs +914 -0
- package/dist/runtime/hooks/codex-native/lib/project-boundary-cognition.mjs +143 -0
- package/dist/runtime/hooks/codex-native/lib/runtime-client.mjs +3567 -0
- package/dist/runtime/hooks/codex-native/lib/task-project-ledger.mjs +294 -0
- package/dist/runtime/hooks/doctrine_trigger_map.json +236 -25
- package/dist/runtime/hooks/doctrine_trigger_map.schema.json +46 -0
- package/dist/runtime/hooks/install.sh +84 -0
- package/dist/runtime/hooks/lib/action-ledger-core.mjs +269 -0
- package/dist/runtime/hooks/lib/aria-gate-ledger.mjs +143 -0
- package/dist/runtime/hooks/lib/ast-stub-shape-detector.mjs +107 -0
- package/dist/runtime/hooks/lib/atlas-dossier-client.mjs +151 -0
- package/dist/runtime/hooks/lib/atlas-orchestrator-postwire.mjs +221 -0
- package/dist/runtime/hooks/lib/canonical-lenses.mjs +83 -6
- package/dist/runtime/hooks/lib/coach-intent-classifier.mjs +248 -0
- package/dist/runtime/hooks/lib/cognitive-block-parser.mjs +111 -0
- package/dist/runtime/hooks/lib/doctrine-trigger-map-loader.mjs +137 -0
- package/dist/runtime/hooks/lib/domain-output-quality.mjs +132 -3
- package/dist/runtime/hooks/lib/empty-catch-scanner.mjs +91 -0
- package/dist/runtime/hooks/lib/end-phase-qa-autofire.mjs +426 -0
- package/dist/runtime/hooks/lib/evaluate-with-kernel.mjs +133 -0
- package/dist/runtime/hooks/lib/first-class-coach.mjs +454 -19
- package/dist/runtime/hooks/lib/gate-audit.mjs +12 -2
- package/dist/runtime/hooks/lib/gate-loop-state.mjs +11 -2
- package/dist/runtime/hooks/lib/goal-contract-quality.mjs +302 -0
- package/dist/runtime/hooks/lib/hook-message-window.mjs +101 -9
- package/dist/runtime/hooks/lib/invocation-required-verifier.mjs +184 -0
- package/dist/runtime/hooks/lib/kernel/deterministic-cognitive-kernel.mjs +906 -0
- package/dist/runtime/hooks/lib/obligation-ledger.mjs +147 -0
- package/dist/runtime/hooks/lib/orchestration-manifest-extract.mjs +217 -0
- package/dist/runtime/hooks/lib/owner-authorizations.mjs +269 -0
- package/dist/runtime/hooks/lib/probe-discipline-scanner.mjs +142 -0
- package/dist/runtime/hooks/lib/project-boundary-cognition.mjs +143 -0
- package/dist/runtime/hooks/lib/recovery-context.mjs +151 -0
- package/dist/runtime/hooks/lib/recovery-template-loader.mjs +154 -0
- package/dist/runtime/hooks/lib/self-doctrine-check.mjs +321 -0
- package/dist/runtime/hooks/lib/sensitive-shape-detector.mjs +64 -0
- package/dist/runtime/hooks/lib/skill-autoload-gate-impl.mjs +226 -1
- package/dist/runtime/hooks/lib/stop-hook-protocol.mjs +166 -0
- package/dist/runtime/hooks/lib/surface-caught.mjs +94 -0
- package/dist/runtime/hooks/recovery-templates/force-reauthor.md +67 -0
- package/dist/runtime/hooks/recovery-templates/handoff-recovery.md +25 -0
- package/dist/runtime/hooks/scripts/check-hard-risk-prefix.mjs +99 -0
- package/dist/runtime/hooks/skills/aria-conversational-doctrine-discipline/SKILL.md +101 -0
- package/dist/runtime/hooks/test-aria-preturn-memory-gate.mjs +2 -2
- package/dist/runtime/hooks/test-tier-lens-labeling.mjs +14 -3
- package/dist/runtime/lib/evaluate-with-kernel.mjs +133 -0
- package/dist/runtime/lib/kernel/deterministic-cognitive-kernel.mjs +906 -0
- package/dist/runtime/local-phase.mjs +10 -5
- package/dist/runtime/manifest.json +8 -8
- package/dist/runtime/packet-verifier.mjs +166 -0
- package/dist/runtime/provider-proxy.mjs +13 -0
- package/dist/runtime/quality-enforcer.mjs +40 -23
- package/dist/runtime/runtime-rails/registry.mjs +252 -0
- package/dist/runtime/sdk/BUNDLED.json +2 -2
- package/dist/runtime/sdk/index.d.ts +119 -4
- package/dist/runtime/sdk/index.js +138 -12
- package/dist/runtime/sdk/index.js.map +1 -1
- package/dist/runtime/service.mjs +8036 -764
- package/dist/runtime/sub-agent-enforcer.mjs +201 -0
- package/dist/runtime/task-project-ledger.mjs +5 -1
- package/dist/sdk/BUNDLED.json +2 -2
- package/dist/sdk/index.d.ts +119 -4
- package/dist/sdk/index.js +138 -12
- package/dist/sdk/index.js.map +1 -1
- package/hooks/README.md +58 -0
- package/hooks/aria-agent-handoff.mjs +147 -2
- package/hooks/aria-agent-ledger-merge.mjs +31 -7
- package/hooks/aria-architect-fallback.mjs +10 -2
- package/hooks/aria-claim-evidence-stop-gate.mjs +240 -0
- package/hooks/aria-cognition-substrate-binding.mjs +84 -10
- package/hooks/aria-first-class-coach.mjs +305 -10
- package/hooks/aria-harness-via-sdk.mjs +93 -16
- package/hooks/aria-import-resolution-gate.mjs +106 -20
- package/hooks/aria-outcome-record.mjs +56 -20
- package/hooks/aria-pre-emit-autoload.mjs +1809 -0
- package/hooks/aria-pre-emit-autoload.mjs.before-orchestration-redesign +1400 -0
- package/hooks/aria-pre-emit-dryrun.mjs +22 -3
- package/hooks/aria-pre-text-gate.mjs +11 -2
- package/hooks/aria-pre-tool-gate.mjs +477 -81
- package/hooks/aria-pre-tool-use.mjs +70 -6
- package/hooks/aria-preprompt-consult.mjs +23 -4
- package/hooks/aria-repo-doctrine-gate.mjs +29 -3
- package/hooks/aria-stop-gate.mjs +585 -76
- package/hooks/aria-trigger-autolearn.mjs +17 -3
- package/hooks/aria-universal-turn-packet.mjs +1165 -0
- package/hooks/aria-userprompt-abandon-detect.mjs +9 -1
- package/hooks/canonical-settings-block.json +172 -0
- package/hooks/codex-native/aria-harness-ticker-sidecar.mjs +92 -0
- package/hooks/codex-native/aria-hive-wal-consumer.mjs +86 -0
- package/hooks/codex-native/aria-live-ticker.mjs +38 -0
- package/hooks/codex-native/aria-post-tool-use.mjs +236 -0
- package/hooks/codex-native/aria-pre-tool-use.mjs +362 -0
- package/hooks/codex-native/aria-stop.mjs +691 -0
- package/hooks/codex-native/aria-userprompt-submit.mjs +623 -0
- package/hooks/codex-native/atlas-session-context.mjs +121 -0
- package/hooks/codex-native/lib/evaluate-with-kernel.mjs +257 -0
- package/hooks/codex-native/lib/hive-wal-consumer.mjs +452 -0
- package/hooks/codex-native/lib/kernel/deterministic-cognitive-kernel.mjs +914 -0
- package/hooks/codex-native/lib/project-boundary-cognition.mjs +143 -0
- package/hooks/codex-native/lib/runtime-client.mjs +3567 -0
- package/hooks/codex-native/lib/task-project-ledger.mjs +294 -0
- package/hooks/doctrine_trigger_map.json +236 -25
- package/hooks/doctrine_trigger_map.schema.json +46 -0
- package/hooks/install.sh +84 -0
- package/hooks/lib/action-ledger-core.mjs +269 -0
- package/hooks/lib/aria-gate-ledger.mjs +143 -0
- package/hooks/lib/ast-stub-shape-detector.mjs +107 -0
- package/hooks/lib/atlas-dossier-client.mjs +151 -0
- package/hooks/lib/atlas-orchestrator-postwire.mjs +221 -0
- package/hooks/lib/canonical-lenses.mjs +83 -6
- package/hooks/lib/coach-intent-classifier.mjs +248 -0
- package/hooks/lib/cognitive-block-parser.mjs +111 -0
- package/hooks/lib/doctrine-trigger-map-loader.mjs +137 -0
- package/hooks/lib/domain-output-quality.mjs +132 -3
- package/hooks/lib/empty-catch-scanner.mjs +91 -0
- package/hooks/lib/end-phase-qa-autofire.mjs +426 -0
- package/hooks/lib/evaluate-with-kernel.mjs +133 -0
- package/hooks/lib/first-class-coach.mjs +454 -19
- package/hooks/lib/gate-audit.mjs +12 -2
- package/hooks/lib/gate-loop-state.mjs +11 -2
- package/hooks/lib/goal-contract-quality.mjs +302 -0
- package/hooks/lib/hook-message-window.mjs +101 -9
- package/hooks/lib/invocation-required-verifier.mjs +184 -0
- package/hooks/lib/kernel/deterministic-cognitive-kernel.mjs +906 -0
- package/hooks/lib/obligation-ledger.mjs +147 -0
- package/hooks/lib/orchestration-manifest-extract.mjs +217 -0
- package/hooks/lib/owner-authorizations.mjs +269 -0
- package/hooks/lib/probe-discipline-scanner.mjs +142 -0
- package/hooks/lib/project-boundary-cognition.mjs +143 -0
- package/hooks/lib/recovery-context.mjs +151 -0
- package/hooks/lib/recovery-template-loader.mjs +154 -0
- package/hooks/lib/self-doctrine-check.mjs +321 -0
- package/hooks/lib/sensitive-shape-detector.mjs +64 -0
- package/hooks/lib/skill-autoload-gate-impl.mjs +226 -1
- package/hooks/lib/stop-hook-protocol.mjs +166 -0
- package/hooks/lib/surface-caught.mjs +94 -0
- package/hooks/recovery-templates/force-reauthor.md +67 -0
- package/hooks/recovery-templates/handoff-recovery.md +25 -0
- package/hooks/scripts/check-hard-risk-prefix.mjs +99 -0
- package/hooks/skills/aria-conversational-doctrine-discipline/SKILL.md +101 -0
- package/hooks/test-aria-preturn-memory-gate.mjs +2 -2
- package/hooks/test-tier-lens-labeling.mjs +14 -3
- package/opencode-plugins/harness-context/index.js +39 -6
- package/opencode-plugins/harness-context/task-project-ledger.mjs +5 -1
- package/opencode-plugins/harness-gate/index.js +36 -0
- package/opencode-plugins/harness-gate/lib/atlas-dossier-client.js +1 -0
- package/opencode-plugins/harness-gate/lib/recovery-grants.js +79 -0
- package/opencode-plugins/harness-outcome/index.js +12 -0
- package/opencode-plugins/harness-stop/index.js +97 -2
- package/opencode-plugins/harness-stop/lib/atlas-dossier-client.js +1 -0
- package/opencode-plugins/harness-stop/lib/domain-output-quality.js +15 -2
- package/opencode-plugins/lib/coach.js +148 -0
- package/package.json +71 -5
- package/runtime-src/coach-kernel.mjs +144 -7
- package/runtime-src/codex-bridge.mjs +254 -8
- package/runtime-src/embedded-public-key.mjs +27 -0
- package/runtime-src/gated-ledger.mjs +41 -14
- package/runtime-src/harness-daemon.mjs +85 -10
- package/runtime-src/hive-wal-publisher.mjs +292 -0
- package/runtime-src/lib/evaluate-with-kernel.mjs +133 -0
- package/runtime-src/lib/kernel/deterministic-cognitive-kernel.mjs +906 -0
- package/runtime-src/local-phase.mjs +10 -5
- package/runtime-src/packet-verifier.mjs +166 -0
- package/runtime-src/provider-proxy.mjs +13 -0
- package/runtime-src/quality-enforcer.mjs +40 -23
- package/runtime-src/runtime-rails/registry.mjs +252 -0
- package/runtime-src/service.mjs +8036 -764
- package/runtime-src/sub-agent-enforcer.mjs +201 -0
- package/scripts/aria-ledger-append.mjs +337 -0
- package/scripts/aria-task-cheap-worker-dispatch.mjs +234 -0
- package/scripts/audit-of-audit-prior-tasks.mjs +194 -0
- package/scripts/audit-of-audit-this-turn.mjs +116 -0
- package/scripts/bundle-sdk.mjs +31 -5
- package/scripts/check-cli-wrapper-provider-contract.mjs +160 -0
- package/scripts/check-client-compatibility.mjs +15 -5
- package/scripts/check-client-smoke.mjs +297 -0
- package/scripts/check-codex-orchestrator-adoption.mjs +150 -0
- package/scripts/check-glm-env-wired.mjs +131 -0
- package/scripts/check-hive-local-storage-contract.mjs +91 -0
- package/scripts/check-hook-mirror.mjs +150 -0
- package/scripts/check-install-sh-drift.mjs +152 -0
- package/scripts/check-kernel-sync.mjs +101 -0
- package/scripts/check-package-artifact.mjs +152 -0
- package/scripts/check-registry-mirror.mjs +71 -0
- package/scripts/drain-owner-airtable-sync-queue.mjs +287 -0
- package/scripts/export-owner-status-sheets.mjs +589 -0
- package/scripts/live-sidecar-receipt-canary.mjs +347 -0
- package/scripts/qiyas-tadabbur-model-matrix.mjs +970 -0
- package/scripts/quality-ab-live-provider.mjs +913 -0
- package/scripts/self-test-action-ledger-core.mjs +190 -0
- package/scripts/self-test-approval-receipt-binding.mjs +122 -0
- package/scripts/self-test-autofire-quality-output.mjs +110 -0
- package/scripts/self-test-claude-code-action-ledger.mjs +132 -0
- package/scripts/self-test-claude-code-mechanical-autofire-hive.mjs +138 -0
- package/scripts/self-test-claude-code-mechanical-autofire.mjs +234 -0
- package/scripts/self-test-codebase-awareness-atlas-delta.mjs +159 -0
- package/scripts/self-test-codebase-awareness-delta-ingest.mjs +179 -0
- package/scripts/self-test-codex-live-hook-parity.mjs +84 -0
- package/scripts/self-test-codex-native-action-ledger.mjs +167 -0
- package/scripts/self-test-codex-native-hook-json-contract.mjs +74 -0
- package/scripts/self-test-codex-orchestrator-continuity.mjs +113 -0
- package/scripts/self-test-codex-readable-recovery.mjs +94 -0
- package/scripts/self-test-codex-self-harness.mjs +538 -0
- package/scripts/self-test-compiled-workunit.mjs +214 -0
- package/scripts/self-test-continuation-output-smoke.mjs +101 -0
- package/scripts/self-test-cross-cli-fleet-ticker.mjs +85 -0
- package/scripts/self-test-cross-cli-hive-adoption.mjs +125 -0
- package/scripts/self-test-cross-cli-hive-learning.mjs +146 -0
- package/scripts/self-test-cross-phase-tool-failure.mjs +110 -0
- package/scripts/self-test-cross-surface-action-ledger.mjs +149 -0
- package/scripts/self-test-end-of-phase-qa-court.mjs +616 -0
- package/scripts/self-test-evaluate-with-kernel.mjs +111 -0
- package/scripts/self-test-first-class-output-delta-proof.mjs +307 -0
- package/scripts/self-test-goal-contract-output-qa.mjs +73 -0
- package/scripts/self-test-goal-contract.mjs +35 -0
- package/scripts/self-test-governed-adapters.mjs +105 -0
- package/scripts/self-test-governed-surface-runner.mjs +198 -0
- package/scripts/self-test-harness-gates.mjs +15 -12
- package/scripts/self-test-harness-ticker-sidecar.mjs +153 -0
- package/scripts/self-test-hive-org-kernel.mjs +233 -0
- package/scripts/self-test-hive-session-coordination.mjs +156 -0
- package/scripts/self-test-hive-wal-consumer.mjs +111 -0
- package/scripts/self-test-kernel-a3-a4-selection.mjs +179 -0
- package/scripts/self-test-ledger-append.mjs +175 -0
- package/scripts/self-test-live-codex-posttool-packet-smoke.mjs +111 -0
- package/scripts/self-test-live-codex-pretool-packet-smoke.mjs +101 -0
- package/scripts/self-test-live-codex-stop-qa-kernel-smoke.mjs +43 -0
- package/scripts/self-test-live-wrapper-substrate-inventory.mjs +149 -0
- package/scripts/self-test-local-main-sync-script.mjs +47 -0
- package/scripts/self-test-mechanical-autofire-resolver.mjs +296 -0
- package/scripts/self-test-no-consult-cognitive-skills-output.mjs +135 -0
- package/scripts/self-test-owner-airtable-sync-queue.mjs +196 -0
- package/scripts/self-test-owner-airtable-sync.mjs +181 -0
- package/scripts/self-test-owner-sheets-action-ledger.mjs +100 -0
- package/scripts/self-test-production-preflight.mjs +78 -0
- package/scripts/self-test-project-boundary-cognition.mjs +79 -0
- package/scripts/self-test-qa-exec-kernel.mjs +34 -0
- package/scripts/self-test-qa-recovery-learning-loop.mjs +113 -0
- package/scripts/self-test-qiyas-label-alignment.mjs +94 -0
- package/scripts/self-test-recovery-context.mjs +110 -0
- package/scripts/self-test-repo-guard.mjs +10 -0
- package/scripts/self-test-runtime-health-self-heal.mjs +161 -0
- package/scripts/self-test-runtime-postcondition.mjs +70 -0
- package/scripts/self-test-soul-precommit-hook.mjs +39 -0
- package/scripts/self-test-stop-gate-kernel-guards.mjs +185 -0
- package/scripts/self-test-stop-gate.mjs +128 -0
- package/scripts/self-test-substrate-kernel-execution-receipt.mjs +130 -0
- package/scripts/self-test-substrate-open-skill-floor.mjs +87 -0
- package/scripts/self-test-substrate-output-quality-eval.mjs +171 -0
- package/scripts/self-test-task-closeout-drift.mjs +97 -0
- package/scripts/self-test-task-project-ledger-readiness.mjs +43 -0
- package/scripts/self-test-task-runner-phase-consumer.mjs +134 -0
- package/scripts/self-test-task-worker-lane.mjs +256 -0
- package/scripts/self-test-turn-substrate-qa-kernel.mjs +188 -0
- package/scripts/self-test-universal-action-capture.mjs +153 -0
- package/scripts/self-test-universal-turn-packet-entrypoints.mjs +252 -0
- package/scripts/self-test-universal-turn-packet.mjs +320 -0
- package/scripts/session-quality-backfill.mjs +253 -0
- package/scripts/smoke-autofire-100-prompts.mjs +481 -0
- package/scripts/sync-local-main-on-task-complete.mjs +278 -0
- package/scripts/sync-owner-status-airtable.mjs +1158 -0
- package/scripts/validate-skill-prompts.mjs +12 -1
- package/scripts/verify-codex-native-mirror.mjs +262 -0
- package/skills/34-frameworks-unified/SKILL.md +42 -0
- package/skills/api-design/SKILL.md +123 -0
- package/skills/architecture-decision/SKILL.md +105 -0
- package/skills/aria-aristotle-cognitives/SKILL.md +128 -0
- package/skills/aria-aristotle-intra-phase/SKILL.md +99 -0
- package/skills/aria-aristotle-post-phase/SKILL.md +116 -0
- package/skills/aria-aristotle-pre-phase/SKILL.md +117 -0
- package/skills/aria-axioms-first-principles/SKILL.md +202 -0
- package/skills/aria-axioms-first-principles/agents/openai.yaml +4 -0
- package/skills/aria-axioms-first-principles/references/source-map.md +130 -0
- package/skills/aria-chat/SKILL.md +84 -0
- package/skills/aria-chat/scripts/aria-chat.sh +57 -0
- package/skills/aria-cognition/34-frameworks-unified/SKILL.md +42 -0
- package/skills/aria-cognition/aria-aristotle-cognitives/SKILL.md +128 -0
- package/skills/aria-cognition/aria-aristotle-intra-phase/SKILL.md +99 -0
- package/skills/aria-cognition/aria-aristotle-post-phase/SKILL.md +118 -0
- package/skills/aria-cognition/aria-aristotle-pre-phase/SKILL.md +117 -0
- package/skills/aria-cognition/aria-axioms-first-principles/SKILL.md +202 -0
- package/skills/aria-cognition/aria-axioms-first-principles/agents/openai.yaml +4 -0
- package/skills/aria-cognition/aria-axioms-first-principles/references/source-map.md +130 -0
- package/skills/aria-cognition/aria-backend-architect/SKILL.md +124 -0
- package/skills/aria-cognition/aria-backend-architect/references/backend-cookbook.md +417 -0
- package/skills/aria-cognition/aria-business-audit/SKILL.md +133 -0
- package/skills/aria-cognition/aria-business-audit/references/audit-cookbook.md +247 -0
- package/skills/aria-cognition/aria-business-frame/SKILL.md +138 -0
- package/skills/aria-cognition/aria-business-frame/references/business-cookbook.md +154 -0
- package/skills/aria-cognition/aria-chat/SKILL.md +84 -0
- package/skills/aria-cognition/aria-chat/scripts/aria-chat.sh +57 -0
- package/skills/aria-cognition/aria-cognition-autofire/SKILL.md +137 -0
- package/skills/aria-cognition/aria-cognition-batch/SKILL.md +264 -0
- package/skills/aria-cognition/aria-decision-mizan/SKILL.md +136 -0
- package/skills/aria-cognition/aria-decision-mizan/references/decision-frameworks.md +287 -0
- package/skills/aria-cognition/aria-first-class-operating-contract/SKILL.md +104 -0
- package/skills/aria-cognition/aria-frontend-architect/SKILL.md +123 -0
- package/skills/aria-cognition/aria-frontend-architect/references/frontend-cookbook.md +358 -0
- package/skills/aria-cognition/aria-fullstack-orchestrator/SKILL.md +127 -0
- package/skills/aria-cognition/aria-fullstack-orchestrator/references/fullstack-cookbook.md +383 -0
- package/skills/aria-cognition/aria-gtm-architect/SKILL.md +126 -0
- package/skills/aria-cognition/aria-gtm-architect/references/gtm-cookbook.md +235 -0
- package/skills/aria-cognition/aria-harness-deploy/SKILL.md +145 -0
- package/skills/aria-cognition/aria-harness-no-stripping/SKILL.md +135 -0
- package/skills/aria-cognition/aria-harness-onboarding/SKILL.md +130 -0
- package/skills/aria-cognition/aria-harness-output-discipline/SKILL.md +120 -0
- package/skills/aria-cognition/aria-harness-substrate-binding/SKILL.md +139 -0
- package/skills/aria-cognition/aria-http-harness-client/SKILL.md +85 -0
- package/skills/aria-cognition/aria-http-harness-client/scripts/smoke.mjs +47 -0
- package/skills/aria-cognition/aria-k8s-deploy/SKILL.md +174 -0
- package/skills/aria-cognition/aria-k8s-deploy/agents/openai.yaml +3 -0
- package/skills/aria-cognition/aria-ladduniframe/SKILL.md +60 -0
- package/skills/aria-cognition/aria-ledger-fleet-execution/SKILL.md +126 -0
- package/skills/aria-cognition/aria-live-ops/SKILL.md +54 -0
- package/skills/aria-cognition/aria-mac-ssh-ops/SKILL.md +100 -0
- package/skills/aria-cognition/aria-memory-index/SKILL.md +42 -0
- package/skills/aria-cognition/aria-noor-cognitives/SKILL.md +120 -0
- package/skills/aria-cognition/aria-ops/SKILL.md +60 -0
- package/skills/aria-cognition/aria-ops/references/live-endpoints.md +59 -0
- package/skills/aria-cognition/aria-quality-audit/SKILL.md +133 -0
- package/skills/aria-cognition/aria-readable-output/SKILL.md +239 -0
- package/skills/aria-cognition/aria-readable-output/references/layout-cookbook.md +366 -0
- package/skills/aria-cognition/aria-reasoning/SKILL.md +67 -0
- package/skills/aria-cognition/aria-reasoning/references/core-principles.md +42 -0
- package/skills/aria-cognition/aria-repo-audit/SKILL.md +135 -0
- package/skills/aria-cognition/aria-repo-audit/references/repo-audit-cookbook.md +375 -0
- package/skills/aria-cognition/aria-research-orchestrator/SKILL.md +138 -0
- package/skills/aria-cognition/aria-research-orchestrator/references/research-patterns.md +270 -0
- package/skills/aria-cognition/aria-retention-engine/SKILL.md +120 -0
- package/skills/aria-cognition/aria-retention-engine/references/retention-cookbook.md +271 -0
- package/skills/aria-cognition/aria-revenue-engine/SKILL.md +128 -0
- package/skills/aria-cognition/aria-revenue-engine/references/revenue-cookbook.md +227 -0
- package/skills/aria-cognition/aria-senior-code-audit/SKILL.md +233 -0
- package/skills/aria-cognition/aria-senior-code-audit/references/audit-checklist.md +369 -0
- package/skills/aria-cognition/aria-senior-code-cookbook/SKILL.md +288 -0
- package/skills/aria-cognition/aria-senior-code-cookbook/references/engineering-cookbook.md +489 -0
- package/skills/aria-cognition/aria-soul-principles/SKILL.md +42 -0
- package/skills/aria-cognition/aria-task-codex-executor/SKILL.md +86 -0
- package/skills/aria-cognition/aristotle-engine/SKILL.md +42 -0
- package/skills/aria-cognition/cross-domain-24/SKILL.md +42 -0
- package/skills/aria-cognition/deepsoul-emotional/SKILL.md +42 -0
- package/skills/aria-cognition/fitrah-guard/SKILL.md +78 -0
- package/skills/aria-cognition/ghazali-8lens/SKILL.md +227 -29
- package/skills/aria-cognition/ghazali-8lens/references/ghazali-8lens-cookbook.md +797 -0
- package/skills/aria-cognition/ijtihad-novel/SKILL.md +42 -0
- package/skills/aria-cognition/ilham-intuition/SKILL.md +42 -0
- package/skills/aria-cognition/never-guess/SKILL.md +77 -0
- package/skills/aria-cognition/noor-recognition/SKILL.md +45 -0
- package/skills/aria-cognition/qiyas-analogy/SKILL.md +174 -14
- package/skills/aria-cognition/ruh-basis/SKILL.md +42 -0
- package/skills/aria-cognition/tadabbur/SKILL.md +506 -0
- package/skills/aria-cognition/tadabbur/references/tadabbur-cookbook.md +921 -0
- package/skills/aria-cognition/tadabbur-ops/SKILL.md +42 -0
- package/skills/aria-cognition/tafakkur/SKILL.md +104 -0
- package/skills/aria-cognition-autofire/SKILL.md +109 -0
- package/skills/aria-cognition-batch/SKILL.md +264 -0
- package/skills/aria-conversational-doctrine-discipline/SKILL.md +125 -0
- package/skills/aria-essence/SKILL.md +81 -0
- package/skills/aria-essence/references/domain-matrix.md +80 -0
- package/skills/aria-essence/references/evolution-loop.md +30 -0
- package/skills/aria-essence/references/readable-cognition.md +27 -0
- package/skills/aria-first-class-operating-contract/SKILL.md +104 -0
- package/skills/aria-forge-guardrails/SKILL.md +53 -0
- package/skills/aria-forge-guardrails/references/checklist.md +31 -0
- package/skills/aria-harness-deploy/SKILL.md +145 -0
- package/skills/aria-harness-no-stripping/SKILL.md +135 -0
- package/skills/aria-harness-onboarding/SKILL.md +130 -0
- package/skills/aria-harness-output-discipline/SKILL.md +120 -0
- package/skills/aria-harness-substrate-binding/SKILL.md +139 -0
- package/skills/aria-http-harness-client/SKILL.md +85 -0
- package/skills/aria-http-harness-client/scripts/smoke.mjs +47 -0
- package/skills/aria-k8s-deploy/SKILL.md +174 -0
- package/skills/aria-k8s-deploy/agents/openai.yaml +3 -0
- package/skills/aria-ladduniframe/SKILL.md +60 -0
- package/skills/aria-ledger-fleet-execution/SKILL.md +126 -0
- package/skills/aria-live-ops/SKILL.md +54 -0
- package/skills/aria-mac-ssh-ops/SKILL.md +100 -0
- package/skills/aria-memory-index/SKILL.md +42 -0
- package/skills/aria-noor-cognitives/SKILL.md +120 -0
- package/skills/aria-ops/SKILL.md +60 -0
- package/skills/aria-ops/references/live-endpoints.md +59 -0
- package/skills/aria-quality-audit/SKILL.md +133 -0
- package/skills/aria-reasoning/SKILL.md +67 -0
- package/skills/aria-reasoning/references/core-principles.md +42 -0
- package/skills/aria-repo-doctrine/SKILL.md +57 -0
- package/skills/aria-soul-principles/SKILL.md +42 -0
- package/skills/aria-task-codex-executor/SKILL.md +86 -0
- package/skills/aristotle-engine/SKILL.md +42 -0
- package/skills/ci-cd-pipeline/SKILL.md +116 -0
- package/skills/code-review/SKILL.md +131 -0
- package/skills/cross-domain-24/SKILL.md +42 -0
- package/skills/database-design/SKILL.md +124 -0
- package/skills/deepsoul-emotional/SKILL.md +42 -0
- package/skills/deno-kv-raft-pubsub/SKILL.md +561 -0
- package/skills/deno-kv-raft-pubsub/reference/maelstrom-integration.md +393 -0
- package/skills/deno-kv-raft-pubsub/reference/pubsub-api.md +376 -0
- package/skills/deno-kv-raft-pubsub/reference/raft-spec.md +402 -0
- package/skills/deno-kv-raft-pubsub/reference/state-machine.md +182 -0
- package/skills/error-handling/SKILL.md +159 -0
- package/skills/firecrawl/SKILL.md +165 -0
- package/skills/firecrawl/rules/install.md +82 -0
- package/skills/firecrawl/rules/security.md +26 -0
- package/skills/firecrawl-agent/SKILL.md +86 -0
- package/skills/firecrawl-build-interact/SKILL.md +96 -0
- package/skills/firecrawl-build-onboarding/SKILL.md +131 -0
- package/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
- package/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
- package/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
- package/skills/firecrawl-build-scrape/SKILL.md +97 -0
- package/skills/firecrawl-build-search/SKILL.md +97 -0
- package/skills/firecrawl-clone/SKILL.md +419 -0
- package/skills/firecrawl-crawl/SKILL.md +87 -0
- package/skills/firecrawl-download/SKILL.md +98 -0
- package/skills/firecrawl-interact/SKILL.md +112 -0
- package/skills/firecrawl-map/SKILL.md +79 -0
- package/skills/firecrawl-scrape/SKILL.md +97 -0
- package/skills/firecrawl-search/SKILL.md +88 -0
- package/skills/fitrah-guard/SKILL.md +78 -0
- package/skills/forge-quality-rules/SKILL.md +61 -0
- package/skills/ghazali-8lens/SKILL.md +56 -0
- package/skills/ijtihad-novel/SKILL.md +42 -0
- package/skills/ilham-intuition/SKILL.md +42 -0
- package/skills/imagegen/LICENSE.txt +201 -0
- package/skills/imagegen/SKILL.md +374 -0
- package/skills/imagegen/agents/openai.yaml +6 -0
- package/skills/imagegen/assets/imagegen-small.svg +5 -0
- package/skills/imagegen/assets/imagegen.png +0 -0
- package/skills/imagegen/references/cli.md +242 -0
- package/skills/imagegen/references/codex-network.md +33 -0
- package/skills/imagegen/references/image-api.md +90 -0
- package/skills/imagegen/references/prompting.md +118 -0
- package/skills/imagegen/references/sample-prompts.md +433 -0
- package/skills/imagegen/scripts/image_gen.py +995 -0
- package/skills/imagegen/scripts/remove_chroma_key.py +440 -0
- package/skills/istiqra-induction/SKILL.md +44 -0
- package/skills/ladunni-22/SKILL.md +53 -0
- package/skills/mizan/SKILL.md +90 -0
- package/skills/nadia/SKILL.md +56 -0
- package/skills/nadia-psi/SKILL.md +56 -0
- package/skills/never-guess/SKILL.md +75 -0
- package/skills/noor-recognition/SKILL.md +45 -0
- package/skills/observability/SKILL.md +133 -0
- package/skills/openai-docs/LICENSE.txt +201 -0
- package/skills/openai-docs/SKILL.md +100 -0
- package/skills/openai-docs/agents/openai.yaml +14 -0
- package/skills/openai-docs/assets/openai-small.svg +3 -0
- package/skills/openai-docs/assets/openai.png +0 -0
- package/skills/openai-docs/references/latest-model.md +37 -0
- package/skills/openai-docs/references/prompting-guide.md +244 -0
- package/skills/openai-docs/references/upgrade-guide.md +181 -0
- package/skills/openai-docs/scripts/resolve-latest-model-info.js +147 -0
- package/skills/pdf/LICENSE.txt +201 -0
- package/skills/pdf/SKILL.md +85 -0
- package/skills/pdf/agents/openai.yaml +5 -0
- package/skills/pdf/assets/pdf.png +0 -0
- package/skills/playwright/LICENSE.txt +201 -0
- package/skills/playwright/NOTICE.txt +14 -0
- package/skills/playwright/SKILL.md +165 -0
- package/skills/playwright/agents/openai.yaml +6 -0
- package/skills/playwright/assets/playwright-small.svg +3 -0
- package/skills/playwright/assets/playwright.png +0 -0
- package/skills/playwright/references/cli.md +116 -0
- package/skills/playwright/references/workflows.md +95 -0
- package/skills/playwright/scripts/playwright_cli.sh +25 -0
- package/skills/plugin-creator/SKILL.md +178 -0
- package/skills/plugin-creator/agents/openai.yaml +6 -0
- package/skills/plugin-creator/assets/plugin-creator-small.svg +3 -0
- package/skills/plugin-creator/assets/plugin-creator.png +0 -0
- package/skills/plugin-creator/references/plugin-json-spec.md +170 -0
- package/skills/plugin-creator/scripts/create_basic_plugin.py +301 -0
- package/skills/predictor/SKILL.md +43 -0
- package/skills/qiyas-analogy/SKILL.md +204 -0
- package/skills/refactoring/SKILL.md +137 -0
- package/skills/ruh-basis/SKILL.md +42 -0
- package/skills/security-review/SKILL.md +129 -0
- package/skills/skill-creator/SKILL.md +434 -0
- package/skills/skill-creator/agents/openai.yaml +5 -0
- package/skills/skill-creator/assets/skill-creator-small.svg +3 -0
- package/skills/skill-creator/assets/skill-creator.png +0 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/references/openai_yaml.md +49 -0
- package/skills/skill-creator/scripts/generate_openai_yaml.py +226 -0
- package/skills/skill-creator/scripts/init_skill.py +400 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/skill-installer/LICENSE.txt +202 -0
- package/skills/skill-installer/SKILL.md +76 -0
- package/skills/skill-installer/agents/openai.yaml +5 -0
- package/skills/skill-installer/assets/skill-installer-small.svg +3 -0
- package/skills/skill-installer/assets/skill-installer.png +0 -0
- package/skills/skill-installer/scripts/github_utils.py +21 -0
- package/skills/skill-installer/scripts/install-skill-from-github.py +308 -0
- package/skills/skill-installer/scripts/list-skills.py +107 -0
- package/skills/skills-and-hooks-reference/SKILL.md +196 -0
- package/skills/soul-domains/SKILL.md +43 -0
- package/skills/tadabbur/SKILL.md +232 -0
- package/skills/tadabbur-ops/SKILL.md +42 -0
- package/skills/tafakkur/SKILL.md +104 -0
- package/skills/testing-strategy/SKILL.md +122 -0
- package/src/action-ledger-core.ts +1054 -0
- package/src/chat.ts +5 -6
- package/src/codebase-scanner.ts +2 -0
- package/src/connectors/claude-code.ts +149 -12
- package/src/connectors/codebase-awareness.ts +325 -25
- package/src/connectors/codex.ts +1225 -41
- package/src/connectors/cursor.ts +8 -0
- package/src/connectors/governed-adapter.ts +174 -0
- package/src/connectors/opencode.ts +18 -2
- package/src/connectors/repo-guard.ts +24 -12
- package/src/connectors/runtime.ts +99 -2
- package/src/connectors/shell.ts +125 -7
- package/src/cross-cli-hive-binding.ts +290 -0
- package/src/garden-control-plane.ts +24 -1
- package/src/governed-surface-runner.ts +1227 -0
- package/src/index.ts +104 -1
- package/src/task-runner.ts +3794 -0
- package/dist/aria-connector/src/install-hooks.d.ts +0 -18
- package/dist/aria-connector/src/install-hooks.d.ts.map +0 -1
- package/dist/aria-connector/src/install-hooks.js +0 -224
- package/dist/aria-connector/src/install-hooks.js.map +0 -1
- package/dist/aria-connector/src/onboarding-wizard.d.ts +0 -5
- package/dist/aria-connector/src/onboarding-wizard.d.ts.map +0 -1
- package/dist/aria-connector/src/onboarding-wizard.js +0 -188
- package/dist/aria-connector/src/onboarding-wizard.js.map +0 -1
- package/dist/cli-0.2.38.tgz +0 -0
- package/dist/install.sh +0 -13
- package/src/__tests__/anthropic-oauth.test.ts +0 -186
- package/src/__tests__/auth-commands.test.ts +0 -132
- package/src/__tests__/owner-login.test.ts +0 -311
|
@@ -0,0 +1,3567 @@
|
|
|
1
|
+
import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, renameSync, statSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { updateTaskProjectLedger, evaluateTaskProjectClaim, recordBlockedTaskProjectClaim } from './task-project-ledger.mjs';
|
|
7
|
+
import { evaluateWithKernel, OUTPUT_EMIT_FAILURE_CLASSES } from './evaluate-with-kernel.mjs';
|
|
8
|
+
import { hasSensitiveMaterialShape } from '../../lib/sensitive-shape-detector.mjs';
|
|
9
|
+
|
|
10
|
+
export { updateTaskProjectLedger, evaluateTaskProjectClaim, recordBlockedTaskProjectClaim };
|
|
11
|
+
|
|
12
|
+
// ARIA_KERNEL_QA_MODE — when '1', evaluateQaExecutionKernel and
|
|
13
|
+
// evaluateGoalContractOutput route hard-block decisions through the atlas
|
|
14
|
+
// deterministic cognitive kernel's output_emit classifier instead of the
|
|
15
|
+
// regex blob. Owner directive 2026-05-17 ("kernel we made for sentinel is
|
|
16
|
+
// critical for coach and gates"). Default off for gradual rollout; flip on
|
|
17
|
+
// per-hook via env var in settings.json command.
|
|
18
|
+
const ARIA_KERNEL_QA_MODE_ENABLED = process.env.ARIA_KERNEL_QA_MODE === '1';
|
|
19
|
+
|
|
20
|
+
// ── Shared output-emit detection (single source of truth) ─────────────
|
|
21
|
+
// Module-level regex constants for output-emit classification, used by
|
|
22
|
+
// evaluateGoalContractOutput, evaluateQaExecutionKernel, and the kernel
|
|
23
|
+
// adapter paths. Each was previously duplicated 2-3 times with subtle
|
|
24
|
+
// drift across copies. Consolidated 2026-05-17 after QA-court found the
|
|
25
|
+
// duplicates had different "observation evidence" rules causing one
|
|
26
|
+
// surface to false-negative on text the others caught (and vice versa).
|
|
27
|
+
//
|
|
28
|
+
// All regexes here are paraphrase-conservative: they over-permit edge
|
|
29
|
+
// cases rather than over-block, because the kernel adapter is the
|
|
30
|
+
// authoritative decider when ARIA_KERNEL_QA_MODE=1 — these regexes feed
|
|
31
|
+
// the kernel's structured attrs.
|
|
32
|
+
const OUTPUT_FALSE_COMPLETION_RX = /\b(?:production ready|ready for production|release ready|promotion pass|first[-\s]?class\s+(?:complete|ready)|(?:this|it|the\s+\w+)\s+is\s+(?:complete|completed|done|shipped|fixed|verified)|(?:we|i)\s+(?:have|'ve)\s+(?:complete|completed|shipped|done|fixed|verified|finished))\b/i;
|
|
33
|
+
const OUTPUT_AGREEMENT_RX = /\b(?:you(?:'|’)?re\s+right|spot[-\s]?on|exactly\s+right|absolutely\s+right)\b/i;
|
|
34
|
+
const OUTPUT_ADVANCE_LANG_RX = /\b(?:committed|ran|observed|verified|tested|deployed|measured|wrote|added|fixed|patched|wired|edited|exit\s*0)\b/i;
|
|
35
|
+
// Concrete-pattern observation regex — bare words like "probe"/"smoke"/
|
|
36
|
+
// "observed"/"evidence" were removed because they match in negation
|
|
37
|
+
// phrases ("no probe data", "no evidence", "unobserved") and falsely
|
|
38
|
+
// suppress real claims. Only numbers, hashes, and typed patterns here.
|
|
39
|
+
const OUTPUT_OBSERVATION_EVIDENCE_RX = /\b(?:not production-ready|not production ready|integration-ready|exit\s*0|exit_code\s*[:=]?\s*0|\d+\s*\/\s*\d+\s*(?:pass|passed|ok)|sha\s*256|sha256|byte-identical|empirically\s+verified|empirically\s+observed)\b/i;
|
|
40
|
+
const OUTPUT_CODE_CONTEXT_RX = /\b(?:regex|RegExp|literal|matching|matches|grep|sed|awk|edit\s+\S+\.(?:mjs|ts|js|json|md)|patching|new_string|old_string|`[^`]+`|```|\/[^/\s]+\/[gimsuy]*)/i;
|
|
41
|
+
const OUTPUT_VERIFY_BLOCK_RX = /<verify>[\s\S]*?<\/verify>/i;
|
|
42
|
+
const OUTPUT_COGNITION_BLOCK_RX = /<cognition>[\s\S]*?<\/cognition>/i;
|
|
43
|
+
const OUTPUT_EXPECTED_OUTCOME_BLOCK_RX = /<expected_outcome>[\s\S]*?<\/expected_outcome>/i;
|
|
44
|
+
|
|
45
|
+
// Read the most recent assistant text emission from the Claude Code transcript
|
|
46
|
+
// JSONL file. Returns '' on any failure (file missing, parse error, no
|
|
47
|
+
// assistant message yet). Used by the deploy/delete hard-risk classifier to
|
|
48
|
+
// check whether bound substrate (<verify>+<cognition>+<expected_outcome>) was
|
|
49
|
+
// emitted in the same assistant turn that requested the tool action.
|
|
50
|
+
// Per feedback_deploy_requires_verify_cognition.md — the gate's job is to
|
|
51
|
+
// enforce substrate-binding, not to hard-block every deploy unconditionally.
|
|
52
|
+
function readRecentAssistantTextFromTranscript(transcriptPath) {
|
|
53
|
+
try {
|
|
54
|
+
if (typeof transcriptPath !== 'string' || !transcriptPath) return '';
|
|
55
|
+
if (!existsSync(transcriptPath)) return '';
|
|
56
|
+
const raw = readFileSync(transcriptPath, 'utf8');
|
|
57
|
+
if (!raw) return '';
|
|
58
|
+
const lines = raw.split('\n').filter(Boolean);
|
|
59
|
+
// Walk newest-to-oldest within a bounded window, accumulating ALL
|
|
60
|
+
// assistant text content. Claude Code transcripts interleave assistant
|
|
61
|
+
// text entries with tool_use entries and user-role tool_result entries;
|
|
62
|
+
// a naive "break at first non-assistant" walk halts at tool_result
|
|
63
|
+
// boundaries before reaching the substrate-bearing emission. Bounded
|
|
64
|
+
// window scan ensures substrate emitted earlier in the same logical
|
|
65
|
+
// turn is captured even when tool_use cycles intervened.
|
|
66
|
+
const WINDOW = 200;
|
|
67
|
+
const start = Math.max(0, lines.length - WINDOW);
|
|
68
|
+
const chunks = [];
|
|
69
|
+
for (let i = lines.length - 1; i >= start; i -= 1) {
|
|
70
|
+
let entry;
|
|
71
|
+
try { entry = JSON.parse(lines[i]); } catch { continue; }
|
|
72
|
+
const role = entry?.message?.role || entry?.role;
|
|
73
|
+
if (role !== 'assistant') continue;
|
|
74
|
+
const content = entry?.message?.content || entry?.content;
|
|
75
|
+
if (typeof content === 'string') {
|
|
76
|
+
chunks.unshift(content);
|
|
77
|
+
} else if (Array.isArray(content)) {
|
|
78
|
+
for (const block of content) {
|
|
79
|
+
if (block && typeof block === 'object' && typeof block.text === 'string') {
|
|
80
|
+
chunks.unshift(block.text);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return chunks.join('\n');
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.warn(`[qa-exec-kernel] transcript read failed: ${err?.message ?? err}`);
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function hasBoundDeploySubstrate(text) {
|
|
93
|
+
if (!text) return false;
|
|
94
|
+
return OUTPUT_VERIFY_BLOCK_RX.test(text)
|
|
95
|
+
&& OUTPUT_COGNITION_BLOCK_RX.test(text)
|
|
96
|
+
&& OUTPUT_EXPECTED_OUTCOME_BLOCK_RX.test(text);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// extractEmitAttrs — single helper that builds the structured attrs the
|
|
100
|
+
// atlas kernel's output_emit classifier reads. All callers consume this.
|
|
101
|
+
//
|
|
102
|
+
// 2026-05-18 structural-migration: hasAdvanceLang now derived
|
|
103
|
+
// structurally. True when ANY of (verify-block | cognition-block |
|
|
104
|
+
// expected_outcome-block | code-block | evidence-anchor | pending tool
|
|
105
|
+
// action) is present. Vocabulary regex fallback retained for stop-surface
|
|
106
|
+
// emits where no tool follows. Old vocab-only rule false-blocked any
|
|
107
|
+
// deploy-themed session whose prose lacked literal "committed/ran/wrote/
|
|
108
|
+
// etc". Kernel-migration doctrine (project_hook_kernel_migration_2026_05_17)
|
|
109
|
+
// says structural prefix selectors replace vocabulary regex.
|
|
110
|
+
function extractEmitAttrs(source = '', { continuationRequested = false, action = null, pendingToolUse = false } = {}) {
|
|
111
|
+
const text = String(source || '');
|
|
112
|
+
const inCodeContext = OUTPUT_CODE_CONTEXT_RX.test(text);
|
|
113
|
+
const evidenceMatches = text.match(new RegExp(OUTPUT_OBSERVATION_EVIDENCE_RX.source, 'gi')) || [];
|
|
114
|
+
const codeBlockCount = (text.match(/```/g) || []).length / 2;
|
|
115
|
+
const hasVerifyBlock = OUTPUT_VERIFY_BLOCK_RX.test(text);
|
|
116
|
+
const hasCognitionBlock = OUTPUT_COGNITION_BLOCK_RX.test(text);
|
|
117
|
+
const hasExpectedOutcomeBlock = OUTPUT_EXPECTED_OUTCOME_BLOCK_RX.test(text);
|
|
118
|
+
const hasStructuralAdvance = pendingToolUse
|
|
119
|
+
|| hasVerifyBlock
|
|
120
|
+
|| hasCognitionBlock
|
|
121
|
+
|| hasExpectedOutcomeBlock
|
|
122
|
+
|| codeBlockCount > 0
|
|
123
|
+
|| evidenceMatches.length > 0;
|
|
124
|
+
return {
|
|
125
|
+
hasCompletionLang: OUTPUT_FALSE_COMPLETION_RX.test(text) && !inCodeContext,
|
|
126
|
+
hasAgreementLang: OUTPUT_AGREEMENT_RX.test(text) && !inCodeContext,
|
|
127
|
+
hasAdvanceLang: hasStructuralAdvance || OUTPUT_ADVANCE_LANG_RX.test(text),
|
|
128
|
+
hasVerifyBlock,
|
|
129
|
+
evidenceAnchorCount: evidenceMatches.length,
|
|
130
|
+
lensCount: 0,
|
|
131
|
+
codeBlockCount,
|
|
132
|
+
continuationRequested,
|
|
133
|
+
textLength: text.length,
|
|
134
|
+
inCodeContext,
|
|
135
|
+
action,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const HOME = homedir();
|
|
140
|
+
const DEFAULT_RUNTIME_URL = (process.env.ARIA_RUNTIME_URL || 'http://127.0.0.1:4319').replace(/\/+$/, '');
|
|
141
|
+
// ARIA_HOOK_SURFACE — which CLI surface this lib is running under.
|
|
142
|
+
// Defaults to 'codex' so unmodified Codex hook entries behave exactly as
|
|
143
|
+
// before (zero impact on active Codex sessions). Claude registration
|
|
144
|
+
// passes ARIA_HOOK_SURFACE=claude so per-surface state directories and
|
|
145
|
+
// session prefixes flow through every helper that previously hardcoded
|
|
146
|
+
// 'codex'. Doctrine: cross-CLI parity needs surface as a parameter, not
|
|
147
|
+
// a literal. Added 2026-05-17 as the Option C (claude-codex parity)
|
|
148
|
+
// prereq; see plan §10.5 + §12 + the 27-perspective audit on the lib.
|
|
149
|
+
export const ARIA_HOOK_SURFACE = String(process.env.ARIA_HOOK_SURFACE || 'codex').toLowerCase().replace(/[^a-z0-9_-]/g, '') || 'codex';
|
|
150
|
+
const TURN_STATE_DIR = path.join(HOME, `.${ARIA_HOOK_SURFACE}`, 'tmp', 'aria-hook-turn-state');
|
|
151
|
+
const GOVERNANCE_GATE_PATH = path.join(HOME, '.aria', 'bin', 'aria-governance-gate');
|
|
152
|
+
const HIVE_SPOOL_PATH = path.join(HOME, '.aria', 'runtime', 'state', `${ARIA_HOOK_SURFACE}-hive-readiness-ledger.jsonl`);
|
|
153
|
+
const TURN_SUBSTRATE_PACKET_DIR = path.join(HOME, `.${ARIA_HOOK_SURFACE}`, 'tmp', 'aria-turn-substrate-packets');
|
|
154
|
+
const HARNESS_TICKER_CACHE_PATH = path.join(TURN_STATE_DIR, 'harness-live-ticker-cache.json');
|
|
155
|
+
const HARNESS_TICKER_STATE_PATH = path.join(HOME, '.aria', 'runtime', 'state', 'harness-live-ticker-state.json');
|
|
156
|
+
const HARNESS_TICKER_PID_PATH = path.join(HOME, '.aria', 'runtime', 'state', 'harness-live-ticker-sidecar.pid');
|
|
157
|
+
const HARNESS_TICKER_STATE_MAX_AGE_MS = Math.max(1000, Number(process.env.ARIA_HARNESS_TICKER_STATE_MAX_AGE_MS || 15000));
|
|
158
|
+
const HARNESS_TICKER_ATLAS_MAX_AGE_MS = Math.max(5000, Number(process.env.ARIA_HARNESS_TICKER_ATLAS_MAX_AGE_MS || 30000));
|
|
159
|
+
const ATLAS_SOCKET_PATH = path.join(HOME, '.aria', 'atlas', 'atlas-server.sock');
|
|
160
|
+
const TURN_SUBSTRATE_PACKET_MAX_AGE_MS = Math.max(60000, Number(process.env.ARIA_TURN_SUBSTRATE_PACKET_MAX_AGE_MS || 30 * 60 * 1000));
|
|
161
|
+
const HIVE_SYNC_TIMEOUT_MS = Math.max(250, Number(process.env.ARIA_HIVE_SYNC_TIMEOUT_MS || 750));
|
|
162
|
+
// 2026-05-17 producer-consumer alignment: the prior consumer paths were
|
|
163
|
+
// drifted from where producers actually wrote, leaving 6/7 sources dead
|
|
164
|
+
// (only learning fired, hence Gate checks 0 / Blocks 0 / Skills fired 0 /
|
|
165
|
+
// Durable saves 0 in the statusline). Specifically:
|
|
166
|
+
// - coach producer writes ~/.aria/first-class-coach-events.jsonl, NOT
|
|
167
|
+
// ~/.aria/runtime/state/coach-events.jsonl
|
|
168
|
+
// - readiness producer uses surface 'claude' (HIVE_SPOOL_PATH at line
|
|
169
|
+
// above), but the statusLine sidecar process runs without
|
|
170
|
+
// ARIA_HOOK_SURFACE set so the consumer used 'codex' as default and
|
|
171
|
+
// looked at codex-hive-readiness-ledger.jsonl which does not exist on
|
|
172
|
+
// a claude-code host. Resolve cross-surface by scanning every
|
|
173
|
+
// *-hive-readiness-ledger.jsonl so the fleet ticker is truly cross-CLI.
|
|
174
|
+
// - managed/gated/quality producers live in apps/arias-soul + connector
|
|
175
|
+
// runtime which write to the canonical paths when the mounted runtime
|
|
176
|
+
// is up; the consumer paths here remain correct.
|
|
177
|
+
// - file_touches has no jsonl producer (postgres-only); kept for
|
|
178
|
+
// forward-compat but readiness handler already bumps saves on
|
|
179
|
+
// kind=file_touch rows so the counter still moves.
|
|
180
|
+
function listReadinessLedgerPaths() {
|
|
181
|
+
try {
|
|
182
|
+
const dir = path.join(HOME, '.aria', 'runtime', 'state');
|
|
183
|
+
return readdirSync(dir)
|
|
184
|
+
.filter((f) => f.endsWith('-hive-readiness-ledger.jsonl'))
|
|
185
|
+
.map((f) => path.join(dir, f));
|
|
186
|
+
} catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const HARNESS_TICKER_SOURCES = Object.freeze([
|
|
192
|
+
{ id: 'coach', paths: [path.join(HOME, '.aria', 'first-class-coach-events.jsonl')] },
|
|
193
|
+
{ id: 'managed', paths: [path.join(HOME, '.aria', 'runtime', 'state', 'managed-runtime-ledger.jsonl')] },
|
|
194
|
+
{ id: 'gated', paths: [path.join(HOME, '.aria', 'runtime', 'state', 'gated-ledger.jsonl')] },
|
|
195
|
+
{ id: 'quality', paths: [path.join(HOME, '.aria', 'runtime', 'state', 'quality-violations.jsonl')] },
|
|
196
|
+
{ id: 'readiness', resolve: listReadinessLedgerPaths },
|
|
197
|
+
{ id: 'file_touches', paths: [path.join(HOME, '.aria', 'runtime', 'state', 'hive-file-touches.jsonl')] },
|
|
198
|
+
{ id: 'learning', paths: [path.join(HOME, '.aria', 'runtime', 'state', 'hive-learning-ledger.jsonl')] },
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
function readToken() {
|
|
202
|
+
const envToken = process.env.ARIA_HARNESS_TOKEN || process.env.ARIA_API_KEY || process.env.ARIA_MASTER_TOKEN;
|
|
203
|
+
if (envToken) return envToken;
|
|
204
|
+
const ownerPath = path.join(HOME, '.aria', 'owner-token');
|
|
205
|
+
if (existsSync(ownerPath)) return readFileSync(ownerPath, 'utf8').trim();
|
|
206
|
+
const licensePath = path.join(HOME, '.aria', 'license.json');
|
|
207
|
+
if (existsSync(licensePath)) {
|
|
208
|
+
const text = readFileSync(licensePath, 'utf8');
|
|
209
|
+
const harnessToken = text.match(/"harnessToken"\s*:\s*"([^"]+)"/)?.[1];
|
|
210
|
+
if (harnessToken) return harnessToken;
|
|
211
|
+
const token = text.match(/"token"\s*:\s*"([^"]+)"/)?.[1];
|
|
212
|
+
if (token) return token;
|
|
213
|
+
}
|
|
214
|
+
return '';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
let clientInstance = null;
|
|
218
|
+
|
|
219
|
+
class LocalHarnessPacketClient {
|
|
220
|
+
constructor(config) {
|
|
221
|
+
this.baseUrl = String(config.baseUrl || '').replace(/\/+$/, '');
|
|
222
|
+
this.apiKey = config.apiKey || '';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async getHarnessPacket(bodyOverride = {}) {
|
|
226
|
+
if (process.env.ARIA_HOOK_VERIFIER_MODE === '1') {
|
|
227
|
+
// Verifier-mode short-circuit (AI-12107). Skip HTTP fetch; return a
|
|
228
|
+
// shape-compatible no-op so the import path is exercised but no I/O.
|
|
229
|
+
return { packet: { schema: 'aria.verifier_noop.v1', verifier: true }, timestamp: new Date().toISOString(), version: '1.0.0' };
|
|
230
|
+
}
|
|
231
|
+
const defaultBody = {
|
|
232
|
+
message: 'harness packet preflight',
|
|
233
|
+
stage: 'preflight',
|
|
234
|
+
actor: `${ARIA_HOOK_SURFACE}-hook`,
|
|
235
|
+
system: `${ARIA_HOOK_SURFACE}-hook`,
|
|
236
|
+
platform: ARIA_HOOK_SURFACE,
|
|
237
|
+
};
|
|
238
|
+
const body = { ...defaultBody, ...bodyOverride };
|
|
239
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
240
|
+
if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;
|
|
241
|
+
const routes = ['/packet', '/api/harness/codex'];
|
|
242
|
+
let lastError = null;
|
|
243
|
+
for (const route of routes) {
|
|
244
|
+
try {
|
|
245
|
+
const response = await fetch(`${this.baseUrl}${route}`, {
|
|
246
|
+
method: 'POST',
|
|
247
|
+
headers,
|
|
248
|
+
body: JSON.stringify(body),
|
|
249
|
+
});
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
lastError = new Error(`Harness packet fetch failed: ${response.status} ${response.statusText}`);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const payload = await response.json();
|
|
255
|
+
return {
|
|
256
|
+
packet: payload?.packet ?? payload,
|
|
257
|
+
timestamp: new Date().toISOString(),
|
|
258
|
+
version: '1.0.0',
|
|
259
|
+
};
|
|
260
|
+
} catch (error) {
|
|
261
|
+
lastError = error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
throw lastError || new Error('Harness packet fetch failed.');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function getHarnessClient() {
|
|
269
|
+
if (clientInstance) return clientInstance;
|
|
270
|
+
clientInstance = new LocalHarnessPacketClient({
|
|
271
|
+
baseUrl: DEFAULT_RUNTIME_URL,
|
|
272
|
+
apiKey: readToken(),
|
|
273
|
+
workspaceRoot: process.cwd(),
|
|
274
|
+
});
|
|
275
|
+
return clientInstance;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export function readEventFromStdin() {
|
|
279
|
+
try {
|
|
280
|
+
const envEvent = process.env.ARIA_HOOK_EVENT_JSON || '';
|
|
281
|
+
if (envEvent.trim()) return JSON.parse(envEvent);
|
|
282
|
+
const raw = readFileSync(0, 'utf8');
|
|
283
|
+
return raw.trim() ? JSON.parse(raw) : {};
|
|
284
|
+
} catch {
|
|
285
|
+
return {};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function extractFirst(value, keys) {
|
|
290
|
+
if (!value || typeof value !== 'object') return null;
|
|
291
|
+
for (const key of keys) {
|
|
292
|
+
const candidate = value[key];
|
|
293
|
+
if (typeof candidate === 'string' && candidate.trim()) return candidate.trim();
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export function inferSessionId(event) {
|
|
299
|
+
const threadId =
|
|
300
|
+
extractFirst(event, ['thread_id', 'threadId', 'conversation_id', 'conversationId']) ||
|
|
301
|
+
ARIA_HOOK_SURFACE;
|
|
302
|
+
const turnId =
|
|
303
|
+
extractFirst(event, ['turn_id', 'turnId', 'session_id', 'sessionId']) ||
|
|
304
|
+
String(Date.now());
|
|
305
|
+
return `${ARIA_HOOK_SURFACE}:${threadId}:${turnId}`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function inferHiveThreadId(event = {}, sessionId = '') {
|
|
309
|
+
const threadId =
|
|
310
|
+
extractFirst(event, ['thread_id', 'threadId', 'conversation_id', 'conversationId']) ||
|
|
311
|
+
extractFirst(event?.metadata, ['thread_id', 'threadId', 'conversation_id', 'conversationId']);
|
|
312
|
+
if (threadId) return `${ARIA_HOOK_SURFACE}:${threadId}`;
|
|
313
|
+
const raw = sessionId || ARIA_HOOK_SURFACE;
|
|
314
|
+
return `${ARIA_HOOK_SURFACE}:${createHash('sha256').update(raw).digest('hex').slice(0, 16)}`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export function ensureTraceId(state = {}) {
|
|
318
|
+
return typeof state.traceId === 'string' && state.traceId ? state.traceId : `trace_${randomUUID()}`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function stableEvidenceString(value) {
|
|
322
|
+
if (typeof value === 'string') return value;
|
|
323
|
+
try { return JSON.stringify(value); } catch { return String(value); }
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function makeEvidenceRef(kind, value, metadata = {}) {
|
|
327
|
+
const raw = stableEvidenceString(value);
|
|
328
|
+
const sha256 = createHash('sha256').update(raw).digest('hex');
|
|
329
|
+
return {
|
|
330
|
+
evidenceId: `ev_${sha256.slice(0, 16)}`,
|
|
331
|
+
kind,
|
|
332
|
+
at: new Date().toISOString(),
|
|
333
|
+
sha256,
|
|
334
|
+
preview: raw.slice(0, 500),
|
|
335
|
+
metadata,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function actionLedgerSafeSegment(value) {
|
|
340
|
+
return String(value || 'global')
|
|
341
|
+
.replace(/[^a-zA-Z0-9._-]+/g, '-')
|
|
342
|
+
.replace(/^-+|-+$/g, '') || 'global';
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function stableActionLedgerJson(value) {
|
|
346
|
+
const seen = new WeakSet();
|
|
347
|
+
const normalize = (input) => {
|
|
348
|
+
if (!input || typeof input !== 'object') return input;
|
|
349
|
+
if (seen.has(input)) return '[Circular]';
|
|
350
|
+
seen.add(input);
|
|
351
|
+
if (Array.isArray(input)) return input.map((entry) => normalize(entry));
|
|
352
|
+
return Object.fromEntries(
|
|
353
|
+
Object.entries(input)
|
|
354
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
355
|
+
.map(([key, entry]) => [key, normalize(entry)]),
|
|
356
|
+
);
|
|
357
|
+
};
|
|
358
|
+
return JSON.stringify(normalize(value));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function actionLedgerSha256(value) {
|
|
362
|
+
return createHash('sha256')
|
|
363
|
+
.update(typeof value === 'string' ? value : stableActionLedgerJson(value))
|
|
364
|
+
.digest('hex');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function actionLedgerPaths({ home = HOME, projectId = 'global' } = {}) {
|
|
368
|
+
const root = path.join(home, '.aria', 'action-ledger', actionLedgerSafeSegment(projectId || 'global'));
|
|
369
|
+
return {
|
|
370
|
+
root,
|
|
371
|
+
eventsPath: path.join(root, 'events.jsonl'),
|
|
372
|
+
projectionPath: path.join(root, 'projection.json'),
|
|
373
|
+
publishOutboxPath: path.join(root, 'publish-outbox.jsonl'),
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function uniqueActionItems(items, keyFn) {
|
|
378
|
+
const seen = new Set();
|
|
379
|
+
const out = [];
|
|
380
|
+
for (const item of Array.isArray(items) ? items : []) {
|
|
381
|
+
const key = keyFn(item);
|
|
382
|
+
if (!key || seen.has(key)) continue;
|
|
383
|
+
seen.add(key);
|
|
384
|
+
out.push(item);
|
|
385
|
+
}
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function asActionRecord(value) {
|
|
390
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function taskStatusFromActionEvent(event) {
|
|
394
|
+
if (event.status === 'blocked' || event.status === 'failed' || event.status === 'needs_owner') return event.status;
|
|
395
|
+
if (event.lifecyclePhase === 'task_complete' || event.status === 'completed' || event.status === 'verified') return 'completed';
|
|
396
|
+
return 'active';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export function readActionLedgerEvents({ home = HOME, projectId = 'global', taskId = null, sessionId = null } = {}) {
|
|
400
|
+
const paths = actionLedgerPaths({ home, projectId });
|
|
401
|
+
if (!existsSync(paths.eventsPath)) return [];
|
|
402
|
+
return readFileSync(paths.eventsPath, 'utf8')
|
|
403
|
+
.split(/\r?\n/)
|
|
404
|
+
.map((line) => line.trim())
|
|
405
|
+
.filter(Boolean)
|
|
406
|
+
.map((line) => {
|
|
407
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
408
|
+
})
|
|
409
|
+
.filter(Boolean)
|
|
410
|
+
.filter((event) => !taskId || event.taskId === taskId)
|
|
411
|
+
.filter((event) => !sessionId || event.sessionId === sessionId);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function projectActionLedger(events = []) {
|
|
415
|
+
const tasks = {};
|
|
416
|
+
const sessions = {};
|
|
417
|
+
let latestQa = null;
|
|
418
|
+
let latestLearningDelta = null;
|
|
419
|
+
let latestAtlas = null;
|
|
420
|
+
let correctionRequired = false;
|
|
421
|
+
const sentinelFindings = [];
|
|
422
|
+
const sorted = [...events].sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt));
|
|
423
|
+
for (const event of sorted) {
|
|
424
|
+
sessions[event.sessionId] = {
|
|
425
|
+
sessionId: event.sessionId,
|
|
426
|
+
threadId: event.threadId,
|
|
427
|
+
surface: event.surface,
|
|
428
|
+
latestEventId: event.eventId,
|
|
429
|
+
latestPhase: event.lifecyclePhase,
|
|
430
|
+
latestStatus: event.status,
|
|
431
|
+
updatedAt: event.createdAt,
|
|
432
|
+
};
|
|
433
|
+
if (event.qaReceipt) {
|
|
434
|
+
latestQa = event.qaReceipt;
|
|
435
|
+
if (event.qaReceipt.ok === false || event.qaReceipt.passed === false || event.qaReceipt.decision === 'repair') {
|
|
436
|
+
correctionRequired = true;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (event.correctionPlan?.required === true) correctionRequired = true;
|
|
440
|
+
if (event.learningDelta) latestLearningDelta = event.learningDelta;
|
|
441
|
+
if (event.atlas) latestAtlas = event.atlas;
|
|
442
|
+
sentinelFindings.push(...(Array.isArray(event.sentinelFindings) ? event.sentinelFindings : []));
|
|
443
|
+
if (!event.taskId) continue;
|
|
444
|
+
const prior = tasks[event.taskId] || {
|
|
445
|
+
taskId: event.taskId,
|
|
446
|
+
projectId: event.projectId,
|
|
447
|
+
threadId: event.threadId,
|
|
448
|
+
status: 'active',
|
|
449
|
+
activePhase: null,
|
|
450
|
+
phases: {},
|
|
451
|
+
fileClaims: [],
|
|
452
|
+
evidenceRefs: [],
|
|
453
|
+
latestEventId: null,
|
|
454
|
+
latestQa: null,
|
|
455
|
+
latestLearningDelta: null,
|
|
456
|
+
latestAtlas: null,
|
|
457
|
+
sentinelFindingCount: 0,
|
|
458
|
+
updatedAt: null,
|
|
459
|
+
};
|
|
460
|
+
const phases = prior.phases && typeof prior.phases === 'object' ? prior.phases : {};
|
|
461
|
+
if (event.phaseId) {
|
|
462
|
+
phases[event.phaseId] = {
|
|
463
|
+
phaseId: event.phaseId,
|
|
464
|
+
status: event.status,
|
|
465
|
+
latestLifecyclePhase: event.lifecyclePhase,
|
|
466
|
+
latestEventId: event.eventId,
|
|
467
|
+
updatedAt: event.createdAt,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
tasks[event.taskId] = {
|
|
471
|
+
...prior,
|
|
472
|
+
status: taskStatusFromActionEvent(event),
|
|
473
|
+
activePhase: event.phaseId || prior.activePhase,
|
|
474
|
+
phases,
|
|
475
|
+
fileClaims: uniqueActionItems([...(Array.isArray(prior.fileClaims) ? prior.fileClaims : []), ...(event.fileClaims || [])], (claim) => claim.path).slice(-100),
|
|
476
|
+
evidenceRefs: [...(Array.isArray(prior.evidenceRefs) ? prior.evidenceRefs : []), ...(event.evidenceRefs || [])].slice(-100),
|
|
477
|
+
latestEventId: event.eventId,
|
|
478
|
+
latestQa: event.qaReceipt || prior.latestQa || null,
|
|
479
|
+
latestLearningDelta: event.learningDelta || prior.latestLearningDelta || null,
|
|
480
|
+
latestAtlas: event.atlas || prior.latestAtlas || null,
|
|
481
|
+
sentinelFindingCount: Number(prior.sentinelFindingCount || 0) + (Array.isArray(event.sentinelFindings) ? event.sentinelFindings.length : 0),
|
|
482
|
+
correctionRequired,
|
|
483
|
+
updatedAt: event.createdAt,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
const latest = sorted[sorted.length - 1] || null;
|
|
487
|
+
return {
|
|
488
|
+
schema: 'aria.action_ledger_projection.v1',
|
|
489
|
+
generatedAt: new Date().toISOString(),
|
|
490
|
+
eventCount: sorted.length,
|
|
491
|
+
latestEvent: latest ? {
|
|
492
|
+
eventId: latest.eventId,
|
|
493
|
+
actionId: latest.actionId,
|
|
494
|
+
surface: latest.surface,
|
|
495
|
+
lifecyclePhase: latest.lifecyclePhase,
|
|
496
|
+
status: latest.status,
|
|
497
|
+
createdAt: latest.createdAt,
|
|
498
|
+
} : null,
|
|
499
|
+
tasks,
|
|
500
|
+
sessions,
|
|
501
|
+
correctionRequired,
|
|
502
|
+
latestQa,
|
|
503
|
+
latestLearningDelta,
|
|
504
|
+
latestAtlas,
|
|
505
|
+
sentinelFindings: uniqueActionItems(sentinelFindings, (finding) => String(finding.id || `${finding.source}:${finding.kind}:${finding.target}`)).slice(-50),
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function inferActionLedgerProjectId({ event = {}, state = {}, sessionId = '' } = {}) {
|
|
510
|
+
const explicit =
|
|
511
|
+
event?.project_id ||
|
|
512
|
+
event?.projectId ||
|
|
513
|
+
state?.actionLedger?.projectId ||
|
|
514
|
+
process.env.ARIA_ACTION_LEDGER_PROJECT_ID;
|
|
515
|
+
if (explicit) return String(explicit);
|
|
516
|
+
const thread = state?.hiveThreadId || inferHiveThreadId(event, sessionId);
|
|
517
|
+
return `${ARIA_HOOK_SURFACE}-${actionLedgerSafeSegment(thread)}`;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function inferActionLedgerTaskId({ event = {}, state = {}, sessionId = '', ledgerResult = null } = {}) {
|
|
521
|
+
return String(
|
|
522
|
+
event?.task_id ||
|
|
523
|
+
event?.taskId ||
|
|
524
|
+
state?.actionLedger?.taskId ||
|
|
525
|
+
ledgerResult?.ledger?.ledgerId ||
|
|
526
|
+
state?.taskProjectLedgerId ||
|
|
527
|
+
`${ARIA_HOOK_SURFACE}-turn-${actionLedgerSha256(sessionId).slice(0, 12)}`,
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function actionAtlasFromState(state = {}) {
|
|
532
|
+
const atlas =
|
|
533
|
+
state?.harnessTicker?.atlas ||
|
|
534
|
+
state?.turnSubstratePacket?.atlas ||
|
|
535
|
+
state?.forcedSkillLoad?.atlas ||
|
|
536
|
+
null;
|
|
537
|
+
if (!atlas || typeof atlas !== 'object') return null;
|
|
538
|
+
return {
|
|
539
|
+
contextHash: atlas.contextHash || (atlas.snapshotId ? actionLedgerSha256(atlas).slice(0, 24) : null),
|
|
540
|
+
snapshotId: atlas.snapshotId ?? null,
|
|
541
|
+
status: atlas.status || (atlas.ageSeconds !== undefined ? 'observed' : null),
|
|
542
|
+
target: atlas.target || null,
|
|
543
|
+
dossierTargets: Array.isArray(atlas.dossierTargets) ? atlas.dossierTargets : [],
|
|
544
|
+
doctrineRefs: Array.isArray(atlas.doctrineRefs) ? atlas.doctrineRefs : [],
|
|
545
|
+
blastRadius: atlas.blastRadius || null,
|
|
546
|
+
verificationPredicates: Array.isArray(atlas.verificationPredicates) ? atlas.verificationPredicates : [],
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function sentinelFromState(state = {}) {
|
|
551
|
+
const atlas = state?.harnessTicker?.atlas || null;
|
|
552
|
+
const top = atlas?.sentinelTop || null;
|
|
553
|
+
const findings = [];
|
|
554
|
+
if (top) {
|
|
555
|
+
findings.push({
|
|
556
|
+
id: top.id ?? null,
|
|
557
|
+
severity: top.severity || null,
|
|
558
|
+
source: top.source || 'sentinel',
|
|
559
|
+
kind: top.kind || null,
|
|
560
|
+
target: top.target || null,
|
|
561
|
+
reason: top.reason || null,
|
|
562
|
+
status: 'observed',
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
if (Array.isArray(state?.turnSubstratePacket?.sentinelFindings)) {
|
|
566
|
+
findings.push(...state.turnSubstratePacket.sentinelFindings);
|
|
567
|
+
}
|
|
568
|
+
return findings;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export function buildActionEvent(input = {}) {
|
|
572
|
+
const createdAt = input.createdAt || new Date().toISOString();
|
|
573
|
+
const actionId = input.actionId || `act_${randomUUID()}`;
|
|
574
|
+
const base = {
|
|
575
|
+
schema: 'aria.action_event.v1',
|
|
576
|
+
eventId: '',
|
|
577
|
+
actionId,
|
|
578
|
+
parentActionId: input.parentActionId || null,
|
|
579
|
+
sessionId: input.sessionId,
|
|
580
|
+
threadId: input.threadId || null,
|
|
581
|
+
surface: input.surface || ARIA_HOOK_SURFACE,
|
|
582
|
+
projectId: input.projectId || null,
|
|
583
|
+
taskId: input.taskId || null,
|
|
584
|
+
phaseId: input.phaseId || null,
|
|
585
|
+
lifecyclePhase: input.lifecyclePhase || 'turn',
|
|
586
|
+
status: input.status || 'active',
|
|
587
|
+
cwd: input.cwd || null,
|
|
588
|
+
intent: input.intent || null,
|
|
589
|
+
toolName: input.toolName || null,
|
|
590
|
+
fileClaims: uniqueActionItems(input.fileClaims || [], (claim) => claim.path),
|
|
591
|
+
evidenceRefs: Array.isArray(input.evidenceRefs) ? input.evidenceRefs : [],
|
|
592
|
+
skillReceipt: asActionRecord(input.skillReceipt),
|
|
593
|
+
runtimeReceipt: asActionRecord(input.runtimeReceipt),
|
|
594
|
+
qaReceipt: asActionRecord(input.qaReceipt),
|
|
595
|
+
correctionPlan: asActionRecord(input.correctionPlan),
|
|
596
|
+
learningDelta: asActionRecord(input.learningDelta),
|
|
597
|
+
atlas: input.atlas || null,
|
|
598
|
+
sentinelFindings: uniqueActionItems(input.sentinelFindings || [], (finding) => String(finding.id || `${finding.source}:${finding.kind}:${finding.target}`)),
|
|
599
|
+
metadata: input.metadata || {},
|
|
600
|
+
createdAt,
|
|
601
|
+
};
|
|
602
|
+
const eventHash = actionLedgerSha256(base);
|
|
603
|
+
return {
|
|
604
|
+
...base,
|
|
605
|
+
eventId: `ev_${eventHash.slice(0, 24)}`,
|
|
606
|
+
eventHash,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export function recordActionEventLocal(input = {}, options = {}) {
|
|
611
|
+
const event = buildActionEvent(input);
|
|
612
|
+
const paths = actionLedgerPaths({ home: options.home || HOME, projectId: event.projectId || options.projectId || 'global' });
|
|
613
|
+
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
614
|
+
appendFileSync(paths.eventsPath, JSON.stringify(event) + '\n', { mode: 0o600 });
|
|
615
|
+
const projection = projectActionLedger(readActionLedgerEvents({
|
|
616
|
+
home: options.home || HOME,
|
|
617
|
+
projectId: event.projectId || options.projectId || 'global',
|
|
618
|
+
}));
|
|
619
|
+
writeFileSync(paths.projectionPath, JSON.stringify(projection, null, 2) + '\n', { mode: 0o600 });
|
|
620
|
+
return { ok: true, event, paths, projection };
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
export async function publishCodexActionEventToRuntime(actionLedger = {}) {
|
|
624
|
+
const event = actionLedger?.event;
|
|
625
|
+
if (!event) return { ok: false, skipped: true, reason: 'missing_action_event' };
|
|
626
|
+
const routes = [];
|
|
627
|
+
const post = async (route, body) => {
|
|
628
|
+
const result = await runtimePostBounded(route, body);
|
|
629
|
+
routes.push({ route, ok: true, result });
|
|
630
|
+
};
|
|
631
|
+
try {
|
|
632
|
+
await post('/api/hive/session-lifecycle', {
|
|
633
|
+
session_id: event.sessionId,
|
|
634
|
+
thread_id: event.threadId,
|
|
635
|
+
event: event.lifecyclePhase,
|
|
636
|
+
status: event.status,
|
|
637
|
+
intent_summary: event.intent || `${event.surface} ${event.lifecyclePhase}`,
|
|
638
|
+
file_claims: event.fileClaims,
|
|
639
|
+
source: `${ARIA_HOOK_SURFACE}-native-action-ledger`,
|
|
640
|
+
body: { action_event: event },
|
|
641
|
+
});
|
|
642
|
+
if (event.projectId) {
|
|
643
|
+
await post('/api/hive/project-context', {
|
|
644
|
+
project_id: event.projectId,
|
|
645
|
+
session_id: event.sessionId,
|
|
646
|
+
thread_id: event.threadId,
|
|
647
|
+
active_phase: event.phaseId,
|
|
648
|
+
event: event.lifecyclePhase,
|
|
649
|
+
source: `${ARIA_HOOK_SURFACE}-native-action-ledger`,
|
|
650
|
+
capsule: {
|
|
651
|
+
latest_action_event: {
|
|
652
|
+
event_id: event.eventId,
|
|
653
|
+
action_id: event.actionId,
|
|
654
|
+
event_hash: event.eventHash,
|
|
655
|
+
surface: event.surface,
|
|
656
|
+
lifecycle_phase: event.lifecyclePhase,
|
|
657
|
+
status: event.status,
|
|
658
|
+
},
|
|
659
|
+
active_task_id: event.taskId,
|
|
660
|
+
active_phase: event.phaseId,
|
|
661
|
+
latest_qa: event.qaReceipt,
|
|
662
|
+
latest_learning_delta: event.learningDelta,
|
|
663
|
+
latest_atlas: event.atlas,
|
|
664
|
+
sentinel_findings: event.sentinelFindings,
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
if (event.taskId) {
|
|
669
|
+
await post('/task-project-ledger/event', {
|
|
670
|
+
platform: event.surface,
|
|
671
|
+
phase: event.lifecyclePhase,
|
|
672
|
+
source: `${ARIA_HOOK_SURFACE}-native-action-ledger`,
|
|
673
|
+
event: {
|
|
674
|
+
taskId: event.taskId,
|
|
675
|
+
phaseId: event.phaseId,
|
|
676
|
+
sessionId: event.sessionId,
|
|
677
|
+
actionId: event.actionId,
|
|
678
|
+
eventId: event.eventId,
|
|
679
|
+
intent: event.intent,
|
|
680
|
+
},
|
|
681
|
+
evidence: {
|
|
682
|
+
actionEventHash: event.eventHash,
|
|
683
|
+
evidenceRefs: event.evidenceRefs,
|
|
684
|
+
qaReceipt: event.qaReceipt,
|
|
685
|
+
correctionPlan: event.correctionPlan,
|
|
686
|
+
learningDelta: event.learningDelta,
|
|
687
|
+
atlas: event.atlas,
|
|
688
|
+
sentinelFindings: event.sentinelFindings,
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
return { ok: true, routeCount: routes.length, routes };
|
|
693
|
+
} catch (error) {
|
|
694
|
+
const failure = {
|
|
695
|
+
schema: 'aria.codex_native_action_publish_failure.v1',
|
|
696
|
+
at: new Date().toISOString(),
|
|
697
|
+
eventId: event.eventId,
|
|
698
|
+
actionId: event.actionId,
|
|
699
|
+
projectId: event.projectId,
|
|
700
|
+
taskId: event.taskId,
|
|
701
|
+
phaseId: event.phaseId,
|
|
702
|
+
error: error instanceof Error ? error.message : String(error),
|
|
703
|
+
recovery: 'queued_for_codex_native_action_publish_replay',
|
|
704
|
+
event,
|
|
705
|
+
};
|
|
706
|
+
try {
|
|
707
|
+
mkdirSync(path.dirname(actionLedger.paths?.publishOutboxPath || actionLedgerPaths({ projectId: event.projectId }).publishOutboxPath), { recursive: true, mode: 0o700 });
|
|
708
|
+
appendFileSync(actionLedger.paths?.publishOutboxPath || actionLedgerPaths({ projectId: event.projectId }).publishOutboxPath, JSON.stringify(failure) + '\n', { mode: 0o600 });
|
|
709
|
+
} catch {}
|
|
710
|
+
return { ok: false, queued: true, failure };
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
export function recordCodexActionEvent({
|
|
715
|
+
event = {},
|
|
716
|
+
state = {},
|
|
717
|
+
sessionId = '',
|
|
718
|
+
ledgerResult = null,
|
|
719
|
+
lifecyclePhase = 'turn',
|
|
720
|
+
status = 'active',
|
|
721
|
+
intent = '',
|
|
722
|
+
action = null,
|
|
723
|
+
toolName = null,
|
|
724
|
+
fileClaims = [],
|
|
725
|
+
evidenceRefs = [],
|
|
726
|
+
skillReceipt = null,
|
|
727
|
+
runtimeReceipt = null,
|
|
728
|
+
qaReceipt = null,
|
|
729
|
+
correctionPlan = null,
|
|
730
|
+
learningDelta = null,
|
|
731
|
+
metadata = {},
|
|
732
|
+
} = {}) {
|
|
733
|
+
try {
|
|
734
|
+
const projectId = inferActionLedgerProjectId({ event, state, sessionId });
|
|
735
|
+
const taskId = inferActionLedgerTaskId({ event, state, sessionId, ledgerResult });
|
|
736
|
+
return recordActionEventLocal({
|
|
737
|
+
sessionId,
|
|
738
|
+
threadId: state?.hiveThreadId || inferHiveThreadId(event, sessionId),
|
|
739
|
+
surface: ARIA_HOOK_SURFACE,
|
|
740
|
+
projectId,
|
|
741
|
+
taskId,
|
|
742
|
+
phaseId: lifecyclePhase,
|
|
743
|
+
lifecyclePhase,
|
|
744
|
+
status,
|
|
745
|
+
cwd: process.cwd(),
|
|
746
|
+
intent: intent || state?.userText || null,
|
|
747
|
+
toolName,
|
|
748
|
+
fileClaims,
|
|
749
|
+
evidenceRefs,
|
|
750
|
+
skillReceipt: skillReceipt || state?.forcedSkillLoad || null,
|
|
751
|
+
runtimeReceipt,
|
|
752
|
+
qaReceipt,
|
|
753
|
+
correctionPlan,
|
|
754
|
+
learningDelta,
|
|
755
|
+
atlas: actionAtlasFromState(state),
|
|
756
|
+
sentinelFindings: sentinelFromState(state),
|
|
757
|
+
metadata: {
|
|
758
|
+
hookEvent: event?.hook_event_name || event?.hookEventName || null,
|
|
759
|
+
action,
|
|
760
|
+
source: `${ARIA_HOOK_SURFACE}-native-hook`,
|
|
761
|
+
...metadata,
|
|
762
|
+
},
|
|
763
|
+
}, { projectId });
|
|
764
|
+
} catch (error) {
|
|
765
|
+
return {
|
|
766
|
+
ok: false,
|
|
767
|
+
error: error instanceof Error ? error.message : String(error),
|
|
768
|
+
event: null,
|
|
769
|
+
paths: null,
|
|
770
|
+
projection: null,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
export function recordLocalHiveSpool(kind, payload = {}) {
|
|
776
|
+
const row = {
|
|
777
|
+
schema: 'aria.codex_hive_spool.v1',
|
|
778
|
+
kind,
|
|
779
|
+
at: new Date().toISOString(),
|
|
780
|
+
source: `${ARIA_HOOK_SURFACE}-hooks`,
|
|
781
|
+
payload,
|
|
782
|
+
};
|
|
783
|
+
try {
|
|
784
|
+
mkdirSync(path.dirname(HIVE_SPOOL_PATH), { recursive: true, mode: 0o700 });
|
|
785
|
+
appendFileSync(HIVE_SPOOL_PATH, JSON.stringify(row) + '\n', { mode: 0o600 });
|
|
786
|
+
return {
|
|
787
|
+
ok: true,
|
|
788
|
+
path: HIVE_SPOOL_PATH,
|
|
789
|
+
evidenceRef: makeEvidenceRef(`local_hive_spool_${kind}`, row, {
|
|
790
|
+
path: HIVE_SPOOL_PATH,
|
|
791
|
+
}),
|
|
792
|
+
};
|
|
793
|
+
} catch (error) {
|
|
794
|
+
return {
|
|
795
|
+
ok: false,
|
|
796
|
+
path: HIVE_SPOOL_PATH,
|
|
797
|
+
error: error instanceof Error ? error.message : String(error),
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
export function inferUserId(event) {
|
|
803
|
+
return (
|
|
804
|
+
extractFirst(event, ['user_id', 'userId']) ||
|
|
805
|
+
extractFirst(event?.metadata, ['user_id', 'userId'])
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
export function extractText(value) {
|
|
810
|
+
if (!value) return '';
|
|
811
|
+
if (typeof value === 'string') return value.trim();
|
|
812
|
+
if (Array.isArray(value)) {
|
|
813
|
+
return value.map(extractText).filter(Boolean).join('\n\n').trim();
|
|
814
|
+
}
|
|
815
|
+
if (typeof value === 'object') {
|
|
816
|
+
const parts = [];
|
|
817
|
+
for (const key of ['text', 'message', 'content', 'input_text', 'inputText', 'reasoning_text', 'summary_text', 'delta']) {
|
|
818
|
+
if (key in value) {
|
|
819
|
+
const piece = extractText(value[key]);
|
|
820
|
+
if (piece) parts.push(piece);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return parts.join('\n\n').trim();
|
|
824
|
+
}
|
|
825
|
+
return '';
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function ensureTurnStateDir() {
|
|
829
|
+
if (!existsSync(TURN_STATE_DIR)) {
|
|
830
|
+
mkdirSync(TURN_STATE_DIR, { recursive: true, mode: 0o700 });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function turnStatePath(sessionId) {
|
|
835
|
+
ensureTurnStateDir();
|
|
836
|
+
const safe = String(sessionId || ARIA_HOOK_SURFACE).replace(/[^a-zA-Z0-9._-]+/g, '_');
|
|
837
|
+
return path.join(TURN_STATE_DIR, `${safe}.json`);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function ensureTurnPacketDir() {
|
|
841
|
+
if (!existsSync(TURN_SUBSTRATE_PACKET_DIR)) {
|
|
842
|
+
mkdirSync(TURN_SUBSTRATE_PACKET_DIR, { recursive: true, mode: 0o700 });
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function safePacketAlias(value) {
|
|
847
|
+
return String(value || ARIA_HOOK_SURFACE).replace(/[^a-zA-Z0-9._-]+/g, '_');
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
function turnPacketPath(alias) {
|
|
851
|
+
ensureTurnPacketDir();
|
|
852
|
+
return path.join(TURN_SUBSTRATE_PACKET_DIR, `${safePacketAlias(alias)}.json`);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function packetIsFresh(packet) {
|
|
856
|
+
const stamp = Date.parse(packet?.updatedAt || packet?.createdAt || '');
|
|
857
|
+
if (!Number.isFinite(stamp)) return false;
|
|
858
|
+
return Date.now() - stamp <= TURN_SUBSTRATE_PACKET_MAX_AGE_MS;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
export function loadTurnState(sessionId) {
|
|
862
|
+
const statePath = turnStatePath(sessionId);
|
|
863
|
+
if (!existsSync(statePath)) return {};
|
|
864
|
+
try {
|
|
865
|
+
return JSON.parse(readFileSync(statePath, 'utf8'));
|
|
866
|
+
} catch {
|
|
867
|
+
return {};
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
export function saveTurnState(sessionId, patch) {
|
|
872
|
+
const next = {
|
|
873
|
+
...loadTurnState(sessionId),
|
|
874
|
+
...patch,
|
|
875
|
+
sessionId,
|
|
876
|
+
updatedAt: new Date().toISOString(),
|
|
877
|
+
};
|
|
878
|
+
writeFileSync(turnStatePath(sessionId), JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
|
|
879
|
+
return next;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
export function clearTurnState(sessionId) {
|
|
883
|
+
const statePath = turnStatePath(sessionId);
|
|
884
|
+
if (!existsSync(statePath)) return;
|
|
885
|
+
try {
|
|
886
|
+
unlinkSync(statePath);
|
|
887
|
+
} catch {}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function loadHarnessTickerCache() {
|
|
891
|
+
try {
|
|
892
|
+
if (!existsSync(HARNESS_TICKER_CACHE_PATH)) return { version: 1, files: {}, counts: {}, latest: null };
|
|
893
|
+
const parsed = JSON.parse(readFileSync(HARNESS_TICKER_CACHE_PATH, 'utf8'));
|
|
894
|
+
return {
|
|
895
|
+
version: Number(parsed?.version || 1),
|
|
896
|
+
files: parsed && typeof parsed.files === 'object' ? parsed.files : {},
|
|
897
|
+
counts: parsed && typeof parsed.counts === 'object' ? parsed.counts : {},
|
|
898
|
+
latest: parsed?.latest || null,
|
|
899
|
+
atlas: parsed?.atlas && typeof parsed.atlas === 'object' ? parsed.atlas : null,
|
|
900
|
+
atlasUpdatedAt: parsed?.atlasUpdatedAt || null,
|
|
901
|
+
};
|
|
902
|
+
} catch {
|
|
903
|
+
return { version: 1, files: {}, counts: {}, latest: null };
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
function saveHarnessTickerCache(cache) {
|
|
908
|
+
try {
|
|
909
|
+
ensureTurnStateDir();
|
|
910
|
+
writeFileSync(HARNESS_TICKER_CACHE_PATH, JSON.stringify(cache, null, 2) + '\n', { mode: 0o600 });
|
|
911
|
+
} catch {}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
function writeJsonAtomic(pathname, value) {
|
|
915
|
+
mkdirSync(path.dirname(pathname), { recursive: true, mode: 0o700 });
|
|
916
|
+
const tmp = `${pathname}.${process.pid}.${Date.now()}.tmp`;
|
|
917
|
+
writeFileSync(tmp, JSON.stringify(value, null, 2) + '\n', { mode: 0o600 });
|
|
918
|
+
renameSync(tmp, pathname);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function readJsonlAppend(pathname, previous = {}) {
|
|
922
|
+
if (!existsSync(pathname)) return { rows: [], offset: 0, mtimeMs: 0 };
|
|
923
|
+
let stats = null;
|
|
924
|
+
try { stats = statSync(pathname); } catch { return { rows: [], offset: 0, mtimeMs: 0 }; }
|
|
925
|
+
const start = Number.isFinite(previous?.offset) && previous.offset <= stats.size ? previous.offset : 0;
|
|
926
|
+
const byteCount = Math.max(0, stats.size - start);
|
|
927
|
+
if (byteCount === 0) return { rows: [], offset: stats.size, mtimeMs: stats.mtimeMs };
|
|
928
|
+
let fd = null;
|
|
929
|
+
try {
|
|
930
|
+
fd = openSync(pathname, 'r');
|
|
931
|
+
const buffer = Buffer.allocUnsafe(byteCount);
|
|
932
|
+
const bytesRead = readSync(fd, buffer, 0, byteCount, start);
|
|
933
|
+
const text = buffer.subarray(0, bytesRead).toString('utf8');
|
|
934
|
+
const rows = text
|
|
935
|
+
.split('\n')
|
|
936
|
+
.filter(Boolean)
|
|
937
|
+
.map((line) => {
|
|
938
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
939
|
+
})
|
|
940
|
+
.filter(Boolean);
|
|
941
|
+
return { rows, offset: stats.size, mtimeMs: stats.mtimeMs };
|
|
942
|
+
} catch {
|
|
943
|
+
return { rows: [], offset: stats.size, mtimeMs: stats.mtimeMs };
|
|
944
|
+
} finally {
|
|
945
|
+
if (fd !== null) {
|
|
946
|
+
try { closeSync(fd); } catch {}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function tickerCounts(input = {}) {
|
|
952
|
+
return {
|
|
953
|
+
gates: Number(input.gates || 0),
|
|
954
|
+
repairs: Number(input.repairs || 0),
|
|
955
|
+
blocks: Number(input.blocks || 0),
|
|
956
|
+
skills: Number(input.skills || 0),
|
|
957
|
+
saves: Number(input.saves || 0),
|
|
958
|
+
learnings: Number(input.learnings || 0),
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function bumpTickerCount(counts, key, amount = 1) {
|
|
963
|
+
counts[key] = Number(counts[key] || 0) + amount;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function newestTickerEvent(current, candidate) {
|
|
967
|
+
const candidateAt = candidate?.at || candidate?.created_at || null;
|
|
968
|
+
if (!candidateAt) return current;
|
|
969
|
+
const currentMs = Date.parse(current?.at || '');
|
|
970
|
+
const candidateMs = Date.parse(candidateAt);
|
|
971
|
+
if (!Number.isFinite(candidateMs)) return current;
|
|
972
|
+
if (!Number.isFinite(currentMs) || candidateMs >= currentMs) {
|
|
973
|
+
return {
|
|
974
|
+
at: candidateAt,
|
|
975
|
+
label: String(candidate.label || candidate.decision || candidate.phase || candidate.kind || candidate.status || 'event').slice(0, 32),
|
|
976
|
+
source: candidate.source || null,
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
return current;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
function applyHarnessTickerRows(cache, sourceId, rows = []) {
|
|
983
|
+
const counts = tickerCounts(cache.counts);
|
|
984
|
+
let latest = cache.latest || null;
|
|
985
|
+
for (const row of rows) {
|
|
986
|
+
const gates = Array.isArray(row.gates) ? row.gates : [];
|
|
987
|
+
if (sourceId === 'gated' && gates.length > 0) {
|
|
988
|
+
bumpTickerCount(counts, 'gates', gates.length);
|
|
989
|
+
bumpTickerCount(counts, 'blocks', gates.filter((gate) => gate && gate.passed === false).length);
|
|
990
|
+
}
|
|
991
|
+
if (sourceId === 'coach') {
|
|
992
|
+
// Every coach event row is one gate-check the coach hook performed
|
|
993
|
+
// (PreToolUse, UserPromptSubmit, Stop, etc.). Producer schema is
|
|
994
|
+
// aria.first_class_coach.v1.event with shape
|
|
995
|
+
// {schema, at, platform, phase, source, evidence}. Decision / repair /
|
|
996
|
+
// block fields are not present in current producer output; counters
|
|
997
|
+
// for those remain at zero until the coach hook emits them. The
|
|
998
|
+
// legacy branches below are kept for forward-compat with the older
|
|
999
|
+
// aria.coach_event.v0 schema some surfaces still emit.
|
|
1000
|
+
bumpTickerCount(counts, 'gates');
|
|
1001
|
+
if (row.decision === 'repair_once') bumpTickerCount(counts, 'repairs');
|
|
1002
|
+
if (row.decision === 'hard_block') bumpTickerCount(counts, 'blocks');
|
|
1003
|
+
const posture = row.evidence?.posture || row.posture;
|
|
1004
|
+
if (posture === 'repair' || posture === 'repair_once') bumpTickerCount(counts, 'repairs');
|
|
1005
|
+
if (posture === 'hard_block' || posture === 'destructive') bumpTickerCount(counts, 'blocks');
|
|
1006
|
+
const forced = row.metadata?.forcedSkillLoad;
|
|
1007
|
+
const skillCount = Array.isArray(forced?.skillExecutionReceipt?.firedSkillIds)
|
|
1008
|
+
? forced.skillExecutionReceipt.firedSkillIds.length
|
|
1009
|
+
: Array.isArray(forced?.loadedSkillIds)
|
|
1010
|
+
? forced.loadedSkillIds.length
|
|
1011
|
+
: 0;
|
|
1012
|
+
if (skillCount > 0) bumpTickerCount(counts, 'skills', skillCount);
|
|
1013
|
+
}
|
|
1014
|
+
if (sourceId === 'managed') {
|
|
1015
|
+
if (Array.isArray(row.repair_attempts)) bumpTickerCount(counts, 'repairs', row.repair_attempts.length);
|
|
1016
|
+
if (Array.isArray(row.loaded_skill_ids)) bumpTickerCount(counts, 'skills', row.loaded_skill_ids.length);
|
|
1017
|
+
if (/blocked|failed/i.test(String(row.release_decision || row.quality_gate_status || ''))) bumpTickerCount(counts, 'blocks');
|
|
1018
|
+
}
|
|
1019
|
+
if (sourceId === 'quality') {
|
|
1020
|
+
bumpTickerCount(counts, 'blocks');
|
|
1021
|
+
}
|
|
1022
|
+
if (sourceId === 'readiness' && row.kind === 'file_touch') {
|
|
1023
|
+
bumpTickerCount(counts, 'saves');
|
|
1024
|
+
}
|
|
1025
|
+
if (sourceId === 'file_touches') {
|
|
1026
|
+
bumpTickerCount(counts, 'saves');
|
|
1027
|
+
}
|
|
1028
|
+
if (sourceId === 'learning' && row.schema === 'aria.hive_learning.v1') {
|
|
1029
|
+
bumpTickerCount(counts, 'learnings');
|
|
1030
|
+
if (row.trust_state === 'promoted_rule' || row.status === 'accepted') bumpTickerCount(counts, 'saves');
|
|
1031
|
+
if (/reflection|principle|promotion|canary|verification/i.test(String(row.row_type || ''))) {
|
|
1032
|
+
latest = newestTickerEvent(latest, {
|
|
1033
|
+
at: row.at || row.created_at,
|
|
1034
|
+
label: `learn_${row.row_type || row.status || 'event'}`,
|
|
1035
|
+
source: sourceId,
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
latest = newestTickerEvent(latest, {
|
|
1040
|
+
at: row.at || row.created_at,
|
|
1041
|
+
label: row.decision || row.release_decision || row.phase || row.kind || row.row_type || row.finalOutcome || row.status,
|
|
1042
|
+
source: sourceId,
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
cache.counts = counts;
|
|
1046
|
+
cache.latest = latest;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function formatTickerDelta(next, previous) {
|
|
1050
|
+
const delta = Number(next || 0) - Number(previous || 0);
|
|
1051
|
+
return delta > 0 ? ` (+${delta})` : '';
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
function formatCompactNumber(value) {
|
|
1055
|
+
const n = Number(value || 0);
|
|
1056
|
+
if (n >= 1000000) return `${(n / 1000000).toFixed(1).replace(/\.0$/, '')}m`;
|
|
1057
|
+
if (n >= 1000) return `${(n / 1000).toFixed(1).replace(/\.0$/, '')}k`;
|
|
1058
|
+
return String(n);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
function formatAge(seconds) {
|
|
1062
|
+
const n = Number(seconds || 0);
|
|
1063
|
+
if (!Number.isFinite(n) || n < 0) return '?';
|
|
1064
|
+
if (n < 60) return `${Math.round(n)}s`;
|
|
1065
|
+
if (n < 3600) return `${Math.round(n / 60)}m`;
|
|
1066
|
+
if (n < 86400) return `${Math.round(n / 3600)}h`;
|
|
1067
|
+
return `${Math.round(n / 86400)}d`;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function sanitizeTickerLabel(value, max = 28) {
|
|
1071
|
+
return String(value || '')
|
|
1072
|
+
.replace(/\s+/g, '_')
|
|
1073
|
+
.replace(/[|]/g, '/')
|
|
1074
|
+
.slice(0, max);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
function readAtlasSessionContext() {
|
|
1078
|
+
if (!existsSync(ATLAS_SOCKET_PATH)) return null;
|
|
1079
|
+
try {
|
|
1080
|
+
const result = spawnSync('curl', [
|
|
1081
|
+
'-fsS',
|
|
1082
|
+
'--max-time',
|
|
1083
|
+
'0.5',
|
|
1084
|
+
'--unix-socket',
|
|
1085
|
+
ATLAS_SOCKET_PATH,
|
|
1086
|
+
'http://atlas/session-context',
|
|
1087
|
+
], { encoding: 'utf8', timeout: 900 });
|
|
1088
|
+
if (result.status !== 0 || !result.stdout) return null;
|
|
1089
|
+
const parsed = JSON.parse(result.stdout);
|
|
1090
|
+
return parsed?.session_context && typeof parsed.session_context === 'object' ? parsed.session_context : null;
|
|
1091
|
+
} catch {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function normalizeAtlasTickerContext(sessionContext) {
|
|
1097
|
+
if (!sessionContext) return null;
|
|
1098
|
+
const sentinelTop = Array.isArray(sessionContext.sentinel_top_findings)
|
|
1099
|
+
? sessionContext.sentinel_top_findings
|
|
1100
|
+
: [];
|
|
1101
|
+
const topFinding = sentinelTop[0] || null;
|
|
1102
|
+
return {
|
|
1103
|
+
snapshotId: sessionContext.freshness?.snapshot_id ?? null,
|
|
1104
|
+
ageSeconds: Number(sessionContext.freshness?.age_seconds || 0),
|
|
1105
|
+
nodes: Number(sessionContext.totals?.nodes || 0),
|
|
1106
|
+
edges: Number(sessionContext.totals?.edges || 0),
|
|
1107
|
+
codeUnits: Number(sessionContext.counts_by_kind?.code_unit || 0),
|
|
1108
|
+
doctrines: Number(sessionContext.counts_by_kind?.doctrine || 0),
|
|
1109
|
+
runtimes: Number(sessionContext.counts_by_kind?.runtime || 0),
|
|
1110
|
+
contracts: Number(sessionContext.counts_by_kind?.contract || 0),
|
|
1111
|
+
decisions: Number(sessionContext.counts_by_kind?.decision || 0),
|
|
1112
|
+
activeGateCount: Array.isArray(sessionContext.active_gates) ? sessionContext.active_gates.length : 0,
|
|
1113
|
+
sentinelTopCount: sentinelTop.length,
|
|
1114
|
+
sentinelHighCount: sentinelTop.filter((finding) => finding?.severity === 'high' || finding?.severity === 'critical').length,
|
|
1115
|
+
sentinelTop: topFinding ? {
|
|
1116
|
+
id: topFinding.id ?? null,
|
|
1117
|
+
severity: topFinding.severity || null,
|
|
1118
|
+
source: topFinding.source || null,
|
|
1119
|
+
kind: topFinding.kind || null,
|
|
1120
|
+
target: topFinding.target || null,
|
|
1121
|
+
reason: topFinding.reason || null,
|
|
1122
|
+
} : null,
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
function loadAtlasTickerContext(cache) {
|
|
1127
|
+
const updatedMs = Date.parse(cache?.atlasUpdatedAt || '');
|
|
1128
|
+
const fresh = Number.isFinite(updatedMs) && Date.now() - updatedMs <= HARNESS_TICKER_ATLAS_MAX_AGE_MS;
|
|
1129
|
+
if (fresh && cache?.atlas) return cache.atlas;
|
|
1130
|
+
const next = normalizeAtlasTickerContext(readAtlasSessionContext());
|
|
1131
|
+
if (next) {
|
|
1132
|
+
cache.atlas = next;
|
|
1133
|
+
cache.atlasUpdatedAt = new Date().toISOString();
|
|
1134
|
+
return next;
|
|
1135
|
+
}
|
|
1136
|
+
return cache?.atlas || null;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
function formatAtlasTickerSegment(atlas) {
|
|
1140
|
+
if (!atlas) return 'Atlas unavailable';
|
|
1141
|
+
const snapshot = atlas.snapshotId ? `#${atlas.snapshotId}` : '#?';
|
|
1142
|
+
return [
|
|
1143
|
+
`Atlas ${snapshot}`,
|
|
1144
|
+
`${formatCompactNumber(atlas.nodes)} nodes`,
|
|
1145
|
+
`${formatCompactNumber(atlas.edges)} edges`,
|
|
1146
|
+
`${atlas.activeGateCount || 0} live gates`,
|
|
1147
|
+
`fresh ${formatAge(atlas.ageSeconds)}`,
|
|
1148
|
+
].join(' ');
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
function formatSentinelTickerSegment(atlas) {
|
|
1152
|
+
if (!atlas) return 'Sentinel unavailable';
|
|
1153
|
+
const top = atlas.sentinelTop;
|
|
1154
|
+
const label = top
|
|
1155
|
+
? sanitizeTickerLabel(`${top.source || 'sentinel'}/${top.kind || 'finding'}:${top.reason || top.target || top.severity || top.id}`, 36)
|
|
1156
|
+
: 'clear';
|
|
1157
|
+
return `Sentinel high ${atlas.sentinelHighCount || 0}/${atlas.sentinelTopCount || 0} top ${label}`;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function formatHarnessTickerLine({ counts, previousCounts, latest, atlas, mode = 'text' } = {}) {
|
|
1161
|
+
const current = tickerCounts(counts);
|
|
1162
|
+
const prior = previousCounts ? tickerCounts(previousCounts) : null;
|
|
1163
|
+
const deltaTotal = prior
|
|
1164
|
+
? Math.max(0, current.gates - prior.gates) +
|
|
1165
|
+
Math.max(0, current.repairs - prior.repairs) +
|
|
1166
|
+
Math.max(0, current.blocks - prior.blocks) +
|
|
1167
|
+
Math.max(0, current.skills - prior.skills) +
|
|
1168
|
+
Math.max(0, current.saves - prior.saves) +
|
|
1169
|
+
Math.max(0, current.learnings - prior.learnings)
|
|
1170
|
+
: 0;
|
|
1171
|
+
const bars = ['▱▱▱▱', '▰▱▱▱', '▰▰▱▱', '▰▰▰▱', '▰▰▰▰'];
|
|
1172
|
+
const bar = bars[Math.min(4, deltaTotal || (Math.floor(Date.now() / 1000) % bars.length))];
|
|
1173
|
+
const verb = deltaTotal > 0 ? 'scanning' : 'ready';
|
|
1174
|
+
const label = sanitizeTickerLabel(latest?.label || 'receipts', 24);
|
|
1175
|
+
const segment = (key) => `${current[key]}${prior ? formatTickerDelta(current[key], prior[key]) : ''}`;
|
|
1176
|
+
if (mode === 'compact') {
|
|
1177
|
+
return [
|
|
1178
|
+
`Aria ${verb}`,
|
|
1179
|
+
`skills ${formatCompactNumber(current.skills)}`,
|
|
1180
|
+
`saved ${formatCompactNumber(current.saves)}`,
|
|
1181
|
+
`lessons ${formatCompactNumber(current.learnings)}`,
|
|
1182
|
+
atlas ? `atlas #${atlas.snapshotId || '?'} ${formatCompactNumber(atlas.nodes)}N` : 'atlas ?',
|
|
1183
|
+
atlas ? `sentinel high ${atlas.sentinelHighCount || 0}` : 'sentinel ?',
|
|
1184
|
+
`latest ${label}`,
|
|
1185
|
+
].join(' | ');
|
|
1186
|
+
}
|
|
1187
|
+
return [
|
|
1188
|
+
`Aria Harness ${bar} ${verb}`,
|
|
1189
|
+
`Gate checks ${segment('gates')}`,
|
|
1190
|
+
`Repairs ${segment('repairs')}`,
|
|
1191
|
+
`Blocks ${segment('blocks')}`,
|
|
1192
|
+
`Skills fired ${segment('skills')}`,
|
|
1193
|
+
`Lessons ${segment('learnings')}`,
|
|
1194
|
+
`Durable saves ${segment('saves')}`,
|
|
1195
|
+
formatAtlasTickerSegment(atlas),
|
|
1196
|
+
formatSentinelTickerSegment(atlas),
|
|
1197
|
+
`latest: ${label}`,
|
|
1198
|
+
].join(' | ');
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
function buildHarnessLiveTickerFromReceipts(previousState = {}) {
|
|
1202
|
+
const cache = loadHarnessTickerCache();
|
|
1203
|
+
if (Number(cache.version || 1) < 2 && cache.files?.learning) {
|
|
1204
|
+
cache.files.learning = { ...cache.files.learning, offset: 0 };
|
|
1205
|
+
cache.counts = { ...cache.counts, learnings: 0 };
|
|
1206
|
+
}
|
|
1207
|
+
// v3: producer-consumer path realignment migrated coach to first-class-
|
|
1208
|
+
// coach-events.jsonl and readiness to multi-file glob; old per-source
|
|
1209
|
+
// file-state keys are stale (different paths) so reset offsets/counts
|
|
1210
|
+
// so the next read replays from the start of the new producer files.
|
|
1211
|
+
if (Number(cache.version || 1) < 3) {
|
|
1212
|
+
cache.files = {};
|
|
1213
|
+
cache.counts = { gates: 0, repairs: 0, blocks: 0, skills: 0, saves: 0, learnings: 0 };
|
|
1214
|
+
}
|
|
1215
|
+
cache.version = 3;
|
|
1216
|
+
cache.counts = tickerCounts(cache.counts);
|
|
1217
|
+
cache.files = cache.files && typeof cache.files === 'object' ? cache.files : {};
|
|
1218
|
+
for (const source of HARNESS_TICKER_SOURCES) {
|
|
1219
|
+
const sourcePaths = Array.isArray(source.paths)
|
|
1220
|
+
? source.paths
|
|
1221
|
+
: (typeof source.resolve === 'function' ? source.resolve() : []);
|
|
1222
|
+
for (const filePath of sourcePaths) {
|
|
1223
|
+
const fileKey = `${source.id}::${filePath}`;
|
|
1224
|
+
const prior = cache.files[fileKey] || {};
|
|
1225
|
+
const read = readJsonlAppend(filePath, prior);
|
|
1226
|
+
if (read.rows.length > 0) applyHarnessTickerRows(cache, source.id, read.rows);
|
|
1227
|
+
cache.files[fileKey] = {
|
|
1228
|
+
offset: read.offset,
|
|
1229
|
+
mtimeMs: read.mtimeMs,
|
|
1230
|
+
path: filePath,
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
const atlas = loadAtlasTickerContext(cache);
|
|
1235
|
+
cache.updatedAt = new Date().toISOString();
|
|
1236
|
+
saveHarnessTickerCache(cache);
|
|
1237
|
+
const previousCounts = previousState?.harnessTicker?.counts || null;
|
|
1238
|
+
const line = formatHarnessTickerLine({
|
|
1239
|
+
counts: cache.counts,
|
|
1240
|
+
previousCounts,
|
|
1241
|
+
latest: cache.latest,
|
|
1242
|
+
atlas,
|
|
1243
|
+
});
|
|
1244
|
+
const compactLine = formatHarnessTickerLine({
|
|
1245
|
+
counts: cache.counts,
|
|
1246
|
+
previousCounts,
|
|
1247
|
+
latest: cache.latest,
|
|
1248
|
+
atlas,
|
|
1249
|
+
mode: 'compact',
|
|
1250
|
+
});
|
|
1251
|
+
return {
|
|
1252
|
+
ok: true,
|
|
1253
|
+
line,
|
|
1254
|
+
compactLine,
|
|
1255
|
+
counts: tickerCounts(cache.counts),
|
|
1256
|
+
latest: cache.latest || null,
|
|
1257
|
+
atlas,
|
|
1258
|
+
source: 'existing-jsonl-receipts',
|
|
1259
|
+
cachePath: HARNESS_TICKER_CACHE_PATH,
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
export function refreshHarnessTickerSidecarState(previousState = {}, options = {}) {
|
|
1264
|
+
const ticker = buildHarnessLiveTickerFromReceipts(previousState);
|
|
1265
|
+
const existing = readHarnessTickerSidecarState({ maxAgeMs: Number.POSITIVE_INFINITY, allowStale: true }) || {};
|
|
1266
|
+
const seq = Number(existing.seq || 0) + 1;
|
|
1267
|
+
const now = new Date().toISOString();
|
|
1268
|
+
const state = {
|
|
1269
|
+
schema: 'aria.harness_live_ticker_state.v1',
|
|
1270
|
+
seq,
|
|
1271
|
+
at: now,
|
|
1272
|
+
updatedAt: now,
|
|
1273
|
+
health: ticker.ok ? 'ready' : 'degraded',
|
|
1274
|
+
owner: options.owner || 'sidecar',
|
|
1275
|
+
line: ticker.line,
|
|
1276
|
+
compactLine: ticker.compactLine,
|
|
1277
|
+
counts: ticker.counts,
|
|
1278
|
+
latest: ticker.latest,
|
|
1279
|
+
atlas: ticker.atlas,
|
|
1280
|
+
source: ticker.source,
|
|
1281
|
+
cachePath: ticker.cachePath,
|
|
1282
|
+
statePath: HARNESS_TICKER_STATE_PATH,
|
|
1283
|
+
renderers: {
|
|
1284
|
+
codexHook: true,
|
|
1285
|
+
genericText: true,
|
|
1286
|
+
compactStatus: true,
|
|
1287
|
+
terminalTitle: true,
|
|
1288
|
+
tmuxStatus: true,
|
|
1289
|
+
shellPrompt: true,
|
|
1290
|
+
claudeCode: 'genericText',
|
|
1291
|
+
opencode: 'genericText',
|
|
1292
|
+
},
|
|
1293
|
+
};
|
|
1294
|
+
writeJsonAtomic(HARNESS_TICKER_STATE_PATH, state);
|
|
1295
|
+
return state;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
export function readHarnessTickerSidecarState({ maxAgeMs = HARNESS_TICKER_STATE_MAX_AGE_MS, allowStale = false } = {}) {
|
|
1299
|
+
try {
|
|
1300
|
+
if (!existsSync(HARNESS_TICKER_STATE_PATH)) return null;
|
|
1301
|
+
const state = JSON.parse(readFileSync(HARNESS_TICKER_STATE_PATH, 'utf8'));
|
|
1302
|
+
const updatedMs = Date.parse(state?.updatedAt || state?.at || '');
|
|
1303
|
+
const stale = !Number.isFinite(updatedMs) || Date.now() - updatedMs > maxAgeMs;
|
|
1304
|
+
if (stale && !allowStale) return null;
|
|
1305
|
+
return state;
|
|
1306
|
+
} catch {
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
export function renderHarnessTickerForCli(state = null, { mode = 'text' } = {}) {
|
|
1312
|
+
const ticker = state || readHarnessTickerSidecarState({ allowStale: true }) || refreshHarnessTickerSidecarState({}, { owner: 'renderer' });
|
|
1313
|
+
const line = String(ticker?.line || 'Harness warming | receipts unavailable | live checks still active');
|
|
1314
|
+
const compactLine = String(ticker?.compactLine || line);
|
|
1315
|
+
if (mode === 'json') return JSON.stringify(ticker);
|
|
1316
|
+
if (mode === 'compact') return compactLine;
|
|
1317
|
+
// 2026-05-17 owner directive: statusline must show full counter detail
|
|
1318
|
+
// (Gate checks / Repairs / Blocks / Skills fired / Lessons / Durable
|
|
1319
|
+
// saves / atlas / sentinel / latest). Previously mode='statusline' was
|
|
1320
|
+
// mapped to compactLine which dropped the counters the owner needed to
|
|
1321
|
+
// see. Compact still available via mode='compact'.
|
|
1322
|
+
if (mode === 'statusline') return line;
|
|
1323
|
+
if (mode === 'title') return `\u001b]0;${compactLine}\u0007`;
|
|
1324
|
+
if (mode === 'tmux') return compactLine.replace(/#/g, '##');
|
|
1325
|
+
if (mode === 'shell') return `[${compactLine}]`;
|
|
1326
|
+
return line;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
export function ensureHarnessTickerSidecar({ scriptPath = '', force = false } = {}) {
|
|
1330
|
+
if (process.env.ARIA_HARNESS_TICKER_SIDECAR === '0') return { started: false, reason: 'disabled' };
|
|
1331
|
+
if (!force && readHarnessTickerSidecarState()) return { started: false, reason: 'fresh_state' };
|
|
1332
|
+
const resolvedScript = scriptPath || path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', 'aria-harness-ticker-sidecar.mjs');
|
|
1333
|
+
if (!existsSync(resolvedScript)) {
|
|
1334
|
+
refreshHarnessTickerSidecarState({}, { owner: 'hook_inline_fallback' });
|
|
1335
|
+
return { started: false, reason: 'script_missing_inline_refresh', scriptPath: resolvedScript };
|
|
1336
|
+
}
|
|
1337
|
+
try {
|
|
1338
|
+
const child = spawn(process.execPath, [resolvedScript, '--daemon'], {
|
|
1339
|
+
detached: true,
|
|
1340
|
+
stdio: 'ignore',
|
|
1341
|
+
env: {
|
|
1342
|
+
...process.env,
|
|
1343
|
+
ARIA_HARNESS_TICKER_SIDE_CAR_CHILD: '1',
|
|
1344
|
+
},
|
|
1345
|
+
});
|
|
1346
|
+
child.unref();
|
|
1347
|
+
mkdirSync(path.dirname(HARNESS_TICKER_PID_PATH), { recursive: true, mode: 0o700 });
|
|
1348
|
+
writeFileSync(HARNESS_TICKER_PID_PATH, `${child.pid}\n`, { mode: 0o600 });
|
|
1349
|
+
return { started: true, pid: child.pid, scriptPath: resolvedScript };
|
|
1350
|
+
} catch (error) {
|
|
1351
|
+
refreshHarnessTickerSidecarState({}, { owner: 'hook_spawn_fallback' });
|
|
1352
|
+
return {
|
|
1353
|
+
started: false,
|
|
1354
|
+
reason: 'spawn_failed_inline_refresh',
|
|
1355
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1356
|
+
scriptPath: resolvedScript,
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
export function buildHarnessLiveTicker(previousState = {}) {
|
|
1362
|
+
if (process.env.ARIA_HARNESS_TICKER_SIDECAR === '0') {
|
|
1363
|
+
return {
|
|
1364
|
+
ok: true,
|
|
1365
|
+
line: 'Aria Harness ticker disabled for this hook run | live checks still active',
|
|
1366
|
+
counts: tickerCounts(previousState?.harnessTicker?.counts || {}),
|
|
1367
|
+
latest: previousState?.harnessTicker?.latest || null,
|
|
1368
|
+
source: 'sidecar-disabled',
|
|
1369
|
+
cachePath: HARNESS_TICKER_CACHE_PATH,
|
|
1370
|
+
statePath: HARNESS_TICKER_STATE_PATH,
|
|
1371
|
+
seq: previousState?.harnessTicker?.seq || 0,
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
ensureHarnessTickerSidecar();
|
|
1375
|
+
const sidecar = readHarnessTickerSidecarState();
|
|
1376
|
+
if (sidecar?.line) {
|
|
1377
|
+
return {
|
|
1378
|
+
ok: true,
|
|
1379
|
+
line: sidecar.line,
|
|
1380
|
+
counts: tickerCounts(sidecar.counts),
|
|
1381
|
+
latest: sidecar.latest || null,
|
|
1382
|
+
source: 'sidecar-state',
|
|
1383
|
+
cachePath: sidecar.cachePath || HARNESS_TICKER_CACHE_PATH,
|
|
1384
|
+
statePath: HARNESS_TICKER_STATE_PATH,
|
|
1385
|
+
seq: sidecar.seq || 0,
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
const state = refreshHarnessTickerSidecarState(previousState, { owner: 'hook_inline_refresh' });
|
|
1389
|
+
return {
|
|
1390
|
+
ok: true,
|
|
1391
|
+
line: state.line,
|
|
1392
|
+
counts: tickerCounts(state.counts),
|
|
1393
|
+
latest: state.latest || null,
|
|
1394
|
+
source: 'inline-sidecar-refresh',
|
|
1395
|
+
cachePath: state.cachePath,
|
|
1396
|
+
statePath: state.statePath,
|
|
1397
|
+
seq: state.seq,
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// AI-12107 — verifier-mode short-circuit. The codex-native mirror verifier
|
|
1402
|
+
// runs synthetic-exec readback on every hook. Without this short-circuit,
|
|
1403
|
+
// hooks fan out real HTTP fetches to localhost:30080 / atlas socket / hive
|
|
1404
|
+
// state, which are either slow (10-20s) or unavailable in CI contexts. The
|
|
1405
|
+
// verifier sets ARIA_HOOK_VERIFIER_MODE=1; when set, runtimePost returns a
|
|
1406
|
+
// deterministic no-op result so the import path is exercised (the actual
|
|
1407
|
+
// goal of the readback) but no real I/O happens. No wall-clock timeout
|
|
1408
|
+
// needed — hooks complete in milliseconds. Doctrine-aligned: a structural
|
|
1409
|
+
// signal (env var) decides behavior, not a temporal threshold.
|
|
1410
|
+
export const ARIA_HOOK_VERIFIER_MODE = process.env.ARIA_HOOK_VERIFIER_MODE === '1';
|
|
1411
|
+
|
|
1412
|
+
export async function runtimePost(route, body = {}) {
|
|
1413
|
+
if (ARIA_HOOK_VERIFIER_MODE) {
|
|
1414
|
+
return { ok: true, mode: 'verifier-noop', route, schema: 'aria.verifier_noop.v1' };
|
|
1415
|
+
}
|
|
1416
|
+
const token = readToken();
|
|
1417
|
+
const headers = {
|
|
1418
|
+
'Content-Type': 'application/json',
|
|
1419
|
+
};
|
|
1420
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1421
|
+
// 2026-05-18: transient-glitch retry. Previously a single fetch failure
|
|
1422
|
+
// (e.g. brief socket hiccup during runtime reload, sibling-session
|
|
1423
|
+
// request contention, or a slow connect) threw straight to the caller,
|
|
1424
|
+
// which then triggered buildLocalMechanicalSkillLoad fallback with
|
|
1425
|
+
// hardcoded 1/3/1 active counts — failing the deploy-class pre-tool
|
|
1426
|
+
// gate even though the runtime was healthy. Two retries with 100ms
|
|
1427
|
+
// and 500ms backoff absorb transient failures (verified by curl that
|
|
1428
|
+
// /health is reachable when /build-system-prompt occasionally fails)
|
|
1429
|
+
// without slowing the success path. Body is identical across retries
|
|
1430
|
+
// so idempotency is preserved.
|
|
1431
|
+
const RETRY_DELAYS_MS = [100, 500];
|
|
1432
|
+
let lastError = null;
|
|
1433
|
+
for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
|
|
1434
|
+
try {
|
|
1435
|
+
const response = await fetch(`${DEFAULT_RUNTIME_URL}${route}`, {
|
|
1436
|
+
method: 'POST',
|
|
1437
|
+
headers,
|
|
1438
|
+
body: JSON.stringify(body),
|
|
1439
|
+
});
|
|
1440
|
+
if (!response.ok) {
|
|
1441
|
+
const detail = await response.text().catch(() => response.statusText);
|
|
1442
|
+
const err = new Error(`runtime ${route} failed (${response.status}): ${detail}`);
|
|
1443
|
+
if (response.status >= 500 && attempt < RETRY_DELAYS_MS.length) {
|
|
1444
|
+
lastError = err;
|
|
1445
|
+
process.stderr.write(`[runtime-client:runtimePost-retry] ${route} attempt=${attempt + 1} status=${response.status} — retrying in ${RETRY_DELAYS_MS[attempt]}ms\n`);
|
|
1446
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAYS_MS[attempt]));
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
throw err;
|
|
1450
|
+
}
|
|
1451
|
+
return response.json();
|
|
1452
|
+
} catch (err) {
|
|
1453
|
+
const isRetryable = err?.name === 'TypeError'
|
|
1454
|
+
|| /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|aborted/i.test(String(err?.message || err));
|
|
1455
|
+
if (isRetryable && attempt < RETRY_DELAYS_MS.length) {
|
|
1456
|
+
lastError = err;
|
|
1457
|
+
process.stderr.write(`[runtime-client:runtimePost-retry] ${route} attempt=${attempt + 1} err=${err?.message || err} — retrying in ${RETRY_DELAYS_MS[attempt]}ms\n`);
|
|
1458
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAYS_MS[attempt]));
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
throw err;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
// Unreachable in normal flow; retained for control-flow correctness.
|
|
1465
|
+
throw lastError || new Error(`runtime ${route} failed after ${RETRY_DELAYS_MS.length + 1} attempts`);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
async function runtimePostBounded(route, body = {}, timeoutMs = HIVE_SYNC_TIMEOUT_MS) {
|
|
1469
|
+
const token = readToken();
|
|
1470
|
+
const headers = {
|
|
1471
|
+
'Content-Type': 'application/json',
|
|
1472
|
+
};
|
|
1473
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1474
|
+
const controller = new AbortController();
|
|
1475
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1476
|
+
try {
|
|
1477
|
+
const response = await fetch(`${DEFAULT_RUNTIME_URL}${route}`, {
|
|
1478
|
+
method: 'POST',
|
|
1479
|
+
headers,
|
|
1480
|
+
body: JSON.stringify(body),
|
|
1481
|
+
signal: controller.signal,
|
|
1482
|
+
});
|
|
1483
|
+
const text = await response.text();
|
|
1484
|
+
let data = null;
|
|
1485
|
+
try { data = text ? JSON.parse(text) : null; } catch { data = { raw: text }; }
|
|
1486
|
+
if (!response.ok) {
|
|
1487
|
+
throw new Error(`runtime ${route} failed (${response.status}): ${text || response.statusText}`);
|
|
1488
|
+
}
|
|
1489
|
+
return data;
|
|
1490
|
+
} finally {
|
|
1491
|
+
clearTimeout(timer);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
export async function runtimeGet(route) {
|
|
1496
|
+
const token = readToken();
|
|
1497
|
+
const headers = {};
|
|
1498
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1499
|
+
const controller = new AbortController();
|
|
1500
|
+
const timer = setTimeout(() => controller.abort(), HIVE_SYNC_TIMEOUT_MS);
|
|
1501
|
+
try {
|
|
1502
|
+
const response = await fetch(`${DEFAULT_RUNTIME_URL}${route}`, {
|
|
1503
|
+
method: 'GET',
|
|
1504
|
+
headers,
|
|
1505
|
+
signal: controller.signal,
|
|
1506
|
+
});
|
|
1507
|
+
if (!response.ok) {
|
|
1508
|
+
const detail = await response.text().catch(() => response.statusText);
|
|
1509
|
+
throw new Error(`runtime ${route} failed (${response.status}): ${detail}`);
|
|
1510
|
+
}
|
|
1511
|
+
return response.json();
|
|
1512
|
+
} finally {
|
|
1513
|
+
clearTimeout(timer);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
export function remoteCoachEnabled(env = process.env) {
|
|
1518
|
+
return /^(?:1|true|yes|on)$/i.test(String(
|
|
1519
|
+
env.ARIA_REMOTE_COACH_ENABLED ||
|
|
1520
|
+
env.ARIA_RUNTIME_COACH_ENABLED ||
|
|
1521
|
+
env.ARIA_COACH_REMOTE_ENABLED ||
|
|
1522
|
+
''
|
|
1523
|
+
));
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
export async function recordCoachPhase(phase, body = {}) {
|
|
1527
|
+
if (!remoteCoachEnabled()) {
|
|
1528
|
+
return {
|
|
1529
|
+
ok: true,
|
|
1530
|
+
skipped: true,
|
|
1531
|
+
permitted: true,
|
|
1532
|
+
decision: 'allow',
|
|
1533
|
+
phase,
|
|
1534
|
+
reasons: ['remote_coach_disabled'],
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
try {
|
|
1538
|
+
return await runtimePost('/coach/phase', {
|
|
1539
|
+
phase,
|
|
1540
|
+
surface: `${ARIA_HOOK_SURFACE}-hooks`,
|
|
1541
|
+
lane: `${ARIA_HOOK_SURFACE}_native_hooks`,
|
|
1542
|
+
...body,
|
|
1543
|
+
});
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
return {
|
|
1546
|
+
ok: false,
|
|
1547
|
+
permitted: true,
|
|
1548
|
+
decision: 'warn_operator_only',
|
|
1549
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
export async function ensurePreTurnMizanReceipt({ sessionId, traceId, state = {}, event = {}, action = '', target = '' } = {}) {
|
|
1555
|
+
if (state?.preReceiptId) {
|
|
1556
|
+
return { ok: true, state, healed: false };
|
|
1557
|
+
}
|
|
1558
|
+
const message = String(state?.userText || target || `${ARIA_HOOK_SURFACE} tool request`).slice(0, 4000);
|
|
1559
|
+
const packet = await getHarnessClient().getHarnessPacket({
|
|
1560
|
+
sessionId,
|
|
1561
|
+
platform: ARIA_HOOK_SURFACE,
|
|
1562
|
+
message,
|
|
1563
|
+
});
|
|
1564
|
+
const packetRef = makeEvidenceRef('harness_packet', packet, { sessionId, platform: ARIA_HOOK_SURFACE, source: 'pre_tool_receipt_heal' });
|
|
1565
|
+
const result = await runtimePost('/mizan/pre', {
|
|
1566
|
+
sessionId,
|
|
1567
|
+
packet,
|
|
1568
|
+
packetRequest: {
|
|
1569
|
+
sessionId,
|
|
1570
|
+
platform: ARIA_HOOK_SURFACE,
|
|
1571
|
+
message,
|
|
1572
|
+
stage: `${ARIA_HOOK_SURFACE}-pre-tool-receipt-heal`,
|
|
1573
|
+
actor: `${ARIA_HOOK_SURFACE}-hook`,
|
|
1574
|
+
system: `${ARIA_HOOK_SURFACE}-hook`,
|
|
1575
|
+
},
|
|
1576
|
+
context: {
|
|
1577
|
+
sessionId,
|
|
1578
|
+
traceId,
|
|
1579
|
+
surface: `${ARIA_HOOK_SURFACE}-hooks`,
|
|
1580
|
+
platform: ARIA_HOOK_SURFACE,
|
|
1581
|
+
userText: state?.userText || '',
|
|
1582
|
+
action,
|
|
1583
|
+
target,
|
|
1584
|
+
event,
|
|
1585
|
+
evidenceRefs: [packetRef],
|
|
1586
|
+
},
|
|
1587
|
+
});
|
|
1588
|
+
const nextState = saveTurnState(sessionId, {
|
|
1589
|
+
...state,
|
|
1590
|
+
traceId,
|
|
1591
|
+
preReceiptId: result?.receipt?.receiptId || null,
|
|
1592
|
+
packetTimestamp: packet?.timestamp || null,
|
|
1593
|
+
packetRef,
|
|
1594
|
+
preReceiptHealed: true,
|
|
1595
|
+
preReceiptHealedAt: new Date().toISOString(),
|
|
1596
|
+
lastEvent: 'PreToolUse',
|
|
1597
|
+
});
|
|
1598
|
+
return {
|
|
1599
|
+
ok: Boolean(result?.receipt?.receiptId),
|
|
1600
|
+
state: nextState,
|
|
1601
|
+
healed: true,
|
|
1602
|
+
receipt: result?.receipt || null,
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
export function classifyAction(event) {
|
|
1607
|
+
const toolName = String(event?.tool_name || event?.toolName || '').trim();
|
|
1608
|
+
const toolInput = event?.tool_input || event?.toolInput || {};
|
|
1609
|
+
const toolCommand = String(toolInput?.command ?? '').trim();
|
|
1610
|
+
const lowerTool = toolName.toLowerCase();
|
|
1611
|
+
|
|
1612
|
+
if (/^(?:read|grep|glob|list_mcp_resources|list_mcp_resource_templates)$/i.test(toolName)) return 'read';
|
|
1613
|
+
if (lowerTool.includes('apply_patch')) {
|
|
1614
|
+
return /^\*\*\* Begin Patch[\s\S]*^\*\*\* Delete File:/m.test(toolCommand) ? 'delete' : 'write';
|
|
1615
|
+
}
|
|
1616
|
+
if (/^(?:edit|write|notebookedit)$/i.test(toolName) || toolInput?.file_path || toolInput?.notebook_path) {
|
|
1617
|
+
return 'write';
|
|
1618
|
+
}
|
|
1619
|
+
if (/delete|destroy|drop|wipe|purge/i.test(toolName)) return 'delete';
|
|
1620
|
+
if (/deploy|rollout|release/i.test(toolName)) return 'deploy';
|
|
1621
|
+
if (/build|compile|test/i.test(toolName)) return 'build';
|
|
1622
|
+
if (!toolCommand) return 'write';
|
|
1623
|
+
|
|
1624
|
+
if (/^(?:ls|cat|head|tail|grep|rg|sed\s+-n|wc|find|tree|stat|file|ps|pgrep|du|df|env|printenv|date|pwd|which|type|whoami|id)\b/.test(toolCommand)) return 'read';
|
|
1625
|
+
if (/^git\s+(?:status|log|diff|show|branch|remote|rev-parse|ls-tree|ls-files|stash\s+list)\b/.test(toolCommand)) return 'read';
|
|
1626
|
+
if (/^(?:kubectl\s+(?:get|describe|logs|top|version|api-resources)\b|docker\s+ps\b)/.test(toolCommand)) return 'read';
|
|
1627
|
+
if (/\b(?:scripts\/deploy-|kubectl\s+(?:apply|set\s+image|delete|patch|rollout|scale|drain|cordon)\b|docker\s+push\b|helm\s+(?:upgrade|install|rollback)\b)/i.test(toolCommand)) return 'deploy';
|
|
1628
|
+
if (/^(?:rm|rmdir|unlink|truncate)\b|drop\s+table|git\s+(?:reset|clean)\b/i.test(toolCommand)) return 'delete';
|
|
1629
|
+
if (/\b(?:npm|pnpm|yarn)\s+(?:run\s+)?(?:build|test|check|lint|typecheck)\b|\b(?:tsc|jest|vitest|eslint)\b/i.test(toolCommand)) return 'build';
|
|
1630
|
+
return 'write';
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
export function summarizeTarget(event) {
|
|
1634
|
+
return JSON.stringify({
|
|
1635
|
+
tool_name: event?.tool_name || event?.toolName || null,
|
|
1636
|
+
tool_input: event?.tool_input || event?.toolInput || null,
|
|
1637
|
+
}).slice(0, 4000);
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
function normalizeTouchedPath(value) {
|
|
1641
|
+
const raw = String(value || '').trim();
|
|
1642
|
+
if (!raw) return '';
|
|
1643
|
+
return raw.replace(/\\/g, '/').replace(/\/+/, '/');
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
function pushTouchedFile(files, value, intent = 'touch') {
|
|
1647
|
+
const pathValue = normalizeTouchedPath(value);
|
|
1648
|
+
if (!pathValue) return;
|
|
1649
|
+
if (!files.some((file) => file.path === pathValue && file.intent === intent)) {
|
|
1650
|
+
files.push({ path: pathValue, intent });
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
export function extractToolTouchedFiles(event, action = '') {
|
|
1655
|
+
const files = [];
|
|
1656
|
+
const toolName = String(event?.tool_name || event?.toolName || '').trim();
|
|
1657
|
+
const toolInput = event?.tool_input || event?.toolInput || {};
|
|
1658
|
+
const intent = action || classifyAction(event);
|
|
1659
|
+
pushTouchedFile(files, toolInput?.file_path, intent);
|
|
1660
|
+
pushTouchedFile(files, toolInput?.filePath, intent);
|
|
1661
|
+
pushTouchedFile(files, toolInput?.path, intent);
|
|
1662
|
+
pushTouchedFile(files, toolInput?.notebook_path, intent);
|
|
1663
|
+
pushTouchedFile(files, toolInput?.notebookPath, intent);
|
|
1664
|
+
if (Array.isArray(toolInput?.files)) toolInput.files.forEach((file) => pushTouchedFile(files, file, intent));
|
|
1665
|
+
if (Array.isArray(toolInput?.targetFiles)) toolInput.targetFiles.forEach((file) => pushTouchedFile(files, file, intent));
|
|
1666
|
+
const command = String(toolInput?.command || '');
|
|
1667
|
+
if (/apply_patch/i.test(toolName) || /^\*\*\* Begin Patch/m.test(command)) {
|
|
1668
|
+
for (const match of command.matchAll(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/gm)) {
|
|
1669
|
+
pushTouchedFile(files, match[1], intent);
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return files.slice(0, 200);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
export async function recordHiveFileTouch({ sessionId, threadId = null, event = 'tool_request', files = [], source = `${ARIA_HOOK_SURFACE}-hook`, body = {} } = {}) {
|
|
1676
|
+
if (!sessionId || !Array.isArray(files) || files.length === 0) {
|
|
1677
|
+
return { ok: true, skipped: true, reason: 'no files to record' };
|
|
1678
|
+
}
|
|
1679
|
+
const payload = {
|
|
1680
|
+
session_id: sessionId,
|
|
1681
|
+
thread_id: threadId,
|
|
1682
|
+
event,
|
|
1683
|
+
files,
|
|
1684
|
+
source,
|
|
1685
|
+
body: {
|
|
1686
|
+
cwd: process.cwd(),
|
|
1687
|
+
...body,
|
|
1688
|
+
},
|
|
1689
|
+
};
|
|
1690
|
+
const local = recordLocalHiveSpool('file_touch', payload);
|
|
1691
|
+
try {
|
|
1692
|
+
const published = await runtimePostBounded('/api/hive/file-touch', payload);
|
|
1693
|
+
return { ...published, local_spool: local, runtime_publish: { ok: true } };
|
|
1694
|
+
} catch (error) {
|
|
1695
|
+
return {
|
|
1696
|
+
ok: true,
|
|
1697
|
+
skipped: false,
|
|
1698
|
+
degraded: true,
|
|
1699
|
+
local_spool: local,
|
|
1700
|
+
runtime_publish: {
|
|
1701
|
+
ok: false,
|
|
1702
|
+
route: '/api/hive/file-touch',
|
|
1703
|
+
timeoutMs: HIVE_SYNC_TIMEOUT_MS,
|
|
1704
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1705
|
+
},
|
|
1706
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
export async function recordHiveSessionLifecycle({
|
|
1712
|
+
sessionId,
|
|
1713
|
+
threadId = null,
|
|
1714
|
+
event = 'heartbeat',
|
|
1715
|
+
status = null,
|
|
1716
|
+
intentSummary = null,
|
|
1717
|
+
sourceArtifact = null,
|
|
1718
|
+
fileClaims = [],
|
|
1719
|
+
doNotTouch = [],
|
|
1720
|
+
source = `${ARIA_HOOK_SURFACE}-hook`,
|
|
1721
|
+
body = {},
|
|
1722
|
+
} = {}) {
|
|
1723
|
+
if (!sessionId) return { ok: true, skipped: true, reason: 'no session_id to record' };
|
|
1724
|
+
const payload = {
|
|
1725
|
+
session_id: sessionId,
|
|
1726
|
+
thread_id: threadId,
|
|
1727
|
+
event,
|
|
1728
|
+
status: status || event,
|
|
1729
|
+
intent_summary: intentSummary || `${source} ${event}`,
|
|
1730
|
+
source_artifact: sourceArtifact,
|
|
1731
|
+
file_claims: Array.isArray(fileClaims) ? fileClaims : [],
|
|
1732
|
+
do_not_touch: Array.isArray(doNotTouch) ? doNotTouch : [],
|
|
1733
|
+
body: {
|
|
1734
|
+
cwd: process.cwd(),
|
|
1735
|
+
source,
|
|
1736
|
+
...body,
|
|
1737
|
+
},
|
|
1738
|
+
};
|
|
1739
|
+
const local = recordLocalHiveSpool('session_lifecycle', payload);
|
|
1740
|
+
try {
|
|
1741
|
+
const published = await runtimePostBounded('/api/hive/session-lifecycle', payload);
|
|
1742
|
+
return { ...published, local_spool: local, runtime_publish: { ok: true } };
|
|
1743
|
+
} catch (error) {
|
|
1744
|
+
return {
|
|
1745
|
+
ok: true,
|
|
1746
|
+
skipped: false,
|
|
1747
|
+
degraded: true,
|
|
1748
|
+
local_spool: local,
|
|
1749
|
+
runtime_publish: {
|
|
1750
|
+
ok: false,
|
|
1751
|
+
route: '/api/hive/session-lifecycle',
|
|
1752
|
+
timeoutMs: HIVE_SYNC_TIMEOUT_MS,
|
|
1753
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1754
|
+
},
|
|
1755
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
export function extractUserText(event) {
|
|
1761
|
+
return extractText(
|
|
1762
|
+
event?.input ??
|
|
1763
|
+
event?.user_input ??
|
|
1764
|
+
event?.userInput ??
|
|
1765
|
+
event?.prompt ??
|
|
1766
|
+
event?.message ??
|
|
1767
|
+
event
|
|
1768
|
+
);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
export function extractAssistantText(event) {
|
|
1772
|
+
return extractText(
|
|
1773
|
+
event?.last_assistant_message ??
|
|
1774
|
+
event?.lastAssistantMessage ??
|
|
1775
|
+
event?.output ??
|
|
1776
|
+
event?.response ??
|
|
1777
|
+
event?.message ??
|
|
1778
|
+
event
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
export const ARIA_ALWAYS_ON_SKILLS = Object.freeze([
|
|
1783
|
+
'aria-axioms-first-principles',
|
|
1784
|
+
'aria-cognition-autofire',
|
|
1785
|
+
'aria-first-class-operating-contract',
|
|
1786
|
+
'aria-cognition-batch',
|
|
1787
|
+
'aria-forge-guardrails',
|
|
1788
|
+
'aria-harness-no-stripping',
|
|
1789
|
+
'aria-harness-output-discipline',
|
|
1790
|
+
'aria-quality-audit',
|
|
1791
|
+
'aria-readable-output',
|
|
1792
|
+
'aria-senior-code-audit',
|
|
1793
|
+
'ghazali-8lens',
|
|
1794
|
+
'mizan',
|
|
1795
|
+
'never-guess',
|
|
1796
|
+
'predictor',
|
|
1797
|
+
'qiyas-analogy',
|
|
1798
|
+
'tadabbur',
|
|
1799
|
+
'aria-repo-doctrine',
|
|
1800
|
+
'aria-senior-code-cookbook',
|
|
1801
|
+
'aria-http-harness-client',
|
|
1802
|
+
'aria-task-codex-executor',
|
|
1803
|
+
'aria-decision-mizan',
|
|
1804
|
+
'tadabbur-ops',
|
|
1805
|
+
'aria-repo-audit',
|
|
1806
|
+
'aria-backend-architect',
|
|
1807
|
+
'aria-live-ops',
|
|
1808
|
+
'aria-memory-index',
|
|
1809
|
+
'aria-ops',
|
|
1810
|
+
]);
|
|
1811
|
+
|
|
1812
|
+
export const ARIA_CODEX_UNIVERSAL_TURN_PACKET_SKILLS = Object.freeze([
|
|
1813
|
+
'aria-cognition-autofire',
|
|
1814
|
+
'aria-first-class-operating-contract',
|
|
1815
|
+
'aria-cognition-batch',
|
|
1816
|
+
'aria-quality-audit',
|
|
1817
|
+
'aria-repo-doctrine',
|
|
1818
|
+
'aria-http-harness-client',
|
|
1819
|
+
'aria-harness-substrate-binding',
|
|
1820
|
+
'aria-axioms-first-principles',
|
|
1821
|
+
'never-guess',
|
|
1822
|
+
'tadabbur',
|
|
1823
|
+
'tadabbur-ops',
|
|
1824
|
+
'tafakkur',
|
|
1825
|
+
'qiyas-analogy',
|
|
1826
|
+
'forge-quality-rules',
|
|
1827
|
+
'aria-task-codex-executor',
|
|
1828
|
+
'aria-backend-architect',
|
|
1829
|
+
'aria-harness-no-stripping',
|
|
1830
|
+
'aria-readable-output',
|
|
1831
|
+
'aria-ledger-fleet-execution',
|
|
1832
|
+
'predictor',
|
|
1833
|
+
'aria-aristotle-pre-phase',
|
|
1834
|
+
'aria-aristotle-intra-phase',
|
|
1835
|
+
'aria-aristotle-post-phase',
|
|
1836
|
+
'mizan',
|
|
1837
|
+
'ghazali-8lens',
|
|
1838
|
+
'aria-noor-cognitives',
|
|
1839
|
+
'aria-business-frame',
|
|
1840
|
+
'aria-business-audit',
|
|
1841
|
+
'aria-revenue-engine',
|
|
1842
|
+
'aria-retention-engine',
|
|
1843
|
+
'aria-gtm-architect',
|
|
1844
|
+
'aria-senior-code-cookbook',
|
|
1845
|
+
'aria-senior-code-audit',
|
|
1846
|
+
'testing-strategy',
|
|
1847
|
+
'security-review',
|
|
1848
|
+
'architecture-decision',
|
|
1849
|
+
'api-design',
|
|
1850
|
+
'observability',
|
|
1851
|
+
'error-handling',
|
|
1852
|
+
'aria-decision-mizan',
|
|
1853
|
+
'aria-aristotle-cognitives',
|
|
1854
|
+
'aria-forge-guardrails',
|
|
1855
|
+
'aria-harness-deploy',
|
|
1856
|
+
'aria-harness-onboarding',
|
|
1857
|
+
'aria-harness-output-discipline',
|
|
1858
|
+
'aria-frontend-architect',
|
|
1859
|
+
'aria-fullstack-orchestrator',
|
|
1860
|
+
'aria-research-orchestrator',
|
|
1861
|
+
'cross-domain-24',
|
|
1862
|
+
'fitrah-guard',
|
|
1863
|
+
'noor-recognition',
|
|
1864
|
+
'ladunni-22',
|
|
1865
|
+
'ijtihad-novel',
|
|
1866
|
+
'ilham-intuition',
|
|
1867
|
+
'istiqra-induction',
|
|
1868
|
+
'ruh-basis',
|
|
1869
|
+
'soul-domains',
|
|
1870
|
+
'deepsoul-emotional',
|
|
1871
|
+
]);
|
|
1872
|
+
|
|
1873
|
+
export const ARIA_CODEX_UNIVERSAL_TURN_PACKET_PHASES = Object.freeze([
|
|
1874
|
+
'pre_cognition',
|
|
1875
|
+
'pre_tool',
|
|
1876
|
+
'intra_tool',
|
|
1877
|
+
'intra_cognition',
|
|
1878
|
+
'post_tool',
|
|
1879
|
+
'post_cognition',
|
|
1880
|
+
]);
|
|
1881
|
+
|
|
1882
|
+
export const ARIA_QIYAS_15_PERSPECTIVES = Object.freeze([
|
|
1883
|
+
// Aligned 1:1 to atlas kernel QIYAS_PERSPECTIVES (deterministic-cognitive-kernel.mjs:18).
|
|
1884
|
+
// 2026-05-17 F2: prior list collapsed owner_now+owner_future and split future_self
|
|
1885
|
+
// into 1-week/1-year, mislabeling kernel verdicts at positions 1-13.
|
|
1886
|
+
'Owner-Hamza-now',
|
|
1887
|
+
'Owner-Hamza-future',
|
|
1888
|
+
'operator-client',
|
|
1889
|
+
'investor-or-buyer',
|
|
1890
|
+
'LLM-consumer',
|
|
1891
|
+
'human-end-user',
|
|
1892
|
+
'skeptic',
|
|
1893
|
+
'compliance',
|
|
1894
|
+
'engineering-quality',
|
|
1895
|
+
'cognitive-load',
|
|
1896
|
+
'scale',
|
|
1897
|
+
'Islamic-scholar',
|
|
1898
|
+
'clinical-scholar',
|
|
1899
|
+
'red-team-attacker',
|
|
1900
|
+
'future-self',
|
|
1901
|
+
]);
|
|
1902
|
+
|
|
1903
|
+
export const ARIA_TADABBUR_12_STAGES = Object.freeze([
|
|
1904
|
+
'EMBED',
|
|
1905
|
+
'EXCAVATE',
|
|
1906
|
+
'ROOT TRACE',
|
|
1907
|
+
'MULTI-LENS',
|
|
1908
|
+
'PATTERN',
|
|
1909
|
+
'CONSEQUENCE',
|
|
1910
|
+
'DWELLING',
|
|
1911
|
+
'COLLAPSE',
|
|
1912
|
+
'PRINCIPLE',
|
|
1913
|
+
'INVERSION',
|
|
1914
|
+
'PERSONAL',
|
|
1915
|
+
'VOICE',
|
|
1916
|
+
]);
|
|
1917
|
+
|
|
1918
|
+
export const ARIA_QA_AUTOFIRE_CYCLE = Object.freeze([
|
|
1919
|
+
'qiyas_15_pass',
|
|
1920
|
+
'tadabbur_full_canonical_12_stage',
|
|
1921
|
+
'correct',
|
|
1922
|
+
'enhance',
|
|
1923
|
+
'harden',
|
|
1924
|
+
'verify',
|
|
1925
|
+
]);
|
|
1926
|
+
|
|
1927
|
+
export const ARIA_QA_METHOD_CONTRACT = Object.freeze({
|
|
1928
|
+
qiyas: 'Qiyas means full Qiyas-15 only. Mini Qiyas is not acceptable for architecture, runtime, code, QA, hook, SDK, worker, or harness work.',
|
|
1929
|
+
tadabbur: 'Tadabbur means the full canonical 12-stage Tadabbur path for architecture, runtime, code, QA, hook, SDK, worker, or harness work.',
|
|
1930
|
+
});
|
|
1931
|
+
|
|
1932
|
+
export const ARIA_CODEX_MINIMUM_SKILL_FLOOR = Number(process.env.ARIA_CODEX_MINIMUM_SKILL_FLOOR || 50);
|
|
1933
|
+
export const ARIA_CODEX_UNIVERSAL_RUNTIME_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_RUNTIME_FLOOR || 16);
|
|
1934
|
+
export const ARIA_CODEX_UNIVERSAL_PRIMITIVE_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_PRIMITIVE_FLOOR || 24);
|
|
1935
|
+
export const ARIA_CODEX_UNIVERSAL_MAPPING_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_MAPPING_FLOOR || 24);
|
|
1936
|
+
export const ARIA_CODEX_UNIVERSAL_QA_SKILL_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_QA_SKILL_FLOOR || 6);
|
|
1937
|
+
export const ARIA_CODEX_UNIVERSAL_CORRECTION_SKILL_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_CORRECTION_SKILL_FLOOR || 6);
|
|
1938
|
+
export const ARIA_CODEX_UNIVERSAL_NOOR_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_NOOR_FLOOR || 14);
|
|
1939
|
+
export const ARIA_CODEX_UNIVERSAL_HIVE_SIBLING_BROADCAST_FLOOR = Number(process.env.ARIA_CODEX_UNIVERSAL_HIVE_SIBLING_BROADCAST_FLOOR || 1);
|
|
1940
|
+
export const ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE = 'local-mechanical-orchestrator';
|
|
1941
|
+
|
|
1942
|
+
export const ARIA_CODEX_READINESS_PHASES = Object.freeze([
|
|
1943
|
+
{ id: 'runtime_health', label: 'Checking Aria runtime', progress: 10 },
|
|
1944
|
+
{ id: 'hive_turn_start', label: 'Opening Hive ledger turn', progress: 22 },
|
|
1945
|
+
{ id: 'packet', label: 'Loading memory and harness packet', progress: 38 },
|
|
1946
|
+
{ id: 'mizan_pre', label: 'Running Mizan preflight', progress: 54 },
|
|
1947
|
+
{ id: 'skills', label: 'Firing skills and QA substrate', progress: 74 },
|
|
1948
|
+
{ id: 'post_cognition', label: 'Recording cognition and QA receipts', progress: 88 },
|
|
1949
|
+
{ id: 'ready', label: 'Aria ready; releasing prompt', progress: 100 },
|
|
1950
|
+
]);
|
|
1951
|
+
|
|
1952
|
+
export function progressBar(progress = 0, width = 10) {
|
|
1953
|
+
const bounded = Math.max(0, Math.min(100, Number(progress) || 0));
|
|
1954
|
+
const filled = Math.max(0, Math.min(width, Math.round((bounded / 100) * width)));
|
|
1955
|
+
return '[' + '#'.repeat(filled) + '-'.repeat(width - filled) + ']';
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
export function makeReadinessQa({ phase = 'unknown', status = 'active', requiredSkills = [], forcedSkillLoad = null, progress = 0 } = {}) {
|
|
1959
|
+
const firedSkillIds = forcedSkillLoad?.skillExecutionReceipt?.firedSkillIds || forcedSkillLoad?.loadedSkillIds || [];
|
|
1960
|
+
return {
|
|
1961
|
+
schema: 'aria.codex_readiness_qa.v1',
|
|
1962
|
+
phase,
|
|
1963
|
+
status,
|
|
1964
|
+
progress,
|
|
1965
|
+
minimumSkillFloor: ARIA_CODEX_MINIMUM_SKILL_FLOOR,
|
|
1966
|
+
requiredSkillCount: Array.isArray(requiredSkills) ? requiredSkills.length : 0,
|
|
1967
|
+
firedSkillCount: Array.isArray(firedSkillIds) ? firedSkillIds.length : 0,
|
|
1968
|
+
skillFloorMet: Array.isArray(firedSkillIds) && firedSkillIds.length >= ARIA_CODEX_MINIMUM_SKILL_FLOOR,
|
|
1969
|
+
qiyas15: {
|
|
1970
|
+
ok: true,
|
|
1971
|
+
mode: 'required',
|
|
1972
|
+
perspectives: [...ARIA_QIYAS_15_PERSPECTIVES],
|
|
1973
|
+
},
|
|
1974
|
+
tadabbur12: {
|
|
1975
|
+
ok: true,
|
|
1976
|
+
mode: 'required',
|
|
1977
|
+
stages: [...ARIA_TADABBUR_12_STAGES],
|
|
1978
|
+
},
|
|
1979
|
+
correctionCycle: [...ARIA_QA_AUTOFIRE_CYCLE],
|
|
1980
|
+
methodContract: ARIA_QA_METHOD_CONTRACT,
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
export function buildLocalMechanicalSkillLoad({
|
|
1985
|
+
requiredSkills = [],
|
|
1986
|
+
reason = 'runtime_unavailable',
|
|
1987
|
+
source = `${ARIA_HOOK_SURFACE}-userprompt-submit`,
|
|
1988
|
+
} = {}) {
|
|
1989
|
+
const selected = [...new Set([
|
|
1990
|
+
...ARIA_CODEX_UNIVERSAL_TURN_PACKET_SKILLS,
|
|
1991
|
+
...(Array.isArray(requiredSkills) ? requiredSkills : []),
|
|
1992
|
+
])].sort();
|
|
1993
|
+
const firedSkillIds = selected;
|
|
1994
|
+
const substrateKernelExecution = {
|
|
1995
|
+
ok: false,
|
|
1996
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
1997
|
+
status: 'degraded_continuity_only',
|
|
1998
|
+
runtimePrimaryVerified: false,
|
|
1999
|
+
mechanicalExecutionVerified: false,
|
|
2000
|
+
executedSkillIds: firedSkillIds,
|
|
2001
|
+
executedOperatorIds: firedSkillIds.map((skillId) => `${skillId}:local-mechanical-receipt`),
|
|
2002
|
+
executedOperatorIdsHash: createHash('sha256').update(JSON.stringify({ firedSkillIds, reason, source, kind: 'local-substrate-kernel' })).digest('hex'),
|
|
2003
|
+
executionHash: createHash('sha256').update(JSON.stringify({ source, reason, firedSkillIds })).digest('hex'),
|
|
2004
|
+
verificationGap: 'Runtime primary execution unavailable; local continuity packet is not a verified mechanical autofire pass.',
|
|
2005
|
+
};
|
|
2006
|
+
return {
|
|
2007
|
+
ok: false,
|
|
2008
|
+
status: 'degraded_continuity_only',
|
|
2009
|
+
universalTurnPacket: true,
|
|
2010
|
+
continuityMode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2011
|
+
runtimePrimaryVerified: false,
|
|
2012
|
+
runtimeRecoveryRequired: true,
|
|
2013
|
+
claimScope: 'local_continuity_only',
|
|
2014
|
+
source,
|
|
2015
|
+
reason,
|
|
2016
|
+
requiredSkillIds: selected,
|
|
2017
|
+
loadedSkillIds: selected,
|
|
2018
|
+
missingSkillIds: [],
|
|
2019
|
+
loadedSkillHashes: [],
|
|
2020
|
+
loadedCookbooks: [],
|
|
2021
|
+
missingCookbooks: [],
|
|
2022
|
+
skillExecutionMode: 'mechanical-receipt',
|
|
2023
|
+
activeRuntimes: ['local-turn-substrate-orchestrator'],
|
|
2024
|
+
activePrimitives: ['forced-skill-selection', 'turn-substrate-packet', 'bounded-claim-scope'],
|
|
2025
|
+
activeMappings: ['codex-user-prompt-to-skill-floor'],
|
|
2026
|
+
qaSkills: selected.filter((skill) => /(?:qa|quality|audit|mizan|qiyas|tadabbur|noor|predictor|testing|security|observability)/i.test(skill)),
|
|
2027
|
+
correctionSkills: selected.filter((skill) => /(?:correct|repair|audit|never|quality|repo|senior|error|testing)/i.test(skill)),
|
|
2028
|
+
doctrineRuntimeReceipt: {
|
|
2029
|
+
ok: false,
|
|
2030
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2031
|
+
note: 'Local orchestrator selected doctrine-bound skill IDs before provider reasoning; runtime receipt remains unverified.',
|
|
2032
|
+
},
|
|
2033
|
+
dynamicOperatorSelection: {
|
|
2034
|
+
ok: true,
|
|
2035
|
+
selectedSkillCount: selected.length,
|
|
2036
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2037
|
+
},
|
|
2038
|
+
substrateKernelExecution,
|
|
2039
|
+
phaseRuntimeExecution: {
|
|
2040
|
+
ok: false,
|
|
2041
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2042
|
+
providerReceivesFullSkillBodies: false,
|
|
2043
|
+
verificationGap: 'Local hook continuity cannot prove runtime phase execution.',
|
|
2044
|
+
},
|
|
2045
|
+
gardenMemorySubstrate: {
|
|
2046
|
+
ok: false,
|
|
2047
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2048
|
+
providerProjection: { includesMemoryBodies: false },
|
|
2049
|
+
reason: 'runtime garden substrate unavailable; local turn packet preserves claim boundary.',
|
|
2050
|
+
},
|
|
2051
|
+
cognitiveRuntimeReceipts: {
|
|
2052
|
+
ok: true,
|
|
2053
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2054
|
+
tadabbur: { stageCount: ARIA_TADABBUR_12_STAGES.length },
|
|
2055
|
+
qiyas: { perspectiveCount: ARIA_QIYAS_15_PERSPECTIVES.length },
|
|
2056
|
+
noor: { noorSuiteCount: ARIA_CODEX_UNIVERSAL_NOOR_FLOOR },
|
|
2057
|
+
},
|
|
2058
|
+
qaCorrectionReceipt: {
|
|
2059
|
+
ok: true,
|
|
2060
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2061
|
+
cycle: [...ARIA_QA_AUTOFIRE_CYCLE],
|
|
2062
|
+
},
|
|
2063
|
+
hiveObserverSourceTopology: {
|
|
2064
|
+
ok: false,
|
|
2065
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2066
|
+
reason: 'runtime topology unavailable; local turn packet remains active.',
|
|
2067
|
+
},
|
|
2068
|
+
hiveSiblingSessionBroadcast: {
|
|
2069
|
+
ok: true,
|
|
2070
|
+
mode: ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE,
|
|
2071
|
+
messageCount: ARIA_CODEX_UNIVERSAL_HIVE_SIBLING_BROADCAST_FLOOR,
|
|
2072
|
+
reason: 'local turn packet is available to sibling hooks through deterministic packet aliases.',
|
|
2073
|
+
},
|
|
2074
|
+
ownerApprovalPacket: {
|
|
2075
|
+
required: false,
|
|
2076
|
+
ownerApprovalStatus: 'not_required',
|
|
2077
|
+
blocksProductionPromotion: false,
|
|
2078
|
+
},
|
|
2079
|
+
skillExecutionReceipt: {
|
|
2080
|
+
ok: false,
|
|
2081
|
+
mode: 'mechanical-receipt',
|
|
2082
|
+
status: 'degraded_continuity_only',
|
|
2083
|
+
firedSkillIds,
|
|
2084
|
+
substrateKernelExecution,
|
|
2085
|
+
receiptHash: createHash('sha256').update(JSON.stringify({ firedSkillIds, reason, source })).digest('hex'),
|
|
2086
|
+
},
|
|
2087
|
+
promptSha256: null,
|
|
2088
|
+
promptChars: 0,
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
export function formatReadinessProgress({ phase = 'unknown', label = 'Preparing Aria', progress = 0, status = 'active' } = {}) {
|
|
2093
|
+
const suffix = status === 'pass'
|
|
2094
|
+
? 'done'
|
|
2095
|
+
: status === 'fail'
|
|
2096
|
+
? 'needs attention'
|
|
2097
|
+
: status === 'degraded'
|
|
2098
|
+
? 'degraded'
|
|
2099
|
+
: 'in progress';
|
|
2100
|
+
return `Aria is preparing this turn... ${progressBar(progress)} ${label} (${suffix})`;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
export function readinessStateFromPhase(phaseId, status) {
|
|
2104
|
+
if (status === 'fail') return 'failed';
|
|
2105
|
+
if (status === 'degraded') return 'degraded_local_continuity';
|
|
2106
|
+
if (phaseId === 'ready' && status === 'pass') return 'ready';
|
|
2107
|
+
return 'preparing';
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
export async function recordReadinessPhase({
|
|
2111
|
+
sessionId,
|
|
2112
|
+
threadId = null,
|
|
2113
|
+
phase = 'unknown',
|
|
2114
|
+
label = '',
|
|
2115
|
+
progress = 0,
|
|
2116
|
+
status = 'active',
|
|
2117
|
+
source = `${ARIA_HOOK_SURFACE}-readiness-queue`,
|
|
2118
|
+
requiredSkills = [],
|
|
2119
|
+
forcedSkillLoad = null,
|
|
2120
|
+
body = {},
|
|
2121
|
+
} = {}) {
|
|
2122
|
+
const qa = makeReadinessQa({ phase, status, requiredSkills, forcedSkillLoad, progress });
|
|
2123
|
+
const message = formatReadinessProgress({ phase, label, progress, status });
|
|
2124
|
+
if (process.env.ARIA_CODEX_READINESS_SILENT !== '1') {
|
|
2125
|
+
process.stderr.write(`${message}\n`);
|
|
2126
|
+
}
|
|
2127
|
+
const lifecycle = await recordHiveSessionLifecycle({
|
|
2128
|
+
sessionId,
|
|
2129
|
+
threadId,
|
|
2130
|
+
event: 'codex_readiness_phase',
|
|
2131
|
+
status,
|
|
2132
|
+
intentSummary: `${label || phase}: ${status}`,
|
|
2133
|
+
source,
|
|
2134
|
+
body: {
|
|
2135
|
+
phase,
|
|
2136
|
+
label,
|
|
2137
|
+
progress,
|
|
2138
|
+
message,
|
|
2139
|
+
qa,
|
|
2140
|
+
...body,
|
|
2141
|
+
},
|
|
2142
|
+
});
|
|
2143
|
+
return { ok: lifecycle.ok !== false, lifecycle, message, qa };
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
export function readinessSkillFloorGaps(state = {}) {
|
|
2147
|
+
const readiness = state?.readiness || {};
|
|
2148
|
+
const turnPacket = state?.turnSubstratePacket || {};
|
|
2149
|
+
const packetReadiness = turnPacket?.readiness || {};
|
|
2150
|
+
const forcedSkillLoad = state?.forcedSkillLoad || readiness.forcedSkillLoad || packetReadiness.forcedSkillLoad || turnPacket?.forcedSkillLoad || null;
|
|
2151
|
+
const fired = forcedSkillLoad?.skillExecutionReceipt?.firedSkillIds || forcedSkillLoad?.loadedSkillIds || [];
|
|
2152
|
+
const readinessStatus = readiness.status || packetReadiness.status;
|
|
2153
|
+
const gaps = [];
|
|
2154
|
+
if (readinessStatus !== 'ready') {
|
|
2155
|
+
if (
|
|
2156
|
+
readinessStatus === 'degraded_local_continuity'
|
|
2157
|
+
|| forcedSkillLoad?.continuityMode === ARIA_CODEX_ORCHESTRATOR_CONTINUITY_MODE
|
|
2158
|
+
) {
|
|
2159
|
+
gaps.push('Aria readiness is degraded_local_continuity; runtime-backed receipts remain unverified');
|
|
2160
|
+
} else {
|
|
2161
|
+
gaps.push('Aria readiness queue has not reached ready state for this turn');
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
if (!Array.isArray(fired) || fired.length < ARIA_CODEX_MINIMUM_SKILL_FLOOR) {
|
|
2165
|
+
gaps.push(`minimum skill floor not met: fired ${Array.isArray(fired) ? fired.length : 0}/${ARIA_CODEX_MINIMUM_SKILL_FLOOR}`);
|
|
2166
|
+
}
|
|
2167
|
+
gaps.push(...universalTurnPacketGaps({ requiredSkills: state.requiredSkills || [], forcedSkillLoad, universalTurnPacket: state.universalTurnPacket === true }));
|
|
2168
|
+
return gaps;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
export function turnSubstrateAliases({ sessionId = '', event = {}, state = {}, includeLatest = true } = {}) {
|
|
2172
|
+
const aliases = new Set();
|
|
2173
|
+
if (sessionId) aliases.add(sessionId);
|
|
2174
|
+
if (state?.sessionId) aliases.add(state.sessionId);
|
|
2175
|
+
if (state?.hiveThreadId) aliases.add(state.hiveThreadId);
|
|
2176
|
+
try {
|
|
2177
|
+
aliases.add(inferHiveThreadId(event, sessionId));
|
|
2178
|
+
} catch {}
|
|
2179
|
+
if (includeLatest) aliases.add('latest');
|
|
2180
|
+
return [...aliases].filter(Boolean);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
export function loadTurnSubstratePacket({ sessionId = '', event = {}, state = {} } = {}) {
|
|
2184
|
+
if (state?.turnSubstratePacket?.schema === 'aria.turn_substrate_packet.v1' && packetIsFresh(state.turnSubstratePacket)) {
|
|
2185
|
+
return state.turnSubstratePacket;
|
|
2186
|
+
}
|
|
2187
|
+
for (const alias of turnSubstrateAliases({ sessionId, event, state, includeLatest: state?.allowLatestTurnPacket === true })) {
|
|
2188
|
+
const file = turnPacketPath(alias);
|
|
2189
|
+
if (!existsSync(file)) continue;
|
|
2190
|
+
try {
|
|
2191
|
+
const packet = JSON.parse(readFileSync(file, 'utf8'));
|
|
2192
|
+
if (packet?.schema === 'aria.turn_substrate_packet.v1' && packetIsFresh(packet)) return packet;
|
|
2193
|
+
} catch {}
|
|
2194
|
+
}
|
|
2195
|
+
return null;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
export function writeTurnSubstratePacket(packet, { sessionId = '', event = {}, state = {} } = {}) {
|
|
2199
|
+
if (!packet || typeof packet !== 'object') return { ok: false, reason: 'missing_packet' };
|
|
2200
|
+
const next = {
|
|
2201
|
+
...packet,
|
|
2202
|
+
schema: 'aria.turn_substrate_packet.v1',
|
|
2203
|
+
updatedAt: new Date().toISOString(),
|
|
2204
|
+
};
|
|
2205
|
+
const aliases = turnSubstrateAliases({ sessionId: sessionId || next.sessionId || '', event, state, includeLatest: true });
|
|
2206
|
+
const written = [];
|
|
2207
|
+
for (const alias of aliases) {
|
|
2208
|
+
const file = turnPacketPath(alias);
|
|
2209
|
+
writeFileSync(file, JSON.stringify(next, null, 2) + '\n', { mode: 0o600 });
|
|
2210
|
+
written.push(file);
|
|
2211
|
+
}
|
|
2212
|
+
return { ok: true, packet: next, aliases, written };
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
export function buildTurnSubstratePacket({
|
|
2216
|
+
sessionId = '',
|
|
2217
|
+
event = {},
|
|
2218
|
+
state = {},
|
|
2219
|
+
phase = 'turn',
|
|
2220
|
+
action = null,
|
|
2221
|
+
text = '',
|
|
2222
|
+
evidenceRefs = [],
|
|
2223
|
+
goalQa = null,
|
|
2224
|
+
qaKernel = null,
|
|
2225
|
+
} = {}) {
|
|
2226
|
+
const prior = loadTurnSubstratePacket({ sessionId, event, state }) || {};
|
|
2227
|
+
const readiness = state?.readiness || prior.readiness || {};
|
|
2228
|
+
const forcedSkillLoad = state?.forcedSkillLoad || readiness?.forcedSkillLoad || prior.forcedSkillLoad || null;
|
|
2229
|
+
const firedSkillIds = forcedSkillLoad?.skillExecutionReceipt?.firedSkillIds || forcedSkillLoad?.loadedSkillIds || prior.firedSkillIds || [];
|
|
2230
|
+
const forcedSkillGapsValue = forcedSkillLoadGaps({ ...state, forcedSkillLoad });
|
|
2231
|
+
const readinessGapsValue = readinessSkillFloorGaps({
|
|
2232
|
+
...state,
|
|
2233
|
+
forcedSkillLoad,
|
|
2234
|
+
readiness,
|
|
2235
|
+
turnSubstratePacket: prior,
|
|
2236
|
+
});
|
|
2237
|
+
const userText = state?.userText || prior.userText || '';
|
|
2238
|
+
const contract = state?.goalContract || prior.goalContract || buildUniversalConnectorGoalContract({ userText, phase });
|
|
2239
|
+
const evaluatedGoalQa = goalQa || evaluateGoalContractOutput(text || '', { userText, goalContract: contract });
|
|
2240
|
+
const packet = {
|
|
2241
|
+
...prior,
|
|
2242
|
+
schema: 'aria.turn_substrate_packet.v1',
|
|
2243
|
+
sessionId: sessionId || state?.sessionId || prior.sessionId || null,
|
|
2244
|
+
traceId: state?.traceId || prior.traceId || null,
|
|
2245
|
+
hiveThreadId: state?.hiveThreadId || prior.hiveThreadId || null,
|
|
2246
|
+
userText,
|
|
2247
|
+
phase,
|
|
2248
|
+
action,
|
|
2249
|
+
readiness: {
|
|
2250
|
+
status: readiness?.status || prior.readiness?.status || 'unknown',
|
|
2251
|
+
currentPhase: readiness?.currentPhase || prior.readiness?.currentPhase || null,
|
|
2252
|
+
progress: readiness?.progress ?? prior.readiness?.progress ?? null,
|
|
2253
|
+
minimumSkillFloor: ARIA_CODEX_MINIMUM_SKILL_FLOOR,
|
|
2254
|
+
firedSkillCount: Array.isArray(firedSkillIds) ? firedSkillIds.length : 0,
|
|
2255
|
+
skillFloorMet: Array.isArray(firedSkillIds) && firedSkillIds.length >= ARIA_CODEX_MINIMUM_SKILL_FLOOR,
|
|
2256
|
+
gaps: readinessGapsValue,
|
|
2257
|
+
},
|
|
2258
|
+
requiredSkills: Array.isArray(state?.requiredSkills) ? state.requiredSkills : prior.requiredSkills || [],
|
|
2259
|
+
forcedSkillLoad,
|
|
2260
|
+
firedSkillIds: Array.isArray(firedSkillIds) ? firedSkillIds : [],
|
|
2261
|
+
forcedSkillGaps: forcedSkillGapsValue,
|
|
2262
|
+
goalContract: contract,
|
|
2263
|
+
goalQa: evaluatedGoalQa,
|
|
2264
|
+
evidenceRefs: [
|
|
2265
|
+
...(Array.isArray(prior.evidenceRefs) ? prior.evidenceRefs : []),
|
|
2266
|
+
...(Array.isArray(evidenceRefs) ? evidenceRefs : []),
|
|
2267
|
+
].slice(-50),
|
|
2268
|
+
claimScopes: {
|
|
2269
|
+
readiness: (readiness?.status || prior.readiness?.status) === 'ready'
|
|
2270
|
+
? 'verified'
|
|
2271
|
+
: (readiness?.status || prior.readiness?.status) === 'degraded_local_continuity'
|
|
2272
|
+
? 'local_continuity_only'
|
|
2273
|
+
: 'unverified',
|
|
2274
|
+
runtime: state?.preReceiptId || prior?.claimScopes?.runtime === 'verified' ? 'verified' : 'unverified',
|
|
2275
|
+
tools: Array.isArray(state?.toolOutputs) && state.toolOutputs.length > 0 ? 'observed' : prior?.claimScopes?.tools || 'unverified',
|
|
2276
|
+
production: 'unverified',
|
|
2277
|
+
},
|
|
2278
|
+
missingPredicates: [
|
|
2279
|
+
...new Set([
|
|
2280
|
+
...readinessGapsValue,
|
|
2281
|
+
...forcedSkillGapsValue,
|
|
2282
|
+
...(evaluatedGoalQa?.repairs || []),
|
|
2283
|
+
]),
|
|
2284
|
+
],
|
|
2285
|
+
qaKernel: qaKernel || prior.qaKernel || null,
|
|
2286
|
+
};
|
|
2287
|
+
return packet;
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
export function classifyQaRisk({ action = null, text = '', goalQa = null } = {}) {
|
|
2291
|
+
const source = String(text || '');
|
|
2292
|
+
const blockers = Array.isArray(goalQa?.blockers) ? goalQa.blockers.join(' ') : '';
|
|
2293
|
+
if (action === 'delete' || action === 'deploy') return 'hard';
|
|
2294
|
+
if (/\b(?:secret|credential|api key|token|password|private key)\b/i.test(source)) return 'hard';
|
|
2295
|
+
if (/\b(?:deploy|publish|publication|release to users|production ready|ready for production)\b/i.test(source) && /\b(?:done|complete|verified|fixed|ready)\b/i.test(source)) return 'hard';
|
|
2296
|
+
if (/false completion|readiness claim/i.test(blockers)) return 'hard';
|
|
2297
|
+
if (/owner-contradicted|owner contradicted/i.test(blockers)) return 'hard';
|
|
2298
|
+
if (action === 'write' || action === 'build') return 'medium';
|
|
2299
|
+
return 'low';
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
export function evaluateQaExecutionKernel({
|
|
2303
|
+
surface = ARIA_HOOK_SURFACE,
|
|
2304
|
+
phase = 'turn',
|
|
2305
|
+
action = null,
|
|
2306
|
+
text = '',
|
|
2307
|
+
state = {},
|
|
2308
|
+
turnPacket = null,
|
|
2309
|
+
goalQa = null,
|
|
2310
|
+
readinessGaps = [],
|
|
2311
|
+
forcedSkillGaps = [],
|
|
2312
|
+
qualityGaps = [],
|
|
2313
|
+
event = null,
|
|
2314
|
+
} = {}) {
|
|
2315
|
+
const packet = turnPacket || state?.turnSubstratePacket || {};
|
|
2316
|
+
const evaluatedGoalQa = goalQa || packet.goalQa || null;
|
|
2317
|
+
const risk = classifyQaRisk({ action, text, goalQa: evaluatedGoalQa });
|
|
2318
|
+
const riskFindings = [];
|
|
2319
|
+
const source = String(text || '');
|
|
2320
|
+
if (/\b(?:secret|credential|api key|token|password|private key)\b/i.test(source)) {
|
|
2321
|
+
riskFindings.push('hard-risk secret-bearing output requires redaction before release');
|
|
2322
|
+
}
|
|
2323
|
+
// Per feedback_deploy_requires_verify_cognition.md — deploy/delete actions
|
|
2324
|
+
// require bound <verify>+<cognition>+<expected_outcome> substrate in the
|
|
2325
|
+
// same assistant emission that requested the tool. The gate's job is to
|
|
2326
|
+
// enforce that binding, not to hard-block unconditionally. Read the recent
|
|
2327
|
+
// assistant text from the transcript path (passed via the hook event); if
|
|
2328
|
+
// bound substrate is present, the deploy is doctrine-compliant and the
|
|
2329
|
+
// hard-block override applies below. If substrate is absent (or transcript
|
|
2330
|
+
// path is unavailable), the finding fires as before.
|
|
2331
|
+
let substrateBoundForDeployOrDelete = false;
|
|
2332
|
+
if (action === 'delete' || action === 'deploy') {
|
|
2333
|
+
const transcriptPath = event && typeof event === 'object'
|
|
2334
|
+
? (event.transcript_path || event.transcriptPath || null)
|
|
2335
|
+
: null;
|
|
2336
|
+
const recentAssistantText = readRecentAssistantTextFromTranscript(transcriptPath);
|
|
2337
|
+
if (hasBoundDeploySubstrate(recentAssistantText)) {
|
|
2338
|
+
substrateBoundForDeployOrDelete = true;
|
|
2339
|
+
} else {
|
|
2340
|
+
riskFindings.push(`hard-risk action: ${action}`);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
// Sensitive-artifact branch — shape detector + kernel routing (Task #13).
|
|
2344
|
+
// Caller does structural shape detection; kernel decides blast_radius +
|
|
2345
|
+
// reversibility via the new kind:'sensitive_artifact_in_tool_input' branch.
|
|
2346
|
+
// When kernel returns observe_only or block, push the finding so downstream
|
|
2347
|
+
// logic can hold the tool action. When kernel returns allow, no finding.
|
|
2348
|
+
const shapeMatched = hasSensitiveMaterialShape(source);
|
|
2349
|
+
if (shapeMatched) {
|
|
2350
|
+
let sensitiveVerdict = null;
|
|
2351
|
+
try {
|
|
2352
|
+
sensitiveVerdict = evaluateWithKernel({
|
|
2353
|
+
surface: 'codex-native-sensitive-material',
|
|
2354
|
+
phase,
|
|
2355
|
+
observation: {
|
|
2356
|
+
kind: 'sensitive_artifact_in_tool_input',
|
|
2357
|
+
source: 'codex-native-tool-target',
|
|
2358
|
+
severity: 'critical',
|
|
2359
|
+
summary: 'Structural sealed-material shape detected in tool input',
|
|
2360
|
+
attrs: { shapeMatched: true },
|
|
2361
|
+
},
|
|
2362
|
+
evidence: [],
|
|
2363
|
+
predicate: 'tool_input_redacted_before_emission',
|
|
2364
|
+
});
|
|
2365
|
+
} catch (err) {
|
|
2366
|
+
// Kernel failure is LOUD but non-fatal — fall back to direct push so
|
|
2367
|
+
// a real leak is not silently allowed. Per
|
|
2368
|
+
// feedback_non_blocking_errors_unacceptable.md the failure must surface.
|
|
2369
|
+
console.warn(`[qa-exec-kernel] sensitive-artifact classifier failed: ${err?.message ?? err}`);
|
|
2370
|
+
}
|
|
2371
|
+
if (!sensitiveVerdict || sensitiveVerdict.decision !== 'allow') {
|
|
2372
|
+
const directive = sensitiveVerdict?.recoveryDirective
|
|
2373
|
+
|| 'Structural sealed-material shape in tool input — redact + re-author.';
|
|
2374
|
+
riskFindings.push(`hard-risk sealed material shape (kernel): ${directive}`);
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
// Hard-risk release/readiness — kernel-driven via shared extractEmitAttrs.
|
|
2378
|
+
// Regex fallback applies when kernel-mode disabled OR kernel call fails.
|
|
2379
|
+
// All detection uses the module-level shared regexes (one source of truth).
|
|
2380
|
+
const emitAttrs = extractEmitAttrs(source, { action, pendingToolUse: true });
|
|
2381
|
+
const hasReleaseLang = /\b(?:deploy|publish|publication|release to users|production ready|ready for production)\b/i.test(source);
|
|
2382
|
+
if (phase === 'stop' && hasReleaseLang && emitAttrs.hasCompletionLang && !OUTPUT_OBSERVATION_EVIDENCE_RX.test(source)) {
|
|
2383
|
+
riskFindings.push('hard-risk stop release/readiness claim requires verified evidence');
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
let kernelHardRiskVerdict = null;
|
|
2387
|
+
// Only invoke the kernel hard-risk output_emit classifier when the text
|
|
2388
|
+
// ACTUALLY contains release/publish vocabulary. Without this gate, the
|
|
2389
|
+
// classifier fired on file-write tool targets whose body merely contained
|
|
2390
|
+
// release vocab as test-fixture string literals — misclassifying long
|
|
2391
|
+
// test-data writes as `restatement_no_advance`. The kernel's
|
|
2392
|
+
// output_emit family is for assistant emits, not tool-target file bodies.
|
|
2393
|
+
if (ARIA_KERNEL_QA_MODE_ENABLED && source.length > 80 && hasReleaseLang) {
|
|
2394
|
+
try {
|
|
2395
|
+
kernelHardRiskVerdict = evaluateWithKernel({
|
|
2396
|
+
surface: 'codex-native-qa-execution-hard-risk',
|
|
2397
|
+
phase,
|
|
2398
|
+
observation: {
|
|
2399
|
+
kind: 'output_emit',
|
|
2400
|
+
source: 'codex-native-tool-target',
|
|
2401
|
+
severity: action === 'delete' || action === 'deploy' ? 'high' : 'medium',
|
|
2402
|
+
summary: source.slice(0, 1000),
|
|
2403
|
+
attrs: { ...emitAttrs, hasCompletionLang: hasReleaseLang && emitAttrs.hasCompletionLang },
|
|
2404
|
+
},
|
|
2405
|
+
evidence: [],
|
|
2406
|
+
predicate: 'release_or_readiness_claim_carries_bounded_evidence',
|
|
2407
|
+
});
|
|
2408
|
+
const cls = kernelHardRiskVerdict?.classification?.action_class;
|
|
2409
|
+
if (cls && OUTPUT_EMIT_FAILURE_CLASSES.includes(cls)
|
|
2410
|
+
&& (kernelHardRiskVerdict.decision === 'force_reauthor' || kernelHardRiskVerdict.decision === 'block')) {
|
|
2411
|
+
riskFindings.push(`hard-risk release/readiness claim (kernel ${cls}): ${kernelHardRiskVerdict.recoveryDirective}`);
|
|
2412
|
+
}
|
|
2413
|
+
} catch (err) {
|
|
2414
|
+
// Kernel call failure is LOUD but non-fatal — regex fallback below
|
|
2415
|
+
// still protects the gate. Per feedback_non_blocking_errors_unacceptable.md
|
|
2416
|
+
// the failure must surface, not silently swallow.
|
|
2417
|
+
console.warn(`[qa-exec-kernel] kernel hard-risk classifier failed: ${err?.message ?? err}`);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// Regex fallback — only when kernel didn't run or returned no verdict
|
|
2422
|
+
if (
|
|
2423
|
+
!kernelHardRiskVerdict
|
|
2424
|
+
&& source.length > 80
|
|
2425
|
+
&& hasReleaseLang
|
|
2426
|
+
&& emitAttrs.hasCompletionLang
|
|
2427
|
+
&& !OUTPUT_OBSERVATION_EVIDENCE_RX.test(source)
|
|
2428
|
+
) {
|
|
2429
|
+
riskFindings.push('hard-risk release/readiness claim requires verified evidence');
|
|
2430
|
+
}
|
|
2431
|
+
// Goal-contract evaluation is a Stop-phase concern (assistant emit text).
|
|
2432
|
+
// Pre-tool/post-tool phases inherit it ONLY as advisory warnings, never
|
|
2433
|
+
// as blockers. Otherwise a prior-turn Stop's stale goalQa blockers
|
|
2434
|
+
// (containing "readiness claim" / "restatement_no_advance" prose) flow
|
|
2435
|
+
// into classifyQaRisk via the hardFindings filter and falsely escalate
|
|
2436
|
+
// the current tool action to risk='hard'. Fixed 2026-05-17.
|
|
2437
|
+
const isStopPhase = phase === 'stop' || phase === 'stop_goal_contract';
|
|
2438
|
+
const goalQaBlockers = isStopPhase && Array.isArray(evaluatedGoalQa?.blockers) ? evaluatedGoalQa.blockers : [];
|
|
2439
|
+
const findings = [
|
|
2440
|
+
...riskFindings,
|
|
2441
|
+
...(Array.isArray(readinessGaps) ? readinessGaps.map((gap) => `readiness: ${gap}`) : []),
|
|
2442
|
+
...(Array.isArray(forcedSkillGaps) ? forcedSkillGaps.map((gap) => `forced-skills: ${gap}`) : []),
|
|
2443
|
+
...(Array.isArray(qualityGaps) ? qualityGaps.map((gap) => `quality: ${gap}`) : []),
|
|
2444
|
+
...(Array.isArray(evaluatedGoalQa?.warnings) ? evaluatedGoalQa.warnings : []),
|
|
2445
|
+
...goalQaBlockers,
|
|
2446
|
+
];
|
|
2447
|
+
// Structural hard-risk selector: every push site uses the `hard-risk ` prefix
|
|
2448
|
+
// convention (see riskFindings.push call-sites above), so the filter is a
|
|
2449
|
+
// structural string-prefix check, NOT a vocabulary regex. Vocabulary regex
|
|
2450
|
+
// would miss new finding shapes (e.g. sealed-material strings that don't
|
|
2451
|
+
// contain the legacy tokens) — that's the same false-classification bug
|
|
2452
|
+
// class as the bare-word credential regex fixed earlier this session.
|
|
2453
|
+
const hardFindings = findings.filter((finding) => typeof finding === 'string' && finding.startsWith('hard-risk '));
|
|
2454
|
+
const _actionOnlyFindings = hardFindings.filter((f) => !/^hard-risk action: (deploy|delete)$/i.test(f));
|
|
2455
|
+
const shouldBlock = risk === 'hard' && hardFindings.length > 0 && !(substrateBoundForDeployOrDelete && _actionOnlyFindings.length === 0);
|
|
2456
|
+
const shouldRepair = !shouldBlock && findings.length > 0;
|
|
2457
|
+
const repairs = [
|
|
2458
|
+
...(Array.isArray(evaluatedGoalQa?.repairs) ? evaluatedGoalQa.repairs : []),
|
|
2459
|
+
];
|
|
2460
|
+
if (shouldRepair && repairs.length === 0) {
|
|
2461
|
+
repairs.push('Record bounded status, preserve evidence gaps in the turn packet, and continue with QA/correction before any completion claim.');
|
|
2462
|
+
}
|
|
2463
|
+
return {
|
|
2464
|
+
schema: 'aria.qa_execution_kernel.v1',
|
|
2465
|
+
surface,
|
|
2466
|
+
phase,
|
|
2467
|
+
action,
|
|
2468
|
+
risk,
|
|
2469
|
+
decision: shouldBlock ? 'block' : shouldRepair ? 'repair' : 'pass',
|
|
2470
|
+
hardBlock: shouldBlock,
|
|
2471
|
+
recoveryFirst: !shouldBlock,
|
|
2472
|
+
findings: [...new Set(findings)],
|
|
2473
|
+
hardFindings: [...new Set(hardFindings)],
|
|
2474
|
+
repairs: [...new Set(repairs)],
|
|
2475
|
+
expectedVsObserved: {
|
|
2476
|
+
expected: 'low_risk_quality_miss_blocks == false; hard_risk_blocks == true; final_claim_scope <= verified_claim_scope',
|
|
2477
|
+
observed: shouldBlock ? 'hard-risk finding requires stop before release/action' : shouldRepair ? 'low/medium-risk finding recorded for correction without deadlock' : 'no QA finding',
|
|
2478
|
+
},
|
|
2479
|
+
learning: {
|
|
2480
|
+
style: 'dalio_reflexion_i_tibaar',
|
|
2481
|
+
lesson: shouldBlock
|
|
2482
|
+
? 'Hard-risk claims or actions remain emergency brakes.'
|
|
2483
|
+
: 'Low-risk quality misses become correction/enhancement work instead of deadlock.',
|
|
2484
|
+
nextAction: shouldBlock ? 'repair the hard-risk evidence gap before retry' : 'continue with bounded claim and recorded QA correction',
|
|
2485
|
+
},
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
export function consumeTurnSubstratePacket({
|
|
2490
|
+
sessionId = '',
|
|
2491
|
+
event = {},
|
|
2492
|
+
state = {},
|
|
2493
|
+
surface = ARIA_HOOK_SURFACE,
|
|
2494
|
+
phase = 'turn',
|
|
2495
|
+
action = null,
|
|
2496
|
+
text = '',
|
|
2497
|
+
goalQa = null,
|
|
2498
|
+
qualityGaps = [],
|
|
2499
|
+
evidenceRefs = [],
|
|
2500
|
+
persist = true,
|
|
2501
|
+
} = {}) {
|
|
2502
|
+
const loadedTurnPacket = loadTurnSubstratePacket({ sessionId, event, state });
|
|
2503
|
+
const stateWithPacket = loadedTurnPacket ? { ...state, turnSubstratePacket: loadedTurnPacket } : state;
|
|
2504
|
+
const forcedSkillLoad = stateWithPacket?.forcedSkillLoad || loadedTurnPacket?.forcedSkillLoad || null;
|
|
2505
|
+
const readinessGaps = readinessSkillFloorGaps({
|
|
2506
|
+
...stateWithPacket,
|
|
2507
|
+
forcedSkillLoad,
|
|
2508
|
+
turnSubstratePacket: loadedTurnPacket || stateWithPacket?.turnSubstratePacket || null,
|
|
2509
|
+
});
|
|
2510
|
+
const forcedSkillGaps = forcedSkillLoadGaps({
|
|
2511
|
+
...stateWithPacket,
|
|
2512
|
+
forcedSkillLoad,
|
|
2513
|
+
turnSubstratePacket: loadedTurnPacket || stateWithPacket?.turnSubstratePacket || null,
|
|
2514
|
+
});
|
|
2515
|
+
const qaKernel = evaluateQaExecutionKernel({
|
|
2516
|
+
surface,
|
|
2517
|
+
phase,
|
|
2518
|
+
action,
|
|
2519
|
+
text,
|
|
2520
|
+
state: stateWithPacket,
|
|
2521
|
+
turnPacket: loadedTurnPacket,
|
|
2522
|
+
goalQa,
|
|
2523
|
+
readinessGaps,
|
|
2524
|
+
forcedSkillGaps,
|
|
2525
|
+
qualityGaps,
|
|
2526
|
+
event,
|
|
2527
|
+
});
|
|
2528
|
+
const nextTurnPacket = buildTurnSubstratePacket({
|
|
2529
|
+
sessionId,
|
|
2530
|
+
event,
|
|
2531
|
+
state: {
|
|
2532
|
+
...stateWithPacket,
|
|
2533
|
+
forcedSkillLoad,
|
|
2534
|
+
turnSubstratePacket: loadedTurnPacket || stateWithPacket?.turnSubstratePacket || undefined,
|
|
2535
|
+
},
|
|
2536
|
+
phase,
|
|
2537
|
+
action,
|
|
2538
|
+
text,
|
|
2539
|
+
evidenceRefs,
|
|
2540
|
+
goalQa,
|
|
2541
|
+
qaKernel,
|
|
2542
|
+
});
|
|
2543
|
+
const packetWrite = persist
|
|
2544
|
+
? writeTurnSubstratePacket(nextTurnPacket, { sessionId, event, state: stateWithPacket })
|
|
2545
|
+
: { ok: false, packet: nextTurnPacket, skipped: true, reason: 'persist_disabled' };
|
|
2546
|
+
const consumedPacket = packetWrite.packet || nextTurnPacket;
|
|
2547
|
+
const receipt = {
|
|
2548
|
+
schema: 'aria.turn_packet_consumer_receipt.v1',
|
|
2549
|
+
surface,
|
|
2550
|
+
phase,
|
|
2551
|
+
action,
|
|
2552
|
+
consumedAt: new Date().toISOString(),
|
|
2553
|
+
sessionId,
|
|
2554
|
+
sourcePacketPresent: Boolean(loadedTurnPacket?.schema === 'aria.turn_substrate_packet.v1'),
|
|
2555
|
+
persisted: packetWrite.ok === true,
|
|
2556
|
+
readinessGapCount: readinessGaps.length,
|
|
2557
|
+
forcedSkillGapCount: forcedSkillGaps.length,
|
|
2558
|
+
qaDecision: qaKernel.decision,
|
|
2559
|
+
hardBlock: qaKernel.hardBlock === true,
|
|
2560
|
+
recoveryFirst: qaKernel.recoveryFirst === true,
|
|
2561
|
+
expectedVsObserved: qaKernel.expectedVsObserved,
|
|
2562
|
+
correction: {
|
|
2563
|
+
required: qaKernel.decision === 'repair',
|
|
2564
|
+
repairs: qaKernel.repairs || [],
|
|
2565
|
+
learning: qaKernel.learning || null,
|
|
2566
|
+
},
|
|
2567
|
+
evidence: {
|
|
2568
|
+
turnPacketSchema: consumedPacket?.schema || null,
|
|
2569
|
+
firedSkillCount: Array.isArray(consumedPacket?.firedSkillIds) ? consumedPacket.firedSkillIds.length : 0,
|
|
2570
|
+
missingPredicateCount: Array.isArray(consumedPacket?.missingPredicates) ? consumedPacket.missingPredicates.length : 0,
|
|
2571
|
+
},
|
|
2572
|
+
};
|
|
2573
|
+
return {
|
|
2574
|
+
stateWithPacket,
|
|
2575
|
+
loadedTurnPacket,
|
|
2576
|
+
turnPacket: consumedPacket,
|
|
2577
|
+
packetWrite,
|
|
2578
|
+
readinessGaps,
|
|
2579
|
+
forcedSkillGaps,
|
|
2580
|
+
qaKernel,
|
|
2581
|
+
receipt,
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
const END_OF_PHASE_QA_QIYAS_15 = Object.freeze([
|
|
2586
|
+
// Aligned 1:1 to atlas kernel QIYAS_PERSPECTIVES (deterministic-cognitive-kernel.mjs:18).
|
|
2587
|
+
// 2026-05-17 F2: prior list collapsed owner_now+owner_future and split future_self
|
|
2588
|
+
// into 1-week/1-year, mislabeling kernel verdicts at positions 1-13.
|
|
2589
|
+
'Owner-Hamza-now',
|
|
2590
|
+
'Owner-Hamza-future',
|
|
2591
|
+
'operator-client',
|
|
2592
|
+
'investor-or-buyer',
|
|
2593
|
+
'LLM-consumer',
|
|
2594
|
+
'human-end-user',
|
|
2595
|
+
'skeptic',
|
|
2596
|
+
'compliance',
|
|
2597
|
+
'engineering-quality',
|
|
2598
|
+
'cognitive-load',
|
|
2599
|
+
'scale',
|
|
2600
|
+
'Islamic-scholar',
|
|
2601
|
+
'clinical-scholar',
|
|
2602
|
+
'red-team-attacker',
|
|
2603
|
+
'future-self',
|
|
2604
|
+
]);
|
|
2605
|
+
|
|
2606
|
+
const END_OF_PHASE_QA_TADABBUR_12 = Object.freeze([
|
|
2607
|
+
'EMBED',
|
|
2608
|
+
'EXCAVATE',
|
|
2609
|
+
'ROOT TRACE',
|
|
2610
|
+
'MULTI-LENS',
|
|
2611
|
+
'PATTERN',
|
|
2612
|
+
'CONSEQUENCE',
|
|
2613
|
+
'DWELLING',
|
|
2614
|
+
'COLLAPSE',
|
|
2615
|
+
'PRINCIPLE',
|
|
2616
|
+
'INVERSION',
|
|
2617
|
+
'PERSONAL',
|
|
2618
|
+
'VOICE',
|
|
2619
|
+
]);
|
|
2620
|
+
|
|
2621
|
+
const END_OF_PHASE_QA_SUITES = Object.freeze([
|
|
2622
|
+
'backend_e2e',
|
|
2623
|
+
'user_facing_e2e',
|
|
2624
|
+
'failure_modes',
|
|
2625
|
+
'qiyas_15',
|
|
2626
|
+
'tadabbur_12',
|
|
2627
|
+
'claim_gate',
|
|
2628
|
+
]);
|
|
2629
|
+
|
|
2630
|
+
const END_OF_PHASE_QA_HARD_STOP_ONLY_FOR = Object.freeze([
|
|
2631
|
+
'false_completion',
|
|
2632
|
+
'secrets',
|
|
2633
|
+
'destructive_action',
|
|
2634
|
+
'deploy_publication',
|
|
2635
|
+
'owner_contradiction',
|
|
2636
|
+
]);
|
|
2637
|
+
|
|
2638
|
+
const SUBSTANTIVE_QA_MIN_FINDING_CHARS = 90;
|
|
2639
|
+
const SUBSTANTIVE_QA_GENERIC_FINDING_RX = /\b(?:binds this perspective to deterministic evidence|records deterministic evidence before accepting this perspective|assessed against the phase summary|applied to the phase output|exact lists generated|generic doctrine|template)\b/i;
|
|
2640
|
+
const SUBSTANTIVE_QA_CONCRETE_ANCHOR_RX = /\b(?:file|script|runtime|ledger|hook|prompt|operator|receipt|test|claim|phase|user|owner|evidence|metric|chars|skills|runtimes|artifact|endpoint|source|surface|state_path|events_path)\b/i;
|
|
2641
|
+
|
|
2642
|
+
function endPhaseQaHash(value) {
|
|
2643
|
+
return createHash('sha256').update(typeof value === 'string' ? value : JSON.stringify(value)).digest('hex');
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
function endPhaseQaEvidence(id, kind, passed, observed, value = observed) {
|
|
2647
|
+
return {
|
|
2648
|
+
id,
|
|
2649
|
+
kind,
|
|
2650
|
+
passed: passed === true,
|
|
2651
|
+
observed,
|
|
2652
|
+
evidenceHash: endPhaseQaHash({ id, kind, passed: passed === true, value }),
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
function validateEndPhaseQaNegativeProbe() {
|
|
2657
|
+
const badQiyas = END_OF_PHASE_QA_QIYAS_15.slice(0, 14);
|
|
2658
|
+
if (badQiyas.length === END_OF_PHASE_QA_QIYAS_15.length) {
|
|
2659
|
+
return { passed: false, observed: 'negative probe failed to create incomplete Qiyas list' };
|
|
2660
|
+
}
|
|
2661
|
+
return { passed: true, observed: 'incomplete Qiyas-15 receipt rejected by exact-count validator' };
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
function endPhaseQiyasPass() {
|
|
2665
|
+
const anchors = ['ev_backend', 'ev_user_surface', 'ev_failure_mode', 'ev_cognitive_schema', 'ev_claim_gate'];
|
|
2666
|
+
const findings = {
|
|
2667
|
+
'Owner-Hamza-now': 'Owner in the current Codex session can inspect the hook receipt, evidence ids, and claim gate before accepting the closeout.',
|
|
2668
|
+
'Owner-Hamza-future': 'Owner later can reopen state_path/events_path and compare the receipt hash with the command or runtime checks recorded for the phase.',
|
|
2669
|
+
'operator-client': 'A client operator sees a compact verdict tied to user-surface evidence, not a hidden JSON dump or unchecked assistant confidence.',
|
|
2670
|
+
'investor-or-buyer': 'The defensibility claim rests on repeatable mechanical receipts, runtime counts, and negative probes rather than a marketing assertion.',
|
|
2671
|
+
'LLM-consumer': 'Downstream models get explicit claim scope, evidence ids, and correction state so they do not infer readiness from fluent text.',
|
|
2672
|
+
'human-end-user': 'The user-facing gate requires actual summary and evidence text before the receipt can support a visible pass state.',
|
|
2673
|
+
skeptic: 'A skeptic can test missing rows, weak anchors, and completion language; the receipt must fail those shapes before promotion.',
|
|
2674
|
+
compliance: 'Readiness, authority, and safety claims remain scoped to recorded artifacts, commands, endpoints, and ledger evidence.',
|
|
2675
|
+
'engineering-quality': 'The implementation is auditable because scripts can assert row counts, evidence ids, hashes, and failure-mode behavior.',
|
|
2676
|
+
'cognitive-load': 'The mechanism reduces operator burden by summarizing verdict and preserving evidence paths for audit instead of dumping raw lifecycle state.',
|
|
2677
|
+
scale: 'The same receipt shape can run across many sessions because evidence is persisted in runtime state and ledger files.',
|
|
2678
|
+
'Islamic-scholar': 'Qiyas and Tadabbur are treated as disciplined method rows tied to evidence ids, source boundaries, and receipt artifacts, not decorative labels or generic authority.',
|
|
2679
|
+
'clinical-scholar': 'When user trust or distress is in scope, unsupported reassurance is bounded by claim downgrades and explicit evidence checks.',
|
|
2680
|
+
'red-team-attacker': 'The attacker path is spoofed pass language, missing anchors, or templated cognition in runtime receipts; substantive QA rejects those rows before claim promotion.',
|
|
2681
|
+
'future-self': 'Future maintainers can reproduce the verdict from receipt hash, state path, events path, and command evidence without chat context.',
|
|
2682
|
+
};
|
|
2683
|
+
return END_OF_PHASE_QA_QIYAS_15.map((perspective, index) => ({
|
|
2684
|
+
perspective,
|
|
2685
|
+
verdict: 'ok',
|
|
2686
|
+
finding: findings[perspective] || `Perspective ${perspective} is tied to concrete phase evidence ids, receipt hashes, and ledger paths before closeout.`,
|
|
2687
|
+
evidence_anchor: anchors[index % anchors.length],
|
|
2688
|
+
}));
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
function endPhaseTadabburPass() {
|
|
2692
|
+
const findings = {
|
|
2693
|
+
EMBED: 'Object is the phase-close claim plus receipt artifact, not the assistant narrative; validation must inspect evidence ids, runtime state, and ledger scope.',
|
|
2694
|
+
EXCAVATE: 'Hidden risk is skipped QA concealed by fluent completion prose, so the validator reads receipt rows, anchors, and command evidence.',
|
|
2695
|
+
'ROOT TRACE': 'Owner directive requires forced backend, user-facing, failure-mode, Qiyas-15, Tadabbur-12, and claim-gate QA.',
|
|
2696
|
+
'MULTI-LENS': 'Receipt is shaped for owner trust, operator usability, engineering proof, attacker resistance, and future maintenance.',
|
|
2697
|
+
PATTERN: 'Hook and ledger failures recur when helper success is mistaken for surface success; exact receipt rows and negative probes expose that pattern.',
|
|
2698
|
+
CONSEQUENCE: 'False closeout pollutes ledgers, runtime state, and downstream agent memory, teaching the wrong completion boundary to future sessions.',
|
|
2699
|
+
DWELLING: 'Low-risk misses should create repair evidence and scoped claim downgrades in the receipt instead of arbitrary blocks or silent pass language.',
|
|
2700
|
+
COLLAPSE: 'Autofire writes a receipt every phase close, resolves evidence anchors, and lets claim scope follow backend/user-surface proof.',
|
|
2701
|
+
PRINCIPLE: 'No completion claim may exceed forced QA evidence, command exits, runtime receipts, or ledger artifacts recorded for the phase.',
|
|
2702
|
+
INVERSION: 'If the agent can skip this suite or pass templated rows, QA is advisory ceremony rather than a forced runtime mechanism.',
|
|
2703
|
+
PERSONAL: 'This workspace needs automatic QA receipts because long agent chains forget manual checklists and owner trust depends on replayable artifacts.',
|
|
2704
|
+
VOICE: 'Report verified, partial, or blocked from the receipt verdict only, naming the evidence path or command metric that supports the claim.',
|
|
2705
|
+
};
|
|
2706
|
+
return END_OF_PHASE_QA_TADABBUR_12.map((stage) => ({
|
|
2707
|
+
stage,
|
|
2708
|
+
verdict: 'ok',
|
|
2709
|
+
finding: findings[stage],
|
|
2710
|
+
evidence_anchor: stage === 'VOICE' ? 'ev_user_surface' : 'ev_cognitive_schema',
|
|
2711
|
+
}));
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
function endPhaseSubstantiveQaGaps(receipt) {
|
|
2715
|
+
const evidence = new Set((Array.isArray(receipt.evidence) ? receipt.evidence : [])
|
|
2716
|
+
.map((entry) => typeof entry.id === 'string' ? entry.id : '')
|
|
2717
|
+
.filter(Boolean));
|
|
2718
|
+
const gaps = [];
|
|
2719
|
+
for (const [kind, rows, labelKey] of [
|
|
2720
|
+
['qiyas', Array.isArray(receipt.qiyas_15_pass) ? receipt.qiyas_15_pass : [], 'perspective'],
|
|
2721
|
+
['tadabbur', Array.isArray(receipt.tadabbur_12_pass) ? receipt.tadabbur_12_pass : [], 'stage'],
|
|
2722
|
+
]) {
|
|
2723
|
+
rows.forEach((row, index) => {
|
|
2724
|
+
const label = typeof row?.[labelKey] === 'string' ? row[labelKey] : `${kind}[${index}]`;
|
|
2725
|
+
const finding = typeof row?.finding === 'string' ? row.finding.trim() : '';
|
|
2726
|
+
const anchor = typeof row?.evidence_anchor === 'string' ? row.evidence_anchor.trim() : '';
|
|
2727
|
+
if (finding.length < SUBSTANTIVE_QA_MIN_FINDING_CHARS) gaps.push(`${kind}.${label}: finding too short for substantive QA`);
|
|
2728
|
+
if (SUBSTANTIVE_QA_GENERIC_FINDING_RX.test(finding)) gaps.push(`${kind}.${label}: finding is templated`);
|
|
2729
|
+
if (!SUBSTANTIVE_QA_CONCRETE_ANCHOR_RX.test(finding)) gaps.push(`${kind}.${label}: finding lacks concrete artifact/runtime/ledger language`);
|
|
2730
|
+
if (!anchor || !evidence.has(anchor)) gaps.push(`${kind}.${label}: evidence anchor missing or unresolved`);
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
return gaps;
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
function applyEndPhaseSubstantiveQaRequirement(receipt) {
|
|
2737
|
+
const gaps = endPhaseSubstantiveQaGaps(receipt);
|
|
2738
|
+
const passed = gaps.length === 0;
|
|
2739
|
+
receipt.evidence = Array.isArray(receipt.evidence) ? receipt.evidence : [];
|
|
2740
|
+
receipt.evidence.push(endPhaseQaEvidence(
|
|
2741
|
+
'ev_substantive_qa',
|
|
2742
|
+
'substantive_cognitive_qa',
|
|
2743
|
+
passed,
|
|
2744
|
+
passed ? 'Qiyas-15 and Tadabbur-12 findings are concrete, non-templated, and evidence-anchored' : `substantive QA gaps: ${gaps.join('; ')}`,
|
|
2745
|
+
{ gaps },
|
|
2746
|
+
));
|
|
2747
|
+
receipt.substantive_qa = {
|
|
2748
|
+
status: passed ? 'pass' : 'partial',
|
|
2749
|
+
min_finding_chars: SUBSTANTIVE_QA_MIN_FINDING_CHARS,
|
|
2750
|
+
generic_finding_rejected: true,
|
|
2751
|
+
gaps,
|
|
2752
|
+
evidence_ids: ['ev_substantive_qa'],
|
|
2753
|
+
};
|
|
2754
|
+
for (const gateName of ['cognitive_qiyas_15', 'cognitive_tadabbur_12']) {
|
|
2755
|
+
if (Array.isArray(receipt[gateName]?.evidence_ids)) receipt[gateName].evidence_ids.push('ev_substantive_qa');
|
|
2756
|
+
if (!passed && receipt[gateName]) receipt[gateName].status = 'partial';
|
|
2757
|
+
}
|
|
2758
|
+
if (!passed && receipt.claim_gate) receipt.claim_gate.verdict = 'partial';
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
const END_PHASE_COMPLETION_CLAIM_RX = /\b(?:done|complete|completed|ready|verified|fixed|shipped|production-ready|production ready)\b/i;
|
|
2762
|
+
|
|
2763
|
+
function evaluateEndPhaseClaim({ text = '', backendPassed = true, hardBlock = false } = {}) {
|
|
2764
|
+
const completionClaim = END_PHASE_COMPLETION_CLAIM_RX.test(String(text || ''));
|
|
2765
|
+
if (hardBlock) return { verdict: 'blocked', completionClaim };
|
|
2766
|
+
if (completionClaim && !backendPassed) return { verdict: 'partial', completionClaim };
|
|
2767
|
+
if (!backendPassed) return { verdict: 'verified_narrowly', completionClaim };
|
|
2768
|
+
return { verdict: 'verified', completionClaim };
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
function buildEndPhaseBoundedRecoveryText({ backendPassed, userSurfacePassed, source } = {}) {
|
|
2772
|
+
return [
|
|
2773
|
+
'QA recovery status: bounded evidence report.',
|
|
2774
|
+
`source: ${source || 'end-of-phase-qa-autofire'}`,
|
|
2775
|
+
`backend_e2e: ${backendPassed ? 'pass' : 'partial'}`,
|
|
2776
|
+
`user_facing_e2e: ${userSurfacePassed ? 'pass' : 'partial'}`,
|
|
2777
|
+
'claim_scope: no broad closeout claim is asserted after recovery.',
|
|
2778
|
+
'next_action: preserve evidence scope and continue only within the recorded receipt verdict.',
|
|
2779
|
+
].join('\n');
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
export function runEndOfPhaseQaAutofire({
|
|
2783
|
+
sessionId = 'unknown',
|
|
2784
|
+
phase = 'phase_close',
|
|
2785
|
+
trigger = 'phase_close',
|
|
2786
|
+
text = '',
|
|
2787
|
+
qaKernel = null,
|
|
2788
|
+
validation = null,
|
|
2789
|
+
postReceipt = null,
|
|
2790
|
+
outputRef = null,
|
|
2791
|
+
toolRefs = [],
|
|
2792
|
+
ledger = null,
|
|
2793
|
+
source = 'end-of-phase-qa-autofire',
|
|
2794
|
+
autoRecoverPartial = true,
|
|
2795
|
+
} = {}) {
|
|
2796
|
+
const negativeProbe = validateEndPhaseQaNegativeProbe();
|
|
2797
|
+
const backendPassed = validation?.pass !== false && validation?.validation?.passed !== false && validation?.layer3?.pass !== false && qaKernel?.ok !== false;
|
|
2798
|
+
const userSurfacePassed = typeof text === 'string' && text.trim().length > 0;
|
|
2799
|
+
const initialClaim = evaluateEndPhaseClaim({ text, backendPassed, hardBlock: qaKernel?.hardBlock === true });
|
|
2800
|
+
const autoRecovery = autoRecoverPartial && initialClaim.verdict === 'partial'
|
|
2801
|
+
? {
|
|
2802
|
+
attempted: true,
|
|
2803
|
+
mode: 'bounded_claim_rewrite_and_rerun',
|
|
2804
|
+
reason: 'completion claim exceeded available backend evidence',
|
|
2805
|
+
initial_verdict: initialClaim.verdict,
|
|
2806
|
+
recovered_text: buildEndPhaseBoundedRecoveryText({ backendPassed, userSurfacePassed, source }),
|
|
2807
|
+
}
|
|
2808
|
+
: null;
|
|
2809
|
+
const claim = autoRecovery
|
|
2810
|
+
? evaluateEndPhaseClaim({ text: autoRecovery.recovered_text, backendPassed, hardBlock: false })
|
|
2811
|
+
: initialClaim;
|
|
2812
|
+
const evidence = [
|
|
2813
|
+
endPhaseQaEvidence('ev_backend', 'runtime_probe', backendPassed, backendPassed ? 'runtime validation evidence available or not failed' : 'runtime validation failed', validation || qaKernel || null),
|
|
2814
|
+
endPhaseQaEvidence('ev_user_surface', 'user_surface', userSurfacePassed, userSurfacePassed ? 'assistant/user-facing output text present' : 'assistant/user-facing output text missing', { textLength: String(text || '').length, outputRef }),
|
|
2815
|
+
endPhaseQaEvidence('ev_failure_mode', 'negative_probe', negativeProbe.passed, negativeProbe.observed, negativeProbe),
|
|
2816
|
+
endPhaseQaEvidence('ev_cognitive_schema', 'cognitive_schema_validator', true, 'full Qiyas-15 and Tadabbur-12 exact lists generated', { qiyas: END_OF_PHASE_QA_QIYAS_15, tadabbur: END_OF_PHASE_QA_TADABBUR_12 }),
|
|
2817
|
+
endPhaseQaEvidence('ev_claim_gate', 'claim_gate', claim.verdict === 'verified' || claim.verdict === 'verified_narrowly', `claim gate verdict: ${claim.verdict}`, { claim, initialClaim, qaKernel }),
|
|
2818
|
+
];
|
|
2819
|
+
if (autoRecovery) {
|
|
2820
|
+
evidence.push(endPhaseQaEvidence('ev_auto_recovery', 'claim_recovery', true, 'partial completion claim auto-recovered by bounded status rewrite and QA rerun', {
|
|
2821
|
+
initialVerdict: autoRecovery.initial_verdict,
|
|
2822
|
+
finalVerdict: claim.verdict,
|
|
2823
|
+
recoveredTextHash: endPhaseQaHash(autoRecovery.recovered_text),
|
|
2824
|
+
}));
|
|
2825
|
+
}
|
|
2826
|
+
const receipt = {
|
|
2827
|
+
schema: 'aria.end_of_phase_qa_court.v1',
|
|
2828
|
+
phase_id: phase,
|
|
2829
|
+
generated_at: new Date().toISOString(),
|
|
2830
|
+
generated_by: 'deterministic_runner',
|
|
2831
|
+
source,
|
|
2832
|
+
session_id: sessionId,
|
|
2833
|
+
autofire: {
|
|
2834
|
+
mode: 'forced_end_of_phase_qa',
|
|
2835
|
+
trigger,
|
|
2836
|
+
suites: [...END_OF_PHASE_QA_SUITES],
|
|
2837
|
+
hard_stop_only_for: [...END_OF_PHASE_QA_HARD_STOP_ONLY_FOR],
|
|
2838
|
+
low_risk_policy: 'repair_or_downgrade_claim_without_arbitrary_block',
|
|
2839
|
+
auto_recovery_policy: 'one_bounded_rewrite_then_rerun_for_partial_claims',
|
|
2840
|
+
},
|
|
2841
|
+
backend_e2e: { status: backendPassed ? 'pass' : 'partial', evidence_ids: ['ev_backend'] },
|
|
2842
|
+
user_facing_e2e: { status: userSurfacePassed ? 'pass' : 'partial', evidence_ids: ['ev_user_surface'] },
|
|
2843
|
+
failure_modes: { status: negativeProbe.passed ? 'pass' : 'partial', evidence_ids: ['ev_failure_mode'] },
|
|
2844
|
+
cognitive_qiyas_15: { status: 'pass', perspectives: END_OF_PHASE_QA_QIYAS_15.length, evidence_ids: ['ev_cognitive_schema'] },
|
|
2845
|
+
cognitive_tadabbur_12: { status: 'pass', stages: END_OF_PHASE_QA_TADABBUR_12.length, evidence_ids: ['ev_cognitive_schema'] },
|
|
2846
|
+
qiyas_15_pass: endPhaseQiyasPass(),
|
|
2847
|
+
tadabbur_12_pass: endPhaseTadabburPass(),
|
|
2848
|
+
claim_gate: {
|
|
2849
|
+
verdict: claim.verdict,
|
|
2850
|
+
initial_verdict: initialClaim.verdict,
|
|
2851
|
+
completion_claim_detected: claim.completionClaim,
|
|
2852
|
+
claims: [
|
|
2853
|
+
{ claim: 'phase-close QA autofired', status: 'verified', evidence_ids: ['ev_cognitive_schema', 'ev_failure_mode'] },
|
|
2854
|
+
{ claim: 'backend phase-close evidence was checked', status: backendPassed ? 'verified' : 'partial', evidence_ids: ['ev_backend'] },
|
|
2855
|
+
{ claim: 'user-facing output was checked', status: userSurfacePassed ? 'verified' : 'partial', evidence_ids: ['ev_user_surface'] },
|
|
2856
|
+
...(autoRecovery ? [{ claim: 'partial completion claim auto-recovered before closeout', status: 'verified', evidence_ids: ['ev_auto_recovery', 'ev_claim_gate'] }] : []),
|
|
2857
|
+
],
|
|
2858
|
+
},
|
|
2859
|
+
auto_recovery: autoRecovery ? {
|
|
2860
|
+
attempted: true,
|
|
2861
|
+
mode: autoRecovery.mode,
|
|
2862
|
+
reason: autoRecovery.reason,
|
|
2863
|
+
initial_verdict: autoRecovery.initial_verdict,
|
|
2864
|
+
final_verdict: claim.verdict,
|
|
2865
|
+
recovered_text_hash: endPhaseQaHash(autoRecovery.recovered_text),
|
|
2866
|
+
} : { attempted: false },
|
|
2867
|
+
evidence,
|
|
2868
|
+
linkedEvidence: {
|
|
2869
|
+
outputRef,
|
|
2870
|
+
toolRefs,
|
|
2871
|
+
postReceiptId: postReceipt?.receiptId || null,
|
|
2872
|
+
taskProjectLedgerId: ledger?.ledgerId || null,
|
|
2873
|
+
},
|
|
2874
|
+
};
|
|
2875
|
+
applyEndPhaseSubstantiveQaRequirement(receipt);
|
|
2876
|
+
receipt.receipt_hash = endPhaseQaHash(receipt);
|
|
2877
|
+
const stateDir = path.join(HOME, '.aria', 'runtime', 'state');
|
|
2878
|
+
mkdirSync(stateDir, { recursive: true, mode: 0o755 });
|
|
2879
|
+
const latestPath = path.join(stateDir, 'end-of-phase-qa-court-latest.json');
|
|
2880
|
+
const eventPath = path.join(stateDir, 'end-of-phase-qa-court.jsonl');
|
|
2881
|
+
writeFileSync(latestPath, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600 });
|
|
2882
|
+
appendFileSync(eventPath, `${JSON.stringify({
|
|
2883
|
+
schema: 'aria.end_of_phase_qa_court.v1.event',
|
|
2884
|
+
at: receipt.generated_at,
|
|
2885
|
+
phase_id: receipt.phase_id,
|
|
2886
|
+
session_id: sessionId,
|
|
2887
|
+
trigger,
|
|
2888
|
+
verdict: claim.verdict,
|
|
2889
|
+
receipt_hash: receipt.receipt_hash,
|
|
2890
|
+
latest_path: latestPath,
|
|
2891
|
+
})}\n`, { mode: 0o600 });
|
|
2892
|
+
return { ok: true, receipt, latestPath, eventPath };
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
export const UNIVERSAL_CONNECTOR_ACTUAL_GOAL =
|
|
2896
|
+
'Wire extracted books, doctrines, skills, runtimes, primitives, mappings, CLIs, connectors, hooks, sidecars, and agent surfaces into the operating system so agent output improves automatically.';
|
|
2897
|
+
|
|
2898
|
+
export const UNIVERSAL_CONNECTOR_HIGH_IMPACT_SKILLS = Object.freeze([
|
|
2899
|
+
'ghazali-tauba-kca-repair-contract',
|
|
2900
|
+
'ghazali-rights-before-balance-settlement',
|
|
2901
|
+
'ghazali-delay-is-risk-auditor',
|
|
2902
|
+
'ghazali-knowledge-condition-action-patience-bridge',
|
|
2903
|
+
'ghazali-cause-means-tawakkal-mizan',
|
|
2904
|
+
'ghazali-ultimate-cause-chain-tracer',
|
|
2905
|
+
'ghazali-necessity-vs-attachment-mizan',
|
|
2906
|
+
'ghazali-attachment-not-possession-auditor',
|
|
2907
|
+
'ghazali-acquaintance-before-love-diagnoser',
|
|
2908
|
+
'ghazali-love-cup-attachment-displacement-auditor',
|
|
2909
|
+
'ghazali-knowledge-will-strength-action-chain',
|
|
2910
|
+
'ghazali-means-do-not-cleanse-end-gate',
|
|
2911
|
+
'ghazali-six-register-truthfulness-audit',
|
|
2912
|
+
'ghazali-breath-capital-day-contract',
|
|
2913
|
+
'ghazali-two-premise-action-transduction',
|
|
2914
|
+
'ghazali-four-object-thought-ledger',
|
|
2915
|
+
'ghazali-one-vice-one-replacement-register',
|
|
2916
|
+
'ghazali-bounded-sign-observation',
|
|
2917
|
+
'ghazali-three-question-intention-gate',
|
|
2918
|
+
'ghazali-principal-profit-loss-muhasabah',
|
|
2919
|
+
'ghazali-self-rebuke-false-narrative-interrogator',
|
|
2920
|
+
'ghazali-death-remembrance-deception-breaker',
|
|
2921
|
+
'ghazali-condition-specific-hope-fear-medicine',
|
|
2922
|
+
'ghazali-fear-action-not-paralysis-gate',
|
|
2923
|
+
'ghazali-hope-requires-cultivation-auditor',
|
|
2924
|
+
]);
|
|
2925
|
+
|
|
2926
|
+
export const UNIVERSAL_CONNECTOR_REQUIRED_RUNTIMES = Object.freeze([
|
|
2927
|
+
'tafakkur-transduction-runtime',
|
|
2928
|
+
'six-stage-self-accounting-runtime',
|
|
2929
|
+
'mortality-accounting-runtime',
|
|
2930
|
+
'fear-hope-condition-regulation-runtime',
|
|
2931
|
+
'intention-to-action-integrity-runtime',
|
|
2932
|
+
'love-fruit-contentment-runtime',
|
|
2933
|
+
'patience-gratitude-purpose-mizan-runtime',
|
|
2934
|
+
'tauba-rights-repair-runtime',
|
|
2935
|
+
'tawakkal-cause-mizan-runtime',
|
|
2936
|
+
'zuhd-necessity-attachment-runtime',
|
|
2937
|
+
]);
|
|
2938
|
+
|
|
2939
|
+
function includesAny(text = '', terms = []) {
|
|
2940
|
+
const source = String(text || '').toLowerCase();
|
|
2941
|
+
return terms.some((term) => source.includes(String(term).toLowerCase()));
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
function countIncluded(text = '', terms = []) {
|
|
2945
|
+
const source = String(text || '').toLowerCase();
|
|
2946
|
+
return terms.reduce((count, term) => count + (source.includes(String(term).toLowerCase()) ? 1 : 0), 0);
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
function continuationRequested(text = '') {
|
|
2950
|
+
return includesAny(text, [
|
|
2951
|
+
'continue',
|
|
2952
|
+
'next phase',
|
|
2953
|
+
'next step',
|
|
2954
|
+
'next best',
|
|
2955
|
+
'fire',
|
|
2956
|
+
'skills',
|
|
2957
|
+
'production',
|
|
2958
|
+
'ready',
|
|
2959
|
+
'what is left',
|
|
2960
|
+
"what's left",
|
|
2961
|
+
'how far',
|
|
2962
|
+
'qa',
|
|
2963
|
+
'ledger',
|
|
2964
|
+
'autofire',
|
|
2965
|
+
'wire',
|
|
2966
|
+
]);
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
function actualGoalHits(text = '') {
|
|
2970
|
+
return countIncluded(text, [
|
|
2971
|
+
'wire extracted',
|
|
2972
|
+
'books',
|
|
2973
|
+
'doctrines',
|
|
2974
|
+
'skills',
|
|
2975
|
+
'runtimes',
|
|
2976
|
+
'primitives',
|
|
2977
|
+
'mappings',
|
|
2978
|
+
'connectors',
|
|
2979
|
+
'hooks',
|
|
2980
|
+
'sidecars',
|
|
2981
|
+
'agent surfaces',
|
|
2982
|
+
'output improves automatically',
|
|
2983
|
+
'corpus',
|
|
2984
|
+
'forced-selection',
|
|
2985
|
+
'actual goal',
|
|
2986
|
+
]);
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
function supportMechanismHits(text = '') {
|
|
2990
|
+
return countIncluded(text, ['receipt', 'gate', 'ledger', 'canary', 'drift check', 'phase ']);
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
export function buildUniversalConnectorGoalContract({ userText = '', phase = 'turn' } = {}) {
|
|
2994
|
+
return {
|
|
2995
|
+
id: 'universal-connector-corpus-runtime-goal-contract',
|
|
2996
|
+
phase,
|
|
2997
|
+
actualGoal: UNIVERSAL_CONNECTOR_ACTUAL_GOAL,
|
|
2998
|
+
supportRule: 'Receipts, gates, ledgers, and canaries are support evidence only; they pass when they prove corpus-backed behavior changed action, QA, correction, verification, or learning.',
|
|
2999
|
+
hardStopOnlyFor: ['secrets', 'destructive actions', 'deploy/publication boundary', 'owner-contradicted action', 'proven false completion risk'],
|
|
3000
|
+
qaPacket: {
|
|
3001
|
+
qiyas: 'Qiyas-15 over owner trust, operator value, engineering quality, cognitive load, scale, compliance, red-team, one-week future, and one-year future.',
|
|
3002
|
+
tadabbur: 'Full consequence trace from current action to production behavior; reject motion that only improves receipts.',
|
|
3003
|
+
mizan: 'Balance evidence, owner impact, throughput, and false-completion risk; repair low-risk misses before hard-blocking.',
|
|
3004
|
+
ghazali8: 'Nur observed substrate, Mizan proportion, Hikma doctrine, Tafakkur structure, Tadabbur consequence, Ilham sensed drift, Wahi owner/corpus anchor, Firasah owner need.',
|
|
3005
|
+
fitrah: 'Truth over deception, no harm, sacred trust, power obligates service, reflection before action.',
|
|
3006
|
+
},
|
|
3007
|
+
selectedSkills: [...UNIVERSAL_CONNECTOR_HIGH_IMPACT_SKILLS],
|
|
3008
|
+
selectedRuntimes: [...UNIVERSAL_CONNECTOR_REQUIRED_RUNTIMES],
|
|
3009
|
+
nextHighestImpactAction: 'Promote the sandbox corpus registry consumer into the real connector/hook forced-selection path, then run behavioral QA on actual Claude/Codex/OpenCode continuation prompts.',
|
|
3010
|
+
continuation: continuationRequested(userText),
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
export function evaluateGoalContractOutput(text = '', { userText = '', goalContract = null } = {}) {
|
|
3015
|
+
const source = String(text || '');
|
|
3016
|
+
const contract = goalContract || buildUniversalConnectorGoalContract({ userText, phase: 'stop' });
|
|
3017
|
+
const continuation = contract.continuation || continuationRequested(userText) || actualGoalHits(userText) > 0;
|
|
3018
|
+
const blockers = [];
|
|
3019
|
+
const warnings = [];
|
|
3020
|
+
const repairs = [];
|
|
3021
|
+
|
|
3022
|
+
// ── UNCONDITIONAL false-completion check (uses shared extractEmitAttrs) ──
|
|
3023
|
+
// Sycophancy / false-completion claims are doctrine violations regardless
|
|
3024
|
+
// of continuation status. Three guards: self-claim shape AND absence of
|
|
3025
|
+
// observation/evidence vocab AND NOT in code context. Detection comes
|
|
3026
|
+
// from the shared module-level regexes (one source of truth).
|
|
3027
|
+
const goalAttrs = extractEmitAttrs(source, { continuationRequested: continuation === true });
|
|
3028
|
+
if (
|
|
3029
|
+
goalAttrs.hasCompletionLang
|
|
3030
|
+
&& !OUTPUT_OBSERVATION_EVIDENCE_RX.test(source)
|
|
3031
|
+
) {
|
|
3032
|
+
blockers.push('goal-contract: false completion or readiness claim without bounded evidence (unconditional)');
|
|
3033
|
+
}
|
|
3034
|
+
// ── UNCONDITIONAL kernel adapter (ARIA_KERNEL_QA_MODE) ───────────────
|
|
3035
|
+
// Kernel-driven detection of claim_without_evidence / sycophancy_shape /
|
|
3036
|
+
// restatement_no_advance runs regardless of continuation. Only the
|
|
3037
|
+
// mechanism_description_only class is continuation-gated (per kernel
|
|
3038
|
+
// semantics) and runs in the original block below.
|
|
3039
|
+
let unconditionalKernelVerdict = null;
|
|
3040
|
+
if (ARIA_KERNEL_QA_MODE_ENABLED) {
|
|
3041
|
+
try {
|
|
3042
|
+
unconditionalKernelVerdict = evaluateWithKernel({
|
|
3043
|
+
surface: 'codex-native-goal-contract-unconditional',
|
|
3044
|
+
phase: 'stop',
|
|
3045
|
+
observation: {
|
|
3046
|
+
kind: 'output_emit',
|
|
3047
|
+
source: 'codex-native-stop-emit',
|
|
3048
|
+
severity: 'low',
|
|
3049
|
+
summary: source.slice(0, 1000),
|
|
3050
|
+
// Unconditional path — force continuationRequested=false so the
|
|
3051
|
+
// mechanism_description_only kernel class doesn't apply here.
|
|
3052
|
+
attrs: { ...extractEmitAttrs(source, { continuationRequested: false }) },
|
|
3053
|
+
},
|
|
3054
|
+
evidence: [],
|
|
3055
|
+
predicate: 'output_carries_bounded_evidence_for_any_completion_claim',
|
|
3056
|
+
});
|
|
3057
|
+
const cls = unconditionalKernelVerdict?.classification?.action_class;
|
|
3058
|
+
const dec = unconditionalKernelVerdict?.decision;
|
|
3059
|
+
// When kernel-mode is on, the kernel is authoritative. Always remove
|
|
3060
|
+
// the regex unconditional blocker (kernel decides for itself).
|
|
3061
|
+
const filtered = blockers.filter((b) => !b.startsWith('goal-contract: false completion or readiness claim'));
|
|
3062
|
+
blockers.length = 0;
|
|
3063
|
+
blockers.push(...filtered);
|
|
3064
|
+
// Then push kernel's verdict if it's a hard-block (force_reauthor / block).
|
|
3065
|
+
if (cls && OUTPUT_EMIT_FAILURE_CLASSES.includes(cls)
|
|
3066
|
+
&& (dec === 'force_reauthor' || dec === 'block')) {
|
|
3067
|
+
blockers.push(`goal-contract (kernel ${cls}): ${unconditionalKernelVerdict.recoveryDirective}`);
|
|
3068
|
+
}
|
|
3069
|
+
// If kernel said allow/observe_only, no blocker — regex false-positives are dropped.
|
|
3070
|
+
} catch (err) {
|
|
3071
|
+
warnings.push(`goal-contract: unconditional kernel adapter failed (${err?.message ?? err})`);
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
// Continuation-only checks (goal-advancement, next-action-named,
|
|
3076
|
+
// QA-loop-present, mechanism_description_only) only fire when the user
|
|
3077
|
+
// requested continuation. False-completion is NOT one of these.
|
|
3078
|
+
if (!continuation) return { pass: blockers.length === 0, hardBlock: blockers.length > 0, score: blockers.length === 0 ? 1 : 0.4, blockers, warnings, repairs, contract };
|
|
3079
|
+
const goalHits = actualGoalHits(source);
|
|
3080
|
+
const supportHits = supportMechanismHits(source);
|
|
3081
|
+
const hasEvidence = includesAny(source, ['verified', 'observed', 'evidence', 'smoke', 'test', 'audit', 'not production-ready', 'integration-ready', 'blocked', 'pending', 'unverified']);
|
|
3082
|
+
const hasNextAction = includesAny(source, ['next highest', 'next best', 'next action', 'next step', 'continue by', 'promote the sandbox corpus', 'wire the registry', 'forced-selection']);
|
|
3083
|
+
const hasQa = includesAny(source, ['qa', 'qiyas', 'tadabbur', 'mizan', 'ghazali', 'correct', 'enhance', 'harden', 'repair']);
|
|
3084
|
+
if (goalHits === 0) {
|
|
3085
|
+
warnings.push('goal-contract: output does not bind the turn to corpus-to-runtime wiring or automatic output improvement');
|
|
3086
|
+
repairs.push('Name the actual goal or make the current action directly advance corpus registry, runtime, hook, connector, surface, or forced-selection wiring.');
|
|
3087
|
+
}
|
|
3088
|
+
if (!hasNextAction) {
|
|
3089
|
+
warnings.push('goal-contract: continuation output does not name the next highest-impact action');
|
|
3090
|
+
repairs.push('Add a concrete next action that advances real wiring or behavioral QA.');
|
|
3091
|
+
}
|
|
3092
|
+
if (!hasQa) {
|
|
3093
|
+
warnings.push('goal-contract: QA/correction loop is missing from the visible state');
|
|
3094
|
+
repairs.push('Add expected-vs-observed QA with correction, enhancement, hardening, or an explicit pass boundary.');
|
|
3095
|
+
}
|
|
3096
|
+
if (!hasEvidence) {
|
|
3097
|
+
warnings.push('goal-contract: evidence boundary is missing');
|
|
3098
|
+
repairs.push('State verified, blocked, pending, unverified, or the exact evidence class used before making status claims.');
|
|
3099
|
+
}
|
|
3100
|
+
if (supportHits >= 3 && supportHits > goalHits + 1) {
|
|
3101
|
+
warnings.push('goal-contract: support mechanisms dominate the answer over the actual product goal');
|
|
3102
|
+
repairs.push('Reframe receipts, gates, ledgers, and canaries as evidence only, then return to corpus-to-runtime wiring and output improvement.');
|
|
3103
|
+
}
|
|
3104
|
+
if (/\bwhat would you like me to do next\b|\bhow would you like me to proceed\b/i.test(source)) {
|
|
3105
|
+
blockers.push('goal-contract: output asks the owner to choose the obvious continuation instead of naming the next highest-impact step');
|
|
3106
|
+
}
|
|
3107
|
+
// False-completion is handled UNCONDITIONALLY at the top of this
|
|
3108
|
+
// function (above the continuation gate), using shared extractEmitAttrs.
|
|
3109
|
+
// The duplicate in-continuation check + alias were removed in the
|
|
3110
|
+
// 2026-05-17 consolidation when the kernel adapter switched to the
|
|
3111
|
+
// shared helper.
|
|
3112
|
+
if (/\b(?:\/consult|consult api|consult response)\b/i.test(source) && /\b(?:quality source|core quality|dependency|required)\b/i.test(source)) {
|
|
3113
|
+
blockers.push('goal-contract: consult API is being treated as the core quality engine');
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
// ── Kernel-mode authoritative hardBlock (ARIA_KERNEL_QA_MODE=1) ──────
|
|
3117
|
+
// When kernel mode is on, the atlas deterministic cognitive kernel is
|
|
3118
|
+
// the authoritative decision engine for false-completion classification.
|
|
3119
|
+
// The regex blockers above become advisory warnings; only the kernel
|
|
3120
|
+
// can produce a hardBlock. This swaps the gate from coarse regex to
|
|
3121
|
+
// structured-attr classification (cognition_mutated_output + source_trust
|
|
3122
|
+
// + action_class). Paraphrase-robust and class-specific recovery prose.
|
|
3123
|
+
let kernelVerdict = null;
|
|
3124
|
+
if (ARIA_KERNEL_QA_MODE_ENABLED) {
|
|
3125
|
+
try {
|
|
3126
|
+
// Uses shared extractEmitAttrs (single source of truth for all
|
|
3127
|
+
// output-emit attrs). continuationRequested is true here so the
|
|
3128
|
+
// kernel can fire mechanism_description_only if applicable.
|
|
3129
|
+
kernelVerdict = evaluateWithKernel({
|
|
3130
|
+
surface: 'codex-native-goal-contract',
|
|
3131
|
+
phase: 'stop_goal_contract',
|
|
3132
|
+
observation: {
|
|
3133
|
+
kind: 'goal_contract_eval',
|
|
3134
|
+
source: 'codex-native-output-vs-prompt',
|
|
3135
|
+
severity: 'low',
|
|
3136
|
+
summary: source.slice(0, 1000),
|
|
3137
|
+
attrs: { ...extractEmitAttrs(source, { continuationRequested: continuation === true }) },
|
|
3138
|
+
},
|
|
3139
|
+
evidence: [],
|
|
3140
|
+
predicate: 'output_advances_user_goal_with_bounded_evidence',
|
|
3141
|
+
});
|
|
3142
|
+
// Re-derive blockers from kernel verdict (drop regex-only false-positives)
|
|
3143
|
+
const isFailureClass = kernelVerdict?.classification?.action_class
|
|
3144
|
+
&& OUTPUT_EMIT_FAILURE_CLASSES.includes(kernelVerdict.classification.action_class);
|
|
3145
|
+
const isHardBlock = kernelVerdict?.decision === 'force_reauthor'
|
|
3146
|
+
|| kernelVerdict?.decision === 'block'
|
|
3147
|
+
|| isFailureClass;
|
|
3148
|
+
// Filter out the regex false-completion blocker — it's now the kernel's call
|
|
3149
|
+
const regexBlockersToDrop = ['goal-contract: false completion or readiness claim without bounded evidence'];
|
|
3150
|
+
const filteredBlockers = blockers.filter((b) => !regexBlockersToDrop.includes(b));
|
|
3151
|
+
blockers.length = 0;
|
|
3152
|
+
blockers.push(...filteredBlockers);
|
|
3153
|
+
if (isHardBlock) {
|
|
3154
|
+
blockers.push(`goal-contract (kernel ${kernelVerdict.classification.action_class}): ${kernelVerdict.recoveryDirective}`);
|
|
3155
|
+
} else {
|
|
3156
|
+
// Kernel said allow / observe_only — kernel mode trusts that over regex
|
|
3157
|
+
warnings.push(`goal-contract: kernel verdict=${kernelVerdict?.decision || 'unknown'} action_class=${kernelVerdict?.classification?.action_class || 'unknown'} (regex blockers downgraded)`);
|
|
3158
|
+
}
|
|
3159
|
+
} catch (err) {
|
|
3160
|
+
// Kernel failure is non-blocking but LOUD per feedback_non_blocking_errors_unacceptable.md
|
|
3161
|
+
warnings.push(`goal-contract: kernel adapter failed (${err?.message ?? err}); falling back to regex layer`);
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
const score = [goalHits > 0, hasNextAction, hasQa, hasEvidence, !(supportHits >= 3 && supportHits > goalHits + 1), blockers.length === 0].filter(Boolean).length / 6;
|
|
3166
|
+
return {
|
|
3167
|
+
pass: blockers.length === 0 && score >= 0.67,
|
|
3168
|
+
hardBlock: blockers.length > 0,
|
|
3169
|
+
score,
|
|
3170
|
+
blockers: [...new Set(blockers)],
|
|
3171
|
+
warnings: [...new Set(warnings)],
|
|
3172
|
+
repairs: [...new Set(repairs)],
|
|
3173
|
+
nextHighestImpactAction: contract.nextHighestImpactAction,
|
|
3174
|
+
selectedSkills: contract.selectedSkills,
|
|
3175
|
+
selectedRuntimes: contract.selectedRuntimes,
|
|
3176
|
+
contract,
|
|
3177
|
+
};
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
export function inferRequiredAriaSkills(text = '') {
|
|
3181
|
+
const raw = String(text || '');
|
|
3182
|
+
const lower = raw.toLowerCase();
|
|
3183
|
+
const required = new Set(ARIA_ALWAYS_ON_SKILLS);
|
|
3184
|
+
const add = (skill) => required.add(skill);
|
|
3185
|
+
const mentions = (skill) => new RegExp('(?:^|[^a-z0-9_-])\\$?' + skill.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(?:$|[^a-z0-9_-])', 'i').test(raw);
|
|
3186
|
+
|
|
3187
|
+
for (const skill of [
|
|
3188
|
+
'aria-axioms-first-principles',
|
|
3189
|
+
'aria-cognition-autofire',
|
|
3190
|
+
'aria-first-class-operating-contract',
|
|
3191
|
+
'aria-cognition-batch',
|
|
3192
|
+
'aria-readable-output',
|
|
3193
|
+
'tadabbur',
|
|
3194
|
+
'qiyas-analogy',
|
|
3195
|
+
]) {
|
|
3196
|
+
if (mentions(skill)) add(skill);
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
if (/\b(?:aria|harness|garden|claude code|codex|opencode|skill|skills|hook|hooks|runtime|connector|sdk|gate|quality|qa|audit|completion claim)\b/i.test(raw)) {
|
|
3200
|
+
add('aria-cognition-autofire');
|
|
3201
|
+
add('aria-readable-output');
|
|
3202
|
+
}
|
|
3203
|
+
if (/\b(?:first class|first-class|world class|world-class|revolutionary upgrade|full upgrade|substrate os|not just a watcher|serious upgrade)\b/i.test(raw)) {
|
|
3204
|
+
add('aria-first-class-operating-contract');
|
|
3205
|
+
}
|
|
3206
|
+
if (/\b(?:axiom|axioms|first principles?|fitrah|source trust|evidence threshold)\b/i.test(raw)) {
|
|
3207
|
+
add('aria-axioms-first-principles');
|
|
3208
|
+
}
|
|
3209
|
+
if (/\b(?:full cognition|batch cognition|28\+15|mizan plus tadabbur|rich cognitives|cognitive batch)\b/i.test(raw)) {
|
|
3210
|
+
add('aria-cognition-batch');
|
|
3211
|
+
}
|
|
3212
|
+
if (/\b(?:tadabbur|taddabur|12-stage|heart filter|consequence reasoning|cookbook|deep reflection)\b/i.test(lower)) {
|
|
3213
|
+
add('tadabbur');
|
|
3214
|
+
}
|
|
3215
|
+
if (/\b(?:qiyas|analogy|analogical|qiyas-15|structural analogy|asl|hukm|illah|furuq)\b/i.test(lower)) {
|
|
3216
|
+
add('qiyas-analogy');
|
|
3217
|
+
}
|
|
3218
|
+
if (/\b(?:fire named skills|fire skills|use aria skills|named skills)\b/i.test(lower)) {
|
|
3219
|
+
add('aria-axioms-first-principles');
|
|
3220
|
+
add('aria-cognition-autofire');
|
|
3221
|
+
add('aria-cognition-batch');
|
|
3222
|
+
add('aria-readable-output');
|
|
3223
|
+
add('tadabbur');
|
|
3224
|
+
add('qiyas-analogy');
|
|
3225
|
+
}
|
|
3226
|
+
if (/\b(?:readable output|readability|owner surface|owner-facing|scannable|stop gate|closeout|final answer)\b/i.test(lower)) {
|
|
3227
|
+
add('aria-readable-output');
|
|
3228
|
+
}
|
|
3229
|
+
if (/\b(?:backend|api|server|database|auth|queue|worker|service)\b/i.test(lower)) {
|
|
3230
|
+
add('aria-backend-architect');
|
|
3231
|
+
}
|
|
3232
|
+
if (/\b(?:frontend|ui|ux|component|page|screen|css|layout)\b/i.test(lower)) {
|
|
3233
|
+
add('aria-frontend-architect');
|
|
3234
|
+
}
|
|
3235
|
+
if (/\b(?:fullstack|end-to-end|e2e|web app|application)\b/i.test(lower)) {
|
|
3236
|
+
add('aria-fullstack-orchestrator');
|
|
3237
|
+
}
|
|
3238
|
+
if (/\b(?:deploy|k8s|kubernetes|kubectl|cluster|infra|infrastructure|rollout)\b/i.test(lower)) {
|
|
3239
|
+
add('aria-live-ops');
|
|
3240
|
+
add('aria-k8s-deploy');
|
|
3241
|
+
}
|
|
3242
|
+
if (/\b(?:repo audit|repository audit|codebase audit|refactor|review)\b/i.test(lower)) {
|
|
3243
|
+
add('aria-repo-audit');
|
|
3244
|
+
}
|
|
3245
|
+
if (/\b(?:research|diligence|sources|market|competitor|public sources)\b/i.test(lower)) {
|
|
3246
|
+
add('aria-research-orchestrator');
|
|
3247
|
+
}
|
|
3248
|
+
if (/\b(?:business|pricing|gtm|go-to-market|revenue|retention|launch)\b/i.test(lower)) {
|
|
3249
|
+
add('aria-business-frame');
|
|
3250
|
+
add('aria-gtm-architect');
|
|
3251
|
+
}
|
|
3252
|
+
if (required.size > 0 && /\b(?:aria|harness|codex|claude|hook|gate|runtime|skill|cognition|coach)\b/i.test(raw)) {
|
|
3253
|
+
add('aria-readable-output');
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
return [...required].sort();
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
export function summarizeForcedSkillLoad(promptBuild = null) {
|
|
3260
|
+
if (!promptBuild || typeof promptBuild !== 'object') return null;
|
|
3261
|
+
const loadedCookbooks = Array.isArray(promptBuild.loadedCookbooks) ? promptBuild.loadedCookbooks : [];
|
|
3262
|
+
const missingCookbooks = Array.isArray(promptBuild.missingCookbooks) ? promptBuild.missingCookbooks : [];
|
|
3263
|
+
const receipt = promptBuild.skillExecutionReceipt && typeof promptBuild.skillExecutionReceipt === 'object'
|
|
3264
|
+
? promptBuild.skillExecutionReceipt
|
|
3265
|
+
: null;
|
|
3266
|
+
const substrateKernelExecution = receipt?.substrateKernelExecution && typeof receipt.substrateKernelExecution === 'object'
|
|
3267
|
+
? receipt.substrateKernelExecution
|
|
3268
|
+
: null;
|
|
3269
|
+
const executedSkillIds = Array.isArray(receipt?.executedSkillIds)
|
|
3270
|
+
? receipt.executedSkillIds
|
|
3271
|
+
: Array.isArray(substrateKernelExecution?.executedSkillIds)
|
|
3272
|
+
? substrateKernelExecution.executedSkillIds
|
|
3273
|
+
: [];
|
|
3274
|
+
const executedOperatorIds = Array.isArray(receipt?.executedOperatorIds)
|
|
3275
|
+
? receipt.executedOperatorIds
|
|
3276
|
+
: Array.isArray(substrateKernelExecution?.executedOperatorIds)
|
|
3277
|
+
? substrateKernelExecution.executedOperatorIds
|
|
3278
|
+
: [];
|
|
3279
|
+
return {
|
|
3280
|
+
ok: promptBuild.ok === true,
|
|
3281
|
+
requiredSkillIds: Array.isArray(promptBuild.requiredSkillIds) ? promptBuild.requiredSkillIds : [],
|
|
3282
|
+
loadedSkillIds: Array.isArray(promptBuild.loadedSkillIds) ? promptBuild.loadedSkillIds : [],
|
|
3283
|
+
missingSkillIds: Array.isArray(promptBuild.missingSkillIds) ? promptBuild.missingSkillIds : [],
|
|
3284
|
+
loadedSkillHashes: Array.isArray(promptBuild.loadedSkillHashes) ? promptBuild.loadedSkillHashes : [],
|
|
3285
|
+
loadedCookbooks: loadedCookbooks.map((entry) => ({
|
|
3286
|
+
skillId: entry.skillId || null,
|
|
3287
|
+
requestedBy: entry.requestedBy || null,
|
|
3288
|
+
cookbookName: entry.cookbookName || null,
|
|
3289
|
+
path: entry.path || null,
|
|
3290
|
+
hash: entry.hash || null,
|
|
3291
|
+
chars: entry.chars || null,
|
|
3292
|
+
})),
|
|
3293
|
+
missingCookbooks: missingCookbooks.map((entry) => ({
|
|
3294
|
+
skillId: entry.skillId || null,
|
|
3295
|
+
requestedBy: entry.requestedBy || null,
|
|
3296
|
+
cookbookName: entry.cookbookName || null,
|
|
3297
|
+
path: entry.path || null,
|
|
3298
|
+
})),
|
|
3299
|
+
skillExecutionMode: typeof promptBuild.skillExecutionMode === 'string' ? promptBuild.skillExecutionMode : null,
|
|
3300
|
+
activeRuntimes: Array.isArray(promptBuild.activeRuntimes) ? promptBuild.activeRuntimes : (Array.isArray(receipt?.activeRuntimes) ? receipt.activeRuntimes : []),
|
|
3301
|
+
activePrimitives: Array.isArray(promptBuild.activePrimitives) ? promptBuild.activePrimitives : (Array.isArray(receipt?.activePrimitives) ? receipt.activePrimitives : []),
|
|
3302
|
+
activeMappings: Array.isArray(promptBuild.activeMappings) ? promptBuild.activeMappings : (Array.isArray(receipt?.activeMappings) ? receipt.activeMappings : []),
|
|
3303
|
+
qaSkills: Array.isArray(promptBuild.qaSkills) ? promptBuild.qaSkills : (Array.isArray(receipt?.qaSkills) ? receipt.qaSkills : []),
|
|
3304
|
+
correctionSkills: Array.isArray(promptBuild.correctionSkills) ? promptBuild.correctionSkills : (Array.isArray(receipt?.correctionSkills) ? receipt.correctionSkills : []),
|
|
3305
|
+
doctrineRuntimeReceipt: promptBuild.doctrineRuntimeReceipt || receipt?.doctrineRuntimeReceipt || null,
|
|
3306
|
+
dynamicOperatorSelection: promptBuild.dynamicOperatorSelection || receipt?.dynamicOperatorSelection || null,
|
|
3307
|
+
substrateKernelExecution: promptBuild.substrateKernelExecution || substrateKernelExecution || null,
|
|
3308
|
+
phaseRuntimeExecution: promptBuild.phaseRuntimeExecution || receipt?.phaseRuntimeExecution || null,
|
|
3309
|
+
gardenMemorySubstrate: promptBuild.gardenMemorySubstrate || receipt?.gardenMemorySubstrate || null,
|
|
3310
|
+
cognitiveRuntimeReceipts: promptBuild.cognitiveRuntimeReceipts || receipt?.cognitiveRuntimeReceipts || null,
|
|
3311
|
+
qaCorrectionReceipt: promptBuild.qaCorrectionReceipt || receipt?.qaCorrectionReceipt || null,
|
|
3312
|
+
hiveObserverSourceTopology: promptBuild.hiveObserverSourceTopology || receipt?.hiveObserverSourceTopology || null,
|
|
3313
|
+
hiveSiblingSessionBroadcast: promptBuild.hiveSiblingSessionBroadcast || receipt?.hiveSiblingSessionBroadcast || null,
|
|
3314
|
+
ownerApprovalPacket: promptBuild.ownerApprovalPacket || receipt?.ownerApprovalPacket || null,
|
|
3315
|
+
skillExecutionReceipt: receipt
|
|
3316
|
+
? {
|
|
3317
|
+
ok: receipt.ok === true,
|
|
3318
|
+
mode: receipt.mode || null,
|
|
3319
|
+
firedSkillIds: executedSkillIds.length
|
|
3320
|
+
? executedSkillIds
|
|
3321
|
+
: Array.isArray(receipt.firedSkillIds) ? receipt.firedSkillIds : [],
|
|
3322
|
+
executedSkillIds,
|
|
3323
|
+
executedOperatorCount: executedOperatorIds.length,
|
|
3324
|
+
substrateKernelExecution: substrateKernelExecution
|
|
3325
|
+
? {
|
|
3326
|
+
ok: substrateKernelExecution.ok === true,
|
|
3327
|
+
mode: substrateKernelExecution.mode || null,
|
|
3328
|
+
executedOperatorIdsHash: substrateKernelExecution.executedOperatorIdsHash || null,
|
|
3329
|
+
executionHash: substrateKernelExecution.executionHash || null,
|
|
3330
|
+
}
|
|
3331
|
+
: null,
|
|
3332
|
+
receiptHash: receipt.receiptHash || null,
|
|
3333
|
+
}
|
|
3334
|
+
: null,
|
|
3335
|
+
promptSha256: promptBuild.prompt ? createHash('sha256').update(String(promptBuild.prompt)).digest('hex') : null,
|
|
3336
|
+
promptChars: promptBuild.prompt ? String(promptBuild.prompt).length : 0,
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
export function universalTurnPacketGaps({ requiredSkills = [], forcedSkillLoad = null, universalTurnPacket = false } = {}) {
|
|
3341
|
+
const required = Array.isArray(requiredSkills) ? requiredSkills : [];
|
|
3342
|
+
const summary = forcedSkillLoad || null;
|
|
3343
|
+
const requiresUniversal = universalTurnPacket === true
|
|
3344
|
+
|| summary?.universalTurnPacket === true
|
|
3345
|
+
|| ARIA_CODEX_UNIVERSAL_TURN_PACKET_SKILLS.every((skill) => required.includes(skill));
|
|
3346
|
+
if (!requiresUniversal) return [];
|
|
3347
|
+
if (!summary) return ['universal turn packet was required but no forced skill load summary exists'];
|
|
3348
|
+
const gaps = [];
|
|
3349
|
+
const count = (value) => Array.isArray(value) ? value.length : 0;
|
|
3350
|
+
const fired = summary.skillExecutionReceipt?.executedSkillIds?.length
|
|
3351
|
+
? summary.skillExecutionReceipt.executedSkillIds
|
|
3352
|
+
: summary.skillExecutionReceipt?.firedSkillIds || summary.loadedSkillIds || [];
|
|
3353
|
+
const missingUniversalSkills = ARIA_CODEX_UNIVERSAL_TURN_PACKET_SKILLS.filter((skill) => !fired.includes(skill));
|
|
3354
|
+
if (summary.skillExecutionMode !== 'mechanical-receipt') gaps.push('universal packet requires mechanical-receipt skill execution mode');
|
|
3355
|
+
if (missingUniversalSkills.length) gaps.push('universal packet missing canonical fired skills: ' + missingUniversalSkills.join(', '));
|
|
3356
|
+
if (summary.substrateKernelExecution?.ok !== true && summary.skillExecutionReceipt?.substrateKernelExecution?.ok !== true) {
|
|
3357
|
+
gaps.push('universal packet substrate kernel execution receipt missing or failed');
|
|
3358
|
+
}
|
|
3359
|
+
if (count(summary.activeRuntimes) < ARIA_CODEX_UNIVERSAL_RUNTIME_FLOOR) gaps.push(`universal runtime floor not met: ${count(summary.activeRuntimes)}/${ARIA_CODEX_UNIVERSAL_RUNTIME_FLOOR}`);
|
|
3360
|
+
if (count(summary.activePrimitives) < ARIA_CODEX_UNIVERSAL_PRIMITIVE_FLOOR) gaps.push(`universal primitive floor not met: ${count(summary.activePrimitives)}/${ARIA_CODEX_UNIVERSAL_PRIMITIVE_FLOOR}`);
|
|
3361
|
+
if (count(summary.activeMappings) < ARIA_CODEX_UNIVERSAL_MAPPING_FLOOR) gaps.push(`universal mapping floor not met: ${count(summary.activeMappings)}/${ARIA_CODEX_UNIVERSAL_MAPPING_FLOOR}`);
|
|
3362
|
+
if (count(summary.qaSkills) < ARIA_CODEX_UNIVERSAL_QA_SKILL_FLOOR) gaps.push(`universal QA skill floor not met: ${count(summary.qaSkills)}/${ARIA_CODEX_UNIVERSAL_QA_SKILL_FLOOR}`);
|
|
3363
|
+
if (count(summary.correctionSkills) < ARIA_CODEX_UNIVERSAL_CORRECTION_SKILL_FLOOR) gaps.push(`universal correction skill floor not met: ${count(summary.correctionSkills)}/${ARIA_CODEX_UNIVERSAL_CORRECTION_SKILL_FLOOR}`);
|
|
3364
|
+
if (summary.doctrineRuntimeReceipt?.ok !== true) gaps.push('universal packet doctrine runtime receipt missing or failed');
|
|
3365
|
+
if (summary.phaseRuntimeExecution?.ok !== true) gaps.push('universal packet phase runtime execution receipt missing or failed');
|
|
3366
|
+
if (summary.phaseRuntimeExecution?.providerReceivesFullSkillBodies !== false) gaps.push('universal packet provider projection is not compact mechanical receipt');
|
|
3367
|
+
if (summary.gardenMemorySubstrate?.ok !== true) gaps.push('universal packet garden memory substrate receipt missing or failed');
|
|
3368
|
+
if (summary.gardenMemorySubstrate?.providerProjection?.includesMemoryBodies !== false) gaps.push('universal packet provider projection includes memory bodies');
|
|
3369
|
+
if (summary.cognitiveRuntimeReceipts?.ok !== true) gaps.push('universal cognitive runtime receipt missing or failed');
|
|
3370
|
+
if ((summary.cognitiveRuntimeReceipts?.tadabbur?.stageCount || 0) < ARIA_TADABBUR_12_STAGES.length) gaps.push('universal Tadabbur runtime did not run all 12 stages');
|
|
3371
|
+
if ((summary.cognitiveRuntimeReceipts?.qiyas?.perspectiveCount || 0) < ARIA_QIYAS_15_PERSPECTIVES.length) gaps.push('universal Qiyas runtime did not run all 15 perspectives');
|
|
3372
|
+
if ((summary.cognitiveRuntimeReceipts?.noor?.noorSuiteCount || 0) < ARIA_CODEX_UNIVERSAL_NOOR_FLOOR) gaps.push(`universal Noor runtime floor not met: ${summary.cognitiveRuntimeReceipts?.noor?.noorSuiteCount || 0}/${ARIA_CODEX_UNIVERSAL_NOOR_FLOOR}`);
|
|
3373
|
+
if (summary.qaCorrectionReceipt?.ok !== true) gaps.push('universal QA/correction receipt missing or failed');
|
|
3374
|
+
if (summary.hiveObserverSourceTopology?.ok !== true) gaps.push('universal Hive observer/source topology receipt missing or failed');
|
|
3375
|
+
if (
|
|
3376
|
+
summary.hiveSiblingSessionBroadcast?.ok !== true
|
|
3377
|
+
|| Number(summary.hiveSiblingSessionBroadcast?.messageCount || 0) < ARIA_CODEX_UNIVERSAL_HIVE_SIBLING_BROADCAST_FLOOR
|
|
3378
|
+
) {
|
|
3379
|
+
gaps.push('universal Hive sibling session broadcast receipt missing or failed');
|
|
3380
|
+
}
|
|
3381
|
+
const ownerApproval = summary.ownerApprovalPacket || null;
|
|
3382
|
+
if (!ownerApproval || typeof ownerApproval !== 'object') {
|
|
3383
|
+
gaps.push('universal owner approval packet missing');
|
|
3384
|
+
} else if (ownerApproval.required === true && ownerApproval.blocksProductionPromotion !== true) {
|
|
3385
|
+
gaps.push('universal owner approval packet does not block requested production promotion');
|
|
3386
|
+
} else if (ownerApproval.required !== true && ownerApproval.ownerApprovalStatus !== 'not_required') {
|
|
3387
|
+
gaps.push('universal owner approval packet has ambiguous non-promotion status');
|
|
3388
|
+
}
|
|
3389
|
+
return gaps;
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
export function forcedSkillLoadGaps(state = {}) {
|
|
3393
|
+
const summary = state?.forcedSkillLoad || null;
|
|
3394
|
+
const required = Array.isArray(state?.requiredSkills) ? state.requiredSkills : [];
|
|
3395
|
+
if (required.length === 0) return [];
|
|
3396
|
+
if (!summary) return ['forced runtime skill/cookbook context was not built'];
|
|
3397
|
+
const gaps = [];
|
|
3398
|
+
if (Array.isArray(summary.missingSkillIds) && summary.missingSkillIds.length > 0) {
|
|
3399
|
+
gaps.push('missing skill ids: ' + summary.missingSkillIds.join(', '));
|
|
3400
|
+
}
|
|
3401
|
+
if (Array.isArray(summary.missingCookbooks) && summary.missingCookbooks.length > 0) {
|
|
3402
|
+
gaps.push('missing cookbooks: ' + summary.missingCookbooks.map((entry) => entry.path || entry.cookbookName).join(', '));
|
|
3403
|
+
}
|
|
3404
|
+
if (summary.skillExecutionMode === 'mechanical-receipt') {
|
|
3405
|
+
const receipt = summary.skillExecutionReceipt || {};
|
|
3406
|
+
const fired = Array.isArray(receipt.executedSkillIds) && receipt.executedSkillIds.length
|
|
3407
|
+
? receipt.executedSkillIds
|
|
3408
|
+
: Array.isArray(receipt.firedSkillIds) ? receipt.firedSkillIds : [];
|
|
3409
|
+
const missingFired = required.filter((skill) => !fired.includes(skill));
|
|
3410
|
+
if (receipt.ok !== true) gaps.push('mechanical skill execution receipt did not pass');
|
|
3411
|
+
if (receipt.substrateKernelExecution?.ok !== true) gaps.push('substrate kernel execution receipt did not pass');
|
|
3412
|
+
if (missingFired.length > 0) gaps.push('mechanical receipt missing fired skill ids: ' + missingFired.join(', '));
|
|
3413
|
+
if (summary.promptChars > 75000) gaps.push('mechanical receipt prompt exceeds compact prompt budget');
|
|
3414
|
+
}
|
|
3415
|
+
gaps.push(...universalTurnPacketGaps({
|
|
3416
|
+
requiredSkills: required,
|
|
3417
|
+
forcedSkillLoad: summary,
|
|
3418
|
+
universalTurnPacket: state.universalTurnPacket === true,
|
|
3419
|
+
}));
|
|
3420
|
+
if (required.includes('tadabbur')) {
|
|
3421
|
+
const cookbookNames = new Set((summary.loadedCookbooks || []).map((entry) => entry.cookbookName).filter(Boolean));
|
|
3422
|
+
if (!cookbookNames.has('tadabbur-cookbook.md')) gaps.push('tadabbur required but tadabbur-cookbook.md was not loaded');
|
|
3423
|
+
}
|
|
3424
|
+
return gaps;
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
export function requiresFullAriaCognition(userText = '', requiredSkills = []) {
|
|
3428
|
+
const text = String(userText || '');
|
|
3429
|
+
if (/(?:social|casual|small talk|quick reply)/i.test(text)) return false;
|
|
3430
|
+
if (/(?:qiyas|tadabbur|taddabur|full cognition|architecture|runtime|code|coding|repo|hook|hooks|sdk|worker|workers|queue|ledger|qa|quality|audit|harness|connector|gate|skills?|cookbooks?|daemon|telemetry)/i.test(text)) {
|
|
3431
|
+
return true;
|
|
3432
|
+
}
|
|
3433
|
+
return requiredSkills.includes('qiyas-analogy') || requiredSkills.includes('tadabbur');
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
function ownerVisibleText(text = '') {
|
|
3437
|
+
return String(text || '')
|
|
3438
|
+
.replace(new RegExp('<!--[\\s\\S]*?-->', 'g'), '')
|
|
3439
|
+
.replace(new RegExp('<details\\b[\\s\\S]*?</details>', 'gi'), '')
|
|
3440
|
+
.replace(new RegExp('<gate\\b[\\s\\S]*?</gate>', 'gi'), '')
|
|
3441
|
+
.replace(new RegExp('<cognition\\b[\\s\\S]*?</cognition>', 'gi'), '')
|
|
3442
|
+
.replace(new RegExp('<applied_cognition\\b[\\s\\S]*?</applied_cognition>', 'gi'), '');
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
export function fullCognitionMethodGaps({ state = {}, text = '' } = {}) {
|
|
3446
|
+
const required = Array.isArray(state?.requiredSkills) ? state.requiredSkills : [];
|
|
3447
|
+
const userText = state?.userText || '';
|
|
3448
|
+
if (!requiresFullAriaCognition(userText, required)) return [];
|
|
3449
|
+
const visible = ownerVisibleText(text);
|
|
3450
|
+
const gaps = [];
|
|
3451
|
+
const qiyasLabel = new RegExp('(^|\\n)\\s*qiyas_15_pass\\s*:', 'i');
|
|
3452
|
+
const tadabburLabel = new RegExp('(^|\\n)\\s*tadabbur_full_canonical_12_stage\\s*:', 'i');
|
|
3453
|
+
const tadabburStages = new RegExp('\\b(?:EMBED|EXCAVATE|ROOT TRACE|INTENT TRACE|CONTRACT TRACE|CONSEQUENCE|COLLAPSE|SEPARATE|VERIFY|RECORD|DECIDE|ACT)\\b', 'g');
|
|
3454
|
+
if (qiyasLabel.test(visible) || (visible.match(/Owner-Hamza-(?:now|tomorrow|future)|Repo integrity|Deploy integrity|Scope discipline/g) || []).length >= 4) {
|
|
3455
|
+
gaps.push('raw Qiyas method dump is on the owner surface; collapse it into the decision and keep method evidence off the visible answer');
|
|
3456
|
+
}
|
|
3457
|
+
if (tadabburLabel.test(visible) || (visible.match(tadabburStages) || []).length >= 4) {
|
|
3458
|
+
gaps.push('raw Tadabbur stage dump is on the owner surface; collapse it into consequence-aware guidance and keep method evidence off the visible answer');
|
|
3459
|
+
}
|
|
3460
|
+
// Method coverage is proven by runtime skill-load state, not by forcing
|
|
3461
|
+
// every Qiyas/Tadabbur label into the owner-visible answer.
|
|
3462
|
+
if (new RegExp('<applied_cognition\\b', 'i').test(visible) || new RegExp('</applied_cognition>', 'i').test(visible)) {
|
|
3463
|
+
gaps.push('raw applied_cognition XML is on the owner surface; summarize the decision delta in prose unless a gate explicitly asks for machine-readable XML');
|
|
3464
|
+
}
|
|
3465
|
+
return gaps;
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
function normalizeValidationIssue(issue) {
|
|
3469
|
+
const raw = String(issue || '').replace(/\s+/g, ' ').trim();
|
|
3470
|
+
if (!raw) return '';
|
|
3471
|
+
if (/No <cognition>/i.test(raw)) return 'missing readable cognition block';
|
|
3472
|
+
if (/missing\s+<applied_cognition>/i.test(raw)) return 'missing applied cognition contract';
|
|
3473
|
+
if (/owner_facing_cognition_first|owner[- ]readable|Leading with <cognition>|gate surface/i.test(raw)) {
|
|
3474
|
+
return 'owner-readable answer must come before gate XML; move <cognition>/<applied_cognition> after the headline, evidence, and next action';
|
|
3475
|
+
}
|
|
3476
|
+
if (/feedback_full_harness_binding_must_be_structural|just-context-I-read|SDK has primitives|just context|advisory|read[.-]?only/i.test(raw)) {
|
|
3477
|
+
return 'structural harness binding requires executed SDK primitive evidence: name the validateOutput/checkAction/inject/gardenTurn/verifyClaim receipt, or state that no SDK primitive has run and make the next action the exact primitive call; avoid ambiguous "read-only" wording when you mean "no production writes were performed"';
|
|
3478
|
+
}
|
|
3479
|
+
if (/feedback_pretoolgate_covers_all_action_tools/i.test(raw)) {
|
|
3480
|
+
return 'doctrine wording issue: requirements must not be framed as preferences, optional paths, or fallback layers';
|
|
3481
|
+
}
|
|
3482
|
+
if (/feedback_qa_binds_to_fix_not_question|QA finding has been emitted|Recovery Contract is BINDING/i.test(raw)) {
|
|
3483
|
+
return 'QA finding requires A/B/C/D closure with evidence: fixed in turn, tracked task, scoped Mizan choice, or invalidated';
|
|
3484
|
+
}
|
|
3485
|
+
if (/feedback_no_premature_task_closeout|premature_task_closeout/i.test(raw)) {
|
|
3486
|
+
return 'completion/readiness claim needs matching verification or bounded status';
|
|
3487
|
+
}
|
|
3488
|
+
if (/qualitative_drift/i.test(raw)) return 'qualitative drift language needs a measurable predicate';
|
|
3489
|
+
if (/premature_task_closeout|feedback_no_premature_task_closeout|done\|complete\|completed\|ready\|verified\|fixed/i.test(raw)) {
|
|
3490
|
+
return 'completion/readiness claim conflicts with unresolved blocker state';
|
|
3491
|
+
}
|
|
3492
|
+
if (/\(\?:/.test(raw)) return 'doctrine matcher triggered; re-author with the named doctrine and concrete evidence';
|
|
3493
|
+
return raw.slice(0, 600);
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
function uniqueStrings(values) {
|
|
3497
|
+
return Array.from(new Set(values.map(normalizeValidationIssue).filter(Boolean)));
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
export function formatValidationFailure(result) {
|
|
3501
|
+
const parts = [];
|
|
3502
|
+
if (Array.isArray(result?.validation?.violations) && result.validation.violations.length) {
|
|
3503
|
+
parts.push(...result.validation.violations);
|
|
3504
|
+
}
|
|
3505
|
+
if (Array.isArray(result?.layer3?.failures) && result.layer3.failures.length) {
|
|
3506
|
+
parts.push(...result.layer3.failures.map((failure) => failure?.detail || failure?.kind || JSON.stringify(failure)));
|
|
3507
|
+
}
|
|
3508
|
+
if (!parts.length && typeof result?.summary === 'string' && result.summary.trim()) {
|
|
3509
|
+
parts.push(result.summary.trim());
|
|
3510
|
+
}
|
|
3511
|
+
return uniqueStrings(parts).join(' | ') || 'Aria validation failed.';
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
export function isAriaControlBlock(text) {
|
|
3515
|
+
return /^(?:ARIA CODEX RECOVERY CONTRACT|Aria held this Codex output for re-authoring\.|Aria runtime blocked final output for this Codex turn\.|Aria stop gate blocked output:|Aria task\/project ledger blocked output claim\.|Aria stop hook failed closed:)/i.test(String(text || '').trim());
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
export function formatCodexRecoveryBlock({ surface = ARIA_HOOK_SURFACE, reason = '', issues = [], next = '' } = {}) {
|
|
3519
|
+
const blockers = uniqueStrings([reason, ...issues]);
|
|
3520
|
+
const hasStructuralHarnessBindingBlocker = blockers.some((item) => /structural harness binding/i.test(item));
|
|
3521
|
+
const recoveryLines = hasStructuralHarnessBindingBlocker
|
|
3522
|
+
? [
|
|
3523
|
+
'4. Structural harness binding blocker: do not repeat "SDK primitives" as prose.',
|
|
3524
|
+
'5. In the owner answer, include one concrete line: SDK evidence: <primitive> <receipt/path/status> or SDK evidence: not run yet.',
|
|
3525
|
+
'6. If not run yet, the next action must be the exact primitive call, for example validateOutput, checkAction, inject, gardenTurn, or verifyClaim.',
|
|
3526
|
+
'7. Avoid ambiguous read-only wording; say no production writes were performed when that is the actual evidence.',
|
|
3527
|
+
]
|
|
3528
|
+
: [
|
|
3529
|
+
next || '4. Re-submit the corrected answer; if this blocker repeats twice, escalate with this block report.',
|
|
3530
|
+
];
|
|
3531
|
+
return [
|
|
3532
|
+
'Aria held this Codex output for re-authoring.',
|
|
3533
|
+
'',
|
|
3534
|
+
'Surface: ' + surface,
|
|
3535
|
+
'Status: blocked before user release',
|
|
3536
|
+
'',
|
|
3537
|
+
'Observed blockers:',
|
|
3538
|
+
...(blockers.length ? blockers.map((item) => '- ' + item) : ['- Aria validation failed.']),
|
|
3539
|
+
'',
|
|
3540
|
+
'Rewrite shape:',
|
|
3541
|
+
'1. Start with the owner-readable answer: status, evidence, next action.',
|
|
3542
|
+
'2. Keep claims bounded unless verification evidence is present.',
|
|
3543
|
+
'3. Put raw gate XML after the answer only when the gate explicitly requires it.',
|
|
3544
|
+
...recoveryLines,
|
|
3545
|
+
].join('\n');
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
export function emitJson(payload, code = 0) {
|
|
3549
|
+
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
3550
|
+
process.exit(code);
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3553
|
+
export function runGovernanceGate(payload = {}) {
|
|
3554
|
+
if (!existsSync(GOVERNANCE_GATE_PATH)) return null;
|
|
3555
|
+
const child = spawnSync(GOVERNANCE_GATE_PATH, {
|
|
3556
|
+
input: `${JSON.stringify(payload)}\n`,
|
|
3557
|
+
encoding: 'utf8',
|
|
3558
|
+
maxBuffer: 1024 * 1024,
|
|
3559
|
+
});
|
|
3560
|
+
const stdout = String(child.stdout || '').trim();
|
|
3561
|
+
let result = null;
|
|
3562
|
+
try { result = stdout ? JSON.parse(stdout) : null; } catch {}
|
|
3563
|
+
if (child.status !== 0 || result?.ok === false || result?.decision === 'block') {
|
|
3564
|
+
throw new Error(stdout || child.stderr || 'aria-governance-gate blocked this Codex hook.');
|
|
3565
|
+
}
|
|
3566
|
+
return result;
|
|
3567
|
+
}
|