@humwick/server 0.130.0 → 0.130.2
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/README.md +5 -0
- package/docs/guides/tools-administration.md +6 -1
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +58 -0
- package/docs/openapi.json +414 -1
- package/package.json +8 -17
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-BWLqMGKG.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-3TlIQpjk.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-Wimm0Czv.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-Bau_vNax.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-CrSurn-r.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-CknAJKcb.js} +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-DKbiIhBo.js} +2 -2
- package/public/assets/agent-profiles-DwF6EQ4R.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-Diz4Sjjb.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-CRhpRQza.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-LrUEU3lB.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-B-v66C-4.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-BqCb-LKi.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-kf4pGuAR.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-D32zyw4Y.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-DJevXcvg.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BpRajx_5.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-D_UjTdzX.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-N3VEh4ao.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-9jopungq.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-CSXrTB3C.js} +2 -2
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-p1NnmqK0.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-CZdqlDNL.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BgdsE4dG.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-30aXTKva.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-B_jvw2GE.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-DoN6bAb5.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-BrKWFGJz.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-D6XEu8Ng.js} +2 -2
- package/public/assets/fleet-C7jQWbw2.js +2 -0
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BiDs3MLx.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-CQBwc1fb.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-DyG0WsQS.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-DKaW31dN.js} +2 -2
- package/public/assets/index-CRHep3M9.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-CzrtkpOE.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-aVsUmigt.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-BnSlM_95.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-qe7Ee47Z.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-NfjqFZAk.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-BiH0HgaE.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-BixaT3Xr.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-DNGlWIS3.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-DNsCl6UX.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-DopU1L1X.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Cq7ckLQT.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-C1DCTzzV.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-DE_m6rrE.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-B3rfh77F.js} +2 -2
- package/public/assets/project-profile-instructions-DQWZE0kA.js +2 -0
- package/public/assets/projects-Br2Bd2h1.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-BKvFsvGD.js} +2 -2
- package/public/assets/provider-display-DsuWMvVL.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-Cw38_6gW.js} +2 -2
- package/public/assets/run-card-CpKqRbhg.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-DxI-vzSq.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-D9s_VJbd.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CKZTVGIx.js} +2 -2
- package/public/assets/{shipping-Bu8p1gEw.js → shipping-B9YtnwtG.js} +2 -2
- package/public/assets/{stats-V9Z-GxUd.js → stats-DyUBKyWI.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-DYqlEUhJ.js} +2 -2
- package/public/assets/{store-BvtFdlGX.js → store-DcClXLH0.js} +3 -3
- package/public/assets/{tasks-CXU75HRF.js → tasks-Bh7Chr4-.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-bowI7qVY.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-BgVLHdsU.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-Dz22UPy6.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-DSQQ-iY7.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-samMQhQf.js} +2 -2
- package/public/assets/use-project-list-59LheVP7.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BZa25xEB.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-DHxlvUvV.js} +2 -2
- package/public/assets/versioned-prompt-editor-BmED5DnJ.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-CSvpuNLz.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-DAZcj5qt.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-DdmxRSyg.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-BxeKfVuF.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +31 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
- package/runner/src/adapters/claude-effort.ts +2 -4
- package/runner/src/adapters/codex-launch-config.ts +4 -5
- package/runner/src/adapters/codex.ts +1 -1
- package/runner/src/adapters/opencode-provider.ts +7 -22
- package/runner/src/adapters/opencode.ts +4 -4
- package/runner/src/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +0 -2
- package/runner/src/bin/claude.ts +4 -0
- package/runner/src/bin/codex.ts +4 -0
- package/runner/src/bin/opencode.ts +4 -0
- package/runner/src/index.ts +5 -2
- package/runner/src/provider-setup.ts +34 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +18 -23
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/scripts/cd-config.ts +24 -3
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +7 -76
- package/src/bus.ts +19 -20
- package/src/cd-deploy-notify.ts +30 -2
- package/src/cd-host-lag-notify.ts +7 -6
- package/src/ci/incidents.ts +2 -2
- package/src/ci/monitor.ts +5 -8
- package/src/ci/root-missing.ts +2 -7
- package/src/ci/transition-notify.ts +7 -39
- package/src/cli/cd-pauses.ts +19 -0
- package/src/cli/orchestrator.ts +1 -1
- package/src/cli/state.ts +2 -19
- package/src/cli/task-edit.ts +22 -0
- package/src/cli/task.ts +3 -1
- package/src/cli/workflow.ts +8 -2
- package/src/commands-db.ts +10 -6
- package/src/commands-write.ts +8 -0
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- package/src/db/activity-async.ts +6 -1
- package/src/db/activity-write-ops.ts +13 -1
- package/src/db/activity.ts +1 -14
- package/src/db/agent-lifecycle-write-ops.ts +1 -0
- package/src/db/agent-meta.ts +2 -2
- package/src/db/agent-ownership-write-ops.ts +4 -0
- package/src/db/agent-search.ts +1 -15
- package/src/db/agents-async.ts +58 -7
- package/src/db/agents-write-ops.ts +28 -5
- package/src/db/agents.ts +81 -54
- package/src/db/artifacts-write-ops.ts +8 -3
- package/src/db/bus-outbox-write-ops.ts +1 -0
- package/src/db/channels-write-ops.ts +4 -0
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/claude-api-budget-ops.ts +5 -5
- package/src/db/claude-app-oauth.ts +4 -4
- package/src/db/codex-reset-consumes-write-ops.ts +3 -0
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/commands-write-ops.ts +21 -0
- package/src/db/config-store-write-ops.ts +9 -2
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +9 -0
- package/src/db/continuations.ts +2 -2
- package/src/db/db-writer-worker.ts +8 -1
- package/src/db/delivery-write-ops.ts +5 -0
- package/src/db/deploy-events-async.ts +1 -0
- package/src/db/deploy-events-read-ops.ts +2 -1
- package/src/db/deploy-events.ts +35 -4
- package/src/db/hosts-registration.ts +10 -2
- package/src/db/hosts-write-ops.ts +14 -0
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox-write-ops.ts +4 -0
- package/src/db/inbox.ts +0 -14
- package/src/db/index.ts +2 -0
- package/src/db/insights-write-ops.ts +1 -0
- package/src/db/integrations-async.ts +8 -0
- package/src/db/integrations-ops.ts +15 -0
- package/src/db/integrations.ts +15 -21
- package/src/db/issue-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +20 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +7 -8
- package/src/db/long-running-work.ts +2 -2
- package/src/db/macos-privacy.ts +1 -1
- package/src/db/main-connection-writes.ts +23 -2
- package/src/db/maintenance-job-reconcile.ts +61 -0
- package/src/db/maintenance-job-runs-async.ts +14 -0
- package/src/db/maintenance-job-write-ops.ts +9 -0
- package/src/db/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/message-reads-write-ops.ts +3 -0
- package/src/db/message-write-ops.ts +4 -0
- package/src/db/migrations.ts +7 -15
- package/src/db/orchestrators-async.ts +7 -3
- package/src/db/orchestrators-write-ops.ts +7 -1
- package/src/db/orchestrators.ts +21 -77
- package/src/db/pairs.ts +1 -13
- package/src/db/project-profile-instructions.ts +50 -0
- package/src/db/prompt-versions-ops.ts +1 -0
- package/src/db/prompt-versions.ts +9 -2
- package/src/db/provider-catalog-write-ops.ts +4 -4
- package/src/db/provider-config-history.ts +8 -3
- package/src/db/provider-flap-messages-write-ops.ts +1 -0
- package/src/db/provider-model-seed.ts +34 -0
- package/src/db/provider-quota-lease-write-ops.ts +1 -0
- package/src/db/provider-quota-write-ops.ts +2 -0
- package/src/db/provisioning-write-ops.ts +9 -8
- package/src/db/read-op-marshaling-fixtures.ts +5 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/routing-policy.ts +3 -4
- package/src/db/schema.ts +9 -3
- package/src/db/secrets-broker-write-ops.ts +5 -5
- package/src/db/secrets-vault-write.ts +7 -7
- package/src/db/services-write-ops.ts +3 -0
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/spawn-tree-cleanup.ts +3 -0
- package/src/db/stats-async.ts +4 -3
- package/src/db/task-entity.ts +23 -2
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/team-spawn-delegation.ts +1 -1
- package/src/db/teams-write-ops.ts +4 -4
- package/src/db/timer-cutover-write-ops.ts +7 -0
- package/src/db/timer-ingress-write-ops.ts +9 -0
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/timer-operator-write-ops.ts +14 -0
- package/src/db/timer-transfer-write-ops.ts +4 -0
- package/src/db/timer-write-ops.ts +14 -0
- package/src/db/token-db-write-ops.ts +21 -0
- package/src/db/token-standing.ts +15 -11
- package/src/db/user-settings-write-ops.ts +1 -0
- package/src/db/vault-backup.ts +2 -2
- package/src/db/vault-expiry.ts +2 -2
- package/src/db/vault-health.ts +3 -3
- package/src/db/vault-token-ops.ts +8 -8
- package/src/db/web-tool-call-ops.ts +3 -3
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/write-ops.ts +15 -1
- package/src/db/writer-fault-seam.ts +5 -2
- package/src/db/writer-gateway.ts +21 -12
- package/src/dispatch-availability.ts +10 -6
- package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
- package/src/host/disk-alert.ts +121 -0
- package/src/lifecycle-manager.ts +3 -2
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/critical-job-watchdog.ts +16 -17
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +3 -2
- package/src/maintenance/scheduler.ts +84 -128
- package/src/maintenance/stalled-delivery-pager.ts +6 -5
- package/src/maintenance/workspaces.ts +1 -1
- package/src/managed-policy.ts +31 -27
- package/src/mcp/index.ts +5 -2
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +4 -4
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/tool-groups.ts +1 -1
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-host-tools.ts +1 -1
- package/src/mcp-issue-ref-tools.ts +12 -11
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-profile-trust-tools.ts +4 -4
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-workflow-tools.ts +10 -3
- package/src/notification-types.ts +2 -1
- package/src/operator-alarm.ts +26 -11
- package/src/package-pack.ts +42 -39
- package/src/project-instructions.ts +4 -0
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- package/src/provider-catalog-store.ts +3 -49
- package/src/provider-config-store.ts +12 -11
- package/src/provider-model-seed.ts +1 -18
- package/src/provider-quota-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/recipe-runner.ts +2 -2
- package/src/repo-config-source.ts +10 -4
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +6 -6
- package/src/routes/commands-listing.ts +4 -0
- package/src/routes/commands.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/host-resource-control.ts +4 -1
- package/src/routes/index.ts +10 -1
- package/src/routes/integrations.ts +24 -50
- package/src/routes/issue-refs.ts +7 -7
- package/src/routes/orchestrator-bootstrap.ts +3 -3
- package/src/routes/orchestrator-host-registration.ts +2 -2
- package/src/routes/orchestrator-host-utilization.ts +3 -1
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +4 -4
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +2 -2
- package/src/routes/provider-config.ts +9 -8
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/settings.ts +5 -5
- package/src/routes/stats.ts +6 -6
- package/src/routes/task-http.ts +15 -1
- package/src/routes/task-issues.ts +11 -26
- package/src/routes/tasks.ts +22 -53
- package/src/routes/team-templates.ts +5 -5
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/tokens.ts +12 -5
- package/src/routes/workflows.ts +20 -5
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +4 -2
- package/src/runtime-tokens.ts +50 -9
- package/src/security.ts +13 -20
- package/src/server-background.ts +1 -1
- package/src/server.ts +5 -2
- package/src/services/host-utilization.ts +23 -0
- package/src/services/idle-epics.ts +5 -6
- package/src/services/issue-lifecycle.ts +57 -61
- package/src/services/issue-refs.ts +9 -13
- package/src/services/kernel-timers-cutover-chaos-worker.ts +12 -7
- package/src/services/kernel-timers-ingress.ts +1 -1
- package/src/services/kernel-timers-request-key-migration-chaos-worker.ts +4 -1
- package/src/services/landed-ancestry.ts +19 -3
- package/src/services/memory-areas.ts +15 -51
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-wake-digest.ts +1 -0
- package/src/services/profile-trust.ts +4 -3
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/restart-spawn.ts +61 -49
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +5 -1
- package/src/services/spawn-agent.ts +13 -2
- package/src/services/spawn-chain-inspector.ts +6 -13
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-tree-cleanup.ts +2 -2
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-state-reconcile.ts +6 -14
- package/src/services/team-templates.ts +9 -8
- package/src/services/transient-agent-reaper.ts +3 -1
- package/src/services/workflow-auto-start.ts +25 -13
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-deferred-cleanup.ts +4 -2
- package/src/services/workflow-effect-driver.ts +2 -0
- package/src/services/workflow-effects.ts +18 -11
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-reconcile.ts +13 -11
- package/src/services/workflow-run-view.ts +2 -0
- package/src/services/workflow-runs.ts +29 -13
- package/src/services/workflow-supervisor-state.ts +5 -0
- package/src/services/workflow-supervisor.ts +7 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +1 -1
- package/src/spawn-targets.ts +1 -1
- package/src/startup-context-injection.ts +1 -0
- package/src/state-adoption/cd-cutover.ts +53 -7
- package/src/state-adoption/fleet-cutover.ts +35 -0
- package/src/state-adoption/fleet-plan.ts +36 -0
- package/src/state-adoption/index.ts +2 -2
- package/src/state-adoption/linux-plan.ts +2 -2
- package/src/state-adoption/linux.ts +2 -2
- package/src/state-adoption/macos-plan.ts +2 -2
- package/src/state-adoption/macos.ts +1 -1
- package/src/steward.ts +7 -6
- package/src/task-dispatch-live.ts +1 -1
- package/src/task-dispatcher.ts +1 -1
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/workspace-command-settle.ts +2 -1
- package/src/workspace-steward-wake.ts +2 -2
- package/node_modules/@humwick/kernel/LICENSE +0 -167
- package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
- package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
- package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
- package/node_modules/@humwick/kernel/config.ts +0 -111
- package/node_modules/@humwick/kernel/contract.ts +0 -572
- package/node_modules/@humwick/kernel/control-authz.ts +0 -281
- package/node_modules/@humwick/kernel/control.ts +0 -645
- package/node_modules/@humwick/kernel/effects.ts +0 -493
- package/node_modules/@humwick/kernel/event-log.ts +0 -319
- package/node_modules/@humwick/kernel/http-transport.ts +0 -384
- package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
- package/node_modules/@humwick/kernel/identity.ts +0 -248
- package/node_modules/@humwick/kernel/index.ts +0 -28
- package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
- package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
- package/node_modules/@humwick/kernel/landing.ts +0 -953
- package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
- package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
- package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
- package/node_modules/@humwick/kernel/message-authority.ts +0 -281
- package/node_modules/@humwick/kernel/module-host.ts +0 -722
- package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
- package/node_modules/@humwick/kernel/package.json +0 -47
- package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
- package/node_modules/@humwick/kernel/persistence.ts +0 -510
- package/node_modules/@humwick/kernel/registry.ts +0 -60
- package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
- package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
- package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
- package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
- package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
- package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
- package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
- package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
- package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
- package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
- package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
- package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
- package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
- package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
- package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
- package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
- package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
- package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
- package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
- package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
- package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
- package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
- package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
- package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
- package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
- package/node_modules/@humwick/offload/LICENSE +0 -167
- package/node_modules/@humwick/offload/README.md +0 -57
- package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
- package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
- package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
- package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.js +0 -80
- package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
- package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/index.js +0 -5
- package/node_modules/@humwick/offload/dist/index.js.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
- package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
- package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/types.js +0 -176
- package/node_modules/@humwick/offload/dist/types.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
- package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
- package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.js +0 -1
- package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
- package/node_modules/@humwick/offload/package.json +0 -46
- package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
- package/node_modules/@humwick/offload/src/envelope.ts +0 -92
- package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
- package/node_modules/@humwick/offload/src/index.ts +0 -4
- package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
- package/node_modules/@humwick/offload/src/types.ts +0 -235
- package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
- package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
- package/node_modules/@humwick/offload/src/worker.ts +0 -5
- package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
- package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
- package/public/assets/fleet-BL4UXS_k.js +0 -2
- package/public/assets/index-B7ZerHLY.css +0 -2
- package/public/assets/index-BK0WV6hF.js +0 -15
- package/public/assets/projects-B_lmcqfO.js +0 -2
- package/public/assets/provider-display-DbLWpP3j.js +0 -2
- package/public/assets/run-card-CO_bguQf.js +0 -2
- package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/routing-model-aliases.ts +0 -21
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
import type { Database } from "bun:sqlite";
|
|
2
|
-
import type { Clock, Scope } from "./contract";
|
|
3
|
-
import { reclaimDeadWorkflowLeases, type WorkflowLeaseOwnerProbe } from "./workflow-lease-owner";
|
|
4
|
-
import { ensureEventLogSchema, type EmittedEvent, type EventReplaySlice } from "./event-log";
|
|
5
|
-
import type {
|
|
6
|
-
KernelEntityCatalog,
|
|
7
|
-
KernelEntityListRead,
|
|
8
|
-
KernelEntityMutation,
|
|
9
|
-
KernelEntityPointRead,
|
|
10
|
-
KernelEntityStoredRow,
|
|
11
|
-
KernelJournalOnlyCommitEnvelope,
|
|
12
|
-
KernelModuleCatalog,
|
|
13
|
-
KernelOpCommitEnvelope,
|
|
14
|
-
KernelOpCommitResult,
|
|
15
|
-
KernelPersistence,
|
|
16
|
-
KernelStepCommitEnvelope,
|
|
17
|
-
KernelStoredValue,
|
|
18
|
-
} from "./kernel-persistence";
|
|
19
|
-
import {
|
|
20
|
-
MessageAuthorityCommitRefusedError,
|
|
21
|
-
type MessageAuthorityOperation,
|
|
22
|
-
type MessageAuthorityStore,
|
|
23
|
-
} from "./message-authority";
|
|
24
|
-
import { EntityConflictError } from "./persistence";
|
|
25
|
-
import { quoteIdentifier, type StorageKind } from "./persistence-schema";
|
|
26
|
-
import {
|
|
27
|
-
WorkflowContendedError,
|
|
28
|
-
WorkflowJournalPersistence,
|
|
29
|
-
isSqliteBusy,
|
|
30
|
-
type AcquireLeaseParams,
|
|
31
|
-
type ListInstancesOptions,
|
|
32
|
-
type RenewLeaseParams,
|
|
33
|
-
type WorkflowInstancePage,
|
|
34
|
-
type WorkflowInstanceRow,
|
|
35
|
-
type WorkflowInstanceSeed,
|
|
36
|
-
type WorkflowStepJournalRow,
|
|
37
|
-
} from "./workflow-journal";
|
|
38
|
-
import type { WorkflowStepCommitFaults } from "./workflow-step-commit";
|
|
39
|
-
|
|
40
|
-
const EVENTS_TABLE = "kernel_events";
|
|
41
|
-
const SEQ_TABLE = "kernel_event_scope_seq";
|
|
42
|
-
// The table is the idempotency authority; these bounded maps are only a hot-result optimization.
|
|
43
|
-
const DEDUP_TABLE = "kernel_compat_request_results";
|
|
44
|
-
export const SQLITE_COMPAT_DEDUP_MAX_ENTRIES = 1_024;
|
|
45
|
-
|
|
46
|
-
class BoundedResultMap<V> {
|
|
47
|
-
readonly #entries = new Map<string, V>();
|
|
48
|
-
|
|
49
|
-
get size(): number { return this.#entries.size; }
|
|
50
|
-
get(key: string): V | undefined {
|
|
51
|
-
const value = this.#entries.get(key);
|
|
52
|
-
if (value !== undefined) {
|
|
53
|
-
this.#entries.delete(key);
|
|
54
|
-
this.#entries.set(key, value);
|
|
55
|
-
}
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
set(key: string, value: V): void {
|
|
59
|
-
this.#entries.delete(key);
|
|
60
|
-
this.#entries.set(key, value);
|
|
61
|
-
while (this.#entries.size > SQLITE_COMPAT_DEDUP_MAX_ENTRIES) this.#entries.delete(this.#entries.keys().next().value!);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface CompatibilityOpFaults {
|
|
66
|
-
readonly afterParticipantBeforeEntities?: () => void;
|
|
67
|
-
readonly betweenEntitiesAndEvents?: () => void;
|
|
68
|
-
readonly afterEventsBeforeWorkflowSeeds?: () => void;
|
|
69
|
-
readonly afterWorkflowSeedsBeforeCommit?: () => void;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const opFaults = new WeakMap<KernelPersistence, Map<string, CompatibilityOpFaults>>();
|
|
73
|
-
const stepFaults = new WeakMap<KernelPersistence, Map<string, WorkflowStepCommitFaults>>();
|
|
74
|
-
|
|
75
|
-
/** Private compatibility-only side channel for existing in-process chaos hooks. */
|
|
76
|
-
export function armCompatibilityOpFaults(port: KernelPersistence, requestKey: string, faults: CompatibilityOpFaults): void {
|
|
77
|
-
const entries = opFaults.get(port) ?? new Map();
|
|
78
|
-
entries.set(requestKey, faults);
|
|
79
|
-
opFaults.set(port, entries);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Private compatibility-only side channel for existing in-process chaos hooks. */
|
|
83
|
-
export function armCompatibilityStepFaults(port: KernelPersistence, requestKey: string, faults: WorkflowStepCommitFaults): void {
|
|
84
|
-
const entries = stepFaults.get(port) ?? new Map();
|
|
85
|
-
entries.set(requestKey, faults);
|
|
86
|
-
stepFaults.set(port, entries);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function sqlType(kind: StorageKind): string {
|
|
90
|
-
if (kind === "integer" || kind === "boolean" || kind === "date") return "INTEGER";
|
|
91
|
-
if (kind === "real") return "REAL";
|
|
92
|
-
return "TEXT";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function installEntity(db: Database, entity: KernelEntityCatalog): void {
|
|
96
|
-
const table = quoteIdentifier(entity.tableName);
|
|
97
|
-
const fields = entity.fields.map((field) => `${quoteIdentifier(field.name)} ${sqlType(field.kind)}${field.nullable ? "" : " NOT NULL"}`);
|
|
98
|
-
const references = Object.entries(entity.references).map(([field, ref]) =>
|
|
99
|
-
`FOREIGN KEY (scope, ${quoteIdentifier(field)}) REFERENCES ${quoteIdentifier(`kernel_entity__${ref.module}__${ref.entity}`)}`,
|
|
100
|
-
);
|
|
101
|
-
db.run(`CREATE TABLE IF NOT EXISTS ${table} (
|
|
102
|
-
scope TEXT NOT NULL,
|
|
103
|
-
${fields.join(",\n ")},
|
|
104
|
-
version INTEGER NOT NULL,
|
|
105
|
-
created_at INTEGER NOT NULL,
|
|
106
|
-
updated_at INTEGER NOT NULL,
|
|
107
|
-
PRIMARY KEY (scope, ${quoteIdentifier(entity.key)})${references.length ? `,\n ${references.join(",\n ")}` : ""}
|
|
108
|
-
)`);
|
|
109
|
-
const info = db.query(`PRAGMA table_info(${table})`).all() as Array<{ name: string; type: string; notnull: number; pk: number }>;
|
|
110
|
-
for (const [name, type] of [["scope", "TEXT"], ["version", "INTEGER"], ["created_at", "INTEGER"], ["updated_at", "INTEGER"]] as const) {
|
|
111
|
-
const stored = info.find((row) => row.name === name);
|
|
112
|
-
if (!stored || stored.type.toUpperCase() !== type || stored.notnull !== 1) {
|
|
113
|
-
throw new Error(`entity table '${entity.tableName}' has incompatible kernel column '${name}'`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
const primaryKey = info.filter((row) => row.pk > 0).sort((a, b) => a.pk - b.pk).map((row) => row.name);
|
|
117
|
-
if (primaryKey.length !== 2 || primaryKey[0] !== "scope" || primaryKey[1] !== entity.key) {
|
|
118
|
-
throw new Error(`entity table '${entity.tableName}' must have primary key (scope, ${entity.key})`);
|
|
119
|
-
}
|
|
120
|
-
for (const field of entity.fields) {
|
|
121
|
-
const stored = info.find((row) => row.name === field.name);
|
|
122
|
-
if (!stored) {
|
|
123
|
-
if (!field.nullable) throw new Error(`cannot add required field '${field.name}' to existing entity table '${entity.tableName}'`);
|
|
124
|
-
db.run(`ALTER TABLE ${table} ADD COLUMN ${quoteIdentifier(field.name)} ${sqlType(field.kind)}`);
|
|
125
|
-
} else if (stored.type.toUpperCase() !== sqlType(field.kind)) {
|
|
126
|
-
throw new Error(`entity field '${entity.moduleId}.${entity.entityName}.${field.name}' changed SQLite type`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
entity.indexes.forEach((names, index) => db.run(
|
|
130
|
-
`CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${entity.tableName}__idx_${index}`)} ON ${table} (scope, ${names.map(quoteIdentifier).join(", ")})`,
|
|
131
|
-
));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function columns(entity: KernelEntityCatalog): string {
|
|
135
|
-
return entity.fields.map((field) => quoteIdentifier(field.name)).join(", ");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function storedRow(entity: KernelEntityCatalog, row: Record<string, unknown> | null): KernelEntityStoredRow | undefined {
|
|
139
|
-
if (!row) return undefined;
|
|
140
|
-
return {
|
|
141
|
-
values: Object.fromEntries(entity.fields.map((field) => [field.name, row[field.name] as KernelStoredValue])),
|
|
142
|
-
version: row.version as number,
|
|
143
|
-
createdAt: row.created_at as number,
|
|
144
|
-
updatedAt: row.updated_at as number,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function applyAuthority(db: Database, store: MessageAuthorityStore | undefined, operations: readonly MessageAuthorityOperation[]): void {
|
|
149
|
-
for (const operation of operations) {
|
|
150
|
-
const result = store?.executeInTransaction(db, operation);
|
|
151
|
-
if (!result) throw new Error("MESSAGE authority participation is not configured on this host");
|
|
152
|
-
if (!result.ok) throw new MessageAuthorityCommitRefusedError(result, operation);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function applyEntities(db: Database, mutations: readonly KernelEntityMutation[], now: number): void {
|
|
157
|
-
for (const mutation of mutations) {
|
|
158
|
-
const table = quoteIdentifier(mutation.entity.tableName);
|
|
159
|
-
const key = quoteIdentifier(mutation.entity.key);
|
|
160
|
-
let changes: number;
|
|
161
|
-
if (mutation.kind === "delete") {
|
|
162
|
-
changes = db.query(`DELETE FROM ${table} WHERE scope = ? AND ${key} = ? AND version = ?`)
|
|
163
|
-
.run(mutation.scope, mutation.key, mutation.expectedVersion).changes;
|
|
164
|
-
} else if (mutation.expectedVersion === null) {
|
|
165
|
-
const names = mutation.entity.fields.map((field) => field.name);
|
|
166
|
-
const values = names.map((name) => mutation.values?.[name] ?? null);
|
|
167
|
-
changes = db.query(`INSERT INTO ${table} (scope, ${names.map(quoteIdentifier).join(", ")}, version, created_at, updated_at)
|
|
168
|
-
VALUES (?, ${names.map(() => "?").join(", ")}, 0, ?, ?) ON CONFLICT DO NOTHING`)
|
|
169
|
-
.run(mutation.scope, ...values, now, now).changes;
|
|
170
|
-
} else {
|
|
171
|
-
const names = mutation.entity.fields.map((field) => field.name);
|
|
172
|
-
changes = db.query(`UPDATE ${table} SET ${names.map((name) => `${quoteIdentifier(name)} = ?`).join(", ")}, version = version + 1, updated_at = ?
|
|
173
|
-
WHERE scope = ? AND ${key} = ? AND version = ?`).run(
|
|
174
|
-
...names.map((name) => mutation.values?.[name] ?? null), now, mutation.scope, mutation.key, mutation.expectedVersion,
|
|
175
|
-
).changes;
|
|
176
|
-
}
|
|
177
|
-
if (changes !== 1) throw new EntityConflictError(mutation.entity.moduleId, mutation.entity.entityName, mutation.logicalKey);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function appendEvents(db: Database, events: KernelOpCommitEnvelope["events"]): void {
|
|
182
|
-
if (events.length === 0) return;
|
|
183
|
-
const groups = new Map<Scope, typeof events>();
|
|
184
|
-
for (const event of events) groups.set(event.scope, [...(groups.get(event.scope) ?? []), event]);
|
|
185
|
-
for (const [scope, scoped] of groups) {
|
|
186
|
-
const bumped = db.query(`INSERT INTO ${SEQ_TABLE} (scope, high_water) VALUES (?, ?)
|
|
187
|
-
ON CONFLICT(scope) DO UPDATE SET high_water = high_water + excluded.high_water RETURNING high_water`)
|
|
188
|
-
.get(scope, scoped.length) as { high_water: number };
|
|
189
|
-
const first = bumped.high_water - scoped.length + 1;
|
|
190
|
-
scoped.forEach((event, index) => db.run(
|
|
191
|
-
`INSERT INTO ${EVENTS_TABLE} (scope, seq, module_id, name, payload, created_at) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
192
|
-
[scope, first + index, event.moduleId, event.name, event.payload, event.createdAt],
|
|
193
|
-
));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Private K0 adapter. Production src gateway registration replaces this in K1. */
|
|
198
|
-
export class SqliteKernelPersistence implements KernelPersistence {
|
|
199
|
-
readonly #journal: WorkflowJournalPersistence;
|
|
200
|
-
readonly #opResults = new BoundedResultMap<KernelOpCommitResult>();
|
|
201
|
-
readonly #stepResults = new BoundedResultMap<number>();
|
|
202
|
-
readonly #writeResults = new BoundedResultMap<unknown>();
|
|
203
|
-
readonly messageAuthorityAvailable: boolean;
|
|
204
|
-
|
|
205
|
-
constructor(
|
|
206
|
-
readonly db: Database,
|
|
207
|
-
readonly clock: Clock,
|
|
208
|
-
readonly messageAuthority: MessageAuthorityStore | undefined,
|
|
209
|
-
/** `null`: a borrowed connection whose owner sets busy_timeout (see WorkflowJournalOptions). */
|
|
210
|
-
busyTimeoutMs?: number | null,
|
|
211
|
-
bootstrap = true,
|
|
212
|
-
readonly leaseOwnerProbe?: WorkflowLeaseOwnerProbe,
|
|
213
|
-
) {
|
|
214
|
-
db.run("PRAGMA foreign_keys = ON");
|
|
215
|
-
const foreignKeys = db.query("PRAGMA foreign_keys").get() as { foreign_keys: number } | undefined;
|
|
216
|
-
if (foreignKeys?.foreign_keys !== 1) throw new Error("kernel SQLite compatibility adapter requires foreign keys to be enabled");
|
|
217
|
-
if (bootstrap) ensureEventLogSchema(db);
|
|
218
|
-
if (bootstrap) db.run(`CREATE TABLE IF NOT EXISTS ${DEDUP_TABLE} (
|
|
219
|
-
operation TEXT NOT NULL,
|
|
220
|
-
request_key TEXT NOT NULL,
|
|
221
|
-
result TEXT NOT NULL,
|
|
222
|
-
PRIMARY KEY (operation, request_key)
|
|
223
|
-
)`);
|
|
224
|
-
this.#journal = new WorkflowJournalPersistence({ db, clock, installSchema: bootstrap, ...(busyTimeoutMs !== undefined ? { busyTimeoutMs } : {}) });
|
|
225
|
-
this.messageAuthorityAvailable = messageAuthority !== undefined;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
installModule(catalog: KernelModuleCatalog): Promise<void> {
|
|
229
|
-
this.installModuleSync(catalog);
|
|
230
|
-
return Promise.resolve();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
installModuleSync(catalog: KernelModuleCatalog): void {
|
|
234
|
-
const install = () => {
|
|
235
|
-
for (const entity of catalog.entities) installEntity(this.db, entity);
|
|
236
|
-
};
|
|
237
|
-
if (this.db.inTransaction) install();
|
|
238
|
-
else this.db.transaction(install).immediate();
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
moduleTableExistsSync(tableName: string): boolean {
|
|
242
|
-
return this.db.query("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(tableName) != null;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
entityPointSync(input: KernelEntityPointRead): KernelEntityStoredRow | undefined {
|
|
246
|
-
const row = this.db.query(`SELECT ${columns(input.entity)}, version, created_at, updated_at FROM ${quoteIdentifier(input.entity.tableName)}
|
|
247
|
-
WHERE scope = ? AND ${quoteIdentifier(input.entity.key)} = ?`).get(input.scope, input.key) as Record<string, unknown> | null;
|
|
248
|
-
return storedRow(input.entity, row);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
entityListSync(input: KernelEntityListRead): readonly KernelEntityStoredRow[] {
|
|
252
|
-
const clauses = ["scope = ?"];
|
|
253
|
-
const bindings: KernelStoredValue[] = [input.scope];
|
|
254
|
-
for (const [name, value] of Object.entries(input.where)) {
|
|
255
|
-
clauses.push(value === null ? `${quoteIdentifier(name)} IS NULL` : `${quoteIdentifier(name)} = ?`);
|
|
256
|
-
if (value !== null) bindings.push(value);
|
|
257
|
-
}
|
|
258
|
-
if (input.after !== undefined) { clauses.push(`${quoteIdentifier(input.entity.key)} > ?`); bindings.push(input.after); }
|
|
259
|
-
const rows = this.db.query(`SELECT ${columns(input.entity)}, version, created_at, updated_at FROM ${quoteIdentifier(input.entity.tableName)}
|
|
260
|
-
WHERE ${clauses.join(" AND ")} ORDER BY ${quoteIdentifier(input.entity.key)} ASC LIMIT ?`)
|
|
261
|
-
.all(...bindings, input.limit) as Array<Record<string, unknown>>;
|
|
262
|
-
return rows.map((row) => storedRow(input.entity, row)!);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
replayEventsSync(scope: Scope, since: number, limit: number, moduleId?: string): EventReplaySlice {
|
|
266
|
-
const pageSize = Math.min(Math.max(Math.trunc(limit), 1), 5_000);
|
|
267
|
-
const rows = (moduleId === undefined
|
|
268
|
-
? this.db.query(`SELECT scope, seq, module_id, name, payload, created_at FROM ${EVENTS_TABLE} WHERE scope = ? AND seq > ? ORDER BY seq LIMIT ?`).all(scope, since, pageSize)
|
|
269
|
-
: this.db.query(`SELECT scope, seq, module_id, name, payload, created_at FROM ${EVENTS_TABLE} WHERE scope = ? AND module_id = ? AND seq > ? ORDER BY seq LIMIT ?`).all(scope, moduleId, since, pageSize)) as Array<Record<string, unknown>>;
|
|
270
|
-
const events = rows.map((row) => ({ scope: row.scope as Scope, seq: row.seq as number, moduleId: row.module_id as string, name: row.name as EmittedEvent["name"], payload: JSON.parse(row.payload as string), createdAt: row.created_at as number }));
|
|
271
|
-
const lastSeq = events.at(-1)?.seq ?? since;
|
|
272
|
-
const more = moduleId === undefined
|
|
273
|
-
? this.eventHighWaterSync(scope) > lastSeq
|
|
274
|
-
: this.db.query(`SELECT 1 FROM ${EVENTS_TABLE} WHERE scope = ? AND module_id = ? AND seq > ? LIMIT 1`).get(scope, moduleId, lastSeq) != null;
|
|
275
|
-
return { events, lastSeq, truncated: rows.length === pageSize && more };
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
eventHighWaterSync(scope: Scope): number {
|
|
279
|
-
return (this.db.query(`SELECT high_water FROM ${SEQ_TABLE} WHERE scope = ?`).get(scope) as { high_water: number } | undefined)?.high_water ?? 0;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
eventHasMatchSync(scope: Scope, topic: string, correlationId?: string): boolean {
|
|
283
|
-
let since = 0;
|
|
284
|
-
for (;;) {
|
|
285
|
-
const page = this.replayEventsSync(scope, since, 5_000);
|
|
286
|
-
if (page.events.some((event) => event.name === topic && (correlationId === undefined || (event.payload as { correlationId?: unknown } | null)?.correlationId === correlationId))) return true;
|
|
287
|
-
if (!page.truncated) return false;
|
|
288
|
-
since = page.lastSeq;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
getWorkflowInstanceSync(id: string) { return this.#journal.getInstance(id); }
|
|
293
|
-
getWorkflowInstanceByIdentitySync(moduleName: string, workflowName: string, idempotencyKey: string) { return this.#journal.getInstanceByIdentity(moduleName, workflowName, idempotencyKey); }
|
|
294
|
-
listWorkflowInstancesSync(options?: ListInstancesOptions): WorkflowInstancePage { return this.#journal.listInstances(options); }
|
|
295
|
-
listWorkflowStepsSync(instanceId: string): WorkflowStepJournalRow[] { return this.#journal.listSteps(instanceId); }
|
|
296
|
-
listResumableWorkflowsSync(moduleName: string, now: number) { return this.#journal.listResumable(moduleName, now); }
|
|
297
|
-
listDueWorkflowsSync(moduleName: string, now: number) { return this.#journal.listDueSleepers(moduleName, now); }
|
|
298
|
-
listWaitingWorkflowsSync(moduleName: string, now: number) { return this.#journal.listWaiters(moduleName, now); }
|
|
299
|
-
snapshotWorkflowResidualSync(moduleName: string, now: number) { return this.#journal.snapshotReconcileResidual(moduleName, now); }
|
|
300
|
-
seedWorkflowSync(requestKey: string, seed: WorkflowInstanceSeed, capturedAt: number) {
|
|
301
|
-
return this.#cachedWrite(requestKey, "seedWorkflow", () => this.#journal.createInstanceIfAbsent(seed, capturedAt));
|
|
302
|
-
}
|
|
303
|
-
acquireWorkflowLeaseSync(requestKey: string, params: AcquireLeaseParams) {
|
|
304
|
-
return this.#cachedWrite(requestKey, "acquireLease", () => this.#journal.acquireLease(params), params.instanceId);
|
|
305
|
-
}
|
|
306
|
-
reclaimDeadWorkflowLeasesSync(moduleName: string, now: number): void {
|
|
307
|
-
reclaimDeadWorkflowLeases(this.db, moduleName, now, this.leaseOwnerProbe);
|
|
308
|
-
}
|
|
309
|
-
renewWorkflowLeaseSync(requestKey: string, params: RenewLeaseParams) {
|
|
310
|
-
return this.#cachedWrite(requestKey, "renewLease", () => this.#journal.renewLease(params), params.instanceId);
|
|
311
|
-
}
|
|
312
|
-
releaseWorkflowLeaseSync(requestKey: string, instanceId: string, token: string, now: number) {
|
|
313
|
-
try {
|
|
314
|
-
return this.#cachedWrite(requestKey, "releaseWorkflowLease", () => this.#journal.releaseLease(instanceId, token, now));
|
|
315
|
-
} catch (error) {
|
|
316
|
-
if (isSqliteBusy(error)) return false;
|
|
317
|
-
throw error;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
controlWorkflowSync(requestKey: string, operation: "cancel" | "pause" | "resume" | "reopen" | "fail", id: string, now: number, failure?: unknown) {
|
|
321
|
-
return this.#cachedWrite(requestKey, `controlWorkflow:${operation}`, () => {
|
|
322
|
-
if (operation === "cancel") return this.#journal.cancelInstance(id, now);
|
|
323
|
-
if (operation === "pause") return this.#journal.pauseInstance(id, now);
|
|
324
|
-
if (operation === "resume") return this.#journal.resumeInstance(id, now);
|
|
325
|
-
if (operation === "reopen") return this.#journal.reopenInstance(id, now);
|
|
326
|
-
return this.#journal.failInstance(id, failure as never, now);
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
opCommitSync(envelope: KernelOpCommitEnvelope): KernelOpCommitResult {
|
|
331
|
-
const operation = "opCommit";
|
|
332
|
-
const cacheKey = this.#cacheKey(operation, envelope.requestKey);
|
|
333
|
-
const prior = this.#knownResult(this.#opResults, operation, envelope.requestKey);
|
|
334
|
-
if (prior) return prior;
|
|
335
|
-
const faults = opFaults.get(this)?.get(envelope.requestKey);
|
|
336
|
-
const result = this.db.transaction(() => {
|
|
337
|
-
const durable = this.#durableResult<KernelOpCommitResult>(operation, envelope.requestKey);
|
|
338
|
-
if (durable !== undefined) return durable;
|
|
339
|
-
const workflowInstanceIds: string[] = [];
|
|
340
|
-
applyAuthority(this.db, this.messageAuthority, envelope.messageAuthority);
|
|
341
|
-
faults?.afterParticipantBeforeEntities?.();
|
|
342
|
-
applyEntities(this.db, envelope.entities, envelope.capturedAt);
|
|
343
|
-
faults?.betweenEntitiesAndEvents?.();
|
|
344
|
-
appendEvents(this.db, envelope.events);
|
|
345
|
-
faults?.afterEventsBeforeWorkflowSeeds?.();
|
|
346
|
-
for (const item of envelope.workflowSeeds) workflowInstanceIds[item.resultIndex] = this.#journal.createInstanceIfAbsent(item.seed, envelope.capturedAt).instance.id;
|
|
347
|
-
for (const control of envelope.workflowControls ?? []) {
|
|
348
|
-
const changed = control.operation === "cancel"
|
|
349
|
-
? this.#journal.cancelInstance(control.instanceId, envelope.capturedAt)
|
|
350
|
-
: control.operation === "reopen"
|
|
351
|
-
? this.#journal.reopenInstance(control.instanceId, envelope.capturedAt)
|
|
352
|
-
: this.#journal.failInstance(control.instanceId, control.failure ?? { code: "landing_controlled_failure" }, envelope.capturedAt);
|
|
353
|
-
if (!changed) {
|
|
354
|
-
throw new Error(`workflow control '${control.operation}' refused for instance '${control.instanceId}'`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
faults?.afterWorkflowSeedsBeforeCommit?.();
|
|
358
|
-
const committed = Object.freeze({ workflowInstanceIds: Object.freeze(workflowInstanceIds) });
|
|
359
|
-
this.#storeDurableResult(operation, envelope.requestKey, committed);
|
|
360
|
-
return committed;
|
|
361
|
-
}).immediate();
|
|
362
|
-
this.#opResults.set(cacheKey, result);
|
|
363
|
-
opFaults.get(this)?.delete(envelope.requestKey);
|
|
364
|
-
return result;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
stepCommitSync(envelope: KernelStepCommitEnvelope): number {
|
|
368
|
-
const faults = stepFaults.get(this)?.get(envelope.requestKey);
|
|
369
|
-
const result = this.#commitStep(envelope.requestKey, envelope.lease.instanceId, "stepCommit", faults?.beforeCommit, () => {
|
|
370
|
-
this.#journal.fenceLeaseInTransaction(envelope.lease.instanceId, envelope.lease.token, envelope.lease.now);
|
|
371
|
-
faults?.afterFenceBeforeParticipant?.();
|
|
372
|
-
applyAuthority(this.db, this.messageAuthority, envelope.messageAuthority);
|
|
373
|
-
faults?.afterParticipantBeforeEntities?.(); faults?.afterFenceBeforeEntities?.();
|
|
374
|
-
applyEntities(this.db, envelope.entities, envelope.capturedAt);
|
|
375
|
-
faults?.betweenEntitiesAndEvents?.();
|
|
376
|
-
appendEvents(this.db, envelope.events);
|
|
377
|
-
faults?.insideTxBeforeJournal?.();
|
|
378
|
-
const seq = this.#journal.recordStepInTransaction(envelope.record, envelope.capturedAt);
|
|
379
|
-
faults?.afterJournalBeforeCommit?.();
|
|
380
|
-
return seq;
|
|
381
|
-
});
|
|
382
|
-
faults?.afterCommit?.();
|
|
383
|
-
return result;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
failedStepCommitSync(envelope: KernelJournalOnlyCommitEnvelope): number { return this.#journalCommit(envelope, "failedStepCommit"); }
|
|
387
|
-
supersededStepCommitSync(envelope: KernelJournalOnlyCommitEnvelope): number { return this.#journalCommit(envelope, "supersededStepCommit"); }
|
|
388
|
-
|
|
389
|
-
async seedWorkflow(requestKey: string, seed: WorkflowInstanceSeed, capturedAt: number) { return this.seedWorkflowSync(requestKey, seed, capturedAt); }
|
|
390
|
-
async acquireWorkflowLease(requestKey: string, params: AcquireLeaseParams) { return this.acquireWorkflowLeaseSync(requestKey, params); }
|
|
391
|
-
async reclaimDeadWorkflowLeases(moduleName: string, now: number) { this.reclaimDeadWorkflowLeasesSync(moduleName, now); }
|
|
392
|
-
async renewWorkflowLease(requestKey: string, params: RenewLeaseParams) { return this.renewWorkflowLeaseSync(requestKey, params); }
|
|
393
|
-
async releaseWorkflowLease(requestKey: string, instanceId: string, token: string, now: number) { return this.releaseWorkflowLeaseSync(requestKey, instanceId, token, now); }
|
|
394
|
-
async controlWorkflow(requestKey: string, operation: "cancel" | "pause" | "resume" | "reopen" | "fail", id: string, now: number, failure?: unknown) { return this.controlWorkflowSync(requestKey, operation, id, now, failure); }
|
|
395
|
-
async opCommit(envelope: KernelOpCommitEnvelope): Promise<KernelOpCommitResult> { return this.opCommitSync(envelope); }
|
|
396
|
-
async stepCommit(envelope: KernelStepCommitEnvelope): Promise<number> { return this.stepCommitSync(envelope); }
|
|
397
|
-
async failedStepCommit(envelope: KernelJournalOnlyCommitEnvelope): Promise<number> { return this.failedStepCommitSync(envelope); }
|
|
398
|
-
async supersededStepCommit(envelope: KernelJournalOnlyCommitEnvelope): Promise<number> { return this.supersededStepCommitSync(envelope); }
|
|
399
|
-
|
|
400
|
-
#journalCommit(envelope: KernelJournalOnlyCommitEnvelope, operation: string): number {
|
|
401
|
-
const faults = stepFaults.get(this)?.get(envelope.requestKey);
|
|
402
|
-
return this.#commitStep(envelope.requestKey, envelope.lease.instanceId, operation, faults?.beforeCommit, () => {
|
|
403
|
-
this.#journal.fenceLeaseInTransaction(envelope.lease.instanceId, envelope.lease.token, envelope.lease.now);
|
|
404
|
-
faults?.insideTxBeforeJournal?.();
|
|
405
|
-
const seq = this.#journal.recordStepInTransaction(envelope.record, envelope.capturedAt);
|
|
406
|
-
faults?.afterJournalBeforeCommit?.();
|
|
407
|
-
return seq;
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
#commitStep(requestKey: string, instanceId: string, operation: string, beforeWrite: (() => void) | undefined, write: () => number): number {
|
|
412
|
-
const cacheKey = this.#cacheKey(operation, requestKey);
|
|
413
|
-
const prior = this.#knownResult(this.#stepResults, operation, requestKey);
|
|
414
|
-
if (prior !== undefined) return prior;
|
|
415
|
-
try {
|
|
416
|
-
beforeWrite?.();
|
|
417
|
-
const result = this.db.transaction(() => {
|
|
418
|
-
const durable = this.#durableResult<number>(operation, requestKey);
|
|
419
|
-
if (durable !== undefined) return durable;
|
|
420
|
-
const committed = write();
|
|
421
|
-
this.#storeDurableResult(operation, requestKey, committed);
|
|
422
|
-
return committed;
|
|
423
|
-
}).immediate();
|
|
424
|
-
this.#stepResults.set(cacheKey, result);
|
|
425
|
-
stepFaults.get(this)?.delete(requestKey);
|
|
426
|
-
return result;
|
|
427
|
-
} catch (error) {
|
|
428
|
-
stepFaults.get(this)?.delete(requestKey);
|
|
429
|
-
if (isSqliteBusy(error)) throw new WorkflowContendedError(instanceId, operation, { cause: error });
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
#cachedWrite<T>(requestKey: string, operation: string, write: () => T, contendedInstanceId?: string): T {
|
|
435
|
-
const cacheKey = this.#cacheKey(operation, requestKey);
|
|
436
|
-
const prior = this.#knownResult(this.#writeResults as BoundedResultMap<T>, operation, requestKey);
|
|
437
|
-
if (prior !== undefined) return prior;
|
|
438
|
-
try {
|
|
439
|
-
const result = this.db.transaction(() => {
|
|
440
|
-
const durable = this.#durableResult<T>(operation, requestKey);
|
|
441
|
-
if (durable !== undefined) return durable;
|
|
442
|
-
const committed = write();
|
|
443
|
-
this.#storeDurableResult(operation, requestKey, committed);
|
|
444
|
-
return committed;
|
|
445
|
-
}).immediate();
|
|
446
|
-
this.#writeResults.set(cacheKey, result);
|
|
447
|
-
return result;
|
|
448
|
-
} catch (error) {
|
|
449
|
-
if (contendedInstanceId !== undefined && isSqliteBusy(error)) {
|
|
450
|
-
throw new WorkflowContendedError(contendedInstanceId, operation, { cause: error });
|
|
451
|
-
}
|
|
452
|
-
throw error;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
#cacheKey(operation: string, requestKey: string): string {
|
|
457
|
-
return `${operation}\0${requestKey}`;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
#knownResult<T>(cache: BoundedResultMap<T>, operation: string, requestKey: string): T | undefined {
|
|
461
|
-
const cacheKey = this.#cacheKey(operation, requestKey);
|
|
462
|
-
const cached = cache.get(cacheKey) as T | undefined;
|
|
463
|
-
if (cached !== undefined) return cached;
|
|
464
|
-
const durable = this.#durableResult<T>(operation, requestKey);
|
|
465
|
-
if (durable !== undefined) cache.set(cacheKey, durable);
|
|
466
|
-
return durable;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
#durableResult<T>(operation: string, requestKey: string): T | undefined {
|
|
470
|
-
const row = this.db.query(`SELECT result FROM ${DEDUP_TABLE} WHERE operation = ? AND request_key = ?`)
|
|
471
|
-
.get(operation, requestKey) as { result: string } | undefined;
|
|
472
|
-
return row == null ? undefined : JSON.parse(row.result) as T;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
#storeDurableResult(operation: string, requestKey: string, result: unknown): void {
|
|
476
|
-
if (!this.db.inTransaction) throw new Error("kernel compatibility request result must be stored inside its writer transaction");
|
|
477
|
-
this.db.run(`INSERT INTO ${DEDUP_TABLE} (operation, request_key, result) VALUES (?, ?, ?)`, [operation, requestKey, JSON.stringify(result)]);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
async moduleTableExists(tableName: string): Promise<boolean> { return this.moduleTableExistsSync(tableName); }
|
|
481
|
-
async entityPoint(input: KernelEntityPointRead): Promise<KernelEntityStoredRow | undefined> { return this.entityPointSync(input); }
|
|
482
|
-
async entityList(input: KernelEntityListRead): Promise<readonly KernelEntityStoredRow[]> { return this.entityListSync(input); }
|
|
483
|
-
async replayEvents(scope: Scope, since: number, limit: number, moduleId?: string): Promise<EventReplaySlice> { return this.replayEventsSync(scope, since, limit, moduleId); }
|
|
484
|
-
async eventHighWater(scope: Scope): Promise<number> { return this.eventHighWaterSync(scope); }
|
|
485
|
-
async eventHasMatch(scope: Scope, topic: string, correlationId?: string): Promise<boolean> { return this.eventHasMatchSync(scope, topic, correlationId); }
|
|
486
|
-
async getWorkflowInstance(id: string) { return this.getWorkflowInstanceSync(id); }
|
|
487
|
-
async getWorkflowInstanceByIdentity(moduleName: string, workflowName: string, idempotencyKey: string) { return this.getWorkflowInstanceByIdentitySync(moduleName, workflowName, idempotencyKey); }
|
|
488
|
-
async listWorkflowInstances(options?: ListInstancesOptions): Promise<WorkflowInstancePage> { return this.listWorkflowInstancesSync(options); }
|
|
489
|
-
async listWorkflowSteps(instanceId: string): Promise<WorkflowStepJournalRow[]> { return this.listWorkflowStepsSync(instanceId); }
|
|
490
|
-
async listResumableWorkflows(moduleName: string, now: number) { return this.listResumableWorkflowsSync(moduleName, now); }
|
|
491
|
-
async listDueWorkflows(moduleName: string, now: number) { return this.listDueWorkflowsSync(moduleName, now); }
|
|
492
|
-
async listWaitingWorkflows(moduleName: string, now: number) { return this.listWaitingWorkflowsSync(moduleName, now); }
|
|
493
|
-
async snapshotWorkflowResidual(moduleName: string, now: number) { return this.snapshotWorkflowResidualSync(moduleName, now); }
|
|
494
|
-
|
|
495
|
-
/** @internal Compatibility-adapter telemetry used to prove retry caches stay bounded. */
|
|
496
|
-
compatibilityDedupEntryCounts(): Readonly<{ op: number; step: number; write: number }> {
|
|
497
|
-
return { op: this.#opResults.size, step: this.#stepResults.size, write: this.#writeResults.size };
|
|
498
|
-
}
|
|
499
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import type { Database } from "bun:sqlite";
|
|
2
|
-
import { createRealClock } from "./effects";
|
|
3
|
-
import type { EventSession } from "./event-log";
|
|
4
|
-
import type { MessageAuthoritySession, MessageAuthorityStore } from "./message-authority";
|
|
5
|
-
import { createModuleHost, type ModuleHost, type ModuleHostOptions, type OpCommitFaults } from "./module-host";
|
|
6
|
-
import type { EntitySession } from "./persistence";
|
|
7
|
-
import { SqliteKernelPersistence } from "./sqlite-kernel-persistence";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* TEST / CHAOS SUPPORT ONLY (#1910 K3). Compose an in-process {@link SqliteKernelPersistence} with a
|
|
11
|
-
* {@link createModuleHost} host against a raw `Database`.
|
|
12
|
-
*
|
|
13
|
-
* Production code builds hosts on the ASYNC gateway persistence (`createGatewayKernelPersistence`, in
|
|
14
|
-
* src/db) — the {@link ModuleHost} itself never holds a `Database`. This helper exists so unit tests
|
|
15
|
-
* and kill-9 chaos harnesses can still drive a host directly against a `:memory:`/file handle, now that
|
|
16
|
-
* the `createModuleHost({ db })` K0 compatibility branch is gone. The raw handle is confined to the
|
|
17
|
-
* `SqliteKernelPersistence` constructed here — the legitimate in-process persistence implementation
|
|
18
|
-
* that the src gateway worker ops also use.
|
|
19
|
-
*
|
|
20
|
-
* The clock is resolved ONCE and shared by both the persistence and the host so their timestamps agree,
|
|
21
|
-
* exactly as the removed `{ db }` path did (which built the compat persistence with the host's own
|
|
22
|
-
* resolved clock). `messageAuthority`/`busyTimeoutMs` are the SqliteKernelPersistence construction
|
|
23
|
-
* params the old branch accepted; every other option is forwarded to the host unchanged (including the
|
|
24
|
-
* in-process `opCommitFaults`/`workflowCommitFaults` fault-injection callbacks).
|
|
25
|
-
*/
|
|
26
|
-
export interface SqliteModuleHostOptions extends Omit<ModuleHostOptions, "persistence"> {
|
|
27
|
-
readonly db: Database;
|
|
28
|
-
/** Stage-0 MESSAGE authority store for the in-process persistence (timers authority tests). */
|
|
29
|
-
readonly messageAuthority?: MessageAuthorityStore;
|
|
30
|
-
/** SQLite busy timeout for the in-process persistence. */
|
|
31
|
-
readonly busyTimeoutMs?: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function createSqliteModuleHost(options: SqliteModuleHostOptions): ModuleHost {
|
|
35
|
-
const { db, messageAuthority, busyTimeoutMs, ...hostOptions } = options;
|
|
36
|
-
const clock = hostOptions.clock ?? createRealClock();
|
|
37
|
-
const persistence = new SqliteKernelPersistence(db, clock, messageAuthority, busyTimeoutMs);
|
|
38
|
-
return createModuleHost({ ...hostOptions, clock, persistence });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* TEST / CHAOS SUPPORT ONLY (#1910 K3). Atomically commit an entity session (K4) and an event
|
|
43
|
-
* session (K5) into ONE synchronous SQLite transaction against a RAW `Database` handle. Both sessions
|
|
44
|
-
* buffer their intent asynchronously and flush synchronously; sealing them and flushing inside a
|
|
45
|
-
* single `db.transaction` means a version conflict (or any throw) in either flush rolls BOTH back
|
|
46
|
-
* together — entities are never written without their events, and events are never written without
|
|
47
|
-
* their entities.
|
|
48
|
-
*
|
|
49
|
-
* `seedWorkflowsInTx` (T-0 #1409 finding 1) executes any ENLISTED workflow-instance seeds INSIDE
|
|
50
|
-
* the same transaction, AFTER both flushes: an op whose entity flush loses its optimistic-version
|
|
51
|
-
* CAS therefore rolls its workflow seeds back with everything else — a fence-losing op leaves no
|
|
52
|
-
* orphaned instance behind, and an op's instance can only exist alongside the entities it
|
|
53
|
-
* committed with.
|
|
54
|
-
*
|
|
55
|
-
* This lives in the test-only module (NOT the public {@link createModuleHost} barrel) and is NOT
|
|
56
|
-
* re-exported from the `@humwick/kernel` root: it takes a raw `Database` and runs a synchronous
|
|
57
|
-
* transaction, so exposing it publicly would reintroduce a main-loop SQLite bypass around the async
|
|
58
|
-
* {@link import("./kernel-persistence").KernelPersistence} gateway (#1910 K3 review). Production code
|
|
59
|
-
* commits through the gateway writer op; only kernel unit tests drive this directly against a
|
|
60
|
-
* `:memory:`/file handle to assert the raw atomic-commit semantics the gateway op is built on.
|
|
61
|
-
*/
|
|
62
|
-
export function commitAtomically(
|
|
63
|
-
db: Database,
|
|
64
|
-
entitySession: EntitySession<unknown>,
|
|
65
|
-
eventSession: EventSession<unknown>,
|
|
66
|
-
seedWorkflowsInTx?: () => void,
|
|
67
|
-
messageAuthoritySession?: MessageAuthoritySession,
|
|
68
|
-
faults?: Omit<OpCommitFaults, "beforeCommit" | "afterCommit">,
|
|
69
|
-
): void {
|
|
70
|
-
entitySession.seal();
|
|
71
|
-
eventSession.seal();
|
|
72
|
-
messageAuthoritySession?.seal();
|
|
73
|
-
db.transaction(() => {
|
|
74
|
-
// Authority first matches the workflow commit order. A later entity/event/seed failure still
|
|
75
|
-
// rolls this SQL back because the participant never owns a side transaction.
|
|
76
|
-
messageAuthoritySession?.flush();
|
|
77
|
-
faults?.afterParticipantBeforeEntities?.();
|
|
78
|
-
// Entities first: an optimistic-version conflict here aborts the transaction before any
|
|
79
|
-
// event row is inserted, so a rejected mutation emits nothing.
|
|
80
|
-
entitySession.flush();
|
|
81
|
-
faults?.betweenEntitiesAndEvents?.();
|
|
82
|
-
eventSession.flush();
|
|
83
|
-
faults?.afterEventsBeforeWorkflowSeeds?.();
|
|
84
|
-
seedWorkflowsInTx?.();
|
|
85
|
-
faults?.afterWorkflowSeedsBeforeCommit?.();
|
|
86
|
-
})();
|
|
87
|
-
}
|