@plurnk/plurnk-service 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.defaults +49 -42
- package/INSTALL.md +48 -11
- package/README.md +12 -2
- package/SPEC.md +1166 -475
- package/digest-sql/channel-dispositions/dispositions.sql +15 -0
- package/digest-sql/channel-state/state.sql +6 -0
- package/digest-sql/curation/curation.sql +5 -0
- package/digest-sql/derivations/derivations.sql +4 -0
- package/digest-sql/embeddings/embeddings.sql +4 -0
- package/digest-sql/entry-dispositions/dispositions.sql +15 -0
- package/digest-sql/entry-state/state.sql +6 -0
- package/digest-sql/token-counts/token-counts.sql +2 -0
- package/dist/Paths.d.ts +0 -4
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +1 -21
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +4 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +12 -22
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +8 -3
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +40 -8
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +19 -5
- package/dist/core/CoreSchemeServices.d.ts +7 -3
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +8 -1
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +15 -6
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +352 -306
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +22 -10
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +86 -46
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +202 -177
- package/dist/core/EntryAddressBinding.d.ts +32 -0
- package/dist/core/EntryAddressBinding.d.ts.map +1 -0
- package/dist/core/EntryAddressBinding.js +93 -0
- package/dist/core/EntryAddressBinding.js.map +1 -0
- package/dist/core/ExecutorRegistry.d.ts +12 -6
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +34 -31
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/HostPaths.d.ts +29 -0
- package/dist/core/HostPaths.d.ts.map +1 -0
- package/dist/core/HostPaths.js +74 -0
- package/dist/core/HostPaths.js.map +1 -0
- package/dist/core/LegacyHome.d.ts +10 -0
- package/dist/core/LegacyHome.d.ts.map +1 -0
- package/dist/core/LegacyHome.js +170 -0
- package/dist/core/LegacyHome.js.map +1 -0
- package/dist/core/LogBody.d.ts +1 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +21 -3
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.js +1 -1
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LogVisibility.d.ts +28 -0
- package/dist/core/LogVisibility.d.ts.map +1 -0
- package/dist/core/LogVisibility.js +215 -0
- package/dist/core/LogVisibility.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +1 -0
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +8 -0
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +10 -0
- package/dist/core/OperatorConfig.d.ts +6 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -0
- package/dist/core/OperatorConfig.js +95 -0
- package/dist/core/OperatorConfig.js.map +1 -0
- package/dist/core/OverflowTurn.d.ts +11 -0
- package/dist/core/OverflowTurn.d.ts.map +1 -0
- package/dist/core/OverflowTurn.js +81 -0
- package/dist/core/OverflowTurn.js.map +1 -0
- package/dist/core/Owner.js +3 -3
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +7 -15
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +64 -127
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.js +1 -1
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts +4 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +86 -47
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts +9 -5
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +99 -104
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ReasoningEvent.d.ts +13 -0
- package/dist/core/ReasoningEvent.d.ts.map +1 -0
- package/dist/core/ReasoningEvent.js +6 -0
- package/dist/core/ReasoningEvent.js.map +1 -0
- package/dist/core/ResourceMutations.d.ts +15 -19
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +118 -41
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +12 -12
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +58 -57
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ToolResources.d.ts +19 -0
- package/dist/core/ToolResources.d.ts.map +1 -0
- package/dist/core/ToolResources.js +123 -0
- package/dist/core/ToolResources.js.map +1 -0
- package/dist/core/Turn.d.ts +27 -0
- package/dist/core/Turn.d.ts.map +1 -0
- package/dist/core/Turn.js +43 -0
- package/dist/core/Turn.js.map +1 -0
- package/dist/core/Turn.sql +72 -0
- package/dist/core/TurnOps.d.ts +7 -0
- package/dist/core/TurnOps.d.ts.map +1 -0
- package/dist/core/TurnOps.js +73 -0
- package/dist/core/TurnOps.js.map +1 -0
- package/dist/core/TurnRunner.d.ts +56 -5
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +1163 -929
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerName.d.ts +2 -1
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +2 -1
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +17 -2
- package/dist/core/WorkspaceGate.js +1 -1
- package/dist/core/WorkspaceGate.js.map +1 -1
- package/dist/core/caps/CapsResolve.d.ts +2 -2
- package/dist/core/caps/CapsResolve.d.ts.map +1 -1
- package/dist/core/caps/CapsResolve.js +5 -7
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts +1 -1
- package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +13 -11
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.d.ts +5 -5
- package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +27 -30
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
- package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +5 -3
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.d.ts +3 -3
- package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +16 -26
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +6 -4
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +37 -5
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js +7 -5
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/file-creation-policy.d.ts +9 -0
- package/dist/core/file-creation-policy.d.ts.map +1 -0
- package/dist/core/file-creation-policy.js +25 -0
- package/dist/core/file-creation-policy.js.map +1 -0
- package/dist/core/fork.d.ts +4 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +39 -16
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +83 -40
- package/dist/core/git-env.d.ts +0 -1
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +0 -3
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-membership.d.ts +19 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +233 -74
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +13 -14
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/operation-target-groups.d.ts +3 -0
- package/dist/core/operation-target-groups.d.ts.map +1 -0
- package/dist/core/operation-target-groups.js +53 -0
- package/dist/core/operation-target-groups.js.map +1 -0
- package/dist/core/packet-inject.d.ts +0 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +6 -13
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +4 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +226 -53
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +14 -3
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +62 -24
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/scheme-types.d.ts +1 -0
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +4 -5
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/worker-ops.sql +10 -6
- package/dist/core/worker-settings.d.ts +10 -0
- package/dist/core/worker-settings.d.ts.map +1 -0
- package/dist/core/worker-settings.js +32 -0
- package/dist/core/worker-settings.js.map +1 -0
- package/dist/core/workspace-settings.d.ts +2 -11
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +7 -47
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +164 -92
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +9 -3
- package/dist/observe/genai.d.ts +9 -0
- package/dist/observe/genai.d.ts.map +1 -0
- package/dist/observe/genai.js +31 -0
- package/dist/observe/genai.js.map +1 -0
- package/dist/observe/spans.d.ts +3 -3
- package/dist/observe/spans.d.ts.map +1 -1
- package/dist/observe/spans.js +20 -5
- package/dist/observe/spans.js.map +1 -1
- package/dist/schemes/EffectPolicy.d.ts +3 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +38 -6
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts +3 -2
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +109 -34
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +5 -4
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +170 -80
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +6 -2
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +73 -22
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +25 -7
- package/dist/schemes/Prompt.d.ts +2 -3
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +5 -9
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts +10 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -0
- package/dist/schemes/QuestionTool.js +81 -0
- package/dist/schemes/QuestionTool.js.map +1 -0
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +6 -1
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +97 -34
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +5 -5
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +22 -17
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +77 -24
- package/dist/schemes/_entry-find.d.ts +8 -5
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +121 -40
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +16 -11
- package/dist/schemes/_entry-graph.sql +2 -6
- package/dist/schemes/_entry-manifest.d.ts +2 -2
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +18 -6
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +6 -5
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +39 -46
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +9 -6
- package/dist/schemes/_entry-send.d.ts +2 -2
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +16 -14
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +39 -25
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/server/Daemon.d.ts +98 -15
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +864 -348
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +84 -19
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +15 -10
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +70 -19
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/Functionality.d.ts +44 -0
- package/dist/server/Functionality.d.ts.map +1 -0
- package/dist/server/Functionality.js +422 -0
- package/dist/server/Functionality.js.map +1 -0
- package/dist/server/FunctionalityManager.d.ts +22 -0
- package/dist/server/FunctionalityManager.d.ts.map +1 -0
- package/dist/server/FunctionalityManager.js +121 -0
- package/dist/server/FunctionalityManager.js.map +1 -0
- package/dist/server/SkillsFunctionality.d.ts +61 -0
- package/dist/server/SkillsFunctionality.d.ts.map +1 -0
- package/dist/server/SkillsFunctionality.js +449 -0
- package/dist/server/SkillsFunctionality.js.map +1 -0
- package/dist/server/WorkerCapabilities.d.ts +21 -0
- package/dist/server/WorkerCapabilities.d.ts.map +1 -0
- package/dist/server/WorkerCapabilities.js +214 -0
- package/dist/server/WorkerCapabilities.js.map +1 -0
- package/dist/server/WorkerResidency.d.ts +40 -0
- package/dist/server/WorkerResidency.d.ts.map +1 -0
- package/dist/server/WorkerResidency.js +283 -0
- package/dist/server/WorkerResidency.js.map +1 -0
- package/dist/server/client-input.d.ts +6 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +72 -32
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts +2 -2
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +109 -23
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +33 -13
- package/dist/server/envelope.d.ts +7 -2
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +12 -6
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +36 -4
- package/dist/server/lifecycle-recovery.sql +24 -17
- package/dist/server/logEntry.d.ts +2 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +3 -2
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +7 -0
- package/dist/server/loop-model.d.ts +2 -2
- package/dist/server/loop-model.d.ts.map +1 -1
- package/dist/server/loop-model.js +23 -33
- package/dist/server/loop-model.js.map +1 -1
- package/dist/server/loopDocs.d.ts +2 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +88 -21
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/loopDocs.sql +14 -8
- package/dist/server/model-catalog.d.ts +3 -0
- package/dist/server/model-catalog.d.ts.map +1 -0
- package/dist/server/model-catalog.js +83 -0
- package/dist/server/model-catalog.js.map +1 -0
- package/dist/server/model-route.d.ts +7 -0
- package/dist/server/model-route.d.ts.map +1 -0
- package/dist/server/model-route.js +47 -0
- package/dist/server/model-route.js.map +1 -0
- package/dist/server/module-discovery.d.ts +13 -0
- package/dist/server/module-discovery.d.ts.map +1 -0
- package/dist/server/module-discovery.js +103 -0
- package/dist/server/module-discovery.js.map +1 -0
- package/dist/server/seam-entry-read.sql +9 -7
- package/dist/server/seam-log-read.sql +1 -1
- package/dist/server/seam-loop.sql +10 -1
- package/dist/server/seam-proposal-list.sql +4 -2
- package/dist/server/worker-capabilities.sql +19 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +193 -124
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +905 -196
- package/package.json +40 -38
- package/dist/core/ExecutableTools.d.ts +0 -11
- package/dist/core/ExecutableTools.d.ts.map +0 -1
- package/dist/core/ExecutableTools.js +0 -49
- package/dist/core/ExecutableTools.js.map +0 -1
- package/dist/core/JournalTurn.d.ts +0 -9
- package/dist/core/JournalTurn.d.ts.map +0 -1
- package/dist/core/JournalTurn.js +0 -14
- package/dist/core/JournalTurn.js.map +0 -1
- package/dist/core/JournalTurn.sql +0 -10
- package/dist/core/git-iso.d.ts +0 -13
- package/dist/core/git-iso.d.ts.map +0 -1
- package/dist/core/git-iso.js +0 -267
- package/dist/core/git-iso.js.map +0 -1
- package/dist/core/search-gate.d.ts +0 -17
- package/dist/core/search-gate.d.ts.map +0 -1
- package/dist/core/search-gate.js +0 -77
- package/dist/core/search-gate.js.map +0 -1
- package/dist/digest/Digest.sql +0 -1
- package/dist/server/workspace-capabilities.sql +0 -19
package/dist/core/Dispatcher.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
var _a;
|
|
2
|
-
import Owner from "./Owner.js";
|
|
3
2
|
import WorkerName, { WorkerNameError } from "./WorkerName.js";
|
|
4
3
|
import WorkerControlAddress from "./WorkerControlAddress.js";
|
|
5
|
-
import {
|
|
4
|
+
import { entryCoordinateOf, foldAuthorityIntoPath, renderAddress, renderTarget, schemeNameOf } from "./plurnk-uri.js";
|
|
6
5
|
import Fork from "./fork.js";
|
|
7
6
|
import WorkerCap from "./worker-cap.js";
|
|
8
7
|
import { PathSyntax, TagSignal } from "@plurnk/plurnk-contracts";
|
|
@@ -11,17 +10,16 @@ import LoopFlagsReader from "./LoopFlagsReader.js";
|
|
|
11
10
|
import ChannelWrite from "./ChannelWrite.js";
|
|
12
11
|
import { ReadProjector } from "../content/index.js";
|
|
13
12
|
import SchemeCtxImpl from "./caps/SchemeCtxImpl.js";
|
|
14
|
-
import EntryCrud from "../schemes/_entry-crud.js";
|
|
15
13
|
import EntryOps from "../schemes/_entry-ops.js";
|
|
16
14
|
import EntryFind from "../schemes/_entry-find.js";
|
|
17
|
-
import WorkspaceSettings from "./workspace-settings.js";
|
|
18
15
|
import LoopLifecycle from "./LoopLifecycle.js";
|
|
19
16
|
import TerminalResult from "./TerminalResult.js";
|
|
20
17
|
import Results from "./results.js";
|
|
21
18
|
import { OperationFailureError } from "./results.js";
|
|
22
19
|
import EffectPolicy from "../schemes/EffectPolicy.js";
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
20
|
+
import WorkerSettingsReader from "./worker-settings.js";
|
|
21
|
+
import { CoreSchemeAdapterBase } from "./CoreSchemeServices.js";
|
|
22
|
+
import { InvalidOperationResultError, } from "@plurnk/plurnk-schemes";
|
|
25
23
|
import DurableStatement from "./DurableStatement.js";
|
|
26
24
|
import ResourceMutations from "./ResourceMutations.js";
|
|
27
25
|
import LogBody from "./LogBody.js";
|
|
@@ -70,13 +68,13 @@ class Dispatcher {
|
|
|
70
68
|
// {§send-premature-terminate}/SEND signal 202 with scope — the engine-owned park-deadline registry (loopId → seconds;
|
|
71
69
|
// -1 = indefinite). The dispatcher WRITES at park; the daemon's drain park-exit consumes.
|
|
72
70
|
#parkDeadlines;
|
|
73
|
-
#searchGate;
|
|
74
71
|
// Per-turn running-worker READ obligations. {§join-blocking-collect}
|
|
75
72
|
#joinTargets;
|
|
76
73
|
#liveSubscriptions;
|
|
77
74
|
#lifecycle;
|
|
78
75
|
#resourceMutations;
|
|
79
|
-
|
|
76
|
+
#entryAddresses;
|
|
77
|
+
constructor({ db, schemes, mimetypes, weigh, notices, proposals, interactions, executors, loopSignal, streamEventNotify, wakeWorkerNotify, injectWorker, branchWorker, branchCompletionGate, cancelWorker, cancelDescendants, parkDeadlines, joinTargets, liveSubscriptions, entryAddresses }) {
|
|
80
78
|
this.#db = db;
|
|
81
79
|
this.#schemes = schemes;
|
|
82
80
|
this.#mimetypes = mimetypes;
|
|
@@ -94,48 +92,66 @@ class Dispatcher {
|
|
|
94
92
|
this.#cancelWorker = cancelWorker;
|
|
95
93
|
this.#cancelDescendants = cancelDescendants;
|
|
96
94
|
this.#parkDeadlines = parkDeadlines ?? new Map();
|
|
97
|
-
this.#searchGate = searchGate;
|
|
98
95
|
this.#joinTargets = joinTargets ?? new Set();
|
|
99
96
|
this.#liveSubscriptions = liveSubscriptions;
|
|
97
|
+
this.#entryAddresses = entryAddresses;
|
|
100
98
|
this.#lifecycle = new LoopLifecycle(db);
|
|
101
99
|
this.#resourceMutations = new ResourceMutations({
|
|
102
100
|
schemes,
|
|
103
101
|
liveSubscriptions,
|
|
104
102
|
run: (schemeName, statement, ctx) => this.#run(schemeName, statement, ctx),
|
|
105
|
-
checkWritable: (statement, origin,
|
|
106
|
-
checkFlagsGate: (statement, loopId,
|
|
107
|
-
editTargetIdentity: (statement, workspaceId) => this.#editTargetIdentity(statement, workspaceId),
|
|
103
|
+
checkWritable: (statement, origin, workerId) => this.#checkWritable(statement, origin, workerId),
|
|
104
|
+
checkFlagsGate: (statement, loopId, workerId) => this.#checkFlagsGate(statement, loopId, workerId),
|
|
105
|
+
editTargetIdentity: (statement, workspaceId, workerId) => this.#editTargetIdentity(statement, workspaceId, workerId),
|
|
108
106
|
canonicalFilePath: (pathname, workspaceId) => this.#canonicalFilePath(pathname, workspaceId),
|
|
109
107
|
prepareDataRepresentation: (args) => this.#prepareDataRepresentation({
|
|
110
108
|
...args,
|
|
111
109
|
handler: args.handler,
|
|
112
110
|
}),
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
resolveDataEntryAddress: (args) => this.#entryAddresses.resolve(args),
|
|
112
|
+
readEntry: (scheme, address, ctx) => this.#readEntry(scheme, address, ctx),
|
|
113
|
+
writeEntry: (scheme, address, entry, ctx) => this.#writeEntry(scheme, address, entry, ctx),
|
|
114
|
+
deleteChannel: (scheme, address, channel, ctx) => this.#deleteChannel(scheme, address, channel, ctx),
|
|
116
115
|
applyProposal: (statement, result, resolution, ids) => this.#proposals.workerApply(statement, result, resolution, ids),
|
|
117
116
|
});
|
|
118
117
|
}
|
|
119
118
|
// workspace → project_root, memoized: {§fs-namespace} fixes the root immutably at
|
|
120
119
|
// workspace creation, so a process-lifetime cache can never go stale.
|
|
121
120
|
#rootCache = new Map();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return manifest === undefined ? null : new SchemeCtxImpl(ctx, scheme, manifest, this.#liveSubscriptions);
|
|
121
|
+
evictWorkspaceCache(workspaceId) {
|
|
122
|
+
this.#rootCache.delete(workspaceId);
|
|
125
123
|
}
|
|
126
|
-
#
|
|
127
|
-
|
|
128
|
-
return this.#schemes.manifestFor(scheme, ctx.workspaceId)?.category === "data" ? handlerCtx : null;
|
|
124
|
+
async #fixedEntryOwnerId(manifest, ctx) {
|
|
125
|
+
return this.#entryAddresses.fixedOwnerId(manifest, ctx);
|
|
129
126
|
}
|
|
130
|
-
#
|
|
131
|
-
const
|
|
127
|
+
async #handlerContext(scheme, ctx, authority = "") {
|
|
128
|
+
const manifest = this.#schemes.manifestFor(scheme, ctx.functionalityWorkerId);
|
|
129
|
+
return manifest === undefined
|
|
130
|
+
? null
|
|
131
|
+
: new SchemeCtxImpl(ctx, scheme, manifest, this.#liveSubscriptions, {
|
|
132
|
+
authority,
|
|
133
|
+
ownerId: await this.#fixedEntryOwnerId(manifest, ctx),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
#boundEntryContext(routedScheme, address, ctx) {
|
|
137
|
+
const manifest = this.#schemes.manifestFor(routedScheme, ctx.functionalityWorkerId);
|
|
138
|
+
return manifest?.category === "data"
|
|
139
|
+
? new SchemeCtxImpl(ctx, address.scheme, manifest, this.#liveSubscriptions, {
|
|
140
|
+
authority: address.authority,
|
|
141
|
+
ownerId: address.ownerId,
|
|
142
|
+
})
|
|
143
|
+
: null;
|
|
144
|
+
}
|
|
145
|
+
#coreCrud(scheme, workerId) {
|
|
146
|
+
const handler = this.#schemes.get(scheme, workerId);
|
|
132
147
|
return handler instanceof CoreSchemeAdapterBase
|
|
133
148
|
? handler
|
|
134
149
|
: undefined;
|
|
135
150
|
}
|
|
136
|
-
async #readEntry(scheme,
|
|
137
|
-
const
|
|
138
|
-
const
|
|
151
|
+
async #readEntry(scheme, address, ctx) {
|
|
152
|
+
const { pathname } = address;
|
|
153
|
+
const handler = this.#coreCrud(scheme, ctx.functionalityWorkerId);
|
|
154
|
+
const handlerCtx = this.#boundEntryContext(scheme, address, ctx);
|
|
139
155
|
if (typeof handler?.readEntry === "function" && handlerCtx !== null) {
|
|
140
156
|
return Results.assert(await handler.readEntry(pathname, handlerCtx));
|
|
141
157
|
}
|
|
@@ -144,11 +160,11 @@ class Dispatcher {
|
|
|
144
160
|
return _a.#failure("entry-read-not-implemented", 501, `The '${scheme}' scheme does not provide entry reads.`, { entry: null }, {
|
|
145
161
|
stage: "entry-read",
|
|
146
162
|
scheme,
|
|
147
|
-
target: renderAddress(
|
|
163
|
+
target: renderAddress(address),
|
|
148
164
|
retryable: false,
|
|
149
165
|
});
|
|
150
166
|
}
|
|
151
|
-
const result = Results.assert(await caps.read(pathname
|
|
167
|
+
const result = Results.assert(await caps.read(pathname));
|
|
152
168
|
return Results.assert({
|
|
153
169
|
...result,
|
|
154
170
|
status: result.status,
|
|
@@ -162,9 +178,10 @@ class Dispatcher {
|
|
|
162
178
|
},
|
|
163
179
|
});
|
|
164
180
|
}
|
|
165
|
-
async #writeEntry(scheme,
|
|
166
|
-
const
|
|
167
|
-
const
|
|
181
|
+
async #writeEntry(scheme, address, entry, ctx) {
|
|
182
|
+
const { pathname } = address;
|
|
183
|
+
const handler = this.#coreCrud(scheme, ctx.functionalityWorkerId);
|
|
184
|
+
const handlerCtx = this.#boundEntryContext(scheme, address, ctx);
|
|
168
185
|
if (typeof handler?.writeEntry === "function" && handlerCtx !== null) {
|
|
169
186
|
return Results.assert(await handler.writeEntry(pathname, entry, handlerCtx));
|
|
170
187
|
}
|
|
@@ -173,15 +190,16 @@ class Dispatcher {
|
|
|
173
190
|
return _a.#failure("entry-write-not-implemented", 501, `The '${scheme}' scheme does not provide entry writes.`, { created: false, entryId: null }, {
|
|
174
191
|
stage: "entry-write",
|
|
175
192
|
scheme,
|
|
176
|
-
target: renderAddress(
|
|
193
|
+
target: renderAddress(address),
|
|
177
194
|
retryable: false,
|
|
178
195
|
});
|
|
179
196
|
}
|
|
180
|
-
return Results.assert(await caps.write(pathname, entry
|
|
197
|
+
return Results.assert(await caps.write(pathname, entry));
|
|
181
198
|
}
|
|
182
|
-
async #deleteEntry(scheme,
|
|
183
|
-
const
|
|
184
|
-
const
|
|
199
|
+
async #deleteEntry(scheme, address, ctx) {
|
|
200
|
+
const { pathname } = address;
|
|
201
|
+
const handler = this.#coreCrud(scheme, ctx.functionalityWorkerId);
|
|
202
|
+
const handlerCtx = this.#boundEntryContext(scheme, address, ctx);
|
|
185
203
|
if (typeof handler?.deleteEntry === "function" && handlerCtx !== null) {
|
|
186
204
|
return Results.assert(await handler.deleteEntry(pathname, handlerCtx));
|
|
187
205
|
}
|
|
@@ -190,15 +208,16 @@ class Dispatcher {
|
|
|
190
208
|
return _a.#failure("entry-delete-not-implemented", 501, `The '${scheme}' scheme does not provide entry deletion.`, {}, {
|
|
191
209
|
stage: "entry-delete",
|
|
192
210
|
scheme,
|
|
193
|
-
target: renderAddress(
|
|
211
|
+
target: renderAddress(address),
|
|
194
212
|
retryable: false,
|
|
195
213
|
});
|
|
196
214
|
}
|
|
197
|
-
return Results.assert(await caps.delete(pathname
|
|
215
|
+
return Results.assert(await caps.delete(pathname));
|
|
198
216
|
}
|
|
199
|
-
async #deleteChannel(scheme,
|
|
200
|
-
const
|
|
201
|
-
const
|
|
217
|
+
async #deleteChannel(scheme, address, channel, ctx) {
|
|
218
|
+
const { pathname } = address;
|
|
219
|
+
const handler = this.#coreCrud(scheme, ctx.functionalityWorkerId);
|
|
220
|
+
const handlerCtx = this.#boundEntryContext(scheme, address, ctx);
|
|
202
221
|
if (typeof handler?.deleteChannel === "function" && handlerCtx !== null) {
|
|
203
222
|
return Results.assert(await handler.deleteChannel(pathname, channel, handlerCtx));
|
|
204
223
|
}
|
|
@@ -207,12 +226,12 @@ class Dispatcher {
|
|
|
207
226
|
return _a.#failure("channel-delete-not-implemented", 501, `The '${scheme}' scheme does not provide channel deletion.`, {}, {
|
|
208
227
|
stage: "channel-delete",
|
|
209
228
|
scheme,
|
|
210
|
-
target: renderAddress(
|
|
229
|
+
target: renderAddress(address),
|
|
211
230
|
channel,
|
|
212
231
|
retryable: false,
|
|
213
232
|
});
|
|
214
233
|
}
|
|
215
|
-
return Results.assert(await caps.delete(pathname,
|
|
234
|
+
return Results.assert(await caps.delete(pathname, channel));
|
|
216
235
|
}
|
|
217
236
|
async #workspaceRoot(workspaceId) {
|
|
218
237
|
if (this.#rootCache.has(workspaceId))
|
|
@@ -235,8 +254,8 @@ class Dispatcher {
|
|
|
235
254
|
async #canonicalFilePath(pathname, workspaceId) {
|
|
236
255
|
return Namespace.canonicalizeSpelling(pathname, await this.#workspaceRoot(workspaceId));
|
|
237
256
|
}
|
|
238
|
-
async #editTargetIdentity(statement, workspaceId) {
|
|
239
|
-
const target = this.#extractTarget(statement.target,
|
|
257
|
+
async #editTargetIdentity(statement, workspaceId, workerId) {
|
|
258
|
+
const target = this.#extractTarget(statement.target, workerId);
|
|
240
259
|
await this.#canonColumns(target, workspaceId);
|
|
241
260
|
return {
|
|
242
261
|
key: JSON.stringify([
|
|
@@ -252,8 +271,8 @@ class Dispatcher {
|
|
|
252
271
|
async prepareEditBatches(statements, context) {
|
|
253
272
|
for (const statement of statements)
|
|
254
273
|
assertClassifyingSignal(statement); // {§log-tag-signal}
|
|
255
|
-
const { workspaceId, workerId, loopId, turnId, origin } = context;
|
|
256
|
-
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, loopId, turnId, origin });
|
|
274
|
+
const { workspaceId, workerId, functionalityWorkerId, loopId, turnId, origin } = context;
|
|
275
|
+
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, functionalityWorkerId, loopId, turnId, origin });
|
|
257
276
|
await this.#resourceMutations.prepareEditBatches(statements, context, schemeCtx);
|
|
258
277
|
}
|
|
259
278
|
async dispatch(context) {
|
|
@@ -266,12 +285,13 @@ class Dispatcher {
|
|
|
266
285
|
}
|
|
267
286
|
async #dispatchOne(context) {
|
|
268
287
|
const { statement, workspaceId, workerId, loopId, turnId, sequence, origin, onDispatch, } = context;
|
|
269
|
-
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, loopId, turnId, origin });
|
|
288
|
+
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, functionalityWorkerId: context.functionalityWorkerId, loopId, turnId, origin });
|
|
289
|
+
const { functionalityWorkerId } = schemeCtx;
|
|
270
290
|
let result;
|
|
271
291
|
let curationPlan = null;
|
|
272
|
-
let denial = this.#checkWritable(statement, origin,
|
|
292
|
+
let denial = this.#checkWritable(statement, origin, functionalityWorkerId);
|
|
273
293
|
if (denial === null)
|
|
274
|
-
denial = await this.#checkFlagsGate(statement, loopId,
|
|
294
|
+
denial = await this.#checkFlagsGate(statement, loopId, functionalityWorkerId);
|
|
275
295
|
if (denial !== null) {
|
|
276
296
|
result = denial;
|
|
277
297
|
}
|
|
@@ -286,7 +306,14 @@ class Dispatcher {
|
|
|
286
306
|
result = await this.#resourceMutations.preparedEditResult(statement);
|
|
287
307
|
}
|
|
288
308
|
else if (statement.op === "SEND" && statement.target === null) {
|
|
289
|
-
result = await this.#handleSendBroadcast(statement, {
|
|
309
|
+
result = await this.#handleSendBroadcast(statement, {
|
|
310
|
+
workspaceId,
|
|
311
|
+
workerId,
|
|
312
|
+
loopId,
|
|
313
|
+
turnId,
|
|
314
|
+
sequence,
|
|
315
|
+
origin,
|
|
316
|
+
});
|
|
290
317
|
}
|
|
291
318
|
else if (statement.op === "OPEN" || statement.op === "FOLD") {
|
|
292
319
|
const curation = await this.#runLogCuration(statement, schemeCtx);
|
|
@@ -309,9 +336,22 @@ class Dispatcher {
|
|
|
309
336
|
result = this.#handlePlan(statement);
|
|
310
337
|
}
|
|
311
338
|
else if (statement.op === "EXEC") {
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
|
|
339
|
+
// {§worker-tool-admission} — the question runtime is admitted
|
|
340
|
+
// per worker: a worker whose own rules don't request user input
|
|
341
|
+
// gets the explicit not-available outcome, never a parked loop.
|
|
342
|
+
if (("signal" in statement && typeof statement.signal === "string")
|
|
343
|
+
&& !(await WorkerSettingsReader.toolAvailable(this.#db, schemeCtx.functionalityWorkerId, statement.signal))) {
|
|
344
|
+
result = _a.#failure("question-tool-unavailable", 404, "The question tool is not available to this worker.", {}, {
|
|
345
|
+
stage: "tool-admission",
|
|
346
|
+
recovery: "This worker does not request user input; continue from the available evidence.",
|
|
347
|
+
retryable: false,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
// EXEC routes unconditionally to its operation owner. The
|
|
352
|
+
// resolved runtime declaration owns body/target semantics.
|
|
353
|
+
result = await this.#run("exec", statement, schemeCtx);
|
|
354
|
+
}
|
|
315
355
|
}
|
|
316
356
|
else {
|
|
317
357
|
result = await this.#run(schemeNameOf(statement.target), statement, schemeCtx); // {§op-methods-op-dispatch}
|
|
@@ -320,15 +360,18 @@ class Dispatcher {
|
|
|
320
360
|
catch (err) { // a scheme exception becomes the op's 500 outcome — {§scheme-surface-exception-500}
|
|
321
361
|
if (err instanceof InvalidOperationResultError)
|
|
322
362
|
throw err;
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
363
|
+
if (err instanceof OperationFailureError) {
|
|
364
|
+
result = err.result;
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
const scheme = schemeNameOf(statement.target);
|
|
368
|
+
console.error(`Scheme '${scheme ?? "unknown"}' ${statement.op} threw outside its operation result contract:`, err);
|
|
369
|
+
result = _a.#failure("scheme-handler-threw", 500, `The '${scheme ?? "unknown"}' scheme did not produce a ${statement.op} result.`, {}, {
|
|
328
370
|
stage: "scheme-dispatch",
|
|
329
371
|
scheme,
|
|
330
372
|
operation: statement.op,
|
|
331
373
|
});
|
|
374
|
+
}
|
|
332
375
|
}
|
|
333
376
|
}
|
|
334
377
|
// {§fold-open-meta-operations} — persist OPEN/FOLD for forensics;
|
|
@@ -340,6 +383,7 @@ class Dispatcher {
|
|
|
340
383
|
const logEntryId = await this.#writeLog({
|
|
341
384
|
statement,
|
|
342
385
|
result,
|
|
386
|
+
functionalityWorkerId,
|
|
343
387
|
workspaceId,
|
|
344
388
|
workerId,
|
|
345
389
|
loopId,
|
|
@@ -349,15 +393,6 @@ class Dispatcher {
|
|
|
349
393
|
curationPlan,
|
|
350
394
|
modelCallId: null,
|
|
351
395
|
});
|
|
352
|
-
// {§search-gate} — register successful searches AFTER #writeLog stamps the runtime
|
|
353
|
-
// entry's coordinate onto result.attrs.pathname (the gate's dedup serves from it).
|
|
354
|
-
if (statement.op === "EXEC" && result.status < 400) {
|
|
355
|
-
const rt = ("signal" in statement && typeof statement.signal === "string" && statement.signal.length > 0) ? statement.signal : "sh";
|
|
356
|
-
const body = ("body" in statement && typeof statement.body === "string") ? statement.body : "";
|
|
357
|
-
const attrPath = result.attrs?.pathname;
|
|
358
|
-
if (typeof attrPath === "string")
|
|
359
|
-
this.#searchGate?.registerPending(loopId, turnId, rt, body, attrPath);
|
|
360
|
-
}
|
|
361
396
|
onDispatch?.(logEntryId);
|
|
362
397
|
// Proposal lifecycle (SPEC.md {§engine-rails} + {§methods-proposal-resolve}; {§proposal-202-pauses}). When a
|
|
363
398
|
// side-effecting op returns status 202 (a broadcast SEND signal 202 park is model
|
|
@@ -379,13 +414,13 @@ class Dispatcher {
|
|
|
379
414
|
autoAccept = EffectPolicy.decide(effect) === "auto";
|
|
380
415
|
}
|
|
381
416
|
if (autoAccept) {
|
|
382
|
-
const initialSettlement = await this.#proposals.workerApply(statement, result, { decision: "accept" }, { workspaceId, workerId, loopId, turnId });
|
|
417
|
+
const initialSettlement = await this.#proposals.workerApply(statement, result, { decision: "accept" }, { workspaceId, workerId, functionalityWorkerId, loopId, turnId });
|
|
383
418
|
const effective = await this.#resourceMutations.settleProposal({
|
|
384
419
|
statement,
|
|
385
420
|
result,
|
|
386
421
|
settlement: initialSettlement,
|
|
387
422
|
ctx: schemeCtx,
|
|
388
|
-
ids: { workspaceId, workerId, loopId, turnId },
|
|
423
|
+
ids: { workspaceId, workerId, functionalityWorkerId, loopId, turnId },
|
|
389
424
|
});
|
|
390
425
|
return this.#proposals.applyResolution(logEntryId, effective);
|
|
391
426
|
}
|
|
@@ -414,13 +449,13 @@ class Dispatcher {
|
|
|
414
449
|
// file, spawns the process, etc.). Its operation result is
|
|
415
450
|
// preserved: an apply failure keeps its original status and
|
|
416
451
|
// Problem Details instead of masquerading as a client rejection.
|
|
417
|
-
const initialSettlement = await this.#proposals.workerApply(statement, result, resolution, { workspaceId, workerId, loopId, turnId });
|
|
452
|
+
const initialSettlement = await this.#proposals.workerApply(statement, result, resolution, { workspaceId, workerId, functionalityWorkerId, loopId, turnId });
|
|
418
453
|
const effective = await this.#resourceMutations.settleProposal({
|
|
419
454
|
statement,
|
|
420
455
|
result,
|
|
421
456
|
settlement: initialSettlement,
|
|
422
457
|
ctx: schemeCtx,
|
|
423
|
-
ids: { workspaceId, workerId, loopId, turnId },
|
|
458
|
+
ids: { workspaceId, workerId, functionalityWorkerId, loopId, turnId },
|
|
424
459
|
});
|
|
425
460
|
const post = await this.#proposals.applyResolution(logEntryId, effective);
|
|
426
461
|
return post;
|
|
@@ -437,8 +472,8 @@ class Dispatcher {
|
|
|
437
472
|
if (statement.op !== "READ")
|
|
438
473
|
throw new Error(`look resolves READ only; got ${statement.op}`);
|
|
439
474
|
// turnId is a write-time FK only — a look writes no row, so 0 (no turn) is inert.
|
|
440
|
-
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, loopId, turnId: 0, origin });
|
|
441
|
-
const denial = await this.#checkFlagsGate(statement, loopId,
|
|
475
|
+
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, functionalityWorkerId: context.functionalityWorkerId, loopId, turnId: 0, origin });
|
|
476
|
+
const denial = await this.#checkFlagsGate(statement, loopId, schemeCtx.functionalityWorkerId);
|
|
442
477
|
if (denial !== null)
|
|
443
478
|
return denial;
|
|
444
479
|
return this.#run(schemeNameOf(statement.target), statement, schemeCtx);
|
|
@@ -448,30 +483,17 @@ class Dispatcher {
|
|
|
448
483
|
// schemes may return the already-authorized principal key.
|
|
449
484
|
async resolveEntryAddress(context) {
|
|
450
485
|
const { target, workspaceId, workerId } = context;
|
|
451
|
-
const routedScheme = schemeNameOf(target);
|
|
452
|
-
if (routedScheme === null)
|
|
453
|
-
return null;
|
|
454
|
-
const handler = this.#schemes.get(routedScheme, workspaceId);
|
|
455
|
-
const manifest = this.#schemes.manifestFor(routedScheme, workspaceId);
|
|
456
|
-
if (handler === undefined || manifest?.category !== "data")
|
|
457
|
-
return null;
|
|
458
|
-
const addressedScheme = target.kind === "url" ? target.scheme : routedScheme;
|
|
459
486
|
const coreCtx = this.#buildSchemeCtx({
|
|
460
487
|
workspaceId,
|
|
461
488
|
workerId,
|
|
489
|
+
functionalityWorkerId: context.functionalityWorkerId,
|
|
462
490
|
loopId: 0,
|
|
463
491
|
turnId: 0,
|
|
464
492
|
origin: "client",
|
|
465
493
|
});
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
routedScheme,
|
|
470
|
-
handler,
|
|
471
|
-
manifest,
|
|
472
|
-
ctx: coreCtx,
|
|
473
|
-
schemeCtx,
|
|
474
|
-
});
|
|
494
|
+
const resolved = await this.bindEntryAddress(target, coreCtx);
|
|
495
|
+
if (resolved === null)
|
|
496
|
+
return null;
|
|
475
497
|
if (resolved.address === null)
|
|
476
498
|
return null;
|
|
477
499
|
const rendered = target.kind === "url"
|
|
@@ -482,70 +504,30 @@ class Dispatcher {
|
|
|
482
504
|
return {
|
|
483
505
|
ownerId: resolved.address.ownerId,
|
|
484
506
|
scheme: resolved.address.scheme,
|
|
507
|
+
authority: resolved.address.authority,
|
|
485
508
|
pathname: resolved.address.pathname,
|
|
486
509
|
target: rendered,
|
|
487
510
|
};
|
|
488
511
|
}
|
|
489
|
-
async
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
return { address: null, result: null };
|
|
503
|
-
if ("status" in resolved) {
|
|
504
|
-
const result = Results.assert(resolved);
|
|
505
|
-
if (result.status < 300) {
|
|
506
|
-
throw new InvalidOperationResultError(`Scheme '${routedScheme}' returned a successful operation result instead of an entry address.`);
|
|
507
|
-
}
|
|
508
|
-
return { address: null, result };
|
|
509
|
-
}
|
|
510
|
-
if (typeof resolved.pathname !== "string") {
|
|
511
|
-
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry pathname.`);
|
|
512
|
-
}
|
|
513
|
-
let ownerId;
|
|
514
|
-
if ("ownerId" in resolved) {
|
|
515
|
-
if (!(handler instanceof CoreSchemeAdapterBase)) {
|
|
516
|
-
throw new TypeError(`Scheme '${routedScheme}' returned a core-only entry owner id.`);
|
|
517
|
-
}
|
|
518
|
-
ownerId = resolved.ownerId;
|
|
519
|
-
}
|
|
520
|
-
else if (resolved.owner === "worker") {
|
|
521
|
-
ownerId = ctx.workerId;
|
|
522
|
-
}
|
|
523
|
-
else if (resolved.owner === "commons") {
|
|
524
|
-
ownerId = await Owner.commonsId(this.#db, ctx.workspaceId);
|
|
525
|
-
}
|
|
526
|
-
else {
|
|
527
|
-
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry owner.`);
|
|
528
|
-
}
|
|
529
|
-
if (!Number.isSafeInteger(ownerId) || ownerId < 1) {
|
|
530
|
-
throw new TypeError(`Scheme '${routedScheme}' returned an invalid entry owner id.`);
|
|
512
|
+
async bindEntryAddress(target, ctx) {
|
|
513
|
+
const routedScheme = schemeNameOf(target);
|
|
514
|
+
if (routedScheme === null)
|
|
515
|
+
return null;
|
|
516
|
+
const handler = this.#schemes.get(routedScheme, ctx.functionalityWorkerId);
|
|
517
|
+
const manifest = this.#schemes.manifestFor(routedScheme, ctx.functionalityWorkerId);
|
|
518
|
+
if (handler === undefined || manifest?.category !== "data")
|
|
519
|
+
return null;
|
|
520
|
+
return this.#resolveDataEntryAddress({ target, routedScheme, handler, manifest, ctx });
|
|
521
|
+
}
|
|
522
|
+
async #resolveDataEntryAddress({ target, routedScheme, handler, manifest, ctx, }) {
|
|
523
|
+
if (manifest.category !== "data") {
|
|
524
|
+
throw new TypeError(`Scheme '${routedScheme}' is not entry-bearing.`);
|
|
531
525
|
}
|
|
532
|
-
return {
|
|
533
|
-
address: {
|
|
534
|
-
ownerId,
|
|
535
|
-
scheme: manifest.storedScheme ?? addressedScheme,
|
|
536
|
-
pathname: resolved.pathname,
|
|
537
|
-
},
|
|
538
|
-
result: null,
|
|
539
|
-
};
|
|
526
|
+
return this.#entryAddresses.resolve({ target, routedScheme, handler, manifest, ctx });
|
|
540
527
|
}
|
|
541
|
-
async #prepareDataRepresentation({ target, routedScheme, handler, manifest, ctx,
|
|
542
|
-
const resolved = await this.#resolveDataEntryAddress({
|
|
543
|
-
target,
|
|
544
|
-
routedScheme,
|
|
545
|
-
handler,
|
|
546
|
-
manifest,
|
|
547
|
-
ctx,
|
|
548
|
-
schemeCtx,
|
|
528
|
+
async #prepareDataRepresentation({ target, routedScheme, handler, manifest, ctx, publishedChannel, resolved: priorResolution, }) {
|
|
529
|
+
const resolved = priorResolution ?? await this.#resolveDataEntryAddress({
|
|
530
|
+
target, routedScheme, handler, manifest, ctx,
|
|
549
531
|
});
|
|
550
532
|
if (resolved.address === null
|
|
551
533
|
|| resolved.result !== null
|
|
@@ -561,11 +543,13 @@ class Dispatcher {
|
|
|
561
543
|
}
|
|
562
544
|
: target;
|
|
563
545
|
const preparationCtx = new SchemeCtxImpl(ctx, target.kind === "url" ? target.scheme : routedScheme, manifest, this.#liveSubscriptions, {
|
|
546
|
+
authority: address.authority,
|
|
564
547
|
ownerId: address.ownerId,
|
|
565
548
|
publishedChannel,
|
|
566
549
|
});
|
|
567
550
|
const prepared = Results.assertRepresentationPreparation(await handler.prepareRepresentation({
|
|
568
551
|
target: selectionNeutralTarget,
|
|
552
|
+
authority: address.authority,
|
|
569
553
|
pathname: address.pathname,
|
|
570
554
|
}, preparationCtx));
|
|
571
555
|
return {
|
|
@@ -577,7 +561,7 @@ class Dispatcher {
|
|
|
577
561
|
// handler and addressed context as an authored READ. {§exec-target-routing}
|
|
578
562
|
async readExecSource(statement, ctx) {
|
|
579
563
|
const schemeName = schemeNameOf(statement.target);
|
|
580
|
-
const manifest = schemeName === null ? undefined : this.#schemes.manifestFor(schemeName, ctx.
|
|
564
|
+
const manifest = schemeName === null ? undefined : this.#schemes.manifestFor(schemeName, ctx.functionalityWorkerId);
|
|
581
565
|
if (manifest !== undefined && manifest.category !== "data") {
|
|
582
566
|
return _a.#failure("exec-source-not-data", 501, `Scheme '${schemeName}' is not a data source for EXEC.`, {}, {
|
|
583
567
|
scheme: schemeName,
|
|
@@ -587,11 +571,16 @@ class Dispatcher {
|
|
|
587
571
|
}
|
|
588
572
|
return Results.assertReadResult(await this.#run(schemeName, statement, ctx));
|
|
589
573
|
}
|
|
574
|
+
// The one place per-dispatch coordinates are built; a caller that carries no
|
|
575
|
+
// explicit Functionality coordinate acts in its own Worker's
|
|
576
|
+
// ({§actor-boundary-attached-functionality}). Consumers read the built
|
|
577
|
+
// PlurnkSchemeContext and never re-derive.
|
|
590
578
|
#buildSchemeCtx(ids) {
|
|
591
579
|
const { workspaceId, workerId, loopId, turnId, origin } = ids;
|
|
580
|
+
const functionalityWorkerId = ids.functionalityWorkerId ?? workerId;
|
|
592
581
|
return {
|
|
593
582
|
db: this.#db,
|
|
594
|
-
workspaceId, workerId, loopId, turnId,
|
|
583
|
+
workspaceId, workerId, functionalityWorkerId, loopId, turnId,
|
|
595
584
|
writer: origin,
|
|
596
585
|
signal: this.#loopSignal(loopId),
|
|
597
586
|
streamEventNotify: this.#streamEventNotify,
|
|
@@ -610,7 +599,8 @@ class Dispatcher {
|
|
|
610
599
|
// - SEND broadcast (path=null) has no target scheme; not gated.
|
|
611
600
|
// - COPY: dst scheme writableBy applies.
|
|
612
601
|
// - MOVE: both src (delete) and dst (write) schemes' writableBy apply.
|
|
613
|
-
#checkWritable(statement, origin,
|
|
602
|
+
#checkWritable(statement, origin, functionalityWorkerId) {
|
|
603
|
+
const workerId = functionalityWorkerId;
|
|
614
604
|
if (!MUTATING_OPS.has(statement.op))
|
|
615
605
|
return null;
|
|
616
606
|
if (statement.op === "SEND" && statement.target === null)
|
|
@@ -618,23 +608,23 @@ class Dispatcher {
|
|
|
618
608
|
// EXEC's operation authority always belongs to the exec scheme;
|
|
619
609
|
// runtime-specific resource authority is gated separately below.
|
|
620
610
|
if (statement.op === "EXEC") {
|
|
621
|
-
return this.#denyIfDisallowed("exec", origin,
|
|
611
|
+
return this.#denyIfDisallowed("exec", origin, workerId);
|
|
622
612
|
}
|
|
623
613
|
// Worker control (FORK/WORK → worker://<name>, spawn or fork) is gated by worker://'s writableBy — its
|
|
624
614
|
// body is a seed prompt, not a dst path, so the entry-COPY dst-parse below doesn't apply.
|
|
625
615
|
// {§machine-processes}
|
|
626
616
|
if (this.#isWorkerControl(statement))
|
|
627
|
-
return this.#denyIfDisallowed("worker", origin,
|
|
617
|
+
return this.#denyIfDisallowed("worker", origin, workerId);
|
|
628
618
|
if (statement.op === "COPY" || statement.op === "MOVE") {
|
|
629
619
|
const dst = statement.body?.target ?? null;
|
|
630
620
|
const dstScheme = schemeNameOf(dst);
|
|
631
|
-
const dstDenial = this.#denyIfDisallowed(dstScheme, origin,
|
|
621
|
+
const dstDenial = this.#denyIfDisallowed(dstScheme, origin, workerId);
|
|
632
622
|
if (dstDenial !== null)
|
|
633
623
|
return dstDenial;
|
|
634
624
|
if (statement.op === "MOVE") {
|
|
635
625
|
const srcScheme = schemeNameOf(statement.target);
|
|
636
626
|
if (srcScheme !== dstScheme) {
|
|
637
|
-
const srcDenial = this.#denyIfDisallowed(srcScheme, origin,
|
|
627
|
+
const srcDenial = this.#denyIfDisallowed(srcScheme, origin, workerId);
|
|
638
628
|
if (srcDenial !== null)
|
|
639
629
|
return srcDenial;
|
|
640
630
|
}
|
|
@@ -642,45 +632,15 @@ class Dispatcher {
|
|
|
642
632
|
return null;
|
|
643
633
|
}
|
|
644
634
|
const target = schemeNameOf(statement.target);
|
|
645
|
-
return this.#denyIfDisallowed(target, origin,
|
|
646
|
-
}
|
|
647
|
-
// {§search-gate} — gate only configured search runtimes; duplicates serve
|
|
648
|
-
// the prior durable digest and the per-turn cap refuses without execution.
|
|
649
|
-
async #gatedExec(statement, ctx, loopId, turnId) {
|
|
650
|
-
const runtime = ("signal" in statement && typeof statement.signal === "string" && statement.signal.length > 0) ? statement.signal : "sh";
|
|
651
|
-
const body = ("body" in statement && typeof statement.body === "string") ? statement.body : "";
|
|
652
|
-
const verdict = this.#searchGate?.check(loopId, turnId, runtime, body) ?? { verdict: "pass" };
|
|
653
|
-
if (verdict.verdict === "capped") {
|
|
654
|
-
return _a.#failure("search-limit-reached", 429, `This turn already used its ${verdict.cap} permitted searches.`, {}, {
|
|
655
|
-
searchLimit: verdict.cap,
|
|
656
|
-
stage: "search-admission",
|
|
657
|
-
recovery: "Continue without another search in this turn.",
|
|
658
|
-
retryable: false,
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
if (verdict.verdict === "duplicate") {
|
|
662
|
-
// {§stream-owner-scoped} — the prior ranked digest is the CALLER's own stream entry.
|
|
663
|
-
const prior = await EntryCrud.readEntry(verdict.priorPathname, ctx, runtime, ctx.workerId);
|
|
664
|
-
const raw = prior.entry?.channels["#results"]?.content ?? "";
|
|
665
|
-
let results = raw;
|
|
666
|
-
try {
|
|
667
|
-
results = JSON.parse(raw);
|
|
668
|
-
}
|
|
669
|
-
catch { /* non-JSON results serve verbatim */ }
|
|
670
|
-
return _a.#failure("duplicate-search", 409, "This search already ran in the current loop; the prior results are attached.", { results }, {
|
|
671
|
-
recovery: "Use the attached prior results.",
|
|
672
|
-
retryable: false,
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
return this.#run("exec", statement, ctx);
|
|
635
|
+
return this.#denyIfDisallowed(target, origin, workerId);
|
|
676
636
|
}
|
|
677
|
-
#denyIfDisallowed(schemeName, origin,
|
|
637
|
+
#denyIfDisallowed(schemeName, origin, workerId) {
|
|
678
638
|
if (schemeName === null)
|
|
679
639
|
return null;
|
|
680
|
-
const handler = this.#schemes.get(schemeName,
|
|
640
|
+
const handler = this.#schemes.get(schemeName, workerId);
|
|
681
641
|
if (handler === undefined)
|
|
682
642
|
return null;
|
|
683
|
-
const manifest = this.#schemes.manifestFor(schemeName,
|
|
643
|
+
const manifest = this.#schemes.manifestFor(schemeName, workerId);
|
|
684
644
|
if (manifest === undefined)
|
|
685
645
|
throw new Error(`registered scheme '${schemeName}' has no manifest`);
|
|
686
646
|
if (manifest.writableBy.includes(origin))
|
|
@@ -698,7 +658,8 @@ class Dispatcher {
|
|
|
698
658
|
// active set under the loop's persisted flags. A registered scheme outside
|
|
699
659
|
// that set returns 403; unknown names continue to their operation owner for
|
|
700
660
|
// the ordinary registration failure. Action-entry-as-outcome carries either.
|
|
701
|
-
async #checkFlagsGate(statement, loopId,
|
|
661
|
+
async #checkFlagsGate(statement, loopId, functionalityWorkerId) {
|
|
662
|
+
const workerId = functionalityWorkerId;
|
|
702
663
|
// Broadcast SEND has no scheme to gate.
|
|
703
664
|
if (statement.op === "SEND" && statement.target === null)
|
|
704
665
|
return null;
|
|
@@ -732,15 +693,15 @@ class Dispatcher {
|
|
|
732
693
|
});
|
|
733
694
|
}
|
|
734
695
|
}
|
|
735
|
-
const active = this.#schemes.resolveForLoop(flags,
|
|
736
|
-
// {§
|
|
696
|
+
const active = this.#schemes.resolveForLoop(flags, workerId);
|
|
697
|
+
// {§mode-ask-read-only}: name the non-retryable restriction so the model changes course.
|
|
737
698
|
const restriction = flags.mode === "ask"
|
|
738
699
|
? "this is an ask-mode (read-only) loop — you cannot run commands or take host actions here"
|
|
739
700
|
: flags.noWeb && flags.noInteraction ? "web and interaction are disabled for this loop"
|
|
740
701
|
: flags.noWeb ? "web access is disabled for this loop"
|
|
741
702
|
: "interaction is disabled for this loop";
|
|
742
703
|
const checkScheme = (scheme) => {
|
|
743
|
-
if (scheme === null || !this.#schemes.has(scheme,
|
|
704
|
+
if (scheme === null || !this.#schemes.has(scheme, workerId))
|
|
744
705
|
return null;
|
|
745
706
|
if (active.has(scheme))
|
|
746
707
|
return null;
|
|
@@ -764,7 +725,7 @@ class Dispatcher {
|
|
|
764
725
|
return operationDenial;
|
|
765
726
|
const requested = typeof statement.signal === "string" ? statement.signal : "";
|
|
766
727
|
const runtime = requested === "" ? "sh" : requested;
|
|
767
|
-
const targetKind = this.#executors()?.entry(runtime,
|
|
728
|
+
const targetKind = this.#executors()?.entry(runtime, workerId)?.invocation.target?.kind;
|
|
768
729
|
if (targetKind !== "resource")
|
|
769
730
|
return null;
|
|
770
731
|
const sourceScheme = schemeNameOf(statement.target);
|
|
@@ -837,17 +798,32 @@ class Dispatcher {
|
|
|
837
798
|
}
|
|
838
799
|
if (statement.op === "FORK") {
|
|
839
800
|
// Branch the current worker's log into a named sister.
|
|
840
|
-
const branchWorkerId = await Fork.fork(this.#db, ctx.workerId, name);
|
|
841
|
-
await ctx.injectWorker({
|
|
801
|
+
const branchWorkerId = await Fork.fork(this.#db, ctx.workerId, name, (scheme) => this.#schemes.entryInheritanceForStoredScheme(scheme, ctx.workerId));
|
|
802
|
+
await ctx.injectWorker({
|
|
803
|
+
workspaceId: ctx.workspaceId,
|
|
804
|
+
workerId: branchWorkerId,
|
|
805
|
+
sourceWorkerId: ctx.workerId,
|
|
806
|
+
prompt,
|
|
807
|
+
flags,
|
|
808
|
+
parentLoopId: ctx.loopId,
|
|
809
|
+
});
|
|
842
810
|
return { status: 200, body: name };
|
|
843
811
|
}
|
|
844
812
|
// WORK — a fresh worker sister named <name>.
|
|
845
813
|
const row = await this.#db.fork_insert_worker.get({
|
|
846
814
|
workspace_id: ctx.workspaceId, name, parent_worker_id: ctx.workerId, origin: ctx.writer,
|
|
815
|
+
fork_snapshot: 0,
|
|
847
816
|
});
|
|
848
817
|
if (row === undefined)
|
|
849
818
|
throw new Error("worker spawn: worker insert returned no row");
|
|
850
|
-
await ctx.injectWorker({
|
|
819
|
+
await ctx.injectWorker({
|
|
820
|
+
workspaceId: ctx.workspaceId,
|
|
821
|
+
workerId: row.id,
|
|
822
|
+
sourceWorkerId: ctx.workerId,
|
|
823
|
+
prompt,
|
|
824
|
+
flags,
|
|
825
|
+
parentLoopId: ctx.loopId,
|
|
826
|
+
});
|
|
851
827
|
return { status: 200, body: name };
|
|
852
828
|
}
|
|
853
829
|
// KILL is target-polymorphic. Scheme handlers own the optional numeric code's
|
|
@@ -863,20 +839,40 @@ class Dispatcher {
|
|
|
863
839
|
if (schemeName === null) {
|
|
864
840
|
return _a.#failure("kill-target-scheme-required", 400, "KILL target requires a scheme.", {}, { retryable: false });
|
|
865
841
|
}
|
|
842
|
+
const manifest = this.#schemes.manifestFor(schemeName, ctx.functionalityWorkerId);
|
|
843
|
+
const coordinate = entryCoordinateOf(path, manifest?.authority ?? "namespace");
|
|
866
844
|
// Log targets use the same killable dispatch as streams; erasure is their
|
|
867
|
-
// permanent curation operation. {§
|
|
845
|
+
// permanent curation operation. {§turn-ops-log-curation}
|
|
868
846
|
// Process-KILL: any scheme whose handler exposes kill() aborts a live stream — the
|
|
869
847
|
// exec handler, registered as "exec" + under every runtime tag (sh/node), so a tag-
|
|
870
848
|
// addressed stream (sh:///l/t/s) routes here, not to deleteEntry. {§exec}
|
|
871
|
-
const killable = this.#schemes.get(schemeName, ctx.
|
|
849
|
+
const killable = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
872
850
|
if (killable !== undefined && typeof killable.kill === "function") {
|
|
873
851
|
// Pass the model's OWN scheme so a stream-KILL error answers in the runtime tag the
|
|
874
852
|
// model addressed (sh:///…), not the internal `exec` ({§fs-answer-in-canon}).
|
|
875
|
-
|
|
853
|
+
let handlerCtx;
|
|
854
|
+
if (manifest?.category === "data") {
|
|
855
|
+
const resolved = await this.#resolveDataEntryAddress({
|
|
856
|
+
target: path,
|
|
857
|
+
routedScheme: schemeName,
|
|
858
|
+
handler: killable,
|
|
859
|
+
manifest,
|
|
860
|
+
ctx,
|
|
861
|
+
});
|
|
862
|
+
if (resolved.result !== null)
|
|
863
|
+
return resolved.result;
|
|
864
|
+
if (resolved.address === null) {
|
|
865
|
+
return _a.#failure("entry-not-found", 404, `No entry exists at ${renderAddress({ scheme: schemeName, ...coordinate })}.`);
|
|
866
|
+
}
|
|
867
|
+
handlerCtx = this.#boundEntryContext(schemeName, resolved.address, ctx);
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
handlerCtx = await this.#handlerContext(schemeName, ctx, coordinate.authority);
|
|
871
|
+
}
|
|
876
872
|
if (handlerCtx === null) {
|
|
877
873
|
throw new InvalidOperationResultError(`Registered scheme '${schemeName}' has no dispatch context.`);
|
|
878
874
|
}
|
|
879
|
-
return await killable.kill(
|
|
875
|
+
return await killable.kill(coordinate.pathname, statement.signal, handlerCtx, schemeName);
|
|
880
876
|
}
|
|
881
877
|
if (schemeName === "worker") {
|
|
882
878
|
// Entry-path present → KILL a private owner-held entry (delete it), self-only —
|
|
@@ -885,7 +881,22 @@ class Dispatcher {
|
|
|
885
881
|
const entryPath = path.kind === "url" ? (path.pathname ?? "") : "";
|
|
886
882
|
if (entryPath !== "" && entryPath !== "/") {
|
|
887
883
|
const workerHandler = this.#schemes.get("worker");
|
|
888
|
-
|
|
884
|
+
if (manifest?.category !== "data") {
|
|
885
|
+
throw new InvalidOperationResultError("Registered scheme 'worker' is not entry-bearing.");
|
|
886
|
+
}
|
|
887
|
+
const resolved = await this.#resolveDataEntryAddress({
|
|
888
|
+
target: path,
|
|
889
|
+
routedScheme: "worker",
|
|
890
|
+
handler: workerHandler,
|
|
891
|
+
manifest,
|
|
892
|
+
ctx,
|
|
893
|
+
});
|
|
894
|
+
if (resolved.result !== null)
|
|
895
|
+
return resolved.result;
|
|
896
|
+
if (resolved.address === null) {
|
|
897
|
+
return _a.#failure("entry-not-found", 404, "The worker entry does not exist.");
|
|
898
|
+
}
|
|
899
|
+
const handlerCtx = this.#boundEntryContext("worker", resolved.address, ctx);
|
|
889
900
|
if (handlerCtx === null) {
|
|
890
901
|
throw new InvalidOperationResultError("Registered scheme 'worker' has no dispatch context.");
|
|
891
902
|
}
|
|
@@ -912,12 +923,28 @@ class Dispatcher {
|
|
|
912
923
|
await this.#cancelWorker(workerId, "killed via worker:// KILL");
|
|
913
924
|
return { status: 200 };
|
|
914
925
|
}
|
|
915
|
-
if (!this.#schemes.has(schemeName, ctx.
|
|
926
|
+
if (!this.#schemes.has(schemeName, ctx.functionalityWorkerId)) {
|
|
916
927
|
return _a.#failure("scheme-not-found", 501, `Scheme '${schemeName}' is not registered.`, {}, { scheme: schemeName, retryable: false });
|
|
917
928
|
}
|
|
929
|
+
const handler = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
930
|
+
if (handler === undefined || manifest?.category !== "data") {
|
|
931
|
+
return _a.#failure("entry-operation-unsupported", 400, `KILL requires an entry-bearing target; '${schemeName}' does not provide one.`, {}, { scheme: schemeName, retryable: false });
|
|
932
|
+
}
|
|
933
|
+
const resolved = await this.#resolveDataEntryAddress({
|
|
934
|
+
target: path,
|
|
935
|
+
routedScheme: schemeName,
|
|
936
|
+
handler,
|
|
937
|
+
manifest,
|
|
938
|
+
ctx,
|
|
939
|
+
});
|
|
940
|
+
if (resolved.result !== null)
|
|
941
|
+
return resolved.result;
|
|
942
|
+
if (resolved.address === null) {
|
|
943
|
+
return _a.#failure("entry-not-found", 404, "The KILL target does not exist.");
|
|
944
|
+
}
|
|
918
945
|
// A host-effecting delete (file) returns 202 to PROPOSE — pass its attrs through so the proposal
|
|
919
946
|
// carries the delete target to review (#isProposal fires on 202). Plurnk-internal deletes execute inline.
|
|
920
|
-
return this.#deleteEntry(schemeName,
|
|
947
|
+
return this.#deleteEntry(schemeName, resolved.address, ctx);
|
|
921
948
|
}
|
|
922
949
|
async #writeActionlessEntry({ verbatim, workerId, loopId, turnId, sequence, origin, kind, folded, modelCallId = null, attrs = {} }) {
|
|
923
950
|
const durableAttrs = { ...attrs, kind };
|
|
@@ -925,7 +952,7 @@ class Dispatcher {
|
|
|
925
952
|
const row = await this.#db.engine_insert_log_entry.get({
|
|
926
953
|
worker_id: workerId, loop_id: loopId, turn_id: turnId, sequence,
|
|
927
954
|
origin, source: null, model_call_id: modelCallId,
|
|
928
|
-
op: null,
|
|
955
|
+
op: null, delimiter: "", signal: null,
|
|
929
956
|
scheme: null, username: null, password: null, hostname: null, port: null,
|
|
930
957
|
pathname: null, query: null, fragment: null, lineMarker: null,
|
|
931
958
|
tx: "", mimetype_tx: "text/vnd.plurnk",
|
|
@@ -949,30 +976,29 @@ class Dispatcher {
|
|
|
949
976
|
await this.#db.engine_fold_log_entry.run({ id: row.id });
|
|
950
977
|
return row.id;
|
|
951
978
|
}
|
|
952
|
-
// {§
|
|
953
|
-
//
|
|
954
|
-
async
|
|
979
|
+
// {§turn-ops-entry} — preserve exact admitted source beside, never instead
|
|
980
|
+
// of, the ordinary operation-result rows produced by dispatch.
|
|
981
|
+
async writeTurnOps({ verbatim, workerId, loopId, turnId, sequence, origin, folded, modelCallId = null, reasoningItems }) {
|
|
955
982
|
return this.#writeActionlessEntry({
|
|
956
983
|
verbatim, workerId, loopId, turnId, sequence,
|
|
957
|
-
origin
|
|
984
|
+
origin, kind: "turnOps", folded, modelCallId,
|
|
985
|
+
attrs: {
|
|
986
|
+
...(reasoningItems !== undefined && reasoningItems.length > 0 ? { reasoning: reasoningItems } : {}),
|
|
987
|
+
},
|
|
958
988
|
});
|
|
959
989
|
}
|
|
960
|
-
// {§
|
|
961
|
-
//
|
|
962
|
-
|
|
963
|
-
// born-open rejected item under {§invalid-emission-attempts} and labels
|
|
964
|
-
// that admission fact structurally.
|
|
965
|
-
async writeModelEntry({ verbatim, workerId, loopId, turnId, sequence, folded, modelCallId, admission = "accepted", reasoningItems }) {
|
|
990
|
+
// {§rejected-emission-entry} — provider bytes that fail admission are an
|
|
991
|
+
// attempt artifact, never a turn program.
|
|
992
|
+
async writeEmissionAttempt({ verbatim, workerId, loopId, turnId, sequence, modelCallId, reasoningItems }) {
|
|
966
993
|
return this.#writeActionlessEntry({
|
|
967
994
|
verbatim, workerId, loopId, turnId, sequence,
|
|
968
|
-
origin: "model", kind: "
|
|
995
|
+
origin: "model", kind: "emissionAttempt", folded: true, modelCallId,
|
|
969
996
|
attrs: {
|
|
970
|
-
...(admission === "rejected" ? { admission } : {}),
|
|
971
997
|
...(reasoningItems !== undefined && reasoningItems.length > 0 ? { reasoning: reasoningItems } : {}),
|
|
972
998
|
},
|
|
973
999
|
});
|
|
974
1000
|
}
|
|
975
|
-
// PLAN — the model's
|
|
1001
|
+
// PLAN — the model's complete current Plan. An ordinary op: dispatched like any
|
|
976
1002
|
// other, logged, and broadcast to the client as a log entry — but a pure no-op for
|
|
977
1003
|
// state (PLAN ∉ MUTATING_OPS); its body serializes into the log row's tx, no effect.
|
|
978
1004
|
#handlePlan(statement) {
|
|
@@ -987,6 +1013,7 @@ class Dispatcher {
|
|
|
987
1013
|
Results.assert(result);
|
|
988
1014
|
const logEntryId = await this.#writeLog({
|
|
989
1015
|
...context,
|
|
1016
|
+
functionalityWorkerId: context.functionalityWorkerId ?? context.workerId,
|
|
990
1017
|
result,
|
|
991
1018
|
curationPlan: null,
|
|
992
1019
|
modelCallId,
|
|
@@ -1013,8 +1040,10 @@ class Dispatcher {
|
|
|
1013
1040
|
const boundaries = await this.#nextPacketBoundaries(workerId, turnId);
|
|
1014
1041
|
if (boundaries.retrievals)
|
|
1015
1042
|
pending.push("this turn's retrieval results (they land in the NEXT packet's Log)");
|
|
1016
|
-
if (boundaries.streamTerminations) {
|
|
1017
|
-
|
|
1043
|
+
if (boundaries.streamTerminations.length > 0) {
|
|
1044
|
+
// Name the exact streams (bench#5 requiem #9): the model can wait on
|
|
1045
|
+
// or KILL them specifically instead of guessing what remains.
|
|
1046
|
+
pending.push(`completed stream results that land in the NEXT packet's Log: ${boundaries.streamTerminations.join("; ")}`);
|
|
1018
1047
|
}
|
|
1019
1048
|
if (boundaries.childTerminations)
|
|
1020
1049
|
pending.push("worker results that arrived during this turn (they land NEXT turn)");
|
|
@@ -1026,17 +1055,17 @@ class Dispatcher {
|
|
|
1026
1055
|
// their distinct contracts: retrievals block explicit completion, whereas FOLD only
|
|
1027
1056
|
// prevents an empty wait from being inferred as completion.
|
|
1028
1057
|
async #nextPacketBoundaries(workerId, turnId) {
|
|
1029
|
-
const [turnBoundaries,
|
|
1058
|
+
const [turnBoundaries, streamTerminations, childTermination] = await Promise.all([
|
|
1030
1059
|
this.#db.engine_turn_packet_boundaries.all({ turn_id: turnId }),
|
|
1031
1060
|
this.#db.engine_worker_has_undelivered_stream_term
|
|
1032
|
-
.
|
|
1061
|
+
.all({ worker_id: workerId }),
|
|
1033
1062
|
this.#db.engine_worker_has_undelivered_child_term
|
|
1034
1063
|
.get({ worker_id: workerId }),
|
|
1035
1064
|
]);
|
|
1036
1065
|
return {
|
|
1037
1066
|
retrievals: turnBoundaries.some(({ op }) => op !== "FOLD"),
|
|
1038
1067
|
folds: turnBoundaries.some(({ op }) => op === "FOLD"),
|
|
1039
|
-
streamTerminations:
|
|
1068
|
+
streamTerminations: streamTerminations.map(({ handle }) => handle),
|
|
1040
1069
|
childTerminations: childTermination !== undefined,
|
|
1041
1070
|
};
|
|
1042
1071
|
}
|
|
@@ -1118,7 +1147,7 @@ class Dispatcher {
|
|
|
1118
1147
|
// fired, so do not park; continue directly to the packet that
|
|
1119
1148
|
// materializes them.
|
|
1120
1149
|
const boundaries = await this.#nextPacketBoundaries(workerId, turnId);
|
|
1121
|
-
if (boundaries.retrievals || boundaries.folds || boundaries.streamTerminations || boundaries.childTerminations) {
|
|
1150
|
+
if (boundaries.retrievals || boundaries.folds || boundaries.streamTerminations.length > 0 || boundaries.childTerminations) {
|
|
1122
1151
|
return { status: 102 };
|
|
1123
1152
|
}
|
|
1124
1153
|
const failCount = await this.#unobservedFailureCount(turnId);
|
|
@@ -1135,58 +1164,45 @@ class Dispatcher {
|
|
|
1135
1164
|
attrs: { joined: true, pending: 0 },
|
|
1136
1165
|
};
|
|
1137
1166
|
}
|
|
1138
|
-
// {§send-300-choices} — ask the operator and park (the answer returns via loop.inject).
|
|
1139
|
-
// The three-state cascade (owner design): PLURNK_QUESTIONS unset = ALLOWED (not enabled);
|
|
1140
|
-
// =0 = DENIED servicewide (a ceiling the client cannot override); ENABLED requires the
|
|
1141
|
-
// client to affirmatively pass it per workspace (settings.questions — the interactive client
|
|
1142
|
-
// with a human enables its own workspaces; headless/bench never asks). Enabled workspaces ALSO
|
|
1143
|
-
// get the questions.md teaching injected (docEntries) — capability and teaching gate as one.
|
|
1144
|
-
// Disabled → refused with a self-decide steer, never a park into the void.
|
|
1145
|
-
if (status === 300) {
|
|
1146
|
-
if (!(await WorkspaceSettings.questionsEnabled(this.#db, ctx.workspaceId))) {
|
|
1147
|
-
return _a.#failure("operator-questions-disabled", 409, "Operator questions are disabled in this workspace.", {}, {
|
|
1148
|
-
recovery: "Decide from the available evidence and continue or conclude.",
|
|
1149
|
-
retryable: false,
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
// {§send-300-choices} — return a proposal whose accepted body becomes
|
|
1153
|
-
// the answer; zero choices denotes an open question.
|
|
1154
|
-
const parts = raw.split(";").map((x) => x.trim()).filter((x) => x.length > 0);
|
|
1155
|
-
const [question = "", ...choices] = parts;
|
|
1156
|
-
return { status: 202, attrs: choices.length > 0 ? { question, choices } : { question } };
|
|
1157
|
-
}
|
|
1158
1167
|
// [200] — terminate, gated by the pending set (post-batch). The row records the refused
|
|
1159
1168
|
// attempt faithfully (status_rx=409, never erased); the loop stays a continue; the strike
|
|
1160
1169
|
// couples in runTurn. [499] abandons and cancels the descendant scope.
|
|
1161
1170
|
if (status === 200) {
|
|
1162
|
-
//
|
|
1163
|
-
//
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
//
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1171
|
+
// Model completion is a claim about the Worker's observed work and
|
|
1172
|
+
// therefore crosses the pending-result rails. A `_plurnk`
|
|
1173
|
+
// maintenance program closes only its own administrative loop; it
|
|
1174
|
+
// must not claim, consume, or be blocked by model work elsewhere in
|
|
1175
|
+
// the same Worker.
|
|
1176
|
+
if (ctx.origin === "model") {
|
|
1177
|
+
// {§send-premature-terminate} — same-turn failures are unobserved
|
|
1178
|
+
// pending results and therefore refuse completion.
|
|
1179
|
+
const failCount = await this.#unobservedFailureCount(turnId);
|
|
1180
|
+
if (failCount > 0)
|
|
1181
|
+
return _a.#unobservedFailures(failCount);
|
|
1182
|
+
const pending = await this.#pendingSet(workerId, turnId);
|
|
1183
|
+
if (pending.length > 0) {
|
|
1184
|
+
// A retrieval-only refusal needs no KILL/park remedy menu: the results simply
|
|
1185
|
+
// arrive in the next packet. Streams and children retain their remedy steer.
|
|
1186
|
+
const retrievalsOnly = pending.every((k) => k.startsWith("this turn's retrieval results"));
|
|
1187
|
+
if (retrievalsOnly) {
|
|
1188
|
+
return _a.#failure("retrieval-results-unobserved", 409, "Last turn both performed retrieval operations and attempted to terminate. Retrieval operations force an additional turn so their results can be reviewed.", {}, {
|
|
1189
|
+
pending: [...pending],
|
|
1190
|
+
stage: "completion",
|
|
1191
|
+
recovery: "Review the results, then use only `# PLAN0` and `## SEND0 [200]` to conclude.",
|
|
1192
|
+
retryable: false,
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
return _a.#failure("work-remains", 409, `Completion was refused while work remains: ${pending.join("; ")}.`, {}, {
|
|
1174
1196
|
pending: [...pending],
|
|
1175
1197
|
stage: "completion",
|
|
1176
|
-
recovery: "
|
|
1198
|
+
recovery: "Resolve the listed pending work before concluding.",
|
|
1177
1199
|
retryable: false,
|
|
1178
1200
|
});
|
|
1179
1201
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
recovery: "Resolve the listed pending work before concluding.",
|
|
1184
|
-
retryable: false,
|
|
1185
|
-
});
|
|
1202
|
+
const branchDenial = await this.#branchCompletionGate?.(workerId) ?? null;
|
|
1203
|
+
if (branchDenial !== null)
|
|
1204
|
+
return branchDenial;
|
|
1186
1205
|
}
|
|
1187
|
-
const branchDenial = await this.#branchCompletionGate?.(workerId) ?? null;
|
|
1188
|
-
if (branchDenial !== null)
|
|
1189
|
-
return branchDenial;
|
|
1190
1206
|
const finished = await this.#lifecycle.finish(loopId, TerminalResult.success(raw));
|
|
1191
1207
|
return _a.#statusResult(finished !== null ? 200 : await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to conclude it.");
|
|
1192
1208
|
}
|
|
@@ -1230,13 +1246,56 @@ class Dispatcher {
|
|
|
1230
1246
|
: {};
|
|
1231
1247
|
return _a.#failure("target-scheme-required", 400, `${statement.op} requires a target scheme.`, fields, { operation: statement.op, retryable: false });
|
|
1232
1248
|
}
|
|
1233
|
-
|
|
1249
|
+
const manifest = this.#schemes.manifestFor(schemeName, ctx.functionalityWorkerId);
|
|
1250
|
+
const handler = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
1251
|
+
if (handler === undefined) {
|
|
1252
|
+
return _a.#failure("scheme-not-found", 501, `Scheme '${schemeName}' is not registered.`, {}, { scheme: schemeName, retryable: false });
|
|
1253
|
+
}
|
|
1254
|
+
const methodName = statement.op.toLowerCase();
|
|
1255
|
+
const method = handler[methodName];
|
|
1256
|
+
const addressedScheme = statement.target?.kind === "url" ? statement.target.scheme : null;
|
|
1257
|
+
if (manifest === undefined)
|
|
1258
|
+
throw new Error(`scheme '${schemeName}' has no manifest`);
|
|
1259
|
+
const publishedChannel = statement.target?.kind === "url"
|
|
1260
|
+
? statement.target.fragment ?? manifest.defaultChannel
|
|
1261
|
+
: manifest.defaultChannel;
|
|
1262
|
+
const authoredCoordinate = statement.target === null
|
|
1263
|
+
? { authority: "", pathname: "" }
|
|
1264
|
+
: entryCoordinateOf(statement.target, manifest.authority ?? "namespace");
|
|
1265
|
+
// EXEC's authored target belongs to its declared invocation contract;
|
|
1266
|
+
// a resource target is input to the executor, never the output-stream
|
|
1267
|
+
// address owned by the internal exec scheme. {§exec-target-routing}
|
|
1268
|
+
const addressResolution = manifest.category === "data"
|
|
1269
|
+
&& statement.target !== null
|
|
1270
|
+
&& statement.op !== "EXEC"
|
|
1271
|
+
? await this.#resolveDataEntryAddress({
|
|
1272
|
+
target: statement.target,
|
|
1273
|
+
routedScheme: schemeName,
|
|
1274
|
+
handler: handler,
|
|
1275
|
+
manifest,
|
|
1276
|
+
ctx,
|
|
1277
|
+
})
|
|
1278
|
+
: null;
|
|
1279
|
+
if (addressResolution?.result !== null && addressResolution?.result !== undefined) {
|
|
1280
|
+
return addressResolution.result;
|
|
1281
|
+
}
|
|
1282
|
+
const operationAddress = addressResolution?.address ?? null;
|
|
1283
|
+
const schemeCtx = new SchemeCtxImpl(ctx, addressedScheme ?? schemeName, manifest, this.#liveSubscriptions, {
|
|
1284
|
+
authority: operationAddress?.authority ?? authoredCoordinate.authority,
|
|
1285
|
+
ownerId: operationAddress?.ownerId ?? await this.#fixedEntryOwnerId(manifest, ctx),
|
|
1286
|
+
publishedChannel,
|
|
1287
|
+
});
|
|
1288
|
+
if (statement.op === "SEND"
|
|
1289
|
+
&& statement.signal === 499
|
|
1290
|
+
&& statement.target?.kind === "url"
|
|
1291
|
+
&& operationAddress !== null) {
|
|
1234
1292
|
const addressedScheme = statement.target.scheme;
|
|
1235
1293
|
const entry = await this.#db.crud_find_workspace_entry.get({
|
|
1236
1294
|
workspace_id: ctx.workspaceId,
|
|
1237
|
-
owner_id:
|
|
1238
|
-
scheme:
|
|
1239
|
-
|
|
1295
|
+
owner_id: operationAddress.ownerId,
|
|
1296
|
+
scheme: operationAddress.scheme,
|
|
1297
|
+
authority: operationAddress.authority,
|
|
1298
|
+
pathname: operationAddress.pathname,
|
|
1240
1299
|
});
|
|
1241
1300
|
if (entry !== undefined) {
|
|
1242
1301
|
const subscription = await ChannelWrite.findActiveSubscription(this.#db, {
|
|
@@ -1252,20 +1311,6 @@ class Dispatcher {
|
|
|
1252
1311
|
}
|
|
1253
1312
|
}
|
|
1254
1313
|
}
|
|
1255
|
-
const handler = this.#schemes.get(schemeName, ctx.workspaceId);
|
|
1256
|
-
if (handler === undefined) {
|
|
1257
|
-
return _a.#failure("scheme-not-found", 501, `Scheme '${schemeName}' is not registered.`, {}, { scheme: schemeName, retryable: false });
|
|
1258
|
-
}
|
|
1259
|
-
const methodName = statement.op.toLowerCase();
|
|
1260
|
-
const method = handler[methodName];
|
|
1261
|
-
const addressedScheme = statement.target?.kind === "url" ? statement.target.scheme : null;
|
|
1262
|
-
const manifest = this.#schemes.manifestFor(schemeName, ctx.workspaceId);
|
|
1263
|
-
if (manifest === undefined)
|
|
1264
|
-
throw new Error(`scheme '${schemeName}' has no manifest`);
|
|
1265
|
-
const publishedChannel = statement.target?.kind === "url"
|
|
1266
|
-
? statement.target.fragment ?? manifest.defaultChannel
|
|
1267
|
-
: manifest.defaultChannel;
|
|
1268
|
-
const schemeCtx = new SchemeCtxImpl(ctx, addressedScheme ?? schemeName, manifest, this.#liveSubscriptions, { publishedChannel });
|
|
1269
1314
|
if (statement.op === "READ"
|
|
1270
1315
|
&& handler instanceof CoreSchemeAdapterBase
|
|
1271
1316
|
&& typeof handler.resolveCoreRepresentation === "function") {
|
|
@@ -1307,8 +1352,8 @@ class Dispatcher {
|
|
|
1307
1352
|
handler: handler,
|
|
1308
1353
|
manifest,
|
|
1309
1354
|
ctx,
|
|
1310
|
-
schemeCtx,
|
|
1311
1355
|
publishedChannel,
|
|
1356
|
+
...(addressResolution === null ? {} : { resolved: addressResolution }),
|
|
1312
1357
|
});
|
|
1313
1358
|
if (prepared.result !== null)
|
|
1314
1359
|
return prepared.result;
|
|
@@ -1321,9 +1366,10 @@ class Dispatcher {
|
|
|
1321
1366
|
}
|
|
1322
1367
|
const storageScheme = resolved?.scheme ?? manifest.storedScheme ?? addressedScheme ?? schemeName;
|
|
1323
1368
|
const projected = Results.assertReadResult(await EntryOps.readWorkspaceEntry(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, resolved === null
|
|
1324
|
-
?
|
|
1369
|
+
? null
|
|
1325
1370
|
: {
|
|
1326
1371
|
ownerId: resolved.ownerId,
|
|
1372
|
+
authority: resolved.authority,
|
|
1327
1373
|
pathname: resolved.pathname,
|
|
1328
1374
|
}));
|
|
1329
1375
|
return projected;
|
|
@@ -1345,7 +1391,7 @@ class Dispatcher {
|
|
|
1345
1391
|
&& (targetPathname === "" || targetPathname.endsWith("/"));
|
|
1346
1392
|
const exactTarget = statement.target !== null
|
|
1347
1393
|
&& !collectionTarget
|
|
1348
|
-
&& !PathSyntax.hasGlob(
|
|
1394
|
+
&& !PathSyntax.hasGlob(authoredCoordinate.pathname);
|
|
1349
1395
|
if (exactTarget && statement.target !== null) {
|
|
1350
1396
|
const prepared = await this.#prepareDataRepresentation({
|
|
1351
1397
|
target: statement.target,
|
|
@@ -1353,8 +1399,8 @@ class Dispatcher {
|
|
|
1353
1399
|
handler: handler,
|
|
1354
1400
|
manifest,
|
|
1355
1401
|
ctx,
|
|
1356
|
-
schemeCtx,
|
|
1357
1402
|
publishedChannel,
|
|
1403
|
+
...(addressResolution === null ? {} : { resolved: addressResolution }),
|
|
1358
1404
|
});
|
|
1359
1405
|
if (prepared.result !== null)
|
|
1360
1406
|
return prepared.result;
|
|
@@ -1378,6 +1424,7 @@ class Dispatcher {
|
|
|
1378
1424
|
?? schemeName;
|
|
1379
1425
|
return Results.assert(await EntryFind.findWorkspaceEntries(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, {
|
|
1380
1426
|
ownerId: prepared.address.ownerId,
|
|
1427
|
+
authority: prepared.address.authority,
|
|
1381
1428
|
pathname: prepared.address.pathname,
|
|
1382
1429
|
}));
|
|
1383
1430
|
}
|
|
@@ -1409,23 +1456,20 @@ class Dispatcher {
|
|
|
1409
1456
|
if (handler === undefined || manifest === undefined) {
|
|
1410
1457
|
throw new Error("the core log curation owner is not registered");
|
|
1411
1458
|
}
|
|
1412
|
-
const schemeCtx = new SchemeCtxImpl(ctx, "log", manifest, this.#liveSubscriptions);
|
|
1459
|
+
const schemeCtx = new SchemeCtxImpl(ctx, "log", manifest, this.#liveSubscriptions, { ownerId: null });
|
|
1413
1460
|
const outcome = await handler.curate(statement, schemeCtx);
|
|
1414
1461
|
return { result: Results.assert(outcome.result), plan: outcome.plan };
|
|
1415
1462
|
}
|
|
1416
1463
|
// {§proposal}/{§send} — status 202 is a proposal except for broadcast
|
|
1417
1464
|
// SEND signal 202, which parks the loop. The operation disambiguates the status.
|
|
1418
1465
|
static #isProposal(statement, result) {
|
|
1419
|
-
// {§send-300-choices} — SEND signal 300 is the proposal exception.
|
|
1420
1466
|
if (result.status !== 202)
|
|
1421
1467
|
return false;
|
|
1422
|
-
if (statement.op === "SEND" && statement.signal === 300)
|
|
1423
|
-
return true;
|
|
1424
1468
|
return !(statement.op === "SEND" && statement.target === null);
|
|
1425
1469
|
}
|
|
1426
|
-
async #writeLog({ statement, result, workspaceId, workerId, loopId, turnId, sequence, origin, curationPlan, modelCallId, }) {
|
|
1470
|
+
async #writeLog({ statement, result, workspaceId, workerId, functionalityWorkerId, loopId, turnId, sequence, origin, curationPlan, modelCallId, }) {
|
|
1427
1471
|
const durableStatement = DurableStatement.project(statement);
|
|
1428
|
-
const target = this.#extractTarget(durableStatement.target,
|
|
1472
|
+
const target = this.#extractTarget(durableStatement.target, functionalityWorkerId);
|
|
1429
1473
|
await this.#canonColumns(target, workspaceId); // {§fs-answer-in-canon}
|
|
1430
1474
|
const lineMarkerJson = "lineMarker" in durableStatement && durableStatement.lineMarker !== null
|
|
1431
1475
|
? JSON.stringify(durableStatement.lineMarker)
|
|
@@ -1444,8 +1488,7 @@ class Dispatcher {
|
|
|
1444
1488
|
throw new Error("Dispatcher.#writeLog: result attrs collide with private log curation state");
|
|
1445
1489
|
}
|
|
1446
1490
|
attrsObj.__plurnk_curation = {
|
|
1447
|
-
|
|
1448
|
-
expanded: curationPlan.expanded,
|
|
1491
|
+
targets: curationPlan.targets,
|
|
1449
1492
|
add: curationPlan.add,
|
|
1450
1493
|
remove: curationPlan.remove,
|
|
1451
1494
|
};
|
|
@@ -1502,7 +1545,7 @@ class Dispatcher {
|
|
|
1502
1545
|
source: null, // dispatch entries are self-authored; {§env-delta} deltas set this
|
|
1503
1546
|
model_call_id: modelCallId,
|
|
1504
1547
|
op: durableStatement.op,
|
|
1505
|
-
|
|
1548
|
+
delimiter: durableStatement.delimiter,
|
|
1506
1549
|
signal: this.#signalToJson(durableStatement.signal),
|
|
1507
1550
|
scheme: target.scheme,
|
|
1508
1551
|
username: target.username,
|
|
@@ -1538,23 +1581,26 @@ class Dispatcher {
|
|
|
1538
1581
|
// inputs collapse to scheme=null in log target metadata because both render
|
|
1539
1582
|
// as bare paths. Addressable file entries separately persist under the
|
|
1540
1583
|
// reserved `file` identity scheme ({§entry-identity-no-null}).
|
|
1541
|
-
#extractTarget(path,
|
|
1584
|
+
#extractTarget(path, workerId) {
|
|
1542
1585
|
if (path === null)
|
|
1543
1586
|
return { scheme: null, username: null, password: null, hostname: null, port: null, pathname: null, query: null, fragment: null };
|
|
1544
1587
|
// `local` (bare path) carries no URL parts — store the raw text as the pathname for the log record, scheme=null.
|
|
1545
1588
|
if (path.kind === "local")
|
|
1546
1589
|
return { scheme: null, username: null, password: null, hostname: null, port: null, pathname: PathSyntax.decodeParens(path.raw), query: null, fragment: null }; // {§path-parentheses}
|
|
1547
1590
|
const scheme = path.scheme === "file" ? null : path.scheme;
|
|
1548
|
-
//
|
|
1549
|
-
//
|
|
1550
|
-
//
|
|
1591
|
+
// The registered scheme owns authority disposition. Namespace authority
|
|
1592
|
+
// is path syntax; resource and owner authorities remain explicit in the
|
|
1593
|
+
// durable operation evidence.
|
|
1594
|
+
const routedScheme = schemeNameOf(path);
|
|
1595
|
+
const manifest = routedScheme === null
|
|
1596
|
+
? undefined
|
|
1597
|
+
: this.#schemes.manifestFor(routedScheme, workerId);
|
|
1551
1598
|
const foldNs = scheme !== null
|
|
1552
|
-
&&
|
|
1553
|
-
&&
|
|
1554
|
-
&& this.#schemes.has(scheme, workspaceId);
|
|
1599
|
+
&& manifest !== undefined
|
|
1600
|
+
&& (manifest.authority ?? "namespace") === "namespace";
|
|
1555
1601
|
return {
|
|
1556
1602
|
scheme, username: path.username, password: path.password,
|
|
1557
|
-
hostname: foldNs ? null : path.hostname, port: path.port,
|
|
1603
|
+
hostname: foldNs ? null : path.hostname, port: foldNs ? null : path.port,
|
|
1558
1604
|
pathname: PathSyntax.decodeParens(foldNs ? foldAuthorityIntoPath(path.hostname, path.pathname) : path.pathname), // {§path-parentheses}
|
|
1559
1605
|
query: path.query, fragment: path.fragment,
|
|
1560
1606
|
};
|