@humwick/server 0.130.2 → 0.130.3
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/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/workflows.md +16 -0
- package/docs/openapi.json +73 -4
- package/package.json +8 -7
- package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
- package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
- package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
- package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
- package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
- package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
- package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +28 -28
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +2 -1
- package/runner/src/runner-core.ts +14 -15
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +3 -3
- package/src/branch-landed.ts +25 -23
- package/src/bus.ts +21 -19
- package/src/cd-deploy-notify.ts +2 -2
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +3 -3
- package/src/ci/transition-notify.ts +5 -5
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/workflow.ts +12 -3
- package/src/commands-db.ts +4 -4
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +2 -2
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agents-async.ts +8 -5
- package/src/db/agents.ts +15 -12
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuations.ts +4 -4
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -3
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-refs-async.ts +4 -1
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs.ts +8 -8
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +20 -2
- package/src/db/maintenance-job-runs-async.ts +2 -2
- package/src/db/maintenance-job-write-ops.ts +1 -1
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +18 -1
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +10 -4
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +41 -48
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/read-op-marshaling-fixtures.ts +18 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +4 -1
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +5 -3
- package/src/db/task-entity.ts +5 -4
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/token-db-write-ops.ts +2 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +6 -9
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +31 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +42 -46
- package/src/dev.ts +8 -3
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/land-gate-notifications.ts +11 -10
- package/src/land-gate-queue-progress.ts +3 -3
- package/src/land-settle-dispatch.ts +52 -92
- package/src/lifecycle-context-pressure.ts +11 -10
- package/src/lifecycle-manager.ts +104 -98
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +3 -3
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/jobs.ts +29 -67
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +18 -13
- package/src/maintenance/stalled-delivery-pager.ts +4 -4
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +17 -27
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +3 -3
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +8 -8
- package/src/mcp/output-descriptions.ts +1 -1
- package/src/mcp/presentation.ts +2 -1
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +3 -2
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +3 -3
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +1 -1
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +5 -3
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +2 -5
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +8 -1
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +4 -3
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +17 -119
- package/src/routes/auth.ts +14 -15
- package/src/routes/authority-audit.ts +2 -2
- package/src/routes/automations.ts +6 -5
- package/src/routes/channel-binding-delete.ts +1 -1
- package/src/routes/channel-output.ts +3 -3
- package/src/routes/claude-api-budget.ts +5 -5
- package/src/routes/commands-listing.ts +1 -1
- package/src/routes/commands.ts +29 -27
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +2 -1
- package/src/routes/integrations.ts +9 -7
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +3 -3
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +1 -1
- package/src/routes/orchestrator-host-registration.ts +2 -0
- package/src/routes/orchestrator-host-utilization.ts +2 -2
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +27 -18
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +1 -1
- package/src/routes/project-trust.ts +1 -1
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +1 -1
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/team-templates.ts +7 -7
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +18 -17
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +2 -2
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-push.ts +6 -6
- package/src/runtime-grant.ts +17 -11
- package/src/runtime-tokens.ts +20 -28
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +3 -1
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +1 -1
- package/src/server.ts +21 -22
- package/src/services/agent-action.ts +12 -31
- package/src/services/agent-effort.ts +7 -32
- package/src/services/agent-hang-watchdog-job.ts +2 -2
- package/src/services/agent-heartbeat.ts +166 -0
- package/src/services/agent-reporting.ts +1 -1
- package/src/services/browser-inventory.ts +3 -3
- package/src/services/browser-session-state.ts +3 -2
- package/src/services/browser-session.ts +21 -27
- package/src/services/bus-command-update.ts +9 -9
- package/src/services/checkout-refresh-state.ts +1 -0
- package/src/services/checkout-refresh.test-fixture.ts +3 -2
- package/src/services/command-host.ts +7 -2
- package/src/services/coordinator-digest.ts +3 -2
- package/src/services/dispatch-command.ts +12 -13
- package/src/services/effective-launch-driver.ts +14 -9
- package/src/services/host-changed-paths.test-fixture.ts +5 -6
- package/src/services/host-project-readiness.ts +2 -2
- package/src/services/host-providers.ts +1 -1
- package/src/services/host-utilization.ts +9 -9
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +4 -4
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +14 -13
- package/src/services/issue-refs.ts +4 -5
- package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +3 -3
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +6 -5
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +3 -3
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +1 -1
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +8 -3
- package/src/services/profile-trust.ts +2 -2
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +17 -16
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/send-message.ts +16 -33
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +12 -41
- package/src/services/spawn-chain-inspector.ts +1 -1
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +7 -8
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +3 -4
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +5 -5
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +22 -19
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +2 -1
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +1 -1
- package/src/services/workflow-effect-driver.ts +42 -19
- package/src/services/workflow-effects.ts +41 -27
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +1 -0
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +4 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +34 -22
- package/src/services/workflow-supervisor-state.ts +21 -1
- package/src/services/workflow-supervisor.ts +4 -3
- package/src/services/workspace-recovery.ts +4 -3
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-placement.ts +27 -9
- package/src/spawn-targets.ts +8 -8
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +61 -57
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +2 -2
- package/src/task-dispatch-live.ts +5 -2
- package/src/task-dispatcher.ts +2 -2
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +24 -16
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
- package/public/assets/provider-display-DsuWMvVL.js +0 -2
- package/public/assets/run-card-CpKqRbhg.js +0 -2
- package/public/assets/shipping-B9YtnwtG.js +0 -2
- package/public/assets/store-DcClXLH0.js +0 -9
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/src/db/on-loop-write-transaction.ts +0 -34
|
@@ -111,3 +111,18 @@ export function clearAgentNotice(child: Pick<AgentCard, "id" | "epoch" | "meta">
|
|
|
111
111
|
getDb().query("DELETE FROM agent_exit_notices WHERE agent_id = ? AND epoch = ? AND spawn_request_id = ? AND kind = ?")
|
|
112
112
|
.run(child.id, child.epoch, stringValue(child.meta?.spawnRequestId) ?? "", kind);
|
|
113
113
|
}
|
|
114
|
+
|
|
115
|
+
export interface AgentNoticeSlot {
|
|
116
|
+
child: Pick<AgentCard, "id" | "epoch" | "meta">;
|
|
117
|
+
kind: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Called inside notifications.agentNotice, so failure rolls back the slot and all sends. */
|
|
121
|
+
export function insertAgentNoticeSlot({ child, kind }: AgentNoticeSlot, now: number): boolean {
|
|
122
|
+
if (kind === "agent.ready") {
|
|
123
|
+
getDb().query("DELETE FROM agent_exit_notices WHERE agent_id = ? AND kind = 'agent.ready' AND NOT (epoch = ? AND spawn_request_id = ?)")
|
|
124
|
+
.run(child.id, child.epoch, stringValue(child.meta?.spawnRequestId) ?? "");
|
|
125
|
+
}
|
|
126
|
+
return getDb().query("INSERT OR IGNORE INTO agent_exit_notices (agent_id, epoch, spawn_request_id, kind, created_at) VALUES (?, ?, ?, ?, ?)")
|
|
127
|
+
.run(child.id, child.epoch, stringValue(child.meta?.spawnRequestId) ?? "", kind, now).changes > 0;
|
|
128
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { getDb, currentWriteTransactionContext } from "./connection";
|
|
2
|
+
import { clearExpiredLegacyMessageClaimsInTx, timerMessageDeadlineSnapshot } from "./timer-message-cutover";
|
|
3
|
+
import { normalizePhase, readCutover, appendJournal } from "./timer-cutover-state";
|
|
4
|
+
import type { KernelTimersDesiredMode, TimerMessageBackend, TimerMessageCutoverRow } from "./timer-message-flip";
|
|
5
|
+
import type { TimerMessageCutoverPhase, TimerMessageCutoverJournalEntry, TimerMessageDeadlineGuard } from "./timer-cutover-core";
|
|
6
|
+
import type { WriterOpSpec } from "./write-ops";
|
|
7
|
+
|
|
8
|
+
export interface CutoverWriterState {
|
|
9
|
+
ownerId: string; epoch?: number; leaseMs: number; quiesceTimeoutMs: number; worstCaseMs: number;
|
|
10
|
+
authoritativeActivation: boolean; operationLeaseFence?: { requestId: string; ownerId: string };
|
|
11
|
+
}
|
|
12
|
+
export interface CutoverStepArgs {
|
|
13
|
+
abort: { now: number; reason: string };
|
|
14
|
+
activate: { now: number; epoch: number };
|
|
15
|
+
completeLegacy: { now: number; epoch: number };
|
|
16
|
+
completeTransfer: { now: number; epoch: number; mode: KernelTimersDesiredMode; expectedBackend: TimerMessageBackend };
|
|
17
|
+
reverse: { now: number; epoch: number; targetMode: KernelTimersDesiredMode; sourceObservedMode: KernelTimersDesiredMode };
|
|
18
|
+
clearClaims: { now: number };
|
|
19
|
+
acquire: { now: number; create: boolean };
|
|
20
|
+
renew: { now: number; epoch: number };
|
|
21
|
+
closeGate: { epoch: number; now: number };
|
|
22
|
+
transition: { epoch: number; phase: TimerMessageCutoverPhase; reason: string; now: number };
|
|
23
|
+
finishAbort: { epoch: number; reason: string; now: number };
|
|
24
|
+
}
|
|
25
|
+
export interface CutoverStepResults {
|
|
26
|
+
abort: boolean;
|
|
27
|
+
activate: void;
|
|
28
|
+
completeLegacy: void;
|
|
29
|
+
completeTransfer: void;
|
|
30
|
+
reverse: void;
|
|
31
|
+
clearClaims: number;
|
|
32
|
+
acquire: { acquiredEpoch?: number };
|
|
33
|
+
renew: boolean;
|
|
34
|
+
closeGate: boolean;
|
|
35
|
+
transition: void;
|
|
36
|
+
finishAbort: void;
|
|
37
|
+
}
|
|
38
|
+
function owned(state: CutoverWriterState, epoch: number, now: number): TimerMessageCutoverRow {
|
|
39
|
+
const row = readCutover();
|
|
40
|
+
if (!row || row.epoch !== epoch || row.leaseOwner !== state.ownerId || (row.leaseExpiresAt ?? 0) <= now) {
|
|
41
|
+
throw new Error(`cutover epoch ${epoch} is not owned by ${state.ownerId}`);
|
|
42
|
+
}
|
|
43
|
+
return row;
|
|
44
|
+
}
|
|
45
|
+
function deadlineGuard(state: CutoverWriterState, at: number): TimerMessageDeadlineGuard {
|
|
46
|
+
const deadlines = timerMessageDeadlineSnapshot();
|
|
47
|
+
const slackMs = deadlines.earliestDeadline === null ? null : deadlines.earliestDeadline - at;
|
|
48
|
+
return { safe: slackMs === null || slackMs >= state.worstCaseMs, slackMs, requiredMs: state.worstCaseMs, deadlines };
|
|
49
|
+
}
|
|
50
|
+
const steps = {
|
|
51
|
+
abort: (state: CutoverWriterState, { now, reason }: CutoverStepArgs["abort"]) => {
|
|
52
|
+
const row = readCutover();
|
|
53
|
+
if (!row || normalizePhase(row.phase) === "idle") return false;
|
|
54
|
+
return getDb().query(`UPDATE timer_message_cutover
|
|
55
|
+
SET abort_requested = 1, phase_journal = ?, updated_at = ? WHERE id = 1`)
|
|
56
|
+
.run(appendJournal(row, { epoch: row.epoch, phase: "aborting", at: now, reason }), now).changes === 1;
|
|
57
|
+
|
|
58
|
+
},
|
|
59
|
+
activate: (state: CutoverWriterState, { now, epoch }: CutoverStepArgs["activate"]) => {
|
|
60
|
+
const row = owned(state, epoch, now);
|
|
61
|
+
if (normalizePhase(row.phase) !== "quiesced" || row.messageMutationGate !== "closed") {
|
|
62
|
+
throw new Error("ingress routing activation requires the live quiesced gate owner");
|
|
63
|
+
}
|
|
64
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET ingress_policy = 'ingress',
|
|
65
|
+
phase_journal = ?, updated_at = ?
|
|
66
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND lease_expires_at > ?
|
|
67
|
+
AND phase = 'quiesced' AND message_mutation_gate = 'closed'`)
|
|
68
|
+
.run(appendJournal(row, { epoch, phase: "quiesced", at: now, reason: "authoritative ingress routing activated under fence" }),
|
|
69
|
+
now, epoch, state.ownerId, now);
|
|
70
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost before ingress routing activation");
|
|
71
|
+
|
|
72
|
+
},
|
|
73
|
+
completeLegacy: (state: CutoverWriterState, { now, epoch }: CutoverStepArgs["completeLegacy"]) => {
|
|
74
|
+
const row = owned(state, epoch, now);
|
|
75
|
+
if (normalizePhase(row.phase) !== "quiesced" || row.messageMutationGate !== "closed" || row.ingressPolicy !== "ingress") {
|
|
76
|
+
throw new Error("G1 completion requires fenced authoritative ingress routing");
|
|
77
|
+
}
|
|
78
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET
|
|
79
|
+
protocol_version = MAX(COALESCE(protocol_version, 1), 2),
|
|
80
|
+
phase = 'idle', lease_owner = NULL, lease_expires_at = NULL,
|
|
81
|
+
quiesce_started_at = NULL, quiesce_deadline = NULL,
|
|
82
|
+
message_mutation_gate = 'open', gate_epoch = NULL, abort_requested = 0,
|
|
83
|
+
phase_journal = ?, updated_at = ?
|
|
84
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND lease_expires_at > ?
|
|
85
|
+
AND phase = 'quiesced' AND message_mutation_gate = 'closed' AND ingress_policy = 'ingress'`)
|
|
86
|
+
.run(appendJournal(row, { epoch, phase: "idle", at: now, reason: "G1 proven; gate reopened under legacy authority" }),
|
|
87
|
+
now, epoch, state.ownerId, now);
|
|
88
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost before G1 gate reopen");
|
|
89
|
+
|
|
90
|
+
},
|
|
91
|
+
completeTransfer: (state: CutoverWriterState, { now, epoch, mode, expectedBackend }: CutoverStepArgs["completeTransfer"]) => {
|
|
92
|
+
const row = owned(state, epoch, now);
|
|
93
|
+
if (normalizePhase(row.phase) !== "quiesced" || row.messageMutationGate !== "closed"
|
|
94
|
+
|| row.ingressPolicy !== "ingress") {
|
|
95
|
+
throw new Error("authority-transfer completion requires the live quiesced ingress gate owner");
|
|
96
|
+
}
|
|
97
|
+
// Only ACTIVE (scheduled) rows must converge on the target backend — terminal rows never
|
|
98
|
+
// dispatch, so their backend is irrelevant and must not block completion (an ordinary kernel-mode
|
|
99
|
+
// cancel terminalizes a kernel-owned row that a reverse would otherwise be unable to move).
|
|
100
|
+
const wrongOwners = (getDb().query(`SELECT count(*) AS n FROM timer_message_authority
|
|
101
|
+
WHERE lifecycle='scheduled' AND backend != ?`).get(expectedBackend) as { n: number }).n;
|
|
102
|
+
if (wrongOwners !== 0) throw new Error(`${wrongOwners} scheduled MESSAGE owners are not ${expectedBackend}`);
|
|
103
|
+
const expectedFrozen = expectedBackend === "kernel" ? 1 : 0;
|
|
104
|
+
const projectionMismatch = (getDb().query(`SELECT count(*) AS n FROM timer_message_authority a
|
|
105
|
+
JOIN scheduled_timers s ON s.id=a.timer_id
|
|
106
|
+
WHERE a.lifecycle='scheduled' AND (s.command IS NOT NULL OR s.message_authority_frozen != ?)`)
|
|
107
|
+
.get(expectedFrozen) as { n: number }).n;
|
|
108
|
+
if (projectionMismatch !== 0) throw new Error(`${projectionMismatch} MESSAGE compatibility projections disagree with ${mode}`);
|
|
109
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET
|
|
110
|
+
desired_mode = ?, observed_mode = ?, phase = 'idle', lease_owner = NULL,
|
|
111
|
+
lease_expires_at = NULL, quiesce_started_at = NULL, quiesce_deadline = NULL,
|
|
112
|
+
message_mutation_gate = 'open', gate_epoch = NULL, abort_requested = 0,
|
|
113
|
+
phase_journal = ?, updated_at = ?
|
|
114
|
+
WHERE id=1 AND epoch=? AND lease_owner=? AND lease_expires_at>?
|
|
115
|
+
AND phase='quiesced' AND message_mutation_gate='closed' AND ingress_policy='ingress'`)
|
|
116
|
+
.run(mode, mode, appendJournal(row, {
|
|
117
|
+
epoch, phase: "idle", at: now,
|
|
118
|
+
reason: `${mode} per-row ownership proven; MESSAGE mutation gate reopened`,
|
|
119
|
+
}), now, epoch, state.ownerId, now);
|
|
120
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost before authority-transfer completion");
|
|
121
|
+
|
|
122
|
+
},
|
|
123
|
+
reverse: (state: CutoverWriterState, { now, epoch, targetMode, sourceObservedMode }: CutoverStepArgs["reverse"]) => {
|
|
124
|
+
const row = owned(state, epoch, now);
|
|
125
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET desired_mode=?,
|
|
126
|
+
phase_journal=?, updated_at=?
|
|
127
|
+
WHERE id=1 AND epoch=? AND lease_owner=? AND lease_expires_at>?
|
|
128
|
+
AND phase='quiesced' AND message_mutation_gate='closed' AND observed_mode=?`)
|
|
129
|
+
.run(targetMode, appendJournal(row, {
|
|
130
|
+
epoch, phase: "quiesced", at: now,
|
|
131
|
+
reason: `${targetMode} rollback desired; kernel decision commits quiesced for reverse projection`,
|
|
132
|
+
}), now, epoch, state.ownerId, now, sourceObservedMode);
|
|
133
|
+
if (changed.changes !== 1) throw new Error(`reverse transfer requires observed ${sourceObservedMode} under the live fence`);
|
|
134
|
+
|
|
135
|
+
},
|
|
136
|
+
clearClaims: (state: CutoverWriterState, { now }: CutoverStepArgs["clearClaims"]) => {return clearExpiredLegacyMessageClaimsInTx(currentWriteTransactionContext()!, now);
|
|
137
|
+
},
|
|
138
|
+
acquire: (state: CutoverWriterState, { now, create }: CutoverStepArgs["acquire"]) => {let acquiredEpoch: number | undefined; let takeover = false;
|
|
139
|
+
(() => {
|
|
140
|
+
// Stage-10 pins the resolved leg before it asks this independent coordinator to close the
|
|
141
|
+
// global gate. Check that pin's operation lease under THIS acquisition transaction: if an
|
|
142
|
+
// abort won after pin but before requestQuiesce, it cannot be followed by a stale gate close.
|
|
143
|
+
const fence = state.operationLeaseFence;
|
|
144
|
+
if (fence) {
|
|
145
|
+
const live = getDb().query(`SELECT 1 FROM timer_message_cutover_operation
|
|
146
|
+
WHERE id=1 AND request_id=? AND state='running' AND abort_requested=0
|
|
147
|
+
AND lease_owner=? AND lease_expires_at > ?`)
|
|
148
|
+
.get(fence.requestId, fence.ownerId, now);
|
|
149
|
+
if (!live) return;
|
|
150
|
+
}
|
|
151
|
+
const row = readCutover();
|
|
152
|
+
if (!row) {
|
|
153
|
+
if (!create) return;
|
|
154
|
+
acquiredEpoch = 1;
|
|
155
|
+
const journal: TimerMessageCutoverJournalEntry[] = [{ epoch: 1, phase: "leased", at: now, reason: "initial lease acquired" }];
|
|
156
|
+
getDb().query(`INSERT INTO timer_message_cutover
|
|
157
|
+
(id, protocol_version, epoch, desired_mode, observed_mode, phase, lease_owner, lease_expires_at,
|
|
158
|
+
quiesce_started_at, quiesce_deadline, last_completed_timer, ingress_policy,
|
|
159
|
+
message_mutation_gate, gate_epoch, abort_requested, phase_journal, updated_at)
|
|
160
|
+
VALUES (1, 1, 1, 'shadow', 'shadow', 'leased', ?, ?, NULL, NULL, NULL, 'legacy', 'open', NULL, 0, ?, ?)`)
|
|
161
|
+
.run(state.ownerId, now + state.leaseMs, JSON.stringify(journal), now);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const rowPhase = normalizePhase(row.phase);
|
|
165
|
+
const liveForeign = row.leaseOwner !== null && row.leaseOwner !== state.ownerId && (row.leaseExpiresAt ?? 0) > now;
|
|
166
|
+
if (liveForeign) return;
|
|
167
|
+
if (row.leaseOwner === state.ownerId && (row.leaseExpiresAt ?? 0) > now && state.epoch === row.epoch) {
|
|
168
|
+
acquiredEpoch = row.epoch;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const nextEpoch = row.epoch + 1;
|
|
172
|
+
takeover = row.leaseOwner !== null || rowPhase !== "idle" || row.messageMutationGate === "closed";
|
|
173
|
+
const nextPhase: TimerMessageCutoverPhase = rowPhase === "idle" ? "leased" : rowPhase;
|
|
174
|
+
const entry: TimerMessageCutoverJournalEntry = {
|
|
175
|
+
epoch: nextEpoch,
|
|
176
|
+
phase: takeover ? "takeover" : "leased",
|
|
177
|
+
at: now,
|
|
178
|
+
reason: takeover ? `expired epoch ${row.epoch} taken over in phase ${rowPhase}` : "lease acquired",
|
|
179
|
+
};
|
|
180
|
+
const result = getDb().query(`UPDATE timer_message_cutover SET
|
|
181
|
+
protocol_version = COALESCE(protocol_version, 1), epoch = ?, phase = ?, lease_owner = ?, lease_expires_at = ?,
|
|
182
|
+
gate_epoch = CASE WHEN message_mutation_gate = 'closed' THEN ? ELSE NULL END,
|
|
183
|
+
phase_journal = ?, updated_at = ?
|
|
184
|
+
WHERE id = 1 AND (lease_owner IS NULL OR lease_expires_at <= ? OR lease_owner = ?)`)
|
|
185
|
+
.run(nextEpoch, nextPhase, state.ownerId, now + state.leaseMs, nextEpoch,
|
|
186
|
+
appendJournal(row, entry), now, now, state.ownerId);
|
|
187
|
+
if (result.changes === 1) acquiredEpoch = nextEpoch;
|
|
188
|
+
})();
|
|
189
|
+
return { acquiredEpoch };
|
|
190
|
+
},
|
|
191
|
+
renew: (state: CutoverWriterState, { now, epoch }: CutoverStepArgs["renew"]) => {
|
|
192
|
+
const row = readCutover();
|
|
193
|
+
if (!row || row.epoch !== epoch || row.leaseOwner !== state.ownerId || (row.leaseExpiresAt ?? 0) <= now) return false;
|
|
194
|
+
const deadlineCap = row.messageMutationGate === "closed" && row.quiesceDeadline !== null
|
|
195
|
+
? row.quiesceDeadline
|
|
196
|
+
: Number.MAX_SAFE_INTEGER;
|
|
197
|
+
const nextExpiry = Math.min(now + state.leaseMs, deadlineCap);
|
|
198
|
+
return getDb().query(`UPDATE timer_message_cutover SET lease_expires_at = ?, phase_journal = ?, updated_at = ?
|
|
199
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND lease_expires_at > ?`)
|
|
200
|
+
.run(nextExpiry, appendJournal(row, { epoch, phase: "renewed", at: now }), now,
|
|
201
|
+
epoch, state.ownerId, now).changes === 1;
|
|
202
|
+
|
|
203
|
+
},
|
|
204
|
+
closeGate: (state: CutoverWriterState, { epoch, now }: CutoverStepArgs["closeGate"]) => {
|
|
205
|
+
const row = owned(state, epoch, now);
|
|
206
|
+
// `requestQuiesce` acquires the coordinator lease before the following tick closes the gate.
|
|
207
|
+
// Recheck the Stage-10 operation lease in this close transaction: an abort (or expiry) that
|
|
208
|
+
// won in that interval must leave this independent coordinator open and unleased, never
|
|
209
|
+
// permit stale authority to close the MESSAGE gate after the abort's release observed it open.
|
|
210
|
+
const fence = state.operationLeaseFence;
|
|
211
|
+
if (fence) {
|
|
212
|
+
const live = getDb().query(`SELECT 1 FROM timer_message_cutover_operation
|
|
213
|
+
WHERE id=1 AND request_id=? AND state='running' AND abort_requested=0
|
|
214
|
+
AND lease_owner=? AND lease_expires_at > ?`)
|
|
215
|
+
.get(fence.requestId, fence.ownerId, now);
|
|
216
|
+
if (!live) {
|
|
217
|
+
const released = getDb().query(`UPDATE timer_message_cutover SET
|
|
218
|
+
phase = 'idle', lease_owner = NULL, lease_expires_at = NULL,
|
|
219
|
+
quiesce_started_at = NULL, quiesce_deadline = NULL,
|
|
220
|
+
message_mutation_gate = 'open', gate_epoch = NULL, abort_requested = 0,
|
|
221
|
+
desired_mode = observed_mode, phase_journal = ?, updated_at = ?
|
|
222
|
+
WHERE id=1 AND epoch=? AND lease_owner=? AND lease_expires_at>? AND phase='leased'`)
|
|
223
|
+
.run(appendJournal(row, {
|
|
224
|
+
epoch, phase: "idle", at: now,
|
|
225
|
+
reason: "Stage-10 operation lease no longer authorizes MESSAGE gate close",
|
|
226
|
+
}), now, epoch, state.ownerId, now);
|
|
227
|
+
if (released.changes !== 1) throw new Error("cutover lease lost while releasing stale Stage-10 gate request");
|
|
228
|
+
state.epoch = undefined;
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Re-read all three deadline sources under the SAME writer lock that closes the gate. A
|
|
233
|
+
// deadline mutation that won the race is therefore observed here and refuses entry; one that
|
|
234
|
+
// loses cannot commit until after the closed marker and is caught by the next continuous tick.
|
|
235
|
+
const guard = deadlineGuard(state, now);
|
|
236
|
+
if (!guard.safe) {
|
|
237
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET phase = 'aborting', abort_requested = 1,
|
|
238
|
+
phase_journal = ?, updated_at = ? WHERE id = 1 AND epoch = ? AND lease_owner = ? AND phase = 'leased'`)
|
|
239
|
+
.run(appendJournal(row, {
|
|
240
|
+
epoch, phase: "aborting", at: now,
|
|
241
|
+
reason: `deadline guard refused atomic gate close (slack=${guard.slackMs}, required=${guard.requiredMs})`,
|
|
242
|
+
}), now, epoch, state.ownerId);
|
|
243
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost while refusing gate close");
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
const deadline = Math.min(
|
|
247
|
+
now + state.quiesceTimeoutMs,
|
|
248
|
+
guard.deadlines.earliestDeadline === null ? Number.MAX_SAFE_INTEGER : guard.deadlines.earliestDeadline - 1,
|
|
249
|
+
);
|
|
250
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET phase = 'quiescing',
|
|
251
|
+
message_mutation_gate = 'closed', gate_epoch = ?, quiesce_started_at = ?, quiesce_deadline = ?,
|
|
252
|
+
ingress_policy = CASE WHEN ? THEN 'activating' ELSE ingress_policy END,
|
|
253
|
+
phase_journal = ?, updated_at = ?
|
|
254
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND phase = 'leased'`)
|
|
255
|
+
.run(epoch, now, deadline, state.authoritativeActivation ? 1 : 0,
|
|
256
|
+
appendJournal(row, { epoch, phase: "quiescing", at: now, reason: "MESSAGE mutation gate closed" }),
|
|
257
|
+
now, epoch, state.ownerId);
|
|
258
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost before gate close");
|
|
259
|
+
return true;
|
|
260
|
+
|
|
261
|
+
},
|
|
262
|
+
transition: (state: CutoverWriterState, { epoch, phase, reason, now }: CutoverStepArgs["transition"]) => {
|
|
263
|
+
const row = owned(state, epoch, now);
|
|
264
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET phase = ?, phase_journal = ?, updated_at = ?
|
|
265
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND lease_expires_at > ?`)
|
|
266
|
+
.run(phase, appendJournal(row, { epoch, phase, at: now, reason }), now, epoch, state.ownerId, now);
|
|
267
|
+
if (changed.changes !== 1) throw new Error(`cutover lease lost before phase ${phase}`);
|
|
268
|
+
|
|
269
|
+
},
|
|
270
|
+
finishAbort: (state: CutoverWriterState, { epoch, reason, now }: CutoverStepArgs["finishAbort"]) => {
|
|
271
|
+
const row = owned(state, epoch, now);
|
|
272
|
+
const changed = getDb().query(`UPDATE timer_message_cutover SET
|
|
273
|
+
phase = 'idle', lease_owner = NULL, lease_expires_at = NULL,
|
|
274
|
+
quiesce_started_at = NULL, quiesce_deadline = NULL,
|
|
275
|
+
message_mutation_gate = 'open', gate_epoch = NULL, abort_requested = 0,
|
|
276
|
+
phase_journal = ?, updated_at = ?
|
|
277
|
+
WHERE id = 1 AND epoch = ? AND lease_owner = ? AND lease_expires_at > ?`)
|
|
278
|
+
.run(appendJournal(row, { epoch, phase: "idle", at: now, reason: `gate reopened: ${reason}` }),
|
|
279
|
+
now, epoch, state.ownerId, now);
|
|
280
|
+
if (changed.changes !== 1) throw new Error("cutover lease lost before abort release");
|
|
281
|
+
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
export const TIMER_CUTOVER_COORDINATOR_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
285
|
+
"timerCutover.coordinatorStep": { offLoop: true, idempotent: false,
|
|
286
|
+
fn: (input: { step: keyof CutoverStepArgs; state: CutoverWriterState; args: CutoverStepArgs[keyof CutoverStepArgs] }) => {
|
|
287
|
+
const epoch = input.state.epoch;
|
|
288
|
+
const body = steps[input.step] as (state: CutoverWriterState, args: typeof input.args) => unknown;
|
|
289
|
+
const value = body(input.state, input.args);
|
|
290
|
+
return { value: value ?? null, ...(input.state.epoch !== epoch ? { clearEpoch: true } : {}) };
|
|
291
|
+
} },
|
|
292
|
+
});
|