blun-king-cli 9.1.587 → 9.1.588
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/CHANGELOG.md +11 -185
- package/LIESMICH.txt +51 -13
- package/README.md +44 -47
- package/agent-spine-plugin/.codex-plugin/plugin.json +16 -4
- package/agent-spine-plugin/CHANGELOG.md +37 -5
- package/agent-spine-plugin/README.md +3 -3
- package/agent-spine-plugin/blun.plugin.json +45 -10
- package/agent-spine-plugin/docs/artifact-evaluation.md +93 -0
- package/agent-spine-plugin/docs/host-integration.md +42 -27
- package/agent-spine-plugin/docs/preflight-recall.md +4 -2
- package/agent-spine-plugin/docs/session-timeline.md +97 -236
- package/agent-spine-plugin/docs/world-model.md +25 -0
- package/agent-spine-plugin/hooks/codex.json +1 -1
- package/agent-spine-plugin/hooks/hooks.json +1 -1
- package/agent-spine-plugin/package.json +1 -3
- package/agent-spine-plugin/scripts/check-hosts.js +3 -3
- package/agent-spine-plugin/scripts/release-check.js +10 -5
- package/agent-spine-plugin/scripts/run-checks.js +4 -1
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +32 -6
- package/agent-spine-plugin/src/cli-learning.js +15 -0
- package/agent-spine-plugin/src/cli.js +2 -0
- package/agent-spine-plugin/src/hook.js +32 -32
- package/agent-spine-plugin/src/lib/action-lesson-recall.js +73 -8
- package/agent-spine-plugin/src/lib/briefing.js +146 -36
- package/agent-spine-plugin/src/lib/channel-continuity.js +19 -0
- package/agent-spine-plugin/src/lib/delivery-agent-usage.js +14 -7
- package/agent-spine-plugin/src/lib/gateway-group-response.js +128 -0
- package/agent-spine-plugin/src/lib/gateway-runs.js +24 -15
- package/agent-spine-plugin/src/lib/hook-briefing-use.js +13 -3
- package/agent-spine-plugin/src/lib/hook-context.js +16 -3
- package/agent-spine-plugin/src/lib/hook-output.js +129 -5
- package/agent-spine-plugin/src/lib/hook-timeline.js +5 -3
- package/agent-spine-plugin/src/lib/indexed-memory.js +2 -2
- package/agent-spine-plugin/src/lib/learning-artifact-evaluator.js +114 -0
- package/agent-spine-plugin/src/lib/learning-context.js +11 -4
- package/agent-spine-plugin/src/lib/learning-measurements.js +2 -2
- package/agent-spine-plugin/src/lib/mcp-runtime.js +89 -3
- package/agent-spine-plugin/src/lib/mcp-source-context.js +12 -2
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +91 -8
- package/agent-spine-plugin/src/lib/mcp-world-tools.js +2 -2
- package/agent-spine-plugin/src/lib/owned-file-lock.js +20 -1
- package/agent-spine-plugin/src/lib/persona-runtime.js +2 -2
- package/agent-spine-plugin/src/lib/preflight-delivery-id.js +27 -0
- package/agent-spine-plugin/src/lib/preflight.js +4 -4
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +15 -0
- package/agent-spine-plugin/src/lib/session-timeline-contract.js +12 -4
- package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +36 -7
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +13 -10
- package/agent-spine-plugin/src/lib/session-timeline-invocation.js +1 -1
- package/agent-spine-plugin/src/lib/session-timeline-king.js +14 -0
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +18 -12
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +5 -0
- package/agent-spine-plugin/src/lib/session-timeline-query.js +2 -0
- package/agent-spine-plugin/src/lib/session-timeline-results.js +35 -10
- package/agent-spine-plugin/src/lib/session-timeline-source-open.js +30 -0
- package/agent-spine-plugin/src/lib/session-timeline.js +122 -75
- package/agent-spine-plugin/src/lib/source-roots.js +3 -2
- package/agent-spine-plugin/src/lib/task-knowledge-context.js +22 -1
- package/agent-spine-plugin/src/lib/timeline-continuation-update.js +100 -0
- package/agent-spine-plugin/src/lib/timeline-tool-guard.js +30 -7
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +217 -0
- package/agent-spine-plugin/src/lib/timeline-world-capture.js +233 -0
- package/agent-spine-plugin/src/lib/world-knowledge.js +59 -2
- package/agent-spine-plugin/src/lib/world-model.js +64 -9
- package/agent-spine-plugin/src/worker.js +13 -1
- package/bin/blun.js +43 -28
- package/bin/core-bootstrap.js +5 -4
- package/bin/king.js +43 -28
- package/bin/launcher-mode.js +1 -10
- package/bin/launcher-runtime.js +128 -295
- package/bin/managed-node.js +0 -0
- package/bin/managed-plugin-selection.cjs +0 -1
- package/bin/native-module-repair.js +0 -0
- package/bin/node-runtime.js +0 -0
- package/bin/node-version.js +0 -0
- package/bin/plugin-bootstrap.js +56 -120
- package/bin/private-paths.js +11 -34
- package/bin/standard-tools-bootstrap.js +34 -114
- package/bin/turn-thinking-policy.cjs +3 -11
- package/bin/update-copy.js +200 -0
- package/bin/update-lease.js +0 -0
- package/bin/update-notice.js +136 -289
- package/bin/verify-agent-behavior.cjs +122 -0
- package/bin/verify-agent-components.cjs +104 -0
- package/bin/verify-bundled-agent-sources.cjs +57 -0
- package/blun.mjs +143076 -135288
- package/bundled-agent-sources.json +701 -0
- package/package.json +12 -15
- package/standard-skills/translate-native/README.md +1293 -0
- package/standard-skills/translate-native/SKILL.md +172 -22
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/agents/openai.yaml +18 -0
- package/standard-skills/translate-native/assets/icon.svg +8 -0
- package/standard-skills/translate-native/docs/BLUN_CODE_INTEGRATION.md +76 -0
- package/standard-skills/translate-native/docs/PREMORTEM.md +489 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +2035 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1302 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +136 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HEALTH_HTTP.md +130 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +175 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +86 -0
- package/standard-skills/translate-native/integrations/AGENT_RULES.md +32 -0
- package/standard-skills/translate-native/integrations/adapters/blun-code-language-guard.js +514 -0
- package/standard-skills/translate-native/integrations/adapters/node-language-guard.js +230 -0
- package/standard-skills/translate-native/integrations/audit_log.py +327 -0
- package/standard-skills/translate-native/integrations/claude_language_hook.js +1536 -0
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +42 -0
- package/standard-skills/translate-native/integrations/delivery-policy.example.json +28 -0
- package/standard-skills/translate-native/integrations/enforced_delivery.py +543 -0
- package/standard-skills/translate-native/integrations/guard_service.py +435 -0
- package/standard-skills/translate-native/integrations/language_gateway.py +67 -0
- package/standard-skills/translate-native/integrations/mcp_auth_headers.py +198 -0
- package/standard-skills/translate-native/integrations/mcp_http_gateway.py +429 -0
- package/standard-skills/translate-native/integrations/non_language_html_entities.js +1485 -0
- package/standard-skills/translate-native/integrations/pre_output_guard.py +65 -0
- package/standard-skills/translate-native/integrations/task_router.py +101 -0
- package/standard-skills/translate-native/integrations/website_localization.py +401 -0
- package/standard-skills/translate-native/integrations/website_localization_api.py +581 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +1885 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_campaign.py +1772 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_candidate.py +506 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_http.py +400 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_review_store.py +781 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_reviewer_http.py +500 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_runtime.py +1107 -0
- package/standard-skills/translate-native/integrations/website_localization_benchmark_suite.py +463 -0
- package/standard-skills/translate-native/integrations/website_localization_cms.py +2835 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +875 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_dispatch.py +805 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_http.py +588 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_lifecycle_monitor.py +991 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +1441 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +414 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +1073 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_removal_dispatch.py +865 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +583 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +964 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +665 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +1153 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +675 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +1125 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification.py +674 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +1469 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +1142 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +634 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +804 -0
- package/standard-skills/translate-native/integrations/website_localization_deepl_baseline.py +922 -0
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +482 -0
- package/standard-skills/translate-native/integrations/website_localization_health.py +1541 -0
- package/standard-skills/translate-native/integrations/website_localization_health_http.py +372 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +297 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_http.py +479 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_intake.py +363 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_queue.py +1449 -0
- package/standard-skills/translate-native/integrations/website_localization_native_reference_store.py +420 -0
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +235 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +671 -0
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +516 -0
- package/standard-skills/translate-native/integrations/website_localization_release.py +928 -0
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +1008 -0
- package/standard-skills/translate-native/integrations/website_localization_runner.py +276 -0
- package/standard-skills/translate-native/integrations/website_localization_runtime.py +862 -0
- package/standard-skills/translate-native/integrations/website_localization_service.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_supervisor.py +511 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +663 -0
- package/standard-skills/translate-native/provenance.json +3 -4
- package/standard-skills/translate-native/references/commercial-localization.md +177 -0
- package/standard-skills/translate-native/scripts/blun_language_guard.py +7 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +80 -0
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +333 -0
- package/standard-tools/language-guard/LICENSE +21 -0
- package/standard-tools/language-guard/VERSION +1 -0
- package/standard-tools/language-guard/blun_language_guard.py +7 -1
- package/standard-tools/language-guard/check_commercial_review.py +80 -0
- package/standard-tools/language-guard/commercial_localization_profile.py +333 -0
- package/standard-tools/language-guard/language_gateway.py +62 -0
- package/standard-tools/language-guard/pre_output_guard.py +64 -0
- package/standard-tools/language-guard/provenance.json +4 -11
- package/standard-tools/manifest.json +34 -11
- package/telegram-plugin/commands/access.md +2 -10
- package/telegram-plugin/dist/bridge.mjs +64041 -687
- package/telegram-plugin/dist/mcp-server.mjs +72810 -9027
- package/telegram-plugin/dist/noise.mjs +28 -63511
- package/agent-spine-plugin/CONTRIBUTING.md +0 -52
- package/agent-spine-plugin/SECURITY.md +0 -47
- package/agent-spine-plugin/docs/assignment-continuation.md +0 -48
- package/agent-spine-plugin/docs/releasing.md +0 -85
- package/agent-spine-plugin/docs/structured-completion.md +0 -67
- package/bin/abort-listener-policy.cjs +0 -43
- package/bin/active-steer-priority-policy.cjs +0 -24
- package/bin/agent-api-http-adapter.mjs +0 -446
- package/bin/agent-api-private-http-server.mjs +0 -288
- package/bin/agent-api-runtime.mjs +0 -252
- package/bin/agent-api-service-environment.mjs +0 -236
- package/bin/agent-api-service-host.mjs +0 -209
- package/bin/agent-api-service-process.mjs +0 -171
- package/bin/agent-api-session-registry.mjs +0 -428
- package/bin/agent-api-tool-broker.cjs +0 -248
- package/bin/agent-api-turn-controller.mjs +0 -461
- package/bin/agent-api-usage-journal.cjs +0 -259
- package/bin/agent-resume-snapshot.cjs +0 -241
- package/bin/agentspine-king-goal-inbox.mjs +0 -111
- package/bin/agentspine-king-goal-intake.mjs +0 -106
- package/bin/approval-rejection-stop.cjs +0 -15
- package/bin/assistant-message-offload-policy.cjs +0 -284
- package/bin/baseline-skill-performance-policy.cjs +0 -39
- package/bin/bash-search-scope-policy.cjs +0 -49
- package/bin/codebase-search-runtime.cjs +0 -23
- package/bin/cognitive-action-checkpoint.cjs +0 -1104
- package/bin/cognitive-attention-delivery.cjs +0 -76
- package/bin/cognitive-attention-policy.cjs +0 -143
- package/bin/cognitive-attention-runtime.cjs +0 -91
- package/bin/cognitive-context-projection.cjs +0 -73
- package/bin/cognitive-cross-portal-acceptance.cjs +0 -443
- package/bin/cognitive-effective-view.cjs +0 -77
- package/bin/cognitive-focus-projection.cjs +0 -206
- package/bin/cognitive-focus-scope.cjs +0 -37
- package/bin/cognitive-goal-autostart-policy.cjs +0 -72
- package/bin/cognitive-goal-time-trigger-controller.cjs +0 -146
- package/bin/cognitive-memory-adapter.cjs +0 -282
- package/bin/cognitive-memory-command.cjs +0 -293
- package/bin/cognitive-memory-provider.cjs +0 -92
- package/bin/cognitive-salience-policy.cjs +0 -159
- package/bin/cognitive-state-store.cjs +0 -508
- package/bin/cognitive-turn-lifecycle.cjs +0 -624
- package/bin/cognitive-work-focus.cjs +0 -180
- package/bin/compaction-history-archive.cjs +0 -166
- package/bin/compaction-history-startup.cjs +0 -50
- package/bin/compaction-model-policy.cjs +0 -31
- package/bin/compaction-stage-policy.cjs +0 -21
- package/bin/compaction-transaction-policy.cjs +0 -122
- package/bin/config-write-dedup-policy.cjs +0 -27
- package/bin/context-budget-ledger.cjs +0 -31
- package/bin/context-doctor-policy.cjs +0 -70
- package/bin/context-insight-policy.cjs +0 -36
- package/bin/context-performance-policy.cjs +0 -19
- package/bin/context-pressure-policy.cjs +0 -20
- package/bin/cron-run-output.cjs +0 -45
- package/bin/cron-run-store.cjs +0 -145
- package/bin/curiosity-scout-policy.cjs +0 -49
- package/bin/default-model-output-budget-policy.cjs +0 -28
- package/bin/durable-task-resume-policy.cjs +0 -130
- package/bin/durable-task-resume-runtime.cjs +0 -117
- package/bin/durable-task-resume-store.cjs +0 -88
- package/bin/editable-tool-approval-policy.cjs +0 -540
- package/bin/editable-tool-approval-runtime.cjs +0 -99
- package/bin/effective-system-prompt-cache-policy.cjs +0 -33
- package/bin/error-memory-performance-policy.cjs +0 -113
- package/bin/file-observation-policy.cjs +0 -133
- package/bin/foreground-output-capture-policy.cjs +0 -41
- package/bin/generated-source-health.cjs +0 -142
- package/bin/glob-pattern-policy.cjs +0 -13
- package/bin/goal-completion-evidence-policy.cjs +0 -120
- package/bin/grep-output-limit-policy.cjs +0 -39
- package/bin/historical-media-projection-policy.cjs +0 -48
- package/bin/history-offload-pressure-policy.cjs +0 -33
- package/bin/html-to-research-markdown.cjs +0 -147
- package/bin/identity-context-policy.cjs +0 -764
- package/bin/identity-journal-policy.cjs +0 -107
- package/bin/input-draft-persistence.cjs +0 -77
- package/bin/king-tui-function-contract.json +0 -33
- package/bin/launcher-restart-policy.cjs +0 -150
- package/bin/live-response-repetition-guard.cjs +0 -196
- package/bin/llm-config-log-dedup-policy.cjs +0 -76
- package/bin/loop-event-record-policy.cjs +0 -174
- package/bin/managed-context-startup-policy.cjs +0 -27
- package/bin/media-activity-layout-policy.cjs +0 -34
- package/bin/media-auto-retrieval-policy.cjs +0 -90
- package/bin/media-result-policy.cjs +0 -59
- package/bin/micro-compaction-policy.cjs +0 -145
- package/bin/mistake-relevance-policy.cjs +0 -319
- package/bin/model-retry-progress-policy.cjs +0 -46
- package/bin/native-large-file-io.cjs +0 -42
- package/bin/native-runtime-cache.cjs +0 -76
- package/bin/natural-presence-policy.cjs +0 -28
- package/bin/noninteractive-shell-env-policy.cjs +0 -19
- package/bin/observer-hooks.cjs +0 -14
- package/bin/outbound-claim-provenance.cjs +0 -150
- package/bin/oversized-context-offload-policy.cjs +0 -86
- package/bin/pending-media-policy.cjs +0 -182
- package/bin/pending-token-estimate-policy.cjs +0 -41
- package/bin/personal-memory-consent-policy.cjs +0 -72
- package/bin/personal-memory-performance-policy.cjs +0 -12
- package/bin/personality-choice-policy.cjs +0 -101
- package/bin/personality-memory-adapter.cjs +0 -379
- package/bin/personality-mode.cjs +0 -46
- package/bin/personality-setup-policy.cjs +0 -197
- package/bin/proactive-compaction-policy.cjs +0 -25
- package/bin/profile-identity-resolution.cjs +0 -136
- package/bin/profile-runtime.cjs +0 -318
- package/bin/profile-tool-exclusion-policy.cjs +0 -37
- package/bin/programmatic-context-isolation.cjs +0 -25
- package/bin/programmatic-tool-runtime.mjs +0 -627
- package/bin/provider-idle-timeout-policy.cjs +0 -14
- package/bin/provider-model-refresh-deadline.cjs +0 -53
- package/bin/provider-model-refresh-policy.cjs +0 -107
- package/bin/rate-limit-recovery-policy.cjs +0 -47
- package/bin/read-batch-policy.cjs +0 -32
- package/bin/read-continuation-policy.cjs +0 -59
- package/bin/recurring-cron-history-policy.cjs +0 -124
- package/bin/relationship-continuity-policy.cjs +0 -143
- package/bin/relationship-curiosity-policy.cjs +0 -107
- package/bin/relationship-learning-policy.cjs +0 -168
- package/bin/release-artifact-freeze-policy.cjs +0 -30
- package/bin/reload-plugin-bootstrap.cjs +0 -18
- package/bin/reload-queue-policy.cjs +0 -38
- package/bin/repeated-assistant-response-policy.cjs +0 -232
- package/bin/repeated-injection-projection.cjs +0 -107
- package/bin/repeated-user-message-projection.cjs +0 -8
- package/bin/research-page-result.cjs +0 -74
- package/bin/retry-checkpoint-policy.cjs +0 -13
- package/bin/runtime-exit-ledger.cjs +0 -144
- package/bin/scoped-cron-run-policy.cjs +0 -358
- package/bin/session-checkpoint-policy.cjs +0 -25
- package/bin/session-compaction-policy.cjs +0 -84
- package/bin/session-replay-policy.cjs +0 -20
- package/bin/session-replay-window-policy.cjs +0 -40
- package/bin/session-resume-checkpoint.cjs +0 -254
- package/bin/session-scrollback-archive.cjs +0 -229
- package/bin/skill-activation-performance-policy.cjs +0 -69
- package/bin/skill-listing-performance-policy.cjs +0 -92
- package/bin/soul-organization-policy.cjs +0 -78
- package/bin/soul-preservation-policy.cjs +0 -20
- package/bin/startup-preferences.cjs +0 -131
- package/bin/streaming-flush-performance-policy.cjs +0 -28
- package/bin/structured-agent-swarm-output.cjs +0 -325
- package/bin/structured-subagent-output.cjs +0 -252
- package/bin/subagent-context-fork-policy.cjs +0 -155
- package/bin/subagent-max-tokens-handoff-policy.cjs +0 -69
- package/bin/subagent-parent-responsiveness.cjs +0 -19
- package/bin/subagent-skill-policy.cjs +0 -206
- package/bin/subagent-timeout-policy.cjs +0 -182
- package/bin/subagent-tool-policy.cjs +0 -60
- package/bin/subagent-usage-rollup-policy.cjs +0 -29
- package/bin/system-prompt-context-policy.cjs +0 -124
- package/bin/system-prompt-token-cache-policy.cjs +0 -60
- package/bin/telegram-addressed-focus.cjs +0 -55
- package/bin/telegram-addressed-priority.cjs +0 -12
- package/bin/telegram-approval-relay.cjs +0 -290
- package/bin/telegram-bot-priority.cjs +0 -17
- package/bin/telegram-console-status-policy.cjs +0 -174
- package/bin/telegram-context-projection-policy.cjs +0 -141
- package/bin/telegram-delivery-lifecycle.cjs +0 -125
- package/bin/telegram-direct-focus-policy.cjs +0 -273
- package/bin/telegram-mcp-compatibility.cjs +0 -49
- package/bin/telegram-media-delivery-policy.cjs +0 -42
- package/bin/telegram-private-conversation-policy.cjs +0 -185
- package/bin/telegram-queue-handoff-policy.cjs +0 -73
- package/bin/telegram-remote-status-policy.cjs +0 -120
- package/bin/telegram-session-queue-runtime.mjs +0 -306
- package/bin/telegram-text-chunk-policy.cjs +0 -63
- package/bin/telegram-truncated-reply-policy.cjs +0 -37
- package/bin/telegram-urgent-policy.cjs +0 -45
- package/bin/telemetry-spool-policy.cjs +0 -57
- package/bin/thinking-activity-status-policy.cjs +0 -132
- package/bin/thinking-only-guard.cjs +0 -80
- package/bin/todo-list-turn-policy.cjs +0 -131
- package/bin/tool-call-loop-policy.cjs +0 -51
- package/bin/tool-file-persistence.cjs +0 -141
- package/bin/tool-result-offload-policy.cjs +0 -359
- package/bin/tool-result-offload-telemetry.cjs +0 -12
- package/bin/tool-schema-token-cache-policy.cjs +0 -41
- package/bin/tool-stream-preview-policy.cjs +0 -9
- package/bin/tui-functional-contract.cjs +0 -55
- package/bin/turn-tool-performance-policy.cjs +0 -486
- package/bin/usage-cache-efficiency-policy.cjs +0 -26
- package/bin/user-home-path-policy.cjs +0 -13
- package/bin/user-message-offload-policy.cjs +0 -103
- package/bin/user-prompt-hook-origin-policy.cjs +0 -34
- package/bin/user-tool-record-policy.cjs +0 -7
- package/bin/validated-learning-insight-policy.cjs +0 -58
- package/bin/validated-learning-outcome-trace.cjs +0 -107
- package/bin/validated-learning-performance-policy.cjs +0 -53
- package/bin/validated-learning-signal.cjs +0 -463
- package/bin/windows-bash-dialect-policy.cjs +0 -25
- package/bin/windows-node-crash-dump.cjs +0 -110
- package/bin/write-continuation-policy.cjs +0 -69
- package/codebase-index/README.md +0 -82
- package/codebase-index/codebase_index.py +0 -470
- package/standard-skills/agent-browser/SKILL.md +0 -19
- package/standard-skills/agent-browser/references/runtime.md +0 -8
- package/standard-skills/blun-session-inspector/SKILL.md +0 -41
- package/standard-skills/blun-session-inspector/scripts/inspect-session.cjs +0 -437
- package/standard-skills/design-taste-frontend/SKILL.md +0 -1206
- package/standard-skills/full-output-enforcement/SKILL.md +0 -49
- package/standard-skills/high-end-visual-design/SKILL.md +0 -98
- package/standard-skills/image-to-code/SKILL.md +0 -1228
- package/standard-skills/industrial-brutalist-ui/SKILL.md +0 -92
- package/standard-skills/minimalist-ui/SKILL.md +0 -85
- package/standard-skills/motion-design-taste/SKILL.md +0 -74
- package/standard-skills/playwright-testing/SKILL.md +0 -19
- package/standard-skills/playwright-testing/references/runtime.md +0 -7
- package/standard-skills/premortem/SKILL.md +0 -148
- package/standard-skills/redesign-existing-projects/SKILL.md +0 -178
- package/standard-skills/research-evidence/SKILL.md +0 -39
- package/standard-skills/research-evidence/references/evidence-format.md +0 -104
- package/standard-skills/research-evidence/scripts/evidence-collection.cjs +0 -260
- package/standard-skills/research-evidence/scripts/score-report.cjs +0 -130
- package/standard-skills/screenshot-lesen/SKILL.md +0 -52
- package/standard-skills/stitch-design-taste/DESIGN.md +0 -121
- package/standard-skills/stitch-design-taste/SKILL.md +0 -184
- package/standard-skills/telegram-channel/SKILL.md +0 -18
- package/standard-skills/telegram-channel/references/runtime.md +0 -7
- package/standard-skills/venture-flywheel/SKILL.md +0 -32
- package/standard-skills/venture-flywheel/identity/project-identity.cjs +0 -146
- package/standard-skills/venture-flywheel/policy/capability-engine.cjs +0 -114
- package/standard-skills/venture-flywheel/policy/repository-trust.cjs +0 -229
- package/standard-skills/venture-flywheel/references/BEISPIELE-phase0.md +0 -146
- package/standard-skills/venture-flywheel/references/CAPABILITY-MAP.md +0 -34
- package/standard-skills/venture-flywheel/references/SPEC-phase0-identity-trust.md +0 -77
- package/standard-skills/venture-flywheel/references/SPEC-phase0-state-events.md +0 -93
- package/standard-skills/venture-flywheel/schemas/capability-decision.schema.json +0 -13
- package/standard-skills/venture-flywheel/schemas/execution-event.schema.json +0 -44
- package/standard-skills/venture-flywheel/schemas/project-identity.schema.json +0 -32
- package/standard-skills/venture-flywheel/schemas/repository-trust.schema.json +0 -57
- package/standard-skills/venture-flywheel/schemas/run-transition.schema.json +0 -59
- package/standard-skills/venture-flywheel/state/execution-event.cjs +0 -191
- package/standard-skills/venture-flywheel/state/task-state-machine.cjs +0 -190
- package/standard-skills/web-lesen/SKILL.md +0 -73
- package/standard-skills/web-lesen/scripts/crawl_public.py +0 -379
- package/standard-skills/windows-mcp/SKILL.md +0 -19
- package/standard-skills/windows-mcp/references/runtime.md +0 -9
- package/telegram-plugin/DELIVERY.md +0 -36
- package/telegram-plugin/bin/telegram-approval-relay.cjs +0 -290
- package/telegram-plugin/bin/telegram-console-status-policy.cjs +0 -175
- package/telegram-plugin/bin/telegram-delivery-lifecycle.cjs +0 -125
- package/telegram-plugin/bin/telegram-direct-reply-policy.cjs +0 -48
- package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +0 -122
- package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +0 -186
- package/telegram-plugin/bin/telegram-remote-status-policy.cjs +0 -121
- package/telegram-plugin/bin/telegram-reply-parts.cjs +0 -149
- package/telegram-plugin/bin/telegram-text-chunk-policy.cjs +0 -63
- package/telegram-plugin/bin/telegram-typing-keepalive.cjs +0 -89
- package/telegram-plugin/compat/mcp-server-fa511cd1.mjs +0 -73825
- /package/{bin → scripts}/fix-node-pty-perms.js +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { channelRuntimeFindings, claimChannelEvent, completeChannelEvent, loadChannelPolicy, loadChannelRuntime } from "./channel-runtime.js";
|
|
2
|
+
import { loadGraph } from "./graph.js";
|
|
3
|
+
import { emptyPolicy, emptyRuntime, exactId, sha256, timestamp } from "./gateway-common.js";
|
|
4
|
+
import { assertActivePersona, exactReplyBinding } from "./gateway-runtime-identity.js";
|
|
5
|
+
import { appendReceipt } from "./gateway-runtime-records.js";
|
|
6
|
+
import { normalizePolicy, normalizeRuntime, pathsFor, readJson, withLock } from "./gateway-state.js";
|
|
7
|
+
import { loadPersonaRuntime } from "./persona-runtime.js";
|
|
8
|
+
|
|
9
|
+
const SCHEMA = "agentspine.group-response/v1";
|
|
10
|
+
const CONTRIBUTIONS = new Set(["idea", "error", "improvement"]);
|
|
11
|
+
|
|
12
|
+
// This is a host result contract, not a permission or an objective evaluation.
|
|
13
|
+
export function groupResponseContract(event) {
|
|
14
|
+
if (!event?.groupId) return null;
|
|
15
|
+
return { schema: SCHEMA, defaultKind: "silence", kinds: ["silence", "answer", ...CONTRIBUTIONS],
|
|
16
|
+
eventId: event.eventId, sessionKey: event.sessionKey, groupId: event.groupId,
|
|
17
|
+
authority: "context-only", directAddressVerified: false,
|
|
18
|
+
instruction: "Without a direct request, stay silent unless contributing a relevant idea, concrete error, or improvement. Return groupResponse with this schema and kind; silence has no text. Contributions need a stable subjectId. Answer direct requests normally. Suggestions are not verified facts. Do not echo bot status messages." };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function reviewGroupResponse({ result, text, event, item, runtime, current }) {
|
|
22
|
+
if (result?.groupResponse === undefined) return null; // Preserve the legacy reply contract.
|
|
23
|
+
const response = result.groupResponse;
|
|
24
|
+
if (!event?.groupId || event.privacy !== "group" || event.groupId !== item.groupId
|
|
25
|
+
|| event.projectId !== item.projectId || event.agentId !== item.agentId) {
|
|
26
|
+
throw new Error("group response requires the exact group channel work item");
|
|
27
|
+
}
|
|
28
|
+
if (!response || Array.isArray(response) || response.schema !== SCHEMA
|
|
29
|
+
|| !["silence", "answer", ...CONTRIBUTIONS].includes(response.kind)) {
|
|
30
|
+
throw new Error("unknown group response contract or kind");
|
|
31
|
+
}
|
|
32
|
+
const contribution = CONTRIBUTIONS.has(response.kind);
|
|
33
|
+
const keys = contribution ? ["schema", "kind", "subjectId"] : ["schema", "kind"];
|
|
34
|
+
if (Object.keys(response).length !== keys.length || Object.keys(response).some((key) => !keys.includes(key))) {
|
|
35
|
+
throw new Error("group response fields do not match its kind");
|
|
36
|
+
}
|
|
37
|
+
if (response.kind === "silence" && result.text !== undefined && result.text !== null && result.text !== "") {
|
|
38
|
+
throw new Error("silent group response must not contain text or a visible placeholder");
|
|
39
|
+
}
|
|
40
|
+
if (response.kind !== "silence" && !text) throw new Error("group contribution or answer requires text");
|
|
41
|
+
let contributionDigest = null;
|
|
42
|
+
let duplicate = false;
|
|
43
|
+
if (contribution) {
|
|
44
|
+
const subjectId = exactId(response.subjectId, "groupResponse.subjectId");
|
|
45
|
+
// The gateway derives the digest. Changing an event ID cannot repeat the same
|
|
46
|
+
// contribution; different private routes and sessions never share dedupe state.
|
|
47
|
+
contributionDigest = sha256(JSON.stringify([event.provider, event.tenantId, event.accountId,
|
|
48
|
+
event.bindingId, event.agentId, event.projectId, event.groupId, event.chatId, event.threadId,
|
|
49
|
+
event.sessionKey, subjectId, text]));
|
|
50
|
+
duplicate = runtime.receipts.some((receipt) => receipt.kind === "group-contribution-prepared"
|
|
51
|
+
&& receipt.details.schema === SCHEMA && receipt.details.contributionDigest === contributionDigest);
|
|
52
|
+
}
|
|
53
|
+
const suppressed = response.kind === "silence" || duplicate;
|
|
54
|
+
if (suppressed || contribution) appendReceipt(runtime,
|
|
55
|
+
suppressed ? "group-response-suppressed" : "group-contribution-prepared", item.queueId, current,
|
|
56
|
+
{ schema: SCHEMA, eventId: event.eventId, bindingId: event.bindingId,
|
|
57
|
+
kind: response.kind, reason: duplicate ? "duplicate" : response.kind,
|
|
58
|
+
contributionDigest, deliveryConfirmed: false, completionVerified: false });
|
|
59
|
+
return { schema: SCHEMA, kind: response.kind, suppressed, duplicate,
|
|
60
|
+
deliveryConfirmed: false, completionVerified: false };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Recover the local acknowledgement after the gateway transaction commits.
|
|
64
|
+
// No adapter, outbox or delivery receipt is involved. A crash between claim and
|
|
65
|
+
// completion resumes the same lease, or reacquires it after its original expiry.
|
|
66
|
+
export async function settleSuppressedGroupEvents({ root = process.cwd(), now = new Date() } = {}) {
|
|
67
|
+
const paths = await pathsFor(root);
|
|
68
|
+
return withLock(paths, async () => {
|
|
69
|
+
const [policy, runtime, channelPolicy, channel, personas] = await Promise.all([
|
|
70
|
+
readJson(paths.gatewayPolicyPath, paths.catalog.root, normalizePolicy, emptyPolicy),
|
|
71
|
+
readJson(paths.gatewayRuntimePath, paths.catalog.root, normalizeRuntime, emptyRuntime),
|
|
72
|
+
loadChannelPolicy(paths.catalog.root, paths.catalog), loadChannelRuntime(paths.catalog.root, paths.catalog),
|
|
73
|
+
loadPersonaRuntime(paths.catalog.root, paths.catalog)
|
|
74
|
+
]);
|
|
75
|
+
if (!policy.enabled || policy.killSwitch) return { settled: 0 };
|
|
76
|
+
const current = timestamp(now);
|
|
77
|
+
let settled = 0; let deferred = 0;
|
|
78
|
+
const pending = runtime.receipts.filter((receipt) => receipt.kind === "group-response-suppressed"
|
|
79
|
+
&& channel.runtime.events.some((event) => event.eventId === receipt.details.eventId
|
|
80
|
+
&& !["completed", "cancelled"].includes(event.status)));
|
|
81
|
+
if (pending.length) {
|
|
82
|
+
const { graph } = await loadGraph(paths.catalog.root, paths.catalog);
|
|
83
|
+
if (channelRuntimeFindings(channel.runtime, channelPolicy.policy, graph).length) {
|
|
84
|
+
throw new Error("suppressed channel event integrity mismatch");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const receipt of pending) {
|
|
88
|
+
if (settled >= 20) break;
|
|
89
|
+
if (receipt.details.schema !== SCHEMA) throw new Error("unknown group response receipt version");
|
|
90
|
+
const item = runtime.queue.find((entry) => entry.queueId === receipt.objectId);
|
|
91
|
+
const event = channel.runtime.events.find((entry) => entry.eventId === receipt.details.eventId);
|
|
92
|
+
if (!item || item.status !== "completed" || item.channelEventId !== event.eventId
|
|
93
|
+
|| item.groupId !== event.groupId || item.agentId !== event.agentId || item.projectId !== event.projectId
|
|
94
|
+
|| !event.groupId || receipt.details.bindingId !== event.bindingId
|
|
95
|
+
|| runtime.outbox.some((entry) => entry.queueId === item.queueId)) {
|
|
96
|
+
throw new Error("suppressed group response lost its exact no-delivery binding");
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
assertActivePersona(personas.policy, personas.runtime, item.agentId, item.projectId, item.groupId);
|
|
100
|
+
exactReplyBinding(channelPolicy.policy, event);
|
|
101
|
+
} catch {
|
|
102
|
+
// Revocation keeps this event untouched, without stopping other work.
|
|
103
|
+
deferred += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const workerId = "group-silence:" + sha256(item.queueId).slice(0, 32);
|
|
107
|
+
try {
|
|
108
|
+
if (event.status === "leased" && new Date(event.lease.expiresAt) > new Date(current)) {
|
|
109
|
+
if (event.lease.workerId !== workerId) { deferred += 1; continue; }
|
|
110
|
+
} else {
|
|
111
|
+
const claim = await claimChannelEvent({ root: paths.catalog.root, agentId: event.agentId,
|
|
112
|
+
projectId: event.projectId, groupId: event.groupId, provider: event.provider,
|
|
113
|
+
eventId: event.eventId, workerId, now: current, catalog: paths.catalog });
|
|
114
|
+
if (!claim.event) { deferred += 1; continue; }
|
|
115
|
+
}
|
|
116
|
+
await completeChannelEvent({ root: paths.catalog.root, eventId: event.eventId,
|
|
117
|
+
workerId, status: "completed", now: current });
|
|
118
|
+
settled += 1;
|
|
119
|
+
} catch {
|
|
120
|
+
// Local acknowledgement is recoverable bookkeeping, not a new work gate.
|
|
121
|
+
// Keep the durable suppression and do not claim acknowledgement succeeded.
|
|
122
|
+
deferred += 1;
|
|
123
|
+
break; // Do not repeat the same unavailable channel service in this tick.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { settled, deferred };
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadChannelPolicy, loadChannelRuntime } from "./channel-runtime.js";
|
|
2
|
+
import { reviewGroupResponse } from "./gateway-group-response.js";
|
|
2
3
|
import {
|
|
3
4
|
assertGatewayCompletionMode, exactGatewayLeaseGeneration, failGatewayLane,
|
|
4
5
|
markHostStarted, newGatewayLease, normalizeGatewayExecutionMode,
|
|
@@ -156,26 +157,35 @@ export async function completeGatewayRun({ root = process.cwd(), queueId, worker
|
|
|
156
157
|
executionReview = { passed: false, outcome: null, reason: "Execution outcome history is full." };
|
|
157
158
|
}
|
|
158
159
|
const text = result?.text ? safeText(result.text, "result.text", 16000) : null;
|
|
160
|
+
if (result?.groupResponse !== undefined && !item.channelEventId) {
|
|
161
|
+
throw new Error("group response requires channel work");
|
|
162
|
+
}
|
|
163
|
+
let communication = null;
|
|
159
164
|
let clarification = null; let exploration = null; let selfHelp = null; let selfHelpRequired = null;
|
|
160
165
|
preserve(runtime, "queue", item, "run-completed", current);
|
|
161
166
|
if (item.channelEventId) {
|
|
162
|
-
if (!text) throw new Error("a channel obligation requires a non-empty response");
|
|
163
|
-
const voice = evaluateVoiceOutput(text);
|
|
164
|
-
if (!voice.ok) throw new Error("channel response contains a prohibited attachment or consciousness claim");
|
|
165
167
|
const event = channelRuntime.runtime.events.find((entry) => entry.eventId === item.channelEventId);
|
|
166
168
|
if (!event) throw new Error("channel event disappeared before delivery preparation");
|
|
167
169
|
const binding = exactReplyBinding(channelPolicy.policy, event);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
runtime.outbox.
|
|
170
|
+
communication = reviewGroupResponse({ result, text, event, item, runtime, current });
|
|
171
|
+
if (communication?.suppressed) {
|
|
172
|
+
item.status = "completed"; item.completedAt = current;
|
|
173
|
+
} else {
|
|
174
|
+
if (!text) throw new Error("a channel obligation requires a non-empty response");
|
|
175
|
+
const voice = evaluateVoiceOutput(text);
|
|
176
|
+
if (!voice.ok) throw new Error("channel response contains a prohibited attachment or consciousness claim");
|
|
177
|
+
const idempotencyKey = "delivery:" + sha256([event.eventId, binding.id, event.chatId, event.threadId || "", event.replyTo || ""].join("\0")).slice(0, 32);
|
|
178
|
+
let outbox = runtime.outbox.find((entry) => entry.idempotencyKey === idempotencyKey);
|
|
179
|
+
if (!outbox) {
|
|
180
|
+
outbox = { outboxId: "gateway-outbox:" + sha256(idempotencyKey).slice(0, 32), queueId: item.queueId,
|
|
181
|
+
idempotencyKey, bindingId: binding.id, eventId: event.eventId, provider: event.provider, tenantId: event.tenantId,
|
|
182
|
+
accountId: event.accountId, chatId: event.chatId, threadId: event.threadId, replyTo: event.replyTo,
|
|
183
|
+
text, status: "prepared", attempts: 0, nextAttemptAt: current, createdAt: current, updatedAt: current,
|
|
184
|
+
deliveredAt: null, adapterReceipt: null, lastError: null, authority: "delivery-state-only" };
|
|
185
|
+
runtime.outbox.push(outbox);
|
|
186
|
+
}
|
|
187
|
+
item.status = "awaiting-delivery";
|
|
177
188
|
}
|
|
178
|
-
item.status = "awaiting-delivery";
|
|
179
189
|
} else {
|
|
180
190
|
item.status = result?.blocked || knowledgeGapRequest || premortemReview?.blocked || (executionReview && !executionReview.passed)
|
|
181
191
|
? "blocked" : "completed"; item.completedAt = current;
|
|
@@ -270,7 +280,7 @@ export async function completeGatewayRun({ root = process.cwd(), queueId, worker
|
|
|
270
280
|
appendReceipt(runtime, "run-terminal", item.queueId, current, { status: item.status, goalStepId: item.goalStepId || null }); runtime.revision += 1;
|
|
271
281
|
await writeGatewayStatePair(policy, runtime);
|
|
272
282
|
return { item, outbox: runtime.outbox.find((entry) => entry.queueId === item.queueId) || null,
|
|
273
|
-
clarification, exploration, selfHelp, selfHelpRequired, executionReview, premortemReview };
|
|
283
|
+
clarification, exploration, selfHelp, selfHelpRequired, executionReview, premortemReview, communication };
|
|
274
284
|
});
|
|
275
285
|
}
|
|
276
286
|
|
|
@@ -297,4 +307,3 @@ export async function failGatewayRun({ root = process.cwd(), queueId, workerId,
|
|
|
297
307
|
return { item, receipt: failure.receipt, policyEnabled: policy.enabled && !policy.killSwitch };
|
|
298
308
|
});
|
|
299
309
|
}
|
|
300
|
-
|
|
@@ -29,7 +29,16 @@ function unverified(reason) {
|
|
|
29
29
|
automaticRetry: false, completionVerified: false, authority: "context-only" };
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
function validHandoff(value) {
|
|
33
|
+
return value?.schema === "agentspine.host-context-handoff/v1"
|
|
34
|
+
&& ["additionalContext", "message"].includes(value.field)
|
|
35
|
+
&& ["claude", "codex", "generic", "king"].includes(value.host)
|
|
36
|
+
&& Number.isSafeInteger(value.bytes) && value.bytes > 0
|
|
37
|
+
&& /^[a-f0-9]{64}$/.test(value.digest || "");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function recordHookBriefingUse({ origin, root, handoff, now = new Date() }) {
|
|
41
|
+
if (!validHandoff(handoff)) return unverified("host-context-handoff-unavailable");
|
|
33
42
|
const proof = verified.get(origin);
|
|
34
43
|
if (!verified.delete(origin)) return unverified("host-briefing-origin-unavailable");
|
|
35
44
|
try {
|
|
@@ -51,10 +60,11 @@ export async function recordHookBriefingUse({ origin, root, now = new Date() })
|
|
|
51
60
|
return unverified("host-briefing-binding-mismatch");
|
|
52
61
|
}
|
|
53
62
|
const usage = await recordDeliveryBriefingUse({ root, requirementId,
|
|
54
|
-
preserveConsumed: true,
|
|
63
|
+
preserveConsumed: true, verifiedHostHandoff: true,
|
|
55
64
|
input: { origin: "verified-host-preflight", receiptId: receipt.id,
|
|
56
65
|
promptDigest: receipt.promptDigest, requirementId },
|
|
57
|
-
result: { briefingDigest: receipt.briefingDigest, sourceSnapshotDigest: receipt.bodyDigest
|
|
66
|
+
result: { briefingDigest: receipt.briefingDigest, sourceSnapshotDigest: receipt.bodyDigest,
|
|
67
|
+
handoff: structuredClone(handoff) }, now });
|
|
58
68
|
return { ...usage, verified: ["recorded", "duplicate"].includes(usage.status),
|
|
59
69
|
automaticRetry: false, completionVerified: false };
|
|
60
70
|
} catch { return unverified("host-briefing-service-unavailable"); }
|
|
@@ -58,6 +58,9 @@ export function hostFromInput(input) {
|
|
|
58
58
|
|
|
59
59
|
export function gatewayEnvironmentContext(env = process.env) {
|
|
60
60
|
if (env.AGENTSPINE_GATEWAY_CONTEXT !== "agentspine.gateway-start/v1") return null;
|
|
61
|
+
const portalRef = boundedId(env.AGENTSPINE_PORTAL_REF, "AGENTSPINE_PORTAL_REF");
|
|
62
|
+
const threadRef = boundedId(env.AGENTSPINE_THREAD_REF, "AGENTSPINE_THREAD_REF");
|
|
63
|
+
if (Boolean(portalRef) !== Boolean(threadRef)) throw new Error("gateway portal and thread references must be paired");
|
|
61
64
|
return {
|
|
62
65
|
host: boundedId(env.AGENTSPINE_HOST, "AGENTSPINE_HOST"),
|
|
63
66
|
entityId: boundedId(env.AGENTSPINE_ENTITY_ID, "AGENTSPINE_ENTITY_ID"),
|
|
@@ -71,7 +74,8 @@ export function gatewayEnvironmentContext(env = process.env) {
|
|
|
71
74
|
"AGENTSPINE_PLAN_DEFINITIONS_DIGEST"),
|
|
72
75
|
gatewayAttempt: positiveInteger(env.AGENTSPINE_GATEWAY_ATTEMPT, "AGENTSPINE_GATEWAY_ATTEMPT"),
|
|
73
76
|
eventId: boundedId(env.AGENTSPINE_CHANNEL_EVENT_ID, "AGENTSPINE_CHANNEL_EVENT_ID"),
|
|
74
|
-
provider: boundedId(env.AGENTSPINE_CHANNEL_PROVIDER, "AGENTSPINE_CHANNEL_PROVIDER")
|
|
77
|
+
provider: boundedId(env.AGENTSPINE_CHANNEL_PROVIDER, "AGENTSPINE_CHANNEL_PROVIDER"),
|
|
78
|
+
portalRef, threadRef
|
|
75
79
|
};
|
|
76
80
|
}
|
|
77
81
|
|
|
@@ -116,6 +120,11 @@ export async function runtimeScope(input, root, userStateRoot = null, catalog) {
|
|
|
116
120
|
const gateway = gatewayEnvironmentContext();
|
|
117
121
|
const suppliedAttempt = positiveInteger(supplied.gateway_attempt ?? supplied.gatewayAttempt,
|
|
118
122
|
"gatewayAttempt");
|
|
123
|
+
const suppliedPortalRef = supplied.portal_ref ?? supplied.portalRef;
|
|
124
|
+
const suppliedThreadRef = supplied.thread_ref ?? supplied.threadRef;
|
|
125
|
+
if (!gateway && [suppliedPortalRef, suppliedThreadRef].some((value) => value !== undefined && value !== null && value !== "")) {
|
|
126
|
+
throw new Error("portal timeline scope requires an authenticated gateway binding");
|
|
127
|
+
}
|
|
119
128
|
return {
|
|
120
129
|
entityId: boundedId(gatewayBound(gateway, "entityId",
|
|
121
130
|
supplied.entity_id ?? supplied.entityId, "entityId")
|
|
@@ -139,6 +148,8 @@ export async function runtimeScope(input, root, userStateRoot = null, catalog) {
|
|
|
139
148
|
supplied.plan_definitions_digest ?? supplied.planDefinitionsDigest,
|
|
140
149
|
"planDefinitionsDigest"), "planDefinitionsDigest"),
|
|
141
150
|
gatewayAttempt: gatewayBound(gateway, "gatewayAttempt", suppliedAttempt, "gatewayAttempt"),
|
|
151
|
+
portalRef: boundedId(gatewayBound(gateway, "portalRef", suppliedPortalRef, "portalRef"), "portalRef"),
|
|
152
|
+
threadRef: boundedId(gatewayBound(gateway, "threadRef", suppliedThreadRef, "threadRef"), "threadRef"),
|
|
142
153
|
host: gateway
|
|
143
154
|
? gatewayBound(gateway, "host", input.host ?? input.provider, "host")
|
|
144
155
|
: hostFromInput(input),
|
|
@@ -214,7 +225,8 @@ export function renderContext(event, catalog, briefing, signal = null, attention
|
|
|
214
225
|
sourceResolution: sourceDiagnostics,
|
|
215
226
|
lessonRecall: lessonRecall?.status === "recalled" ? {
|
|
216
227
|
status: "recalled", schema: lessonRecall.schema, receiptDigest: lessonRecall.receiptDigest,
|
|
217
|
-
items: lessonRecall.items,
|
|
228
|
+
items: lessonRecall.items, learning: lessonRecall.learning || [],
|
|
229
|
+
learningDiagnostics: lessonRecall.learningDiagnostics || null, omitted: lessonRecall.omitted,
|
|
218
230
|
instruction: lessonRecall.instruction, authority: "context-only"
|
|
219
231
|
} : lessonRecall?.status === "group-suppressed" ? {
|
|
220
232
|
status: "group-suppressed", items: [], authority: "context-only"
|
|
@@ -260,7 +272,8 @@ export function selfstarterInput(input) {
|
|
|
260
272
|
|
|
261
273
|
function channelEventInput(input) {
|
|
262
274
|
const gateway = gatewayEnvironmentContext();
|
|
263
|
-
const value = input.agent_spine_channel_event ?? (
|
|
275
|
+
const value = input.agent_spine_channel_event ?? (input.hook_event_name === "SessionStart"
|
|
276
|
+
&& gateway?.eventId && gateway?.provider
|
|
264
277
|
? { event_id: gateway.eventId, provider: gateway.provider } : null);
|
|
265
278
|
if (value === undefined || value === null) return null;
|
|
266
279
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("agent_spine_channel_event must be one object");
|
|
@@ -1,6 +1,116 @@
|
|
|
1
1
|
const BLUN_MESSAGE_MAX_BYTES = 1200;
|
|
2
2
|
const BLUN_BOUND_MARKER = "\n[optional runtime detail omitted: 1200-byte bound]";
|
|
3
3
|
|
|
4
|
+
function byteSize(value) {
|
|
5
|
+
return Buffer.byteLength(JSON.stringify(value));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function addRecallField(packet, key, value, maximum = 1020) {
|
|
9
|
+
if (value === undefined || value === null) return;
|
|
10
|
+
packet[key] = value;
|
|
11
|
+
if (byteSize(packet) <= maximum) return true;
|
|
12
|
+
delete packet[key];
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function sharedPrefix(values) {
|
|
17
|
+
let prefix = values[0] || "";
|
|
18
|
+
for (const value of values.slice(1)) {
|
|
19
|
+
while (prefix && !value.startsWith(prefix)) prefix = prefix.slice(0, -1);
|
|
20
|
+
}
|
|
21
|
+
return prefix.length >= 4 ? prefix : "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function compactCandidateRows(packet, candidates) {
|
|
25
|
+
if (candidates.rows.length < 2) return;
|
|
26
|
+
if (!candidates.prefixes) {
|
|
27
|
+
const digest = candidates.fields.indexOf("digest");
|
|
28
|
+
if (digest >= 0 && candidates.rows.every((row) => row[digest] === candidates.rows[0][digest])) {
|
|
29
|
+
candidates.common = { ...(candidates.common || {}), digest: candidates.rows[0][digest] };
|
|
30
|
+
candidates.fields.splice(digest, 1);
|
|
31
|
+
for (const row of candidates.rows) row.splice(digest, 1);
|
|
32
|
+
}
|
|
33
|
+
candidates.prefixes = candidates.fields.map((field, index) => {
|
|
34
|
+
const values = candidates.rows.map((row) => row[index]);
|
|
35
|
+
const prefix = ["id", "message", "session"].includes(field) ? sharedPrefix(values)
|
|
36
|
+
: field === "at" && values.every((value) => /^\d{4}-\d{2}-\d{2}T\d{2}:/.test(value))
|
|
37
|
+
? values[0].slice(0, 14) : "";
|
|
38
|
+
if (!prefix || !values.every((value) => value.startsWith(prefix))) return "";
|
|
39
|
+
for (const row of candidates.rows) row[index] = row[index].slice(prefix.length);
|
|
40
|
+
return prefix;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (packet.task) {
|
|
44
|
+
delete packet.task.status;
|
|
45
|
+
if (packet.task.lastVerifiedStep) delete packet.task.lastVerifiedStep.result;
|
|
46
|
+
}
|
|
47
|
+
const review = packet.feedbackReview;
|
|
48
|
+
if (review?.modelClarification) packet.feedbackReview = {
|
|
49
|
+
status: review.status, completionVerified: false, target: review.targetAssertionId,
|
|
50
|
+
question: review.modelClarification.question, model: true
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function compactFeedbackCandidates(packet) {
|
|
55
|
+
const candidates = packet.feedbackCandidates;
|
|
56
|
+
const proposal = packet.feedbackReview?.modelClarification;
|
|
57
|
+
if (proposal) for (const key of ["completionVerified", "provider", "replaces"]) delete proposal[key];
|
|
58
|
+
if (candidates && !Array.isArray(candidates)
|
|
59
|
+
&& Array.isArray(candidates.fields) && Array.isArray(candidates.rows)) {
|
|
60
|
+
compactCandidateRows(packet, candidates);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (!Array.isArray(candidates) || candidates.length < 2) return false;
|
|
64
|
+
const origins = ["provider", "session"];
|
|
65
|
+
const sharedKeys = origins.filter((key) =>
|
|
66
|
+
candidates.every((item) => item?.[key] === candidates[0]?.[key]));
|
|
67
|
+
const fields = ["id", "text", "digest", "message", "at",
|
|
68
|
+
...origins.filter((key) => !sharedKeys.includes(key))];
|
|
69
|
+
packet.feedbackCandidates = {
|
|
70
|
+
fields,
|
|
71
|
+
...(sharedKeys.length ? { common: Object.fromEntries(sharedKeys.map((key) =>
|
|
72
|
+
[key, candidates[0][key]])) } : {}),
|
|
73
|
+
rows: candidates.map((item) => fields.map((key) => item[key]))
|
|
74
|
+
};
|
|
75
|
+
compactCandidateRows(packet, packet.feedbackCandidates);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function preAnswerRecallCapsule(detailed) {
|
|
80
|
+
if (detailed?.event !== "UserPromptSubmit" || !detailed.loaded) return null;
|
|
81
|
+
const briefing = detailed.briefing;
|
|
82
|
+
const preflight = detailed.preflight?.briefing;
|
|
83
|
+
if (!briefing || !preflight) return null;
|
|
84
|
+
if (briefing.scope?.groupId !== null && briefing.scope?.groupId !== undefined) return null;
|
|
85
|
+
const omitted = [];
|
|
86
|
+
const packet = briefing.preAnswerRecall ? { ...briefing.preAnswerRecall } : {
|
|
87
|
+
schema: "agentspine.pre-answer-recall/v1",
|
|
88
|
+
order: "review-before-claims-and-actions",
|
|
89
|
+
authority: "context-only"
|
|
90
|
+
};
|
|
91
|
+
const mustRemember = (preflight.mustRemember || []).map((item) => ({
|
|
92
|
+
id: item.id, claim: item.claim, checksum: item.checksum
|
|
93
|
+
}));
|
|
94
|
+
if (mustRemember.length && !addRecallField(packet, "mustRemember", mustRemember)) {
|
|
95
|
+
if (!compactFeedbackCandidates(packet)
|
|
96
|
+
|| !addRecallField(packet, "mustRemember", mustRemember, BLUN_MESSAGE_MAX_BYTES)) {
|
|
97
|
+
omitted.push("mustRemember");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const retrieval = (preflight.retrieval || []).flatMap((provider) =>
|
|
101
|
+
(provider.items || []).map((item) => ({ providerId: provider.providerId,
|
|
102
|
+
id: item.id, revision: item.revision, claim: item.claim, source: item.source }))).slice(0, 3);
|
|
103
|
+
if (retrieval.length && !addRecallField(packet, "retrieval", retrieval)) {
|
|
104
|
+
if (!compactFeedbackCandidates(packet)
|
|
105
|
+
|| !addRecallField(packet, "retrieval", retrieval, BLUN_MESSAGE_MAX_BYTES)) {
|
|
106
|
+
omitted.push("retrieval");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
compactFeedbackCandidates(packet);
|
|
110
|
+
if (omitted.length && byteSize({ ...packet, omitted }) <= BLUN_MESSAGE_MAX_BYTES) packet.omitted = omitted;
|
|
111
|
+
return Object.keys(packet).length > 3 ? packet : null;
|
|
112
|
+
}
|
|
113
|
+
|
|
4
114
|
function compactPremortemRegistration(premortem, includeRoot = true) {
|
|
5
115
|
const root = premortem?.registration?.root;
|
|
6
116
|
const requirementId = premortem?.requirementId || premortem?.registration?.requirementId;
|
|
@@ -37,6 +147,8 @@ export function blunRuntimeContext(context) {
|
|
|
37
147
|
: detailed.instruction,
|
|
38
148
|
authority: "context-only"
|
|
39
149
|
};
|
|
150
|
+
const recall = preAnswerRecallCapsule(detailed);
|
|
151
|
+
if (recall) runtime.preAnswerRecall = recall;
|
|
40
152
|
if (detailed.signal && (detailed.signal.captured || detailed.signal.accepted || detailed.signal.reason)) {
|
|
41
153
|
runtime.signal = detailed.signal;
|
|
42
154
|
}
|
|
@@ -56,7 +168,9 @@ export function blunRuntimeMessage(context) {
|
|
|
56
168
|
const runtime = JSON.parse(blunRuntimeContext(context));
|
|
57
169
|
const warning = runtime.sourceResolution?.incomplete ? ` Warning: ${runtime.sourceResolution.warning}` : "";
|
|
58
170
|
const base = runtime.loaded
|
|
59
|
-
?
|
|
171
|
+
? runtime.preAnswerRecall
|
|
172
|
+
? `AgentSpine ready: ${runtime.indexedSources} sources indexed.${warning}`
|
|
173
|
+
: `AgentSpine ready: ${runtime.indexedSources} sources indexed. Load detailed continuity only on demand through session_briefing.${warning}`
|
|
60
174
|
: `AgentSpine unavailable${runtime.sourceResolution?.reason ? `: ${runtime.sourceResolution.reason}` : ""}. ${runtime.instruction}`;
|
|
61
175
|
const active = {};
|
|
62
176
|
if (runtime.signal && (runtime.signal.captured || runtime.signal.accepted
|
|
@@ -72,16 +186,24 @@ export function blunRuntimeMessage(context) {
|
|
|
72
186
|
const details = Object.keys(active).length === 0
|
|
73
187
|
? ""
|
|
74
188
|
: `\nActive AgentSpine runtime data: ${JSON.stringify(active)}`;
|
|
189
|
+
const recall = runtime.preAnswerRecall
|
|
190
|
+
? `\n${JSON.stringify(runtime.preAnswerRecall)}`
|
|
191
|
+
: "";
|
|
75
192
|
const root = runtime.premortem?.registration?.root;
|
|
76
193
|
const instruction = typeof root === "string"
|
|
77
194
|
? runtime.premortem?.instruction?.replace("registration.root", () => `root ${JSON.stringify(root)}`)
|
|
78
195
|
: runtime.premortem?.instruction;
|
|
79
196
|
const premortem = instruction ? `\n${instruction}` : "";
|
|
80
|
-
const message = `${base}${details}${premortem}`;
|
|
197
|
+
const message = `${base}${recall}${details}${premortem}`;
|
|
81
198
|
if (Buffer.byteLength(message) <= BLUN_MESSAGE_MAX_BYTES) return message;
|
|
82
|
-
const compact = `${base}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem)}`;
|
|
199
|
+
const compact = `${base}${recall}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem)}`;
|
|
83
200
|
if (Buffer.byteLength(compact) <= BLUN_MESSAGE_MAX_BYTES) return compact;
|
|
84
|
-
|
|
201
|
+
if (!runtime.preAnswerRecall) {
|
|
202
|
+
return `${base}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem, false)}`;
|
|
203
|
+
}
|
|
204
|
+
const recallOnly = `${base}${recall}${BLUN_BOUND_MARKER}`;
|
|
205
|
+
if (Buffer.byteLength(recallOnly) <= BLUN_MESSAGE_MAX_BYTES) return recallOnly;
|
|
206
|
+
return Buffer.byteLength(recall)<=BLUN_MESSAGE_MAX_BYTES+1?recall.slice(1):`${base}\nRecall unavailable.`;
|
|
85
207
|
}
|
|
86
208
|
|
|
87
209
|
export function hookOutput(event, context, env = process.env) {
|
|
@@ -130,7 +252,9 @@ export function lifecycleOutput(event, artifactGuard, premortem, deliveryVerific
|
|
|
130
252
|
if (lessonRecall?.status === "recalled") {
|
|
131
253
|
messages.push(JSON.stringify({
|
|
132
254
|
schema: lessonRecall.schema, receiptDigest: lessonRecall.receiptDigest,
|
|
133
|
-
instruction: lessonRecall.instruction, items: lessonRecall.items,
|
|
255
|
+
instruction: lessonRecall.instruction, items: lessonRecall.items,
|
|
256
|
+
learning: lessonRecall.learning || [], learningDiagnostics: lessonRecall.learningDiagnostics || null,
|
|
257
|
+
omitted: lessonRecall.omitted,
|
|
134
258
|
authority: "context-only"
|
|
135
259
|
}));
|
|
136
260
|
}
|
|
@@ -77,14 +77,16 @@ export async function finalizeUserPromptSessionTimeline({
|
|
|
77
77
|
}) {
|
|
78
78
|
const consumed = await consumeTimelineHostOrigin({ event: "UserPromptSubmit", input, scope, resolvedSources,
|
|
79
79
|
preflight, prompt, environment: process.env, now });
|
|
80
|
-
if (!consumed?.consumed) return { preflightConsumed: false,
|
|
80
|
+
if (!consumed?.consumed) return { preflightConsumed: false, briefingOrigin: null,
|
|
81
|
+
timeline: unavailable("preflight-receipt-unavailable") };
|
|
81
82
|
try {
|
|
82
|
-
return { preflightConsumed: true,
|
|
83
|
+
return { preflightConsumed: true, briefingOrigin: consumed.briefingOrigin,
|
|
84
|
+
timeline: await captureSessionTimelineLifecycle({
|
|
83
85
|
root, event: "UserPromptSubmit", input, scope, hostHome: resolvedSources.hostHome,
|
|
84
86
|
hostOrigin: consumed.origin, clock: () => new Date(now)
|
|
85
87
|
}) };
|
|
86
88
|
} catch (error) {
|
|
87
|
-
return { preflightConsumed: true, timeline: {
|
|
89
|
+
return { preflightConsumed: true, briefingOrigin: consumed.briefingOrigin, timeline: {
|
|
88
90
|
schema: "agentspine.session-timeline/v1", status: "degraded", reason: error.message, authority: AUTHORITY
|
|
89
91
|
} };
|
|
90
92
|
}
|
|
@@ -247,7 +247,7 @@ export async function resolveIndexedMemory({ root, scope = {}, env = process.env
|
|
|
247
247
|
diagnostics.cacheHits += Number(index.cacheHit);
|
|
248
248
|
diagnostics.cacheMisses += Number(!index.cacheHit);
|
|
249
249
|
const entries = parseMemoryIndex(index.buffer.toString("utf8"), index.path, canonicalRoot);
|
|
250
|
-
if (entries.length > MAX_INDEXED_LINKS) throw new Error(`
|
|
250
|
+
if (entries.length > MAX_INDEXED_LINKS) throw new Error(`MEMORY.md indexes more than ${MAX_INDEXED_LINKS} direct files`);
|
|
251
251
|
diagnostics.indexed = entries.length;
|
|
252
252
|
const sources = [{ path: index.path, relativePath: "MEMORY.md", snapshot: index, relevance: "index" }];
|
|
253
253
|
const selected = [];
|
|
@@ -279,7 +279,7 @@ export async function resolveIndexedMemory({ root, scope = {}, env = process.env
|
|
|
279
279
|
}
|
|
280
280
|
checkDeadline();
|
|
281
281
|
const finalIndex = await safeIndexedSnapshot(canonicalRoot, "MEMORY.md", index.record, hooks);
|
|
282
|
-
if (finalIndex.rejected || finalIndex.metadata.sha256 !== index.metadata.sha256) throw new Error("
|
|
282
|
+
if (finalIndex.rejected || finalIndex.metadata.sha256 !== index.metadata.sha256) throw new Error("MEMORY.md changed during indexed resolution; retry the hook");
|
|
283
283
|
await mutateCache(env, (value) => {
|
|
284
284
|
const records = { "MEMORY.md": index.record };
|
|
285
285
|
for (const source of sources.slice(1)) records[source.relativePath] = source.snapshot.record;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { performance } from "node:perf_hooks";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { targetSnapshot } from "./delivery-target.js";
|
|
6
|
+
import { loadLearning } from "./learning-storage.js";
|
|
7
|
+
import { digest, exactScope, normalizeScope, activeEvaluationBinding } from "./learning-scope-targets.js";
|
|
8
|
+
import { recordLearningMeasurement } from "./learning-measurements.js";
|
|
9
|
+
import { CATALOG_SCHEMA, catalogScanPolicy } from "./catalog.js";
|
|
10
|
+
|
|
11
|
+
const SCHEMA = "agentspine.artifact-checks/v1";
|
|
12
|
+
const PROTOCOL = "agentspine.artifact-evaluator/v1:sha256-or-absent:two-pass:16-cases:2-mib-per-file";
|
|
13
|
+
const PROTOCOL_DIGEST = digest(PROTOCOL);
|
|
14
|
+
// One implementation is ONE principal, even under different aliases or paths.
|
|
15
|
+
const PRINCIPAL_DIGEST = digest({ implementation: PROTOCOL });
|
|
16
|
+
const METRIC = { name: "artifact-check-pass-rate", direction: "higher" };
|
|
17
|
+
|
|
18
|
+
export function artifactEvaluationPlan(spec) {
|
|
19
|
+
if (!spec || spec.schema !== SCHEMA || Object.keys(spec).some((key) => !["schema", "checks"].includes(key))
|
|
20
|
+
|| !Array.isArray(spec.checks) || spec.checks.length < 1 || spec.checks.length > 16) {
|
|
21
|
+
throw new Error("artifact evaluation requires a known schema and 1 to 16 explicit checks");
|
|
22
|
+
}
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
const checks = spec.checks.map((check) => {
|
|
25
|
+
if (!check || Object.keys(check).some((key) => !["path", "sha256", "blocking"].includes(key))
|
|
26
|
+
|| typeof check.path !== "string" || check.path.length > 240
|
|
27
|
+
|| !/^[A-Za-z0-9_-][A-Za-z0-9_./-]*$/.test(check.path)
|
|
28
|
+
|| check.path.split("/").some((part) => !part || part === "." || part === "..")
|
|
29
|
+
|| !(check.sha256 === null || /^[a-f0-9]{64}$/.test(check.sha256 || ""))
|
|
30
|
+
|| typeof check.blocking !== "boolean") {
|
|
31
|
+
throw new Error("artifact checks require unique project-relative paths, SHA-256 or null, and explicit blocking flags");
|
|
32
|
+
}
|
|
33
|
+
const key = check.path.toLowerCase();
|
|
34
|
+
if (seen.has(key)) throw new Error("artifact check paths must be unique across platforms");
|
|
35
|
+
seen.add(key);
|
|
36
|
+
return { path: check.path, sha256: check.sha256, blocking: check.blocking };
|
|
37
|
+
}).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
38
|
+
const normalized = { schema: SCHEMA, checks };
|
|
39
|
+
return { spec: normalized, datasetDigest: digest(normalized), protocolDigest: PROTOCOL_DIGEST,
|
|
40
|
+
principalDigest: PRINCIPAL_DIGEST, metric: { ...METRIC }, minCases: checks.length,
|
|
41
|
+
authority: "context-only" };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Local evaluator only. No shell, model scores, automatic registration, source
|
|
45
|
+
// discovery, outcome consumption, promotion or configuration changes.
|
|
46
|
+
export async function measureLearningArtifacts({ root = process.cwd(), spec, id, learningId, evaluationId,
|
|
47
|
+
phase, scope, evaluatorId, runId, confirmLocalMeasurement = false } = {}) {
|
|
48
|
+
if (confirmLocalMeasurement !== true) throw new Error("artifact measurement requires explicit local confirmation");
|
|
49
|
+
const started = performance.now();
|
|
50
|
+
const plan = artifactEvaluationPlan(spec);
|
|
51
|
+
const canonical = await realpath(root);
|
|
52
|
+
if (canonical !== resolve(root)) throw new Error("artifact project root must be canonical and non-symbolic");
|
|
53
|
+
// State-only catalog: measurement contracts need no document discovery.
|
|
54
|
+
// Never take this catalog from the caller; its root is resolved above.
|
|
55
|
+
const catalog = { schema: CATALOG_SCHEMA, root: canonical, generatedAt: new Date().toISOString(),
|
|
56
|
+
scanPolicy: catalogScanPolicy(canonical), preservation: "source-files-are-read-only",
|
|
57
|
+
documents: [], conflicts: [], summary: { total: 0, protected: 0, conflicts: 0, byLayer: {} } };
|
|
58
|
+
const { learning } = await loadLearning(canonical, catalog);
|
|
59
|
+
const evaluation = learning.evaluations.find((entry) => entry.id === evaluationId && entry.learningId === learningId);
|
|
60
|
+
const binding = normalizeScope(scope);
|
|
61
|
+
if (!evaluation || !exactScope(evaluation.scope, binding) || !activeEvaluationBinding(learning, evaluation)) {
|
|
62
|
+
throw new Error("artifact evaluation requires an active exact-scope local contract");
|
|
63
|
+
}
|
|
64
|
+
if (evaluation.benchmark.datasetDigest !== plan.datasetDigest
|
|
65
|
+
|| evaluation.benchmark.protocolDigest !== plan.protocolDigest
|
|
66
|
+
|| evaluation.benchmark.minCases !== plan.minCases
|
|
67
|
+
|| evaluation.metric.name !== METRIC.name || evaluation.metric.direction !== METRIC.direction) {
|
|
68
|
+
throw new Error("artifact checks or measurement protocol differ from the frozen evaluation");
|
|
69
|
+
}
|
|
70
|
+
if (!evaluation.evaluatorRoots.some((entry) => entry.evaluatorId === evaluatorId
|
|
71
|
+
&& entry.principalDigest === PRINCIPAL_DIGEST)) {
|
|
72
|
+
throw new Error("artifact evaluator must use its single locally registered implementation principal");
|
|
73
|
+
}
|
|
74
|
+
const trial = evaluation.initialTrials?.[phase]?.find((entry) => entry.evaluatorId === evaluatorId);
|
|
75
|
+
if (!trial || trial.runId !== runId) throw new Error("artifact measurement requires the precommitted initial trial");
|
|
76
|
+
if (learning.measurements.some((entry) => entry.id === id
|
|
77
|
+
|| (entry.measurement.evaluatorId === evaluatorId && entry.measurement.runId === runId))) {
|
|
78
|
+
throw new Error("artifact trial was already measured; it cannot be rerun or replaced");
|
|
79
|
+
}
|
|
80
|
+
const snapshots = [];
|
|
81
|
+
for (const check of plan.spec.checks) {
|
|
82
|
+
const snapshot = await targetSnapshot(canonical, check.path);
|
|
83
|
+
if (snapshot.omitted) throw new Error("artifact exceeds the bounded measurement budget");
|
|
84
|
+
snapshots.push(snapshot);
|
|
85
|
+
}
|
|
86
|
+
// Recheck the complete bounded cohort, not just each file during its own read.
|
|
87
|
+
for (let index = 0; index < snapshots.length; index++) {
|
|
88
|
+
const current = await targetSnapshot(canonical, plan.spec.checks[index].path);
|
|
89
|
+
if (JSON.stringify(current) !== JSON.stringify(snapshots[index])) {
|
|
90
|
+
throw new Error("artifact cohort changed during measurement");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const checks = plan.spec.checks.map((check, index) => ({
|
|
94
|
+
path: check.path, expectedDigest: check.sha256,
|
|
95
|
+
observedDigest: snapshots[index].sha256, bytes: snapshots[index].bytes,
|
|
96
|
+
passed: snapshots[index].sha256 === check.sha256, blocking: check.blocking
|
|
97
|
+
}));
|
|
98
|
+
const metric = { ...METRIC, value: checks.filter((check) => check.passed).length / checks.length,
|
|
99
|
+
blockingDefects: checks.filter((check) => !check.passed && check.blocking).length };
|
|
100
|
+
const measuredAt = new Date().toISOString();
|
|
101
|
+
const report = { schema: "agentspine.artifact-measurement/v1", observationId: randomUUID(), evaluationId, learningId,
|
|
102
|
+
scope: binding, evaluatorId, runId, phase, datasetDigest: plan.datasetDigest,
|
|
103
|
+
protocolDigest: PROTOCOL_DIGEST, measuredAt, checks, metric, authority: "context-only" };
|
|
104
|
+
const sourceDigest = digest(report);
|
|
105
|
+
const recorded = await recordLearningMeasurement({ root: canonical, id, learningId, evaluationId, phase,
|
|
106
|
+
scope: binding, metric, measurement: { kind: "objective", evaluatorId, runId, sourceDigest },
|
|
107
|
+
coverage: { datasetDigest: plan.datasetDigest, caseCount: checks.length },
|
|
108
|
+
measuredAt, confirmLocalMeasurement: true, catalog });
|
|
109
|
+
return { ...recorded, report, sourceDigest,
|
|
110
|
+
diagnostics: { elapsedMs: performance.now() - started,
|
|
111
|
+
inspectedFiles: checks.length, inspectedBytes: snapshots.reduce((sum, item) => sum + item.bytes, 0) * 2,
|
|
112
|
+
broadScan: false, commandsExecuted: 0 },
|
|
113
|
+
completionVerified: false, automaticRetry: false, authority: "context-only" };
|
|
114
|
+
}
|