@moretea-labs/forge 1.8.0 → 1.8.1
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 +70 -7
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +228 -1
- package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/interaction-target-authority.ts +142 -18
- package/adapters/mcp/auth.ts +0 -1
- package/adapters/mcp/instructions.ts +5 -4
- package/adapters/mcp/multi-repository.ts +3 -19
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
- package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +18 -504
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +67 -23
- package/adapters/mcp/setup.ts +1 -3
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
- package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
- package/adapters/mcp/toolset-names.ts +5 -0
- package/adapters/mcp/toolset.ts +6 -5
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +154 -677
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/skill-version.json +2 -2
- package/docs/architecture/CURRENT.md +111 -41
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +1 -0
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/forge-plugin-management.md +2 -2
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +14 -6
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +25 -14
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +17 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +25 -63
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +48 -136
- package/scripts/check-runtime-architecture.mjs +622 -217
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/lib/project-init-lib.sh +3 -0
- package/scripts/open-source-audit-allowlist.txt +1 -2
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +0 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +5 -0
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/recovery.ts +135 -121
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context-pack.ts +10 -8
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +39 -1
- package/src/cli/editing/edit-session.ts +1 -7
- package/src/cli/local-bridge/console-automations.ts +18 -13
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +64 -191
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +35 -16
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/registry.ts +77 -11
- package/src/cli/repositories/structured-git.ts +62 -2
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
- package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
- package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +35 -2
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/workers/executor.ts +2 -6
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +85 -28
- package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
- package/src/runtime/plugins/browser-adapter.ts +757 -34
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
- package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime.ts +14 -1
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +222 -11
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/gmail-adapter.ts +23 -2
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +14 -7
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios-adapter.ts +1 -1
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -2
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +602 -428
- package/src/runtime/plugins/types.ts +20 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +105 -19
- package/src/runtime/root/package-runtime-release.ts +117 -18
- package/src/runtime/root/package-runtime-service.ts +17 -11
- package/src/runtime/root/release-execution-canary.ts +44 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -6
- package/src/runtime/root/release-materialize.ts +372 -28
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +159 -27
- package/src/runtime/root/scheduled-controller-composition.ts +28 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +36 -33
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3702 -342
- package/src/runtime/standalone-recovery/entry.ts +469 -39
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
- package/src/runtime/workflow/schedules/engine.ts +138 -172
- package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/stage-runtime-release.ts +0 -44
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { readForgeInstanceIdentity } from '../../../../packages/kernel/identity/api/index';
|
|
2
2
|
import { resolveProjectForRepositoryPlacement } from '../workspace/workspace-store';
|
|
3
3
|
import type { ScopeRef } from '../../../../packages/kernel/identity/api/index';
|
|
4
|
-
import type
|
|
5
|
-
import { getWorkContract,
|
|
6
|
-
import {
|
|
4
|
+
import { recordExperience, recordOutcomeObservation, type ExperienceRecord, type ExperienceStorePort, type OutcomeObservation, type OutcomeObservationStorePort } from '../../../../packages/kernel/memory/api/index';
|
|
5
|
+
import { getWorkContract, isTerminalSemanticWorkState, type WorkContract } from '../../../../packages/kernel/work/api/index';
|
|
6
|
+
import { getControllerRoundRelay } from '../../../../packages/kernel/controller/api/index';
|
|
7
7
|
import { readExecutionArtifact } from '../../evidence/artifact-store';
|
|
8
8
|
import { readExecutionEvidence } from '../../evidence/evidence-store';
|
|
9
9
|
import { assertControlPlaneMetadataPayload } from './metadata-payload-policy';
|
|
@@ -12,14 +12,45 @@ import { deleteControlPlaneRecordWithinTransaction, listControlPlaneRecords, lis
|
|
|
12
12
|
|
|
13
13
|
export const EXPERIENCE_NAMESPACE = 'assistant_experience';
|
|
14
14
|
export const OUTCOME_OBSERVATION_NAMESPACE = 'assistant_outcome_observation';
|
|
15
|
-
export interface ExperienceWriteIdentity {
|
|
15
|
+
export interface ExperienceWriteIdentity {
|
|
16
|
+
workId: string;
|
|
17
|
+
/** Legacy provenance only; never execution or write authority. */
|
|
18
|
+
controllerId?: string;
|
|
19
|
+
/** Legacy provenance only; never execution or write authority. */
|
|
20
|
+
authorityId?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ClosedRoundLearningAuthority { workId: string; sourceRoundId: string }
|
|
23
|
+
|
|
24
|
+
interface ExperienceStoreOptions {
|
|
25
|
+
controllerHome: string;
|
|
26
|
+
repoId: string;
|
|
27
|
+
identity?: ExperienceWriteIdentity;
|
|
28
|
+
closedRoundAuthority?: ClosedRoundLearningAuthority;
|
|
29
|
+
now?: () => string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolvedProjectForWork(work: WorkContract, controllerHome?: string) {
|
|
33
|
+
if (!controllerHome) return undefined;
|
|
34
|
+
const instance = readForgeInstanceIdentity(controllerHome);
|
|
35
|
+
if (!instance) return undefined;
|
|
36
|
+
const declaredProject = work.scopeRef?.kind === 'project'
|
|
37
|
+
? work.scopeRef.id
|
|
38
|
+
: work.engineeringContext?.projectContractReceipt?.projectId;
|
|
39
|
+
return resolveProjectForRepositoryPlacement({
|
|
40
|
+
controllerHome,
|
|
41
|
+
forgeInstanceId: instance.instanceId,
|
|
42
|
+
repositoryId: work.repoId,
|
|
43
|
+
checkoutId: work.checkoutId,
|
|
44
|
+
projectId: declaredProject,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
16
47
|
|
|
17
48
|
export function experienceScopesForWork(work: WorkContract, controllerHome?: string): ScopeRef[] {
|
|
18
49
|
const scopes: ScopeRef[] = [{ schemaVersion: 1, kind: 'work', id: work.workId }];
|
|
19
|
-
const declaredProject = work.scopeRef?.kind === 'project'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
50
|
+
const declaredProject = work.scopeRef?.kind === 'project'
|
|
51
|
+
? work.scopeRef.id
|
|
52
|
+
: work.engineeringContext?.projectContractReceipt?.projectId;
|
|
53
|
+
const projectId = resolvedProjectForWork(work, controllerHome)?.projectId ?? declaredProject;
|
|
23
54
|
if (projectId) scopes.push({ schemaVersion: 1, kind: 'project', id: projectId });
|
|
24
55
|
if (work.requirementId) scopes.push({ schemaVersion: 1, kind: 'requirement', id: work.requirementId });
|
|
25
56
|
if (work.planId) scopes.push({ schemaVersion: 1, kind: 'plan', id: work.planId });
|
|
@@ -28,23 +59,62 @@ export function experienceScopesForWork(work: WorkContract, controllerHome?: str
|
|
|
28
59
|
return scopes;
|
|
29
60
|
}
|
|
30
61
|
|
|
31
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Cognitive recall may include portable Workspace guidance shared by sibling
|
|
64
|
+
* Projects. Raw Controller/Experience writes deliberately remain limited to
|
|
65
|
+
* experienceScopesForWork so project-local observations cannot bypass
|
|
66
|
+
* evidence-backed promotion into cross-project memory.
|
|
67
|
+
*/
|
|
68
|
+
export function cognitiveScopesForWork(work: WorkContract, controllerHome?: string): ScopeRef[] {
|
|
69
|
+
const scopes = experienceScopesForWork(work, controllerHome);
|
|
70
|
+
const workspaceId = resolvedProjectForWork(work, controllerHome)?.workspaceId;
|
|
71
|
+
if (workspaceId && !scopes.some(scope => scope.kind === 'workspace' && scope.id === workspaceId)) {
|
|
72
|
+
scopes.push({ schemaVersion: 1, kind: 'workspace', id: workspaceId });
|
|
73
|
+
}
|
|
74
|
+
return scopes;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function matchesExperienceScope(work: WorkContract, scope: ScopeRef, controllerHome: string): boolean {
|
|
32
78
|
return experienceScopesForWork(work, controllerHome).some(candidate => candidate.kind === scope.kind && candidate.id === scope.id);
|
|
33
79
|
}
|
|
34
80
|
|
|
35
|
-
function
|
|
81
|
+
function matchesCognitiveScope(work: WorkContract, scope: ScopeRef, controllerHome: string): boolean {
|
|
82
|
+
return cognitiveScopesForWork(work, controllerHome).some(candidate => candidate.kind === scope.kind && candidate.id === scope.id);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isLegacyOutputLocatorMiss(error: unknown, kind: 'artifact' | 'evidence'): boolean {
|
|
86
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
+
return kind === 'artifact'
|
|
88
|
+
? message.startsWith('ARTIFACT_LOCATOR_NOT_FOUND:')
|
|
89
|
+
: message.startsWith('EVIDENCE_LOCATOR_NOT_FOUND:');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function canonicalWorkflowEvidenceAvailable(input: { controllerHome: string; repoId: string }, ref: string, scope: ScopeRef, sourceWorkId: string): boolean {
|
|
36
93
|
try {
|
|
37
94
|
const source = getWorkContract(input, sourceWorkId);
|
|
38
|
-
if (!source || !
|
|
95
|
+
if (!source || !matchesCognitiveScope(source, scope, input.controllerHome)) return false;
|
|
39
96
|
const linked = source.evidenceRefs.find(item => item.evidenceId === ref || item.artifactId === ref);
|
|
40
97
|
if (linked) {
|
|
41
98
|
if (ref.startsWith('ART-')) {
|
|
42
|
-
|
|
99
|
+
let artifact;
|
|
100
|
+
try {
|
|
101
|
+
artifact = readExecutionArtifact(input.controllerHome, ref, 16 * 1024);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (!isLegacyOutputLocatorMiss(error, 'artifact')) throw error;
|
|
104
|
+
artifact = readExecutionArtifact(input.controllerHome, ref, 16 * 1024, { legacyRepoId: input.repoId });
|
|
105
|
+
}
|
|
43
106
|
return !artifact.truncated && artifact.artifact.kind === 'evidence';
|
|
44
107
|
}
|
|
45
|
-
if (ref.startsWith('EVD-'))
|
|
108
|
+
if (ref.startsWith('EVD-')) {
|
|
109
|
+
try { return readExecutionEvidence(input.controllerHome, ref).evidenceId === ref; }
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (!isLegacyOutputLocatorMiss(error, 'evidence')) throw error;
|
|
112
|
+
return readExecutionEvidence(input.controllerHome, ref, { legacyRepoId: input.repoId }).evidenceId === ref;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
46
115
|
}
|
|
47
116
|
if (source.checkRefs.some(check => check.receipt?.receiptId === ref && ['passed', 'failed'].includes(check.receipt.status))) return true;
|
|
117
|
+
if (source.engineeringContext?.blockerDispositions?.some(disposition => disposition.receiptId === ref)) return true;
|
|
48
118
|
if (ref.startsWith('workflow-run-') || ref.startsWith('workflow-publication-')) {
|
|
49
119
|
const runs = listControlPlaneRecords<WorkflowRunRecord>(input.controllerHome, { namespace: WORKFLOW_RUN_NAMESPACE, scope: sourceWorkId, limit: 1000 });
|
|
50
120
|
return runs.some(row => row.value.evidenceRef === ref || row.value.publicationReceipt?.receiptId === ref);
|
|
@@ -57,23 +127,58 @@ function canonicalWorkflowEvidenceAvailable(input: { controllerHome: string; rep
|
|
|
57
127
|
} catch { return false; }
|
|
58
128
|
}
|
|
59
129
|
|
|
60
|
-
function
|
|
130
|
+
export function workExperienceProvenance(work: Pick<WorkContract, 'workId' | 'semanticRevision'>): string {
|
|
131
|
+
const revision = Number(work.semanticRevision);
|
|
132
|
+
return `work:${work.workId}:r${Number.isSafeInteger(revision) && revision > 0 ? revision : 'legacy'}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function assertMemoryWriteAuthority(input: { controllerHome: string; repoId: string; identity?: ExperienceWriteIdentity }, scope: ScopeRef, sourceWorkId: string, sourceRoundId: string): void {
|
|
61
136
|
const identity = input.identity;
|
|
62
|
-
if (!identity) throw new Error('
|
|
63
|
-
const current = getWorkContract(input, identity.workId)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
137
|
+
if (!identity?.workId?.trim()) throw new Error('EXPERIENCE_WORK_IDENTITY_REQUIRED');
|
|
138
|
+
const current = getWorkContract(input, identity.workId);
|
|
139
|
+
const source = getWorkContract(input, sourceWorkId);
|
|
140
|
+
if (!current || isTerminalSemanticWorkState(current.semanticState) || !source
|
|
141
|
+
|| current.workId !== source.workId
|
|
142
|
+
|| !matchesExperienceScope(current, scope, input.controllerHome)
|
|
143
|
+
|| !matchesExperienceScope(source, scope, input.controllerHome)) {
|
|
144
|
+
throw new Error('EXPERIENCE_WORK_SCOPE_MISMATCH');
|
|
145
|
+
}
|
|
146
|
+
if (sourceRoundId !== workExperienceProvenance(source)) {
|
|
147
|
+
throw new Error('EXPERIENCE_WORK_PROVENANCE_MISMATCH');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function assertClosedRoundLearningWriteAuthority(
|
|
152
|
+
input: Pick<ExperienceStoreOptions, 'controllerHome' | 'repoId' | 'closedRoundAuthority'>,
|
|
153
|
+
scope: ScopeRef,
|
|
154
|
+
sourceWorkId: string,
|
|
155
|
+
sourceRoundId: string,
|
|
156
|
+
): void {
|
|
157
|
+
const authority = input.closedRoundAuthority;
|
|
158
|
+
if (!authority || authority.workId !== sourceWorkId || authority.sourceRoundId !== sourceRoundId) {
|
|
159
|
+
throw new Error('EXPERIENCE_CLOSED_ROUND_AUTHORITY_MISMATCH');
|
|
160
|
+
}
|
|
161
|
+
const work = getWorkContract(input, authority.workId);
|
|
162
|
+
if (!work || isTerminalSemanticWorkState(work.semanticState) || !matchesExperienceScope(work, scope, input.controllerHome)) {
|
|
163
|
+
throw new Error('EXPERIENCE_CLOSED_ROUND_WORK_SCOPE_MISMATCH');
|
|
164
|
+
}
|
|
165
|
+
const relay = getControllerRoundRelay(input, authority.workId);
|
|
166
|
+
if (!relay?.observationWindow?.some(observation => observation.roundRef === sourceRoundId)) {
|
|
167
|
+
throw new Error('EXPERIENCE_CLOSED_ROUND_NOT_OBSERVED');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function assertExperienceStoreWriteAuthority(input: ExperienceStoreOptions, scope: ScopeRef, sourceWorkId: string, sourceRoundId: string): void {
|
|
172
|
+
if (input.identity && input.closedRoundAuthority) throw new Error('EXPERIENCE_WRITE_AUTHORITY_AMBIGUOUS');
|
|
173
|
+
if (input.closedRoundAuthority) {
|
|
174
|
+
assertClosedRoundLearningWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
assertMemoryWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
|
|
73
178
|
}
|
|
74
179
|
|
|
75
180
|
/** One SQLite writer; nested domain operations share the same transaction. */
|
|
76
|
-
export function controllerExperienceStore(input:
|
|
181
|
+
export function controllerExperienceStore(input: ExperienceStoreOptions): ExperienceStorePort {
|
|
77
182
|
let transaction: SqliteDatabase | undefined;
|
|
78
183
|
const key = (scope: ScopeRef) => `${scope.kind}:${scope.id}`;
|
|
79
184
|
const work = (id: string) => getWorkContract(input, id);
|
|
@@ -86,7 +191,7 @@ export function controllerExperienceStore(input: { controllerHome: string; repoI
|
|
|
86
191
|
});
|
|
87
192
|
},
|
|
88
193
|
assertWriteAuthority(scope, sourceWorkId, sourceRoundId) {
|
|
89
|
-
|
|
194
|
+
assertExperienceStoreWriteAuthority(input, scope, sourceWorkId, sourceRoundId);
|
|
90
195
|
},
|
|
91
196
|
evidenceAvailable(ref, scope, sourceWorkId) {
|
|
92
197
|
return canonicalWorkflowEvidenceAvailable(input, ref, scope, sourceWorkId);
|
|
@@ -113,7 +218,21 @@ export function controllerExperienceStore(input: { controllerHome: string; repoI
|
|
|
113
218
|
};
|
|
114
219
|
}
|
|
115
220
|
|
|
116
|
-
export function
|
|
221
|
+
export function recordClosedRoundExperience(input: {
|
|
222
|
+
controllerHome: string;
|
|
223
|
+
repoId: string;
|
|
224
|
+
authority: ClosedRoundLearningAuthority;
|
|
225
|
+
record: ExperienceRecord;
|
|
226
|
+
now?: string;
|
|
227
|
+
}): ExperienceRecord {
|
|
228
|
+
return recordExperience(
|
|
229
|
+
controllerExperienceStore({ controllerHome: input.controllerHome, repoId: input.repoId, closedRoundAuthority: input.authority }),
|
|
230
|
+
input.record,
|
|
231
|
+
input.now,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function controllerOutcomeObservationStore(input: ExperienceStoreOptions): OutcomeObservationStorePort {
|
|
117
236
|
let transaction: SqliteDatabase | undefined;
|
|
118
237
|
const key = (scope: ScopeRef) => `${scope.kind}:${scope.id}`;
|
|
119
238
|
return {
|
|
@@ -124,7 +243,7 @@ export function controllerOutcomeObservationStore(input: { controllerHome: strin
|
|
|
124
243
|
try { return operation(); } finally { transaction = undefined; }
|
|
125
244
|
});
|
|
126
245
|
},
|
|
127
|
-
assertWriteAuthority(scope, sourceWorkId, sourceRoundId) {
|
|
246
|
+
assertWriteAuthority(scope, sourceWorkId, sourceRoundId) { assertExperienceStoreWriteAuthority(input, scope, sourceWorkId, sourceRoundId); },
|
|
128
247
|
evidenceAvailable(ref, scope, sourceWorkId) { return canonicalWorkflowEvidenceAvailable(input, ref, scope, sourceWorkId); },
|
|
129
248
|
read(scope, id) {
|
|
130
249
|
const row = transaction ? readControlPlaneRecordWithinTransaction<OutcomeObservation>(transaction, OUTCOME_OBSERVATION_NAMESPACE, key(scope), id)
|
|
@@ -146,6 +265,20 @@ export function controllerOutcomeObservationStore(input: { controllerHome: strin
|
|
|
146
265
|
};
|
|
147
266
|
}
|
|
148
267
|
|
|
268
|
+
export function recordClosedRoundOutcomeObservation(input: {
|
|
269
|
+
controllerHome: string;
|
|
270
|
+
repoId: string;
|
|
271
|
+
authority: ClosedRoundLearningAuthority;
|
|
272
|
+
observation: OutcomeObservation;
|
|
273
|
+
now?: string;
|
|
274
|
+
}): OutcomeObservation {
|
|
275
|
+
return recordOutcomeObservation(
|
|
276
|
+
controllerOutcomeObservationStore({ controllerHome: input.controllerHome, repoId: input.repoId, closedRoundAuthority: input.authority }),
|
|
277
|
+
input.observation,
|
|
278
|
+
input.now,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
149
282
|
/** Called by central maintenance, never by recall. A 30-day terminal grace preserves diagnosis. */
|
|
150
283
|
export function cleanupExpiredExperiences(controllerHome: string, now = new Date().toISOString(), limit = 100): number {
|
|
151
284
|
const at = Date.parse(now);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
listControlPlaneRecords,
|
|
3
|
+
listControlPlaneRecordsWithinTransaction,
|
|
3
4
|
readControlPlaneRecord,
|
|
4
5
|
readControlPlaneRecordWithinTransaction,
|
|
5
6
|
withControlPlaneTransaction,
|
|
@@ -7,8 +8,8 @@ import {
|
|
|
7
8
|
type ControlPlaneRecord,
|
|
8
9
|
type SqliteDatabase,
|
|
9
10
|
} from './sqlite-store';
|
|
10
|
-
import { isRepositoryCompletionReceipt, type WorkContract } from '../facade/types';
|
|
11
11
|
import { REQUIREMENT_STATE_TRANSITIONS, type RequirementState } from '../../../../packages/kernel/goal/api/index';
|
|
12
|
+
import type { ScopeRef } from '../../../../packages/kernel/identity/api/index';
|
|
12
13
|
export { REQUIREMENT_STATES, type RequirementState } from '../../../../packages/kernel/goal/api/index';
|
|
13
14
|
|
|
14
15
|
export interface Requirement {
|
|
@@ -30,6 +31,10 @@ export interface Requirement {
|
|
|
30
31
|
planIds: string[];
|
|
31
32
|
acceptedAt: string;
|
|
32
33
|
};
|
|
34
|
+
/** Semantic authored-context revision. Legacy rows normalize to semantic revision 1 until first thin semantic write. */
|
|
35
|
+
semanticRevision?: number;
|
|
36
|
+
/** Timestamp of the authored semantic content; mechanical Requirement updates must not change it. */
|
|
37
|
+
semanticUpdatedAt?: string;
|
|
33
38
|
revision: number;
|
|
34
39
|
createdAt: string;
|
|
35
40
|
updatedAt: string;
|
|
@@ -48,9 +53,41 @@ export interface CreateRequirementInput {
|
|
|
48
53
|
outcomeStatement: string;
|
|
49
54
|
acceptanceCriteria?: string[];
|
|
50
55
|
requiredDeliveryReferences?: string[];
|
|
56
|
+
/** Authority-derived provenance only; raw transports must not pass arbitrary audit refs. */
|
|
57
|
+
auditRefs?: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type SemanticRequirementState = 'open' | 'completed' | 'cancelled';
|
|
61
|
+
|
|
62
|
+
export interface RequirementSemanticView {
|
|
63
|
+
requirementId: string;
|
|
64
|
+
revision: number;
|
|
65
|
+
semanticScope: ScopeRef;
|
|
66
|
+
title: string;
|
|
67
|
+
outcomeStatement: string;
|
|
68
|
+
acceptanceCriteria: string[];
|
|
69
|
+
requiredDeliveryReferences: string[];
|
|
70
|
+
state: SemanticRequirementState;
|
|
71
|
+
createdAt: string;
|
|
72
|
+
updatedAt: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface RequirementRevisionRecord extends RequirementSemanticView {
|
|
76
|
+
schemaVersion: 1;
|
|
77
|
+
recordedAt: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ReviseRequirementSemanticInput {
|
|
81
|
+
expectedRevision: number;
|
|
82
|
+
title?: string;
|
|
83
|
+
outcomeStatement?: string;
|
|
84
|
+
acceptanceCriteria?: string[];
|
|
85
|
+
requiredDeliveryReferences?: string[];
|
|
86
|
+
state?: SemanticRequirementState;
|
|
51
87
|
}
|
|
52
88
|
|
|
53
89
|
const NAMESPACE = 'requirement';
|
|
90
|
+
const REVISION_NAMESPACE = 'requirement_revision';
|
|
54
91
|
const SCOPE = 'controller';
|
|
55
92
|
const SCHEMA_VERSION = 1;
|
|
56
93
|
|
|
@@ -68,6 +105,36 @@ function bounded(values: readonly string[] | undefined, limit: number, maxLength
|
|
|
68
105
|
return (values ?? []).map((value) => String(value).trim()).filter(Boolean).slice(0, limit).map((value) => value.slice(0, maxLength));
|
|
69
106
|
}
|
|
70
107
|
|
|
108
|
+
export function currentRequirementSemanticRevision(requirement: Requirement): number {
|
|
109
|
+
const semantic = Number(requirement.semanticRevision);
|
|
110
|
+
return Number.isInteger(semantic) && semantic > 0 ? semantic : 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function semanticRequirementState(requirement: Pick<Requirement, 'state'>): SemanticRequirementState {
|
|
114
|
+
if (requirement.state === 'done') return 'completed';
|
|
115
|
+
if (requirement.state === 'cancelled') return 'cancelled';
|
|
116
|
+
return 'open';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function requirementSemanticView(requirement: Requirement): RequirementSemanticView {
|
|
120
|
+
return {
|
|
121
|
+
requirementId: requirement.requirementId,
|
|
122
|
+
revision: currentRequirementSemanticRevision(requirement),
|
|
123
|
+
semanticScope: { schemaVersion: 1, kind: 'requirement', id: requirement.requirementId },
|
|
124
|
+
title: requirement.title,
|
|
125
|
+
outcomeStatement: requirement.outcomeStatement,
|
|
126
|
+
acceptanceCriteria: [...requirement.acceptanceCriteria],
|
|
127
|
+
requiredDeliveryReferences: [...requirement.requiredDeliveryReferences],
|
|
128
|
+
state: semanticRequirementState(requirement),
|
|
129
|
+
createdAt: requirement.createdAt,
|
|
130
|
+
updatedAt: requirement.semanticUpdatedAt ?? requirement.createdAt,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function requirementRevisionKey(requirementId: string, revision: number): string {
|
|
135
|
+
return `${id(requirementId)}:r${revision}`;
|
|
136
|
+
}
|
|
137
|
+
|
|
71
138
|
export function isLegacyMachineRequirementWait(requirement: Pick<Requirement, 'state' | 'attentionSummary'>): boolean {
|
|
72
139
|
return requirement.state === 'waiting_for_user'
|
|
73
140
|
&& /^Work .+ delivered machine-valid evidence \(.+\); ChatGPT\/user semantic acceptance is still required\.$/.test(requirement.attentionSummary ?? '');
|
|
@@ -95,6 +162,98 @@ export function listRequirements(
|
|
|
95
162
|
});
|
|
96
163
|
}
|
|
97
164
|
|
|
165
|
+
/** Exact historical lookup, independent of global revision-list limits. */
|
|
166
|
+
export function getRequirementRevisionRecord(
|
|
167
|
+
options: RequirementStoreOptions,
|
|
168
|
+
requirementId: string,
|
|
169
|
+
revision: number,
|
|
170
|
+
): RequirementRevisionRecord | undefined {
|
|
171
|
+
if (!Number.isInteger(revision) || revision < 1) return undefined;
|
|
172
|
+
const record = readControlPlaneRecord<RequirementRevisionRecord>(
|
|
173
|
+
options.controllerHome, REVISION_NAMESPACE, SCOPE, requirementRevisionKey(requirementId, revision),
|
|
174
|
+
)?.value;
|
|
175
|
+
return record ? {
|
|
176
|
+
...record,
|
|
177
|
+
semanticScope: record.semanticScope ?? { schemaVersion: 1, kind: 'requirement', id: record.requirementId },
|
|
178
|
+
} : undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function listRequirementRevisionRecords(
|
|
182
|
+
options: RequirementStoreOptions,
|
|
183
|
+
requirementId?: string,
|
|
184
|
+
limit = 200,
|
|
185
|
+
): RequirementRevisionRecord[] {
|
|
186
|
+
const normalizedId = requirementId ? id(requirementId) : undefined;
|
|
187
|
+
return listControlPlaneRecords<RequirementRevisionRecord>(options.controllerHome, {
|
|
188
|
+
namespace: REVISION_NAMESPACE,
|
|
189
|
+
scope: SCOPE,
|
|
190
|
+
limit: Math.max(1, Math.min(Math.trunc(limit), 1000)),
|
|
191
|
+
}).map((record) => record.value)
|
|
192
|
+
.filter((record) => !normalizedId || record.requirementId === normalizedId)
|
|
193
|
+
.map((record) => ({
|
|
194
|
+
...record,
|
|
195
|
+
semanticScope: record.semanticScope ?? ({ schemaVersion: 1, kind: 'requirement', id: record.requirementId } as const),
|
|
196
|
+
}))
|
|
197
|
+
.sort((left, right) => right.revision - left.revision);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function reviseRequirementSemantic(
|
|
201
|
+
options: RequirementStoreOptions,
|
|
202
|
+
requirementIdInput: string,
|
|
203
|
+
input: ReviseRequirementSemanticInput,
|
|
204
|
+
): Requirement {
|
|
205
|
+
const requirementId = id(requirementIdInput);
|
|
206
|
+
if (!Number.isInteger(input.expectedRevision) || input.expectedRevision < 1) throw new Error('REQUIREMENT_EXPECTED_REVISION_INVALID');
|
|
207
|
+
return withControlPlaneTransaction(options.controllerHome, (database) => {
|
|
208
|
+
const current = readWithin(database, requirementId);
|
|
209
|
+
if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
|
|
210
|
+
const semanticRevision = currentRequirementSemanticRevision(current.value);
|
|
211
|
+
if (semanticRevision !== input.expectedRevision) {
|
|
212
|
+
throw new Error(`REQUIREMENT_REVISION_CONFLICT:${requirementId}:expected=${input.expectedRevision}:actual=${semanticRevision}`);
|
|
213
|
+
}
|
|
214
|
+
const at = nowIso(options);
|
|
215
|
+
const revisionKey = requirementRevisionKey(requirementId, semanticRevision);
|
|
216
|
+
if (!readControlPlaneRecordWithinTransaction<RequirementRevisionRecord>(database, REVISION_NAMESPACE, SCOPE, revisionKey)) {
|
|
217
|
+
const archived: RequirementRevisionRecord = { schemaVersion: 1, ...requirementSemanticView(current.value), recordedAt: at };
|
|
218
|
+
writeControlPlaneRecordWithinTransaction(database, {
|
|
219
|
+
namespace: REVISION_NAMESPACE, scope: SCOPE, key: revisionKey, schemaVersion: 1,
|
|
220
|
+
value: archived, action: 'requirement_semantic_revision_archived', expectedRevision: null,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
const requestedState = input.state;
|
|
224
|
+
if (requestedState === 'open' && (current.value.state === 'done' || current.value.state === 'cancelled')) {
|
|
225
|
+
throw new Error(`REQUIREMENT_SEMANTIC_REOPEN_FORBIDDEN:${requirementId}:${current.value.state}`);
|
|
226
|
+
}
|
|
227
|
+
const legacyState: RequirementState = requestedState === 'completed'
|
|
228
|
+
? 'done'
|
|
229
|
+
: requestedState === 'cancelled'
|
|
230
|
+
? 'cancelled'
|
|
231
|
+
: requestedState === 'open'
|
|
232
|
+
? 'active'
|
|
233
|
+
: current.value.state;
|
|
234
|
+
const title = input.title === undefined ? current.value.title : String(input.title).trim().slice(0, 500);
|
|
235
|
+
const outcomeStatement = input.outcomeStatement === undefined ? current.value.outcomeStatement : String(input.outcomeStatement).trim().slice(0, 2_000);
|
|
236
|
+
if (!title || !outcomeStatement) throw new Error('REQUIREMENT_CONTENT_REQUIRED');
|
|
237
|
+
const updated: Requirement = {
|
|
238
|
+
...current.value,
|
|
239
|
+
title,
|
|
240
|
+
outcomeStatement,
|
|
241
|
+
acceptanceCriteria: input.acceptanceCriteria === undefined ? [...current.value.acceptanceCriteria] : bounded(input.acceptanceCriteria, 50),
|
|
242
|
+
requiredDeliveryReferences: input.requiredDeliveryReferences === undefined ? [...current.value.requiredDeliveryReferences] : bounded(input.requiredDeliveryReferences, 50),
|
|
243
|
+
state: legacyState,
|
|
244
|
+
...(requestedState ? { needsAttention: false, attentionSummary: undefined } : {}),
|
|
245
|
+
semanticRevision: semanticRevision + 1,
|
|
246
|
+
semanticUpdatedAt: at,
|
|
247
|
+
revision: current.value.revision + 1,
|
|
248
|
+
updatedAt: at,
|
|
249
|
+
};
|
|
250
|
+
return writeControlPlaneRecordWithinTransaction(database, {
|
|
251
|
+
namespace: NAMESPACE, scope: SCOPE, key: requirementId, schemaVersion: SCHEMA_VERSION,
|
|
252
|
+
value: updated, action: 'requirement_semantic_revised', expectedRevision: current.revision,
|
|
253
|
+
}).value;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
98
257
|
export function createRequirement(
|
|
99
258
|
options: RequirementStoreOptions,
|
|
100
259
|
input: CreateRequirementInput,
|
|
@@ -109,16 +268,29 @@ export function createRequirement(
|
|
|
109
268
|
outcomeStatement: String(input.outcomeStatement ?? '').trim().slice(0, 2_000),
|
|
110
269
|
acceptanceCriteria: bounded(input.acceptanceCriteria, 50),
|
|
111
270
|
requiredDeliveryReferences: bounded(input.requiredDeliveryReferences, 50),
|
|
271
|
+
auditRefs: bounded(input.auditRefs, 50),
|
|
112
272
|
state: 'planned',
|
|
113
273
|
needsAttention: false,
|
|
274
|
+
semanticRevision: 1,
|
|
275
|
+
semanticUpdatedAt: at,
|
|
114
276
|
revision: 1,
|
|
115
277
|
createdAt: at,
|
|
116
278
|
updatedAt: at,
|
|
117
|
-
auditRefs: [],
|
|
118
279
|
};
|
|
119
280
|
if (!requirement.title || !requirement.outcomeStatement) throw new Error('REQUIREMENT_CONTENT_REQUIRED');
|
|
120
281
|
withControlPlaneTransaction(options.controllerHome, (database) => {
|
|
121
282
|
if (readWithin(database, requirementId)) throw new Error(`REQUIREMENT_ALREADY_EXISTS: ${requirementId}`);
|
|
283
|
+
const exclusiveCandidateRefs = requirement.auditRefs.filter(ref => ref.startsWith('cognitive-requirement-candidate:'));
|
|
284
|
+
if (exclusiveCandidateRefs.length > 0) {
|
|
285
|
+
const existing = listControlPlaneRecordsWithinTransaction<Requirement>(database, {
|
|
286
|
+
namespace: NAMESPACE,
|
|
287
|
+
scope: SCOPE,
|
|
288
|
+
limit: 1000,
|
|
289
|
+
});
|
|
290
|
+
if (existing.length >= 1000) throw new Error('REQUIREMENT_CANDIDATE_BINDING_LOOKUP_LIMIT');
|
|
291
|
+
const alreadyBound = existing.find(record => exclusiveCandidateRefs.some(ref => record.value.auditRefs.includes(ref)));
|
|
292
|
+
if (alreadyBound) throw new Error('REQUIREMENT_CANDIDATE_ALREADY_PROMOTED');
|
|
293
|
+
}
|
|
122
294
|
writeControlPlaneRecordWithinTransaction(database, {
|
|
123
295
|
namespace: NAMESPACE,
|
|
124
296
|
scope: SCOPE,
|
|
@@ -132,6 +304,48 @@ export function createRequirement(
|
|
|
132
304
|
return requirement;
|
|
133
305
|
}
|
|
134
306
|
|
|
307
|
+
export function bindRequirementCandidateAuditRef(
|
|
308
|
+
options: RequirementStoreOptions,
|
|
309
|
+
requirementIdInput: string,
|
|
310
|
+
candidateAuditRefInput: string,
|
|
311
|
+
): Requirement {
|
|
312
|
+
const requirementId = id(requirementIdInput);
|
|
313
|
+
const candidateAuditRef = String(candidateAuditRefInput ?? '').trim().slice(0, 500);
|
|
314
|
+
if (!candidateAuditRef.startsWith('cognitive-requirement-candidate:')) {
|
|
315
|
+
throw new Error('REQUIREMENT_CANDIDATE_AUDIT_REF_INVALID');
|
|
316
|
+
}
|
|
317
|
+
return withControlPlaneTransaction(options.controllerHome, (database) => {
|
|
318
|
+
const records = listControlPlaneRecordsWithinTransaction<Requirement>(database, {
|
|
319
|
+
namespace: NAMESPACE,
|
|
320
|
+
scope: SCOPE,
|
|
321
|
+
limit: 1000,
|
|
322
|
+
});
|
|
323
|
+
if (records.length >= 1000) throw new Error('REQUIREMENT_CANDIDATE_BINDING_LOOKUP_LIMIT');
|
|
324
|
+
const bound = records.find(record => record.value.auditRefs.includes(candidateAuditRef));
|
|
325
|
+
if (bound && bound.value.requirementId !== requirementId) {
|
|
326
|
+
throw new Error('REQUIREMENT_CANDIDATE_ALREADY_PROMOTED');
|
|
327
|
+
}
|
|
328
|
+
const current = readWithin(database, requirementId);
|
|
329
|
+
if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
|
|
330
|
+
if (current.value.auditRefs.includes(candidateAuditRef)) return current.value;
|
|
331
|
+
const updated: Requirement = {
|
|
332
|
+
...current.value,
|
|
333
|
+
auditRefs: [...new Set([...current.value.auditRefs, candidateAuditRef])].slice(-50),
|
|
334
|
+
revision: current.value.revision + 1,
|
|
335
|
+
updatedAt: nowIso(options),
|
|
336
|
+
};
|
|
337
|
+
return writeControlPlaneRecordWithinTransaction(database, {
|
|
338
|
+
namespace: NAMESPACE,
|
|
339
|
+
scope: SCOPE,
|
|
340
|
+
key: requirementId,
|
|
341
|
+
schemaVersion: SCHEMA_VERSION,
|
|
342
|
+
value: updated,
|
|
343
|
+
action: 'requirement_candidate_promoted',
|
|
344
|
+
expectedRevision: current.revision,
|
|
345
|
+
}).value;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
135
349
|
export function updateRequirement(
|
|
136
350
|
options: RequirementStoreOptions,
|
|
137
351
|
input: {
|
|
@@ -167,75 +381,3 @@ export function updateRequirement(
|
|
|
167
381
|
}).value;
|
|
168
382
|
});
|
|
169
383
|
}
|
|
170
|
-
|
|
171
|
-
export interface RequirementCompletionInput {
|
|
172
|
-
requirementId: string;
|
|
173
|
-
work: Pick<WorkContract,
|
|
174
|
-
| 'workId'
|
|
175
|
-
| 'requirementId'
|
|
176
|
-
| 'status'
|
|
177
|
-
| 'phase'
|
|
178
|
-
| 'evidenceState'
|
|
179
|
-
| 'completionOutcome'
|
|
180
|
-
| 'completionReceipt'
|
|
181
|
-
>;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Project machine-complete Work delivery evidence into a Requirement without
|
|
186
|
-
* asserting Requirement-level semantic acceptance. A Work is only one Plan-step
|
|
187
|
-
* execution fact; it must not move the whole Requirement to waiting_for_user
|
|
188
|
-
* while sibling/current Plan slices still exist. Requirement acceptance is a
|
|
189
|
-
* separate lifecycle decision after current Plan/Work authority converges.
|
|
190
|
-
*
|
|
191
|
-
* The legacy function name is retained for compatibility with completion
|
|
192
|
-
* callers. Its authority is evidence projection only, not semantic completion.
|
|
193
|
-
*/
|
|
194
|
-
export function completeRequirementFromWork(
|
|
195
|
-
options: RequirementStoreOptions,
|
|
196
|
-
input: RequirementCompletionInput,
|
|
197
|
-
): Requirement {
|
|
198
|
-
const requirementId = id(input.requirementId);
|
|
199
|
-
const current = readRequirement(options, requirementId);
|
|
200
|
-
if (!current) throw new Error(`REQUIREMENT_NOT_FOUND: ${requirementId}`);
|
|
201
|
-
if (current.value.state === 'done') return current.value;
|
|
202
|
-
if (current.value.state === 'cancelled') throw new Error('REQUIREMENT_CANCELLED');
|
|
203
|
-
|
|
204
|
-
const work = input.work;
|
|
205
|
-
if (work.requirementId !== requirementId) throw new Error('REQUIREMENT_WORK_IDENTITY_MISMATCH');
|
|
206
|
-
if (work.status !== 'completed') throw new Error('REQUIREMENT_WORK_NOT_COMPLETED');
|
|
207
|
-
if (work.phase !== 'cleanup') throw new Error('REQUIREMENT_WORK_CLEANUP_REQUIRED');
|
|
208
|
-
if (work.evidenceState !== 'valid') throw new Error('REQUIREMENT_WORK_EVIDENCE_NOT_VALID');
|
|
209
|
-
if (!work.completionOutcome) throw new Error('REQUIREMENT_WORK_COMPLETION_OUTCOME_REQUIRED');
|
|
210
|
-
if (work.completionOutcome === 'superseded') throw new Error('REQUIREMENT_WORK_OUTCOME_NOT_COMPLETED');
|
|
211
|
-
|
|
212
|
-
const receipt = work.completionReceipt;
|
|
213
|
-
if (!receipt) throw new Error('REQUIREMENT_WORK_COMPLETION_RECEIPT_REQUIRED');
|
|
214
|
-
if (receipt.workId !== work.workId) throw new Error('REQUIREMENT_WORK_RECEIPT_IDENTITY_MISMATCH');
|
|
215
|
-
if (!isRepositoryCompletionReceipt(receipt)) throw new Error('REQUIREMENT_WORK_REPOSITORY_RECEIPT_REQUIRED');
|
|
216
|
-
if (receipt.delivery.kind === 'superseded' || receipt.delivery.status !== 'integrated' || !receipt.delivery.reachable) throw new Error('REQUIREMENT_WORK_DELIVERY_NOT_PROVEN');
|
|
217
|
-
if (!['complete', 'maintenance_warning'].includes(receipt.cleanup.status) || receipt.cleanup.blockers.length > 0) throw new Error('REQUIREMENT_WORK_CLEANUP_NOT_PROVEN');
|
|
218
|
-
|
|
219
|
-
if (current.value.auditRefs.includes(receipt.receiptId)) return current.value;
|
|
220
|
-
return updateRequirement(options, {
|
|
221
|
-
requirementId,
|
|
222
|
-
action: 'requirement_delivery_evidence_recorded',
|
|
223
|
-
mutate: (latest) => {
|
|
224
|
-
// Preserve concurrent terminal or genuinely user-blocked semantic state.
|
|
225
|
-
// Older V2 builds generated waiting_for_user from a single Work receipt;
|
|
226
|
-
// recognize that exact compatibility message and repair it back to active.
|
|
227
|
-
if (latest.state === 'done') return latest;
|
|
228
|
-
if (latest.state === 'cancelled') throw new Error('REQUIREMENT_CANCELLED');
|
|
229
|
-
const legacyMachineWait = latest.state === 'waiting_for_user'
|
|
230
|
-
&& /^Work .+ delivered machine-valid evidence \(.+\); ChatGPT\/user semantic acceptance is still required\.$/.test(latest.attentionSummary ?? '');
|
|
231
|
-
const preserveSemanticWait = latest.state === 'waiting_for_user' && !legacyMachineWait;
|
|
232
|
-
return {
|
|
233
|
-
...latest,
|
|
234
|
-
state: preserveSemanticWait ? 'waiting_for_user' : 'active',
|
|
235
|
-
needsAttention: preserveSemanticWait ? latest.needsAttention : false,
|
|
236
|
-
attentionSummary: preserveSemanticWait ? latest.attentionSummary : undefined,
|
|
237
|
-
auditRefs: Array.from(new Set([...latest.auditRefs, receipt.receiptId])).slice(-50),
|
|
238
|
-
};
|
|
239
|
-
},
|
|
240
|
-
});
|
|
241
|
-
}
|