@plurnk/plurnk-service 1.14.2 → 1.16.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 +2 -2
- package/SPEC.md +243 -173
- package/digest-sql/curation/curation.sql +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/byte-view.d.ts +14 -0
- package/dist/content/byte-view.d.ts.map +1 -0
- package/dist/content/byte-view.js +33 -0
- package/dist/content/byte-view.js.map +1 -0
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +12 -1
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/line-marker.d.ts +2 -1
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js +1 -0
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts +1 -0
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +1 -0
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/read-projector.d.ts +4 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +80 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +43 -0
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -0
- package/dist/core/AdmittedTurnExecutor.js +245 -0
- package/dist/core/AdmittedTurnExecutor.js.map +1 -0
- package/dist/core/BareBatchRunner.d.ts +26 -0
- package/dist/core/BareBatchRunner.d.ts.map +1 -0
- package/dist/core/BareBatchRunner.js +104 -0
- package/dist/core/BareBatchRunner.js.map +1 -0
- package/dist/core/BudgetReadout.d.ts +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +42 -47
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +2 -1
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +8 -9
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +1 -1
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/DataStatementRunner.d.ts +35 -0
- package/dist/core/DataStatementRunner.d.ts.map +1 -0
- package/dist/core/DataStatementRunner.js +252 -0
- package/dist/core/DataStatementRunner.js.map +1 -0
- package/dist/core/Dispatcher.d.ts +8 -3
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +88 -738
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/EditMutations.d.ts +39 -0
- package/dist/core/EditMutations.d.ts.map +1 -0
- package/dist/core/EditMutations.js +418 -0
- package/dist/core/EditMutations.js.map +1 -0
- package/dist/core/Engine.d.ts +2 -23
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +18 -240
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +24 -23
- package/dist/core/KillHandler.d.ts +32 -0
- package/dist/core/KillHandler.d.ts.map +1 -0
- package/dist/core/KillHandler.js +179 -0
- package/dist/core/KillHandler.js.map +1 -0
- package/dist/core/LogVisibility.d.ts +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +3 -4
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LogWriter.d.ts +42 -0
- package/dist/core/LogWriter.d.ts.map +1 -0
- package/dist/core/LogWriter.js +136 -0
- package/dist/core/LogWriter.js.map +1 -0
- package/dist/core/LoopDriver.d.ts +46 -0
- package/dist/core/LoopDriver.d.ts.map +1 -0
- package/dist/core/LoopDriver.js +263 -0
- package/dist/core/LoopDriver.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +2 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/MembershipMaterialization.d.ts +7 -0
- package/dist/core/MembershipMaterialization.d.ts.map +1 -0
- package/dist/core/MembershipMaterialization.js +283 -0
- package/dist/core/MembershipMaterialization.js.map +1 -0
- package/dist/core/MutationEffects.d.ts +29 -0
- package/dist/core/MutationEffects.d.ts.map +1 -0
- package/dist/core/MutationEffects.js +318 -0
- package/dist/core/MutationEffects.js.map +1 -0
- package/dist/core/OverflowTurn.d.ts +4 -4
- package/dist/core/OverflowTurn.d.ts.map +1 -1
- package/dist/core/OverflowTurn.js +6 -7
- package/dist/core/OverflowTurn.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +31 -9
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ResourceMutations.d.ts +12 -36
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +27 -1351
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/ResourceSelector.d.ts +21 -0
- package/dist/core/ResourceSelector.d.ts.map +1 -0
- package/dist/core/ResourceSelector.js +233 -0
- package/dist/core/ResourceSelector.js.map +1 -0
- package/dist/core/ResourceTransfers.d.ts +55 -0
- package/dist/core/ResourceTransfers.d.ts.map +1 -0
- package/dist/core/ResourceTransfers.js +525 -0
- package/dist/core/ResourceTransfers.js.map +1 -0
- package/dist/core/SchemeRegistry.js +2 -2
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/SendBroadcastHandler.d.ts +40 -0
- package/dist/core/SendBroadcastHandler.d.ts.map +1 -0
- package/dist/core/SendBroadcastHandler.js +159 -0
- package/dist/core/SendBroadcastHandler.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +11 -0
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +22 -1
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +19 -9
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TokenCalibration.d.ts +16 -0
- package/dist/core/TokenCalibration.d.ts.map +1 -0
- package/dist/core/TokenCalibration.js +35 -0
- package/dist/core/TokenCalibration.js.map +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +15 -12
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/TurnMaterialization.d.ts +37 -0
- package/dist/core/TurnMaterialization.d.ts.map +1 -0
- package/dist/core/TurnMaterialization.js +296 -0
- package/dist/core/TurnMaterialization.js.map +1 -0
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +6 -8
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts +15 -27
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +76 -670
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerControlHandler.d.ts +15 -0
- package/dist/core/WorkerControlHandler.d.ts.map +1 -0
- package/dist/core/WorkerControlHandler.js +89 -0
- package/dist/core/WorkerControlHandler.js.map +1 -0
- package/dist/core/attachments.d.ts +14 -0
- package/dist/core/attachments.d.ts.map +1 -0
- package/dist/core/attachments.js +18 -0
- package/dist/core/attachments.js.map +1 -0
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +0 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +5 -16
- package/dist/core/git-membership.d.ts +15 -0
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +4 -273
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +2 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/mutation-types.d.ts +102 -0
- package/dist/core/mutation-types.d.ts.map +1 -0
- package/dist/core/mutation-types.js +2 -0
- package/dist/core/mutation-types.js.map +1 -0
- package/dist/core/operation-target-groups.js +1 -1
- package/dist/core/operation-target-groups.js.map +1 -1
- package/dist/core/packet-wire.d.ts +7 -6
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +96 -68
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +0 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +1 -1
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/statement-primary.d.ts +4 -0
- package/dist/core/statement-primary.d.ts.map +1 -0
- package/dist/core/statement-primary.js +3 -0
- package/dist/core/statement-primary.js.map +1 -0
- package/dist/core/teaching-corpus.d.ts +0 -1
- package/dist/core/teaching-corpus.d.ts.map +1 -1
- package/dist/core/teaching-corpus.js +0 -9
- package/dist/core/teaching-corpus.js.map +1 -1
- package/dist/core/turn-scheduler.js +3 -3
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/turn-signals.d.ts +15 -0
- package/dist/core/turn-signals.d.ts.map +1 -0
- package/dist/core/turn-signals.js +19 -0
- package/dist/core/turn-signals.js.map +1 -0
- package/dist/core/worker-settings.d.ts +0 -1
- package/dist/core/worker-settings.d.ts.map +1 -1
- package/dist/core/worker-settings.js +1 -1
- package/dist/core/worker-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts +3 -16
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +10 -958
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/DigestRender.d.ts +12 -0
- package/dist/digest/DigestRender.d.ts.map +1 -0
- package/dist/digest/DigestRender.js +641 -0
- package/dist/digest/DigestRender.js.map +1 -0
- package/dist/digest/DigestRequiem.d.ts +13 -0
- package/dist/digest/DigestRequiem.d.ts.map +1 -0
- package/dist/digest/DigestRequiem.js +332 -0
- package/dist/digest/DigestRequiem.js.map +1 -0
- package/dist/digest/digest-rows.d.ts +303 -0
- package/dist/digest/digest-rows.d.ts.map +1 -0
- package/dist/digest/digest-rows.js +2 -0
- package/dist/digest/digest-rows.js.map +1 -0
- package/dist/digest/digest.sql +1 -7
- package/dist/observe/api.d.ts +0 -2
- package/dist/observe/api.d.ts.map +1 -1
- package/dist/observe/api.js +2 -2
- package/dist/observe/api.js.map +1 -1
- package/dist/observe/metrics.d.ts +0 -1
- package/dist/observe/metrics.d.ts.map +1 -1
- package/dist/observe/metrics.js +0 -1
- package/dist/observe/metrics.js.map +1 -1
- package/dist/schemes/Exec.d.ts +4 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +89 -48
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +2 -1
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +3 -3
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts +4 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +100 -13
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +4 -5
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +26 -118
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +1 -66
- package/dist/schemes/Prompt.js +1 -1
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +1 -13
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +3 -1
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +18 -3
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts +4 -2
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +79 -10
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts +1 -2
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +2 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +20 -2
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts +1 -0
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +3 -0
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +2 -2
- package/dist/schemes/_entry-send.d.ts +0 -1
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +5 -80
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/exec-runtime.d.ts +7 -0
- package/dist/schemes/exec-runtime.d.ts.map +1 -0
- package/dist/schemes/exec-runtime.js +2 -0
- package/dist/schemes/exec-runtime.js.map +1 -0
- package/dist/server/ClientReads.d.ts +34 -0
- package/dist/server/ClientReads.d.ts.map +1 -0
- package/dist/server/ClientReads.js +210 -0
- package/dist/server/ClientReads.js.map +1 -0
- package/dist/server/Daemon.d.ts +12 -22
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +31 -362
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +6 -5
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +3 -2
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +7 -3
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/Functionality.d.ts +0 -12
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +0 -1
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +3 -3
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +2 -13
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +4 -4
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/SkillsFunctionality.d.ts +1 -7
- package/dist/server/SkillsFunctionality.d.ts.map +1 -1
- package/dist/server/SkillsFunctionality.js +3 -3
- package/dist/server/SkillsFunctionality.js.map +1 -1
- package/dist/server/WorkerModelResolver.d.ts +17 -0
- package/dist/server/WorkerModelResolver.d.ts.map +1 -0
- package/dist/server/WorkerModelResolver.js +166 -0
- package/dist/server/WorkerModelResolver.js.map +1 -0
- package/dist/server/daemon-results.d.ts +5 -0
- package/dist/server/daemon-results.d.ts.map +1 -0
- package/dist/server/daemon-results.js +7 -0
- package/dist/server/daemon-results.js.map +1 -0
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +4 -6
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/logEntry.d.ts +0 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +1 -13
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +1 -5
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +11 -2
- package/dist/server/loopDocs.js.map +1 -1
- package/migrations/001_schema.sql +30 -347
- package/package.json +30 -30
package/dist/core/Dispatcher.js
CHANGED
|
@@ -1,48 +1,27 @@
|
|
|
1
1
|
var _a;
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { entryCoordinateOf, foldAuthorityIntoPath, renderAddress, renderTarget, schemeNameOf } from "./plurnk-uri.js";
|
|
5
|
-
import Fork from "./fork.js";
|
|
6
|
-
import WorkerCap from "./worker-cap.js";
|
|
7
|
-
import { PathSyntax, TagSignal } from "@plurnk/plurnk-contracts";
|
|
2
|
+
import { foldAuthorityIntoPath, renderAddress, renderTarget, schemeNameOf } from "./plurnk-uri.js";
|
|
3
|
+
import { PathSyntax } from "@plurnk/plurnk-contracts";
|
|
8
4
|
import Namespace from "./namespace.js";
|
|
9
|
-
import LoopPolicyReader from "./LoopPolicyReader.js";
|
|
10
5
|
import CapabilityResolver from "./CapabilityResolver.js";
|
|
11
|
-
import CapabilityPolicies from "./CapabilityPolicies.js";
|
|
12
|
-
import ChannelWrite from "./ChannelWrite.js";
|
|
13
|
-
import { ReadProjector } from "../content/index.js";
|
|
14
6
|
import SchemeCtxImpl from "./caps/SchemeCtxImpl.js";
|
|
15
|
-
import EntryOps from "../schemes/_entry-ops.js";
|
|
16
|
-
import EntryFind from "../schemes/_entry-find.js";
|
|
17
7
|
import LoopLifecycle from "./LoopLifecycle.js";
|
|
18
|
-
import TerminalResult from "./TerminalResult.js";
|
|
19
8
|
import Results from "./results.js";
|
|
20
9
|
import { OperationFailureError } from "./results.js";
|
|
21
10
|
import EffectPolicy from "../schemes/EffectPolicy.js";
|
|
22
11
|
import { CoreSchemeAdapterBase } from "./CoreSchemeServices.js";
|
|
23
|
-
import { InvalidOperationResultError
|
|
24
|
-
import DurableStatement from "./DurableStatement.js";
|
|
12
|
+
import { InvalidOperationResultError } from "@plurnk/plurnk-schemes";
|
|
25
13
|
import ResourceMutations from "./ResourceMutations.js";
|
|
14
|
+
import { primaryTargetOf } from "./statement-primary.js";
|
|
26
15
|
import LogBody from "./LogBody.js";
|
|
27
16
|
import LogVisibility from "./LogVisibility.js";
|
|
28
|
-
import
|
|
17
|
+
import WorkerControlHandler from "./WorkerControlHandler.js";
|
|
18
|
+
import KillHandler from "./KillHandler.js";
|
|
19
|
+
import SendBroadcastHandler from "./SendBroadcastHandler.js";
|
|
20
|
+
import LogWriter from "./LogWriter.js";
|
|
21
|
+
import DataStatementRunner from "./DataStatementRunner.js";
|
|
29
22
|
// SPEC {§scheme-surface}: writer must be in target scheme's manifest.writableBy.
|
|
30
|
-
//
|
|
23
|
+
// READ/FIND are not gated — they read, never mutating an entry.
|
|
31
24
|
const MUTATING_OPS = new Set(["EDIT", "SEND", "COPY", "MOVE", "EXEC", "KILL", "FORK", "WORK"]);
|
|
32
|
-
const assertClassifyingSignal = (statement) => {
|
|
33
|
-
if (statement.op === "FIND"
|
|
34
|
-
|| statement.op === "READ"
|
|
35
|
-
|| statement.op === "EDIT"
|
|
36
|
-
|| statement.op === "COPY"
|
|
37
|
-
|| statement.op === "MOVE"
|
|
38
|
-
|| statement.op === "BARE") {
|
|
39
|
-
TagSignal.applied(statement.signal);
|
|
40
|
-
}
|
|
41
|
-
if (statement.op === "EXEC")
|
|
42
|
-
TagSignal.applied(statement.tags ?? null); // {§exec-tag-signal}
|
|
43
|
-
};
|
|
44
|
-
const primaryTargetOf = (statement) => statement.op === "COPY" || statement.op === "MOVE" ? statement.source.target : statement.target;
|
|
45
|
-
const primaryLineMarkerOf = (statement) => statement.op === "COPY" || statement.op === "MOVE" ? statement.source.lineMarker : statement.lineMarker;
|
|
46
25
|
// Op dispatch ({§op-methods-op-dispatch}): admission, operation-owner routing,
|
|
47
26
|
// durable log writing, and proposal lifecycle.
|
|
48
27
|
class Dispatcher {
|
|
@@ -84,6 +63,11 @@ class Dispatcher {
|
|
|
84
63
|
#resourceMutations;
|
|
85
64
|
#entryAddresses;
|
|
86
65
|
#capabilities;
|
|
66
|
+
#workerControl;
|
|
67
|
+
#kill;
|
|
68
|
+
#sendBroadcast;
|
|
69
|
+
#logWriter;
|
|
70
|
+
#dataRun;
|
|
87
71
|
constructor({ db, schemes, mimetypes, weigh, notices, proposals, interactions, executors, loopSignal, settleDerivations, settleVectors, streamEventNotify, wakeWorkerNotify, injectWorker, cancelWorker, cancelDescendants, parkDeadlines, joinTargets, liveSubscriptions, entryAddresses }) {
|
|
88
72
|
this.#db = db;
|
|
89
73
|
this.#schemes = schemes;
|
|
@@ -110,7 +94,7 @@ class Dispatcher {
|
|
|
110
94
|
this.#resourceMutations = new ResourceMutations({
|
|
111
95
|
schemes,
|
|
112
96
|
liveSubscriptions,
|
|
113
|
-
run: (schemeName, statement, ctx) => this.#run(schemeName, statement, ctx),
|
|
97
|
+
run: (schemeName, statement, ctx) => this.#dataRun.run(schemeName, statement, ctx),
|
|
114
98
|
checkWritable: (statement, origin, workerId) => this.#checkWritable(statement, origin, workerId),
|
|
115
99
|
checkCapabilities: (statement, workspaceId, loopId, workerId) => this.#checkCapabilities(statement, workspaceId, loopId, workerId),
|
|
116
100
|
editTargetIdentity: (statement, workspaceId, workerId) => this.#editTargetIdentity(statement, workspaceId, workerId),
|
|
@@ -125,6 +109,11 @@ class Dispatcher {
|
|
|
125
109
|
deleteChannel: (scheme, address, channel, ctx) => this.#deleteChannel(scheme, address, channel, ctx),
|
|
126
110
|
applyProposal: (statement, result, resolution, ids) => this.#proposals.workerApply(statement, result, resolution, ids),
|
|
127
111
|
});
|
|
112
|
+
this.#workerControl = new WorkerControlHandler({ db: this.#db, schemes: this.#schemes, failure: _a.#failure });
|
|
113
|
+
this.#kill = new KillHandler({ db: this.#db, schemes: this.#schemes, liveSubscriptions: this.#liveSubscriptions, cancelWorker: this.#cancelWorker, resolveDataEntryAddress: this.#resolveDataEntryAddress.bind(this), boundEntryContext: this.#boundEntryContext.bind(this), handlerContext: this.#handlerContext.bind(this), deleteEntry: this.#deleteEntry.bind(this), failure: _a.#failure });
|
|
114
|
+
this.#sendBroadcast = new SendBroadcastHandler({ db: this.#db, cancelDescendants: this.#cancelDescendants, parkDeadlines: this.#parkDeadlines, joinTargets: this.#joinTargets, lifecycle: this.#lifecycle, nextPacketBoundaries: this.#nextPacketBoundaries.bind(this), unobservedFailureCount: this.#unobservedFailureCount.bind(this), pendingSet: this.#pendingSet.bind(this), hasLiveWork: this.hasLiveWork.bind(this), failure: _a.#failure, statusResult: _a.#statusResult, unobservedFailures: _a.#unobservedFailures });
|
|
115
|
+
this.#logWriter = new LogWriter({ db: this.#db, weighContent: this.#weighContent, extractTarget: this.#extractTarget.bind(this), canonColumns: this.#canonColumns.bind(this), signalToJson: this.#signalToJson.bind(this), isProposal: _a.#isProposal });
|
|
116
|
+
this.#dataRun = new DataStatementRunner({ schemes: this.#schemes, liveSubscriptions: this.#liveSubscriptions, resolveDataEntryAddress: this.#resolveDataEntryAddress.bind(this), fixedEntryOwnerId: this.#fixedEntryOwnerId.bind(this), prepareDataRepresentation: this.#prepareDataRepresentation.bind(this), failure: _a.#failure });
|
|
128
117
|
}
|
|
129
118
|
// workspace → project_root, memoized: {§fs-namespace} fixes the root immutably at
|
|
130
119
|
// workspace creation, so a process-lifetime cache can never go stale.
|
|
@@ -279,21 +268,57 @@ class Dispatcher {
|
|
|
279
268
|
identity: renderTarget(target),
|
|
280
269
|
};
|
|
281
270
|
}
|
|
271
|
+
// {§kill-scope-entry} — a scoped KILL on an entry-bearing scheme is one EDIT with an empty
|
|
272
|
+
// body over the same marker: prepared, gated, and merged as an EDIT while its log row
|
|
273
|
+
// records the model's KILL. Schemes that implement kill() (streams) take the scope themselves;
|
|
274
|
+
// the log's scoped KILL is curation.
|
|
275
|
+
#scopedEntryEdits = new WeakMap();
|
|
276
|
+
#scopedEntryEdit(statement, functionalityWorkerId) {
|
|
277
|
+
if (statement.op === "EDIT")
|
|
278
|
+
return statement;
|
|
279
|
+
// A body pattern is a log selector; a scoped KILL carrying one is not an EDIT — the KILL
|
|
280
|
+
// handler refuses it ({§kill-scope-entry}).
|
|
281
|
+
if (statement.op !== "KILL" || statement.lineMarker === null || statement.body !== null)
|
|
282
|
+
return null;
|
|
283
|
+
const cached = this.#scopedEntryEdits.get(statement);
|
|
284
|
+
if (cached !== undefined)
|
|
285
|
+
return cached;
|
|
286
|
+
const schemeName = schemeNameOf(statement.target);
|
|
287
|
+
if (schemeName === null || schemeName === "log")
|
|
288
|
+
return null;
|
|
289
|
+
const handler = this.#schemes.get(schemeName, functionalityWorkerId);
|
|
290
|
+
if (handler === undefined || typeof handler.kill === "function")
|
|
291
|
+
return null;
|
|
292
|
+
const edit = {
|
|
293
|
+
op: "EDIT",
|
|
294
|
+
delimiter: statement.delimiter,
|
|
295
|
+
annotation: statement.annotation,
|
|
296
|
+
metadata: statement.metadata,
|
|
297
|
+
target: statement.target,
|
|
298
|
+
lineMarker: statement.lineMarker,
|
|
299
|
+
body: "",
|
|
300
|
+
position: statement.position,
|
|
301
|
+
};
|
|
302
|
+
this.#scopedEntryEdits.set(statement, edit);
|
|
303
|
+
return edit;
|
|
304
|
+
}
|
|
282
305
|
async prepareEditBatches(statements, context) {
|
|
283
|
-
for (const statement of statements)
|
|
284
|
-
assertClassifyingSignal(statement); // {§log-tag-signal}
|
|
285
306
|
const { workspaceId, workerId, functionalityWorkerId, loopId, turnId, origin } = context;
|
|
286
307
|
const schemeCtx = this.#buildSchemeCtx({ workspaceId, workerId, functionalityWorkerId, loopId, turnId, origin });
|
|
287
|
-
|
|
308
|
+
const edits = statements.flatMap((statement) => {
|
|
309
|
+
const edit = this.#scopedEntryEdit(statement, schemeCtx.functionalityWorkerId);
|
|
310
|
+
return edit === null ? [] : [edit];
|
|
311
|
+
});
|
|
312
|
+
await this.#resourceMutations.prepareEditBatches(edits, context, schemeCtx);
|
|
288
313
|
}
|
|
289
314
|
async dispatch(context) {
|
|
290
|
-
assertClassifyingSignal(context.statement); // {§log-tag-signal}
|
|
291
315
|
let result = await this.#dispatchOne(context);
|
|
292
|
-
|
|
316
|
+
const edit = context.statement.op === "EDIT" ? context.statement : this.#scopedEntryEdits.get(context.statement);
|
|
317
|
+
if (edit !== undefined) {
|
|
293
318
|
// {§edit-batch-merges} — a proposal's apply result replaces the projected one; the
|
|
294
319
|
// statement's merge facts ride every EDIT result, whichever route produced it.
|
|
295
|
-
result = this.#resourceMutations.withMergeFacts(
|
|
296
|
-
this.#resourceMutations.settleEdit(
|
|
320
|
+
result = this.#resourceMutations.withMergeFacts(edit, result);
|
|
321
|
+
this.#resourceMutations.settleEdit(edit, result);
|
|
297
322
|
}
|
|
298
323
|
return result;
|
|
299
324
|
}
|
|
@@ -320,7 +345,7 @@ class Dispatcher {
|
|
|
320
345
|
result = await this.#resourceMutations.preparedEditResult(statement);
|
|
321
346
|
}
|
|
322
347
|
else if (statement.op === "SEND" && statement.target === null) {
|
|
323
|
-
result = await this.#handleSendBroadcast(statement, {
|
|
348
|
+
result = await this.#sendBroadcast.handleSendBroadcast(statement, {
|
|
324
349
|
workspaceId,
|
|
325
350
|
workerId,
|
|
326
351
|
loopId,
|
|
@@ -329,15 +354,13 @@ class Dispatcher {
|
|
|
329
354
|
origin,
|
|
330
355
|
});
|
|
331
356
|
}
|
|
332
|
-
else if (statement.op === "
|
|
333
|
-
|| statement.op === "FOLD"
|
|
334
|
-
|| (statement.op === "KILL" && schemeNameOf(statement.target) === "log")) {
|
|
357
|
+
else if (statement.op === "KILL" && schemeNameOf(statement.target) === "log") {
|
|
335
358
|
const curation = await this.#runLogCuration(statement, schemeCtx);
|
|
336
359
|
result = curation.result;
|
|
337
360
|
curationPlan = curation.plan;
|
|
338
361
|
}
|
|
339
362
|
else if (statement.op === "FORK" || statement.op === "WORK") {
|
|
340
|
-
result = await this.#handleWorkerControl(statement, schemeCtx);
|
|
363
|
+
result = await this.#workerControl.handleWorkerControl(statement, schemeCtx);
|
|
341
364
|
}
|
|
342
365
|
else if (statement.op === "COPY") {
|
|
343
366
|
result = await this.#resourceMutations.handleCopy(statement, schemeCtx);
|
|
@@ -345,8 +368,11 @@ class Dispatcher {
|
|
|
345
368
|
else if (statement.op === "MOVE") {
|
|
346
369
|
result = await this.#resourceMutations.handleMove(statement, schemeCtx);
|
|
347
370
|
}
|
|
371
|
+
else if (statement.op === "KILL" && this.#scopedEntryEdits.has(statement)) {
|
|
372
|
+
result = await this.#resourceMutations.preparedEditResult(this.#scopedEntryEdits.get(statement));
|
|
373
|
+
}
|
|
348
374
|
else if (statement.op === "KILL") {
|
|
349
|
-
result = await this.#handleKill(statement, schemeCtx);
|
|
375
|
+
result = await this.#kill.handleKill(statement, schemeCtx);
|
|
350
376
|
}
|
|
351
377
|
else if (statement.op === "PLAN") {
|
|
352
378
|
result = this.#handlePlan(statement);
|
|
@@ -354,10 +380,10 @@ class Dispatcher {
|
|
|
354
380
|
else if (statement.op === "EXEC") {
|
|
355
381
|
// EXEC routes unconditionally to its operation owner after
|
|
356
382
|
// the shared capability resolver admits its runtime/tool.
|
|
357
|
-
result = await this.#run("exec", statement, schemeCtx);
|
|
383
|
+
result = await this.#dataRun.run("exec", statement, schemeCtx);
|
|
358
384
|
}
|
|
359
385
|
else {
|
|
360
|
-
result = await this.#run(schemeNameOf(statement.target), statement, schemeCtx); // {§op-methods-op-dispatch}
|
|
386
|
+
result = await this.#dataRun.run(schemeNameOf(statement.target), statement, schemeCtx); // {§op-methods-op-dispatch}
|
|
361
387
|
}
|
|
362
388
|
}
|
|
363
389
|
catch (err) { // a scheme exception becomes the op's 500 outcome — {§scheme-surface-exception-500}
|
|
@@ -383,7 +409,7 @@ class Dispatcher {
|
|
|
383
409
|
// {§join-blocking-collect}
|
|
384
410
|
if (typeof result.awaitWorker === "string")
|
|
385
411
|
this.#joinTargets.add(loopId);
|
|
386
|
-
const logEntryId = await this.#writeLog({
|
|
412
|
+
const logEntryId = await this.#logWriter.writeLog({
|
|
387
413
|
statement,
|
|
388
414
|
result,
|
|
389
415
|
functionalityWorkerId,
|
|
@@ -484,7 +510,7 @@ class Dispatcher {
|
|
|
484
510
|
const denial = await this.#checkCapabilities(statement, schemeCtx.workspaceId, loopId, schemeCtx.functionalityWorkerId);
|
|
485
511
|
if (denial !== null)
|
|
486
512
|
return denial;
|
|
487
|
-
return this.#run(schemeNameOf(statement.target), statement, schemeCtx);
|
|
513
|
+
return this.#dataRun.run(schemeNameOf(statement.target), statement, schemeCtx);
|
|
488
514
|
}
|
|
489
515
|
capabilityProjection(workspaceId, workerId) {
|
|
490
516
|
return this.#capabilities.projection(workspaceId, workerId);
|
|
@@ -587,7 +613,7 @@ class Dispatcher {
|
|
|
587
613
|
retryable: false,
|
|
588
614
|
});
|
|
589
615
|
}
|
|
590
|
-
return Results.assertReadResult(await this.#run(schemeName, statement, ctx));
|
|
616
|
+
return Results.assertReadResult(await this.#dataRun.run(schemeName, statement, ctx));
|
|
591
617
|
}
|
|
592
618
|
// The one place per-dispatch coordinates are built; a caller that carries no
|
|
593
619
|
// explicit Functionality coordinate acts in its own Worker's
|
|
@@ -722,209 +748,6 @@ class Dispatcher {
|
|
|
722
748
|
#isWorkerControl(statement) {
|
|
723
749
|
return statement.op === "FORK" || statement.op === "WORK"; // worker control targets worker://<name> (grammar 0.74.55)
|
|
724
750
|
}
|
|
725
|
-
// WORK and FORK name the new worker in the target authority and carry its seed task in the body.
|
|
726
|
-
// Their distinct fresh/branched histories are specified by {§worker-scheme-spawn} and {§worker-scheme-fork}.
|
|
727
|
-
async #handleWorkerControl(statement, ctx) {
|
|
728
|
-
const address = WorkerControlAddress.resolve(statement.target, statement.op);
|
|
729
|
-
if (!address.ok)
|
|
730
|
-
return address.result;
|
|
731
|
-
const name = address.authority;
|
|
732
|
-
try {
|
|
733
|
-
WorkerName.assert(name); // {§worker-name-minting}
|
|
734
|
-
}
|
|
735
|
-
catch (error) {
|
|
736
|
-
if (!(error instanceof WorkerNameError))
|
|
737
|
-
throw error;
|
|
738
|
-
return _a.#failure(`worker-${error.code}`, 400, error.message, {}, {
|
|
739
|
-
operation: statement.op,
|
|
740
|
-
worker: error.workerName,
|
|
741
|
-
recovery: error.recovery,
|
|
742
|
-
retryable: false,
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
if (ctx.injectWorker === undefined)
|
|
746
|
-
throw new Error("worker control: injectWorker capability absent");
|
|
747
|
-
const denied = await WorkerCap.deny(this.#db, ctx.workspaceId);
|
|
748
|
-
if (denied !== null)
|
|
749
|
-
return denied;
|
|
750
|
-
const prompt = statement.body;
|
|
751
|
-
// {§worker-delegation-inherits-policy} — authority flows down the
|
|
752
|
-
// delegation edge. The child receives the delegator's complete loop
|
|
753
|
-
// policy and an immutable snapshot of its effective capability bound.
|
|
754
|
-
const policy = await LoopPolicyReader.read(this.#db, ctx.loopId);
|
|
755
|
-
const capabilityBound = await CapabilityPolicies.delegationBound(this.#db, ctx.workspaceId, ctx.workerId, policy);
|
|
756
|
-
const delegationPolicy = {
|
|
757
|
-
...policy,
|
|
758
|
-
capabilities: capabilityBound,
|
|
759
|
-
};
|
|
760
|
-
// A name is frozen per worker but reclaimable across time ({§machine-processes-worker-origin}): a LIVE
|
|
761
|
-
// sister holding it is a 409 (legible, never a raw UNIQUE 500); a free/terminated name reclaims.
|
|
762
|
-
const live = await this.#db.worker_live_by_name.get({ workspace_id: ctx.workspaceId, name });
|
|
763
|
-
if (live !== undefined) {
|
|
764
|
-
return _a.#failure("worker-already-running", 409, `Worker '${name}' is already running.`, {}, { worker: name, retryable: false });
|
|
765
|
-
}
|
|
766
|
-
if (statement.signal !== null && statement.signal !== undefined) {
|
|
767
|
-
// {§worker-spawn-no-signal} (#396) — WORK/FORK take no signal. Branch
|
|
768
|
-
// delegation was removed outright; a model manages git branches through
|
|
769
|
-
// ordinary EXEC git, taught by the git skill, never engine machinery.
|
|
770
|
-
return _a.#failure("worker-signal-invalid", 400, `${statement.op} takes no signal.`, {}, {
|
|
771
|
-
worker: name,
|
|
772
|
-
signal: statement.signal,
|
|
773
|
-
recovery: `Spawn without a signal: \`## ${statement.op}0 (worker://${name})\` with the prompt as the body.`,
|
|
774
|
-
retryable: false,
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
if (statement.op === "FORK") {
|
|
778
|
-
// Branch the current worker's log into a named sister.
|
|
779
|
-
const branchWorkerId = await Fork.fork(this.#db, ctx.workerId, name, capabilityBound, (scheme) => this.#schemes.entryInheritanceForStoredScheme(scheme, ctx.workerId));
|
|
780
|
-
await ctx.injectWorker({
|
|
781
|
-
workspaceId: ctx.workspaceId,
|
|
782
|
-
workerId: branchWorkerId,
|
|
783
|
-
sourceWorkerId: ctx.workerId,
|
|
784
|
-
prompt,
|
|
785
|
-
freshLoopPolicy: delegationPolicy,
|
|
786
|
-
parentLoopId: ctx.loopId,
|
|
787
|
-
});
|
|
788
|
-
return { status: 200, body: name };
|
|
789
|
-
}
|
|
790
|
-
// WORK — a fresh worker sister named <name>.
|
|
791
|
-
const row = await this.#db.fork_insert_worker.get({
|
|
792
|
-
workspace_id: ctx.workspaceId, name, parent_worker_id: ctx.workerId, origin: ctx.writer,
|
|
793
|
-
fork_snapshot: 0,
|
|
794
|
-
capability_bound: JSON.stringify(capabilityBound),
|
|
795
|
-
});
|
|
796
|
-
if (row === undefined)
|
|
797
|
-
throw new Error("worker spawn: worker insert returned no row");
|
|
798
|
-
await ctx.injectWorker({
|
|
799
|
-
workspaceId: ctx.workspaceId,
|
|
800
|
-
workerId: row.id,
|
|
801
|
-
sourceWorkerId: ctx.workerId,
|
|
802
|
-
prompt,
|
|
803
|
-
freshLoopPolicy: delegationPolicy,
|
|
804
|
-
parentLoopId: ctx.loopId,
|
|
805
|
-
});
|
|
806
|
-
return { status: 200, body: name };
|
|
807
|
-
}
|
|
808
|
-
// KILL is target-polymorphic. Scheme handlers own the optional numeric code's
|
|
809
|
-
// meaning; core retains worker and entry dispatch. {§operation-code-polymorphism}
|
|
810
|
-
async #handleKill(statement, ctx) {
|
|
811
|
-
if (statement.op !== "KILL")
|
|
812
|
-
throw new Error("unreachable");
|
|
813
|
-
const path = statement.target;
|
|
814
|
-
if (path === null) {
|
|
815
|
-
return _a.#failure("kill-target-required", 400, "KILL requires a target path.", {}, { retryable: false });
|
|
816
|
-
}
|
|
817
|
-
const schemeName = schemeNameOf(path);
|
|
818
|
-
if (schemeName === null) {
|
|
819
|
-
return _a.#failure("kill-target-scheme-required", 400, "KILL target requires a scheme.", {}, { retryable: false });
|
|
820
|
-
}
|
|
821
|
-
const manifest = this.#schemes.manifestFor(schemeName, ctx.functionalityWorkerId);
|
|
822
|
-
const coordinate = entryCoordinateOf(path, manifest?.authority ?? "namespace");
|
|
823
|
-
// log:/// KILL has already gone through the projection-curation owner.
|
|
824
|
-
// This path owns scheme-specific world and process KILL semantics.
|
|
825
|
-
// Process-KILL: any scheme whose handler exposes kill() aborts a live stream — the
|
|
826
|
-
// exec handler, registered as "exec" + under every runtime tag (sh/node), so a tag-
|
|
827
|
-
// addressed stream (sh:///l/t/s) routes here, not to deleteEntry. {§exec}
|
|
828
|
-
const killable = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
829
|
-
if (killable !== undefined && typeof killable.kill === "function") {
|
|
830
|
-
// Pass the model's OWN scheme so a stream-KILL error answers in the runtime tag the
|
|
831
|
-
// model addressed (sh:///…), not the internal `exec` ({§fs-answer-in-canon}).
|
|
832
|
-
let handlerCtx;
|
|
833
|
-
if (manifest?.category === "data") {
|
|
834
|
-
const resolved = await this.#resolveDataEntryAddress({
|
|
835
|
-
target: path,
|
|
836
|
-
routedScheme: schemeName,
|
|
837
|
-
handler: killable,
|
|
838
|
-
manifest,
|
|
839
|
-
ctx,
|
|
840
|
-
});
|
|
841
|
-
if (resolved.result !== null)
|
|
842
|
-
return resolved.result;
|
|
843
|
-
if (resolved.address === null) {
|
|
844
|
-
return _a.#failure("entry-not-found", 404, `No entry exists at ${renderAddress({ scheme: schemeName, ...coordinate })}.`);
|
|
845
|
-
}
|
|
846
|
-
handlerCtx = this.#boundEntryContext(schemeName, resolved.address, ctx);
|
|
847
|
-
}
|
|
848
|
-
else {
|
|
849
|
-
handlerCtx = await this.#handlerContext(schemeName, ctx, coordinate.authority);
|
|
850
|
-
}
|
|
851
|
-
if (handlerCtx === null) {
|
|
852
|
-
throw new InvalidOperationResultError(`Registered scheme '${schemeName}' has no dispatch context.`);
|
|
853
|
-
}
|
|
854
|
-
return await killable.kill(coordinate.pathname, statement.signal, handlerCtx, schemeName);
|
|
855
|
-
}
|
|
856
|
-
if (schemeName === "worker") {
|
|
857
|
-
// Entry-path present → KILL a private owner-held entry (delete it), self-only —
|
|
858
|
-
// NOT worker cancellation. The authority (hostname) names the owner, the pathname the
|
|
859
|
-
// entry; only the path-ABSENT form (worker://<name>) terminates the worker-as-actor. {§worker-scheme}
|
|
860
|
-
const entryPath = path.kind === "url" ? (path.pathname ?? "") : "";
|
|
861
|
-
if (entryPath !== "" && entryPath !== "/") {
|
|
862
|
-
const workerHandler = this.#schemes.get("worker");
|
|
863
|
-
if (manifest?.category !== "data") {
|
|
864
|
-
throw new InvalidOperationResultError("Registered scheme 'worker' is not entry-bearing.");
|
|
865
|
-
}
|
|
866
|
-
const resolved = await this.#resolveDataEntryAddress({
|
|
867
|
-
target: path,
|
|
868
|
-
routedScheme: "worker",
|
|
869
|
-
handler: workerHandler,
|
|
870
|
-
manifest,
|
|
871
|
-
ctx,
|
|
872
|
-
});
|
|
873
|
-
if (resolved.result !== null)
|
|
874
|
-
return resolved.result;
|
|
875
|
-
if (resolved.address === null) {
|
|
876
|
-
return _a.#failure("entry-not-found", 404, "The worker entry does not exist.");
|
|
877
|
-
}
|
|
878
|
-
const handlerCtx = this.#boundEntryContext("worker", resolved.address, ctx);
|
|
879
|
-
if (handlerCtx === null) {
|
|
880
|
-
throw new InvalidOperationResultError("Registered scheme 'worker' has no dispatch context.");
|
|
881
|
-
}
|
|
882
|
-
return await workerHandler.killEntry(statement, handlerCtx);
|
|
883
|
-
}
|
|
884
|
-
const address = WorkerControlAddress.resolve(path, "KILL");
|
|
885
|
-
if (!address.ok)
|
|
886
|
-
return address.result;
|
|
887
|
-
// `~` is the sole current-worker sigil; every other authority is a literal name.
|
|
888
|
-
// An idle worker is a no-op 200; a missing named worker is 404. {§worker-control-addressing}
|
|
889
|
-
const name = address.authority;
|
|
890
|
-
let workerId = ctx.workerId;
|
|
891
|
-
if (name !== "~") {
|
|
892
|
-
const row = await this.#db.worker_resolve_by_name.get({ workspace_id: ctx.workspaceId, name });
|
|
893
|
-
if (row === undefined) {
|
|
894
|
-
return _a.#failure("worker-not-found", 404, `Worker '${name}' does not exist in this workspace.`, {}, { worker: name, retryable: false });
|
|
895
|
-
}
|
|
896
|
-
workerId = row.id;
|
|
897
|
-
}
|
|
898
|
-
if (this.#cancelWorker === undefined)
|
|
899
|
-
throw new Error("worker kill: cancelWorker capability absent");
|
|
900
|
-
// {§op-synchronous} — KILL is decisive. Await the one lifecycle owner so the
|
|
901
|
-
// same-turn pending-work gate observes the complete subtree as terminal.
|
|
902
|
-
await this.#cancelWorker(workerId, "killed via worker:// KILL");
|
|
903
|
-
return { status: 200 };
|
|
904
|
-
}
|
|
905
|
-
if (!this.#schemes.has(schemeName, ctx.functionalityWorkerId)) {
|
|
906
|
-
return _a.#failure("scheme-not-found", 501, `Scheme '${schemeName}' is not registered.`, {}, { scheme: schemeName, retryable: false });
|
|
907
|
-
}
|
|
908
|
-
const handler = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
909
|
-
if (handler === undefined || manifest?.category !== "data") {
|
|
910
|
-
return _a.#failure("entry-operation-unsupported", 400, `KILL requires an entry-bearing target; '${schemeName}' does not provide one.`, {}, { scheme: schemeName, retryable: false });
|
|
911
|
-
}
|
|
912
|
-
const resolved = await this.#resolveDataEntryAddress({
|
|
913
|
-
target: path,
|
|
914
|
-
routedScheme: schemeName,
|
|
915
|
-
handler,
|
|
916
|
-
manifest,
|
|
917
|
-
ctx,
|
|
918
|
-
});
|
|
919
|
-
if (resolved.result !== null)
|
|
920
|
-
return resolved.result;
|
|
921
|
-
if (resolved.address === null) {
|
|
922
|
-
return _a.#failure("entry-not-found", 404, "The KILL target does not exist.");
|
|
923
|
-
}
|
|
924
|
-
// A host-effecting delete (file) returns 202 to PROPOSE — pass its attrs through so the proposal
|
|
925
|
-
// carries the delete target to review (#isProposal fires on 202). Plurnk-internal deletes execute inline.
|
|
926
|
-
return this.#deleteEntry(schemeName, resolved.address, ctx);
|
|
927
|
-
}
|
|
928
751
|
async #writeActionlessEntry({ verbatim, workerId, loopId, turnId, sequence, origin, kind, folded, modelCallId = null, attrs = {} }) {
|
|
929
752
|
const durableAttrs = { ...attrs, kind };
|
|
930
753
|
const rx = JSON.stringify({ content: verbatim, mimetype: "text/vnd.plurnk" });
|
|
@@ -987,9 +810,8 @@ class Dispatcher {
|
|
|
987
810
|
// {§bare-inference} Provider work is prepared concurrently by Engine; the
|
|
988
811
|
// dispatcher owns only the ordinary operation-result commit and notification.
|
|
989
812
|
async recordBareResult(context, result, modelCallId) {
|
|
990
|
-
assertClassifyingSignal(context.statement);
|
|
991
813
|
Results.assert(result);
|
|
992
|
-
const logEntryId = await this.#writeLog({
|
|
814
|
+
const logEntryId = await this.#logWriter.writeLog({
|
|
993
815
|
...context,
|
|
994
816
|
functionalityWorkerId: context.functionalityWorkerId ?? context.workerId,
|
|
995
817
|
result,
|
|
@@ -1009,8 +831,10 @@ class Dispatcher {
|
|
|
1009
831
|
// BY STATED INTENT and is never gated.
|
|
1010
832
|
async #pendingSet(workerId, turnId) {
|
|
1011
833
|
const pending = [];
|
|
1012
|
-
const openSubs = await this.#db.find_open_subscriptions_for_worker.all({ worker_id: workerId });
|
|
1013
834
|
const execHandler = this.#schemes.get("exec");
|
|
835
|
+
// {§exec-timeout} — a `<-1>` spawn outlives the loop and is nobody's obligation.
|
|
836
|
+
const openSubs = (await this.#db.find_open_subscriptions_for_worker.all({ worker_id: workerId }))
|
|
837
|
+
.filter(({ id }) => execHandler?.isDetachedSpawn?.(id) !== true);
|
|
1014
838
|
if (openSubs.length > 0 || execHandler?.hasActiveSpawns?.(workerId) === true)
|
|
1015
839
|
pending.push("streams");
|
|
1016
840
|
const liveChild = await this.#db.engine_worker_has_live_child.get({ worker_id: workerId });
|
|
@@ -1042,8 +866,10 @@ class Dispatcher {
|
|
|
1042
866
|
.get({ worker_id: workerId }),
|
|
1043
867
|
]);
|
|
1044
868
|
return {
|
|
1045
|
-
|
|
1046
|
-
|
|
869
|
+
// {§log-kill-scope} — a log KILL is housekeeping: it continues an empty (WAIT) but never
|
|
870
|
+
// blocks an explicit (TERM); every other boundary row is a retrieval receipt.
|
|
871
|
+
retrievals: turnBoundaries.some(({ op }) => op !== "KILL"),
|
|
872
|
+
folds: turnBoundaries.some(({ op }) => op === "KILL"),
|
|
1047
873
|
streamTerminations,
|
|
1048
874
|
childTerminations: childTermination !== undefined,
|
|
1049
875
|
};
|
|
@@ -1066,374 +892,17 @@ class Dispatcher {
|
|
|
1066
892
|
// J — a live obligation to WAIT on: a spawned child or an open stream (NOT retrievals, which land
|
|
1067
893
|
// next turn regardless). The wait-side twin of #pendingSet's stream+child legs ({§wait-obligation-matrix}).
|
|
1068
894
|
async hasLiveWork(workerId) {
|
|
1069
|
-
const
|
|
895
|
+
const execHandler = this.#schemes.get("exec");
|
|
896
|
+
// {§exec-timeout} — a `<-1>` spawn outlives the loop and is nobody's obligation.
|
|
897
|
+
const openSubs = (await this.#db.find_open_subscriptions_for_worker.all({ worker_id: workerId }))
|
|
898
|
+
.filter(({ id }) => execHandler?.isDetachedSpawn?.(id) !== true);
|
|
1070
899
|
if (openSubs.length > 0)
|
|
1071
900
|
return true;
|
|
1072
|
-
const execHandler = this.#schemes.get("exec");
|
|
1073
901
|
if (execHandler?.hasActiveSpawns?.(workerId) === true)
|
|
1074
902
|
return true;
|
|
1075
903
|
const liveChild = await this.#db.engine_worker_has_live_child.get({ worker_id: workerId });
|
|
1076
904
|
return liveChild !== undefined;
|
|
1077
905
|
}
|
|
1078
|
-
async #handleSendBroadcast(statement, ctx) {
|
|
1079
|
-
if (statement.op !== "SEND")
|
|
1080
|
-
throw new Error("unreachable");
|
|
1081
|
-
const { workerId, loopId, turnId } = ctx;
|
|
1082
|
-
const status = statement.signal;
|
|
1083
|
-
if (status === null) {
|
|
1084
|
-
return _a.#failure("send-status-required", 400, "SEND requires a numeric status.", {}, { retryable: false });
|
|
1085
|
-
}
|
|
1086
|
-
const raw = statement.body === null ? "" : statement.body.raw;
|
|
1087
|
-
// The park rides SEND signal 202 only ({§park-202-only}). A scoped signal 102 is neither
|
|
1088
|
-
// a wait nor a meaningful continuation, so reject it instead of preserving the
|
|
1089
|
-
// retired dual spelling.
|
|
1090
|
-
if (status === 102 && statement.lineMarker !== null) {
|
|
1091
|
-
return _a.#failure("send-scope-invalid", 400, "`## SEND0 [102]` does not accept a scope.", {}, {
|
|
1092
|
-
requestedStatus: 102,
|
|
1093
|
-
scope: statement.lineMarker,
|
|
1094
|
-
recovery: "Use `## SEND0 [202] <scope>` to wait, or remove the scope to continue.",
|
|
1095
|
-
retryable: false,
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
// A bare continue after an armed running-worker READ becomes an
|
|
1099
|
-
// indefinite park. {§join-blocking-collect}
|
|
1100
|
-
const joinArmed = this.#joinTargets.delete(loopId);
|
|
1101
|
-
if (status === 102 && statement.lineMarker === null && joinArmed) {
|
|
1102
|
-
if (!await this.#lifecycle.park(loopId)) {
|
|
1103
|
-
return _a.#statusResult(await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to park it.");
|
|
1104
|
-
}
|
|
1105
|
-
this.#parkDeadlines.set(loopId, -1); // indefinite: the bounded child's terminal is the wake edge
|
|
1106
|
-
return { status: 102, attrs: { parked: -1, join: true } };
|
|
1107
|
-
}
|
|
1108
|
-
// {§wait-obligation-matrix} — SEND signal 202 is the obligation-checked join. A live
|
|
1109
|
-
// obligation (a spawned child or open stream, J) BLOCKS the loop until it concludes and
|
|
1110
|
-
// reawakens it ({§worker-lifecycle-child-wake}); a wait on nothing (∅) is already satisfied and
|
|
1111
|
-
// resolves like 200, so <-1>+∅ self-resolves rather than hang the agent; a pending own
|
|
1112
|
-
// retrieval (R) just lands next turn, so the wait continues.
|
|
1113
|
-
if (status === 202) {
|
|
1114
|
-
const marks = statement.lineMarker?.marks[0];
|
|
1115
|
-
// `<T>` is MINUTES, held in seconds; bare 202 / absent T = indefinite, bounded by the join.
|
|
1116
|
-
const seconds = typeof marks === "number" ? (marks > 0 ? marks * 60 : marks) : -1;
|
|
1117
|
-
if (await this.hasLiveWork(workerId)) {
|
|
1118
|
-
if (!await this.#lifecycle.park(loopId)) {
|
|
1119
|
-
return _a.#statusResult(await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to wait.");
|
|
1120
|
-
}
|
|
1121
|
-
this.#parkDeadlines.set(loopId, seconds);
|
|
1122
|
-
return { status: 202, attrs: { waiting: seconds } };
|
|
1123
|
-
}
|
|
1124
|
-
// Retrievals, fast stream conclusions, and child conclusions are
|
|
1125
|
-
// all complete-but-unobserved. Their wake edge may already have
|
|
1126
|
-
// fired, so do not park; continue directly to the packet that
|
|
1127
|
-
// materializes them.
|
|
1128
|
-
const boundaries = await this.#nextPacketBoundaries(workerId, turnId);
|
|
1129
|
-
if (boundaries.retrievals || boundaries.folds || boundaries.streamTerminations.length > 0 || boundaries.childTerminations) {
|
|
1130
|
-
return { status: 102 };
|
|
1131
|
-
}
|
|
1132
|
-
const failCount = await this.#unobservedFailureCount(turnId);
|
|
1133
|
-
if (failCount > 0)
|
|
1134
|
-
return _a.#unobservedFailures(failCount);
|
|
1135
|
-
// The joined set is already drained. Awaiting an empty task group completes
|
|
1136
|
-
// immediately; it never parks and needs no corrective model turn.
|
|
1137
|
-
const finished = await this.#lifecycle.finish(loopId, TerminalResult.success(raw));
|
|
1138
|
-
return {
|
|
1139
|
-
status: finished !== null ? 200 : await this.#lifecycle.status(loopId),
|
|
1140
|
-
attrs: { joined: true, pending: 0 },
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
// [200] — terminate, gated by the pending set (post-batch). The row records the refused
|
|
1144
|
-
// attempt faithfully (status_rx=409, never erased); the loop stays a continue; the strike
|
|
1145
|
-
// couples in runTurn. [499] abandons and cancels the descendant scope.
|
|
1146
|
-
if (status === 200) {
|
|
1147
|
-
// Model completion is a claim about the Worker's observed work and
|
|
1148
|
-
// therefore crosses the pending-result rails. A `_plurnk`
|
|
1149
|
-
// maintenance program closes only its own administrative loop; it
|
|
1150
|
-
// must not claim, consume, or be blocked by model work elsewhere in
|
|
1151
|
-
// the same Worker.
|
|
1152
|
-
if (ctx.origin === "model") {
|
|
1153
|
-
// {§send-premature-terminate} — same-turn failures are unobserved
|
|
1154
|
-
// pending results and therefore refuse completion.
|
|
1155
|
-
const failCount = await this.#unobservedFailureCount(turnId);
|
|
1156
|
-
if (failCount > 0)
|
|
1157
|
-
return _a.#unobservedFailures(failCount);
|
|
1158
|
-
const pending = await this.#pendingSet(workerId, turnId);
|
|
1159
|
-
if (pending.length > 0) {
|
|
1160
|
-
// A receipts-only refusal needs no KILL/park remedy menu: the results simply
|
|
1161
|
-
// arrive in the next packet. Streams and children retain their remedy steer.
|
|
1162
|
-
const receiptsOnly = pending.every((kind) => kind === "receipts");
|
|
1163
|
-
if (receiptsOnly) {
|
|
1164
|
-
return _a.#failure("retrieval-results-unobserved", 409, "Completion preceded this turn's operation results; they enter the next packet.", {}, {
|
|
1165
|
-
pending: [...pending],
|
|
1166
|
-
stage: "completion",
|
|
1167
|
-
retryable: false,
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1170
|
-
return _a.#failure("work-remains", 409, "Completion encountered pending work or results.", {}, {
|
|
1171
|
-
pending: [...pending],
|
|
1172
|
-
stage: "completion",
|
|
1173
|
-
retryable: false,
|
|
1174
|
-
});
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
const finished = await this.#lifecycle.finish(loopId, TerminalResult.success(raw));
|
|
1178
|
-
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.");
|
|
1179
|
-
}
|
|
1180
|
-
if (status === 499) {
|
|
1181
|
-
const reason = raw === "" ? null : ErrorDetail.preview(raw);
|
|
1182
|
-
const failure = _a.#failure("scope-abandoned", 499, "The worker ended its scope with SEND[499].", {}, {
|
|
1183
|
-
...(reason === null ? {} : { reason }),
|
|
1184
|
-
retryable: false,
|
|
1185
|
-
});
|
|
1186
|
-
const seqs = await this.#db.engine_loop_turn_seqs.get({
|
|
1187
|
-
loop_id: loopId,
|
|
1188
|
-
turn_id: turnId,
|
|
1189
|
-
});
|
|
1190
|
-
if (seqs === undefined) {
|
|
1191
|
-
throw new Error(`SEND signal 499: no coordinate for loop=${loopId} turn=${turnId}`);
|
|
1192
|
-
}
|
|
1193
|
-
Results.attachInstance(failure, `log:///${seqs.loop_seq}/${seqs.turn_seq}/${ctx.sequence}/SEND`);
|
|
1194
|
-
const finished = await this.#lifecycle.finish(loopId, failure);
|
|
1195
|
-
if (finished === null)
|
|
1196
|
-
return _a.#statusResult(await this.#lifecycle.status(loopId), "loop-already-terminal", "The loop was already terminal when SEND attempted to abandon it.");
|
|
1197
|
-
await this.#cancelDescendants?.(workerId, reason ?? "parent worker ended its scope with SEND[499]");
|
|
1198
|
-
return failure;
|
|
1199
|
-
}
|
|
1200
|
-
// Every other signal — 102 bare, 202 (retired as a terminal; now ordinary mid-comms), 1xx —
|
|
1201
|
-
// is a plain broadcast row: no loop transition.
|
|
1202
|
-
return _a.#statusResult(status, "send-broadcast-failed", raw === "" ? `SEND broadcast reported status ${status}.` : raw);
|
|
1203
|
-
}
|
|
1204
|
-
async #run(schemeName, statement, ctx) {
|
|
1205
|
-
if (schemeName === null) {
|
|
1206
|
-
const fields = statement.op === "READ"
|
|
1207
|
-
? { content: null, mimetype: null, channel: null }
|
|
1208
|
-
: statement.op === "FIND"
|
|
1209
|
-
? {
|
|
1210
|
-
content: null,
|
|
1211
|
-
mimetype: null,
|
|
1212
|
-
results: [],
|
|
1213
|
-
itemsWeightTotal: 0,
|
|
1214
|
-
returnedItemsWeightTotal: 0,
|
|
1215
|
-
matchingPathCount: 0,
|
|
1216
|
-
matchLocationCount: 0,
|
|
1217
|
-
}
|
|
1218
|
-
: {};
|
|
1219
|
-
return _a.#failure("target-scheme-required", 400, `${statement.op} requires a target scheme.`, fields, { operation: statement.op, retryable: false });
|
|
1220
|
-
}
|
|
1221
|
-
const manifest = this.#schemes.manifestFor(schemeName, ctx.functionalityWorkerId);
|
|
1222
|
-
const handler = this.#schemes.get(schemeName, ctx.functionalityWorkerId);
|
|
1223
|
-
if (handler === undefined) {
|
|
1224
|
-
return _a.#failure("scheme-not-found", 501, `Scheme '${schemeName}' is not registered.`, {}, { scheme: schemeName, retryable: false });
|
|
1225
|
-
}
|
|
1226
|
-
const methodName = statement.op.toLowerCase();
|
|
1227
|
-
const method = handler[methodName];
|
|
1228
|
-
const addressedScheme = statement.target?.kind === "url" ? statement.target.scheme : null;
|
|
1229
|
-
if (manifest === undefined)
|
|
1230
|
-
throw new Error(`scheme '${schemeName}' has no manifest`);
|
|
1231
|
-
// Metadata belongs to the handler that receives it. EXEC over a
|
|
1232
|
-
// non-file resource is the one split route: exec hosts the operation,
|
|
1233
|
-
// while the canonically routed source scheme receives the metadata.
|
|
1234
|
-
const metadataScheme = schemeName === "exec"
|
|
1235
|
-
&& statement.target?.kind === "url"
|
|
1236
|
-
&& statement.target.scheme !== "file"
|
|
1237
|
-
? schemeNameOf(statement.target) ?? schemeName
|
|
1238
|
-
: schemeName;
|
|
1239
|
-
const metadataManifest = metadataScheme === schemeName
|
|
1240
|
-
? manifest
|
|
1241
|
-
: this.#schemes.manifestFor(metadataScheme, ctx.functionalityWorkerId);
|
|
1242
|
-
if (statement.metadata !== null && metadataManifest === undefined) {
|
|
1243
|
-
return _a.#failure("scheme-not-found", 501, `Scheme '${metadataScheme}' is not registered.`, {}, { scheme: metadataScheme, retryable: false });
|
|
1244
|
-
}
|
|
1245
|
-
if (statement.metadata !== null && metadataManifest?.metadataModifier !== true) {
|
|
1246
|
-
return _a.#failure("scheme-metadata-unsupported", 400, `Scheme '${metadataScheme}' does not accept the {metadata} modifier.`, {}, {
|
|
1247
|
-
scheme: metadataScheme,
|
|
1248
|
-
operation: statement.op,
|
|
1249
|
-
retryable: false,
|
|
1250
|
-
});
|
|
1251
|
-
}
|
|
1252
|
-
const publishedChannel = statement.target?.kind === "url"
|
|
1253
|
-
? statement.target.fragment ?? manifest.defaultChannel
|
|
1254
|
-
: manifest.defaultChannel;
|
|
1255
|
-
const authoredCoordinate = statement.target === null
|
|
1256
|
-
? { authority: "", pathname: "" }
|
|
1257
|
-
: entryCoordinateOf(statement.target, manifest.authority ?? "namespace");
|
|
1258
|
-
// EXEC's authored target belongs to its declared invocation contract;
|
|
1259
|
-
// a resource target is input to the executor, never the output-stream
|
|
1260
|
-
// address owned by the internal exec scheme. {§exec-target-routing}
|
|
1261
|
-
const addressResolution = manifest.category === "data"
|
|
1262
|
-
&& statement.target !== null
|
|
1263
|
-
&& statement.op !== "EXEC"
|
|
1264
|
-
? await this.#resolveDataEntryAddress({
|
|
1265
|
-
target: statement.target,
|
|
1266
|
-
routedScheme: schemeName,
|
|
1267
|
-
handler: handler,
|
|
1268
|
-
manifest,
|
|
1269
|
-
ctx,
|
|
1270
|
-
})
|
|
1271
|
-
: null;
|
|
1272
|
-
if (addressResolution?.result !== null && addressResolution?.result !== undefined) {
|
|
1273
|
-
return addressResolution.result;
|
|
1274
|
-
}
|
|
1275
|
-
const operationAddress = addressResolution?.address ?? null;
|
|
1276
|
-
const schemeCtx = new SchemeCtxImpl(ctx, addressedScheme ?? schemeName, manifest, this.#liveSubscriptions, {
|
|
1277
|
-
authority: operationAddress?.authority ?? authoredCoordinate.authority,
|
|
1278
|
-
ownerId: operationAddress?.ownerId ?? await this.#fixedEntryOwnerId(manifest, ctx),
|
|
1279
|
-
publishedChannel,
|
|
1280
|
-
});
|
|
1281
|
-
if (statement.op === "SEND"
|
|
1282
|
-
&& statement.signal === 499
|
|
1283
|
-
&& statement.target?.kind === "url"
|
|
1284
|
-
&& operationAddress !== null) {
|
|
1285
|
-
const addressedScheme = statement.target.scheme;
|
|
1286
|
-
const entry = await this.#db.crud_find_workspace_entry.get({
|
|
1287
|
-
workspace_id: ctx.workspaceId,
|
|
1288
|
-
owner_id: operationAddress.ownerId,
|
|
1289
|
-
scheme: operationAddress.scheme,
|
|
1290
|
-
authority: operationAddress.authority,
|
|
1291
|
-
pathname: operationAddress.pathname,
|
|
1292
|
-
});
|
|
1293
|
-
if (entry !== undefined) {
|
|
1294
|
-
const subscription = await ChannelWrite.findActiveSubscription(this.#db, {
|
|
1295
|
-
workerId: ctx.workerId,
|
|
1296
|
-
entryId: entry.id,
|
|
1297
|
-
});
|
|
1298
|
-
if (subscription !== null && subscription.scheme === addressedScheme) {
|
|
1299
|
-
const cancelled = await this.#liveSubscriptions.cancel(subscription.id);
|
|
1300
|
-
if (!cancelled) {
|
|
1301
|
-
throw new InvalidOperationResultError(`Subscription ${subscription.id} is durable but has no live cancellation handle.`);
|
|
1302
|
-
}
|
|
1303
|
-
return { status: 200 };
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
if (statement.op === "READ"
|
|
1308
|
-
&& handler instanceof CoreSchemeAdapterBase
|
|
1309
|
-
&& typeof handler.resolveCoreRepresentation === "function") {
|
|
1310
|
-
const selectionNeutralTarget = statement.target?.kind === "url"
|
|
1311
|
-
? {
|
|
1312
|
-
...statement.target,
|
|
1313
|
-
raw: renderTarget({ ...statement.target, fragment: null }) ?? statement.target.raw,
|
|
1314
|
-
fragment: null,
|
|
1315
|
-
}
|
|
1316
|
-
: statement.target;
|
|
1317
|
-
const resolved = await handler
|
|
1318
|
-
.resolveCoreRepresentation(selectionNeutralTarget, schemeCtx);
|
|
1319
|
-
if ("result" in resolved)
|
|
1320
|
-
return Results.assertReadResult(resolved.result);
|
|
1321
|
-
if (selectionNeutralTarget === null) {
|
|
1322
|
-
throw new InvalidOperationResultError(`Core scheme '${schemeName}' resolved a targetless READ representation.`);
|
|
1323
|
-
}
|
|
1324
|
-
const target = renderTarget(selectionNeutralTarget.kind === "url"
|
|
1325
|
-
? selectionNeutralTarget
|
|
1326
|
-
: { scheme: null, pathname: selectionNeutralTarget.raw });
|
|
1327
|
-
if (target === null) {
|
|
1328
|
-
throw new TypeError(`Core scheme '${schemeName}' resolved an unrenderable READ target.`);
|
|
1329
|
-
}
|
|
1330
|
-
return Results.assertReadResult(await ReadProjector.project({
|
|
1331
|
-
statement,
|
|
1332
|
-
manifest,
|
|
1333
|
-
target,
|
|
1334
|
-
identity: target,
|
|
1335
|
-
representation: resolved.representation,
|
|
1336
|
-
mimetypes: ctx.mimetypes,
|
|
1337
|
-
}));
|
|
1338
|
-
}
|
|
1339
|
-
if (statement.op === "READ" && manifest.category === "data") {
|
|
1340
|
-
const prepared = statement.target === null
|
|
1341
|
-
? { address: null, result: null }
|
|
1342
|
-
: await this.#prepareDataRepresentation({
|
|
1343
|
-
target: statement.target,
|
|
1344
|
-
metadata: statement.metadata,
|
|
1345
|
-
routedScheme: schemeName,
|
|
1346
|
-
handler: handler,
|
|
1347
|
-
manifest,
|
|
1348
|
-
ctx,
|
|
1349
|
-
publishedChannel,
|
|
1350
|
-
...(addressResolution === null ? {} : { resolved: addressResolution }),
|
|
1351
|
-
});
|
|
1352
|
-
if (prepared.result !== null)
|
|
1353
|
-
return prepared.result;
|
|
1354
|
-
const resolved = prepared.address;
|
|
1355
|
-
if (statement.target !== null && resolved === null) {
|
|
1356
|
-
const target = renderTarget(statement.target.kind === "url"
|
|
1357
|
-
? statement.target
|
|
1358
|
-
: { scheme: null, pathname: statement.target.raw });
|
|
1359
|
-
return Results.failure(`scheme:${schemeName}`, "entry-not-found", 404, `No entry exists at ${target ?? "the requested address"}.`, { content: null, mimetype: null, channel: null }, { target });
|
|
1360
|
-
}
|
|
1361
|
-
const storageScheme = resolved?.scheme ?? manifest.storedScheme ?? addressedScheme ?? schemeName;
|
|
1362
|
-
const projected = Results.assertReadResult(await EntryOps.readWorkspaceEntry(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, resolved === null
|
|
1363
|
-
? null
|
|
1364
|
-
: {
|
|
1365
|
-
ownerId: resolved.ownerId,
|
|
1366
|
-
authority: resolved.authority,
|
|
1367
|
-
pathname: resolved.pathname,
|
|
1368
|
-
}));
|
|
1369
|
-
return projected;
|
|
1370
|
-
}
|
|
1371
|
-
if (statement.op !== "FIND" || manifest.category !== "data") {
|
|
1372
|
-
if (typeof method === "function") {
|
|
1373
|
-
return Results.assert(await method.call(handler, statement, schemeCtx));
|
|
1374
|
-
}
|
|
1375
|
-
return _a.#failure("operation-not-implemented", 501, `Scheme '${schemeName}' does not implement ${statement.op}.`, {}, {
|
|
1376
|
-
scheme: schemeName,
|
|
1377
|
-
operation: statement.op,
|
|
1378
|
-
retryable: false,
|
|
1379
|
-
});
|
|
1380
|
-
}
|
|
1381
|
-
const targetPathname = statement.target?.kind === "url"
|
|
1382
|
-
? statement.target.pathname
|
|
1383
|
-
: statement.target?.raw ?? "";
|
|
1384
|
-
const collectionTarget = manifest.folderScopes === true
|
|
1385
|
-
&& (targetPathname === "" || targetPathname.endsWith("/"));
|
|
1386
|
-
const exactTarget = statement.target !== null
|
|
1387
|
-
&& !collectionTarget
|
|
1388
|
-
&& !PathSyntax.hasGlob(authoredCoordinate.pathname);
|
|
1389
|
-
if (exactTarget && statement.target !== null) {
|
|
1390
|
-
const prepared = await this.#prepareDataRepresentation({
|
|
1391
|
-
target: statement.target,
|
|
1392
|
-
metadata: statement.metadata,
|
|
1393
|
-
routedScheme: schemeName,
|
|
1394
|
-
handler: handler,
|
|
1395
|
-
manifest,
|
|
1396
|
-
ctx,
|
|
1397
|
-
publishedChannel,
|
|
1398
|
-
...(addressResolution === null ? {} : { resolved: addressResolution }),
|
|
1399
|
-
});
|
|
1400
|
-
if (prepared.result !== null)
|
|
1401
|
-
return prepared.result;
|
|
1402
|
-
if (prepared.address === null) {
|
|
1403
|
-
const target = renderTarget(statement.target.kind === "url"
|
|
1404
|
-
? statement.target
|
|
1405
|
-
: { scheme: null, pathname: statement.target.raw });
|
|
1406
|
-
return Results.failure(`scheme:${schemeName}`, "entry-not-found", 404, `No entry exists at ${target ?? "the requested address"}.`, {
|
|
1407
|
-
content: null,
|
|
1408
|
-
mimetype: null,
|
|
1409
|
-
results: [],
|
|
1410
|
-
itemsWeightTotal: 0,
|
|
1411
|
-
returnedItemsWeightTotal: 0,
|
|
1412
|
-
matchingPathCount: 0,
|
|
1413
|
-
matchLocationCount: 0,
|
|
1414
|
-
}, { target });
|
|
1415
|
-
}
|
|
1416
|
-
const storageScheme = prepared.address.scheme
|
|
1417
|
-
?? manifest.storedScheme
|
|
1418
|
-
?? addressedScheme
|
|
1419
|
-
?? schemeName;
|
|
1420
|
-
return Results.assert(await EntryFind.findWorkspaceEntries(statement, ctx, { ...manifest, name: storageScheme, storedScheme: storageScheme }, {
|
|
1421
|
-
ownerId: prepared.address.ownerId,
|
|
1422
|
-
authority: prepared.address.authority,
|
|
1423
|
-
pathname: prepared.address.pathname,
|
|
1424
|
-
}));
|
|
1425
|
-
}
|
|
1426
|
-
if (typeof method === "function") {
|
|
1427
|
-
return Results.assert(await method.call(handler, statement, schemeCtx));
|
|
1428
|
-
}
|
|
1429
|
-
const prepareFind = handler.prepareFind;
|
|
1430
|
-
if (typeof prepareFind === "function") {
|
|
1431
|
-
const prepared = await prepareFind.call(handler, statement, schemeCtx);
|
|
1432
|
-
if (prepared.status >= 300)
|
|
1433
|
-
return Results.assert(prepared);
|
|
1434
|
-
}
|
|
1435
|
-
return Results.assert(await schemeCtx.entries.operations.find(statement));
|
|
1436
|
-
}
|
|
1437
906
|
async #runLogCuration(statement, ctx) {
|
|
1438
907
|
const addressedScheme = schemeNameOf(statement.target);
|
|
1439
908
|
if (addressedScheme !== null && addressedScheme !== "log") {
|
|
@@ -1462,125 +931,6 @@ class Dispatcher {
|
|
|
1462
931
|
return false;
|
|
1463
932
|
return !(statement.op === "SEND" && statement.target === null);
|
|
1464
933
|
}
|
|
1465
|
-
async #writeLog({ statement, result, workspaceId, workerId, functionalityWorkerId, loopId, turnId, sequence, origin, curationPlan, modelCallId, }) {
|
|
1466
|
-
const durableStatement = DurableStatement.project(statement);
|
|
1467
|
-
const target = this.#extractTarget(primaryTargetOf(durableStatement), functionalityWorkerId);
|
|
1468
|
-
await this.#canonColumns(target, workspaceId); // {§fs-answer-in-canon}
|
|
1469
|
-
const lineMarker = primaryLineMarkerOf(durableStatement);
|
|
1470
|
-
const lineMarkerJson = lineMarker !== null
|
|
1471
|
-
? JSON.stringify(lineMarker)
|
|
1472
|
-
: null;
|
|
1473
|
-
// A proposal (status 202 from a side-effecting op) is written to the log in
|
|
1474
|
-
// state='proposed' until the proposal lifecycle resolves it; attrs holds the
|
|
1475
|
-
// scheme-supplied payload (file diff, exec command, etc.) the client renders
|
|
1476
|
-
// for review and the scheme consumes on accept. A broadcast SEND signal 202 is a
|
|
1477
|
-
// parked-terminal, not a proposal (#isProposal) → state='resolved'.
|
|
1478
|
-
const isProposed = _a.#isProposal(statement, result);
|
|
1479
|
-
let attrsObj = (result.attrs !== undefined && result.attrs !== null)
|
|
1480
|
-
? { ...result.attrs }
|
|
1481
|
-
: {};
|
|
1482
|
-
if (curationPlan !== null) {
|
|
1483
|
-
if (Object.hasOwn(attrsObj, "__plurnk_curation")) {
|
|
1484
|
-
throw new Error("Dispatcher.#writeLog: result attrs collide with private log curation state");
|
|
1485
|
-
}
|
|
1486
|
-
attrsObj.__plurnk_curation = {
|
|
1487
|
-
targets: curationPlan.targets,
|
|
1488
|
-
add: curationPlan.add,
|
|
1489
|
-
remove: curationPlan.remove,
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
const seqs = statement.op === "EXEC" || result.problem !== undefined
|
|
1493
|
-
? await this.#db.engine_loop_turn_seqs.get({
|
|
1494
|
-
loop_id: loopId,
|
|
1495
|
-
turn_id: turnId,
|
|
1496
|
-
})
|
|
1497
|
-
: undefined;
|
|
1498
|
-
if ((statement.op === "EXEC" || result.problem !== undefined) && seqs === undefined) {
|
|
1499
|
-
throw new Error(`Dispatcher.#writeLog: loop_turn_seqs returned no row for loop=${loopId} turn=${turnId}`);
|
|
1500
|
-
}
|
|
1501
|
-
if (statement.op === "READ")
|
|
1502
|
-
Results.assertReadResult(result);
|
|
1503
|
-
if (result.problem !== undefined && seqs !== undefined) {
|
|
1504
|
-
Results.attachInstance(result, `log:///${seqs.loop_seq}/${seqs.turn_seq}/${sequence}/${statement.op}`);
|
|
1505
|
-
}
|
|
1506
|
-
else {
|
|
1507
|
-
Results.assert(result);
|
|
1508
|
-
}
|
|
1509
|
-
// EXEC produces a stream entry addressed by RUNTIME TAG as authority ({§exec}): it lives
|
|
1510
|
-
// at <runtime>:///<loop_seq>/<turn_seq>/<sequence> (e.g. sh:///1/1/2). That address is a
|
|
1511
|
-
// SEPARATE `stream` link in attrs — NOT an overload of `target`, which stays faithful to
|
|
1512
|
-
// the EXEC's own slot (the cwd, or the path to the executable). The log:/// coordinate
|
|
1513
|
-
// shares the trailing <loop>/<turn>/<seq>, so the op still correlates to its stream.
|
|
1514
|
-
// Runtime comes from statement.signal (EXEC's runtime slot), resolvable for failed execs
|
|
1515
|
-
// too; empty/absent = the default shell.
|
|
1516
|
-
if (statement.op === "EXEC") {
|
|
1517
|
-
if (seqs === undefined)
|
|
1518
|
-
throw new Error("Dispatcher.#writeLog: EXEC coordinate was not resolved");
|
|
1519
|
-
const runtime = (typeof statement.signal === "string" && statement.signal.length > 0) ? statement.signal : "sh";
|
|
1520
|
-
const coordPathname = `/${seqs.loop_seq}/${seqs.turn_seq}/${sequence}`;
|
|
1521
|
-
attrsObj.pathname = coordPathname;
|
|
1522
|
-
attrsObj.stream = `${runtime}://${coordPathname}`;
|
|
1523
|
-
// Mutate the in-memory result.attrs too: the dispatch path
|
|
1524
|
-
// hands originalResult.attrs to handler.applyResolution after
|
|
1525
|
-
// proposal accept (see ProposalLifecycle.workerApply). Both views —
|
|
1526
|
-
// the stored row AND the in-memory proposal — need the same
|
|
1527
|
-
// pathname so applyResolution writes the entry at the same URI.
|
|
1528
|
-
if (result.attrs !== undefined && result.attrs !== null) {
|
|
1529
|
-
result.attrs.pathname = coordPathname;
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
const attrs = JSON.stringify(attrsObj);
|
|
1533
|
-
const txJson = JSON.stringify(durableStatement);
|
|
1534
|
-
const rxJson = JSON.stringify(result);
|
|
1535
|
-
const row = await this.#db.engine_insert_log_entry.get({
|
|
1536
|
-
worker_id: workerId,
|
|
1537
|
-
loop_id: loopId,
|
|
1538
|
-
turn_id: turnId,
|
|
1539
|
-
sequence: sequence,
|
|
1540
|
-
origin,
|
|
1541
|
-
source: null, // dispatch entries are self-authored; {§env-delta} deltas set this
|
|
1542
|
-
model_call_id: modelCallId,
|
|
1543
|
-
op: durableStatement.op,
|
|
1544
|
-
delimiter: durableStatement.delimiter,
|
|
1545
|
-
signal: this.#signalToJson(durableStatement.signal),
|
|
1546
|
-
scheme: target.scheme,
|
|
1547
|
-
username: target.username,
|
|
1548
|
-
password: target.password,
|
|
1549
|
-
hostname: target.hostname,
|
|
1550
|
-
port: target.port,
|
|
1551
|
-
pathname: target.pathname,
|
|
1552
|
-
query: target.query,
|
|
1553
|
-
fragment: target.fragment,
|
|
1554
|
-
lineMarker: lineMarkerJson,
|
|
1555
|
-
tx: txJson,
|
|
1556
|
-
mimetype_tx: "application/json",
|
|
1557
|
-
rx: rxJson,
|
|
1558
|
-
mimetype_rx: "application/json",
|
|
1559
|
-
status_rx: result.status,
|
|
1560
|
-
weight: LogBody.weight({
|
|
1561
|
-
op: durableStatement.op,
|
|
1562
|
-
attrs,
|
|
1563
|
-
tx: txJson,
|
|
1564
|
-
rx: rxJson,
|
|
1565
|
-
mimetypeTx: "application/json",
|
|
1566
|
-
mimetypeRx: "application/json",
|
|
1567
|
-
}, this.#weighContent),
|
|
1568
|
-
state: isProposed ? "proposed" : "resolved",
|
|
1569
|
-
outcome: null,
|
|
1570
|
-
attrs,
|
|
1571
|
-
initial_folded: LogVisibility.serialize(LogVisibility.OPEN),
|
|
1572
|
-
});
|
|
1573
|
-
// {§exec-tag-signal} — an EXEC row's signal is its runtime; its tag signal classifies
|
|
1574
|
-
// through the same idempotent primitive the log-write trigger uses for tag operations.
|
|
1575
|
-
if (row !== undefined && statement.op === "EXEC" && statement.tags !== undefined && statement.tags !== null) {
|
|
1576
|
-
for (const tag of TagSignal.applied(statement.tags).add) {
|
|
1577
|
-
await this.#db.log_write_tag.run({ log_entry_id: row.id, tag });
|
|
1578
|
-
}
|
|
1579
|
-
}
|
|
1580
|
-
if (row === undefined)
|
|
1581
|
-
throw new Error("Dispatcher.#writeLog: INSERT ... RETURNING produced no row");
|
|
1582
|
-
return row.id;
|
|
1583
|
-
}
|
|
1584
934
|
// Normalize a parsed target for log storage. Bare paths and `file:///...`
|
|
1585
935
|
// inputs collapse to scheme=null in log target metadata because both render
|
|
1586
936
|
// as bare paths. Addressable file entries separately persist under the
|