@moretea-labs/forge 1.7.2 → 1.8.0
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/AGENTS.md +58 -62
- package/CHANGELOG.md +26 -0
- package/CLAUDE.md +42 -62
- package/README.md +2 -2
- package/SKILL.md +0 -1
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/adapters/browser/index.ts +2 -0
- package/adapters/chatgpt/browser-delivery-host.ts +71 -0
- package/adapters/chatgpt/browser-delivery-runtime.ts +783 -0
- package/adapters/chatgpt/controller-binding-store.ts +55 -0
- package/adapters/chatgpt/controller-host.ts +119 -0
- package/adapters/chatgpt/controller-round-host.ts +78 -0
- package/adapters/chatgpt/controller-round-settlement-store.ts +45 -0
- package/adapters/chatgpt/provider-delivery.ts +113 -0
- package/adapters/chatgpt/work-conversation-binding-store.ts +192 -0
- package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
- package/adapters/computer/desktop-operator-contract.ts +7 -0
- package/adapters/computer/desktop-operator-discovery.ts +201 -0
- package/adapters/computer/desktop-operator-negotiation.ts +174 -0
- package/adapters/computer/desktop-operator-provider.ts +312 -0
- package/adapters/computer/index.ts +1 -0
- package/adapters/computer/interaction-target-authority.ts +944 -0
- package/adapters/controller-process/binding-store.ts +34 -0
- package/adapters/controller-process/controller-host.ts +26 -0
- package/adapters/mcp/access-mode.ts +132 -0
- package/adapters/mcp/audit.ts +32 -0
- package/adapters/mcp/auth.ts +407 -0
- package/adapters/mcp/controller-round-compatibility.ts +184 -0
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +292 -0
- package/adapters/mcp/instructions.ts +36 -0
- package/adapters/mcp/legacy-context.ts +18 -0
- package/adapters/mcp/multi-repository.ts +437 -0
- package/adapters/mcp/oauth.ts +391 -0
- package/adapters/mcp/paths.ts +140 -0
- package/adapters/mcp/policy.ts +232 -0
- package/adapters/mcp/proxy-env.ts +62 -0
- package/adapters/mcp/readiness-projection.ts +24 -0
- package/adapters/mcp/redaction.ts +21 -0
- package/adapters/mcp/repo.ts +24 -0
- package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +829 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +191 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +147 -0
- package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +207 -0
- package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +411 -0
- package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
- package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
- package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
- package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/process-tools.ts +289 -0
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +76 -0
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +268 -0
- package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
- package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +110 -0
- package/adapters/mcp/runtime-gateway/result-adapter.ts +108 -0
- package/adapters/mcp/runtime-gateway/router.ts +728 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1251 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +634 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +68 -0
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +186 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +25 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +870 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +3186 -0
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +502 -0
- package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
- package/adapters/mcp/server.ts +1048 -0
- package/adapters/mcp/setup.ts +791 -0
- package/adapters/mcp/tool-capability-cache.ts +87 -0
- package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5265 -0
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +150 -0
- package/adapters/mcp/tool-mapping/repository-tools.ts +1691 -0
- package/adapters/mcp/tool-mapping/tools.ts +9 -0
- package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
- package/adapters/mcp/toolset-names.ts +74 -0
- package/adapters/mcp/toolset-selection.ts +41 -0
- package/adapters/mcp/toolset.ts +336 -0
- package/adapters/mcp/transports/http.ts +1456 -0
- package/adapters/mcp/transports/session-registry.ts +513 -0
- package/adapters/mcp/transports/stdio.ts +8 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +139 -0
- package/adapters/mcp/types.ts +41 -0
- package/assets/AGENTS.md +2 -16
- package/assets/CLAUDE.md +2 -16
- package/assets/hooks/AGENTS.md +3 -14
- package/assets/hooks/CLAUDE.md +3 -14
- package/assets/hooks/hook-input.sh +9 -2
- package/assets/hooks/lib/workflow-state.sh +28 -10
- package/assets/hooks/prompt-guard.sh +63 -37
- package/assets/hooks/security-sentinel.sh +2 -1
- package/assets/hooks/session-start-context.sh +7 -5
- package/assets/hooks/stop-orchestrator.sh +13 -3
- package/assets/initializer-question-pack.v4.json +11 -7
- package/assets/partials/05-workflow.partial.md +18 -73
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -2
- package/assets/partials-agents/04-task-protocol.partial.md +14 -59
- package/assets/partials-agents/06-quality-safety.partial.md +11 -16
- package/assets/partials-agents/08-deep-docs.partial.md +1 -2
- package/assets/plan-map.json +11 -11
- package/assets/plugin-registry.v1.json +9 -3
- package/assets/plugin-trust-policy.v1.json +6 -0
- package/assets/recovery/ForgeRecovery.ps1 +100 -0
- package/assets/recovery/forge-wsl-rescue +271 -0
- package/assets/reference-configs/development-protocol.md +11 -15
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/global-working-rules.md +9 -1
- package/assets/reference-configs/harness-overview.md +22 -112
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +2 -2
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/architecture-event.ts +3 -34
- package/assets/templates/helpers/architecture-queue.sh +61 -10
- package/assets/templates/helpers/archive-workflow.sh +90 -180
- package/assets/templates/helpers/capability-config.ts +8 -11
- package/assets/templates/helpers/capability-resolver.ts +37 -19
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +1 -9
- package/assets/templates/helpers/check-task-sync.sh +82 -11
- package/assets/templates/helpers/check-task-workflow.sh +1 -3
- package/assets/templates/helpers/context-contract-sync.sh +1 -12
- package/assets/templates/helpers/contract-worktree.sh +26 -24
- package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
- package/assets/templates/helpers/inspect-project-state.ts +1 -1
- package/assets/templates/helpers/migrate-project-template.sh +1 -1
- package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
- package/assets/templates/helpers/new-plan.sh +2 -2
- package/assets/templates/helpers/plan-to-todo.sh +3 -31
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/switch-plan.sh +1 -1
- package/assets/templates/helpers/workflow-contract.ts +1 -0
- package/assets/workflow-contract.v1.json +63 -171
- package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
- package/docs/architecture/CURRENT.md +148 -13
- package/docs/architecture/EVOLUTION.md +13 -0
- package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
- package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
- package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
- package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +35 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +296 -0
- package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
- package/docs/architecture/domains/verification.md +7 -0
- package/docs/architecture/domains/workflow-engine.md +1 -1
- package/docs/architecture/index.md +3 -3
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
- package/docs/forge-chatgpt-mcp-setup.md +5 -3
- package/docs/forge-plugin-management.md +20 -4
- package/docs/forge-runtime-self-healing-loop.md +2 -0
- package/docs/operations/benchmark-cross-version-freeze.md +38 -0
- package/docs/operations/controller-browser-plugin.md +3 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/platform-support.md +16 -8
- package/docs/operations/platform-support.zh-CN.md +2 -2
- package/docs/operations/standalone-disaster-recovery.md +26 -1
- package/docs/operations/uu-remote-rescue.md +41 -0
- package/docs/operations/windows-wsl-host-rescue.md +133 -0
- package/docs/public-usage-guide.md +1 -1
- package/docs/public-usage-guide.zh-CN.md +1 -1
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/02-connect-chatgpt.md +4 -4
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +23 -14
- package/packages/kernel/controller/api/index.ts +2 -0
- package/packages/kernel/controller/application/controller-round-service.ts +29 -0
- package/packages/kernel/controller/application/controller-service.ts +30 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +308 -0
- package/packages/kernel/controller/domain/controller-round.ts +107 -0
- package/packages/kernel/controller/domain/execution-quality.ts +133 -0
- package/packages/kernel/controller/domain/types.ts +56 -0
- package/packages/kernel/controller/index.ts +1 -0
- package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +1384 -0
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +578 -0
- package/packages/kernel/controller/ports/controller-host.ts +16 -0
- package/packages/kernel/goal/api/index.ts +1 -0
- package/packages/kernel/goal/domain/types.ts +40 -0
- package/packages/kernel/goal/index.ts +1 -0
- package/packages/kernel/identity/api/index.ts +5 -0
- package/packages/kernel/identity/application/identity-service.ts +67 -0
- package/packages/kernel/identity/domain/scope.ts +63 -0
- package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
- package/packages/kernel/identity/domain/types.ts +44 -0
- package/packages/kernel/identity/domain/workspace.ts +56 -0
- package/packages/kernel/identity/index.ts +1 -0
- package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
- package/packages/kernel/memory/api/index.ts +5 -0
- package/packages/kernel/memory/application/experience-service.ts +118 -0
- package/packages/kernel/memory/application/outcome-service.ts +77 -0
- package/packages/kernel/memory/domain/experience.ts +103 -0
- package/packages/kernel/memory/domain/operational-prior.ts +92 -0
- package/packages/kernel/memory/index.ts +1 -0
- package/packages/kernel/progression/api/index.ts +2 -0
- package/packages/kernel/progression/application/projector.ts +211 -0
- package/packages/kernel/progression/domain/types.ts +116 -0
- package/packages/kernel/progression/index.ts +1 -0
- package/packages/kernel/scheduler/api/index.ts +6 -0
- package/packages/kernel/scheduler/application/continuation-service.ts +212 -0
- package/packages/kernel/scheduler/application/eligibility.ts +252 -0
- package/packages/kernel/scheduler/application/schedule-service.ts +24 -0
- package/packages/kernel/scheduler/application/settlement.ts +197 -0
- package/packages/kernel/scheduler/domain/continuation.ts +38 -0
- package/packages/kernel/scheduler/domain/schedule.ts +149 -0
- package/packages/kernel/scheduler/index.ts +1 -0
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +38 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +785 -0
- package/packages/kernel/work/api/index.ts +15 -0
- package/packages/kernel/work/application/work-service.ts +148 -0
- package/packages/kernel/work/domain/admission-policy.ts +34 -0
- package/packages/kernel/work/domain/check-receipt.ts +43 -0
- package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
- package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
- package/packages/kernel/work/domain/engineering-design.ts +281 -0
- package/packages/kernel/work/domain/engineering-profile.ts +242 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +254 -0
- package/packages/kernel/work/domain/execution-snapshot.ts +33 -0
- package/packages/kernel/work/domain/implementation-review.ts +510 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +202 -0
- package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
- package/packages/kernel/work/domain/state-machine.ts +259 -0
- package/packages/kernel/work/domain/types.ts +528 -0
- package/packages/kernel/work/index.ts +1 -0
- package/packages/kernel/work/infrastructure/work-contract-store.ts +1876 -0
- package/packages/kernel/work/ports/work-contract-store.ts +18 -0
- package/packages/plugin-runtime/browser/index.ts +3 -0
- package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
- package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
- package/packages/plugin-runtime/browser/session-authority.ts +61 -0
- package/packages/plugin-runtime/computer/index.ts +6 -0
- package/packages/plugin-runtime/computer/provider-error.ts +26 -0
- package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
- package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
- package/packages/plugin-runtime/computer/provider.ts +19 -0
- package/packages/plugin-runtime/computer/target-authority.ts +190 -0
- package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
- package/packages/plugin-runtime/external/index.ts +1 -0
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +457 -0
- package/packages/plugin-runtime/index.ts +3 -0
- package/packages/protocols/browser/index.ts +1 -0
- package/packages/protocols/browser/session.ts +98 -0
- package/packages/protocols/computer/contract.ts +199 -0
- package/packages/protocols/computer/index.ts +1 -0
- package/packages/protocols/failure/contract.ts +158 -0
- package/packages/protocols/failure/index.ts +1 -0
- package/packages/protocols/handoff/index.ts +1 -0
- package/packages/protocols/handoff/status.ts +22 -0
- package/packages/protocols/mcp/execution-context.ts +11 -0
- package/packages/protocols/mcp/index.ts +2 -0
- package/packages/protocols/mcp/tool-contract.ts +42 -0
- package/packages/workflow-runtime/api/index.ts +2 -0
- package/packages/workflow-runtime/application/interpreter.ts +342 -0
- package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
- package/packages/workflow-runtime/index.ts +1 -0
- package/scripts/assemble-template.ts +1 -1
- package/scripts/benchmark-computer-hotpath.ts +255 -0
- package/scripts/benchmark-controller-round2.ts +54 -2
- package/scripts/benchmark-ios-agent-device.ts +3 -6
- package/scripts/benchmark-mcp-transport.ts +3 -4
- package/scripts/benchmark-operational-memory-activation.ts +235 -0
- package/scripts/benchmark-operational-shadow.ts +28 -0
- package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
- package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
- package/scripts/canary-controller-semantic-wait.ts +195 -0
- package/scripts/canary-global-hook.sh +2 -2
- package/scripts/check-mcp-compatibility.ts +173 -7
- package/scripts/check-platform-support.mjs +28 -2
- package/scripts/check-public-docs.sh +1 -1
- package/scripts/check-release-readiness.sh +1 -1
- package/scripts/check-repository-hygiene.mjs +92 -0
- package/scripts/check-runtime-architecture.mjs +1206 -95
- package/scripts/check-source-duplication.mjs +9 -1
- package/scripts/check-tarball-install-smoke.sh +98 -15
- package/scripts/controller-ngrok-rotation.sh +5 -4
- package/scripts/create-project-dirs.sh +10 -74
- package/scripts/forge-local-recovery-helper.mjs +204 -0
- package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
- package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
- package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
- package/scripts/hook-shim.sh +2 -2
- package/scripts/init-project.sh +12 -70
- package/scripts/install-desktop-operator-registration.ts +4 -2
- package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
- package/scripts/install-standalone-recovery.ts +122 -10
- package/scripts/install-uu-remote-rescue-registration.ts +74 -0
- package/scripts/install-windows-host-recovery-registration.ts +22 -0
- package/scripts/lib/controller-home-env.sh +6 -3
- package/scripts/lib/project-init-lib.sh +39 -582
- package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
- package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
- package/scripts/open-source-audit-allowlist.txt +12 -1
- package/scripts/portability-bindings.mjs +70 -0
- package/scripts/run-bounded-command.mjs +55 -0
- package/scripts/run-bun-test-file.ts +22 -6
- package/scripts/run-governed-gate.ts +4 -1
- package/scripts/smoke-mcp-http-runtime.ts +1 -1
- package/scripts/smoke-runtime-recovery.ts +34 -1
- package/scripts/smoke-schedule-engine.ts +1 -1
- package/scripts/stage-runtime-release.ts +6 -1
- package/scripts/test-governance.ts +51 -2
- package/src/cli/agent-jobs/job-manager.ts +10 -1
- package/src/cli/chatgpt-browser/bind-server.ts +2 -1
- package/src/cli/chatgpt-browser/binding.ts +20 -10
- package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
- package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
- package/src/cli/chatgpt-browser/engine.ts +10 -11
- package/src/cli/chatgpt-browser/native-provider.ts +24 -83
- package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
- package/src/cli/chatgpt-browser/types.ts +1 -0
- package/src/cli/commands/bootstrap-control.ts +334 -0
- package/src/cli/commands/brain-assistant.ts +38 -0
- package/src/cli/commands/brain.ts +193 -40
- package/src/cli/commands/chatgpt.ts +127 -0
- package/src/cli/commands/computer.ts +437 -0
- package/src/cli/commands/doctor.ts +18 -1
- package/src/cli/commands/init-hook.ts +71 -61
- package/src/cli/commands/init.ts +3 -1
- package/src/cli/commands/mcp.ts +16 -10
- package/src/cli/commands/plugin.ts +38 -12
- package/src/cli/commands/recovery.ts +493 -80
- package/src/cli/commands/runtime.ts +9 -4
- package/src/cli/commands/setup-profile.ts +89 -39
- package/src/cli/commands/status.ts +2 -1
- package/src/cli/controller/check-runner.ts +487 -98
- package/src/cli/controller/context/types.ts +7 -1
- package/src/cli/controller/context-pack.ts +23 -3
- package/src/cli/controller/issue-store.ts +1 -1
- package/src/cli/controller/systemd-user.ts +110 -0
- package/src/cli/controller/types.ts +10 -70
- package/src/cli/controller/worklog.ts +67 -13
- package/src/cli/editing/edit-operation-contract.ts +92 -0
- package/src/cli/editing/edit-session.ts +289 -13
- package/src/cli/github/plugin.ts +17 -12
- package/src/cli/hook/route-registry.ts +3 -5
- package/src/cli/hook/runtime.ts +49 -3
- package/src/cli/index.ts +3 -0
- package/src/cli/local-bridge/connector-freshness.ts +2 -2
- package/src/cli/local-bridge/console-automations.ts +2 -2
- package/src/cli/local-bridge/facade-api.ts +41 -14
- package/src/cli/local-bridge/job-store.ts +1 -1
- package/src/cli/local-bridge/server.ts +24 -27
- package/src/cli/mcp/access-mode.ts +2 -132
- package/src/cli/mcp/access-tools.ts +2 -387
- package/src/cli/mcp/audit.ts +2 -32
- package/src/cli/mcp/auth.ts +2 -404
- package/src/cli/mcp/instructions.ts +2 -34
- package/src/cli/mcp/legacy-context.ts +2 -16
- package/src/cli/mcp/legacy-tool-service.ts +2 -5308
- package/src/cli/mcp/multi-repository.ts +2 -436
- package/src/cli/mcp/oauth.ts +2 -375
- package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
- package/src/cli/mcp/paths.ts +2 -140
- package/src/cli/mcp/policy.ts +2 -232
- package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
- package/src/cli/mcp/proxy-env.ts +2 -62
- package/src/cli/mcp/readiness-projection.ts +2 -24
- package/src/cli/mcp/redaction.ts +2 -21
- package/src/cli/mcp/repo.ts +2 -24
- package/src/cli/mcp/repository-tools.ts +2 -1613
- package/src/cli/mcp/server.ts +2 -951
- package/src/cli/mcp/setup.ts +2 -737
- package/src/cli/mcp/tool-capability-cache.ts +2 -87
- package/src/cli/mcp/tool-contract.ts +2 -14
- package/src/cli/mcp/tools.ts +2 -9
- package/src/cli/mcp/toolset-names.ts +2 -70
- package/src/cli/mcp/toolset-selection.ts +2 -41
- package/src/cli/mcp/toolset.ts +2 -336
- package/src/cli/mcp/transports/AGENTS.md +1 -10
- package/src/cli/mcp/transports/CLAUDE.md +1 -10
- package/src/cli/mcp/transports/http.ts +2 -1414
- package/src/cli/mcp/transports/session-registry.ts +2 -490
- package/src/cli/mcp/transports/stdio.ts +2 -8
- package/src/cli/mcp/types.ts +2 -41
- package/src/cli/mcp/umbrella-tools.ts +2 -117
- package/src/cli/repositories/command-executor.ts +64 -18
- package/src/cli/repositories/command-scope.ts +117 -1
- package/src/cli/repositories/controller-home.ts +119 -1
- package/src/cli/repositories/identity.ts +13 -0
- package/src/cli/repositories/registry.ts +68 -49
- package/src/cli/repositories/repository-snapshot.ts +53 -7
- package/src/cli/repositories/runtime-storage.ts +27 -2
- package/src/cli/repositories/safe-patch.ts +34 -38
- package/src/cli/repositories/selected-path-actions.ts +22 -2
- package/src/cli/repositories/structured-git.ts +105 -25
- package/src/cli/runtime/helper-runner.ts +7 -0
- package/src/cli/runtime-invocation.ts +8 -1
- package/src/cli/tools/codegraph.ts +44 -25
- package/src/core/adoption/manifest-templates.ts +1 -1
- package/src/core/adoption/plan.ts +3 -26
- package/src/core/adoption/workflow-contract-plan.ts +17 -9
- package/src/effects/process-runner.ts +8 -14
- package/src/runtime/context/assistant-context.ts +154 -0
- package/src/runtime/context/assistant-work-context.ts +147 -0
- package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
- package/src/runtime/context/codegraph-read-provider.ts +55 -22
- package/src/runtime/context/codegraph-sidecar.cjs +8 -1
- package/src/runtime/context/context-closure.ts +268 -0
- package/src/runtime/context/context-plane.ts +211 -0
- package/src/runtime/context/project-engineering-contract.ts +60 -0
- package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
- package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
- package/src/runtime/control-plane/bootstrap/index.ts +5 -0
- package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
- package/src/runtime/control-plane/bootstrap/store.ts +21 -0
- package/src/runtime/control-plane/bootstrap/types.ts +87 -0
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +328 -0
- package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +320 -0
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +169 -0
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +350 -0
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +85 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +369 -99
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +103 -15
- package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +2 -2
- package/src/runtime/control-plane/execution/retained-work-resume.ts +336 -6
- package/src/runtime/control-plane/execution/validation.ts +28 -3
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +116 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +44 -2
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +34 -3
- package/src/runtime/control-plane/execution/work-execution-support.ts +42 -22
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1103 -166
- package/src/runtime/control-plane/execution/work-handle-authority.ts +219 -22
- package/src/runtime/control-plane/execution/work-handle-store.ts +77 -0
- package/src/runtime/control-plane/execution/work-head-settlement.ts +75 -0
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +145 -23
- package/src/runtime/control-plane/execution/work-operation-service.ts +49 -13
- package/src/runtime/control-plane/execution/work-preparation-service.ts +31 -15
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +1 -1
- package/src/runtime/control-plane/execution/work-task-receipt.ts +20 -1
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +407 -76
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +88 -18
- package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
- package/src/runtime/control-plane/execution/work-verification-service.ts +258 -4
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +200 -15
- package/src/runtime/control-plane/facade/capability-registry.ts +21 -10
- package/src/runtime/control-plane/facade/controller-round-relay.ts +3 -1118
- package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -3
- package/src/runtime/control-plane/facade/goal-workloop.ts +972 -137
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +158 -0
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +10 -0
- package/src/runtime/control-plane/facade/index.ts +4 -2
- package/src/runtime/control-plane/facade/operation-digest.ts +22 -58
- package/src/runtime/control-plane/facade/plan-contract-store.ts +1004 -38
- package/src/runtime/control-plane/facade/repository-work-admission.ts +19 -1
- package/src/runtime/control-plane/facade/requirement-authority.ts +218 -0
- package/src/runtime/control-plane/facade/requirement-board.ts +6 -1
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +48 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
- package/src/runtime/control-plane/facade/suggested-actions.ts +4 -1
- package/src/runtime/control-plane/facade/types.ts +189 -532
- package/src/runtime/control-plane/facade/work-admission-policy.ts +84 -35
- package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
- package/src/runtime/control-plane/facade/work-implementation-review.ts +2 -0
- package/src/runtime/control-plane/facade/work-state-machine.ts +2 -250
- package/src/runtime/control-plane/generated-cache-retention.ts +239 -18
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +12 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +76 -13
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +173 -81
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +397 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +301 -560
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +20 -4
- package/src/runtime/control-plane/launcher/thin-launcher.ts +50 -4
- package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +169 -0
- package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +30 -22
- package/src/runtime/control-plane/persistence/sqlite-store.ts +545 -76
- package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
- package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
- package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
- package/src/runtime/control-plane/release-retention.ts +56 -16
- package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
- package/src/runtime/control-plane/routing/route-policy.ts +19 -0
- package/src/runtime/control-plane/runtime-cleanup.ts +574 -37
- package/src/runtime/control-plane/runtime-generation.ts +6 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +465 -0
- package/src/runtime/control-plane/workspace/workspace-store.ts +80 -0
- package/src/runtime/diagnostics/incident-repair.ts +406 -0
- package/src/runtime/diagnostics/mcp-timing.ts +125 -6
- package/src/runtime/diagnostics/performance.ts +6 -14
- package/src/runtime/diagnostics/read-only-tool.ts +1 -1
- package/src/runtime/evidence/artifact-store.ts +65 -2
- package/src/runtime/evidence/operational-shadow.ts +38 -0
- package/src/runtime/evidence/process-check-receipt.ts +5 -43
- package/src/runtime/evidence/sensitive-output.ts +4 -4
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +121 -2
- package/src/runtime/execution/managed-workspace.ts +55 -5
- package/src/runtime/execution/process-runtime/canary.ts +19 -5
- package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +23 -9
- package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
- package/src/runtime/execution/process-runtime/check-result.ts +73 -2
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +42 -3
- package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +38 -87
- package/src/runtime/execution/process-runtime/index.ts +1 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +32 -1
- package/src/runtime/execution/process-runtime/persisted-check.ts +128 -21
- package/src/runtime/execution/process-runtime/resource-claims.ts +60 -3
- package/src/runtime/execution/process-runtime/runtime.ts +132 -15
- package/src/runtime/execution/process-runtime/types.ts +22 -0
- package/src/runtime/execution/workers/executor.ts +16 -13
- package/src/runtime/execution/workers/worker-entry.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
- package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
- package/src/runtime/gateway/mcp/process-tools.ts +2 -289
- package/src/runtime/gateway/mcp/router.ts +2 -1125
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
- package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
- package/src/runtime/maintenance/cleanup.ts +38 -24
- package/src/runtime/platform/browser-product-discovery.ts +174 -0
- package/src/runtime/platform/computer-platform.ts +14 -0
- package/src/runtime/platform/executable-discovery.ts +54 -0
- package/src/runtime/platform/fetch-http-server.ts +90 -0
- package/src/runtime/platform/service-manager.ts +138 -0
- package/src/runtime/platform/windows-host-discovery.ts +118 -0
- package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
- package/src/runtime/plugins/action-application.ts +135 -0
- package/src/runtime/plugins/app-store-connect-adapter.ts +9 -21
- package/src/runtime/plugins/browser-adapter.ts +140 -100
- package/src/runtime/plugins/browser-automation-service.ts +15 -36
- package/src/runtime/plugins/browser-macos-bridge.ts +69 -21
- package/src/runtime/plugins/browser-manifest-surface.ts +30 -6
- package/src/runtime/plugins/browser-native-session-service.ts +1 -1
- package/src/runtime/plugins/browser-provider-registry.ts +2 -109
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
- package/src/runtime/plugins/browser-runtime.ts +41 -9
- package/src/runtime/plugins/browser-session-authority.ts +101 -291
- package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
- package/src/runtime/plugins/browser-session-store.ts +229 -36
- package/src/runtime/plugins/browser-session-types.ts +2 -98
- package/src/runtime/plugins/capability-authorization-grants.ts +17 -0
- package/src/runtime/plugins/catalog-trust.ts +82 -0
- package/src/runtime/plugins/computer-registration.ts +839 -0
- package/src/runtime/plugins/config-store.ts +119 -0
- package/src/runtime/plugins/desktop-operator-external-policy.ts +932 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +111 -8
- package/src/runtime/plugins/errors.ts +8 -1
- package/src/runtime/plugins/external-adapter.ts +45 -322
- package/src/runtime/plugins/external-provider-policy.ts +48 -0
- package/src/runtime/plugins/external-registration.ts +9 -1
- package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
- package/src/runtime/plugins/external-unix-socket.ts +64 -193
- package/src/runtime/plugins/first-party-external-registration.ts +163 -0
- package/src/runtime/plugins/first-party-registry.ts +3 -1
- package/src/runtime/plugins/github-adapter.ts +1 -2
- package/src/runtime/plugins/gmail-adapter.ts +6 -6
- package/src/runtime/plugins/google-calendar-adapter.ts +6 -6
- package/src/runtime/plugins/google-shared.ts +31 -46
- package/src/runtime/plugins/google-tasks-adapter.ts +6 -6
- package/src/runtime/plugins/ios-adapter.ts +1 -2
- package/src/runtime/plugins/local-system-adapter.ts +180 -0
- package/src/runtime/plugins/macos-capability-broker.ts +15 -105
- package/src/runtime/plugins/resend-adapter.ts +15 -24
- package/src/runtime/plugins/store.ts +493 -51
- package/src/runtime/plugins/types.ts +8 -1
- package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
- package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
- package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +86 -430
- package/src/runtime/projections/controller-context.ts +12 -6
- package/src/runtime/projections/git-status-sampler.ts +73 -22
- package/src/runtime/projections/materialized-view.ts +14 -8
- package/src/runtime/recovery/capability-action-application.ts +228 -0
- package/src/runtime/recovery/index.ts +3 -0
- package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
- package/src/runtime/recovery/local-jobs-repair.ts +14 -14
- package/src/runtime/recovery/maintenance-executor.ts +358 -76
- package/src/runtime/recovery/quarantine-retention.ts +256 -0
- package/src/runtime/release/identity.ts +6 -0
- package/src/runtime/resources/leases/store.ts +1 -1
- package/src/runtime/root/active-execution-power-assertion.ts +139 -0
- package/src/runtime/root/assistant-learning-loop.ts +45 -0
- package/src/runtime/root/browser-session-composition.ts +59 -0
- package/src/runtime/root/computer-composition.ts +191 -0
- package/src/runtime/root/computer-target-composition.ts +16 -0
- package/src/runtime/root/computer-target-persistence.ts +39 -0
- package/src/runtime/root/controller-round-composition.ts +107 -0
- package/src/runtime/root/controller-services.ts +2 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/gateway-adapter.ts +3 -3
- package/src/runtime/root/local-bridge.ts +5 -2
- package/src/runtime/root/mcp-transport.ts +5 -5
- package/src/runtime/root/package-connector-service.ts +108 -56
- package/src/runtime/root/package-runtime-release.ts +85 -18
- package/src/runtime/root/package-runtime-service.ts +60 -97
- package/src/runtime/root/release-execution-canary.ts +71 -0
- package/src/runtime/root/release-loader.ts +68 -0
- package/src/runtime/root/release-manifest.ts +106 -2
- package/src/runtime/root/release-materialize.ts +103 -4
- package/src/runtime/root/release-store.ts +31 -2
- package/src/runtime/root/runtime.ts +240 -25
- package/src/runtime/root/scheduled-controller-composition.ts +51 -0
- package/src/runtime/root/scheduler.ts +12 -4
- package/src/runtime/root/service-runner.ts +1 -1
- package/src/runtime/root/service.ts +41 -16
- package/src/runtime/root/status.ts +1 -0
- package/src/runtime/root/types.ts +24 -1
- package/src/runtime/shared/local-bridge-surface.ts +1 -1
- package/src/runtime/shared/process-environment.ts +19 -4
- package/src/runtime/shared/storage-capacity.ts +68 -0
- package/src/runtime/standalone-recovery/controller-home-migration.ts +1116 -0
- package/src/runtime/standalone-recovery/core.ts +984 -230
- package/src/runtime/standalone-recovery/entry.ts +182 -51
- package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
- package/src/runtime/standalone-recovery/installer.ts +212 -104
- package/src/runtime/standalone-recovery/mcp-server.ts +243 -0
- package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
- package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
- package/src/runtime/standalone-recovery/performance.ts +135 -0
- package/src/runtime/standalone-recovery/release.ts +5 -0
- package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -1
- package/src/runtime/workflow/schedules/engine.ts +191 -343
- package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
- package/src/runtime/workflow/schedules/settlement.ts +2 -191
- package/src/runtime/workflow/schedules/store.ts +2 -607
- package/src/runtime/workflow/schedules/types.ts +2 -127
- package/src/runtime/workflow/schedules/work-continuation.ts +180 -15
- package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
- package/src/runtime/workflows/runtime.ts +486 -0
- package/src/testing/test-governance.ts +90 -29
- package/assets/templates/helpers/archive-architecture-request.sh +0 -244
- package/docs/architecture/history/README.md +0 -7
- package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
- package/docs/architecture/history/global-hook-runtime.md +0 -166
- package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
- package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
- package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
- package/docs/architecture/requests/archive/2026/root.md +0 -68
- package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
- package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
- package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
- package/scripts/archive-architecture-request.sh +0 -4
- package/scripts/run-skill-evals.ts +0 -1022
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
1
|
+
import { createHash, randomUUID } from 'crypto';
|
|
2
2
|
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
3
4
|
import { basename, dirname, join, normalize, relative, resolve } from 'path';
|
|
4
5
|
import {
|
|
5
6
|
capProcessOutput,
|
|
@@ -12,6 +13,21 @@ import { runBoundedChild } from '../../runtime/shared/bounded-child-supervisor';
|
|
|
12
13
|
import { signalProcessTree } from '../../runtime/shared/process-tree';
|
|
13
14
|
import { repositoryChildProcessEnvironment, resolveBunExecutable } from '../../runtime/shared/process-environment';
|
|
14
15
|
import { materializeManagedWorkspaceCheckDependencies } from '../../runtime/execution/managed-workspace';
|
|
16
|
+
import {
|
|
17
|
+
isStructuredCheckFailureEvidence,
|
|
18
|
+
STRUCTURED_CHECK_RESULT_PATH_ENV,
|
|
19
|
+
type StructuredCheckFailureEvidence,
|
|
20
|
+
} from '../../runtime/execution/process-runtime/check-result';
|
|
21
|
+
import { readRuntimeReleaseAuthority } from '../../runtime/root/release-store';
|
|
22
|
+
import { observeRuntimeStatus } from '../../runtime/root/status';
|
|
23
|
+
import { readCurrentRecoveryRelease } from '../../runtime/standalone-recovery/release';
|
|
24
|
+
import { acquireRecoveryOperationLock, recoveryOperationLockPath } from '../../runtime/standalone-recovery/operation-lock';
|
|
25
|
+
import {
|
|
26
|
+
ensureRepositoryCheckStorage,
|
|
27
|
+
resolveRepositoryCheckStorage,
|
|
28
|
+
type RepositoryCheckStorageAuthority,
|
|
29
|
+
type ResolvedRepositoryCheckStorage,
|
|
30
|
+
} from '../../runtime/execution/process-runtime/check-storage';
|
|
15
31
|
|
|
16
32
|
export interface ControllerCheckEffects {
|
|
17
33
|
/** Repository-relative read scopes. Use [\".\"] for the whole checkout. */
|
|
@@ -29,6 +45,7 @@ export interface ControllerCheckEffects {
|
|
|
29
45
|
export type ControllerCheckCostClass = 'L0' | 'L1' | 'L2' | 'L3' | 'L4';
|
|
30
46
|
export type ControllerCheckRiskFloor = 'readonly' | 'low' | 'medium' | 'high' | 'destructive';
|
|
31
47
|
export type ControllerCheckPhase = 'pre_edit' | 'post_edit' | 'pre_finalize' | 'release';
|
|
48
|
+
export type ControllerCheckExecutionAuthority = 'isolated_controller_home' | 'live_controller_home';
|
|
32
49
|
|
|
33
50
|
export interface ControllerCheckSelection {
|
|
34
51
|
/** Execution cost only; it does not lower severity or automatically run the check. */
|
|
@@ -45,6 +62,8 @@ export interface ControllerCheck {
|
|
|
45
62
|
cwd: string;
|
|
46
63
|
timeoutMs: number;
|
|
47
64
|
source: 'repo-config' | 'package-script';
|
|
65
|
+
/** Where authority-sensitive child state is resolved. Ordinary checks stay isolated. */
|
|
66
|
+
executionAuthority?: ControllerCheckExecutionAuthority;
|
|
48
67
|
effects?: ControllerCheckEffects;
|
|
49
68
|
/** Selection/preflight metadata; intentionally excluded from physical execution identity. */
|
|
50
69
|
selection?: ControllerCheckSelection;
|
|
@@ -89,8 +108,8 @@ interface CheckConfig {
|
|
|
89
108
|
|
|
90
109
|
const CHECK_CONFIG = '.forge/checks.json';
|
|
91
110
|
const LEGACY_TRACKED_CHECK_CONFIG = '.repo-harness/checks.json';
|
|
92
|
-
const
|
|
93
|
-
const HEAVY_CHECK_LOCK = '
|
|
111
|
+
const CHECK_EVIDENCE_SUBDIR = 'controller';
|
|
112
|
+
const HEAVY_CHECK_LOCK = 'heavy-check.lock';
|
|
94
113
|
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
95
114
|
const MAX_TIMEOUT_MS = 30 * 60 * 1000;
|
|
96
115
|
const SAFE_PACKAGE_SCRIPT = /^(test(?::|$)|check(?::|$)|lint(?::|$)|typecheck(?::|$)|format:check$)/;
|
|
@@ -253,6 +272,14 @@ export function controllerCheckSelection(check: Pick<ControllerCheck, 'id' | 'se
|
|
|
253
272
|
|
|
254
273
|
function inferredPackageCheckEffects(name: string): ControllerCheckEffects | undefined {
|
|
255
274
|
const normalized = name.trim().toLowerCase();
|
|
275
|
+
if (normalized === 'check:stable-baseline') {
|
|
276
|
+
return { reads: ['.'], hostServices: ['canonical-runtime', 'forge-recovery'] };
|
|
277
|
+
}
|
|
278
|
+
if (normalized === 'check:task' || normalized === 'check:main') {
|
|
279
|
+
// Governed gates reject any candidate workspace mutation after every step
|
|
280
|
+
// and persist only content-bound receipts/caches outside repository source.
|
|
281
|
+
return { reads: ['.'], cache: 'write', temp: 'isolated', git: 'read' };
|
|
282
|
+
}
|
|
256
283
|
const staticAnalysis = /(?:^|:)(?:type|typecheck|lint|format:check|runtime-architecture|mcp-compatibility|forge-runtime)$/.test(normalized);
|
|
257
284
|
if (staticAnalysis) return { reads: ['.'], cache: 'write' };
|
|
258
285
|
const isolatedReadOnlyCheck = /(?:^|:)(?:quality-harness|evaluation-framework|background-check-overlap|typescript-navigation|check-scheduling|bootstrap-files)$/.test(normalized);
|
|
@@ -312,6 +339,9 @@ function packageChecks(repoRoot: string): ControllerCheck[] {
|
|
|
312
339
|
cwd: '.',
|
|
313
340
|
timeoutMs: packageScriptTimeoutMs(name),
|
|
314
341
|
source: 'package-script' as const,
|
|
342
|
+
executionAuthority: name.trim().toLowerCase() === 'check:stable-baseline'
|
|
343
|
+
? 'live_controller_home' as const
|
|
344
|
+
: 'isolated_controller_home' as const,
|
|
315
345
|
effects: inferredPackageCheckEffects(name),
|
|
316
346
|
selection: inferredCheckSelection(name),
|
|
317
347
|
}];
|
|
@@ -340,8 +370,9 @@ export interface ControllerCheckResult {
|
|
|
340
370
|
validatedRevision?: string;
|
|
341
371
|
/** Original process execution timestamp; retained when a result is served from cache. */
|
|
342
372
|
originalExecutedAt?: string;
|
|
343
|
-
/**
|
|
373
|
+
/** Non-zero repository failures are acceptance failures unless bounded infrastructure evidence proves otherwise. */
|
|
344
374
|
failureClass?: 'acceptance_failure' | 'infrastructure_failure';
|
|
375
|
+
failureEvidence?: StructuredCheckFailureEvidence;
|
|
345
376
|
}
|
|
346
377
|
|
|
347
378
|
export interface ControllerCheckEvidence {
|
|
@@ -365,54 +396,190 @@ export interface ControllerCheckEvidence {
|
|
|
365
396
|
validatedRevision?: string;
|
|
366
397
|
originalExecutedAt?: string;
|
|
367
398
|
failureClass?: 'acceptance_failure' | 'infrastructure_failure';
|
|
399
|
+
failureEvidence?: StructuredCheckFailureEvidence;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const STRONG_TRANSPORT_FAILURE_PATTERNS = [
|
|
403
|
+
/\bjava\.net\.(?:SocketTimeoutException|UnknownHostException|ConnectException|NoRouteToHostException)\b/i,
|
|
404
|
+
/\b(?:EAI_AGAIN|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|EHOSTUNREACH)\b/i,
|
|
405
|
+
/\bCould not resolve host\b/i,
|
|
406
|
+
/\b(?:connection|connect|read) timed out\b/i,
|
|
407
|
+
/\bNetwork is unreachable\b/i,
|
|
408
|
+
/\b(?:SSLHandshakeException|TLS handshake (?:failed|timeout|timed out)|CERTIFICATE_VERIFY_FAILED)\b/i,
|
|
409
|
+
] as const;
|
|
410
|
+
|
|
411
|
+
function classifyControllerCheckFailure(input: {
|
|
412
|
+
ok: boolean;
|
|
413
|
+
stale?: boolean;
|
|
414
|
+
timedOut: boolean;
|
|
415
|
+
runtimeFailure: boolean;
|
|
416
|
+
stdout: string;
|
|
417
|
+
stderr: string;
|
|
418
|
+
}): 'acceptance_failure' | 'infrastructure_failure' | undefined {
|
|
419
|
+
if (input.ok && !input.stale) return undefined;
|
|
420
|
+
if (input.stale || input.timedOut || input.runtimeFailure) return 'infrastructure_failure';
|
|
421
|
+
const output = `${input.stdout}\n${input.stderr}`;
|
|
422
|
+
if (STRONG_TRANSPORT_FAILURE_PATTERNS.some((pattern) => pattern.test(output))) return 'infrastructure_failure';
|
|
423
|
+
return 'acceptance_failure';
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const GOVERNED_TEST_GATES = new Map<string, string>([
|
|
427
|
+
['package:test', 'affected'],
|
|
428
|
+
['package:test:core', 'core'],
|
|
429
|
+
['package:test:integration', 'integration'],
|
|
430
|
+
['package:test:infrastructure', 'infrastructure'],
|
|
431
|
+
['package:test:fault', 'fault'],
|
|
432
|
+
['package:test:full', 'full'],
|
|
433
|
+
['package:test:bun', 'full'],
|
|
434
|
+
]);
|
|
435
|
+
const MAX_STRUCTURED_CHECK_RESULT_BYTES = 64 * 1024;
|
|
436
|
+
|
|
437
|
+
interface StructuredCheckObservation {
|
|
438
|
+
evidence?: StructuredCheckFailureEvidence;
|
|
439
|
+
error?: string;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function structuredCheckResultPath(check: ControllerCheck): string | undefined {
|
|
443
|
+
if (!GOVERNED_TEST_GATES.has(check.id)) return undefined;
|
|
444
|
+
return join(tmpdir(), `forge-check-result-${process.pid}-${randomUUID()}.json`);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function readStructuredCheckObservation(check: ControllerCheck, path: string | undefined): StructuredCheckObservation {
|
|
448
|
+
const expectedGate = GOVERNED_TEST_GATES.get(check.id);
|
|
449
|
+
if (!expectedGate) return {};
|
|
450
|
+
if (!path || !existsSync(path)) return { error: 'CHECK_STRUCTURED_RESULT_MISSING' };
|
|
451
|
+
try {
|
|
452
|
+
const bytes = readFileSync(path);
|
|
453
|
+
if (bytes.byteLength > MAX_STRUCTURED_CHECK_RESULT_BYTES) return { error: 'CHECK_STRUCTURED_RESULT_TOO_LARGE' };
|
|
454
|
+
const value = JSON.parse(bytes.toString('utf8')) as unknown;
|
|
455
|
+
if (!isStructuredCheckFailureEvidence(value) || value.gate !== expectedGate) return { error: 'CHECK_STRUCTURED_RESULT_INVALID' };
|
|
456
|
+
return { evidence: value };
|
|
457
|
+
} catch {
|
|
458
|
+
return { error: 'CHECK_STRUCTURED_RESULT_INVALID' };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function consumeStructuredCheckObservation(check: ControllerCheck, path: string | undefined): StructuredCheckObservation {
|
|
463
|
+
try {
|
|
464
|
+
return readStructuredCheckObservation(check, path);
|
|
465
|
+
} finally {
|
|
466
|
+
if (path) rmSync(path, { force: true });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function applyStructuredCheckObservation(processOk: boolean, observation: StructuredCheckObservation): {
|
|
471
|
+
ok: boolean;
|
|
472
|
+
failureClass?: 'acceptance_failure' | 'infrastructure_failure';
|
|
473
|
+
failureEvidence?: StructuredCheckFailureEvidence;
|
|
474
|
+
error?: string;
|
|
475
|
+
} {
|
|
476
|
+
if (!observation.error && !observation.evidence) return { ok: processOk };
|
|
477
|
+
if (observation.error) return { ok: false, failureClass: 'infrastructure_failure', error: observation.error };
|
|
478
|
+
const evidence = observation.evidence!;
|
|
479
|
+
const reportOk = evidence.status === 'passed';
|
|
480
|
+
if (reportOk !== processOk) {
|
|
481
|
+
return { ok: false, failureClass: 'infrastructure_failure', failureEvidence: evidence, error: 'CHECK_STRUCTURED_RESULT_STATUS_MISMATCH' };
|
|
482
|
+
}
|
|
483
|
+
if (reportOk) return { ok: true, failureEvidence: evidence };
|
|
484
|
+
const sourceOnly = evidence.failureClasses.length > 0 && evidence.failureClasses.every((entry) => entry === 'source');
|
|
485
|
+
return {
|
|
486
|
+
ok: false,
|
|
487
|
+
failureClass: sourceOnly ? 'acceptance_failure' : 'infrastructure_failure',
|
|
488
|
+
failureEvidence: evidence,
|
|
489
|
+
};
|
|
368
490
|
}
|
|
369
491
|
|
|
370
492
|
function artifactSlug(id: string): string {
|
|
371
493
|
return id.toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'check';
|
|
372
494
|
}
|
|
373
495
|
|
|
374
|
-
function evidencePath(
|
|
375
|
-
return join(
|
|
496
|
+
function evidencePath(storage: ResolvedRepositoryCheckStorage, id: string): string {
|
|
497
|
+
return join(storage.physicalRoot, CHECK_EVIDENCE_SUBDIR, `latest-${artifactSlug(id)}.json`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function historicalEvidencePath(storage: ResolvedRepositoryCheckStorage, id: string, cacheKey: string): string {
|
|
501
|
+
return join(storage.physicalRoot, CHECK_EVIDENCE_SUBDIR, artifactSlug(id), `${cacheKey}.json`);
|
|
376
502
|
}
|
|
377
503
|
|
|
378
|
-
function
|
|
379
|
-
return
|
|
504
|
+
function logicalEvidenceArtifactPath(id: string): string {
|
|
505
|
+
return `controller-home://checks/controller/latest-${artifactSlug(id)}.json`;
|
|
380
506
|
}
|
|
381
507
|
|
|
382
508
|
const CHECK_REVISION_EXCLUDES = [
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
'.ai/harness
|
|
387
|
-
'.ai/harness/worktrees/**',
|
|
388
|
-
'.ai/harness/controller/**',
|
|
389
|
-
'.ai/harness/artifacts/**',
|
|
390
|
-
'.ai/harness/local-bridge/**',
|
|
391
|
-
'.ai/harness/ephemeral-issues/**',
|
|
509
|
+
// `.ai/harness` is Forge runtime/check state, not repository source. Checks
|
|
510
|
+
// are allowed to materialize artifacts such as design-system audit reports
|
|
511
|
+
// there; hashing those outputs would make a stable check invalidate itself.
|
|
512
|
+
'.ai/harness/**',
|
|
392
513
|
];
|
|
393
514
|
|
|
394
515
|
function checkRevisionPathspecs(): string[] {
|
|
395
516
|
return ['.', ...CHECK_REVISION_EXCLUDES.map((path) => `:(exclude)${path}`)];
|
|
396
517
|
}
|
|
397
518
|
|
|
398
|
-
|
|
519
|
+
interface ControllerCheckContentObservation {
|
|
520
|
+
revision: string;
|
|
521
|
+
fileDigests?: Map<string, string>;
|
|
522
|
+
listingAvailable: boolean;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function observeControllerCheckContent(
|
|
526
|
+
repoRoot: string,
|
|
527
|
+
options: { captureFileDigests?: boolean } = {},
|
|
528
|
+
): ControllerCheckContentObservation {
|
|
399
529
|
const files = runProcess('git', ['ls-files', '--cached', '--others', '--exclude-standard', '-z', '--', ...checkRevisionPathspecs()], {
|
|
400
530
|
cwd: repoRoot,
|
|
401
531
|
timeoutMs: 10_000,
|
|
402
532
|
maxOutputBytes: 8 * 1024 * 1024,
|
|
403
533
|
});
|
|
404
534
|
const revision = createHash('sha256').update('controller-check-content-v2\n');
|
|
405
|
-
|
|
535
|
+
const fileDigests = options.captureFileDigests ? new Map<string, string>() : undefined;
|
|
536
|
+
if (!files.ok) {
|
|
537
|
+
return {
|
|
538
|
+
revision: revision.update(`git-error:${files.error || files.stderr}`).digest('hex').slice(0, 24),
|
|
539
|
+
...(fileDigests ? { fileDigests } : {}),
|
|
540
|
+
listingAvailable: false,
|
|
541
|
+
};
|
|
542
|
+
}
|
|
406
543
|
for (const relativePath of files.stdout.split('\0').filter(Boolean).sort()) {
|
|
407
544
|
if (relativePath.startsWith('tasks/') || relativePath.startsWith('plans/')) continue;
|
|
408
545
|
revision.update(`${relativePath}\0`);
|
|
409
546
|
try {
|
|
410
|
-
|
|
547
|
+
const content = readFileSync(resolve(repoRoot, relativePath));
|
|
548
|
+
revision.update(content);
|
|
549
|
+
fileDigests?.set(relativePath, createHash('sha256').update(content).digest('hex'));
|
|
411
550
|
} catch (_error) {
|
|
412
551
|
revision.update('missing');
|
|
552
|
+
fileDigests?.set(relativePath, 'missing');
|
|
413
553
|
}
|
|
414
554
|
}
|
|
415
|
-
return
|
|
555
|
+
return {
|
|
556
|
+
revision: revision.digest('hex').slice(0, 24),
|
|
557
|
+
...(fileDigests ? { fileDigests } : {}),
|
|
558
|
+
listingAvailable: true,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export function currentControllerCheckRevision(repoRoot: string): string {
|
|
563
|
+
return observeControllerCheckContent(repoRoot).revision;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function controllerCheckWriteScopeContainsPath(scope: string, relativePath: string): boolean {
|
|
567
|
+
return scope === '.' || relativePath === scope || relativePath.startsWith(`${scope}/`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function controllerCheckInputIntegrityChanged(
|
|
571
|
+
check: ControllerCheck,
|
|
572
|
+
input: ControllerCheckContentObservation,
|
|
573
|
+
completed: ControllerCheckContentObservation,
|
|
574
|
+
): boolean {
|
|
575
|
+
if (!input.listingAvailable || !completed.listingAvailable || !input.fileDigests || !completed.fileDigests) return true;
|
|
576
|
+
const writeScopes = check.effects?.writes ?? [];
|
|
577
|
+
const observedPaths = new Set([...input.fileDigests.keys(), ...completed.fileDigests.keys()]);
|
|
578
|
+
for (const relativePath of observedPaths) {
|
|
579
|
+
if (writeScopes.some((scope) => controllerCheckWriteScopeContainsPath(scope, relativePath))) continue;
|
|
580
|
+
if (input.fileDigests.get(relativePath) !== completed.fileDigests.get(relativePath)) return true;
|
|
581
|
+
}
|
|
582
|
+
return false;
|
|
416
583
|
}
|
|
417
584
|
|
|
418
585
|
function checkDefinitionDigest(check: ControllerCheck): string {
|
|
@@ -423,6 +590,7 @@ function checkDefinitionDigest(check: ControllerCheck): string {
|
|
|
423
590
|
cwd: check.cwd,
|
|
424
591
|
timeoutMs: check.timeoutMs,
|
|
425
592
|
source: check.source,
|
|
593
|
+
executionAuthority: check.executionAuthority ?? 'isolated_controller_home',
|
|
426
594
|
effects: check.effects,
|
|
427
595
|
})).digest('hex');
|
|
428
596
|
}
|
|
@@ -450,6 +618,7 @@ function validateControllerCheckSnapshot(repoRoot: string, snapshot: ControllerC
|
|
|
450
618
|
cwd: normalizeCwd(repoRoot, snapshot.cwd),
|
|
451
619
|
timeoutMs: boundedTimeout(snapshot.timeoutMs),
|
|
452
620
|
source: snapshot.source,
|
|
621
|
+
executionAuthority: snapshot.executionAuthority ?? 'isolated_controller_home',
|
|
453
622
|
effects: normalizeCheckEffects(repoRoot, snapshot.effects),
|
|
454
623
|
selection: normalizeCheckSelection(snapshot.selection, snapshot.id),
|
|
455
624
|
};
|
|
@@ -457,7 +626,72 @@ function validateControllerCheckSnapshot(repoRoot: string, snapshot: ControllerC
|
|
|
457
626
|
|
|
458
627
|
const CONTROLLER_CHECK_EXECUTION_IDENTITY_VERSION = 'controller-check-execution-v2';
|
|
459
628
|
|
|
460
|
-
|
|
629
|
+
/**
|
|
630
|
+
* Bounded live-state identity for certification checks. This is read-only
|
|
631
|
+
* evidence, not lifecycle authority. It includes current release authority and
|
|
632
|
+
* observed Runtime liveness so a dead/replaced Runtime cannot reuse a prior
|
|
633
|
+
* green Stable Baseline receipt merely because its status file remained.
|
|
634
|
+
*/
|
|
635
|
+
export function controllerCheckLiveExecutionStateFingerprint(controllerHome: string, recoveryFenceInstanceId?: string): string {
|
|
636
|
+
const mutationLockPath = recoveryOperationLockPath(controllerHome);
|
|
637
|
+
try {
|
|
638
|
+
const raw = readFileSync(mutationLockPath, 'utf8');
|
|
639
|
+
if (recoveryFenceInstanceId?.trim()) {
|
|
640
|
+
try {
|
|
641
|
+
const owner = JSON.parse(raw) as { instanceId?: unknown };
|
|
642
|
+
if (owner?.instanceId === recoveryFenceInstanceId.trim()) {
|
|
643
|
+
// This check owns the real Recovery mutation fence; its own lock is not drift.
|
|
644
|
+
} else {
|
|
645
|
+
throw new Error('LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS');
|
|
646
|
+
}
|
|
647
|
+
} catch (error) {
|
|
648
|
+
if (error instanceof Error && error.message === 'LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS') throw error;
|
|
649
|
+
throw new Error('LIVE_CHECK_RECOVERY_MUTATION_STATE_UNREADABLE');
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
throw new Error('LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS');
|
|
653
|
+
}
|
|
654
|
+
} catch (error) {
|
|
655
|
+
if (error instanceof Error && (
|
|
656
|
+
error.message === 'LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS'
|
|
657
|
+
|| error.message === 'LIVE_CHECK_RECOVERY_MUTATION_STATE_UNREADABLE'
|
|
658
|
+
)) throw error;
|
|
659
|
+
if ((error as NodeJS.ErrnoException)?.code !== 'ENOENT') {
|
|
660
|
+
throw new Error('LIVE_CHECK_RECOVERY_MUTATION_STATE_UNREADABLE');
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const release = readRuntimeReleaseAuthority(controllerHome);
|
|
664
|
+
const recoveryRelease = readCurrentRecoveryRelease(controllerHome);
|
|
665
|
+
const runtime = observeRuntimeStatus(controllerHome);
|
|
666
|
+
return createHash('sha256')
|
|
667
|
+
.update(JSON.stringify({
|
|
668
|
+
release: release ? {
|
|
669
|
+
revision: release.revision,
|
|
670
|
+
releaseId: release.active.releaseId,
|
|
671
|
+
artifactIdentity: release.active.artifactIdentity,
|
|
672
|
+
manifestSha256: release.active.manifestSha256,
|
|
673
|
+
} : null,
|
|
674
|
+
recoveryRelease: recoveryRelease ? {
|
|
675
|
+
releaseRevision: recoveryRelease.releaseRevision,
|
|
676
|
+
sourceCommit: recoveryRelease.sourceCommit,
|
|
677
|
+
manifestSha256: recoveryRelease.manifestSha256,
|
|
678
|
+
} : null,
|
|
679
|
+
runtime: {
|
|
680
|
+
running: runtime.running,
|
|
681
|
+
ready: runtime.ready,
|
|
682
|
+
stale: runtime.stale,
|
|
683
|
+
reasonCodes: [...runtime.reasonCodes].sort(),
|
|
684
|
+
runtimeInstanceId: runtime.snapshot?.runtimeInstanceId ?? null,
|
|
685
|
+
pid: runtime.snapshot?.pid ?? null,
|
|
686
|
+
releaseId: runtime.snapshot?.releaseId ?? null,
|
|
687
|
+
artifactIdentity: runtime.snapshot?.artifactIdentity ?? null,
|
|
688
|
+
},
|
|
689
|
+
}))
|
|
690
|
+
.digest('hex')
|
|
691
|
+
.slice(0, 24);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export function controllerCheckEnvironmentFingerprint(check: ControllerCheck, executionStateFingerprint?: string): string {
|
|
461
695
|
const env = repositoryChildProcessEnvironment(process.env);
|
|
462
696
|
return createHash('sha256')
|
|
463
697
|
.update(JSON.stringify({
|
|
@@ -470,6 +704,8 @@ function checkEnvironmentFingerprint(check: ControllerCheck): string {
|
|
|
470
704
|
// for the parent and forge-check-runner for the sidecar; process.execPath
|
|
471
705
|
// therefore differs even though both execute the exact same check/toolchain.
|
|
472
706
|
commandExecutable: check.command[0],
|
|
707
|
+
executionAuthority: check.executionAuthority ?? 'isolated_controller_home',
|
|
708
|
+
executionStateFingerprint: executionStateFingerprint?.trim() || '',
|
|
473
709
|
path: env.PATH ?? '',
|
|
474
710
|
home: env.HOME ?? env.USERPROFILE ?? '',
|
|
475
711
|
bunInstall: env.BUN_INSTALL ?? '',
|
|
@@ -514,7 +750,7 @@ function buildCheckCacheKey(
|
|
|
514
750
|
timeoutMs: number,
|
|
515
751
|
revision: string,
|
|
516
752
|
definitionDigest = checkDefinitionDigest(check),
|
|
517
|
-
environmentFingerprint =
|
|
753
|
+
environmentFingerprint = controllerCheckEnvironmentFingerprint(check),
|
|
518
754
|
): string {
|
|
519
755
|
return createHash('sha256')
|
|
520
756
|
.update(JSON.stringify({
|
|
@@ -531,11 +767,13 @@ function buildCheckCacheKey(
|
|
|
531
767
|
.slice(0, 24);
|
|
532
768
|
}
|
|
533
769
|
|
|
534
|
-
|
|
770
|
+
function controllerCheckExecutionIdentityForRevision(
|
|
535
771
|
repoRoot: string,
|
|
536
772
|
id: string,
|
|
773
|
+
revision: string,
|
|
537
774
|
requestedTimeoutMs?: number,
|
|
538
775
|
snapshot?: ControllerCheckSnapshot,
|
|
776
|
+
executionStateFingerprint?: string,
|
|
539
777
|
): ControllerCheckExecutionIdentity {
|
|
540
778
|
const check = snapshot
|
|
541
779
|
? validateControllerCheckSnapshot(repoRoot, snapshot)
|
|
@@ -544,9 +782,8 @@ export function controllerCheckExecutionIdentity(
|
|
|
544
782
|
const timeoutMs = requestedTimeoutMs === undefined
|
|
545
783
|
? check.timeoutMs
|
|
546
784
|
: Math.min(check.timeoutMs, boundedTimeout(requestedTimeoutMs));
|
|
547
|
-
const revision = currentControllerCheckRevision(repoRoot);
|
|
548
785
|
const definitionDigest = checkDefinitionDigest(check);
|
|
549
|
-
const environmentFingerprint =
|
|
786
|
+
const environmentFingerprint = controllerCheckEnvironmentFingerprint(check, executionStateFingerprint);
|
|
550
787
|
const checkoutClean = checkWorkspaceClean(repoRoot);
|
|
551
788
|
const crossCheckoutReusable = checkoutClean
|
|
552
789
|
&& checkEffectsAllowCrossCheckoutReuse(check)
|
|
@@ -565,8 +802,25 @@ export function controllerCheckExecutionIdentity(
|
|
|
565
802
|
};
|
|
566
803
|
}
|
|
567
804
|
|
|
568
|
-
function
|
|
805
|
+
export function controllerCheckExecutionIdentity(
|
|
569
806
|
repoRoot: string,
|
|
807
|
+
id: string,
|
|
808
|
+
requestedTimeoutMs?: number,
|
|
809
|
+
snapshot?: ControllerCheckSnapshot,
|
|
810
|
+
executionStateFingerprint?: string,
|
|
811
|
+
): ControllerCheckExecutionIdentity {
|
|
812
|
+
return controllerCheckExecutionIdentityForRevision(
|
|
813
|
+
repoRoot,
|
|
814
|
+
id,
|
|
815
|
+
currentControllerCheckRevision(repoRoot),
|
|
816
|
+
requestedTimeoutMs,
|
|
817
|
+
snapshot,
|
|
818
|
+
executionStateFingerprint,
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function persistCheckEvidence(
|
|
823
|
+
storage: ResolvedRepositoryCheckStorage,
|
|
570
824
|
result: Omit<ControllerCheckResult, 'artifactPath'>,
|
|
571
825
|
meta: {
|
|
572
826
|
revision?: string;
|
|
@@ -577,7 +831,7 @@ function persistCheckEvidence(
|
|
|
577
831
|
validatedRevision?: string;
|
|
578
832
|
} = {},
|
|
579
833
|
): string {
|
|
580
|
-
const path = evidencePath(
|
|
834
|
+
const path = evidencePath(storage, result.check.id);
|
|
581
835
|
mkdirSync(dirname(path), { recursive: true });
|
|
582
836
|
const evidence: ControllerCheckEvidence = {
|
|
583
837
|
schemaVersion: 2,
|
|
@@ -600,30 +854,40 @@ function persistCheckEvidence(
|
|
|
600
854
|
validatedRevision: meta.validatedRevision,
|
|
601
855
|
originalExecutedAt: result.originalExecutedAt ?? result.executedAt,
|
|
602
856
|
failureClass: result.failureClass,
|
|
857
|
+
failureEvidence: result.failureEvidence,
|
|
603
858
|
};
|
|
604
859
|
const serialized = `${JSON.stringify(evidence, null, 2)}\n`;
|
|
605
860
|
atomicWriteFileSync(path, serialized);
|
|
606
861
|
if (meta.cacheKey) {
|
|
607
|
-
const historicalPath = historicalEvidencePath(
|
|
862
|
+
const historicalPath = historicalEvidencePath(storage, result.check.id, meta.cacheKey);
|
|
608
863
|
mkdirSync(dirname(historicalPath), { recursive: true });
|
|
609
864
|
atomicWriteFileSync(historicalPath, serialized);
|
|
610
865
|
}
|
|
611
|
-
return
|
|
866
|
+
return logicalEvidenceArtifactPath(result.check.id);
|
|
612
867
|
}
|
|
613
868
|
|
|
614
|
-
export function readLatestControllerCheckEvidence(
|
|
615
|
-
|
|
869
|
+
export function readLatestControllerCheckEvidence(
|
|
870
|
+
repoRoot: string,
|
|
871
|
+
id: string,
|
|
872
|
+
storageAuthority?: RepositoryCheckStorageAuthority | ResolvedRepositoryCheckStorage,
|
|
873
|
+
): ControllerCheckEvidence | undefined {
|
|
874
|
+
const storage = storageAuthority && 'physicalRoot' in storageAuthority
|
|
875
|
+
? storageAuthority as ResolvedRepositoryCheckStorage
|
|
876
|
+
: resolveRepositoryCheckStorage(repoRoot, storageAuthority as RepositoryCheckStorageAuthority | undefined);
|
|
877
|
+
const path = evidencePath(storage, id);
|
|
616
878
|
if (!existsSync(path)) return undefined;
|
|
617
879
|
try {
|
|
618
880
|
const value = JSON.parse(readFileSync(path, 'utf-8')) as ControllerCheckEvidence;
|
|
619
|
-
|
|
881
|
+
if (value.schemaVersion !== 2 || value.checkId !== id) return undefined;
|
|
882
|
+
if (value.failureEvidence !== undefined && !isStructuredCheckFailureEvidence(value.failureEvidence)) return undefined;
|
|
883
|
+
return value;
|
|
620
884
|
} catch (_error) {
|
|
621
885
|
return undefined;
|
|
622
886
|
}
|
|
623
887
|
}
|
|
624
888
|
|
|
625
|
-
function readControllerCheckEvidenceByKey(
|
|
626
|
-
const path = historicalEvidencePath(
|
|
889
|
+
function readControllerCheckEvidenceByKey(storage: ResolvedRepositoryCheckStorage, id: string, cacheKey: string): ControllerCheckEvidence | undefined {
|
|
890
|
+
const path = historicalEvidencePath(storage, id, cacheKey);
|
|
627
891
|
if (!existsSync(path)) return undefined;
|
|
628
892
|
try {
|
|
629
893
|
const value = JSON.parse(readFileSync(path, 'utf-8')) as ControllerCheckEvidence;
|
|
@@ -638,16 +902,27 @@ function prepareControllerCheckDependencies(repoRoot: string, check: ControllerC
|
|
|
638
902
|
materializeManagedWorkspaceCheckDependencies(repoRoot);
|
|
639
903
|
}
|
|
640
904
|
|
|
641
|
-
export function runControllerCheck(
|
|
905
|
+
export function runControllerCheck(
|
|
906
|
+
repoRoot: string,
|
|
907
|
+
id: string,
|
|
908
|
+
requestedTimeoutMs?: number,
|
|
909
|
+
snapshot?: ControllerCheckSnapshot,
|
|
910
|
+
storageAuthority?: RepositoryCheckStorageAuthority,
|
|
911
|
+
): ControllerCheckResult {
|
|
642
912
|
const check = snapshot ? validateControllerCheckSnapshot(repoRoot, snapshot) : listControllerChecks(repoRoot).find((entry) => entry.id === id);
|
|
643
913
|
if (!check || check.id !== id) throw new Error(`check not found: ${id}`);
|
|
914
|
+
if (check.executionAuthority === 'live_controller_home') {
|
|
915
|
+
throw new Error('LIVE_CHECK_DURABLE_EXECUTION_REQUIRED');
|
|
916
|
+
}
|
|
917
|
+
const storage = ensureRepositoryCheckStorage(repoRoot, storageAuthority);
|
|
644
918
|
prepareControllerCheckDependencies(repoRoot, check);
|
|
645
|
-
const
|
|
919
|
+
const inputIntegrity = observeControllerCheckContent(repoRoot, { captureFileDigests: true });
|
|
920
|
+
const identity = controllerCheckExecutionIdentityForRevision(repoRoot, id, inputIntegrity.revision, requestedTimeoutMs, snapshot);
|
|
646
921
|
const timeoutMs = identity.timeoutMs;
|
|
647
922
|
const revision = identity.revision;
|
|
648
923
|
const cacheKey = identity.cacheKey;
|
|
649
|
-
const cached = readControllerCheckEvidenceByKey(
|
|
650
|
-
?? readLatestControllerCheckEvidence(repoRoot, id);
|
|
924
|
+
const cached = readControllerCheckEvidenceByKey(storage, id, cacheKey)
|
|
925
|
+
?? readLatestControllerCheckEvidence(repoRoot, id, storage);
|
|
651
926
|
if (cached?.cacheKey === cacheKey && cached.ok) {
|
|
652
927
|
return {
|
|
653
928
|
check,
|
|
@@ -658,20 +933,23 @@ export function runControllerCheck(repoRoot: string, id: string, requestedTimeou
|
|
|
658
933
|
stderr: cached.stderr,
|
|
659
934
|
command: cached.command,
|
|
660
935
|
executedAt: cached.executedAt,
|
|
661
|
-
artifactPath:
|
|
936
|
+
artifactPath: logicalEvidenceArtifactPath(id),
|
|
662
937
|
cacheHit: true,
|
|
663
938
|
validatedRevision: cached.validatedRevision ?? cached.completedRevision ?? cached.revision ?? revision,
|
|
664
939
|
originalExecutedAt: cached.originalExecutedAt ?? cached.executedAt,
|
|
665
940
|
failureClass: cached.failureClass,
|
|
941
|
+
failureEvidence: cached.failureEvidence,
|
|
666
942
|
};
|
|
667
943
|
}
|
|
668
944
|
const heavy = controllerCheckConcurrencyClass(id) === 'heavy';
|
|
669
|
-
const lease = heavy ? tryAcquireHeavyCheckLock(
|
|
945
|
+
const lease = heavy ? tryAcquireHeavyCheckLock(storage, id) : undefined;
|
|
670
946
|
if (heavy && !lease) throw new Error(`heavy check already running for repository: ${id}`);
|
|
947
|
+
const structuredResultPath = structuredCheckResultPath(check);
|
|
671
948
|
let result: ProcessRunResult;
|
|
672
949
|
try {
|
|
673
950
|
const bridgeRuntime = resolveSyncSupervisorBridgeRuntime();
|
|
674
951
|
const childEnvironment = repositoryChildProcessEnvironment();
|
|
952
|
+
if (structuredResultPath) childEnvironment[STRUCTURED_CHECK_RESULT_PATH_ENV] = structuredResultPath;
|
|
675
953
|
delete childEnvironment[CHECK_BRIDGE_RUNTIME_ENV];
|
|
676
954
|
childEnvironment.FORGE_SUPERVISED_REQUEST = Buffer.from(JSON.stringify({
|
|
677
955
|
command: check.command[0],
|
|
@@ -736,17 +1014,23 @@ export function runControllerCheck(repoRoot: string, id: string, requestedTimeou
|
|
|
736
1014
|
} finally {
|
|
737
1015
|
lease?.release();
|
|
738
1016
|
}
|
|
739
|
-
const
|
|
740
|
-
const
|
|
1017
|
+
const structuredObservation = consumeStructuredCheckObservation(check, structuredResultPath);
|
|
1018
|
+
const structuredDecision = applyStructuredCheckObservation(result.ok, structuredObservation);
|
|
1019
|
+
const completedContent = observeControllerCheckContent(repoRoot, { captureFileDigests: true });
|
|
1020
|
+
const completedRevision = completedContent.revision;
|
|
1021
|
+
const stale = controllerCheckInputIntegrityChanged(check, inputIntegrity, completedContent);
|
|
741
1022
|
const executedAt = new Date().toISOString();
|
|
1023
|
+
const effectiveOk = structuredDecision.ok && !stale;
|
|
1024
|
+
const hardInfrastructureFailure = stale || result.timedOut || Boolean(result.error) || Boolean(result.signal);
|
|
742
1025
|
const withoutPath = {
|
|
743
1026
|
check,
|
|
744
|
-
ok:
|
|
745
|
-
status: stale ? 1 : result.status,
|
|
1027
|
+
ok: effectiveOk,
|
|
1028
|
+
status: stale || (!structuredDecision.ok && result.status === 0) ? 1 : result.status,
|
|
746
1029
|
timedOut: result.timedOut,
|
|
747
1030
|
stdout: result.stdout,
|
|
748
1031
|
stderr: [
|
|
749
1032
|
result.stderr || result.error,
|
|
1033
|
+
structuredDecision.error,
|
|
750
1034
|
stale ? 'repository revision changed while the check was running; evidence is stale and the check must be rerun' : '',
|
|
751
1035
|
].filter(Boolean).join('\n'),
|
|
752
1036
|
command: result.command,
|
|
@@ -754,13 +1038,21 @@ export function runControllerCheck(repoRoot: string, id: string, requestedTimeou
|
|
|
754
1038
|
cacheHit: false,
|
|
755
1039
|
validatedRevision: stale ? completedRevision : revision,
|
|
756
1040
|
originalExecutedAt: executedAt,
|
|
757
|
-
failureClass:
|
|
1041
|
+
failureClass: hardInfrastructureFailure
|
|
758
1042
|
? 'infrastructure_failure' as const
|
|
759
|
-
:
|
|
1043
|
+
: structuredDecision.failureClass ?? classifyControllerCheckFailure({
|
|
1044
|
+
ok: effectiveOk,
|
|
1045
|
+
stale,
|
|
1046
|
+
timedOut: result.timedOut,
|
|
1047
|
+
runtimeFailure: Boolean(result.error) || Boolean(result.signal),
|
|
1048
|
+
stdout: result.stdout,
|
|
1049
|
+
stderr: [result.stderr, result.error, structuredDecision.error].filter(Boolean).join('\n'),
|
|
1050
|
+
}),
|
|
1051
|
+
failureEvidence: structuredDecision.failureEvidence,
|
|
760
1052
|
};
|
|
761
1053
|
return {
|
|
762
1054
|
...withoutPath,
|
|
763
|
-
artifactPath: persistCheckEvidence(
|
|
1055
|
+
artifactPath: persistCheckEvidence(storage, withoutPath, {
|
|
764
1056
|
revision,
|
|
765
1057
|
completedRevision,
|
|
766
1058
|
stale,
|
|
@@ -773,6 +1065,11 @@ export function runControllerCheck(repoRoot: string, id: string, requestedTimeou
|
|
|
773
1065
|
|
|
774
1066
|
export interface AsyncControllerCheckOptions {
|
|
775
1067
|
snapshot?: ControllerCheckSnapshot;
|
|
1068
|
+
/** Exact live-state identity supplied by the persisted Work verifier for live certification checks. */
|
|
1069
|
+
executionStateFingerprint?: string;
|
|
1070
|
+
/** Explicit installed Controller Home; never inferred from ambient child environment. */
|
|
1071
|
+
liveControllerHome?: string;
|
|
1072
|
+
storageAuthority?: RepositoryCheckStorageAuthority;
|
|
776
1073
|
/** Explicit isolated authority for Candidate verification child processes. */
|
|
777
1074
|
isolatedControllerHome?: string;
|
|
778
1075
|
requestedTimeoutMs?: number;
|
|
@@ -823,8 +1120,8 @@ interface HeavyCheckLease {
|
|
|
823
1120
|
release(): void;
|
|
824
1121
|
}
|
|
825
1122
|
|
|
826
|
-
function tryAcquireHeavyCheckLock(
|
|
827
|
-
const path = join(
|
|
1123
|
+
function tryAcquireHeavyCheckLock(storage: ResolvedRepositoryCheckStorage, checkId: string): HeavyCheckLease | undefined {
|
|
1124
|
+
const path = join(storage.lockRoot, HEAVY_CHECK_LOCK);
|
|
828
1125
|
mkdirSync(dirname(path), { recursive: true });
|
|
829
1126
|
const lockId = `${process.pid}:${Date.now()}:${checkId}`;
|
|
830
1127
|
const record: HeavyCheckLockRecord = {
|
|
@@ -851,7 +1148,7 @@ function tryAcquireHeavyCheckLock(repoRoot: string, checkId: string): HeavyCheck
|
|
|
851
1148
|
const orphaned = !isProcessAlive(existing?.controllerPid ?? existing?.pid) && !isProcessAlive(existing?.childPid);
|
|
852
1149
|
if (!existing || orphaned) {
|
|
853
1150
|
rmSync(path, { force: true });
|
|
854
|
-
return tryAcquireHeavyCheckLock(
|
|
1151
|
+
return tryAcquireHeavyCheckLock(storage, checkId);
|
|
855
1152
|
}
|
|
856
1153
|
return undefined;
|
|
857
1154
|
}
|
|
@@ -873,10 +1170,10 @@ function tryAcquireHeavyCheckLock(repoRoot: string, checkId: string): HeavyCheck
|
|
|
873
1170
|
};
|
|
874
1171
|
}
|
|
875
1172
|
|
|
876
|
-
async function acquireHeavyCheckLock(
|
|
1173
|
+
async function acquireHeavyCheckLock(storage: ResolvedRepositoryCheckStorage, checkId: string): Promise<HeavyCheckLease> {
|
|
877
1174
|
const deadline = Date.now() + MAX_TIMEOUT_MS * 2;
|
|
878
1175
|
while (true) {
|
|
879
|
-
const lease = tryAcquireHeavyCheckLock(
|
|
1176
|
+
const lease = tryAcquireHeavyCheckLock(storage, checkId);
|
|
880
1177
|
if (lease) return lease;
|
|
881
1178
|
if (Date.now() >= deadline) throw new Error(`timed out waiting for repository heavy-check lock before ${checkId}`);
|
|
882
1179
|
await new Promise((resolvePromise) => setTimeout(resolvePromise, 50));
|
|
@@ -913,13 +1210,19 @@ async function executeControllerCheckAsync(
|
|
|
913
1210
|
repoRoot: string,
|
|
914
1211
|
check: ControllerCheck,
|
|
915
1212
|
timeoutMs: number,
|
|
1213
|
+
storage: ResolvedRepositoryCheckStorage,
|
|
916
1214
|
onSpawn?: (pid: number) => void,
|
|
917
1215
|
isolatedControllerHome?: string,
|
|
1216
|
+
liveControllerHome?: string,
|
|
918
1217
|
): Promise<ControllerCheckResult> {
|
|
919
1218
|
const maxOutputBytes = 256 * 1024;
|
|
920
1219
|
const command = [check.command[0], ...check.command.slice(1)];
|
|
921
1220
|
const childEnvironment = repositoryChildProcessEnvironment();
|
|
922
|
-
|
|
1221
|
+
const structuredResultPath = structuredCheckResultPath(check);
|
|
1222
|
+
if (structuredResultPath) childEnvironment[STRUCTURED_CHECK_RESULT_PATH_ENV] = structuredResultPath;
|
|
1223
|
+
if (isolatedControllerHome?.trim() && liveControllerHome?.trim()) throw new Error('CHECK_CONTROLLER_HOME_AUTHORITY_CONFLICT');
|
|
1224
|
+
if (liveControllerHome?.trim()) childEnvironment.FORGE_CONTROLLER_HOME = resolve(liveControllerHome);
|
|
1225
|
+
else if (isolatedControllerHome?.trim()) childEnvironment.FORGE_CONTROLLER_HOME = resolve(isolatedControllerHome);
|
|
923
1226
|
const supervised = await runBoundedChild(check.command[0], check.command.slice(1), {
|
|
924
1227
|
cwd: resolve(repoRoot, check.cwd),
|
|
925
1228
|
env: childEnvironment,
|
|
@@ -935,19 +1238,34 @@ async function executeControllerCheckAsync(
|
|
|
935
1238
|
const timeoutMessage = supervised.timedOut
|
|
936
1239
|
? `process timed out after ${timeoutMs}ms: ${command.join(' ')}`
|
|
937
1240
|
: '';
|
|
1241
|
+
const processOk = supervised.status === 0 && !supervised.failureCode;
|
|
1242
|
+
const structuredObservation = consumeStructuredCheckObservation(check, structuredResultPath);
|
|
1243
|
+
const structuredDecision = applyStructuredCheckObservation(processOk, structuredObservation);
|
|
1244
|
+
const hardInfrastructureFailure = supervised.timedOut
|
|
1245
|
+
|| Boolean(supervised.failureCode)
|
|
1246
|
+
|| Boolean(supervised.error)
|
|
1247
|
+
|| Boolean(supervised.signal);
|
|
938
1248
|
const result = {
|
|
939
|
-
ok:
|
|
940
|
-
status: supervised.status,
|
|
1249
|
+
ok: structuredDecision.ok,
|
|
1250
|
+
status: !structuredDecision.ok && supervised.status === 0 ? 1 : supervised.status,
|
|
941
1251
|
timedOut: supervised.timedOut,
|
|
942
1252
|
stdout: capProcessOutput(redactProcessOutput(supervised.stdout), maxOutputBytes),
|
|
943
1253
|
stderr: capProcessOutput(redactProcessOutput([
|
|
944
1254
|
supervised.stderr,
|
|
945
1255
|
timeoutMessage || supervised.error || '',
|
|
946
1256
|
processTreeError,
|
|
1257
|
+
structuredDecision.error,
|
|
947
1258
|
].filter(Boolean).join('\n')), maxOutputBytes),
|
|
948
|
-
failureClass:
|
|
1259
|
+
failureClass: hardInfrastructureFailure
|
|
949
1260
|
? 'infrastructure_failure' as const
|
|
950
|
-
:
|
|
1261
|
+
: structuredDecision.failureClass ?? classifyControllerCheckFailure({
|
|
1262
|
+
ok: structuredDecision.ok,
|
|
1263
|
+
timedOut: supervised.timedOut,
|
|
1264
|
+
runtimeFailure: Boolean(supervised.failureCode) || Boolean(supervised.error) || Boolean(supervised.signal),
|
|
1265
|
+
stdout: supervised.stdout,
|
|
1266
|
+
stderr: [supervised.stderr, timeoutMessage, supervised.error, processTreeError, structuredDecision.error].filter(Boolean).join('\n'),
|
|
1267
|
+
}),
|
|
1268
|
+
failureEvidence: structuredDecision.failureEvidence,
|
|
951
1269
|
};
|
|
952
1270
|
|
|
953
1271
|
const executedAt = new Date().toISOString();
|
|
@@ -964,8 +1282,9 @@ async function executeControllerCheckAsync(
|
|
|
964
1282
|
validatedRevision: undefined,
|
|
965
1283
|
originalExecutedAt: executedAt,
|
|
966
1284
|
failureClass: result.failureClass,
|
|
1285
|
+
failureEvidence: result.failureEvidence,
|
|
967
1286
|
};
|
|
968
|
-
return { ...withoutPath, artifactPath:
|
|
1287
|
+
return { ...withoutPath, artifactPath: logicalEvidenceArtifactPath(check.id) };
|
|
969
1288
|
}
|
|
970
1289
|
|
|
971
1290
|
export function runControllerCheckAsync(
|
|
@@ -980,19 +1299,68 @@ export function runControllerCheckAsync(
|
|
|
980
1299
|
return Promise.reject(error);
|
|
981
1300
|
}
|
|
982
1301
|
if (!check || check.id !== id) return Promise.reject(new Error(`check not found: ${id}`));
|
|
1302
|
+
const liveCertification = check.executionAuthority === 'live_controller_home';
|
|
1303
|
+
const liveControllerHome = options.liveControllerHome?.trim();
|
|
1304
|
+
const expectedLiveState = options.executionStateFingerprint?.trim();
|
|
1305
|
+
if (liveCertification) {
|
|
1306
|
+
if (!liveControllerHome || !expectedLiveState) {
|
|
1307
|
+
return Promise.reject(new Error('LIVE_CHECK_EXPLICIT_AUTHORITY_REQUIRED'));
|
|
1308
|
+
}
|
|
1309
|
+
} else if (liveControllerHome) {
|
|
1310
|
+
return Promise.reject(new Error('LIVE_CHECK_AUTHORITY_NOT_DECLARED'));
|
|
1311
|
+
}
|
|
1312
|
+
let storage: ResolvedRepositoryCheckStorage;
|
|
983
1313
|
try {
|
|
1314
|
+
storage = ensureRepositoryCheckStorage(repoRoot, options.storageAuthority);
|
|
984
1315
|
prepareControllerCheckDependencies(repoRoot, check);
|
|
985
1316
|
} catch (error) {
|
|
986
1317
|
return Promise.reject(error);
|
|
987
1318
|
}
|
|
988
|
-
const
|
|
1319
|
+
const inputIntegrity = observeControllerCheckContent(repoRoot, { captureFileDigests: true });
|
|
1320
|
+
const identity = controllerCheckExecutionIdentityForRevision(
|
|
1321
|
+
repoRoot,
|
|
1322
|
+
id,
|
|
1323
|
+
inputIntegrity.revision,
|
|
1324
|
+
options.requestedTimeoutMs,
|
|
1325
|
+
options.snapshot,
|
|
1326
|
+
options.executionStateFingerprint,
|
|
1327
|
+
);
|
|
989
1328
|
const timeoutMs = identity.timeoutMs;
|
|
990
1329
|
const revision = identity.revision;
|
|
991
1330
|
const cacheKey = identity.cacheKey;
|
|
992
|
-
const cached = readControllerCheckEvidenceByKey(
|
|
993
|
-
?? readLatestControllerCheckEvidence(repoRoot, id);
|
|
1331
|
+
const cached = readControllerCheckEvidenceByKey(storage, id, cacheKey)
|
|
1332
|
+
?? readLatestControllerCheckEvidence(repoRoot, id, storage);
|
|
1333
|
+
const withLiveRecoveryFence = async <T>(action: (recoveryFenceInstanceId?: string) => Promise<T> | T): Promise<T> => {
|
|
1334
|
+
if (!liveCertification) return await action(undefined);
|
|
1335
|
+
let attempt;
|
|
1336
|
+
try {
|
|
1337
|
+
attempt = acquireRecoveryOperationLock({
|
|
1338
|
+
controllerHome: liveControllerHome!,
|
|
1339
|
+
action: 'certify_stable_baseline',
|
|
1340
|
+
requestId: `check:${id}:${cacheKey}`,
|
|
1341
|
+
instanceIdPrefix: 'live-certification-',
|
|
1342
|
+
});
|
|
1343
|
+
} catch (error) {
|
|
1344
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1345
|
+
if (message === 'RECOVERY_OPERATION_LOCK_BUSY') throw new Error('LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS');
|
|
1346
|
+
throw new Error(`LIVE_CHECK_RECOVERY_MUTATION_STATE_UNREADABLE: ${message}`);
|
|
1347
|
+
}
|
|
1348
|
+
if (!attempt.acquired) throw new Error('LIVE_CHECK_RECOVERY_MUTATION_IN_PROGRESS');
|
|
1349
|
+
try {
|
|
1350
|
+
const observedLiveState = controllerCheckLiveExecutionStateFingerprint(
|
|
1351
|
+
liveControllerHome!,
|
|
1352
|
+
attempt.handle.record.instanceId,
|
|
1353
|
+
);
|
|
1354
|
+
if (observedLiveState !== expectedLiveState) {
|
|
1355
|
+
throw new Error('LIVE_CHECK_STATE_CHANGED_BEFORE_EXECUTION');
|
|
1356
|
+
}
|
|
1357
|
+
return await action(attempt.handle.record.instanceId);
|
|
1358
|
+
} finally {
|
|
1359
|
+
attempt.handle.close();
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
994
1362
|
if (cached?.cacheKey === cacheKey && cached.ok) {
|
|
995
|
-
return
|
|
1363
|
+
return withLiveRecoveryFence(() => ({
|
|
996
1364
|
check,
|
|
997
1365
|
ok: cached.ok,
|
|
998
1366
|
status: cached.status,
|
|
@@ -1001,12 +1369,12 @@ export function runControllerCheckAsync(
|
|
|
1001
1369
|
stderr: cached.stderr,
|
|
1002
1370
|
command: cached.command,
|
|
1003
1371
|
executedAt: cached.executedAt,
|
|
1004
|
-
artifactPath:
|
|
1372
|
+
artifactPath: logicalEvidenceArtifactPath(id),
|
|
1005
1373
|
cacheHit: true,
|
|
1006
1374
|
validatedRevision: cached.validatedRevision ?? cached.completedRevision ?? cached.revision ?? revision,
|
|
1007
1375
|
originalExecutedAt: cached.originalExecutedAt ?? cached.executedAt,
|
|
1008
1376
|
failureClass: cached.failureClass,
|
|
1009
|
-
});
|
|
1377
|
+
}));
|
|
1010
1378
|
}
|
|
1011
1379
|
const key = `${resolve(repoRoot)}\u0000${id}\u0000${cacheKey}`;
|
|
1012
1380
|
const existing = activeAsyncChecks.get(key);
|
|
@@ -1052,48 +1420,69 @@ export function runControllerCheckAsync(
|
|
|
1052
1420
|
};
|
|
1053
1421
|
const execute = async (lease?: HeavyCheckLease) => {
|
|
1054
1422
|
assertExecutionStillRequested();
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1423
|
+
return withLiveRecoveryFence(async (recoveryFenceInstanceId) => {
|
|
1424
|
+
assertExecutionStillRequested();
|
|
1425
|
+
const result = await executeControllerCheckAsync(repoRoot, check, timeoutMs, storage, (pid) => {
|
|
1426
|
+
lease?.setChildPid(pid);
|
|
1427
|
+
notifySpawn(pid);
|
|
1428
|
+
}, options.isolatedControllerHome, options.liveControllerHome);
|
|
1429
|
+
const completedContent = observeControllerCheckContent(repoRoot, { captureFileDigests: true });
|
|
1430
|
+
const completedRevision = completedContent.revision;
|
|
1431
|
+
let liveStateStale = false;
|
|
1432
|
+
if (liveCertification) {
|
|
1433
|
+
try {
|
|
1434
|
+
liveStateStale = controllerCheckLiveExecutionStateFingerprint(
|
|
1435
|
+
liveControllerHome!,
|
|
1436
|
+
recoveryFenceInstanceId,
|
|
1437
|
+
) !== expectedLiveState;
|
|
1438
|
+
} catch {
|
|
1439
|
+
liveStateStale = true;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
const repositoryStale = controllerCheckInputIntegrityChanged(check, inputIntegrity, completedContent);
|
|
1443
|
+
const stale = repositoryStale || liveStateStale;
|
|
1444
|
+
const finalized = {
|
|
1445
|
+
...result,
|
|
1446
|
+
...(stale ? {
|
|
1447
|
+
ok: false,
|
|
1448
|
+
status: 1,
|
|
1449
|
+
stderr: [
|
|
1450
|
+
result.stderr,
|
|
1451
|
+
repositoryStale
|
|
1452
|
+
? 'repository revision changed while the check was running; evidence is stale and the check must be rerun'
|
|
1453
|
+
: '',
|
|
1454
|
+
liveStateStale
|
|
1455
|
+
? 'live Runtime/Recovery authority changed while the check was running; evidence is stale and the check must be rerun'
|
|
1456
|
+
: '',
|
|
1457
|
+
].filter(Boolean).join('\n'),
|
|
1458
|
+
failureClass: 'infrastructure_failure' as const,
|
|
1459
|
+
} : {}),
|
|
1460
|
+
cacheHit: false,
|
|
1461
|
+
validatedRevision: stale ? completedRevision : revision,
|
|
1462
|
+
};
|
|
1463
|
+
const { artifactPath: _artifactPath, ...withoutPath } = finalized;
|
|
1464
|
+
const artifactPath = persistCheckEvidence(storage, withoutPath, {
|
|
1465
|
+
revision,
|
|
1466
|
+
completedRevision,
|
|
1467
|
+
stale,
|
|
1468
|
+
cacheKey: stale ? undefined : cacheKey,
|
|
1469
|
+
cacheHit: false,
|
|
1470
|
+
validatedRevision: stale ? completedRevision : revision,
|
|
1471
|
+
});
|
|
1472
|
+
return { ...finalized, artifactPath };
|
|
1083
1473
|
});
|
|
1084
|
-
return { ...finalized, artifactPath };
|
|
1085
1474
|
};
|
|
1086
1475
|
const executeHeavy = async (): Promise<ControllerCheckResult> => {
|
|
1087
1476
|
assertExecutionStillRequested();
|
|
1088
|
-
const lease = await acquireHeavyCheckLock(
|
|
1477
|
+
const lease = await acquireHeavyCheckLock(storage, id);
|
|
1089
1478
|
try {
|
|
1090
1479
|
assertExecutionStillRequested();
|
|
1091
1480
|
const currentRevision = currentControllerCheckRevision(repoRoot);
|
|
1092
1481
|
if (currentRevision !== revision) {
|
|
1093
1482
|
throw new Error(`repository revision changed while heavy check ${id} was queued; resubmit the check`);
|
|
1094
1483
|
}
|
|
1095
|
-
const refreshed = readControllerCheckEvidenceByKey(
|
|
1096
|
-
?? readLatestControllerCheckEvidence(repoRoot, id);
|
|
1484
|
+
const refreshed = readControllerCheckEvidenceByKey(storage, id, cacheKey)
|
|
1485
|
+
?? readLatestControllerCheckEvidence(repoRoot, id, storage);
|
|
1097
1486
|
if (refreshed?.cacheKey === cacheKey && refreshed.ok) {
|
|
1098
1487
|
return {
|
|
1099
1488
|
check,
|
|
@@ -1104,7 +1493,7 @@ export function runControllerCheckAsync(
|
|
|
1104
1493
|
stderr: refreshed.stderr,
|
|
1105
1494
|
command: refreshed.command,
|
|
1106
1495
|
executedAt: refreshed.executedAt,
|
|
1107
|
-
artifactPath:
|
|
1496
|
+
artifactPath: logicalEvidenceArtifactPath(id),
|
|
1108
1497
|
cacheHit: true,
|
|
1109
1498
|
validatedRevision: refreshed.validatedRevision ?? refreshed.completedRevision ?? refreshed.revision ?? revision,
|
|
1110
1499
|
originalExecutedAt: refreshed.originalExecutedAt ?? refreshed.executedAt,
|