@plurnk/plurnk-service 2.0.0 → 3.1.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 +27 -19
- package/INSTALL.md +21 -2
- package/README.md +4 -2
- package/SPEC.md +644 -467
- package/dist/build-info.json +1 -1
- package/dist/completions/_plurnk-service +13 -0
- package/dist/completions/plurnk-service.bash +19 -0
- package/dist/completions/plurnk-service.fish +93 -0
- package/dist/content/edit-receipt.d.ts +1 -1
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +1 -1
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +3 -12
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/AdministrativeLoop.d.ts +1 -1
- package/dist/core/AdministrativeLoop.d.ts.map +1 -1
- package/dist/core/AdministrativeLoop.js +2 -6
- package/dist/core/AdministrativeLoop.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +2 -2
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +16 -24
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +8 -2
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +48 -5
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +2 -4
- package/dist/core/CapabilityPolicies.d.ts.map +1 -1
- package/dist/core/CapabilityPolicies.js +3 -23
- package/dist/core/CapabilityPolicies.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +9 -2
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +34 -5
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +0 -2
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ClientInteractions.d.ts +3 -2
- package/dist/core/ClientInteractions.d.ts.map +1 -1
- package/dist/core/ClientInteractions.js +21 -12
- package/dist/core/ClientInteractions.js.map +1 -1
- package/dist/core/ClientInteractions.sql +8 -2
- package/dist/core/CoreSchemeServices.d.ts +1 -0
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +1 -0
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/DataStatementRunner.js +1 -1
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +3 -2
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +55 -52
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +4 -6
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/EnvFlags.d.ts.map +1 -1
- package/dist/core/EnvFlags.js +5 -4
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/FabricatedLog.d.ts +1 -0
- package/dist/core/FabricatedLog.d.ts.map +1 -1
- package/dist/core/FabricatedLog.js +9 -1
- package/dist/core/FabricatedLog.js.map +1 -1
- package/dist/core/HostPaths.d.ts +0 -1
- package/dist/core/HostPaths.d.ts.map +1 -1
- package/dist/core/HostPaths.js +0 -2
- package/dist/core/HostPaths.js.map +1 -1
- package/dist/core/KillHandler.d.ts.map +1 -1
- package/dist/core/KillHandler.js +3 -1
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/LiveSubscription.d.ts.map +1 -1
- package/dist/core/LiveSubscription.js +14 -2
- package/dist/core/LiveSubscription.js.map +1 -1
- package/dist/core/LiveSubscriptions.d.ts +3 -1
- package/dist/core/LiveSubscriptions.d.ts.map +1 -1
- package/dist/core/LiveSubscriptions.js +16 -1
- package/dist/core/LiveSubscriptions.js.map +1 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +3 -1
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +8 -17
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LoopDriver.js +7 -6
- package/dist/core/LoopDriver.js.map +1 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +4 -9
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +7 -6
- package/dist/core/MessageResources.sql +31 -0
- package/dist/core/OperatorConfig.d.ts +1 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -1
- package/dist/core/OperatorConfig.js +10 -2
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +5 -7
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +160 -158
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +20 -6
- package/dist/core/ProposalLifecycle.d.ts +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +18 -20
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProposalPolicies.d.ts +6 -0
- package/dist/core/ProposalPolicies.d.ts.map +1 -0
- package/dist/core/ProposalPolicies.js +28 -0
- package/dist/core/ProposalPolicies.js.map +1 -0
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +3 -4
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ReplyMetadata.d.ts +10 -0
- package/dist/core/ReplyMetadata.d.ts.map +1 -0
- package/dist/core/ReplyMetadata.js +20 -0
- package/dist/core/ReplyMetadata.js.map +1 -0
- package/dist/core/ResourceSelector.js +2 -2
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.js +3 -3
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/RuntimeWorker.sql +1 -2
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +4 -5
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ServiceHelp.d.ts +6 -0
- package/dist/core/ServiceHelp.d.ts.map +1 -0
- package/dist/core/ServiceHelp.js +35 -0
- package/dist/core/ServiceHelp.js.map +1 -0
- package/dist/core/StoredPacket.d.ts +1 -0
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +4 -1
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +2 -2
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TokenCalibration.d.ts +2 -2
- package/dist/core/TokenCalibration.d.ts.map +1 -1
- package/dist/core/TokenCalibration.js +12 -16
- package/dist/core/TokenCalibration.js.map +1 -1
- package/dist/core/TokenCalibration.sql +29 -6
- package/dist/core/ToolInputSchema.d.ts +1 -0
- package/dist/core/ToolInputSchema.d.ts.map +1 -1
- package/dist/core/ToolInputSchema.js +8 -2
- package/dist/core/ToolInputSchema.js.map +1 -1
- package/dist/core/ToolResources.d.ts +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +7 -1
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/TurnDispositionHandler.d.ts +1 -2
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
- package/dist/core/TurnDispositionHandler.js +31 -33
- package/dist/core/TurnDispositionHandler.js.map +1 -1
- package/dist/core/TurnMaterialization.d.ts.map +1 -1
- package/dist/core/TurnMaterialization.js +12 -2
- package/dist/core/TurnMaterialization.js.map +1 -1
- package/dist/core/TurnOps.d.ts +5 -1
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +29 -2
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +184 -103
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/TurnSources.sql +2 -2
- package/dist/core/WorkerControlHandler.d.ts.map +1 -1
- package/dist/core/WorkerControlHandler.js +1 -8
- package/dist/core/WorkerControlHandler.js.map +1 -1
- package/dist/core/WorkerName.d.ts +1 -0
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +2 -0
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +2 -2
- package/dist/core/WorkerOwners.d.ts +13 -0
- package/dist/core/WorkerOwners.d.ts.map +1 -0
- package/dist/core/WorkerOwners.js +44 -0
- package/dist/core/WorkerOwners.js.map +1 -0
- package/dist/core/WorkerOwners.sql +55 -0
- package/dist/core/env-catalog.d.ts +3 -0
- package/dist/core/env-catalog.d.ts.map +1 -1
- package/dist/core/env-catalog.js +44 -9
- package/dist/core/env-catalog.js.map +1 -1
- package/dist/core/fork.sql +3 -4
- package/dist/core/packet-inject.js +0 -2
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +9 -11
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +103 -126
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +4 -4
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/recap-lines.d.ts +4 -0
- package/dist/core/recap-lines.d.ts.map +1 -0
- package/dist/core/recap-lines.js +11 -0
- package/dist/core/recap-lines.js.map +1 -0
- package/dist/core/scheme-types.d.ts +2 -1
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/sql-functions.d.ts +2 -0
- package/dist/core/sql-functions.d.ts.map +1 -0
- package/dist/core/sql-functions.js +5 -0
- package/dist/core/sql-functions.js.map +1 -0
- package/dist/core/turn-scheduler.d.ts.map +1 -1
- package/dist/core/turn-scheduler.js +1 -1
- package/dist/core/turn-scheduler.js.map +1 -1
- package/dist/core/types.d.ts +0 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.d.ts +1 -3
- package/dist/core/unregistered-scheme.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.js +3 -11
- package/dist/core/unregistered-scheme.js.map +1 -1
- package/dist/evidence/EvidenceReader.d.ts.map +1 -1
- package/dist/evidence/EvidenceReader.js +18 -2
- package/dist/evidence/EvidenceReader.js.map +1 -1
- package/dist/evidence/digest.sql +2 -2
- package/dist/man/plurnk-service.1 +488 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +1 -10
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Env.d.ts +26 -0
- package/dist/schemes/Env.d.ts.map +1 -0
- package/dist/schemes/Env.js +133 -0
- package/dist/schemes/Env.js.map +1 -0
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +30 -37
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +3 -2
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +9 -0
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +10 -16
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +33 -10
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +9 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +1 -3
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +6 -8
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-find.d.ts +1 -1
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +16 -9
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-fts.d.ts.map +1 -1
- package/dist/schemes/_entry-fts.js +3 -9
- package/dist/schemes/_entry-fts.js.map +1 -1
- package/dist/schemes/_entry-manifest.js +3 -3
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.js +1 -1
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/exec-abort.js +2 -2
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/server/ConfigurationDiagnostics.d.ts +1 -0
- package/dist/server/ConfigurationDiagnostics.d.ts.map +1 -1
- package/dist/server/ConfigurationDiagnostics.js +9 -0
- package/dist/server/ConfigurationDiagnostics.js.map +1 -1
- package/dist/server/Daemon.d.ts +13 -8
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +57 -53
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +2 -4
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +5 -12
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/EnvFunctionality.d.ts +6 -6
- package/dist/server/EnvFunctionality.d.ts.map +1 -1
- package/dist/server/EnvFunctionality.js +7 -6
- package/dist/server/EnvFunctionality.js.map +1 -1
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +42 -13
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +3 -4
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +17 -9
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/HttpListener.d.ts.map +1 -1
- package/dist/server/HttpListener.js +9 -3
- package/dist/server/HttpListener.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +2 -5
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +5 -3
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/WorkspaceStorage.d.ts +0 -1
- package/dist/server/WorkspaceStorage.d.ts.map +1 -1
- package/dist/server/WorkspaceStorage.js +1 -24
- package/dist/server/WorkspaceStorage.js.map +1 -1
- package/dist/server/client-input.d.ts +1 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +13 -15
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +1 -1
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +16 -15
- package/dist/server/envelope.d.ts +2 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +7 -17
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +5 -5
- package/dist/server/seam-proposal-list.sql +6 -4
- package/dist/server/workspace-storage.sql +0 -5
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +28 -64
- package/dist/service.js.map +1 -1
- package/docs/env.md +22 -0
- package/migrations/003_loops.sql +2 -2
- package/migrations/006_log.sql +1 -1
- package/migrations/016_selection_statements.sql +1 -0
- package/migrations/017_skills_module.sql +1 -0
- package/migrations/018_worker_owners.sql +103 -0
- package/migrations/019_interactive_owners.sql +7 -0
- package/migrations/020_log_projection.sql +144 -0
- package/migrations/021_packet_roles.sql +86 -0
- package/migrations/022_message_completion.sql +24 -0
- package/package.json +41 -43
- package/dist/core/LegacyHome.d.ts +0 -10
- package/dist/core/LegacyHome.d.ts.map +0 -1
- package/dist/core/LegacyHome.js +0 -170
- package/dist/core/LegacyHome.js.map +0 -1
- package/dist/core/LoopPolicies.d.ts +0 -7
- package/dist/core/LoopPolicies.d.ts.map +0 -1
- package/dist/core/LoopPolicies.js +0 -42
- package/dist/core/LoopPolicies.js.map +0 -1
- package/dist/core/LoopPolicyReader.d.ts +0 -7
- package/dist/core/LoopPolicyReader.d.ts.map +0 -1
- package/dist/core/LoopPolicyReader.js +0 -33
- package/dist/core/LoopPolicyReader.js.map +0 -1
- package/dist/core/LoopPolicyReader.sql +0 -6
- package/dist/index.d.ts +0 -14
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -21
- package/dist/index.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -63,8 +63,6 @@ flowchart LR
|
|
|
63
63
|
| **dispatch** | Core | Routing a statement to its scheme's op handler. |
|
|
64
64
|
| **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
|
|
65
65
|
| **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
|
|
66
|
-
| **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
|
|
67
|
-
| **session** | Retired/unqualified | Not a PLURNK lifecycle noun. Use the actual core noun; a third-party standard may use only its explicitly qualified protocol term. <!-- lexicon-allow: this row defines the retired noun --> |
|
|
68
66
|
|
|
69
67
|
### Storage terms
|
|
70
68
|
|
|
@@ -105,8 +103,8 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
105
103
|
| **BARE inference** | One isolated child-provider model call whose response becomes an ordinary BARE log result. It has no worker, packet, tools, output grammar, or persistent child state ({§bare-inference}). |
|
|
106
104
|
| **cycle** | Repeated operational inputs and observed results under {§engine-cycle-evidence}. |
|
|
107
105
|
| **capability policy** | A purely subtractive `only`/`deny` selector layer over routed operation demands. Service and workspace layers compose without granting authority. |
|
|
108
|
-
| **
|
|
109
|
-
| **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition
|
|
106
|
+
| **approval owner** | One durable, workspace-scoped recipient for a worker's approval requests ({§worker-ownership}). |
|
|
107
|
+
| **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition selects owner review or automatic settlement ({§proposal-disposition}). |
|
|
110
108
|
| **resolution** | A client decision delivered through a standard resume entry. Proposal resolutions accept, reject, or cancel ({§methods-proposal-resolve}); client-interaction resolutions return a payload or cancel ({§methods-client-interaction-resolve}, {§agui-proposal-resolve}). |
|
|
111
109
|
|
|
112
110
|
### §packet-terms Packet terms
|
|
@@ -169,19 +167,14 @@ none, so its daemon leaves out AG-UI ({§module-http-mounts}).
|
|
|
169
167
|
|
|
170
168
|
### §service-package-exports Package export surface
|
|
171
169
|
|
|
172
|
-
| Export path | Current contract
|
|
173
|
-
|
|
174
|
-
| `@plurnk/plurnk-service`
|
|
175
|
-
| `@plurnk/plurnk-service/evidence`
|
|
176
|
-
| `@plurnk/plurnk-service/package.json` | Supported package metadata surface.
|
|
170
|
+
| Export path | Current contract |
|
|
171
|
+
|---------------------------------------|------------------|
|
|
172
|
+
| `@plurnk/plurnk-service/launch` | The daemon launcher ({§daemon-launch}). |
|
|
173
|
+
| `@plurnk/plurnk-service/evidence` | Canonical evidence reader consumed by the separate report package ({§digest-evidence-reader}). |
|
|
174
|
+
| `@plurnk/plurnk-service/package.json` | Supported package metadata surface. |
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
| Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry` |
|
|
181
|
-
| Types | `ChatMessage`, `EditResult`, `FlagDescriptor`, `MockAssistant`, `MockResponse`, `OpenFoldResult`, `ReadResult` |
|
|
182
|
-
|
|
183
|
-
New clients use AG-UI. A new library contract belongs in its owning package or
|
|
184
|
-
an explicitly specified subpath, not in the legacy root barrel.
|
|
176
|
+
These are the package's only export paths. Clients use AG-UI; a new library contract belongs in its
|
|
177
|
+
owning package or an explicitly specified subpath.
|
|
185
178
|
|
|
186
179
|
### §startup-admission Startup admission
|
|
187
180
|
|
|
@@ -212,12 +205,14 @@ listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
|
|
|
212
205
|
({§application-port}). A prefix is an absolute pathname. Each request goes to the
|
|
213
206
|
longest mounted prefix; a prefix claims itself and the subtree beneath it, never
|
|
214
207
|
a longer sibling name; `/` is the root and receives whatever nothing more
|
|
215
|
-
specific claimed
|
|
208
|
+
specific claimed when a module mounts it. An admitted listener returns an HTTP
|
|
209
|
+
`404 route-not-found` Problem for any path without a mounted handler; a root mount
|
|
210
|
+
is not required. Until daemon activation admits it the listener answers `503
|
|
216
211
|
service-starting` to every request: the service has not admitted its client
|
|
217
212
|
interface. Adapters claim their prefixes before setup and mount them at
|
|
218
213
|
`start()`, after durable lifecycle recovery ({§module-http-mounts}), and
|
|
219
214
|
none opens a socket of its own. The standards
|
|
220
|
-
address by URL, never by port (#641): AG-UI mounts
|
|
215
|
+
address by URL, never by port (#641): AG-UI mounts only `/agui`, A2A the
|
|
221
216
|
well-known card and its endpoint path, on the same address.
|
|
222
217
|
|
|
223
218
|
§startup-admission-order After listener ownership, database admission completes
|
|
@@ -230,7 +225,7 @@ preserving the originating failure: daemon, observability, database, listener.
|
|
|
230
225
|
|
|
231
226
|
§startup-readiness-line **Readiness is one stdout line.** After the client interface is mounted
|
|
232
227
|
the service prints exactly one line, `plurnk-service agui=<url> db=<json string> route=<json string>`:
|
|
233
|
-
the URL brackets an IPv6 host, and the database path and the route (the active model route or
|
|
228
|
+
the URL includes `/agui` and brackets an IPv6 host, and the database path and the route (the active model route or
|
|
234
229
|
`no model`, or `invalid model configuration`) are JSON strings, so a path or route containing spaces is exact and a consumer parses
|
|
235
230
|
the URL as a URL and the strings as JSON; nothing else the service prints on stdout before it has
|
|
236
231
|
that prefix. Before the line the listener answers `503 service-starting`; after it,
|
|
@@ -256,6 +251,49 @@ launchers consume the same contract by reading the line themselves.
|
|
|
256
251
|
|
|
257
252
|
## §actor-boundary Workers and workspace boundaries
|
|
258
253
|
|
|
254
|
+
### §worker-ownership Approval ownership
|
|
255
|
+
|
|
256
|
+
Every worker has one workspace-scoped approval owner. Ownership is independent of
|
|
257
|
+
origin, parentage, messages and connection presence. It controls approval routing,
|
|
258
|
+
not access to workspace resources ({§actor-boundary-no-mutex}).
|
|
259
|
+
|
|
260
|
+
| Event | Ownership |
|
|
261
|
+
| --- | --- |
|
|
262
|
+
| Root creation | Explicit owner, otherwise the runtime `_plurnk`. |
|
|
263
|
+
| WORK, FORK, or a fresh child | Inherit the parent's owner. |
|
|
264
|
+
| SEND, schedule occurrence, or other incoming message | Preserve the recipient's owner. |
|
|
265
|
+
| Explicit client control attachment | Claim a runtime-owned conversation and its runtime-owned descendants; never claim the runtime actor or replace another owner. |
|
|
266
|
+
| Observation or disconnect | No change. |
|
|
267
|
+
|
|
268
|
+
An owner declares its capability set: the client tool names it implements, and whether it
|
|
269
|
+
is interactive, that is, whether a person attends it. The declaration remains durable while it
|
|
270
|
+
is disconnected. A proposal requiring review waits for that owner; unsupported review fails at
|
|
271
|
+
the request boundary. Approval needs no person: a client that accepts automatically still
|
|
272
|
+
implements `request_approval`. Clarification and a park only a person can end need an
|
|
273
|
+
interactive owner. `_plurnk` implements no client tools and is never interactive. Server
|
|
274
|
+
approval policy may settle a proposal automatically; it cannot fabricate an interaction answer.
|
|
275
|
+
Kernel maintenance remains kernel work ({§actor-boundary-self-hosting}).
|
|
276
|
+
|
|
277
|
+
§worker-owner-creation Ownership, inheritance, and runtime-owner creation are
|
|
278
|
+
database invariants. A newly created worker cannot be left without an owner;
|
|
279
|
+
an unknown explicit owner is an error. Existing workers migrate to runtime ownership.
|
|
280
|
+
|
|
281
|
+
§worker-owner-resolution A proposal names its worker's owner and one disposition:
|
|
282
|
+
`review`, `accept`, or `reject`. Review routes to that owner, not to the sender,
|
|
283
|
+
the current observer, or whichever ancestor has a live Run. A decision is accepted
|
|
284
|
+
only for that owner and the still-pending gate. Disconnect does not substitute a
|
|
285
|
+
different owner. Capability admission remains independent and precedes approval.
|
|
286
|
+
|
|
287
|
+
§client-interaction-routing Clarification goes to the worker's owner, like approval, but
|
|
288
|
+
only a person can answer it. The owner receives it while it is interactive and declares
|
|
289
|
+
the requested tool; otherwise the request fails at once as unsupported and never parks.
|
|
290
|
+
The pending interaction records that recipient and accepts a response only from it,
|
|
291
|
+
through the ordinary response-schema validation and settlement path. A protocol caller,
|
|
292
|
+
such as an A2A client, converses by message and is never a recipient
|
|
293
|
+
({§a2a-worker-ownership}).
|
|
294
|
+
|
|
295
|
+
### Worker boundaries
|
|
296
|
+
|
|
259
297
|
```mermaid
|
|
260
298
|
flowchart LR
|
|
261
299
|
child["Child worker"] -->|"durable activity<br/>environment door"| parent["Direct parent log"]
|
|
@@ -281,7 +319,8 @@ Functionality ({§module-workspace-capabilities}); runtimes, runtime
|
|
|
281
319
|
schemes, and tools resolve by `workspaceId`. Operations journal in the
|
|
282
320
|
submitting actor's `workerId` ({§connection-lifecycle}), which must belong to
|
|
283
321
|
the workspace. Runtime and policy resolution require no second worker identity.
|
|
284
|
-
Attachment remains many-to-one
|
|
322
|
+
Attachment remains many-to-one and unrelated to parentage. Explicit control
|
|
323
|
+
attachment may claim approval ownership under {§worker-ownership}.
|
|
285
324
|
|
|
286
325
|
§actor-boundary-two-doors **Cross-worker arrival is limited to two doors.**
|
|
287
326
|
An explicit READ is not an arrival: the reading worker deliberately addresses a
|
|
@@ -349,13 +388,14 @@ Maintenance turns create neither lineage nor commons broadcasts. Their loops are
|
|
|
349
388
|
|
|
350
389
|
§actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS`
|
|
351
390
|
foists turn-0 discovery into the worker's first turn, so a worker opens with a
|
|
352
|
-
navigable map instead of blank. Its baseline
|
|
353
|
-
order; unregistered schemes contribute no survey, and workspace capabilities may
|
|
391
|
+
navigable map instead of blank. Its baseline surveys follow this
|
|
392
|
+
order: one READ of the program itself, then bodyless FINDs; unregistered schemes contribute no survey, and workspace capabilities may
|
|
354
393
|
narrow or omit the reference catalogs under {§capability-admission}.
|
|
355
394
|
|
|
356
|
-
| Surface |
|
|
395
|
+
| Surface | Target | Scope / aside |
|
|
357
396
|
| --- | --- | --- |
|
|
358
|
-
|
|
|
397
|
+
| This program | READ `ops://<worker>/<loop>/1` | `this program`; the log carries one program verbatim, and every `ops://` turn is shown readable ({§turn-source-resources}) |
|
|
398
|
+
| Agent Skills | FIND `skill://*/SKILL.md` | `<1,-1>`; {§skills-resources} |
|
|
359
399
|
| Plurnk references: executors, schemes, family managers | `worker:///_plurnk/plurnk/*.md` | `<1,-1>` |
|
|
360
400
|
| Enabled tools | `worker:///_plurnk/tools/*.md` | `<1,-1>`; configured expansions follow under {§tools-resource-materialization} |
|
|
361
401
|
| Enabled agents | `worker:///_plurnk/a2a/*.md` | `<1,-1>`; {§a2a-catalog} |
|
|
@@ -382,7 +422,7 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
|
|
|
382
422
|
unset / `0` disables previews. `log://` is absent because the current worker's
|
|
383
423
|
log already renders in present mode.
|
|
384
424
|
|
|
385
|
-
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` operation turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program — the READ/FIND surveys,
|
|
425
|
+
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` operation turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program — the READ/FIND surveys, led by one NOTE when the surveys run — is recorded as the turn's `ops://` source and executed through {§op-execution-order} exactly as a model's program is; it authors no reasoning and reads none back. The NOTE keeps the example turn within the card's NOTE-per-turn teaching and reads, exactly, `Surveyed tooling, documentation, extended context, and project root.` No emission row is fabricated ({§emission-row}): the first request sees the NOTE and the surveys' ordinary results, never an assistant-content copy of the program. The initial message arrives as an inbound SEND in the first model turn ({§message-arrival}); initialization never READs it, and neither initialization nor later turns manufacture a task inventory. Every orienting row is structurally classified `_plurnk` and `init`. The namespace surveys and their asides follow {§actor-boundary-catalog-preview}.
|
|
386
426
|
|
|
387
427
|
Incoming messages publish once as inbound SEND rows in the first model turn
|
|
388
428
|
({§message-arrival}); initialization neither READs nor archives them. The turn
|
|
@@ -495,7 +535,7 @@ continues to decompose other authorities without treating them as mintable.
|
|
|
495
535
|
|
|
496
536
|
§worker-read-scope **Scratch is workspace-readable.** Any actor reads and searches any named or shared scratch address. Parentage and writer identity do not change resolution. Scratch namespaces do not require a namesake Worker. A pathless actor address requires a named Worker; an unknown actor returns 404.
|
|
497
537
|
|
|
498
|
-
§worker-write-scoping **Scratch is workspace-writable.** All workspace actors may EDIT, COPY, MOVE, or KILL entries in any named or shared scratch namespace, including generated documents.
|
|
538
|
+
§worker-write-scoping **Scratch is workspace-writable.** All workspace actors may EDIT, COPY, MOVE, or KILL entries in any named or shared scratch namespace, including generated documents. Workspace admission remains uniform. Intrinsically immutable evidence in other schemes retains its own contract ({§scheme-entry-matrix}); operation provenance and delegation lifecycle do not grant or restrict scratch access.
|
|
499
539
|
|
|
500
540
|
§worker-generated-subtree **Generated documents share `worker:///_plurnk/`.** Project instructions (`AGENTS.md` and subtree-scoped `instructions/**`), scheme/runtime references (`plurnk/**`), tool details (`tools/**`), and family catalogs are workspace resources. Agent Skills retain their own trees at `skill://<name>/` ({§skills-resources}).
|
|
501
541
|
|
|
@@ -550,7 +590,6 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
550
590
|
own work is a fresh loop, so an inherited mid-flight loop never makes the
|
|
551
591
|
branch look forever-live to the {§send-premature-terminate} gate.
|
|
552
592
|
- §worker-scheme-fork-scratch **Forked scratch.** Named scratch and evidence are copied under the new name through {§machine-processes-entry-inheritance}. Parent and branch can edit either scratch namespace; their copies diverge independently.
|
|
553
|
-
- §worker-delegation-inherits-policy **Fresh delegated loops inherit the sender's policy.** WORK, FORK, and SEND to an idle Worker carry the sender's complete loop policy, disposition and attendance alike. SEND into an active or parked loop leaves its immutable policy untouched. All workers share live workspace capability policy; delegation creates no capability snapshot or bound.
|
|
554
593
|
- §worker-lifecycle-wake-requeue-not-terminal **A wake re-queue is not a terminal.** A conclusion-wake resumes a 202-blocked loop by re-queueing it (202 → 100); when that lands while the loop's own live drain is between turns, the drain **re-claims and continues** (atomic 100 → 102; the injected prompt is already the next turn). The internal re-queue is never reported as an outward terminal.
|
|
555
594
|
|
|
556
595
|
- §worker-scheme-collect **Collect** — each concluded child loop reaches its direct
|
|
@@ -583,7 +622,7 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
583
622
|
holds under the teaching's own word for handing work out: `## Delegation` is
|
|
584
623
|
one JSON object, `{"workers": [...], "streams": [...]}`, its unconcluded child
|
|
585
624
|
workers and its open streams as `{status, path}` pointers (the same shape as
|
|
586
|
-
the errors section)
|
|
625
|
+
the errors section). Body-suppressed child activity is durable
|
|
587
626
|
history; this section is the current inventory that keeps an active obligation
|
|
588
627
|
visible even when no new activity arrived. Each open stream pointer carries
|
|
589
628
|
elapsed runtime, output inactivity, and its channels' sizes and growth since
|
|
@@ -594,7 +633,7 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
594
633
|
starts there too, then resets atomically when any published channel's content
|
|
595
634
|
changes, including replacement or clearing. Identical writes, empty appends,
|
|
596
635
|
READs, publication acknowledgements, metadata, and channel-state changes do
|
|
597
|
-
not reset it. The clock is durable;
|
|
636
|
+
not reset it. The clock is durable; a stream lacking that evidence
|
|
598
637
|
reports `output timing unknown` until its next content change, never a guessed
|
|
599
638
|
timestamp. These are observations, not new timeouts or wake conditions
|
|
600
639
|
({§exec-stream}). It is orienting state, never advice: the model sees its live
|
|
@@ -611,7 +650,7 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
611
650
|
`## Worker` identity block carries `"parent": "worker://<name>"`, or
|
|
612
651
|
`"parent": null` at a root, so a worker never infers its rank from silence.
|
|
613
652
|
- §packet-current-turn **The packet says who and which turn, below the log.** The
|
|
614
|
-
`## Worker` block
|
|
653
|
+
`## Worker` block, in the status clump below the log ({§packet-cache-monotone}), carries
|
|
615
654
|
`{"path": "worker://<name>", "parent": <address or null>, "loop": L, "turn": T}`: the actor,
|
|
616
655
|
whose child it is, and the coordinate this packet's response becomes, so `reasoning://<worker>/L/T`
|
|
617
656
|
and `ops://<worker>/L/T` are the model's own and `log:///L/T/*` its rows; a model never infers the
|
|
@@ -847,7 +886,7 @@ all use that one definition.
|
|
|
847
886
|
|
|
848
887
|
With live work—an open stream or a live child worker—the loop parks until an
|
|
849
888
|
ordinary wake or its maximum wait elapses. `PLURNK_SERVICE_WAIT_SEC` supplies the
|
|
850
|
-
bound; `WAIT
|
|
889
|
+
bound; `WAIT [seconds]` overrides that one park ({§send-wait-scope}). The wake time
|
|
851
890
|
commits atomically with the wait revision, rounded up to the next millisecond.
|
|
852
891
|
Expiry queues the same loop through normal worker/provider admission; it never
|
|
853
892
|
cancels work or fabricates a result.
|
|
@@ -855,7 +894,6 @@ cancels work or fabricates a result.
|
|
|
855
894
|
With live work, each WAIT receipt exposes `waitSeconds`, the maximum accepted
|
|
856
895
|
for that operation. It is not elapsed time or a promised sleep: an ordinary wake
|
|
857
896
|
or a shorter sibling WAIT can resume the loop sooner. An idle WAIT has no bound.
|
|
858
|
-
Historical unbounded receipts do not acquire one during projection.
|
|
859
897
|
|
|
860
898
|
| Boundary | Outcome |
|
|
861
899
|
|---|---|
|
|
@@ -937,7 +975,7 @@ never replay interrupted effects to reconstruct time. Future messages use
|
|
|
937
975
|
the separate schedule contract ({§schedule-delivery}).
|
|
938
976
|
|
|
939
977
|
§worker-message-admission **Recipient selection and admission are one decision.**
|
|
940
|
-
An arrival to a worker selects its running loop, otherwise its oldest parked
|
|
978
|
+
An unaddressed arrival to a worker selects its running loop, otherwise its oldest parked
|
|
941
979
|
loop, otherwise a new queued loop. Compatibility is checked against the exact
|
|
942
980
|
loop that receives the message; the writer does not reselect another recipient.
|
|
943
981
|
The worker's admission lock covers selection, compatibility, message admission,
|
|
@@ -952,6 +990,15 @@ atomically; no drain may claim partially configured work.
|
|
|
952
990
|
| Cancelled as part of the worker scope | Preserve the frame as evidence; never promote it into executable work, including after restart. |
|
|
953
991
|
| Explicit new arrival after cancellation | Admit under ordinary current worker policy; never revive a terminal loop. |
|
|
954
992
|
|
|
993
|
+
§loop-addressed-admission **An explicit Loop recipient never falls back to new work.**
|
|
994
|
+
`runLoop` may name `loopId` alongside its owning `workerId`. Selection requires that
|
|
995
|
+
exact Loop to belong to the Worker and remain queued, running or parked. The inbox
|
|
996
|
+
insert atomically requires the recipient to remain unfinished; completion winning
|
|
997
|
+
that race leaves the message unadmitted. Missing, foreign or terminal recipients
|
|
998
|
+
produce `409 daemon/admission/loop-not-open`, without creating another Loop or
|
|
999
|
+
delivering to a different one. Compatibility checks and wake behavior are the same
|
|
1000
|
+
as ordinary Worker delivery. This is address selection, not a lifecycle policy.
|
|
1001
|
+
|
|
955
1002
|
§stream-catalog-lifecycle Streams are independently durable subscriptions owned by a worker. Payload and
|
|
956
1003
|
lifecycle are orthogonal: zero bytes is a valid payload for both success and
|
|
957
1004
|
failure, while the closed subscription and its status are the terminal fact.
|
|
@@ -1057,8 +1104,8 @@ whose obligations settled during reconciliation is requeued in place so it can
|
|
|
1057
1104
|
observe their terminal results. No effect is replayed across an unknown
|
|
1058
1105
|
boundary.
|
|
1059
1106
|
|
|
1060
|
-
- §worker-lifecycle-single-drain **One drain advances a worker.** At most one drain is registered for a worker at any instant: a `runLoop` request or wake on a worker with a live drain folds in (active→next-turn) or enqueues a loop that drain claims, never a second parallel drain. A drain's start and its empty-queue teardown relinquish the worker under one per-worker lock, so the teardown's re-claim cannot race a concurrent start into a double-drain. Fresh-loop sequence allocation and insertion are one mutation under that same lock;
|
|
1061
|
-
- §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel` and worker `KILL` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Shutdown reaps process-local streams while preserving parked work under {§worker-lifecycle-durable-disposition}. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model ```` ```KILL [code] ```` on one live stream instead delivers exactly that signal once (
|
|
1107
|
+
- §worker-lifecycle-single-drain **One drain advances a worker.** At most one drain is registered for a worker at any instant: a `runLoop` request or wake on a worker with a live drain folds in (active→next-turn) or enqueues a loop that drain claims, never a second parallel drain. A drain's start and its empty-queue teardown relinquish the worker under one per-worker lock, so the teardown's re-claim cannot race a concurrent start into a double-drain. Fresh-loop sequence allocation and insertion are one mutation under that same lock; fresh loops receive distinct increasing sequence numbers. Recipient selection follows {§worker-message-admission}, not whether callers started concurrently.
|
|
1108
|
+
- §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel` and worker `KILL` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Shutdown reaps process-local streams while preserving parked work under {§worker-lifecycle-durable-disposition}. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model ```` ```KILL (sh:///stream) [code] ```` on one live stream instead delivers exactly that signal once (without a signal override it uses the executor's SIGHUP default; `[9]` uses SIGKILL).
|
|
1062
1109
|
- §worker-lifecycle-exec-epoch-bound **A stream's kill binds to the scope it captured at spawn.** A stream captures the worker's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream.
|
|
1063
1110
|
- §worker-lifecycle-no-resurrection **Cancelled work does not revive its scope.** A cancelled worker cannot be woken by its torn-down streams, stale timers, or cancelled unpublished messages. The evidence remains readable. A `499` result from cancelling only one stream is still a completion owed to a live waiting worker: result status is not proof of worker cancellation. Only an explicit new arrival admits new work after scope cancellation; terminal loops themselves remain immutable.
|
|
1064
1111
|
- §worker-cancel-trigger **A cancellation is one bound statement.** `lifecycle_cancel_workers` writes the causal cutoff and the cancellation Problem onto every worker of the scope; `workers_cancel_live_loops` (an `INIT` process trigger beside the lifecycle statements, {§db-process-triggers}) retires each worker's live loops inside that statement — 499, waits cleared, message evidence left unchanged, the Problem instanced `loop://<worker>/<sequence>`, `terminated_by = 'cancel'` — so cutoff and cancellation cannot land apart and no value is string-interpolated. Execution consumption is measured by the process-local monotonic timers ({§loop-execution-allowance}) and lands first through `lifecycle_checkpoint_executions`; a wall clock cannot stand in for it, so the timer stays outside the database by design.
|
|
@@ -1072,10 +1119,10 @@ boundary.
|
|
|
1072
1119
|
| Independent arrival after cancellation | Admit a new loop above the cutoff using the ordinary worker policy. |
|
|
1073
1120
|
| Slow stream teardown after new admission | Reap only subscription identities captured by cancellation; late old-scope spawns follow {§worker-lifecycle-exec-epoch-bound}. |
|
|
1074
1121
|
|
|
1075
|
-
- §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** The stream first persists its terminal state. A worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) then **awakens that loop in place** — the blocked loop *is* the continuation
|
|
1122
|
+
- §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** The stream first persists its terminal state. A worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) then **awakens that loop in place** — the blocked loop *is* the continuation. An already-active worker's next packet reads the durable terminal state. Ambient stream closure starts no loop for a concluded worker. The result remains available in the stream's own state under every case.
|
|
1076
1123
|
- §worker-lifecycle-child-wake **Each child task completion notifies its parent.** Terminal-task publication, including failure and cancellation of a parked task, notifies the direct parent without injecting a prompt. Other unfinished tasks or streams in that child remain independent obligations; they cannot suppress notification. The parent's eligible waits requeue in place under {§loop-wake-identity} and the bounded {§worker-optimistic-settlement} opportunity. Durable revisioning covers completion-before-park and restart; drain teardown and whole-worker quiescence are not completion identities.
|
|
1077
1124
|
- §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before program completion; separately, a stream conclusion, direct-child conclusion or addressed reply persists and publishes immediately but holds eligible parked loops' `202→100` requeues while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces arrivals within that window into at most one requeue per eligible loop. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. An arrival after provider dispatch begins retains its next wake, while poll, new-request and operator wakes never open this hold. Only packet/provider dispatch waits: durable state, client events, cancellation and the replying program do not. One redaction-safe span records elapsed time, quiescence versus deadline, and arrival count without entering the packet.
|
|
1078
|
-
- §worker-lifecycle-idle-is-concluded **Idle is not completion.**
|
|
1125
|
+
- §worker-lifecycle-idle-is-concluded **Idle is not completion.** A loop concludes only under {§loop-completion}; an unanswered message remains an obligation even when nothing is running. A concluded worker retains durable history; a later addressed arrival starts a new loop.
|
|
1079
1126
|
- §worker-lifecycle-no-lost-loop **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur.
|
|
1080
1127
|
- §worker-lifecycle-durable-disposition **Durable disposition wins cancellation races.** At a turn boundary, the engine reads the loop's durable status before interpreting a process-local abort. A committed `202` park survives a later daemon-shutdown signal; only a loop still durably running at `102` can be terminalized by that cancellation. Wake selection rechecks shutdown and worker cancellation before requeuing each parked loop.
|
|
1081
1128
|
- §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request first settles as an error with absent usage and explicitly unknown cost; then its logical model call closes. Recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation requeues on an unseen completion or when no live obligation remains. Otherwise it stays parked on surviving children; the drain restores inherited stream observation through the same guarded scheduler ({§worker-wait-timing}). Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
|
|
@@ -1153,7 +1200,7 @@ These are the complete strike sources:
|
|
|
1153
1200
|
|---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
|
|
1154
1201
|
| Hard result | An admitted non-execution operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `425`, `501`, in a turn where no operation succeeded ({§strike-progress-immunity}). | The originating failure row. |
|
|
1155
1202
|
| Cycle | The executed operations and their observed results repeat under {§engine-cycle-evidence}. | None; cycle detection itself is private engine accounting. |
|
|
1156
|
-
| Empty turn | An
|
|
1203
|
+
| Empty turn | An operation-free turn with unresolved messages or incomplete emission evidence ({§empty-turn}). | The turn's `422` error row. |
|
|
1157
1204
|
|
|
1158
1205
|
Execution results remain exact model-visible evidence but are always soft: an
|
|
1159
1206
|
executor error is not a PLURNK contract violation. Cycle detection remains an
|
|
@@ -1198,9 +1245,9 @@ retains only the current provider state; the next completed exchange notices
|
|
|
1198
1245
|
`provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
|
|
1199
1246
|
is spent the turn completes as `202` and the loop parks exactly like a
|
|
1200
1247
|
WAIT ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
|
|
1201
|
-
next prompt or wake with its log intact — **unless the
|
|
1202
|
-
({§
|
|
1203
|
-
|
|
1248
|
+
next prompt or wake with its log intact — **unless the worker's owner is not interactive
|
|
1249
|
+
({§worker-ownership}); then the loop concludes on the provider's exact failure because no
|
|
1250
|
+
person attends to wake that park.** Only a client cancel, the execution allowance
|
|
1204
1251
|
({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
|
|
1205
1252
|
authorization, quota, an invalid response) settles a loop on a provider failure.
|
|
1206
1253
|
|
|
@@ -1213,7 +1260,7 @@ failures keep their exact rows, but the turn counts as progress — it earns no
|
|
|
1213
1260
|
and clears the streak. A successful operation is any admitted operation that acts on the
|
|
1214
1261
|
task — executions included — whose result status is `< 400`. Operations that steer the
|
|
1215
1262
|
loop never qualify: NOTE (it cannot fail; reasoning NOTEs are filed as NOTEs, and outside
|
|
1216
|
-
text is no operation at all, {§outside-text}), WAIT
|
|
1263
|
+
text is no operation at all, {§outside-text}), WAIT and a targetless SEND; a turn
|
|
1217
1264
|
of failures beside a WAIT still strikes. The cycle source is not exempted: a repeating
|
|
1218
1265
|
turn's operations succeed by construction, and the backstop exists to catch exactly
|
|
1219
1266
|
that ({§engine-cycle-evidence}).
|
|
@@ -1317,7 +1364,7 @@ The parser owns its boundaries; core admits determinate work and exposes its fai
|
|
|
1317
1364
|
| Lost boundary before any closed operation | Reject the attempt; outside text is no substitute for a closed operational statement. An admitted reasoning operation is one ({§reasoning-operations}). |
|
|
1318
1365
|
| Outside text carrying a log-entry heading, other than an emission row's | Reject the attempt ({§fabricated-log-entry}). |
|
|
1319
1366
|
|
|
1320
|
-
§fabricated-log-entry **Only the harness writes the log.** A line of outside response text that begins with a log-entry heading, `### log:///<loop>/<turn>/<sequence>/` ({§log-wire-format}), is the model continuing the packet's transcript instead of answering it: it writes the receipts it expects and then acts on them. The attempt is rejected under {§invalid-emission-attempts}, so neither that text nor any operation beside it runs or is stored as outside text ({§outside-text}), and its one diagnostic, at the heading's line, reads `` `### log:///2/1/5/READ` is a log entry, and only the harness writes the log.
|
|
1367
|
+
§fabricated-log-entry **Only the harness writes the log.** A line of outside response text that begins with a log-entry heading, `### log:///<loop>/<turn>/<sequence>/` ({§log-wire-format}), is the model continuing the packet's transcript instead of answering it: it writes the receipts it expects and then acts on them. The attempt is rejected under {§invalid-emission-attempts}, so neither that text nor any operation beside it runs or is stored as outside text ({§outside-text}), and its one diagnostic, at the heading's line, reads `` `### log:///2/1/5/READ` is a log entry, and only the harness writes the log. `` Text inside an operation body is not examined, so a SEND or KILL may quote a receipt. A heading whose leaf is `emission` is exempt: it names the worker's own source ({§emission-row}), and repeating it invents no receipt, so the attempt is admitted and the heading is dropped from the text beside the operations ({§outside-text}), counted by the digest as an echo. In 10,486 recorded emissions, 101 carried such a heading in outside text, every one a fabrication: 85 of 1,675 from deepseek-flash, 81 of them opening with one, and 16 from glm-5.3-flash, deepseek-v4-pro and qwen3.8-flash, which appended an invented `## Log` after their own operations.
|
|
1321
1368
|
|
|
1322
1369
|
Warnings and closer recovery ({§closer-fallback}) do not reject. `finish=length`
|
|
1323
1370
|
discloses truncation and precludes completion; it is not independently a rejection.
|
|
@@ -1420,10 +1467,9 @@ unrelated suffixes.
|
|
|
1420
1467
|
does nothing with it (#588).** `PLURNK_PROVIDERS_GBNF[_<alias>]` is a file
|
|
1421
1468
|
path — absolute, `~`-relative, or relative to the daemon's working directory —
|
|
1422
1469
|
whose text is read once per daemon and handed to the provider verbatim
|
|
1423
|
-
({§provider-grammar-transport}).
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
becomes unconstrained. Nothing generates, validates, or grades a grammar, and
|
|
1470
|
+
({§provider-grammar-transport}). A filename without a path separator is relative
|
|
1471
|
+
to the daemon's working directory too. An unreadable file fails the constrained
|
|
1472
|
+
generation; it never silently becomes unconstrained. Nothing generates, validates, or grades a grammar, and
|
|
1427
1473
|
no effort is implied by one. The turn records transport as evidence:
|
|
1428
1474
|
`railsAttached: "client"` when the provider reports it sent the grammar, or
|
|
1429
1475
|
`"withheld"` when it reports it did not ({§provider-grammar-evidence}); there
|
|
@@ -1579,9 +1625,9 @@ Every fact names the canonical key, never the host root or an echo of the
|
|
|
1579
1625
|
model's spelling. These classes let a caller distinguish a wrong address, an
|
|
1580
1626
|
invalid range, read-only authority, and occupied hidden state without guessing.
|
|
1581
1627
|
|
|
1582
|
-
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member key, never a `file://` URI. Recovery
|
|
1628
|
+
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member key, never a `file://` URI. Recovery offers listing with FIND, creation with EDIT, and admission with `members (add)` as alternatives and presumes none ({§diagnostic-observation}): `` FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. `` Admission takes a `{"glob": "<path>"}` body. The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo, and their recovery speaks of the address too, true under every members scope: `'<key>' is outside the project root: only a members definition under the operator's namespace scope admits it.` Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.`, with admission-only recovery; a path the repository ignores, which no model definition admits, carries the members discovery verdict instead: `The repository ignores it: a client or operator members definition can include it, a model definition cannot.` Occupancy may surface there; content never does ({§membership}).
|
|
1583
1629
|
|
|
1584
|
-
§file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file
|
|
1630
|
+
§file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file: READ and KILL answer 404, EDIT 403. The detail is `'<key>' is a directory, not a file; <OP> reads/removes/writes one file.`; a READ or KILL carries the listing as its recovery, `` `FIND (<key>/)` lists its files. ``, and an EDIT carries none. Beyond the root the disk stays dark and {§membership-read-refusal} holds unchanged.
|
|
1585
1631
|
|
|
1586
1632
|
§file-find-directory **FIND recognizes existing directories without requiring a trailing slash.** An exact target naming a directory inside the workspace root resolves to the same recursive collection as its slash-suffixed spelling, including content matching and result pagination. Only workspace members appear; an empty directory or one containing only non-members yields a successful empty survey. Exact files stay exact, genuinely absent paths retain their missing-entry error, and this resolution does not inspect disk paths beyond the root. Shared glob and non-file URI semantics are unchanged.
|
|
1587
1633
|
|
|
@@ -1621,7 +1667,7 @@ Registration precedes loop affinity:
|
|
|
1621
1667
|
| Registered but inactive under flag | The flag gate returns `403 scheme-unavailable`. |
|
|
1622
1668
|
| Registered and active | Dispatch continues to the operation owner. |
|
|
1623
1669
|
|
|
1624
|
-
- §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. WAIT
|
|
1670
|
+
- §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. WAIT is deferred until all other admitted operations settle or establish their explicitly asynchronous work ({§disposition-anywhere}). The complete program then settles under {§wait-obligation-matrix}, whether or not it contains a lifecycle request; no completion operation or inventory is invented. Existing cycle, no-operation, and resource rails remain effective. An observation records the resource state at its execution point; the model sees that receipt in the next packet. Exact submitted source and actual operation outcomes remain durable. Earlier successful effects survive a later operation failure; a producer requesting fail-on-error stops before subsequent operations.
|
|
1625
1671
|
|
|
1626
1672
|
§bare-inference **BARE is isolated, synchronous retrieval over the durable child-provider policy.**
|
|
1627
1673
|
|
|
@@ -1853,8 +1899,6 @@ operator knobs in `.env.defaults`. Search indexing performs no inference.
|
|
|
1853
1899
|
|
|
1854
1900
|
§per-entry-channels-edit-writes-only-body EDIT writes one channel per call — the channel resolved from the path's fragment (or the scheme's `defaultChannel` when no fragment).
|
|
1855
1901
|
|
|
1856
|
-
No stored `preview` channel — channel content is pulled on READ, never previewed.
|
|
1857
|
-
|
|
1858
1902
|
Schemes MAY declare multiple channels (`node`: stdout/stderr; `http`: body/header; SSE: per-event-type). Each goes in `manifest.channels` with mimetype pinned; rendered independently. Execution input is control under {§exec-input}, not a stored channel.
|
|
1859
1903
|
|
|
1860
1904
|
For a multi-channel streaming READ, persistence and publication are distinct: the scheme may acquire and persist auxiliary channels, but a fragmentless target publishes only the manifest's `defaultChannel`. An explicit fragment publishes that channel. Thus an ordinary HTTP READ presents the sanitized `body`; response metadata and archival DOM remain addressable implementation/diagnostic surfaces rather than ambient model context.
|
|
@@ -1918,7 +1962,7 @@ Client-interface target parameters carry fragments inline (`{ target: "sh:///a3b
|
|
|
1918
1962
|
MOVE out of it are 400 `channel-derived`; COPY from it is an ordinary read. Binary sources
|
|
1919
1963
|
keep {§membership-source-projection}, where the source is not text and the projection is the
|
|
1920
1964
|
body; a fetched web page keeps its scheme's own two channels ({§html-materialization}).
|
|
1921
|
-
- §channel-selection-visibility **Channel selection is decision-time information, not a guess** — every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, projection `mimetype`, tokens, and lines (default channel first), and matcher
|
|
1965
|
+
- §channel-selection-visibility **Channel selection is decision-time information, not a guess** — every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, projection `mimetype`, tokens, and lines (default channel first), and a matcher location names the channel its line coordinates address whenever that is not the resource's default channel. A READ of a multi-channel resource names its other channels with their tokens in `channels`, keyed by the fragment the model appends (`{"#readable": 812}`), so first contact — a fetched page, a stream's stdout — carries the same choice without a listing; a single-channel resource names none. When the default channel is a readable projection of a differently typed source, it also names `sourceMimetype` once; this is representation evidence, not a different READ workflow. The packet never presents channels as equal and indistinguishable; extents derive from the stored channels by construction. Budget enforcement stays with {§context-fit} — this is information, not a second guard.
|
|
1922
1966
|
|
|
1923
1967
|
### §channel-state Channel state — metadata, not gating
|
|
1924
1968
|
|
|
@@ -2031,7 +2075,7 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
|
|
|
2031
2075
|
- §edit-null-clears Writes the body; `body: null` clears it.
|
|
2032
2076
|
- §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
|
|
2033
2077
|
`{ status: 200, entryId }` for a content update.
|
|
2034
|
-
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring a scoped KILL's idempotence ({§log-kill-scope}). Its terse detail states the observed equality
|
|
2078
|
+
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring a scoped KILL's idempotence ({§log-kill-scope}). Its terse detail states the observed equality, `No change: EDIT body matches the selected content.`, and nothing else ({§diagnostic-observation}).
|
|
2035
2079
|
- §edit-marker-required-on-existing **A markerless EDIT is CREATE-ONLY — there is no easy-clobber path on an existing entry.** A `<L>` marker scopes an EDIT to a range; without one, the body becomes the entry's WHOLE content — legitimate and required for a fresh entry (nothing exists to scope into), but on an EXISTING entry a missing marker is refused **400**, never a silent full replace. A deliberate full rewrite states that intent explicitly: `<1,-1>` resolves through the ordinary marker math to the same whole-content replacement, so the capability is available but cannot be selected by omission.
|
|
2036
2080
|
- §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
|
|
2037
2081
|
its endpoint checks as a core-private mutation precondition. Otherwise-valid
|
|
@@ -2105,7 +2149,7 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
2105
2149
|
when that differs from the channel's own mimetype the result names the
|
|
2106
2150
|
channel's as `sourceMimetype`, so a consumer can still run the channel's
|
|
2107
2151
|
handlers over a whole-resource `<1,-1>` read.
|
|
2108
|
-
- §log-range-miss-names-stream A 416 on a log execution item
|
|
2152
|
+
- §log-range-miss-names-stream A 416 on a log execution item addresses the row's invocation (its authored call body, often empty or one line), while the execution's output stays readable at the stream address the row records. When that stream link exists, the 416 carries it as the `stream` extension; its detail and recovery stay the generic slicer's, naming no cause ({§diagnostic-observation}).
|
|
2109
2153
|
- §read-pattern **A pattern selects the lines a READ renders.** With a heading
|
|
2110
2154
|
matcher ({§matcher-option} in the contracts SPEC) an exact-target READ stays a
|
|
2111
2155
|
READ: the matcher runs over the channel's complete text — a regex anchors
|
|
@@ -2232,9 +2276,9 @@ AST: `{ op: "KILL", target, matcher: MatcherBody | null, lineMarker: TextLineMar
|
|
|
2232
2276
|
|
|
2233
2277
|
§log-kill-distillation **A log KILL may say what it keeps.** A body on a `log:///` KILL is the model's distillation of what the KILL retires. Whatever the kill's outcome, the body lands as the model's own NOTE row at the next sequence of the same turn — written after the kill's receipt, so it never falls inside the kill's own selection — carrying `attrs.distilled` with the KILL's target as written, so a distillation is distinguishable from a free NOTE while it renders, weighs and curates exactly as one; the dispatch reports two rows written. A kill that misses keeps its distillation beside its visible receipt: what the model wrote about its environment is recorded for the model to possess and retire, never dropped for where the kill aimed. A whitespace-only body is a plain KILL. The kill's own receipt stays hidden as any successful log KILL's does ({§context-verbs}).
|
|
2234
2278
|
|
|
2235
|
-
KILL deletes context from the **log** (`log:///`, {§packet}). Without a scope it retires the selected rows from the active projection ({§log-history-projection}). With a one-line or inclusive two-line scope it removes only that body's intersecting body-relative physical lines from the readable projection, and the row stays active. An anchor may be one published on that body or one returned by READing its `log:///` coordinate ({§line-anchors}); an anchor absent from the current body selects no line, as with an out-of-bounds numeric line. Scoped KILL is one-way: intervals accumulate, the durable body is untouched, and subsequent access follows {§log-readable-projection}. A scoped KILL on a bodyless row is a friendly 200 no-op with `matched` reported. An emission row is curated whole ({§emission-row}): a scope
|
|
2279
|
+
KILL deletes context from the **log** (`log:///`, {§packet}). Without a scope it retires the selected rows from the active projection ({§log-history-projection}). With a one-line or inclusive two-line scope it removes only that body's intersecting body-relative physical lines from the readable projection, and the row stays active. An anchor may be one published on that body or one returned by READing its `log:///` coordinate ({§line-anchors}); an anchor absent from the current body selects no line, as with an out-of-bounds numeric line. Scoped KILL is one-way: intervals accumulate, the durable body is untouched, and subsequent access follows {§log-readable-projection}. A scoped KILL on a bodyless row is a friendly 200 no-op with `matched` reported. An emission row is curated whole ({§emission-row}): the unscoped KILL retires it; a line scope on its exact coordinate addresses its legend and retires the NOTEs on the lines it selects, the row staying; on a row with no legend lines the scope is 422 `emission-curated-whole`, whose recovery names the unscoped KILL; a sweep leaves it intact. A KILL that addresses no row is 404 on an exact coordinate and 204 on a sweep ({§log-curation-folder-idiom}). Selection composes target/glob with an optional heading pattern ({§log-curation-set-selection}).
|
|
2236
2280
|
|
|
2237
|
-
§log-scope-recovery A log-body scope follows the file slicer's range rule ({§range-starts-at-one} in the schemes SPEC): a range starting at 0 — `<0,-1>` included — is refused 416 `range-not-satisfiable` on every body, empty ones too, and never clamped; its detail is the slicer's own sentence, `Range <0,-1> starts at 0, which is not a line; lines are numbered from 1.`, and its recovery names the forms a log body takes — `
|
|
2281
|
+
§log-scope-recovery A log-body scope follows the file slicer's range rule ({§range-starts-at-one} in the schemes SPEC): a range starting at 0 — `<0,-1>` included — is refused 416 `range-not-satisfiable` on every body, empty ones too, and never clamped; its detail is the slicer's own sentence, `Range <0,-1> starts at 0, which is not a line; lines are numbered from 1.`, and its recovery names the forms a log body takes — `Trim one line with <L> or lines L through M with <L,M>; KILL (log:///1/9/2/READ) with no scope retires the whole row.` — never the insert and append positions a body cannot take. Every other scope that names no line is 400 `curation-scope-invalid` with the same recovery: the forms that work on that row, never a rebuild of the written scope ({§diagnostic-observation}).
|
|
2238
2282
|
|
|
2239
2283
|
A READ carrying active native media is atomic: any KILL scope is ignored and the entire observation is retired, including its native context contribution ({§packet-attachment-parts}). For a model turn, native activity is the attachment selection in its actual input packet; without a model packet, a native observation is atomic by default. Text-only observations in the same selection retain ordinary scoped behavior. Neither form deletes source data or forensic evidence.
|
|
2240
2284
|
|
|
@@ -2242,7 +2286,7 @@ A READ carrying active native media is atomic: any KILL scope is ignored and the
|
|
|
2242
2286
|
|
|
2243
2287
|
| Fact | Owner | Effect |
|
|
2244
2288
|
| --- | --- | --- |
|
|
2245
|
-
| Initial body suppression | Immutable event `initial_folded` | Packet presentation only; explicit retrieval can read an initially hidden body. An emission row
|
|
2289
|
+
| Initial body suppression | Immutable event `initial_folded` | Packet presentation only; explicit retrieval can read an initially hidden body. An emission row remains folded; its program is separately eligible for {§emission-history}. |
|
|
2246
2290
|
| Deliberate scoped KILL | Current projection `folded`, initially empty | Packet, READ, FIND, COPY, and search omit those lines; later retrieval cannot undo trimming. |
|
|
2247
2291
|
|
|
2248
2292
|
Packet display combines both masks. Other consumers use only deliberate trimming.
|
|
@@ -2280,7 +2324,7 @@ The `## Log` section is a sequence of ordinary Markdown records separated by one
|
|
|
2280
2324
|
| facts | One strict JSON object in stable alphabetical order. | Present only when a fact exists. Asides, scopes, opaque invocation metadata and result facts belong here, not on the H3. |
|
|
2281
2325
|
| body | Coordinate-prefixed lines. | Present when the row is visible. |
|
|
2282
2326
|
|
|
2283
|
-
An emission row's body is not in its record
|
|
2327
|
+
An emission row's body is not in its record ({§emission-row}); its eligible program follows it as a separate assistant message ({§emission-history}). Patterns retain their literal spelling; a pattern containing a line break is JSON-quoted to keep the H3 on one physical line. Receipts are descriptive records, not reconstructed operation headings. Absent fields are not invented. Every physical body line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, so source text cannot create a record boundary. The section contains records only, with no leading prose or enclosing fence.
|
|
2284
2328
|
|
|
2285
2329
|
§log-address-metadata **Addresses name their relationship, not the row's producer.**
|
|
2286
2330
|
|
|
@@ -2324,7 +2368,9 @@ cropping ({§packet-attachment-parts}).
|
|
|
2324
2368
|
|
|
2325
2369
|
Retrieval results omit redundant requested coordinates; durable results and
|
|
2326
2370
|
submitted programs retain them. Failed selections keep requested coordinates
|
|
2327
|
-
and available extent in their owning Problem
|
|
2371
|
+
and available extent in their owning Problem; a channel READ that carries its
|
|
2372
|
+
execution's failure retrieved successfully and formats its extent like any
|
|
2373
|
+
other. Projection never parses its
|
|
2328
2374
|
display strings to recover typed facts. A hidden body has no `preview`; a
|
|
2329
2375
|
complete non-retrieval body retains `lines` where no other field supplies its
|
|
2330
2376
|
navigable extent. None of these spellings changes acquisition, delivery,
|
|
@@ -2347,8 +2393,11 @@ Authored `metadata` retains its opaque ordered block strings under {§scheme-met
|
|
|
2347
2393
|
byte sequence once; the result's `nativeContentHash`, enforced by the log's foreign key, identifies it.
|
|
2348
2394
|
This is retained evidence, not a separate visibility or delivery lifecycle. Source mutation/deletion
|
|
2349
2395
|
cannot change a retained observation. Explicit READ of its still-active log source can acquire the same media again.
|
|
2350
|
-
Every compatible-model packet includes one file part per retained, admitted READ observation,
|
|
2351
|
-
|
|
2396
|
+
Every compatible-model packet includes one file part per retained, admitted READ observation, directly
|
|
2397
|
+
after the user section ending at that READ record, in observation order. The attachment retains that
|
|
2398
|
+
section's name in request evidence; later log records or emissions never move ahead of it. Packets
|
|
2399
|
+
stored without a section binding retain their recorded whole-log placement. Each file part is
|
|
2400
|
+
preceded by a text part that names the observation's log
|
|
2352
2401
|
coordinate, source path and projection facts and states that the bytes are that READ's own, retained
|
|
2353
2402
|
until its row is KILLed: an uncaptioned native part on the user turn reads as a fresh arrival (#899).
|
|
2354
2403
|
Model-response settlement never consumes an observation. KILL follows
|
|
@@ -2362,7 +2411,7 @@ Authored `metadata` retains its opaque ordered block strings under {§scheme-met
|
|
|
2362
2411
|
records the exact READ coordinates sent without controlling retention. Missing immutable bytes are an
|
|
2363
2412
|
internal integrity failure, never silently dropped content. No ejection message or permanent teaching is
|
|
2364
2413
|
added. These stable curation weights are not provider-token measurements ({§tokenomics-render-weight-budget}).
|
|
2365
|
-
- §packet-token-accounting Every row reports one `tokens` charge on its H3 ({§log-wire-format}): its complete materialized H3, facts, visible body
|
|
2414
|
+
- §packet-token-accounting Every row reports one `tokens` charge on its H3 ({§log-wire-format}): its complete materialized H3, facts, visible body and selected native attachment. The emission-history section is charged separately as assistant-message text ({§emission-history}). The completed record is measured to a fixed point, including the accounting field itself. Hidden text is not charged; metadata-only rows still have a reclaimable charge. Source/FIND-item `tokens` measure source content, not the observation's context footprint. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page differs. All use stable curation weights, not provider tokens or dollars. Native component accounting follows {§packet-attachment-parts}; ordinary addressability and truthful errors follow {§log-wire-format}.
|
|
2366
2415
|
|
|
2367
2416
|
### §retrieval-packet-metadata READ/FIND packet metadata
|
|
2368
2417
|
|
|
@@ -2412,41 +2461,40 @@ single line past the end, a reversed range, empty content, a command's log row
|
|
|
2412
2461
|
|
|
2413
2462
|
### §emission-row The emission row
|
|
2414
2463
|
|
|
2415
|
-
Every admitted emission is announced by one row of its own turn
|
|
2416
|
-
|
|
2417
|
-
like any other row.
|
|
2464
|
+
Every admitted content emission is announced by one curatable row of its own turn.
|
|
2465
|
+
Eligible programs supply {§emission-history}; every source remains readable regardless of replay.
|
|
2418
2466
|
|
|
2419
2467
|
| Surface | Contract |
|
|
2420
2468
|
|---|---|
|
|
2421
2469
|
| When | An inference turn that admitted at least one content statement. Reasoning-only turns, including initialization ({§worker-initialization-entry}), a programmatic batch, an empty turn ({§empty-turn}), a client operation and a rejected attempt ({§rejected-emission-entry}) announce nothing. |
|
|
2422
2470
|
| Place | After the turn's inputs (arrivals, deltas, open-path READs) and before its reasoning NOTEs and operations, written after the selection snapshot ({§turn-ops-selection-snapshot}): the emission sits between what the worker had seen and what it caused. |
|
|
2423
2471
|
| Row | A `_plurnk` READ of the turn's own source, `ops://<worker>/L/T`, with `attrs.kind="emission"` and the canonical leaf `/emission`: `### log:///L/T/S/emission → ops://<worker>/L/T · N`. It renders its author, the turn's producer, as `origin`, so a model's row carries none. It is no operation: no receipt, tool call or strike, and outside the op mix. |
|
|
2424
|
-
| Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of the admitted content statements, each whole in a closed fence. All heading operands, scopes, metadata, patterns and asides remain.
|
|
2425
|
-
| Wire |
|
|
2472
|
+
| Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of the admitted content statements, each whole in a closed fence, text beside them as the NOTEs it became ({§outside-text}). All heading operands, scopes, metadata, patterns and asides remain. Unadmitted forms are absent; a recovered native call ({§native-tool-calls}) appears as the operation it was read as; an operation whose receipt failed stays. Reasoning operations retain their own source and normal receipts, never an assistant-content copy. No body text is inspected for nested operations. |
|
|
2473
|
+
| Wire | The record appears in the log; its complete program supplies the readback projection in {§emission-history}. The frozen body and immutable `ops://` source keep every operation and body ({§turn-source-resources}); an explicit READ returns them. |
|
|
2426
2474
|
| Stability | The projection is fixed from its first appearance, never aged or resized under budget pressure. Already frozen announcements and historical request captures are not rewritten. |
|
|
2427
|
-
| Presentation | Born folded: the record shows its header,
|
|
2428
|
-
| Accounting | `tokens` charges
|
|
2429
|
-
| Curation | Curated whole ({§log-kill-scope}): KILL retires it
|
|
2430
|
-
| Schema | Migration 12 admits `kind="emission"` only on this shape: one per turn, the turn's newest row when written, frozen, and curated whole
|
|
2475
|
+
| Presentation | Born folded: the log record shows its header, never an assistant message. When its turn is replayed ({§emission-history}), the record's lines are the legend of that turn's NOTEs, one numbered line per NOTE with its `log:///` path and weight, and those NOTE rows render nowhere else. |
|
|
2476
|
+
| Accounting | The row's `tokens` charges only its rendered record, legend included. The optional emission-history section is measured once as assistant-message text ({§packet-token-accounting}); replacing it never changes older row weights. An explicit source READ has its own ordinary charge. |
|
|
2477
|
+
| Curation | Curated whole ({§log-kill-scope}): the unscoped KILL retires it. A line scope on its exact coordinate addresses the legend: the NOTEs on the selected lines retire and the row stays; on a row with no legend lines the scope is 422 `emission-curated-whole`, whose recovery names the unscoped KILL; a sweep whose scope would only trim it leaves it intact. |
|
|
2478
|
+
| Schema | Migration 12 admits `kind="emission"` only on this shape: one per turn, the turn's newest row when written, frozen, and curated whole; it backfills no announcement for earlier turns. FORK copies it with the inherited turns, still naming its writer. |
|
|
2431
2479
|
| Echoes | A worker that repeats the heading in its own text is tolerated ({§fabricated-log-entry}); the digest counts the echoes. |
|
|
2432
2480
|
|
|
2433
2481
|
### §reasoning-row The reasoning row
|
|
2434
2482
|
|
|
2435
|
-
The model's memory of its own reasoning, behind `PLURNK_SERVICE_REASONING_ROWS` (default `
|
|
2483
|
+
The model's optional memory of its own reasoning, behind `PLURNK_SERVICE_REASONING_ROWS` (default `0`):
|
|
2436
2484
|
when it is `1`, every model turn that reasoned lands its reasoning as one row of its
|
|
2437
2485
|
own, `log:///<loop>/<turn>/<sequence>/reasoning → reasoning://<worker>/<loop>/<turn>`, the harness's
|
|
2438
2486
|
READ of the turn's reasoning source, immediately before the turn's emission row (or its first
|
|
2439
2487
|
operation or diagnostic when there is no content emission), so the transcript
|
|
2440
|
-
reads what the model thought and
|
|
2441
|
-
|
|
2488
|
+
reads what the model thought and where its content program can be found
|
|
2489
|
+
({§emission-row}, {§packet-wire-envelope}).
|
|
2442
2490
|
|
|
2443
2491
|
| Concern | Rule |
|
|
2444
2492
|
|---|---|
|
|
2445
2493
|
| Room | Admission occurs after all mandatory turn rows, including the emission and diagnostics, using the remaining room under {§context-fit}. Its earlier chronological coordinate is reserved without inserting a placeholder; if it does not fit, that coordinate remains unused. Nothing else changes: no partial preview, refusal, or other row touched. Reasoning-only and empty model turns follow the same rule; content operations are not required. |
|
|
2446
|
-
| Body |
|
|
2494
|
+
| Body | `PLURNK_SERVICE_REASONING_TRAILING_LINES=-1` selects the complete reasoning without either shared preview bound. A positive value selects that many trailing lines within `PLURNK_SERVICE_PREVIEW_CHARS`; unset/empty uses `PLURNK_SERVICE_PREVIEW_LINES`. Zero is invalid. Keep complete final lines where possible; if the last line alone exceeds the character bound, select its suffix with the ordinary exact column scope. Unicode code points count once and CRLF is one indivisible separator, as in {§body-projection}. The statement carries the scope it took and the receipt its `range` ({§packet-extent-metadata}); the complete reasoning stays readable at its address by any scope ({§turn-source-resources}). This setting does not change ordinary READ/FIND previews. |
|
|
2447
2495
|
| Weight | Charged like any row, visible in the gauge and its `largest` ({§context-gauge}). |
|
|
2448
2496
|
| Curation | The verbs alone: a KILL retires it like any row ({§context-verbs}); the daemon reorders nothing and un-bodies nothing on its account. |
|
|
2449
|
-
| Absence |
|
|
2497
|
+
| Absence | Disabled, no room, or no reasoning. The setting does not affect reasoning-operation admission or the readable `reasoning://` source ({§reasoning-operations}, {§turn-source-resources}). |
|
|
2450
2498
|
|
|
2451
2499
|
### §turn-source-resources Immutable turn-source resources
|
|
2452
2500
|
|
|
@@ -2465,7 +2513,7 @@ the canonical program ({§emission-row}, {§packet-wire-envelope}).
|
|
|
2465
2513
|
|
|
2466
2514
|
- §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with ```` ```READ (worker:///docs/) ````. A complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: the native operation name or invoked executor name, `/attempt` for a rejected emission, `/emission` for an admitted one's announcement ({§emission-row}). An executor leaf is derived from the durable submitted statement (its `runtime`), never an internal dispatch type or the current tool registry. Digits and punctuation in executor names remain part of the leaf. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. READ anchors use the canonical suffixed identity even when addressed by shorthand. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ`, `log:///**/python3`, `log:///**/attempt`, and `log:///**/emission` deliberately filter canonical leaves. Executor outputs instead use workspace-wide claims such as `sh:///ab3d5678#stdout` ({§execution-output-identity}); their source operation has log coordinates, but resource lifetime and identity are independent of that observation. Error pointers, Problem instances, source attribution, and search use this same identity; client stream coordinates retain the numeric triple. Within a turn, sequence is arrival order. Inbound SEND rows publish before the program runs ({§message-arrival}); a turn receiving messages holds the first at `log:///L/T/1/SEND`, followed by further arrivals oldest first, then its emission's announcement, then the model's operations ({§packet-current-turn} names `L/T`).
|
|
2467
2515
|
- §log-near-miss **A log miss beside rows that exist names them.** A READ, FIND or KILL of an exact coordinate that names no row carries a recovery from the worker's own active rows: the turn's rows carrying the leaf written come first, since the leaf is what the model asked for and the sequence its guess, followed by the row at that coordinate under its own leaf (`` Turn 1/44's reasoning is `log:///1/44/2/reasoning`; the entry at log:///1/44/1 is `log:///1/44/1/READ`. ``); with no row of that leaf, the row at the coordinate alone (`` The entry at log:///1/25/8 is `log:///1/25/8/sh`. ``), else the turn's rows, at most six named, else the loop's latest turn. A coordinate in a loop with no rows carries none. Recorded misses were near misses every time: a READ of `1/25/8/READ` when the row was `sh`, an EDIT one sequence off, and a KILL under the 413 that must curate (#1005).
|
|
2468
|
-
- §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — KILL takes a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: ```` ```KILL (log:///1/2) <1,-1> ```` suppresses turn 1/2's bodies and retires its emission ({§emission-row}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`.
|
|
2516
|
+
- §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — KILL takes a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: ```` ```KILL (log:///1/2) <1,-1> ```` suppresses turn 1/2's bodies and retires its emission ({§emission-row}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`.
|
|
2469
2517
|
- §log-curation-set-selection **Row selection and body scope are independent** — target/glob and an optional heading pattern (```` ```KILL (log:///**) [{"pattern": "~stale"}] ````, every dialect a FIND over rows accepts) compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. An emission row is curated whole instead: the scope retires it when it covers every line and otherwise leaves it ({§emission-row}). Thus ```` ```KILL (log:///**/READ) <17,-1> ```` may change long READs and no-op on short ones while reporting every selected row in `matched`.
|
|
2470
2518
|
|
|
2471
2519
|
§log-kill-meta-operation **A log KILL changes working context, never the underlying resources or execution history.** Receipt visibility depends on the target and result, not the producer, attribution, or age of the turn:
|
|
@@ -2540,7 +2588,7 @@ per-operation projection on `rx`; the aggregate remains inside dispatch.
|
|
|
2540
2588
|
| `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
|
|
2541
2589
|
| `parseIssues.before`, `parseIssues.after` | `parseIssues` as `before→after` | Parser-recovery counts for complete source and landed revisions; omitted when both are clean or either is unavailable. |
|
|
2542
2590
|
| `effect.source`, `result` | `effect` as `<source> -> <result>` | Resolved scopes mapping the source snapshot into the landed body; the admitted marker stays in durable `requested` and `tx`. |
|
|
2543
|
-
| `effect.removed`, `inserted` | `change` | Removed and inserted counts
|
|
2591
|
+
| `effect.removed`, `inserted` | `change` | Removed and inserted counts led by the receipt unit, as `extent` is: `lines -7 +7`. |
|
|
2544
2592
|
| `effect.removedText` | `removed` | {§edit-receipt-removed-text}: a pure deletion's removed text, its first `PLURNK_SERVICE_EDIT_RECEIPT_REMOVED_LINES` lines; absent when the edit inserted anything. |
|
|
2545
2593
|
| `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. A pattern batch's `last` context follows the first's when it differs, with no blank line between: every line of a row body carries its coordinate. |
|
|
2546
2594
|
| `disposition`, `requested` | `disposition`, `requested` | A reviewer-replaced batch preserves the authored marker while stating that its attributed effect was superseded. |
|
|
@@ -2704,7 +2752,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2704
2752
|
matches the selected channel's content or derivation; path globs select
|
|
2705
2753
|
resources through `(target)` ({§path-glob}).
|
|
2706
2754
|
- §find-fulltext-selection Every matcher operates only over the candidate set selected by `(target)`; indexed matchers do not bypass that selection. `~query` passes the native FTS5 expression to SQLite and ranks matching candidates by ascending BM25, with resource identity breaking ties. Native BM25 uses the shared index's term statistics; candidate visibility, owner, channel and target filters determine which resources can be returned. The ordinary FIND pager selects resources for broad targets or match locations for exact targets: markerless search uses {§markerless-first-page}, `<N>` selects position N and `<N,M>` selects an inclusive range. Fractions are invalid result coordinates, not similarity thresholds. Results expose addressable matched text regions; neither cosine scores nor percentage similarity is invented. Native query-syntax failures return 400 with SQLite's diagnostic; database and implementation failures propagate.
|
|
2707
|
-
- §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`).
|
|
2755
|
+
- §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`). An FTS5 failure keeps SQLite's own message as its `diagnostic`, and its recovery is the dialect's form, never a rewrite of the query ({§diagnostic-observation}): `` An FTS5 query is barewords, "quoted phrases", and AND, OR, NOT and NEAR between them. ``
|
|
2708
2756
|
- §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
|
|
2709
2757
|
- §find-result-projection **The resolved target selection determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsWeightTotal, returnedItemsWeightTotal }`:
|
|
2710
2758
|
|
|
@@ -2720,8 +2768,8 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2720
2768
|
with no addressable location is status 200 with `matchingPathCount: 1`,
|
|
2721
2769
|
`matchLocationCount: 0`, and no fabricated row; a matcher selecting no
|
|
2722
2770
|
resource is 204. A matcher-less broad empty catalog survey is status 200; an
|
|
2723
|
-
absent exact resource is 404. Every entry-channel location
|
|
2724
|
-
|
|
2771
|
+
absent exact resource is 404. Every entry-channel location in `results` names
|
|
2772
|
+
its `channel`; log rows carry none.
|
|
2725
2773
|
|
|
2726
2774
|
Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
|
|
2727
2775
|
complete selection before pagination; the packet curates those facts under
|
|
@@ -2740,9 +2788,11 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2740
2788
|
code points including a visible terminal ellipsis, so a row stays one line
|
|
2741
2789
|
of orientation; an invocation-form witness — a summary that is one fenced
|
|
2742
2790
|
operation, the shape a runtime's tool summary takes
|
|
2743
|
-
({§tools-resource-materialization})
|
|
2744
|
-
|
|
2745
|
-
|
|
2791
|
+
({§tools-resource-materialization}), kept on one summary line by writing each
|
|
2792
|
+
newline as `\n` — is shown whole, every tool named and its newlines restored
|
|
2793
|
+
so the row's JSON escapes each once, because the discovery row exists so the
|
|
2794
|
+
model can invoke without a READ and a menu that is cut is no menu. Absent
|
|
2795
|
+
metadata is omitted.
|
|
2746
2796
|
|
|
2747
2797
|
Resource-level `stream` and broad-match
|
|
2748
2798
|
`matchLocationCount` live only on `[0]`. A single-channel resource is therefore
|
|
@@ -2760,11 +2810,15 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2760
2810
|
rank for `~`full-text and candidate order otherwise; location order is dialect
|
|
2761
2811
|
order and exact duplicates deduplicate. The intended drill-down is broad FIND
|
|
2762
2812
|
to choose paths, exact-target FIND to choose locations, then exact READ.
|
|
2763
|
-
`content` uses the shared generated-JSON projection
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2813
|
+
`content` uses the shared generated-JSON projection ({§json-result-rendering}),
|
|
2814
|
+
so universal packet numbering makes result ordinal N addressable as line N,
|
|
2815
|
+
matching `<N>` pagination without a second coordinate system. It translates
|
|
2816
|
+
only this final model-facing representation: `weight` reads `tokens`, a
|
|
2817
|
+
`region` or `enclosingRegion` reads in the one scope notation `<SL,SC,EL,EC>`
|
|
2818
|
+
({§packet-extent-metadata}), and a location names its `channel` only when that
|
|
2819
|
+
is not the resource's default channel ({§channel-selection-visibility}). A
|
|
2820
|
+
location therefore reads `{"region":"<48,1,48,25>","matched":"class BaseCrossValidator"}`.
|
|
2821
|
+
A returned page begins at `range.returned[0]`, and every
|
|
2768
2822
|
page left-pads its ordinals to the decimal width of `range.total`; content
|
|
2769
2823
|
therefore keeps one stable column across the complete result set. Pagination is the only FIND materialization bound; no
|
|
2770
2824
|
hidden complete row or location collection is retained behind the public
|
|
@@ -2774,8 +2828,56 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2774
2828
|
|
|
2775
2829
|
SEND AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, metadata, lineMarker }`.
|
|
2776
2830
|
|
|
2777
|
-
- **Message:** SEND delivers to an actor, endpoint or exact message address. Targetless SEND
|
|
2778
|
-
- **Workflow:** WAIT yields.
|
|
2831
|
+
- **Message:** SEND delivers to an actor, endpoint or exact message address. Targetless SEND selects the oldest published Open Message. Only explicit completion metadata resolves a message ({§message-completion}).
|
|
2832
|
+
- **Workflow:** WAIT yields. The loop concludes from resolved messages, settled work and observed results ({§loop-completion}). NOTE retains memory; KILL names something to cancel or curate.
|
|
2833
|
+
|
|
2834
|
+
§message-completion **Reply delivery and message completion are distinct.**
|
|
2835
|
+
|
|
2836
|
+
| Reply metadata | Delivery | Message obligation |
|
|
2837
|
+
|---|---|---|
|
|
2838
|
+
| No completion code | Deliver the authored text and attachments | Remains open |
|
|
2839
|
+
| `[200]` | Deliver the final answer | Completed |
|
|
2840
|
+
| `[499]` | Deliver the cancellation explanation | Cancelled; no worker or execution is cancelled implicitly |
|
|
2841
|
+
|
|
2842
|
+
The numeric modifier belongs to SEND's reply metadata, not its text scope. It
|
|
2843
|
+
composes with attachment metadata. Completion applies only to replies: an exact
|
|
2844
|
+
message address selects that message. Targetless SEND selects the oldest published
|
|
2845
|
+
Open Message in its loop at dispatch time. Progress leaves it open; `[200]` or
|
|
2846
|
+
`[499]` resolves it, so the next targetless SEND selects the next Open Message.
|
|
2847
|
+
With none open, a targetless SEND is speech to the loop's latest published message: it is
|
|
2848
|
+
delivered to that message's originating client and recorded in `answers`, and a completion
|
|
2849
|
+
code on it changes no outcome. Only a loop with no published message refuses it. It never
|
|
2850
|
+
broadcasts; a correction that changes an outcome names the message explicitly. Empty completion replies
|
|
2851
|
+
resolve their selected messages without inventing speech or erasing an earlier
|
|
2852
|
+
answer. An empty addressed progress reply adds no speech. Failed delivery resolves nothing.
|
|
2853
|
+
The latest explicit completion reply determines each message's outcome; ordinary
|
|
2854
|
+
progress replies never reopen a completed message. Curation changes neither
|
|
2855
|
+
delivery nor completion. Replies and ambient observations do not become requests.
|
|
2856
|
+
|
|
2857
|
+
Completion replies execute in authored order, including alongside mutations and
|
|
2858
|
+
other replies. Their bodies are delivered immediately, never held as drafts to
|
|
2859
|
+
replay. Later results can require further work or a corrected answer without
|
|
2860
|
+
retracting an earlier delivery. The message outcome is distinct from the SEND
|
|
2861
|
+
operation's delivery status and from the loop's execution outcome.
|
|
2862
|
+
After all obligations settle, the loop succeeds if any message completed; it is
|
|
2863
|
+
cancelled only when every message was cancelled. This does not invoke worker-tree
|
|
2864
|
+
cancellation. Engine failures retain their own outcomes.
|
|
2865
|
+
|
|
2866
|
+
§loop-completion **The loop concludes from discharged obligations, not a terminating operation.**
|
|
2867
|
+
A model loop is eligible only when all its messages have explicit completion
|
|
2868
|
+
replies, every held child and non-detached stream has settled, and every required
|
|
2869
|
+
result has crossed a packet boundary. New arrivals guard the terminal transition
|
|
2870
|
+
atomically. An operation-free turn creates no additional observation obligation;
|
|
2871
|
+
it is neither a completion command nor a separate acknowledgement mode. NOTE and
|
|
2872
|
+
successful curation retain the observation exemptions in {§send-premature-terminate}.
|
|
2873
|
+
With unresolved messages, no-operation recovery still applies. Malformed emissions,
|
|
2874
|
+
known output truncation, omitted operations and provider failures cannot conclude
|
|
2875
|
+
the loop by absence of operations. Administrative programs close only their own
|
|
2876
|
+
transaction.
|
|
2877
|
+
|
|
2878
|
+
When all messages are resolved but new results require another packet, the engine
|
|
2879
|
+
reports only: `All Open Messages resolved. Review new results; emit no OPs if finished.`
|
|
2880
|
+
The notice creates no state and does not demand another final reply.
|
|
2779
2881
|
|
|
2780
2882
|
§worker-obligations A worker holds its unresolved children and open non-detached
|
|
2781
2883
|
streams (`worker_obligations`); `loop_obligations` names them per loop. The
|
|
@@ -2789,19 +2891,19 @@ same durable liveness.
|
|
|
2789
2891
|
| Worker or loop already cancelled/terminal | Preserve that result. |
|
|
2790
2892
|
| Administrative program | Finish its transaction without adjudicating another model loop's work. |
|
|
2791
2893
|
| New unpublished message | Continue; publish it in the next packet. |
|
|
2792
|
-
| Fresh operation/parser failure, without an authored WAIT | Continue before any automatic parking. |
|
|
2793
|
-
|
|
|
2794
|
-
|
|
|
2795
|
-
|
|
|
2894
|
+
| Fresh operation/parser failure or incomplete emission, without an authored WAIT | Continue before any automatic parking. |
|
|
2895
|
+
| Authored WAIT and live work | Park the same loop; message arrival, child or stream settlement, or wait expiry wakes it ({§worker-wait-timing}). |
|
|
2896
|
+
| Fresh failure or incomplete emission after an empty WAIT | Continue; the WAIT cannot conceal the failure. |
|
|
2897
|
+
| Any unresolved message | Continue; an operation-free turn receives {§empty-turn} recovery. |
|
|
2796
2898
|
| Unobserved operation results, failures, child results or stream conclusions | Continue; the next packet presents them. |
|
|
2797
|
-
|
|
|
2899
|
+
| All messages resolved and results observed, live work remains | Join that work with the configured bounded park. Replies remain delivered. |
|
|
2900
|
+
| All messages resolved, results observed, no live work | Conclude with the aggregate message outcome ({§message-completion}). |
|
|
2798
2901
|
|
|
2799
2902
|
An empty emission is handled by {§empty-turn}. Ordinary strikes, cycles and
|
|
2800
|
-
execution limits remain independent.
|
|
2801
|
-
|
|
2802
|
-
and every other operational result require observation.
|
|
2903
|
+
execution limits remain independent. Observation exemptions follow
|
|
2904
|
+
{§send-premature-terminate}; they never resolve a message implicitly.
|
|
2803
2905
|
|
|
2804
|
-
§loop-response-messages **A response is a recorded delivery.** A successful SEND reply
|
|
2906
|
+
§loop-response-messages **A response is a recorded delivery.** A successful SEND reply records
|
|
2805
2907
|
the exact message addresses it answers. All replies remain independently recoverable in
|
|
2806
2908
|
message history, in execution order, regardless of producer. An actor-addressed SEND that
|
|
2807
2909
|
does not answer a message, WAIT, NOTE, asides, inherited rows and ambient observations are
|
|
@@ -2828,67 +2930,52 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2828
2930
|
or a scheme that implements SEND (an `https://` POST). A SEND to a scheme the model may not write (the
|
|
2829
2931
|
log) is refused 400 `send-target-not-a-recipient`, never the unrelated writer
|
|
2830
2932
|
rule. The detail states only that the addressed scheme is not a recipient;
|
|
2831
|
-
|
|
2832
|
-
|
|
2933
|
+
recovery names valid recipients without guessing which was intended.
|
|
2934
|
+
A scheme that does not implement SEND
|
|
2833
2935
|
answers its ordinary factual 501 without grafting a guessed recovery onto it.
|
|
2834
2936
|
- §send-response-receipt **A reply records exactly which messages it answers.** A successful
|
|
2835
|
-
reply carries `answers`, the immutable message addresses it answered, not recipient actors.
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
delivers nothing, carries no `answers`, and cannot erase an earlier reply. An accepted
|
|
2840
|
-
parameterless KILL answer uses the same reply routing and empty-body rules. SEND to an exact message
|
|
2937
|
+
reply carries `answers`, the immutable message addresses it answered, not recipient actors.
|
|
2938
|
+
Targetless replies select the oldest published Open Message or, with none open, the
|
|
2939
|
+
loop's latest published message as speech only ({§message-completion}); they never broadcast.
|
|
2940
|
+
Empty completion replies still name their messages. SEND to an exact message
|
|
2841
2941
|
address answers only that message; SEND to an actor endpoint remains ordinary communication
|
|
2842
2942
|
and answers no assignment implicitly. An unpublished arrival cannot be answered by the
|
|
2843
2943
|
targetless shorthand. Failed delivery answers nothing. Reply accounting reads executed
|
|
2844
2944
|
delivery evidence, never log visibility or the mere existence of a later SEND.
|
|
2845
|
-
- §
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
KILL delivers its literal body through {§send-response-receipt}; a deferred body
|
|
2856
|
-
remains forensic evidence, never a stored draft to replay automatically. An empty
|
|
2857
|
-
KILL concludes silently even when an observed message has no delivered answer. It neither
|
|
2858
|
-
invents delivery nor replaces an earlier answer; immutable input and reply history remain intact.
|
|
2859
|
-
SEND, NOTE and targeted KILL never request successful
|
|
2860
|
-
completion. New arrivals still guard the terminal transition atomically
|
|
2861
|
-
({§completion-defers-to-messages}); an unobserved arrival concurrent with completion
|
|
2862
|
-
keeps the loop running. No implicit successful exit exists.
|
|
2863
|
-
- §outside-text **Text outside the operations is the turn's `outside` source: stored, weighed, never a row.**
|
|
2864
|
-
The spans {§response-text} supplies are stored verbatim as one immutable `outside` turn source
|
|
2865
|
-
per admitted emission, in source order joined by a blank line ({§turn-source-resources}); no
|
|
2866
|
-
operation is minted for them, a repetitive or length-cut response stays one source, and nothing
|
|
2867
|
-
filters what is stored. The model hears only the weight: the next packet's Notices section
|
|
2868
|
-
carries `outside_text: N tokens emitted outside OPs. Discarded.`, N by {§tokenomics-agnostic-ruler};
|
|
2869
|
-
the text itself never enters a packet, not even inside its turn's emission ({§emission-row}), is never delivered and never concludes.
|
|
2870
|
-
{§empty-turn} still strikes a turn that holds only text, with unchanged
|
|
2871
|
-
reply accounting and completion rules. A log-entry heading in
|
|
2945
|
+
- §outside-text **Text outside the operations is annotation beside them, and an empty turn without them.**
|
|
2946
|
+
The spans {§response-text} supplies are read with the turn's fenced operations. Beside at least one
|
|
2947
|
+
fenced content operation, each span is one `NOTE` at its position: it joins the admitted program as the
|
|
2948
|
+
model's own NOTE, frozen in the emission ({§emission-row}), lands as a NOTE row, replays with its turn
|
|
2949
|
+
({§emission-history}) and draws no notice; the card's annotation register is where such text belongs.
|
|
2950
|
+
With no fenced operation in the turn, no operation is minted: the spans are stored verbatim as one
|
|
2951
|
+
immutable `outside` turn source per admitted emission, in source order joined by a blank line
|
|
2952
|
+
({§turn-source-resources}), a repetitive or length-cut response stays one source, nothing filters what
|
|
2953
|
+
is stored, and the turn is an empty turn ({§empty-turn}) whose error row is the one thing the model
|
|
2954
|
+
hears of it; the text never enters a packet, is never delivered and never concludes. A log-entry heading in
|
|
2872
2955
|
outside text still rejects the attempt unless it echoes an emission row ({§fabricated-log-entry}); an unfenced operation line is
|
|
2873
|
-
not response text ({§unfenced-operation}) and so
|
|
2956
|
+
not response text ({§unfenced-operation}) and so reaches neither home. Clients receive an outside source once through
|
|
2874
2957
|
`outside/event` ({§notifications-outside-event}, {§agui-outside-text}); FORK snapshots the
|
|
2875
2958
|
source with the turn's others; the digest names its weight. It has no address: there is no
|
|
2876
2959
|
`outside://` scheme, and exact emissions remain at `ops://`. This is evidence, not an alternate
|
|
2877
2960
|
authoring format: the `plurnk.md` requirement to use only valid Plurnk OPs remains, and
|
|
2878
2961
|
{§response-text} alone owns which bytes are operations, quotations or outside text.
|
|
2879
2962
|
- §loop-answer **A loop's address is what it said.** READ `ops://<worker>/<loop>` resolves to
|
|
2880
|
-
the latest reply the loop gave to the message that started it: the body of a SEND
|
|
2881
|
-
|
|
2963
|
+
the latest nonempty reply the loop gave to the message that started it: the body of a SEND
|
|
2964
|
+
that answered that message. A failed terminal takes precedence over
|
|
2882
2965
|
an earlier reply and retains its exact Problem, including {§terminal-evidence}. A running loop
|
|
2883
2966
|
without a reply is 425; a concluded loop without one returns its terminal outcome, including
|
|
2884
2967
|
successful silence. Completion never fabricates an answer or a missing-resource failure.
|
|
2885
2968
|
`ops://<worker>/<loop>/<turn>`
|
|
2886
2969
|
remains that turn's emission. A concluded child's `loop_termination` row to its parent
|
|
2887
2970
|
READs this same loop resource. Witness: `test/intg/loop-answer.test.ts`.
|
|
2888
|
-
- §empty-turn **No
|
|
2971
|
+
- §empty-turn **No operations resolve no messages.**
|
|
2889
2972
|
Count parsed content operations and admitted reasoning operations ({§reasoning-operations}), a NOTE in
|
|
2890
|
-
either channel among them; outside text ({§outside-text}) never enters the count. When none exist
|
|
2891
|
-
|
|
2973
|
+
either channel among them; outside text ({§outside-text}) never enters the count. When none exist,
|
|
2974
|
+
no boundary was lost, and messages remain unresolved or the emission is known incomplete,
|
|
2975
|
+
retain the turn and its raw sources and count one progress-contract strike, whether or not
|
|
2976
|
+
the turn carried text. Once messages are resolved, an intact operation-free turn is adjudicated
|
|
2977
|
+
normally under {§loop-completion}; absence of operations is not a new lifecycle signal.
|
|
2978
|
+
The strike sends no notice of its own: the turn records one `_plurnk`
|
|
2892
2979
|
error row, `422` `The turn performed no operation.`, which rides the next packet's errors like
|
|
2893
2980
|
any failure ({§operation-result-uniform-error-channel}); the threshold terminal still says why ({§engine-rails}).
|
|
2894
2981
|
An empty turn uses its exact text as the cycle fingerprint ({§engine-cycle-evidence});
|
|
@@ -2907,7 +2994,7 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2907
2994
|
({§turn-ops-entry}: the reader READs the source, and an emission of any length never rides
|
|
2908
2995
|
wholesale into a parent's packet). The member is named for what it is — an emission left
|
|
2909
2996
|
unconcluded — and never `answer`: the harness cannot warrant that text is complete or final,
|
|
2910
|
-
because
|
|
2997
|
+
because its obligations did not settle under {§loop-completion}. Earlier deliveries remain delivered;
|
|
2911
2998
|
the citation neither sends them again nor destroys them. A terminal whose last inference
|
|
2912
2999
|
turn performed authored operations carries no `unconcluded`: an absent member is not an
|
|
2913
3000
|
empty one. Attachment is owned by the one terminal seam.
|
|
@@ -2919,25 +3006,22 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2919
3006
|
executions, WORK and FORK own their input and receive it whole ({§send-resource-attachments},
|
|
2920
3007
|
{§env-option}); a key they do not take is their own 400.
|
|
2921
3008
|
- §send-idle-turn **NOTE is memory, not a yield.** NOTE does not imply parking.
|
|
2922
|
-
A NOTE-only response does not
|
|
3009
|
+
A NOTE-only response does not resolve a message or create an observation obligation.
|
|
3010
|
+
The ordinary obligation check still runs ({§loop-completion}).
|
|
2923
3011
|
Repetition remains subject to {§engine-cycle-evidence}.
|
|
2924
3012
|
- §send-premature-terminate **Completion follows observation.** Every fired operation except
|
|
2925
3013
|
SEND, NOTE, WAIT and successful KILL requires a subsequent packet. This barrier uses durable
|
|
2926
3014
|
executed evidence, not curated rows. Fast completion, an empty result or curation cannot
|
|
2927
3015
|
erase it. New arrivals are protected by {§completion-defers-to-messages}; no terminal verb
|
|
2928
3016
|
or prose overrides this rule.
|
|
2929
|
-
- §completion-joins-live-work **
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
own disposition. Only targeted KILL owns cancellation; parameterless KILL never
|
|
2934
|
-
cancels work and delivers no final answer while joining.
|
|
3017
|
+
- §completion-joins-live-work **Resolved messages do not abandon held work.** Once messages
|
|
3018
|
+
and observation obligations are resolved, the loop joins live children and non-detached
|
|
3019
|
+
streams through the existing bounded wait. Each wake presents newly settled state.
|
|
3020
|
+
Neither completion nor message cancellation cancels that work.
|
|
2935
3021
|
- §completion-defers-to-results **Results keep the loop running until observed.** Same-turn
|
|
2936
3022
|
operations and failures, plus undelivered child or stream conclusions, require the next
|
|
2937
|
-
packet. This is ordinary continuation, not a strike.
|
|
2938
|
-
|
|
2939
|
-
replies remain delivered. If observation warrants no further work or revision, a
|
|
2940
|
-
lone empty parameterless KILL requests completion without repeating an earlier answer.
|
|
3023
|
+
packet. This is ordinary continuation, not a strike. SEND replies remain delivered.
|
|
3024
|
+
If observation warrants no further work or revision, no additional operation is needed.
|
|
2941
3025
|
- §send-administrative-terminal **Administrative programs close their own transaction.**
|
|
2942
3026
|
Their caller closes the administrative loop after execution; no terminal operation is
|
|
2943
3027
|
manufactured. Initialization runs in the model loop without concluding it.
|
|
@@ -2946,7 +3030,8 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2946
3030
|
observed only after crossing a packet boundary. WAIT parks only on
|
|
2947
3031
|
live obligations. If work has completed but is unobserved, it continues
|
|
2948
3032
|
directly to the next packet because the wake edge has already fired. A genuinely
|
|
2949
|
-
empty wait
|
|
3033
|
+
empty wait creates no future wake; ordinary obligation adjudication still applies
|
|
3034
|
+
under {§wait-obligation-matrix}.
|
|
2950
3035
|
|
|
2951
3036
|
### §exec-input SEND to a running execution
|
|
2952
3037
|
|
|
@@ -2984,21 +3069,18 @@ target scheme, before effect admission or source acquisition. Core validates the
|
|
|
2984
3069
|
preparation result and retains its cwd; it neither parses option names nor
|
|
2985
3070
|
redirects metadata to a source scheme. An executor without preparation accepts
|
|
2986
3071
|
no metadata. A `script`-kind target ({§executor-invocation}) is the program: core inspects it before
|
|
2987
|
-
anything spawns — a file is the script; a directory is refused `400 target-not-a-program
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
recovery names that executor's fence — `` `python3` is its own executor; use that name on the
|
|
2993
|
-
opening fence and put the program in the body. ``; otherwise it points at an existing script or a bare shell-command body. A non-file resource
|
|
3072
|
+
anything spawns — a file is the script; a directory is refused `400 target-not-a-program`;
|
|
3073
|
+
an absent path is refused `400 target-not-found`, stating what exists and inferring nothing
|
|
3074
|
+
({§diagnostic-observation}): a registered tool of another executor is named with that executor,
|
|
3075
|
+
another available executor as its own executor (`` `python3` is its own executor. ``), and
|
|
3076
|
+
anything else as a target that must name an existing program resource. A non-file resource
|
|
2994
3077
|
target that cannot be read keeps the owning READ's failure identity (#163) and states
|
|
2995
|
-
the slot contract in its recovery
|
|
2996
|
-
a command belongs beneath a targetless heading — without guessing which was meant (#425). The started receipt always
|
|
3078
|
+
the slot contract in its recovery: the resource is the program and the body its stdin. The started receipt always
|
|
2997
3079
|
names the working directory only when it is not the project root, and then in the
|
|
2998
3080
|
project-relative form ({§fs-namespace}); the default directory is omitted rather
|
|
2999
3081
|
than repeated in every receipt. Native file addresses resolve from that same project
|
|
3000
3082
|
directory, while absolute input retains its filesystem meaning. The `(path)` is a program — a script for an interpreter, a tool name for a tool
|
|
3001
|
-
|
|
3083
|
+
runtime — and neither a command nor a working directory is ever a target. The default
|
|
3002
3084
|
shell is written as its own fence, ```` ```sh ````; no runtime-less form exists.
|
|
3003
3085
|
|
|
3004
3086
|
§exec-target-near-miss Two target near-misses have one reading each and are read
|
|
@@ -3012,16 +3094,16 @@ real stream id is always the program source.
|
|
|
3012
3094
|
|
|
3013
3095
|
§exec-target-documentation **Generated reference is never a program.** A resource target under
|
|
3014
3096
|
`worker:///_plurnk/` — the executor and scheme documentation the harness generates — is refused
|
|
3015
|
-
at admission, 400 `target-is-documentation`, before any source is realized or run: `` `worker:///_plurnk/plurnk/sh.md` is reference documentation the harness generated, not a program; sh cannot run it. ``
|
|
3097
|
+
at admission, 400 `target-is-documentation`, before any source is realized or run: `` `worker:///_plurnk/plurnk/sh.md` is reference documentation the harness generated, not a program; sh cannot run it. `` It carries no recovery ({§diagnostic-observation}). Admitting it realized the markdown as a host temporary file that a sandboxed runtime could not open (`cannot open /tmp/plurnk-exec-….md`), and ran markdown where it could.
|
|
3016
3098
|
|
|
3017
3099
|
§exec-tool-fall-through **A tool run as a shell command is named at the failure
|
|
3018
3100
|
site.** A bare shell command whose program is the name of a tool published by
|
|
3019
3101
|
another enabled runtime (`brave_web_search {…}` under the default shell) exits
|
|
3020
|
-
127; the stream's terminal receipt then says the program is
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
`
|
|
3024
|
-
registry does not know keeps the
|
|
3102
|
+
127; the stream's terminal receipt then says the program is a tool of that
|
|
3103
|
+
runtime, names the tool's own document, and carries `toolRuntimes` and `tool`;
|
|
3104
|
+
it builds no invocation ({§diagnostic-observation}). That receipt is core's `404 program-is-a-tool` with
|
|
3105
|
+
`exitCode: 127`: the named program did not run. Nothing is rerouted, and a program the
|
|
3106
|
+
registry does not know keeps the shell's own answer, a 200 receipt with `exitCode: 127`.
|
|
3025
3107
|
|
|
3026
3108
|
| Declared target kind | Authored target | Canonical effect target | Executor realization |
|
|
3027
3109
|
| -------------------- | --------------------------------------- | ----------------------- | --------------------------------------------------------- |
|
|
@@ -3043,7 +3125,7 @@ effect classification or proposal creation.
|
|
|
3043
3125
|
A runtime with {§executor-tool-registry} admits only the snapshot's exact
|
|
3044
3126
|
literal targets. An absent target is 400; a target outside that closed enabled
|
|
3045
3127
|
set is 404; neither reaches effect classification or proposal creation. The
|
|
3046
|
-
selected entry's invocation—not the
|
|
3128
|
+
selected entry's invocation—not the runtime's structural fallback—owns body
|
|
3047
3129
|
requiredness and roles. The executor independently rejects an unregistered
|
|
3048
3130
|
target at its run boundary.
|
|
3049
3131
|
|
|
@@ -3131,12 +3213,12 @@ addressed to `<runtime>:///<id>` when the id holds an execution only under anoth
|
|
|
3131
3213
|
§exec-lifetime **How long a spawn may live is the fence's metadata, one field.**
|
|
3132
3214
|
`[{"lifetime": …}]` takes a duration (`30s`, `30m`, `2h`), or one of three words;
|
|
3133
3215
|
absent is `loop`. The key is one of the service's reserved metadata keys, withheld
|
|
3134
|
-
from every owner by the framework ({§service-metadata-keys}). An execution takes no scope: a
|
|
3135
|
-
|
|
3216
|
+
from every owner by the framework ({§service-metadata-keys}). An execution takes no scope: a scope on an
|
|
3217
|
+
execution is refused `scope-unsupported` (400).
|
|
3136
3218
|
|
|
3137
3219
|
| `lifetime` | The spawn |
|
|
3138
3220
|
| ------------ | --------- |
|
|
3139
|
-
| a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504** `execution-timeout`, distinct from a deliberate kill (499) or a clean exit (200): `` Execution of '*runtime*' outlived its *lifetime* lifetime. ``
|
|
3221
|
+
| a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504** `execution-timeout`, distinct from a deliberate kill (499) or a clean exit (200): `` Execution of '*runtime*' outlived its *lifetime* lifetime. `` |
|
|
3140
3222
|
| `loop` (absent) | Loop-life bounded: reaped on every loop terminal except 202, the background-stream behavior. |
|
|
3141
3223
|
| `turn` | Reaped at the worker's next pre-turn via the registry abort, before the turn's own spawns, so it never survives into the subsequent turn; its terminal output surfaces born visible like any close ({§exec-stream}). |
|
|
3142
3224
|
| `detached` | Outlives its loop's terminal, 200 included. It never binds to the loop's teardown and is nobody's obligation — completion is not gated by it, WAIT does not park on it, optimistic settlement looks past it — and it ends only by KILL, the worker's total reap, or daemon shutdown; its late conclusion surfaces without opening a loop. |
|
|
@@ -3148,7 +3230,7 @@ stream deltas. Calendar recurrence remains a schedule ({§schedule-delivery}).
|
|
|
3148
3230
|
|
|
3149
3231
|
§exec-host-proposes **Effect-gating.** Each executor — and each scheme operation that mutates something outside this process — declares an `effect` (`pure` | `read` | `host`); the service maps it to policy (`EffectPolicy`). The declarer states the FACT, the panel decides the POLICY, and one rule covers every operation: nothing that changes the world runs on nobody's authority. A `host` runtime (subprocess; file-backed sqlite) proposes under {§proposal}, and so does an outbound request that mutates a remote resource ({§http-outbound-proposes}). Once accepted, it spawns and writes channels at its workspace execution address ({§execution-output-identity}), returning `102 Processing`. Channel state transitions (`active` → `closed`/`errored`) drive subsequent observations ({§channel-state}).
|
|
3150
3232
|
|
|
3151
|
-
§entry-owner **Every entry belongs directly to one workspace.** Its immutable identity is `(workspace_id, scheme, authority, pathname)`. The workspace foreign key supplies lifetime; URI authority supplies the literal resource namespace.
|
|
3233
|
+
§entry-owner **Every entry belongs directly to one workspace.** Its immutable identity is `(workspace_id, scheme, authority, pathname)`. The workspace foreign key supplies lifetime; URI authority supplies the literal resource namespace. Core binds one canonical coordinate through {§entry-address-resolution} for every operation and consumer. Producer and subscriber Worker ids describe causal activity, not ownership.
|
|
3152
3234
|
|
|
3153
3235
|
§execution-output-identity **Execution output belongs to the workspace.**
|
|
3154
3236
|
Each invocation claims a collision-checked eight-character lowercase hexadecimal
|
|
@@ -3235,8 +3317,8 @@ it: an immediate slot is `200 { outcome: "started" }`; delayed work is
|
|
|
3235
3317
|
`202 { outcome: "queued", executionsAhead, concurrency }`, and the channel stays
|
|
3236
3318
|
`active` in the existing live sense — output growth and terminal settlement are the
|
|
3237
3319
|
current truth. Admission is FIFO within the workspace; queue residence does not consume
|
|
3238
|
-
the execution timeout; a KILL while queued never invokes the executor and
|
|
3239
|
-
stream
|
|
3320
|
+
the execution timeout; a KILL while queued never invokes the executor and concludes the
|
|
3321
|
+
stream as any KILL does ({§stream-control}). The scheduler is the exec scheme's; the knob is the
|
|
3240
3322
|
service's ({§operator-config}), fail-hard on any other value.
|
|
3241
3323
|
|
|
3242
3324
|
§exec-stream-page **An unrequested delivery never exceeds the retrieval page.** The
|
|
@@ -3260,7 +3342,10 @@ channel that holds content, and an empty sibling channel is a fact on that row
|
|
|
3260
3342
|
(`channels: {"#stderr": 0}`), never a row of its own; only a stream that printed
|
|
3261
3343
|
nothing on any channel lands one bodyless conclusion row, on its default
|
|
3262
3344
|
channel, whose terminal fact, causal execution link, and available exit code make
|
|
3263
|
-
completion explicit without invented narration. A
|
|
3345
|
+
completion explicit without invented narration. A failed execution is one failure: its
|
|
3346
|
+
terminal status and Problem ride its default channel's row when that row landed, else its
|
|
3347
|
+
first, and its other rows are 200 reads of their channels, so it puts one pointer in Errors
|
|
3348
|
+
({§operation-results}). A skipped channel's publication is still marked
|
|
3264
3349
|
terminal, so the stream's termination is delivered and never left pending. KILL may curate
|
|
3265
3350
|
that log row without rewinding the cursor or publishing the terminal result
|
|
3266
3351
|
again; the exact terminal result and channel content remain READable at the
|
|
@@ -3390,10 +3475,10 @@ Core derives the contracts-owned `ProposalProjection` from the durable proposed
|
|
|
3390
3475
|
| `target` | canonical `{ scheme, authority, pathname }` from `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
|
|
3391
3476
|
| `body` | proposed operation result `rx.body`; absent means the empty review body |
|
|
3392
3477
|
| `attrs` | proposed log row `attrs` object |
|
|
3393
|
-
| `
|
|
3478
|
+
| `owner` | the worker's durable workspace-scoped approval owner ({§worker-ownership}) |
|
|
3394
3479
|
| `disposition` | {§proposal-disposition}; the same value drives automatic settlement and client presentation |
|
|
3395
3480
|
|
|
3396
|
-
Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes,
|
|
3481
|
+
Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes, owner registration, or final projection fails at core with its cause; after insertion, core terminalizes that row as a 500 `policy_failed` before propagating the internal failure, so no waiter or durable stopped world is orphaned.
|
|
3397
3482
|
|
|
3398
3483
|
### §client-interactions Client-owned interaction lifecycle
|
|
3399
3484
|
|
|
@@ -3402,7 +3487,8 @@ A scheme or executor may pause its current operation on one
|
|
|
3402
3487
|
pending-only `client_interactions` row bound to one exact
|
|
3403
3488
|
workspace/worker/loop/turn ownership chain, then publishes the same validated
|
|
3404
3489
|
`ClientInteractionProjection` through `loop/interaction` and reconnect
|
|
3405
|
-
discovery. The projection
|
|
3490
|
+
discovery. The projection names its recipient ({§client-interaction-routing}) but
|
|
3491
|
+
contains no workspace id or private upstream
|
|
3406
3492
|
continuation state; those remain respectively in the event envelope and the
|
|
3407
3493
|
awaiting operation owner.
|
|
3408
3494
|
|
|
@@ -3420,112 +3506,44 @@ composes it with the existing owner signal before registering the same waiter.
|
|
|
3420
3506
|
Reconnect discovery intersects durable rows with live waiters; restart
|
|
3421
3507
|
removes ownerless rows without fabricating cancellation, payload, or replay.
|
|
3422
3508
|
|
|
3423
|
-
###
|
|
3424
|
-
|
|
3425
|
-
Side-effecting operations propose ({§exec}) and pause dispatch at 202 for an
|
|
3426
|
-
authority decision ({§engine-rails}, {§methods}). Automatic acceptance has two
|
|
3427
|
-
distinct owners:
|
|
3509
|
+
### Server disposition and client YOLO
|
|
3428
3510
|
|
|
3429
|
-
| Mechanism
|
|
3430
|
-
|
|
|
3431
|
-
|
|
|
3432
|
-
|
|
|
3433
|
-
|
|
3434
|
-
Core cannot distinguish client-side YOLO from a fast human acceptance and does
|
|
3435
|
-
not need to. Loop auto keeps authority inside the loop; client-side YOLO acts
|
|
3436
|
-
only after authority crosses the client boundary.
|
|
3511
|
+
| Mechanism | Authority path |
|
|
3512
|
+
| --- | --- |
|
|
3513
|
+
| Server disposition | `PLURNK_SERVICE_PROPOSALS` selects review, accept, or reject. Core settles automatic decisions through the normal proposal lifecycle. |
|
|
3514
|
+
| Client-side YOLO | The owning client accepts review requests through the same resolution path as human review. It cannot override server rejection or capability admission. |
|
|
3437
3515
|
|
|
3438
|
-
§proposal-ownership-notification
|
|
3516
|
+
§proposal-ownership-notification The notification carries the selected
|
|
3517
|
+
`ProposalDisposition`, not policy inputs. Clients present only `decision: "review"`
|
|
3518
|
+
addressed to their owner identity; they never reconstruct authority from the
|
|
3519
|
+
operation, message sender, or attrs.
|
|
3439
3520
|
|
|
3440
3521
|
### §proposal-disposition Settlement authority and precedence
|
|
3441
3522
|
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
ring, the reason and the recovery — a subtracted tool must say why it is gone and what to do
|
|
3467
|
-
instead. Every other ring is operator configuration and speaks for itself; the loop ring is the
|
|
3468
|
-
one the model can act on. The 501 at the interaction itself is the backstop for the paths that
|
|
3469
|
-
do not cross dispatch (MCP elicitation raised inside a tool call, the execution-input bridge).
|
|
3470
|
-
The ring reaches dispatch but not the reserved tree's listing, which is one artifact per
|
|
3471
|
-
workspace: an unattended model still sees the question document and learns at dispatch that it
|
|
3472
|
-
is refused (#770).
|
|
3473
|
-
- **A provider-recovery park becomes a conclusion** ({§provider-recovery}), carrying the
|
|
3474
|
-
provider's own exact Problem. Never a substituted "the model gave up".
|
|
3475
|
-
|
|
3476
|
-
**A park is a promise that something will restart it.** `LoopLifecycle.park` takes the waker
|
|
3477
|
-
by name; `null` says nothing will. Parking an unattended loop with no waker is a contract
|
|
3478
|
-
violation and throws, so a park site added later fails loudly on its first unattended run
|
|
3479
|
-
instead of idling until some caller's clock notices. It is a tripwire, not a fallback: the
|
|
3480
|
-
provider-recovery path concludes before reaching it.
|
|
3481
|
-
|
|
3482
|
-
Attendance never converts a legitimate wait that has a real waker — a `WAIT`, an open stream,
|
|
3483
|
-
a delegated child — into a termination. Those have wakers; a human question
|
|
3484
|
-
does not. A prompt prefix states a disposition, never an attendance: typing `?` asks for review,
|
|
3485
|
-
and an unattended loop refuses that statement rather than conjuring a reviewer.
|
|
3486
|
-
|
|
3487
|
-
§loop-policy-composition **A loop's policy is what its creator stated over what the panel
|
|
3488
|
-
says.** A creator — a client's `loop.run`, a schedule definition, a transport module — states
|
|
3489
|
-
any part of a policy as a `LoopPolicyRequest`, or nothing. The request stays exactly as stated
|
|
3490
|
-
until a fresh loop is persisted: an omitted field is no opinion, so a fold compares only what
|
|
3491
|
-
was said ({§methods-loop-run-fold-consistency}). `LoopPolicies.compose` then makes it whole,
|
|
3492
|
-
once. `PLURNK_SERVICE_ATTENDED` answers an unstated attendance, and the attendance picks which
|
|
3493
|
-
knob answers an unstated disposition: `PLURNK_SERVICE_PROPOSALS` for an attended loop,
|
|
3494
|
-
`PLURNK_SERVICE_UNATTENDED_PROPOSALS` for an unattended one, whose vocabulary has no `review`.
|
|
3495
|
-
Every valid panel state is therefore lawful; an invalid knob is diagnosed at startup
|
|
3496
|
-
and refuses a loop that needs it ({§configuration-repair-path}). No code,
|
|
3497
|
-
schema or column holds a default ({§operator-config-only-home}): `loops.policy` and
|
|
3498
|
-
`loops.max_turns` carry none, so every insert states both. Client-authored administrative
|
|
3499
|
-
loops use the same composition.
|
|
3500
|
-
|
|
3501
|
-
§runtime-bookkeeping-policy **Runtime bookkeeping has no reviewer and cannot acquire
|
|
3502
|
-
new authority.** Its administrative loops explicitly state
|
|
3503
|
-
`{ attended: false, proposals: "reject" }`; this is a runtime invariant, not an
|
|
3504
|
-
interactive default. Generated reference publication and audit narration therefore
|
|
3505
|
-
do not depend on client policy configuration. Runtime-authored proposals do not
|
|
3506
|
-
use effect-policy auto-admission; bookkeeping proposals settle as failures through
|
|
3507
|
-
the ordinary proposal lifecycle, never wait for a client or auto-accept.
|
|
3508
|
-
|
|
3509
|
-
§loop-policy-effective-read `loops.policy` persists one complete immutable
|
|
3510
|
-
`LoopPolicy`; every runtime policy read validates that snapshot before use.
|
|
3511
|
-
Missing rows or invalid values fail with the owning loop coordinate and cause.
|
|
3512
|
-
Raw archival copies and forensic rendering do not interpret policy.
|
|
3513
|
-
|
|
3514
|
-
The cascade's rings are `service`, `workspace` and, innermost, `loop`. The loop ring exists only
|
|
3515
|
-
for an unattended run and is purely subtractive like every other layer, so it can never widen what
|
|
3516
|
-
its workspace allows; a capability denial names the ring that refused. The operator's capability
|
|
3517
|
-
projection and the shared reserved-document materialization take no loop coordinate on purpose:
|
|
3518
|
-
those questions are about a workspace, not about one run.
|
|
3519
|
-
|
|
3520
|
-
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
|
|
3521
|
-
|
|
3522
|
-
| `policy.proposals` | Disposition |
|
|
3523
|
-
| ------------------ | ---------------------------------------- |
|
|
3524
|
-
| `review` | client |
|
|
3525
|
-
| `accept` | loop accept |
|
|
3526
|
-
| `reject` | loop reject, outcome `no_review_channel` |
|
|
3527
|
-
|
|
3528
|
-
Capability admission precedes this decision, so proposal disposition cannot grant a denied capability. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
|
|
3523
|
+
| First applicable condition | Disposition |
|
|
3524
|
+
| --- | --- |
|
|
3525
|
+
| Runtime bookkeeping | reject, `runtime_bookkeeping` |
|
|
3526
|
+
| Server `accept` | accept |
|
|
3527
|
+
| Server `reject` | reject, `policy_veto` |
|
|
3528
|
+
| Server `review`, owner implements `request_approval` | review |
|
|
3529
|
+
| Server `review`, owner has no reviewer | reject, `no_review_channel` |
|
|
3530
|
+
|
|
3531
|
+
Core selects the disposition once for the pending gate. Its live event and
|
|
3532
|
+
reconnect projection use that same decision. Automatic settlement precedes
|
|
3533
|
+
observational notification; an observer failure cannot change authority or orphan
|
|
3534
|
+
a waiter. Invalid configuration is diagnosed at the proposal boundary without
|
|
3535
|
+
substituting authority ({§configuration-repair-path}). Client-authored
|
|
3536
|
+
administrative operations retain their client's owner.
|
|
3537
|
+
|
|
3538
|
+
§runtime-bookkeeping-policy Runtime bookkeeping cannot acquire new authority.
|
|
3539
|
+
Generated reference publication and audit narration have no reviewer and do not
|
|
3540
|
+
depend on interactive defaults. An unexpected bookkeeping proposal rejects through
|
|
3541
|
+
the ordinary lifecycle, even if the server would accept other operations.
|
|
3542
|
+
|
|
3543
|
+
A park requires a live obligation or an interactive owner. Connection presence
|
|
3544
|
+
does not determine capability. Ordinary WAIT on streams or delegated work is
|
|
3545
|
+
unchanged; a provider-recovery park whose owner is not interactive concludes on the
|
|
3546
|
+
provider failure ({§provider-recovery}).
|
|
3529
3547
|
|
|
3530
3548
|
---
|
|
3531
3549
|
|
|
@@ -3535,7 +3553,7 @@ Capability admission precedes this decision, so proposal disposition cannot gran
|
|
|
3535
3553
|
|
|
3536
3554
|
### §subscriptions Subscriptions
|
|
3537
3555
|
|
|
3538
|
-
§subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. Worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation
|
|
3556
|
+
§subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. Worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation callback or database access is part of the extension contract.
|
|
3539
3557
|
|
|
3540
3558
|
The durable row is lifecycle evidence and the lookup key, not a serialized callback. `subscriptions.open()` establishes both halves before yielding a composed `StreamSubscription`: an `AbortSignal` whose fused `notifyChunk` and terminal `close` methods are safe to retain without the operation's general `SchemeCtx`. `close(result, summary?, channelResults?)` validates one universal terminal producer result plus exact named channel overrides. One SQLite transition closes the subscription and installs each channel's terminal `producerResult`; its lifecycle state derives from that result. The transition then wakes the worker when appropriate and unregisters the live handle. `close_status` is a constrained relational projection of `close_result.status`, never an independent result, while `channel_results` preserves historical overrides after a later subscription replaces the channel's current evidence. A durable open row without a live handle is an explicit lifecycle failure, never a fabricated cancellation success. Channel state ({§channel-state}) + log entries ({§no-chunk-rows}) carry lifecycle.
|
|
3541
3559
|
|
|
@@ -3584,6 +3602,7 @@ Model sees lifecycle events in the `log` section per turn.
|
|
|
3584
3602
|
|
|
3585
3603
|
- **Cancel:** ```` ```KILL (https://feed.example/x) ```` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
|
|
3586
3604
|
- **Kill:** ```` ```KILL (sh:///ab3d5678) ```` — the model terminates the addressed workspace stream. This is stream control, not a write: the output scheme's `writableBy` never gates it. A stream that already ended, killed or not, answers 200 with its recorded `terminalStatus`: the process is not running, which is what KILL asks for (#757); a stream that never existed answers 404 ({§runtime-resource-binding}). A queued execution ({§exec-concurrency}) is cancelled the same way and never enters its executor.
|
|
3605
|
+
- §stream-asked-stop **A stop that was asked for is no failure.** A stream stopped by a model KILL of either form from the worker that holds it concludes 200, with its `exitCode` when its producer reported one: the producer's 499 cancellation is replaced before the subscription settles, so the KILL's 200 receipt is the record and the conclusion row brings nothing into Errors ({§operation-results}). A cancellation its holder did not ask for — a peer's or a client's KILL, loop end, worker teardown, daemon stop — keeps its 499, and a lifetime keeps its 504.
|
|
3587
3606
|
- **WebSocket write:** ```` ```EDIT (wss://feed/x) ```` or ```` ```SEND (wss://feed/x) ```` with a body sends one whole text frame through the active owner. Either write can follow the opening READ in the same turn under {§op-execution-order}.
|
|
3588
3607
|
- **Other stream write:** ```` ```SEND (…) ```` remains scheme-defined, including exec stdin.
|
|
3589
3608
|
|
|
@@ -3612,12 +3631,12 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3612
3631
|
| Concern | Rule |
|
|
3613
3632
|
|---|---|
|
|
3614
3633
|
| §db-schema-baseline Baseline | Versions 1–8 of `migrations/` are the released baseline, as domain chapters — `001_workspaces`, `002_workers`, `003_loops`, `004_inference`, `005_entries`, `006_log`, `007_subscriptions`, `008_interactions` — each one `MIGRATE` block whose version is the file's numeric prefix. They create the shape 1.21.1 shipped: tables, indexes, views, the constraint triggers that are a table's invariants (guards that only `RAISE`), and a view's `INSTEAD OF` write path. No migration holds an `INIT` block or a trigger that writes a row. |
|
|
3615
|
-
| §db-migrations Evolution | A released version is frozen: only its comments may change. Every shape change is one new file at the next version
|
|
3634
|
+
| §db-migrations Evolution | A released version is frozen: only its comments may change. Every shape change is one new file at the next version, applied by sqlrite above the database's `PRAGMA user_version`, ascending, each in its own transaction with its version bump. A fresh database takes the same path as an existing one. Each migration carries upgrade coverage: `test/intg/schema-baseline.test.ts` pins the released shape's fingerprint and migrates a released database, asserting its rows survive. A process trigger's change needs no migration: its `INIT` block re-declares it on the next open ({§db-process-triggers}). Foreign keys stay enforced. Prefer column changes or guard-trigger replacement; rebuilding a referenced table requires copying its complete referencing subgraph first and replacing children before parents, with retained-row and foreign-key coverage. Dropping a parent alone would cascade away its children. |
|
|
3616
3635
|
| §validation-topology Where an invariant is enforced | The SQL core owns each invariant: a chapter's CHECK constraints and guard triggers are its one statement, and a rule two tables share is the same expression over each column (`entry_channel_producer_result_contract` and `subscriptions_result_contract_update` hold the settled-result rule as one text, `011_settled`). Contracts (JSON Schema) are enforced at the gates: a scheme's result entering core (`Results` in plurnk-schemes) and the wire leaving to clients (plurnk-agui's `Validator` calls). Everything between trusts core and the gates and carries no defensive re-validation: a result read back from a row is parsed, never re-asserted. Witness: `test/intg/validation-topology.test.ts` applies one corpus of settled results to the gate, to chapter 5 and to chapter 7 and asserts the three agree on every row. |
|
|
3617
3636
|
| Open failure | A missing table or column after migration means the file's shape disagrees with its version: a database from a newer release, or one from an unreleased development build. The daemon refuses to open it and names both remedies. |
|
|
3618
3637
|
| §db-process-triggers Processes beside their owners | A trigger that writes rows — a cascade, a capture, an ambient event, a publication cursor, a landed curation — is a process, not shape. It is declared as an `-- INIT: <trigger name>` block in the `.sql` file beside the statements that fire it (`ambient.sql` for the ambient feed, `LoopLifecycle.sql`, `Turn.sql`, `Engine.sql` for model calls, `_entry-crud.sql`, `Log.sql`, `ChannelWrite.sql`), as `DROP TRIGGER IF EXISTS` then `CREATE TRIGGER`, so the definition is current on every open of a database whose shape is current. `MIGRATE` always precedes `INIT` and `INIT` runs on the writer only, so a process may reference any table regardless of file order and never runs on the read pool. `test/intg/schema-composition.test.ts` fails on a baseline trigger that writes, an `INIT` trigger that only guards, a block not named after its trigger or not dropping first, and a live trigger set that differs from the declared set after a first and a second open. |
|
|
3619
3638
|
| §db-fk-indexes Foreign-key check paths | Every foreign-key column a delete, cascade, or parent replacement can check carries an index (partial where the column is nullable), and no registry statement's plan scans a growing table: `test/intg/schema-query-plans.test.ts` runs `EXPLAIN QUERY PLAN` over every `-- PREP` statement against the baseline and fails on a `SCAN` of a growing table, except statements that read a whole table by design (digest, startup recovery, whole-workspace listings, scheduled-loop claims). An index claim is a plan, never a grep of index names. |
|
|
3620
|
-
| §db-index-owners Every index has an owner | An explicit index earns its place one of three ways: a registry statement's plan uses it, its leading column is a foreign key whose check it serves, or it enforces uniqueness. The same test fails on any other index, naming it: an index nobody reads is a write on every insert.
|
|
3639
|
+
| §db-index-owners Every index has an owner | An explicit index earns its place one of three ways: a registry statement's plan uses it, its leading column is a foreign key whose check it serves, or it enforces uniqueness. The same test fails on any other index, naming it: an index nobody reads is a write on every insert. A column no statement reads is not stored. |
|
|
3621
3640
|
| §db-maintenance-optimize Statistics at shutdown | The daemon's last database step before the caller closes SQLite is `PRAGMA optimize` on the writer (`maintenance_optimize`), so `sqlite_stat1` reflects tables the connection planned against, bounded by SQLite's own analysis limit; a failure there is a reported shutdown error, never silent. Retention runs before it under the operator's policy ({§retention-policy}) and ends with a WAL truncation ({§db-space-reclamation}); no periodic `ANALYZE` runs. |
|
|
3622
3641
|
| §db-space-reclamation The daemon keeps its own file healthy | `PLURNK_SERVICE_AUTO_VACUUM` (`incremental` or `none`) names the mode the daemon keeps its file in. At start, before any drain, a database in another mode is converted (set the mode, one `VACUUM`, which rewrites the file and needs free disk about its size) and the journal says so with page counts before and after. Under `incremental`, every retention pass ends by stepping `PRAGMA incremental_vacuum` to completion once free pages reach `PLURNK_SERVICE_RECLAIM_MIN_FREE_BYTES` (0 = every pass), and reports `reclaimedPages`; below the floor, free pages stay for SQLite to reuse. Under `none` the file never shrinks and freed pages are reused. No operator step is involved beyond the knobs. The WAL stays bounded by SQLite's automatic checkpoint (#764). |
|
|
3623
3642
|
| §content-store Every body is stored once | `contents` holds each settled body once, addressed by its SHA-256, however many channels, workspaces, forks or derivations carry it; rows are immutable. `entry_channel_rows` points a settled channel at its body and keeps an active stream's body as a private buffer until it settles, when it is interned. Every reader and writer uses the `entry_channels` view, whose `INSTEAD OF` triggers intern bodies, refuse a bound `content_hash` that is not the content's, and write each column group only when it changed, so a search attachment is never a representation write. SQLite counts no changes for a view, so a write that must know whether its channel exists returns the channel's name; an outer join cannot flatten the view, so the two statements that need one read `entry_channel_rows` and `contents` directly. `derivation_fts` is an external-content index over `derivation_texts` (a derivation joined to its body); `derivations.content_id` names the indexed text, and the triggers in `_entry-fts.sql` move the index with it and forget it on delete. A body no channel holds and no derivation indexes is collected by retention under `PLURNK_SERVICE_COLLECT_CONTENTS`. Witnesses: `test/intg/retention.test.ts`, `test/intg/entries.test.ts`, `test/intg/fulltext-index.test.ts`. |
|
|
@@ -3626,6 +3645,26 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3626
3645
|
- DDL = storage truth; JSON Schemas = wire truth. They are allowed to differ where ergonomics demand.
|
|
3627
3646
|
- §entry-identity-no-null **Identity components are never NULL.** `(workspace_id, scheme, authority, pathname)` is a unique key. `workspace_id` references the workspace directly with cascading deletion. Namespace schemes use empty authority; resource schemes retain their canonical authority. File members use nonempty `scheme="file"` and render as bare paths. Registration refuses `storedScheme: null`.
|
|
3628
3647
|
|
|
3648
|
+
### §db-query-report Workload query report
|
|
3649
|
+
|
|
3650
|
+
`report:sql <database.db> [specimens.json]` is an on-demand diagnostic, not a gate.
|
|
3651
|
+
It snapshots only the named database under {§share-snapshot}, registers the production
|
|
3652
|
+
SQL functions, and plans the source PREPs through SqlRite's own parser. It neither
|
|
3653
|
+
migrates nor runs application INIT blocks on that snapshot. Schema mismatch and query
|
|
3654
|
+
errors remain report failures, not empty successful results.
|
|
3655
|
+
|
|
3656
|
+
| Evidence | Meaning |
|
|
3657
|
+
|---|---|
|
|
3658
|
+
| `plans` | Unbound `EXPLAIN QUERY PLAN` rows for every effective PREP, including mutations; no mutation is executed. |
|
|
3659
|
+
| `scans` | Conservative hints: named table/view, indexed, virtual, or unresolved alias/intermediate. Raw details remain authoritative; a scan is not itself a defect. |
|
|
3660
|
+
| `measurements` | Only supplied `{statement, parameters}` specimens execute, with SQLite's query-only guard. Each retains its bound plan, row count, and one elapsed measurement; row bodies are not retained. |
|
|
3661
|
+
|
|
3662
|
+
Timings cover SQLite stepping and row conversion in the report process against the
|
|
3663
|
+
compacted private snapshot, not daemon IPC, application work, cold-cache latency, or a
|
|
3664
|
+
statistical distribution. No implicit workload discovery, synthetic corpus, automatic
|
|
3665
|
+
sampling, or performance threshold is applied. The report changes neither source data
|
|
3666
|
+
nor the existing query-plan gate.
|
|
3667
|
+
|
|
3629
3668
|
### §sql-ts-boundary SQL/TS responsibility boundary
|
|
3630
3669
|
|
|
3631
3670
|
**Lives in SQL:**
|
|
@@ -3652,10 +3691,10 @@ When SQL becomes onerous for a specific case, retreat for that case and document
|
|
|
3652
3691
|
|
|
3653
3692
|
## §core-extension-composition Extension composition
|
|
3654
3693
|
|
|
3655
|
-
The metaproject contract owns installed membership, the one-
|
|
3694
|
+
The metaproject contract owns installed membership, the one-kind manifest
|
|
3656
3695
|
shape, and the shared pre-import trust boundary ({§extension-discovery}). Each
|
|
3657
3696
|
framework owns its typed discovery result and trusted loading path.
|
|
3658
|
-
Core owns only cross-
|
|
3697
|
+
Core owns only cross-kind composition, arbitration, and operator presentation
|
|
3659
3698
|
of skipped-package evidence.
|
|
3660
3699
|
|
|
3661
3700
|
§extension-namespace-arbitration **Every addressable scheme name has one claim.**
|
|
@@ -3669,14 +3708,14 @@ claiming either name, for process-wide and workspace-scoped registrations alike.
|
|
|
3669
3708
|
| Existing claim | Incoming claim | Outcome |
|
|
3670
3709
|
|--------------------------------|---------------------------------------------------------|---------|
|
|
3671
3710
|
| None | Any valid claim | Register it. |
|
|
3672
|
-
| Same installed
|
|
3711
|
+
| Same installed kind/package | Rescan of the same name | No-op; retain the one registered handler. |
|
|
3673
3712
|
| Reserved core name | Any extension, a module included | Fail naming the reserved owner and claimant. |
|
|
3674
3713
|
| Any extension | A different owner, including scheme/executor either way | Fail naming both owners. |
|
|
3675
3714
|
| Module runtime | Its optional same-registration scheme facet | Compose one handler under the runtime's single claim. |
|
|
3676
3715
|
|
|
3677
3716
|
Arbitration precedes host registry mutation. External scheme descriptors are
|
|
3678
3717
|
arbitrated before core imports their handlers; executor packages have already
|
|
3679
|
-
crossed their
|
|
3718
|
+
crossed their framework-owned trusted loading path when core arbitrates their
|
|
3680
3719
|
output faces. A rejected claim leaves both scheme and executor registries
|
|
3681
3720
|
unchanged, so registration order cannot turn a collision into precedence.
|
|
3682
3721
|
Installed third-party packages enter through the same scope-agnostic npm
|
|
@@ -3687,15 +3726,15 @@ registration.
|
|
|
3687
3726
|
|
|
3688
3727
|
## §bundled-set Bundled Set
|
|
3689
3728
|
|
|
3690
|
-
|
|
3729
|
+
Extension discovery ({§extension-discovery}) scans installed scoped and unscoped
|
|
3691
3730
|
packages carrying the applicable `plurnk.kind` declaration.
|
|
3692
3731
|
|
|
3693
3732
|
§default-extension-ownership `@plurnk/plurnk-service` is the sole manifest owner
|
|
3694
3733
|
of the default extensions. Frameworks own contracts, discovery, and loading;
|
|
3695
3734
|
their runtime dependency graphs contain no extension of their kind. A required
|
|
3696
3735
|
default extension missing from a service install is a broken install. A direct
|
|
3697
|
-
framework consumer may intentionally omit
|
|
3698
|
-
documented
|
|
3736
|
+
framework consumer may intentionally omit extensions and receives that framework's
|
|
3737
|
+
documented behavior for an absent extension.
|
|
3699
3738
|
|
|
3700
3739
|
`@plurnk/plurnk-tavily-plugin` is the separately installed, opt-in plugin showcase,
|
|
3701
3740
|
not a service dependency. Its own tests own installation, native discovery,
|
|
@@ -3711,7 +3750,7 @@ service runtime dependency, and an optional one ({§mimetype-optional-grammars})
|
|
|
3711
3750
|
must not be. Installation coverage loads each default grammar and verifies
|
|
3712
3751
|
source definitions, references, structural projections, and teardown outside
|
|
3713
3752
|
the checkout's development dependency graph, and proves each optional language
|
|
3714
|
-
degrades by name when its
|
|
3753
|
+
degrades by name when its grammar package is absent.
|
|
3715
3754
|
|
|
3716
3755
|
§install-root-advisory-ownership **The composed service install owns
|
|
3717
3756
|
third-party advisory detection.** Only that install resolves the default extensions
|
|
@@ -3719,20 +3758,19 @@ and their combined transitive tree. Its audit reports advisories at the
|
|
|
3719
3758
|
moderate floor without blocking by default; strict mode makes the same floor a
|
|
3720
3759
|
gate. A chain rooted through an `@plurnk/*` dependency routes to that package's
|
|
3721
3760
|
owner, while other direct roots remain service-owned. First-party package-pin
|
|
3722
|
-
freshness remains the owning
|
|
3761
|
+
freshness remains the owning package's concern.
|
|
3723
3762
|
|
|
3724
|
-
| Kind | Lean framework | Service-owned default
|
|
3763
|
+
| Kind | Lean framework | Service-owned default packages |
|
|
3725
3764
|
|-----------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
3726
3765
|
| Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
|
|
3727
|
-
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format
|
|
3728
|
-
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format
|
|
3729
|
-
| | | `image
|
|
3730
|
-
| Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite`
|
|
3766
|
+
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format extensions. |
|
|
3767
|
+
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format extensions. |
|
|
3768
|
+
| | | The `image` and `application-pdf` (header-only, {§mimetype-pdf-facts}) extensions, and every `grammar-{slug}` grammar package in the framework's tree-sitter registry ({§mimetype-grammar-packages}), all under `@plurnk/plurnk-mimetypes-*`. |
|
|
3769
|
+
| Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite` extensions under the `@plurnk/plurnk-execs-*` prefix. |
|
|
3731
3770
|
|
|
3732
|
-
The independently published `tokenizers` artifact is an opt-in
|
|
3771
|
+
The independently published `tokenizers` artifact is an opt-in package. Installing
|
|
3733
3772
|
it beside the service admits it through ordinary package resolution without
|
|
3734
|
-
changing the service manifest.
|
|
3735
|
-
native attachment like an image, and the daemon does no extraction (#542).
|
|
3773
|
+
changing the service manifest.
|
|
3736
3774
|
|
|
3737
3775
|
**Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
|
|
3738
3776
|
operator declarations, local adapters, and finally installed AI SDK provider
|
|
@@ -3820,8 +3858,8 @@ Node's pre-script env-file form and the executable's post-script form share the
|
|
|
3820
3858
|
| Agent Plugin extension | `ai.plurnk/.env.defaults` | The winning daemon-wide plugin in {§agent-plugins-hosting}, a valid native declaration, and the same trust gate |
|
|
3821
3859
|
|
|
3822
3860
|
Root and trust flags apply before collection. A project plugin contributes no native panel.
|
|
3823
|
-
Non-module native panels follow their npm-only
|
|
3824
|
-
a plain-folder declaration does not suppress an installed
|
|
3861
|
+
Non-module native panels follow their framework's npm-only discovery ({§extension-manifest-read});
|
|
3862
|
+
a plain-folder declaration does not suppress an installed extension's panel.
|
|
3825
3863
|
Linked packages resolve panels against the same canonical root as native code;
|
|
3826
3864
|
an absent panel is optional, but a panel escaping that root is rejected.
|
|
3827
3865
|
The file travels with its code and is its configuration reference. All admitted files compose
|
|
@@ -3831,6 +3869,24 @@ persisting another copy or exposing effective values. Duplicate key ownership fa
|
|
|
3831
3869
|
owners. Invalid optional native panels are diagnosed and prevent that extension from loading;
|
|
3832
3870
|
they do not block the remaining floor or the repair path ({§configuration-repair-path}).
|
|
3833
3871
|
|
|
3872
|
+
§operator-config-undeclared-key **A key no panel declares is reported, never refused.** At boot the
|
|
3873
|
+
daemon checks each `PLURNK_*` key the operator's configuration files set — `$XDG_CONFIG_HOME/plurnk/.env`
|
|
3874
|
+
and a `--config` file, never an `--env-file*` layer or the process environment — against the
|
|
3875
|
+
assembled panels' declarations, live and commented alike. A declaration whose name holds a
|
|
3876
|
+
`<placeholder>` segment declares a family and is only ever commented. A placeholder, like the scope
|
|
3877
|
+
after a declared name's `_`, stands for one or more letters, digits, `_`, `.` or `-`.
|
|
3878
|
+
|
|
3879
|
+
| Key the file sets | Outcome |
|
|
3880
|
+
|---|---|
|
|
3881
|
+
| A declared name | none |
|
|
3882
|
+
| A declared name, `_`, and a scope (`PLURNK_PROVIDERS_EFFORT_<alias>`, `PLURNK_MODEL_<alias>`) | none |
|
|
3883
|
+
| A family member (`# PLURNK_MCP_<alias>=` declares `PLURNK_MCP_docs_ENABLED`) | none |
|
|
3884
|
+
| Another component's: the client's `PLURNK_CLIENT_*` and `PLURNK_COMPOSITION_*`; the bench's `PLURNK_BENCH*`, `PLURNK_SWEBENCH_*`, `PLURNK_PI_*` and `PLURNK_CANDIDATE_*` | none |
|
|
3885
|
+
| Any other `PLURNK_*` key | one `info` Notice from `engine:configuration`, kind `configuration_undeclared`, naming the `key` and the file |
|
|
3886
|
+
|
|
3887
|
+
Boot continues. The notice is the operator's information: `start`, `config` and `config check` print
|
|
3888
|
+
it, `config check` still passes, and it never enters a model's packet.
|
|
3889
|
+
|
|
3834
3890
|
§operator-config-only-home **The cascading environment is the only home for a choice.** The principle and its reasons are ARCHITECTURE.md's (*Configuration authority*); this is what `scripts/env-surface-policy.mjs` enforces in `root:lint`, over the source Git tracks:
|
|
3835
3891
|
|
|
3836
3892
|
| Rule | What it refuses |
|
|
@@ -3842,7 +3898,6 @@ they do not block the remaining floor or the repair path ({§configuration-repai
|
|
|
3842
3898
|
| `tunable` | a numeric constant whose own name says duration, size, count or pacing, unless `scripts/env-surface-mechanism.json` registers why it is mechanism |
|
|
3843
3899
|
| `timer-literal` | a bare number handed to a timer or a deadline; it is named or read from the panel, and has no register |
|
|
3844
3900
|
| `dead-knob` | a live declaration nothing consumes |
|
|
3845
|
-
| `retired-declared` | a retired key still declared; a retired key is named only by the code that refuses it |
|
|
3846
3901
|
| `duplicate-owner` | a key two packages declare |
|
|
3847
3902
|
| `test-floor` | a package that ships a panel and tests off it |
|
|
3848
3903
|
|
|
@@ -3869,7 +3924,7 @@ names the offending variable or file/entry and retains its cause.
|
|
|
3869
3924
|
|
|
3870
3925
|
| Owner | Offline validation |
|
|
3871
3926
|
|---|---|
|
|
3872
|
-
| Core | Model selection, file-creation/effect/
|
|
3927
|
+
| Core | Model selection, file-creation/effect/approval policy, members definitions and controls, skill-fetch settings and root selection |
|
|
3873
3928
|
| MCP | Whole definitions from the environment and selected files (cwd is the project for this check), future-alias controls, catalog settings, timeouts, retry pacing and registry URL |
|
|
3874
3929
|
| A2A | Whole outbound definitions and controls, timeout/diagnostic bounds, configured inbound exposure |
|
|
3875
3930
|
| Schedule | Whole definitions and controls, recurrence syntax, time zone and preview count |
|
|
@@ -3898,18 +3953,19 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
|
|
|
3898
3953
|
|---|---|
|
|
3899
3954
|
| `PLURNK_SERVICE_DB_PATH` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
3900
3955
|
| `PLURNK_SERVICE_SHARE_FOLDER` | Parent of the shares written when no folder is named ({§share-folder}); empty is `$XDG_STATE_HOME/plurnk/shares`. |
|
|
3901
|
-
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The listener's bind address and TCP port
|
|
3956
|
+
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The daemon-owned listener's bind address and TCP port; modules mount their paths on that one listener ({§http-host}). **A key the daemon and its clients both read has a shared owner**: `@plurnk/plurnk-contracts` declares these two and the optional `PLURNK_AGUI_URL` on its own panel, the one package every side depends on. The daemon folds it like any installed member's, a client folds it beneath its own, and so neither holds the other's default. The service's `--host` and `--port` flags are generated from that panel. |
|
|
3902
3957
|
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
|
|
3903
3958
|
| §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
|
|
3904
3959
|
| `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
|
|
3905
3960
|
| `PLURNK_SERVICE_MAX_TURNS` | Operator model-call **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The durable worker-tree budget includes descendant calls, BARE, and park/resume under {§turn-cap-counts-the-tree}; non-model chronology consumes none. |
|
|
3906
3961
|
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every compiled op dispatches. Each resolved target statement counts once, whether authored separately or in a group ({§target-group}). Overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. Lifecycle operations remain exempt ({§operator-config-workspace-max-commands-floor}). Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
3907
3962
|
| §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | Positive ms of cumulative active execution per loop ({§loop-execution-allowance}); excludes parked/queued time. Snapshotted on first execution, retained across wakes. Exhaustion aborts in-flight work and terminates `504 loop_timeout`, including a stuck provider call. |
|
|
3908
|
-
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks
|
|
3963
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks workers with a reviewer, otherwise concludes their loop, or returns BARE's failure under {§provider-recovery}. |
|
|
3909
3964
|
| `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
|
|
3910
3965
|
| `PLURNK_SERVICE_MAX_STRIKES` | Consecutive turn-contract strike threshold ({§engine-rails}). |
|
|
3911
3966
|
| `PLURNK_SERVICE_EMISSION_ATTEMPTS` | Completed provider responses allowed beneath one engine turn before frame admission is exhausted. Bounded interior operation errors are admitted without spending this budget. Exhaustion contributes one frame-contract strike under {§invalid-emission-attempts}. |
|
|
3912
|
-
| `
|
|
3967
|
+
| `PLURNK_SERVICE_BUDGET_PRESSURE` | Budget percentage above which the gauge names its largest rows ({§context-gauge}) and a packet within its budget carries the `budget_pressure` notice ({§context-pressure-notice}); measured before adding either. |
|
|
3968
|
+
| `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` | How many of the heaviest retained log rows the pressured gauge names ({§context-gauge}). |
|
|
3913
3969
|
| `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | Minimum neighboring lines hashed on each side; repeated handles expand their context ({§line-anchor-disambiguation}). |
|
|
3914
3970
|
| `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
|
|
3915
3971
|
| `PLURNK_SERVICE_MIN_CYCLES` | Min repetitions before cycle detection fires ({§engine-rails}). |
|
|
@@ -3939,13 +3995,21 @@ Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
|
|
|
3939
3995
|
|
|
3940
3996
|
External extensions declare their own env vars in their own `.env.defaults`, assembled at boot ({§operator-config-env-defaults}).
|
|
3941
3997
|
|
|
3942
|
-
§operator-config-cli-flags **Admin CLI flags derive
|
|
3998
|
+
§operator-config-cli-flags **Admin CLI configuration flags derive from the service panel and the contracts-owned shared keys ({§operator-config-shared-keys}).** Each active `PLURNK_*` declaration becomes `--<kebab-cased-name>` (prefix stripped, lowercased, underscores → dashes). A comment immediately above the declaration becomes its `-h` description; undescribed flags still show their environment name and default. Installed extension defaults join the environment floor and catalog but do not implicitly expand the service executable's flag surface.
|
|
3999
|
+
|
|
4000
|
+
§service-posix-artifacts The service package ships `dist/man/plurnk-service.1`
|
|
4001
|
+
and Bash, Zsh and Fish scripts in `dist/completions/`, generated at build time
|
|
4002
|
+
from the same help and panel descriptors as the executable. Completion supplies
|
|
4003
|
+
command and long-option names plus ordinary filename completion; it does not
|
|
4004
|
+
start the service, inspect configuration values, or contact a provider. Installing
|
|
4005
|
+
the manual or enabling completion is explicit and documented in `INSTALL.md`.
|
|
3943
4006
|
|
|
3944
4007
|
### Loop limits
|
|
3945
4008
|
|
|
3946
4009
|
§turn-cap-counts-the-tree **The turn ceiling is the worker tree's budget of model
|
|
3947
4010
|
calls.** The owner is the current loop of the topmost ancestor-or-self worker that has
|
|
3948
|
-
one: for a tree a client started,
|
|
4011
|
+
one, excluding the runtime actor (origin `_plurnk`): for a tree a client started,
|
|
4012
|
+
the root worker's loop current when this loop began (its
|
|
3949
4013
|
`max_turns`: the client's `maxTurns` clamped by the operator ceiling below); a loop with no
|
|
3950
4014
|
such ancestor owns its own budget. Every model call on the owner's loop and on any later
|
|
3951
4015
|
loop of the owner's descendants spends it, emission turns and BARE calls alike, open or
|
|
@@ -3954,6 +4018,10 @@ terminal ({§loop-terminals}) when the ceiling is met; a BARE beyond the budget
|
|
|
3954
4018
|
429 `max-turns` before any provider call, so one turn cannot spend past it with a batch. A
|
|
3955
4019
|
child loop inherits the value and binds the same count.
|
|
3956
4020
|
|
|
4021
|
+
The runtime actor supplies no ceiling and does not combine otherwise independent model
|
|
4022
|
+
subtrees into one allowance. Its descendants still share their own model tree's ceiling.
|
|
4023
|
+
The shipped ceiling is `-1` (uncapped); client and transport defaults introduce no finite cap.
|
|
4024
|
+
|
|
3957
4025
|
§operator-config-max-turns-ceiling Enforcement is per-use-site — no central most-restrictive pass; each ceiling is checked where it bites. `PLURNK_SERVICE_MAX_TURNS` at `-1` is no cap; when an operator sets a positive value, the per-call request is `min()`-capped against it. Other termination rules remain independent ({§loop-terminals}).
|
|
3958
4026
|
|
|
3959
4027
|
### Workspace settings
|
|
@@ -3986,7 +4054,7 @@ leak into another.
|
|
|
3986
4054
|
workspace: a client tightens the runaway-op guard and never raises it past
|
|
3987
4055
|
the operator's.
|
|
3988
4056
|
- §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
|
|
3989
|
-
WAIT
|
|
4057
|
+
WAIT is never counted and always dispatch, so `0` is a valid
|
|
3990
4058
|
floor, admitting lifecycle intent with zero actions. Dropped actions still prevent
|
|
3991
4059
|
successful completion under {§turn-disposition}.
|
|
3992
4060
|
- §operator-config-workspace-git `settings.git` (`false`) **denies** git for the workspace (`PLURNK_SERVICE_GIT_ALLOWED` AND workspace) — the client opts its workspace out of git membership and working-tree status; it can never re-enable git past the operator's service-wide lockout.
|
|
@@ -4006,7 +4074,7 @@ the policy renders in exactly one packet section. Every other tier runs the
|
|
|
4006
4074
|
test cascade, so shipped-default regressions are otherwise invisible by
|
|
4007
4075
|
construction.
|
|
4008
4076
|
|
|
4009
|
-
§operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture that is identical on every machine: complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, the operator's installed skills and plugins left unread ({§agent-roots}),
|
|
4077
|
+
§operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture that is identical on every machine: complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, the operator's installed skills and plugins left unread ({§agent-roots}), server approval set to accept ({§worker-owner-resolution}), and ambient MCP/A2A and schedules default disabled. The drivers also project per-alias `ENABLED=0` overrides for named MCP, A2A, schedule, membership, and skill resources in the operator's config file. Definitions remain inspectable; explicit shell/benchmark controls win. Mock-tier bootstrap clears these ambient families before loading its fixture floor. No operator file is rewritten. Configuration with a narrower or variable owner stays outside it:
|
|
4010
4078
|
|
|
4011
4079
|
| Owner | Configuration |
|
|
4012
4080
|
|---|---|
|
|
@@ -4197,14 +4265,6 @@ workspace forgets its storage key through the existing foreign key; old disk
|
|
|
4197
4265
|
state is not reassigned or automatically purged. A database copy preserves its
|
|
4198
4266
|
storage identities; the directory is operational state, not a backup of it.
|
|
4199
4267
|
|
|
4200
|
-
§skills-storage-upgrade **Skills ownership upgrades without a second identity.**
|
|
4201
|
-
The database migration renames the family state to `@plurnk/plurnk-skills`.
|
|
4202
|
-
Before module setup, core renames the former skills directory within each storage root
|
|
4203
|
-
recorded by this database. Fetched bytes are not refetched or deleted. A missing former
|
|
4204
|
-
directory needs no work; a completed rename is repeatable. Conflicting destinations and
|
|
4205
|
-
filesystem failures stop admission without replacing either directory. No runtime alias
|
|
4206
|
-
recognizes the former owner.
|
|
4207
|
-
|
|
4208
4268
|
§workspace-environment-sharing **The workspace owns its shared environment.**
|
|
4209
4269
|
Workers own their logs; delegation retains its existing lifecycle.
|
|
4210
4270
|
Creating, attaching, forking, cancelling, or deleting a worker does not create,
|
|
@@ -4283,12 +4343,33 @@ Retryability describes the actual failed condition, not its numeric status.
|
|
|
4283
4343
|
| Verb | Common contract |
|
|
4284
4344
|
|---|---|
|
|
4285
4345
|
| `list` | Project definitions, ownership (`origin`), winning configuration source (`provenance`), enabledness, and published preparation outcome: disabled, dormant, active, unavailable with its Problem, or authorization-required. No credential values. |
|
|
4286
|
-
| `discover` | Return inert candidates. Never install, persist, enable, or execute them. |
|
|
4346
|
+
| `discover` | Return inert candidates for the inputs the family serves ({§functionality-discover-advertisement}). Never install, persist, enable, or execute them. |
|
|
4287
4347
|
| `add` | Admit and persist a local definition, prepare it, and enable it atomically. It may override an inherited definition. Reapplying the same local definition enables it idempotently (200); a different local definition for that alias fails 409 without replacing it. |
|
|
4288
4348
|
| `enable` | Publish an available definition; retry preparation if unavailable. |
|
|
4289
4349
|
| `disable` | Withdraw live capability; retain its definition and saved results. |
|
|
4290
4350
|
| `remove` | Forget the locally owned definition and its enabledness override. Restore any inherited definition with its inherited enabledness. Inherited definitions cannot be removed at this scope. Saved results remain. |
|
|
4291
4351
|
|
|
4352
|
+
§functionality-discover-advertisement **A family's `discover` advertises exactly the inputs it
|
|
4353
|
+
serves.** The coordinator builds the family's discover input schema from its declared discovery
|
|
4354
|
+
({§functionality-discovery-inputs}): the declared inputs with their shared
|
|
4355
|
+
`FunctionalityDiscoverQuery` definitions and no other property (a multi-scope family adds
|
|
4356
|
+
`scope`), and, unless a request naming none lists everything, at least one of them: the one
|
|
4357
|
+
input required, or any of several. The client actions, the manager's tool documents and their
|
|
4358
|
+
schema documents carry that schema. Any other input, or a request naming none, is refused by the
|
|
4359
|
+
shared schema check as 400 `arguments-invalid`, its `errors` naming each field; no family mints
|
|
4360
|
+
its own refusal for an input it does not serve. A family without discovery has no `discover`
|
|
4361
|
+
action, and its manager teaches none. A value of a served input the family cannot use remains the
|
|
4362
|
+
family's own refusal.
|
|
4363
|
+
|
|
4364
|
+
| Family | Inputs | A request naming none |
|
|
4365
|
+
|---|---|---|
|
|
4366
|
+
| `skills` | `source` ({§skills-functionality}) | Refused |
|
|
4367
|
+
| `schedule` | `source` ({§schedule-clock}) | Refused |
|
|
4368
|
+
| `mcp` | `query`, while a registry is configured; otherwise no discovery ({§mcp-registry-discovery}) | Refused |
|
|
4369
|
+
| `a2a` | `source`, `configuration` ({§a2a-functionality}) | Refused |
|
|
4370
|
+
| `env` | `query`, `source` ({§env-functionality}) | The whole catalog |
|
|
4371
|
+
| `members` | `query` ({§members-functionality}) | Refused |
|
|
4372
|
+
|
|
4292
4373
|
§configuration-definition-resolution **Named resource definitions replace whole;
|
|
4293
4374
|
independent behavior controls remain independent.** Source readers and scope
|
|
4294
4375
|
overlays apply the same boundary:
|
|
@@ -4328,9 +4409,8 @@ composition boundaries, not arbitrary exceptions:
|
|
|
4328
4409
|
| Optional startup integration (hooks, hosted A2A, observability) cannot be configured | Withhold that integration and retain its exact configuration diagnostic. Activate the client interface and unrelated capabilities; never invent a replacement setting. |
|
|
4329
4410
|
| Invalid default model or child selector | Retain its diagnostic at startup; keep client inspection and explicit selection available. A request relying on the invalid selector fails with `daemon:configuration/configuration-invalid` (503), naming its key. Never substitute another model or silently inherit a child model. |
|
|
4330
4411
|
| Model construction or endpoint verification fails | Reject selection/use before inference or committing the selection. Keep the client available; a later selection can retry or choose another route. |
|
|
4331
|
-
| Invalid effect, file-creation, or
|
|
4412
|
+
| Invalid effect, file-creation, or server approval policy | Retain the startup diagnostic. Reject the affected operation as `daemon:configuration/configuration-invalid` (503); no guessed admission policy, external effect, or orphan approval wait. Independent operations remain usable. |
|
|
4332
4413
|
| Invalid retention configuration | Withhold collection and automatic storage conversion, including shutdown collection. Preserve stored evidence and expose the diagnostic; do not substitute a deletion policy. |
|
|
4333
|
-
| Invalid packet configuration or retired capacity knobs | Retain the startup diagnostic and keep client inspection available. Reject affected packet construction before inference with `daemon:configuration/configuration-invalid` (503). Never guess a capacity or projection setting. |
|
|
4334
4414
|
| Invalid executor construction/probe configuration | Keep the installed declaration and its diagnostic, but no executable instance or output scheme. Other executors and ordinary READ/EDIT remain usable. Invoking the unavailable tag returns its exact 503 configuration Problem. |
|
|
4335
4415
|
| Invalid execution scheduling, input, or scratch configuration | Diagnose at startup and validate on the affected execution path before admission, stream creation, or external effects. Scratch configuration applies only to resource-backed execution; inline programs remain independent. Never substitute concurrency, timeout, or directory settings. |
|
|
4336
4416
|
| Invalid model-alias catalog | Fail catalog inspection explicitly; omit its unavailable snapshot rather than report an empty catalog. Exact provider/model selection does not depend on aliases. |
|
|
@@ -4346,7 +4426,7 @@ composition boundaries, not arbitrary exceptions:
|
|
|
4346
4426
|
Client discovery and passive synchronization report startup diagnostics through the
|
|
4347
4427
|
existing Notice channel, even without a usable model. Each is a Notice from `engine:configuration`
|
|
4348
4428
|
of kind `configuration_unavailable` that names the failed setting's `key` and its `owner`: the
|
|
4349
|
-
setting's reader (such as `
|
|
4429
|
+
setting's reader (such as `retention`, `model` or `executor:<runtime>`), a family, `extensions` for an
|
|
4350
4430
|
extension declaration, or a module as `module:<package>`. The first turn of a drain, and a changed diagnostic
|
|
4351
4431
|
thereafter, reports unresolved configuration to both client and model. An
|
|
4352
4432
|
unchanged diagnostic is not repeated every turn. Operation failures remain Problems.
|
|
@@ -4424,14 +4504,15 @@ core owns discovery roots.
|
|
|
4424
4504
|
|
|
4425
4505
|
An adapter may expose a `scheme` facet beneath its family's runtime namespace
|
|
4426
4506
|
({§runtime-resource-binding}). A facet claims a path subtree and is the scheme's
|
|
4427
|
-
whole live half there: READ and FIND preparation, FIND, SEND, WAIT and KILL
|
|
4428
|
-
its own wherever it implements them. A claimed KILL the facet does not implement
|
|
4507
|
+
whole live half there: READ and FIND preparation, FIND, EDIT, SEND, WAIT and KILL
|
|
4508
|
+
are its own wherever it implements them. A claimed KILL the facet does not implement
|
|
4429
4509
|
is the ordinary entry KILL ({§stream-control}); an unclaimed coordinate keeps the
|
|
4430
4510
|
stored-execution behaviour, SEND to a process included. Where its resources are
|
|
4431
4511
|
not shaped like the executor's output, the facet states their representation —
|
|
4432
|
-
resource authority, channels, the default channel — and that
|
|
4433
|
-
every claimed coordinate: its address, its fragmentless READ, the
|
|
4434
|
-
subscription publishes
|
|
4512
|
+
resource authority, channels, the default channel, who may write them — and that
|
|
4513
|
+
manifest governs every claimed coordinate: its address, its fragmentless READ, the
|
|
4514
|
+
channel a subscription publishes, the writer gate ({§scheme-surface}) an EDIT or a
|
|
4515
|
+
COPY into it passes. An adapter states the `traits` of its runtime — `web`
|
|
4435
4516
|
for a family that reaches the network — so {§capability-admission} selects its
|
|
4436
4517
|
manager and its resources alike.
|
|
4437
4518
|
|
|
@@ -4461,12 +4542,30 @@ set any name it lists or none of them — it answers which names have a **consum
|
|
|
4461
4542
|
a Worker learns the name of a value only the operator can supply. The catalog projects
|
|
4462
4543
|
declarations, never the host environment, so a credential the operator has filled in appears by
|
|
4463
4544
|
name with its documentation and an empty value ({§exec-env-scoped}: referred to by name, never
|
|
4464
|
-
read). `
|
|
4465
|
-
|
|
4545
|
+
read). `source` selects one declaring package, and a request naming neither input is the whole
|
|
4546
|
+
catalog. A client's own environment is no input: contributing candidates, it would be a second
|
|
4547
|
+
door past the ceiling.
|
|
4466
4548
|
|
|
4467
4549
|
The family publishes no process runtimes. Its values are read at the spawn that uses them,
|
|
4468
4550
|
not from a live process or a cached worker environment.
|
|
4469
4551
|
|
|
4552
|
+
§env-scheme **The registry is an address space.** Every name in effect for a Worker's commands —
|
|
4553
|
+
the ambient names the ceiling admits, workspace defaults and the Worker's own entries, exactly
|
|
4554
|
+
what `list` projects — is a resource at `env:///NAME` whose body is the value, verbatim; a
|
|
4555
|
+
reserved or masked name is no resource. The family's manager exposes it as the facet of its own
|
|
4556
|
+
`env://` namespace ({§runtime-resource-binding}), read for the dispatching Worker: READ projects
|
|
4557
|
+
the value its commands receive now, FIND lists the names in effect and a pattern on it matches
|
|
4558
|
+
values, COPY carries a value out. The manager's own output streams, eight hexadecimal characters
|
|
4559
|
+
({§execution-output-identity}), stay the executor's. A write is the Worker's own layer, never the
|
|
4560
|
+
workspace's or the operator's: EDIT sets the whole value through the family's `add` for the
|
|
4561
|
+
Worker, and KILL retires the name from the Worker's commands — `remove` for an entry the Worker
|
|
4562
|
+
owns, which restores an inherited value, `disable` for an inherited one, which keeps its
|
|
4563
|
+
definition. Admission is the family's ({§env-functionality}) and its refusal is the operation's
|
|
4564
|
+
result. A value has no lines: a line scope on EDIT or KILL is `value-whole` (400), and a pattern
|
|
4565
|
+
on EDIT is the dispatcher's refusal for any scheme without text scopes; a target that is not
|
|
4566
|
+
`env:///NAME` is `name-invalid` (400), or `target-required` (400) when absent; a name not in
|
|
4567
|
+
effect is `entry-not-found` (404) on READ and KILL alike.
|
|
4568
|
+
|
|
4470
4569
|
§functionality-scope **A family declares its supported scopes.** Skills, MCP, members
|
|
4471
4570
|
and outbound A2A describe what exists in a **workspace**: a capability, resident or installable,
|
|
4472
4571
|
that every Worker there shares. Environment describes how one **Worker** works — context rather
|
|
@@ -4475,11 +4574,12 @@ than capability — with worker overrides above workspace defaults. The adapter
|
|
|
4475
4574
|
coordinator keys durable state and the locally-owned `origin`
|
|
4476
4575
|
by it: a workspace-scoped family's own entries carry origin `workspace`, a worker-scoped
|
|
4477
4576
|
family's carry `worker`. Origin names ownership, never scope, so a projection never claims the
|
|
4478
|
-
workspace set a value one Worker set for itself. Nothing else in the contract varies
|
|
4479
|
-
|
|
4577
|
+
workspace set a value one Worker set for itself. Nothing else in the contract varies but the
|
|
4578
|
+
discovery inputs a family serves ({§functionality-discover-advertisement}): the verbs, the two
|
|
4579
|
+
projections, enabledness, and the service-baseline rules are one implementation
|
|
4480
4580
|
across every family, which is what keeps their idioms from drifting apart.
|
|
4481
4581
|
|
|
4482
|
-
A family projects `<scope>.<family>.<verb>` for each supported scope. The action's
|
|
4582
|
+
A family projects `<scope>.<family>.<verb>` for each verb it serves, in each supported scope. The action's
|
|
4483
4583
|
context binds that scope; a worker-scoped action also names the Worker. Its durable
|
|
4484
4584
|
value is the same shape per (worker, family) in `worker_module_state`, read
|
|
4485
4585
|
at each verb and at each spawn rather than held in the workspace snapshot. Its `list` and
|
|
@@ -4514,9 +4614,9 @@ Admission, tools, documents, Turn 0, and client status consume that publication.
|
|
|
4514
4614
|
The coordinator's synchronous `publish` participates in the registry commit;
|
|
4515
4615
|
its returned undo restores the previous view before rollback reconciles documents.
|
|
4516
4616
|
Neither callback performs fallible I/O. Publication failure restores the preceding
|
|
4517
|
-
configuration/runtime snapshot; it cannot roll back
|
|
4518
|
-
|
|
4519
|
-
reported as successful configuration
|
|
4617
|
+
configuration/runtime snapshot; it cannot roll back an external effect of preparation,
|
|
4618
|
+
such as a fetched skill source. A failed external effect retains its cause and must not be
|
|
4619
|
+
reported as a successful configuration change.
|
|
4520
4620
|
`settleFunctionality` joins queued
|
|
4521
4621
|
publications before inspection or shutdown.
|
|
4522
4622
|
|
|
@@ -4529,7 +4629,8 @@ definitions add no hot-path teaching. Their exact state and Problem remain
|
|
|
4529
4629
|
available through `list`.
|
|
4530
4630
|
|
|
4531
4631
|
§functionality-model-projection **Each family has one workspace manager
|
|
4532
|
-
executor.**
|
|
4632
|
+
executor.** Its verbs — `discover` only where the family serves discovery
|
|
4633
|
+
({§functionality-discover-advertisement}) — use their actual coordinator schemas and the ordinary
|
|
4533
4634
|
tool-document machinery. `list`/`discover` are read effects; mutations are host
|
|
4534
4635
|
effects and use normal proposals. Summary, signatures, and deep docs derive
|
|
4535
4636
|
from the same registry ({§tools-resource-materialization},
|
|
@@ -4581,10 +4682,10 @@ Core's behavior behind them.
|
|
|
4581
4682
|
|---------------------------------------------------|----------|---------------|
|
|
4582
4683
|
| §methods-event-subscribe Events | `subscribeToEvents(handler) -> unsubscribe` | Subscribes to the raw event source in {§notifications}. A subscriber failure is logged and cannot re-enter engine control flow. |
|
|
4583
4684
|
| §proposal-list Proposals | `pendingProposals(workspaceId)` | Intersects durable proposed rows with the lifecycle owner's live resolution waiters, then returns their validated {§proposal-projection}; persistence alone cannot advertise an unresolvable client interrupt. |
|
|
4584
|
-
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates
|
|
4685
|
+
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution, owner)` | Validates the workspace-scoped owner before delivering one accept, reject, or cancel decision. Unknown, mismatched, and already-resolved identities fail without consuming the gate; the adapter authenticates its owner identity. |
|
|
4585
4686
|
| §client-interaction-list Client interactions | `pendingClientInteractions(workspaceId)` | Intersects durable interaction rows with their live operation waiters and returns the contracts-owned projection; a row alone is not a resumable interaction. |
|
|
4586
|
-
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates
|
|
4587
|
-
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?,
|
|
4687
|
+
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution, respondent, message?)` | Validates the recorded recipient before delivering one resolved payload or cancellation. Unknown, mismatched, and already-resolved identities fail before affecting an operation. |
|
|
4688
|
+
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, loopId?, prompt, source?, maxTurns?, openPaths?, selector?, childSelector? })` | Validates a model worker and persists the request with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. An explicit Loop recipient follows {§loop-addressed-admission}. A trusted adapter may identify the prompt's causal actor with one canonical `source`; ordinary clients cannot author it through their protocol surface. Messages carry no approval authority. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
|
|
4588
4689
|
| §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)`; `cancelWorker({ workspaceId, workerId, reason? })` | `cancelDrain` begins durable structured cancellation and reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. The ownership-bounded `cancelWorker` awaits that same tree cancellation and stream reap, so an exterior protocol can project the settled durable result without polling or fabricating state. |
|
|
4589
4690
|
| §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop in the client worker, executing in the workspace's Functionality ({§actor-boundary-attached-functionality}). Every statement is an ordered client/operation turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep its turn, loop, and action promise open until resolution. Core exposes no per-op method family. |
|
|
4590
4691
|
| Client observation | `look({ workspaceId, workerId, statement, perspectiveWorkerId? })` | Runs an already-parsed READ through the full resolver in the workspace's Functionality without a log row. A non-READ statement is rejected ({§op-look}). |
|
|
@@ -4596,7 +4697,10 @@ Core's behavior behind them.
|
|
|
4596
4697
|
| §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, and emits global `workspace/created`. Creation and attachment are passive: neither starts derivation nor activates workspace Functionality. `projectRoot` is established here or the workspace remains headless. |
|
|
4597
4698
|
| §methods-workspace-attach Workspace lifecycle | `attachWorkspace({ workspaceId, workerId?, workerName? })` | Validates ownership and returns a client envelope for an existing world. It does not retain caller or transport binding state in core. |
|
|
4598
4699
|
| §methods-model-worker Workspace lifecycle | `ensureModelWorker(workspaceId)` | Returns the workspace's stable default model worker, creating it on first use. A durable default-conversation role identifies it independently of worker name and root creation order. Repeated and concurrent calls return the same root; fresh conversations and forks do not replace it. |
|
|
4599
|
-
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin
|
|
4700
|
+
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name?, parentWorkerId?, owner? })` | Creates a distinct model-origin worker with empty history. A root may name a registered owner; a child names its parent and inherits ownership. Supplying both parent and owner is invalid ({§worker-owner-creation}). |
|
|
4701
|
+
| Worker ownership | `registerWorkerOwner(workspaceId, { address, tools, interactive })` | Declares or replaces an owner's supported client-tool names and whether a person attends it, in that workspace; `_plurnk` is reserved. |
|
|
4702
|
+
| Worker ownership | `claimWorkerOwner({ workspaceId, workerId, owner })` | Claims only runtime-owned work under {§worker-ownership}, returning its effective owner. The owner must already be registered. |
|
|
4703
|
+
| Runtime actor | `ensureRuntimeWorker(workspaceId)` | Returns the workspace's `_plurnk` actor, creating it if absent; it always retains runtime ownership. |
|
|
4600
4704
|
| Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
|
|
4601
4705
|
| §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
|
|
4602
4706
|
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?, workerId?)` | Returns nonempty loop-seed prompts a client addressed to the workspace's model workers, newest-first; `workerId` narrows to one worker. Authorship is the seed message's address ({§message-arrival}): a worker-issued seed (WORK, FORK, SEND to a worker) has none and is never history, whichever worker it seeded; a client prompt at a forked conversation worker is. An omitted limit is `PLURNK_SERVICE_PROMPTS_PAGE`. |
|
|
@@ -4616,7 +4720,6 @@ already durable on the loop remains authoritative:
|
|
|
4616
4720
|
|-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
|
|
4617
4721
|
| Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
|
|
4618
4722
|
| `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
|
|
4619
|
-
| `policy` request | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
|
|
4620
4723
|
|
|
4621
4724
|
The conflict names both selections and directs the caller to cancel or conclude
|
|
4622
4725
|
the loop before changing configuration. A newly enqueued loop instead persists
|
|
@@ -4624,9 +4727,12 @@ the requested configuration normally.
|
|
|
4624
4727
|
|
|
4625
4728
|
§methods-loop-run-open-paths **Workspace paths are core-owned context reads.**
|
|
4626
4729
|
`openPaths` belongs to the message submitted by the client. The client
|
|
4627
|
-
sends paths, never duplicated
|
|
4730
|
+
sends local paths or scheme URIs, never duplicated resource bytes; core dispatches one ordinary
|
|
4628
4731
|
`plurnk`-origin READ per path from inside the owning workspace, and successes
|
|
4629
4732
|
and failures surface through the normal operation-result contract.
|
|
4733
|
+
Path spelling follows {§path-syntax}, including channel fragments and literal
|
|
4734
|
+
delimiters. Malformed URI syntax is rejected before message admission; a valid
|
|
4735
|
+
address whose resource is absent produces the ordinary READ failure.
|
|
4630
4736
|
|
|
4631
4737
|
| `runLoop` disposition | Message and path behavior |
|
|
4632
4738
|
|-----------------------|------------------------------------------------------------------------------------------------------|
|
|
@@ -4675,7 +4781,8 @@ independent demands, and harness-authored initialization obeys workspace policy.
|
|
|
4675
4781
|
`workspaces.settings.capabilities` is the one mutable access policy under the
|
|
4676
4782
|
service ceiling. Every actor, including an existing child, uses the current
|
|
4677
4783
|
workspace policy; neither creation nor delegation snapshots authority. Workers
|
|
4678
|
-
own their log and scratchpad, not tools or resource grants
|
|
4784
|
+
own their log and scratchpad, not tools or resource grants; their owner decides only
|
|
4785
|
+
which interaction runtimes they are offered ({§owner-interaction-ring}). Intrinsic source
|
|
4679
4786
|
mutability, workspace separation, and proposal approval remain distinct
|
|
4680
4787
|
contracts. Input is validated before persistence; malformed stored policy fails
|
|
4681
4788
|
at its reader with the workspace coordinate and cause.
|
|
@@ -4689,7 +4796,8 @@ or observation, existing workers reconcile generated references against it. It r
|
|
|
4689
4796
|
conversation worker and returns the complete fresh projection.
|
|
4690
4797
|
|
|
4691
4798
|
§question-tool **The native request-user-input tool.** Core registers one
|
|
4692
|
-
in-process `question` runtime at boot
|
|
4799
|
+
in-process `question` runtime at boot and offers it only to a worker whose owner
|
|
4800
|
+
would receive it ({§owner-interaction-ring}). Its body is the MCP2 2026-07-28
|
|
4693
4801
|
form-elicitation shape verbatim — `{ message, requestedSchema }`. An
|
|
4694
4802
|
optional literal target is a descriptive label only: it neither routes the
|
|
4695
4803
|
question nor changes the body or recipient. The
|
|
@@ -4718,6 +4826,20 @@ weights, and catalog text agree. Turn0 surveys that same catalog. Dispatch evalu
|
|
|
4718
4826
|
same descriptor and policy cascade at the operation boundary, never at
|
|
4719
4827
|
registration; there is no separate per-tool availability system.
|
|
4720
4828
|
|
|
4829
|
+
§owner-interaction-ring **An interaction tool is offered only where an answer can come
|
|
4830
|
+
from.** An asking worker adds one ring inside that cascade, derived live from its owner
|
|
4831
|
+
and never stored. It denies each interaction runtime whose tool the owner would not
|
|
4832
|
+
receive under {§client-interaction-routing}; an interaction runtime asks under its own
|
|
4833
|
+
tag, as `question` does.
|
|
4834
|
+
|
|
4835
|
+
| Surface | With the ring |
|
|
4836
|
+
| --- | --- |
|
|
4837
|
+
| Turn 0 survey and the worker's FIND of the shared reserved tree | The runtime's documents are absent, from counts and folder summaries too. |
|
|
4838
|
+
| Dispatch | 403 `capability-denied` naming scope `owner`, with the recovery pinned in {§pinned-wording-core}. |
|
|
4839
|
+
| Workspace capability projection and reserved-tree materialization | Unaffected: they take no worker. |
|
|
4840
|
+
|
|
4841
|
+
A FIND or READ by exact path is not filtered.
|
|
4842
|
+
|
|
4721
4843
|
§model-catalog **Model discovery is a bounded local projection, not provider
|
|
4722
4844
|
activity.** Core composes the release-pinned Models.dev snapshot with
|
|
4723
4845
|
provider-owned `{§model-catalog-readiness}` and {§provider-effort}.
|
|
@@ -4732,6 +4854,8 @@ packets or state snapshots.
|
|
|
4732
4854
|
|
|
4733
4855
|
§worker-model-selection **Worker-owned model selection.** Every model worker
|
|
4734
4856
|
owns one durable model, persisted as a nullable `model_routes` foreign key.
|
|
4857
|
+
Concurrent first selections of the same resolved tuple share one identity;
|
|
4858
|
+
an insertion conflict returns the existing route without changing its fields.
|
|
4735
4859
|
The root conversation worker is seeded once — from an explicit selection, else
|
|
4736
4860
|
the daemon default — and never re-seeded from a later default change. A
|
|
4737
4861
|
deliberately modelless daemon leaves the worker unset and rejects model work
|
|
@@ -4905,33 +5029,55 @@ rendered or measured; {§context-fit} remains an engine-owned post-build rail.
|
|
|
4905
5029
|
|
|
4906
5030
|
```mermaid
|
|
4907
5031
|
flowchart LR
|
|
4908
|
-
defaults[Engine
|
|
4909
|
-
transforms --> render[Render
|
|
5032
|
+
defaults[Engine sections<br/>log records interleaved with complete programs] --> transforms[Trusted scheme transforms<br/>and boundary validation]
|
|
5033
|
+
transforms --> render[Render ordered message roles]
|
|
4910
5034
|
render --> measure[Budget substitution and<br/>core-owned measurement]
|
|
4911
5035
|
measure --> rail[Engine budget admission and dispatch]
|
|
4912
5036
|
```
|
|
4913
5037
|
|
|
4914
5038
|
### §packet-wire-envelope The wire envelope
|
|
4915
5039
|
|
|
4916
|
-
|
|
5040
|
+
Sections retain their message roles and order. System sections form the leading system message;
|
|
5041
|
+
adjacent nonempty sections of the same remaining role form one message. With an eligible
|
|
5042
|
+
{§emission-history}, the default envelope is:
|
|
4917
5043
|
|
|
4918
5044
|
| Message | Role | Content |
|
|
4919
5045
|
|:--|:--|:--|
|
|
4920
5046
|
| 1 | `system` | the system slot, as rendered |
|
|
4921
|
-
| 2
|
|
4922
|
-
| 3
|
|
4923
|
-
| last | `user` |
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
artifacts record the sections, and `.wire.json` reconstructs their text-message
|
|
5047
|
+
| 2 | `user` | initial retained log records through the first selected emission record |
|
|
5048
|
+
| 3… | alternating `assistant`, `user` | each selected complete content program, then the following log records through the next selected emission record; native parts remain beside their READ records ({§packet-attachment-parts}) |
|
|
5049
|
+
| last | `user` | remaining log records and the current-status footer, from Worker through Open Messages and optional Recap |
|
|
5050
|
+
|
|
5051
|
+
Without selected programs, the log and footer coalesce into one user message: system + user.
|
|
5052
|
+
Each program follows its own emission record and precedes its subsequent results.
|
|
5053
|
+
Log records retain their order; interpolation never groups or relocates their bodies.
|
|
5054
|
+
Stored sections retain their original roles and order: reading evidence
|
|
5055
|
+
never converts an earlier request into a different envelope.
|
|
5056
|
+
|
|
5057
|
+
The digest's packet artifacts record the sections, and `.wire.json` reconstructs their text-message
|
|
4933
5058
|
envelope ({§share-packet-names}); it is not a serialized HTTP capture.
|
|
4934
5059
|
|
|
5060
|
+
### §emission-history The turn's NOTEs, in the model's voice
|
|
5061
|
+
|
|
5062
|
+
| Concern | Contract |
|
|
5063
|
+
|---|---|
|
|
5064
|
+
| Choice | `PLURNK_SERVICE_EMISSION_HISTORY`: `none`, `latest`, or `all` (default). Reasoning return is independent ({§reasoning-row}). |
|
|
5065
|
+
| Selection | `latest` considers only the immediately preceding completed model inference turn in this loop, never falling back to an older eligible program. `all` considers every completed model inference turn in this loop, in ascending turn order. |
|
|
5066
|
+
| Eligibility | An admitted content program with no syntax errors and an active emission row. Rejected attempts, syntactically partial emissions, empty or reasoning-only turns, initialization and other loops supply none. Runtime failures do not disqualify an admitted program. |
|
|
5067
|
+
| Vocabulary | Executor identities come from that turn's admitted operation evidence ({§packet-stored-shape}), not the current registry. Disabling or removing a runtime never changes its admitted history. |
|
|
5068
|
+
| Content | A replayed turn is its NOTEs: every content NOTE the program admitted, whole and in program order, as the model wrote it, including a NOTE that stood outside its fence ({§outside-text}). Every other operation is omitted; its receipt in the log is its record, and the program stays readable at `ops://`. A NOTE whose log row has been retired is omitted from the replay from the next packet on, so one KILL retires the memory everywhere it shows. Selection uses parsed operations, never text inside their bodies. Join retained NOTEs within each program with one blank line. No placeholders, body redaction or preview. Reasoning operations remain in their own source and receipts. |
|
|
5069
|
+
| Legend | The emission row of a replayed turn carries no program preview: its body is the legend of that turn's replayed NOTEs, one numbered line per NOTE, `N:log:///<loop>/<turn>/<sequence>/NOTE · <weight>`, in log order ({§emission-row}). Those NOTE rows render nowhere else in the packet; their text is read in the replay and their handle in the legend. A line scope on the emission row retires the NOTEs on those lines; the unscoped KILL retires the row ({§log-kill-scope}). A NOTE of a turn that is not replayed — an earlier loop, a program omitted at the wall, a reasoning NOTE — renders as an ordinary row with its body. |
|
|
5070
|
+
| Placement | Interpolate each selected program immediately after its durable emission record, as an assistant message without a heading or wrapper. Split the user log at that record; following observations stay after the program. No history is collected at the end. With `none` or no retained NOTEs, no assistant section is added; filtering does not make `latest` fall back to an older turn. |
|
|
5071
|
+
| Authority | Core assembles the chronological sections before the trusted whole-list transform ({§packet-extension-transform}). Each active emission row owns its program's curation lifetime; retiring it removes only that program, never its immutable source. |
|
|
5072
|
+
| Capacity | At the hard context wall, omit the selected history whole before suppressing any result body or native part ({§context-own-rows-fit}). A turn whose replay is omitted is not replayed: its NOTE rows stand in the log as ordinary bodied rows, and the wall's shedding then treats them as any other. A NOTE's text is in the packet once, as replay or as row, never both. Omission lasts through rebuilds of that request; the next request decides afresh. No source, receipt, or stored historical packet is changed. |
|
|
5073
|
+
| Accounting | Each program is charged once as its assistant message; the emission row charges only its record, legend included. |
|
|
5074
|
+
|
|
5075
|
+
The initial user segment is `log`; later segments are `log/<first-record-coordinate>`.
|
|
5076
|
+
Programs are `emission-history/<emission-record-coordinate>`. These are durable, unique section
|
|
5077
|
+
names, not model-facing headings. Only the initial segment has the `Log` header. Section-family
|
|
5078
|
+
inspection joins segments in recorded order; wire projection uses their individual roles and
|
|
5079
|
+
positions. Stored packets retain the sections actually sent, including older packet layouts.
|
|
5080
|
+
|
|
4935
5081
|
### §packet-cache-monotone Default order and cache locality
|
|
4936
5082
|
|
|
4937
5083
|
Conditional absence never reorders the surviving default sections.
|
|
@@ -4941,25 +5087,31 @@ Conditional absence never reorders the surviving default sections.
|
|
|
4941
5087
|
| 1 | system | `definition` | Framework definition; leads the most stable prefix. |
|
|
4942
5088
|
| 2 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
|
|
4943
5089
|
| 3 | system | `inject` | Present only when operator notes are configured. |
|
|
4944
|
-
|
|
|
4945
|
-
|
|
|
4946
|
-
|
|
|
4947
|
-
|
|
|
4948
|
-
|
|
|
4949
|
-
|
|
|
4950
|
-
|
|
|
4951
|
-
|
|
|
4952
|
-
|
|
|
5090
|
+
| 4–5 | user / assistant | `log` and `emission-history` segments | Append-mostly chronological history: each selected program follows its emission record and precedes its results ({§emission-history}). |
|
|
5091
|
+
| 6 | user | `git` | Per-turn workspace status; empty content is omitted. |
|
|
5092
|
+
| 7 | user | `budget` | `Context Curation`; omitted when capacity is unknown. |
|
|
5093
|
+
| 8 | user | `worker` | `Worker`: `{"path": "worker://alice", "parent": <address or null>, "loop": L, "turn": T}`, the actor and the coordinate this packet's response becomes ({§packet-current-turn}). |
|
|
5094
|
+
| 9 | user | `delegation` | `Delegation`: per-turn `{workers, streams}` pointers; always present, each list `[]` when empty ({§packet-empty-sections}). |
|
|
5095
|
+
| 10 | user | `messages` | `Open Messages`: immutable message addresses and causal sources ({§message-arrival}). |
|
|
5096
|
+
| 11 | user | `notices` | Per-turn observations; empty content is omitted. |
|
|
5097
|
+
| 12 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
|
|
5098
|
+
| 13 | user | `recap` | Optional authored operational recap. |
|
|
4953
5099
|
|
|
4954
5100
|
The order favors prefix-cache locality where semantics permit: the definition
|
|
4955
5101
|
and privileged policy lead operator notes, while the append-mostly
|
|
4956
|
-
log
|
|
4957
|
-
|
|
4958
|
-
|
|
5102
|
+
log and interpolated programs lead the volatile user-status clump. That clump is never cached
|
|
5103
|
+
across turns, since the next turn's log grows into its place, so its order serves attention alone:
|
|
5104
|
+
it runs from ambient state (Git Status, Context, Worker, Delegation) to what the turn owes (Open
|
|
5105
|
+
Messages) to feedback on the last turn (Notices, then Errors), and closes with the Recap. The nearer
|
|
5106
|
+
the end, the more a section asks of this turn. With `all`, appending new
|
|
5107
|
+
observations and programs preserves the existing history's roles and text prefix; no old program
|
|
5108
|
+
moves past newly appended observations. Changing selection or curating a row may invalidate the
|
|
5109
|
+
prefix at the affected position. It does **not** claim that every system byte is
|
|
4959
5110
|
immutable or that the complete packet is globally monotone in volatility:
|
|
4960
5111
|
operator notes and policies can change. Trust is a separate
|
|
4961
5112
|
admission rule. The system slot contains trusted control-plane material;
|
|
4962
|
-
|
|
5113
|
+
observations stay in the user role, and only the model's admitted content program is replayed
|
|
5114
|
+
under assistant authorship.
|
|
4963
5115
|
|
|
4964
5116
|
### §packet-extension-transform Trusted whole-list extension seam
|
|
4965
5117
|
|
|
@@ -4971,8 +5123,10 @@ Each initial or returned list passes the schemes-owned validator, including
|
|
|
4971
5123
|
unique-name enforcement, before the next transformer or renderer. Each
|
|
4972
5124
|
transformer may inspect the section content and add, remove, or reorder
|
|
4973
5125
|
sections. It receives no separate engine, database, actor, or request context.
|
|
4974
|
-
|
|
4975
|
-
|
|
5126
|
+
The complete default list already includes the interpolated programs ({§emission-history}) and
|
|
5127
|
+
native READ boundaries. Transforms own section drafts, not the worker's immutable source evidence.
|
|
5128
|
+
Removing a section removes its native deliveries too; a retained native delivery requires its
|
|
5129
|
+
named section to remain user-authored. Core measures the transformed composition.
|
|
4976
5130
|
|
|
4977
5131
|
This is strictly a trusted in-process seam, admitted through the common extension
|
|
4978
5132
|
trust gate; an external client action cannot invoke it. Whole-list transformation is
|
|
@@ -4986,23 +5140,40 @@ time of measurement.
|
|
|
4986
5140
|
|
|
4987
5141
|
| Fact | Owner and unit | Time | Contract |
|
|
4988
5142
|
|:-----|:---------------|:-----|:---------|
|
|
4989
|
-
| Core curation weight | `contentWeight = ceil(chars/2)` over channel content, canonical log bodies, rendered
|
|
5143
|
+
| Core curation weight | `contentWeight = ceil(chars/2)` over channel content, canonical log bodies, and each rendered message (including the optional emission history) | Write/build | Stable, model-independent measure; never a tokenizer claim. The model meets it as `tokens`. |
|
|
4990
5144
|
| §tokenomics-context-envelope-admission Provider input capacity | Provider model limits, the configured output reservation and the output floor, in provider tokens | Before every logical request | The reservation `min(maxInputTokens, contextWindow − outputBudget)` sizes the room; the wall `min(maxInputTokens, contextWindow − outputFloor)` decides admission ({§provider-capacity-admission}). The provider alone measures the complete request and admits it — with the grant flexed when the prompt is over the reservation — defers it, or rejects it at the wall. |
|
|
4991
5145
|
| Provider generation envelope | Provider response grant and optional reasoning subset, in provider tokens | Before every logical request | The reservation includes hidden reasoning; its strict reasoning subset is never additive. The response grant follows {§provider-flexed-allowance}. |
|
|
4992
5146
|
| Provider usage and cost | Provider-reported input/output/cache/reasoning tokens and monetary evidence | After every physical request | Durable physical-request forensics under {§provider-usage}; never curation state or a preflight estimate. |
|
|
4993
5147
|
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
5148
|
+
§context-admission **One request through the room.** Core fits the packet to the wall on its estimate, marks it over budget, then has the provider measure the exact request before it is sent. Shedding is the same at both measures, and only a packet that cannot fit even as receipts ends its loop.
|
|
5149
|
+
|
|
5150
|
+
```mermaid
|
|
5151
|
+
flowchart TD
|
|
5152
|
+
build["Build the packet at the budget"] --> wall{"Estimate over the wall?"}
|
|
5153
|
+
wall -- yes --> shed["Shed: the emission history whole, then the newest rows bodiless"]
|
|
5154
|
+
shed --> wall
|
|
5155
|
+
wall -- no --> over{"Over budget, no row yet?"}
|
|
5156
|
+
over -- yes --> row["One over-budget row at the head of the turn"]
|
|
5157
|
+
row --> wall
|
|
5158
|
+
over -- no --> assess{"The provider assesses the exact request"}
|
|
5159
|
+
assess -- "admit or defer" --> send["Send"]
|
|
5160
|
+
assess -- "exact refusal" --> shed
|
|
5161
|
+
shed -. "nothing left to take" .-> overflow["window-overflow 413, no inference request"]
|
|
5162
|
+
```
|
|
5163
|
+
|
|
5164
|
+
- §context-budget **One room.** The budget is the provider's input capacity through the loop's calibration, `floor(inputCapacity / factor)` ({§tokenomics-calibrated-readout}), and it bounds the whole packet — teaching, catalog, log and gauge together. Nothing on the service panel sizes a part of it: no projection share or preview page. When the loop's first response fixes its factor, the budget follows it either way; a room that shrinks under the model is announced by the over-budget row ({§context-over-budget-row}), never hidden by keeping a larger figure.
|
|
5165
|
+
- §context-gauge **One gauge.** Every packet carries one `## Context` section holding one JSON object: `tokens`, the packet's weight as rendered, and `budget`, the known room. Only when the packet without an inventory strictly exceeds `PLURNK_SERVICE_BUDGET_PRESSURE` of its budget does `largest` name the `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` heaviest retained log rows as `{path, tokens}`, ranked by weight then path. Unknown budget omits both `budget` and `largest`. The final `tokens` includes the inventory; over budget, its full configured count remains available for curation ({§context-over-budget-row}). Each log row heading carries its own `tokens`. The gauge is state: it never presents `budget − tokens` as response allowance and carries no mandate.
|
|
5166
|
+
- §context-pressure-notice **Pressure is one notice.** When the gauge names its inventory ({§context-gauge}) and the packet, with the notice in it, stays within its budget, the packet's notices section carries one `engine:context` notice `budget_pressure`, `level: warn`, whose directive is "YOU MUST NOT exceed budget." and whose message is "Context is at *N*% of budget." *N* is `floor(100 × tokens / budget)` over the gauge's final figures, so the share never disagrees with the gauge, and the notice carries no count of its own. It is decided and rendered with the packet it describes, recurs on every such packet, and is never buffered or sent to clients, which read their own pair ({§tokenomics-client-gauge}). An over-budget packet carries the row instead ({§context-over-budget-row}).
|
|
5167
|
+
- §context-fit **One rule: whole if it fits, otherwise as much as fits, then its size and address.** A result the model asked for — a READ without a scope, a FIND, an exec result delivered on close — arrives complete when its weight fits within `budget − tokens` as of that turn, less the room the turn still owes — one receipt's measured weight for each result still to land in it and the emission record that answers it, so that the receipts of a batch and the answer always fit. Otherwise the complete result stays where it was read from and the row is a `413` receipt naming the result's size, its weight, the remaining budget, and the two verbs: `READ` a range, or `KILL` first. A READ of lines carries, above its receipt, the longest prefix of those lines whose row fits that room — the lines with their anchors, the returned range closed on the last line delivered, and the receipt naming the lines delivered; a result whose first line does not fit, a FIND, a stream page and a byte view are bodiless receipts. An arrival the model did not ask for — an inbound `SEND`, a child's conclusion — takes the same bodiless receipt as a fact, not an error: its size and its address. Explicit scopes (`<a,b>`, a pattern, `<1,-1>`) are exact and take the same test. Result cuts are named where they happen: the first page of what came back unasked in size ({§markerless-first-page}) and the cut at the room in the receipt. The optional emission history is whole or absent ({§emission-history}), never a cut.
|
|
4997
5168
|
- §context-verbs **The verbs are the curation.** `READ` with a range takes a piece of what did not fit ({§read-selection-projection}); `NOTE` keeps what the model learned; `KILL` retires rows, ranges and bodies ({§log-kill-scope}) and may carry what it keeps of them as its own NOTE ({§log-kill-distillation}). The daemon adds no other mechanism.
|
|
4998
5169
|
- §context-over-budget-row **Over budget is a row and a request, not an ending.** A packet whose weight exceeds `budget` is still submitted when it fits the window ({§context-wall}), and it carries one `_plurnk` error row at the head of its turn, `engine/context/packet-exceeds-budget` 413: "Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn." The row is the mandate and carries no figure: the gauge is the one home for `tokens` and `budget` ({§context-gauge}), and it shows the packet over with the row in it. The row recurs on every packet that is over, and nothing is hidden to make the packet smaller; the response grant is the window's remainder above the provider's output floor ({§provider-output-floor}). The limit protects a loop; it never ends one.
|
|
4999
|
-
- §context-wall **Only the window ends a loop.** The wall is the provider's physical input limit: `maxInputTokens`, and the context window less the output floor ({§provider-output-floor})
|
|
5000
|
-
- §context-
|
|
5001
|
-
- §context-
|
|
5170
|
+
- §context-wall **Only the window ends a loop.** The wall is the provider's physical input limit: `maxInputTokens`, and the context window less the output floor ({§provider-output-floor}). A request over the wall sheds ({§context-own-rows-fit}) and is measured again ({§context-wall-measure}); a packet that cannot fit even as receipts ends its loop with the exact `engine/context/window-overflow` 413 Problem, and no inference request is made. An unknown window has no wall ({§tokenomics-window-unpollable-deliberate}).
|
|
5171
|
+
- §context-wall-measure **The wall measures the request that will be sent.** The estimate is the packet's weight through its calibration factor ({§tokenomics-calibrated-readout}) and is never assumed to overestimate. A packet that fits by the estimate is assessed by the provider as the exact wire request ({§provider-capacity-admission}): an admission sends it; an exact refusal is the wall's verdict, and the request sheds by the refusal's excess and is assessed again. A provider that can only estimate defers, and the upstream provider is then the capacity oracle: its refusal ends the loop with the provider's own 413.
|
|
5172
|
+
- §context-own-rows-fit **The model's own rows take the same receipt.** When a request is over the wall by either measure ({§context-wall-measure}), its newest rows that still carry a body or a native part — NOTEs, receipts, delivered results, pictures — render bodiless in the fit rule's receipt shape, newest first and only as many as it takes for the request to fit: the heading, the facts, and `size`, the lines and tokens of what the row stood for. The optional emission history has already been omitted whole ({§emission-history}); an emission record has no body to take. A row whose receipt would weigh no less than its body stays whole. Every body stays stored and readable at its address, the verbs restore the room ({§context-verbs}), and each packet decides afresh from its own newest rows. The daemon chooses nothing to summarize and hides nothing silently.
|
|
5002
5173
|
- §tokenomics-weight-stored-at-write **Curation weight, stored at write.** `entry_channels.weight` weighs the complete channel content. `log_entries.weight` weighs the complete canonical `LogBody` content before coordinate and packet presentation; persistence `tx`/`rx` envelopes contribute nothing merely by existing, and proposal settlement recomputes the value when the canonical result changes. Bodyless rows therefore weigh zero. The stored number is a stable content-depth measurement, not a provider-token prediction. `entry_channels.lines` is the channel's line count beside it, a stored generated column SQLite keeps on every write as the persisted mirror of {§logical-line-count} (a trailing newline terminates the last line; empty content has none), so a catalog lists extent without reading bodies.
|
|
5003
|
-
- §tokenomics-render-weight-budget **Packet curation budget.** `tokens` measures the *complete assembled packet* after section transforms and readout substitution,
|
|
5004
|
-
- §tokenomics-calibrated-readout **Convert capacity, never content costs
|
|
5005
|
-
- §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits, the configured output reservation, and each call's response grant. Its resolved `inputCapacity` supplies the physical denominator exposed to clients and the boundary conversion into curation units ({§tokenomics-calibrated-readout}). Core shapes context in curation units; provider request-shaped evidence alone admits or rejects physical I/O.
|
|
5174
|
+
- §tokenomics-render-weight-budget **Packet curation budget.** `tokens` measures the *complete assembled packet* after section transforms and readout substitution, each rendered message (including {§emission-history}) and native attachments; it is not a sum of stored row weights ({§tokenomics-weight-stored-at-write}). Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns final values into those widths; final substitution is length-invariant and the displayed total equals the stored request weight. Receipt, FIND-item, pressure-inventory, total, and ceiling figures all use the same curation ruler. A `SUM` of stored content weights measures a different artifact and cannot substitute for packet render weight.
|
|
5175
|
+
- §tokenomics-calibrated-readout **Convert capacity, never content costs; one factor per loop.** A sample is a settled emission response pairing its request's measured packet weight with the provider-reported prompt count, both positive. A loop's first sample from the answering model fixes the conversion factor `reported / weight` for the rest of that loop. Until then the loop's packets use that model's most recently fixed factor, from any loop or worker, and a model that has none uses 1. The budget therefore changes at most once in a loop, when its first response settles. `floor(inputCapacity / factor)` converts provider capacity into curation units, the budget ({§context-budget}); the same factor converts the packet's weight into the wall's estimate ({§context-wall-measure}). Zero means no whole curation unit fits; unknown input capacity remains `null`. The built packet captures this allowance and its factor once for its readout, pressure inventory, wall estimate, and persisted client gauge; later responses cannot change that packet's allowance. Calibration never changes stored weights, rendered receipt costs, or the immutable request history ({§tokenomics-agnostic-ruler}).
|
|
5176
|
+
- §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits, the configured output reservation, and each call's response grant. Its resolved `inputCapacity` supplies the physical denominator exposed to clients and the boundary conversion into curation units ({§tokenomics-calibrated-readout}). Core shapes context in curation units; provider request-shaped evidence alone admits or rejects physical I/O. Local and custom deployments tune context window, total output budget and optional reasoning subset at their owning layers.
|
|
5006
5177
|
- §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays unknown.** When the provider cannot derive `inputCapacity`, there is no budget: the gauge carries `tokens` alone, every result arrives whole, and the provider remains the capacity oracle ({§provider-capacity-admission}). Core never invents a stand-in.
|
|
5007
5178
|
|
|
5008
5179
|
§tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest packet-bearing model-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. The curation pair is the packet's measured weight and captured allowance, exactly as displayed to the model, not a recalculation using newer usage evidence. Packetless chronology cannot erase an assembled-request gauge. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
|
|
@@ -5029,7 +5200,7 @@ execute, enter model history, or become a later request's successful output.
|
|
|
5029
5200
|
| 200 | Messages answered, results observed, held work settled |
|
|
5030
5201
|
| 499 | Worker-scope or client cancellation |
|
|
5031
5202
|
| 429 | Turn allowance exhausted |
|
|
5032
|
-
| 413 | A result that does not fit ({§context-fit}), a packet over the budget ({§context-over-budget-row}: a row; the request still goes), a packet
|
|
5203
|
+
| 413 | A result that does not fit ({§context-fit}), a packet over the budget ({§context-over-budget-row}: a row; the request still goes), a packet that cannot fit the window even as receipts ({§context-wall}), or an upstream provider's own refusal ({§context-wall-measure}) |
|
|
5033
5204
|
| 500 / 508 | Strike threshold or invalid-emission exhaustion / crossing strike caused by a cycle |
|
|
5034
5205
|
| 504 | Loop timeout or exec-timeout restamp |
|
|
5035
5206
|
|
|
@@ -5089,7 +5260,7 @@ ordinary operation evidence still reaches that child's direct parent.
|
|
|
5089
5260
|
|
|
5090
5261
|
| Producer / event | Durable occurrence | Observer projection |
|
|
5091
5262
|
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
5092
|
-
| §env-delta-child-activity Direct-child activity | Child-authored final EDIT, COPY, MOVE, SEND, executor invocation, WORK, FORK, and targeted non-log KILL receipts, including failures. `_plurnk` initialization, maintenance, and operation turns stay with the worker. A reply already delivered to the parent uses its reply occurrence instead ({§message-reply-delivery}). | Direct parent only; one exact attributed row born body-suppressed. Incoming message projections ({§message-arrival}),
|
|
5263
|
+
| §env-delta-child-activity Direct-child activity | Child-authored final EDIT, COPY, MOVE, SEND, executor invocation, WORK, FORK, and targeted non-log KILL receipts, including failures. `_plurnk` initialization, maintenance, and operation turns stay with the worker. A reply already delivered to the parent uses its reply occurrence instead ({§message-reply-delivery}). | Direct parent only; one exact attributed row born body-suppressed. Incoming message projections ({§message-arrival}), NOTE, READ (including executor-output READs), FIND, BARE, WAIT, and log KILL never create activity occurrences. Provider reasoning, calls, rejected emissions, and turn sources do not cross automatically. |
|
|
5093
5264
|
| §env-delta-child-termination Direct-child termination | The child's exact terminal loop result, except loops containing only `_plurnk` operation or maintenance turns. A conclusion before the first turn still reports, including failed spawns. `source` names the actor; the READ selects the exact loop ({§loop-answer}). | Direct parent only; bounded, initially visible READ under {§worker-scheme-collect}, never the child's potentially newer loop. Excluded administrative loops create no pending child-result edge. |
|
|
5094
5265
|
| §env-delta-commons-mutation Commons mutation | One successful resolved operation whose landed effects touch `worker:///...`. | Every existing worker; one body-suppressed row per observer, deduplicated with any lineage audience. |
|
|
5095
5266
|
| §env-delta-filesystem-narration Project-file divergence | Runtime-owned reconciliation evidence remains in the runtime actor's own log. | No ambient observer row. Current content remains addressable and stale hash edits reject at their owned boundary. |
|
|
@@ -5120,7 +5291,7 @@ Stream progress remains owned by {§exec-stream}.
|
|
|
5120
5291
|
## §packet Packet shape
|
|
5121
5292
|
|
|
5122
5293
|
§packet-markdown **The packet's Markdown projection (#626).** Core renders the transformed section list
|
|
5123
|
-
into
|
|
5294
|
+
into the ordered messages of {§packet-wire-envelope}. Within each message, section order is
|
|
5124
5295
|
preserved. A nonempty section with a header renders as an H2 immediately followed
|
|
5125
5296
|
by its JSON object/array content; non-JSON content has one blank line after the
|
|
5126
5297
|
header. A null header renders only its content. Empty content is omitted, trailing
|
|
@@ -5141,15 +5312,16 @@ their boundaries ({§log-wire-format}).
|
|
|
5141
5312
|
| `definition` | system | Bare `plurnk.md`; no wrapper heading | {§definition-table-projection} |
|
|
5142
5313
|
| `system-policy` | system | Authored Markdown | {§policy-sections} |
|
|
5143
5314
|
| `inject` | system | Authored Markdown | {§packet-inject} |
|
|
5144
|
-
| `log`
|
|
5315
|
+
| `log`, `log/<coordinate>` | user | Chronological Markdown H3 records with JSON metadata | {§log-wire-format} |
|
|
5145
5316
|
| `worker` | user | JSON `path` with the literal Worker address, `parent` (address or `null`), `loop`, `turn` | {§packet-current-turn} |
|
|
5146
5317
|
| `delegation` | user | JSON `{workers, streams}` | {§child-orientation} |
|
|
5147
5318
|
| `errors` | user | JSON status/log-path pointers | {§operation-results} |
|
|
5148
|
-
| `notices` | user |
|
|
5319
|
+
| `notices` | user | One alert callout per notice, directive first | {§notice-callout} |
|
|
5149
5320
|
| `git` | user | Working-tree state in a NOTE blockquote | {§packet-cache-monotone} |
|
|
5150
|
-
| `budget` | user | JSON curation usage and ceiling
|
|
5321
|
+
| `budget` | user | JSON curation usage and ceiling | {§context-gauge} |
|
|
5151
5322
|
| `messages` | user | JSON pointers to the loop's unanswered immutable messages, path and source | {§message-arrival} |
|
|
5152
5323
|
| `recap` | user | Optional authored operational recap | {§recap} |
|
|
5324
|
+
| `emission-history/<coordinate>` | assistant | Complete retained operations at their emission records; replay omitted whole at capacity | {§emission-history} |
|
|
5153
5325
|
|
|
5154
5326
|
§packet-stored-shape **A model packet preserves the rendered request and, only
|
|
5155
5327
|
when an emission is admitted, its response.** Core assembles and measures the
|
|
@@ -5162,7 +5334,7 @@ leaves the request-only record, while rejected exchanges remain in their
|
|
|
5162
5334
|
| Turn state | `turns.packet` (the bag) + `turn_sections` rows |
|
|
5163
5335
|
| ----------------------------- | ----------------------------------------------- |
|
|
5164
5336
|
| No admitted model request (including initialization and local capacity rejection) | SQL `NULL`, no rows |
|
|
5165
|
-
| Request assembled | `{ weight, attributions }` + the sections as items;
|
|
5337
|
+
| Request assembled | `{ weight, attributions }` + the ordered sections as items; each selected program is stored at its emission boundary, with no empty placeholder ({§emission-history}) |
|
|
5166
5338
|
| Response admitted | `{ weight, attributions, assistant, assistantRaw }` + the sections as items |
|
|
5167
5339
|
|
|
5168
5340
|
§packet-items **Sections are rows over content-addressed items; the bag never holds them.**
|
|
@@ -5208,24 +5380,6 @@ of section weights for the rendered request weight.
|
|
|
5208
5380
|
|
|
5209
5381
|
§definition-table-projection The authored `plurnk.md` remains human-aligned. Its `definition` section deterministically removes Markdown table-cell padding and shortens separator cells to three dashes before extension transforms, measurement, storage, and wire rendering; alignment colons survive, while fenced blocks and all non-table whitespace remain exact.
|
|
5210
5382
|
|
|
5211
|
-
§lexicon **Vocabulary follows the standard of its audience.**
|
|
5212
|
-
|
|
5213
|
-
| Layer | Rule |
|
|
5214
|
-
|--------------------------|------|
|
|
5215
|
-
| Operator, wire, storage | Use the applicable industry term. Provider quantities follow the OpenAI vocabulary where it is standard: `contextWindow`, `reasoning`, `completion`, `finish_reason`, and usage nouns. |
|
|
5216
|
-
| Core lifecycle | Use the exact Workspace → Worker → Loop → Turn → Op hierarchy in {§lifecycle-terms}. An AG-UI Run or thread is always protocol-qualified. |
|
|
5217
|
-
| Model-facing packet | Use the model's training distribution: operations mirror HTTP and shell, while log records use ordinary Markdown headings, strict JSON metadata, and text coordinates. Renaming this vocabulary to internal API terminology would discard useful resonance for a standard the model never sees. |
|
|
5218
|
-
|
|
5219
|
-
| PLURNK-native term | Why it remains |
|
|
5220
|
-
|--------------------------------|----------------|
|
|
5221
|
-
| `worker` / `loop` / `turn` | The process hierarchy in {§lifecycle-terms}; unqualified `run` names no internal entity. |
|
|
5222
|
-
| `packet` | The assembled address space, a kernel concept rather than merely a provider request. |
|
|
5223
|
-
| `costUsd` | No standard cost field exists; the explicit currency avoids implied units, and the value remains an exact decimal string. |
|
|
5224
|
-
| `curationWeight` / `curationBudget` | Explicitly distinguish Core's model-independent context-shaping facts from physical provider tokens. |
|
|
5225
|
-
| the `chars/2` curation ruler | Model-agnostic by design ({§tokenomics-agnostic-ruler}); it is never presented as a tokenizer. |
|
|
5226
|
-
|
|
5227
|
-
Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualified `session` noun, `contextSize`, `decodeBudget`, and moved partition-knob names. <!-- lexicon-allow: this sentence enumerates the retired terms -->
|
|
5228
|
-
|
|
5229
5383
|
§body-projection **One full body, one readable view, one packet projection.** Every durable log row has one canonical full body resolved from its stored tx/rx envelope by `LogBody`. READ and FIND over `log:///`, persistent search derivation, and packet rendering apply the same deliberate trimming under {§log-readable-projection}. Packet rendering additionally applies initial suppression and these presentation bounds:
|
|
5230
5384
|
|
|
5231
5385
|
| row producer | ordinary visible projection |
|
|
@@ -5239,7 +5393,7 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
|
|
|
5239
5393
|
| a row the wall took | its size and address, no body and no native part ({§context-own-rows-fit}) |
|
|
5240
5394
|
| bodyless row | heading and any facts; no coordinate lines; `tokens` includes any selected native part |
|
|
5241
5395
|
|
|
5242
|
-
§markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, and the command it handed an executor. Its own reasoning, when it lands as a row, stands whole only when it fits the row's page and otherwise takes its last page ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and
|
|
5396
|
+
§markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, and the command it handed an executor. Its own reasoning, when it lands as a row, stands whole only when it fits the row's page and otherwise takes its last page ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and emission rows remain folded ({§emission-row}); those are the only exceptions, so the model can reason about every page the same way. A page lands under {§context-fit} like any result: whole when it fits the remaining budget, otherwise the prefix and receipt. Retrievals take their page at the source, before storage, and the packet applies no second cut to a stored result; a stored body takes its page in the packet, and the rest stays readable at the row's address. No operation carries a page size of its own.
|
|
5243
5397
|
|
|
5244
5398
|
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). When a visible projection differs from its canonical body, metadata carries `preview` under {§packet-extent-metadata}; complete and fully suppressed bodies omit it. ```` ```READ (log:///<coordinate>/<OP>) ```` selects untrimmed lines in original coordinates under {§log-readable-projection}; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. ```` ```FIND (log:///...) ```` and search match that same readable view. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
|
|
5245
5399
|
|
|
@@ -5290,7 +5444,7 @@ message — an AG-UI message UUID, an A2A address — stays the durable `path` t
|
|
|
5290
5444
|
delivery and reply accounting use, and remains addressable in its own scheme; the short form is an
|
|
5291
5445
|
additional alias. Answering either reaches the same message.
|
|
5292
5446
|
|
|
5293
|
-
§message-causal-source **Message authorship and delivery are distinct facts.** The harness publishes every arrival row; the row's `source` carries the canonical address of the causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter supplies its own canonical actor address through {§methods-loop-run}: the AG-UI
|
|
5447
|
+
§message-causal-source **Message authorship and delivery are distinct facts.** The harness publishes every arrival row; the row's `source` carries the canonical address of the causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter supplies its own canonical actor address through {§methods-loop-run}: the AG-UI module names the client's message under `agui://` ({§agui-run-source}), the inbound A2A adapter under `a2a://`. An absent source is the operator. Attribution persists with the message through the inbox, parking, orphan recovery, restart, and later log projection; model syntax cannot author it. The wire renders the row's `source` in place of its `origin`, which is constant for every arrival, except where the source is the transport that minted this very message, which says nothing the address does not ({§message-short-identity}). The operator's message is then the one arrival with no sender to show, so it renders `"origin": "user"`; a bare arrival would read as the model's own SEND and hide the request it answers. The Open Messages pointer carries the same attribution ({§message-arrival}).
|
|
5294
5448
|
|
|
5295
5449
|
§message-projection **Message storage is unbounded by model context; its arrival in the packet is not.** Core persists every accepted message completely before packet assembly. An arrival renders complete when it fits the remaining budget ({§context-fit}) and otherwise as its size and address, where a READ of the message's log body, scoped or whole, retrieves it. A peer worker's message is received text and arrives as its first page ({§markerless-first-page}). No share of the capacity is set aside for arrivals, and no knob sizes one.
|
|
5296
5450
|
|
|
@@ -5316,7 +5470,7 @@ their row shape, and their ordering are ordinary FIND projections owned by
|
|
|
5316
5470
|
The model's runtime alert surface has two distinct kinds of information:
|
|
5317
5471
|
|
|
5318
5472
|
- **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They can be scoped-KILLed, retired, and budgeted like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery `emissionAttempt` under {§invalid-emission-attempts}.
|
|
5319
|
-
- **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `search_progress`, and `
|
|
5473
|
+
- **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `search_progress`, and `output_unaccounted` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
|
|
5320
5474
|
|
|
5321
5475
|
The `log` is durable product truth. The `errors` section points at its failures
|
|
5322
5476
|
while the separate `notices` section displays transient observations. The two
|
|
@@ -5342,14 +5496,14 @@ retain distinct contracts and lifetimes.
|
|
|
5342
5496
|
separate item is minted for operation failures. Actionless engine rails mint
|
|
5343
5497
|
`op='error'` items because no authored operation row exists. Invalid provider
|
|
5344
5498
|
emissions are outside this channel because they are not turns. A bare
|
|
5345
|
-
failure status
|
|
5499
|
+
failure status or mismatched result/problem
|
|
5346
5500
|
statuses violate the producer contract and fail hard. Genuine
|
|
5347
5501
|
engine-internal faults crash and never mint model-facing rows.
|
|
5348
5502
|
- **Asynchronous work does not weaken the contract.** A stream-producing operation returns its initial `102` after acquisition. At conclusion the subscription stores the exact universal terminal result; `stream/concluded` carries it unchanged; the next ambient terminal READ merges it with the stream payload and preserves its Problem instance, assigning the committed `log:///.../READ` URI only when absent. Timeouts and service cancellations replace the complete terminal result with a new valid 504/499 Problem—they never mutate a status while retaining a contradictory Problem.
|
|
5349
5503
|
- **Self-explaining rows.** A problem `title` names the stable class and `detail` states the occurrence-specific cause. Producer-known operands belong in factual extensions. `stage` appears only when neighboring stages imply different recovery; `recovery` states one generally valid next action; `retryable` is true only when the producer recommends automatically retrying the identical request. Unknown recovery or retryability is omitted rather than guessed. General workflow teaching stays in the packet rather than being duplicated into every failure. The runtime-neutral writing contract is owned by `@plurnk/plurnk-contracts`.
|
|
5350
|
-
- **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add a missing durable `instance`, never replace an existing one; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection
|
|
5504
|
+
- **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add a missing durable `instance`, never replace an existing one; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, or a scheduler projection. A failed boundary without a valid Problem is a contract violation and fails hard.
|
|
5351
5505
|
- **Caught diagnostics are bounded.** Core-owned Problems may include a bounded preview of a caught runtime diagnostic when it states the occurrence-specific cause. `PLURNK_SERVICE_ERROR_DETAIL_LIMIT` owns that model-facing character bound; complete errors remain in daemon diagnostics. Input validation and stable contract failures do not spend this allowance on implementation text.
|
|
5352
|
-
- §notice-drain-on-read **Notices** - the few observations that are not log rows render one
|
|
5506
|
+
- §notice-drain-on-read **Notices** - the few observations that are not log rows render one callout each under their distinct `## Notices` section ({§notice-callout}), never a JSON dump. Packet rendering normalizes whitespace, bounds the producer message with the shared preview limits, and appends any typed position. The notice buffer drains on read; event Notices appear on at most one packet. Parking preserves pending notices for that loop's next packet; another loop cannot consume them. Terminal cleanup, including cancellation while parked, discards undelivered notices. This buffer is process-local, not restart-persistent. Stateful derivation progress and provider availability coalesce in the buffer, so clients observe every checkpoint live while a later model packet receives only the current state under ordinary level filtering.
|
|
5353
5507
|
- §rail-accounting-private **Rail accounting is private.** Visibility is owned by {§engine-rails}: the model sees concrete failures from admitted turns, never rejected emissions, attempt counts, the strike streak, or cycle detection. Surfacing internal state creates a gamification surface where the model optimizes for engine metrics instead of the task.
|
|
5354
5508
|
|
|
5355
5509
|
**The error rows (one channel) + the only non-log notices:**
|
|
@@ -5360,14 +5514,37 @@ retain distinct contracts and lifetimes.
|
|
|
5360
5514
|
| provider input capacity | `op='error'`, origin `_plurnk`, source `provider`; exact provider-owned `capacity-exceeded` Problem Details | 413 |
|
|
5361
5515
|
| max commands exceeded | `op='error'`, origin `_plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
|
|
5362
5516
|
|
|
5363
|
-
| notice `kind` | Source | Position |
|
|
5364
|
-
|
|
5365
|
-
| `
|
|
5366
|
-
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
|
|
5367
|
-
| `search_progress` | repository materialization/indexing lifecycle ({§persistent-search-index}); structured phase, count, and percent; `level: info`, `warn` when a completed pass carries failed members ({§derivation-member-failure}), `error` on terminal failure | none |
|
|
5368
|
-
| `git_inspection_refused` | engine membership — automatic Git inspection refused a supplied repository whose config declares a `filter.*` program ({§membership-git-hermetic}); names the key; `level: warn`, once per workspace until the key changes or clears | none |
|
|
5517
|
+
| notice `kind` | Source | Directive ({§notice-directive}) | Position |
|
|
5518
|
+
|---|---|---|---|
|
|
5519
|
+
| `output_unaccounted` | a provider whose billed output tokens exceed those its content and reasoning hold | none | content-offset at the end of the content |
|
|
5520
|
+
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | YOU SHOULD write the canonical form. | content-offset into the model's emission |
|
|
5521
|
+
| `search_progress` | repository materialization/indexing lifecycle ({§persistent-search-index}); structured phase, count, and percent; `level: info`, `warn` when a completed pass carries failed members ({§derivation-member-failure}), `error` on terminal failure | none | none |
|
|
5522
|
+
| `git_inspection_refused` | engine membership — automatic Git inspection refused a supplied repository whose config declares a `filter.*` program ({§membership-git-hermetic}); names the key; `level: warn`, once per workspace until the key changes or clears | none | none |
|
|
5523
|
+
| `continued_without_note` | engine turn — a continuing or parked model turn that admitted no NOTE ({§continued-without-note}); `level: warn` | YOU MUST use at least one NOTE per continuing turn. | none |
|
|
5524
|
+
| `budget_pressure` | engine context — a packet within its budget whose gauge is under pressure ({§context-pressure-notice}); `level: warn`; rendered with that packet, never buffered | YOU MUST NOT exceed budget. | none |
|
|
5525
|
+
| `outside_text` | engine turn — text the emission carried outside its operations, discarded ({§outside-text}); `level: warn` | YOU MUST NOT emit anything except whitespace between fenced operations. | none |
|
|
5526
|
+
| `invalid_emission` | engine grammar — a response rejected before dispatch; `level: error` | YOU MUST ONLY emit fenced operations; with the parameters, pattern, and terse aside on the fenced Operation line. | content-offset of the parser diagnostic, when it has one |
|
|
5527
|
+
| `output_truncated` | engine capacity or turn — an emission cut at the output allowance ({§output-allowance-notice}); `level: error` when the cut response was rejected, otherwise `warn` | YOU SHOULD emit fewer or shorter operations per turn. | none |
|
|
5528
|
+
| `provider_warning` | a provider warning: an SDK compatibility note, or native tool calls in a response that declared none; `level: warn` | YOU MUST NOT emit native tool calls. on the native tool calls; none on a compatibility note | none |
|
|
5529
|
+
| `provider_retry` | a provider stream that failed after output began and was answered by a complete retry; `level: warn` | none | none |
|
|
5530
|
+
| `provider_unavailable` | engine provider — a provider failure retried within its recovery budget | none | none |
|
|
5531
|
+
| `path_normalized` | file scheme — a path resolved to its canonical spelling; `level: warn` | YOU SHOULD address the resolved path. | none |
|
|
5532
|
+
| `read_fanout_bounded` | engine dispatcher — a READ whose glob matched more paths than it read; `level: warn` | YOU SHOULD narrow the glob, or FIND first. | none |
|
|
5533
|
+
| `parse_issues_unavailable` | engine mimetype — parser recovery evidence unavailable for a mimetype; `level: warn` | none | none |
|
|
5534
|
+
| `metadata_ignored` | engine dispatcher — `[metadata]` on an operation whose scheme takes none, run without it; `level: warn` | YOU SHOULD NOT write [metadata] on an operation that takes none. | none |
|
|
5535
|
+
| `scope_normalized` | engine slicer — a scope normalized to its canonical form; `level: warn` | YOU SHOULD write the normalized scope. | none |
|
|
5536
|
+
| `edit_merged` | engine slicer — an EDIT resolution rule applied to a batch ({§edit-batch-merges}); `level: warn` | YOU SHOULD verify the merged EDIT before building on it. | none |
|
|
5537
|
+
|
|
5538
|
+
§continued-without-note **A continuing turn that lapsed from the per-turn rule is told so.** The card's rule is one line, `YOU MUST emit at least one NOTE operation with a complete status summary and at least one other operation per turn.`, and the daemon's directive quotes it. When a model turn settles at 102 or 202, so the loop continues past it or parks on it, and it admitted no NOTE in its program or from its reasoning ({§reasoning-operations}), the next packet carries one `engine:turn` notice, `continued_without_note`, `level: warn`, with that directive and the message `The turn continued without a NOTE.`; when its program was NOTEs and nothing else, the next packet carries `noted_without_operation`, the same directive and the message `The turn carried NOTEs and no other operation.` Each is a notice, never a failure: it mints no row, never counts toward the strike rail, and never ends or alters a loop. A turn that concludes its loop, an empty turn, which carries its own no-operation row, and every non-model turn take none.
|
|
5539
|
+
|
|
5540
|
+
§notice-callout **A notice speaks in the card's callout form.** Each renders as one alert callout, its level choosing the callout: `> [!CAUTION]` for `error`, `> [!WARNING]` for `warn`, and `> [!NOTE]` for `info`, which no model packet carries. Inside it stand the directive ({§notice-directive}), then the message, any typed position as `@ line:column`, and the kind in brackets; a blank line separates consecutive callouts:
|
|
5541
|
+
|
|
5542
|
+
```text
|
|
5543
|
+
> [!WARNING]
|
|
5544
|
+
> YOU MUST use at least one NOTE per continuing turn. The turn continued without a NOTE. [continued_without_note]
|
|
5545
|
+
```
|
|
5369
5546
|
|
|
5370
|
-
§notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `
|
|
5547
|
+
§notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `output_unaccounted` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
|
|
5371
5548
|
|
|
5372
5549
|
§operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, independently curatable and exactly READable while active. The `errors` section surfaces a derived pointer to each. Rejected emissions stay in the forensic model-call and admission relations. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
|
|
5373
5550
|
|
|
@@ -5406,7 +5583,7 @@ USD and token totals with separately named known subtotals across every physical
|
|
|
5406
5583
|
calls included. It is the shared exact derivation from the ledger, never a second
|
|
5407
5584
|
stored fact, so a live watcher accrues running loop cost per turn (#465).
|
|
5408
5585
|
|
|
5409
|
-
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `
|
|
5586
|
+
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `output_unaccounted` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops://<worker>/<loop>/<turn>` source; the optional emission-history section shows a canonical program ({§emission-history}), so the position names a line of the source, which READ of its address shows. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
|
|
5410
5587
|
Reasoning normalization notices use source `grammar:reasoning` and omit the
|
|
5411
5588
|
content-offset position: reasoning coordinates do not address the content source.
|
|
5412
5589
|
|
|
@@ -5426,7 +5603,7 @@ Schema-backed targets link from that aside to
|
|
|
5426
5603
|
preserve the full tool description and raw input schema under
|
|
5427
5604
|
{§executor-input-schema-preview}; their nested paths do not contribute extra
|
|
5428
5605
|
Turn0 rows. A schema-backed general runtime uses `<runtime>/input.md`.
|
|
5429
|
-
Non-schema targets retain supplemental details
|
|
5606
|
+
Non-schema targets retain supplemental details after the framework-owned sections.
|
|
5430
5607
|
Tool-result/output schemas remain ordinary evidence, not teaching. Unknown-target
|
|
5431
5608
|
recovery names the published runtime document through the same path owner as
|
|
5432
5609
|
materialization, including a runtime's declared `resourcesPath`.
|
|
@@ -5461,10 +5638,10 @@ with a multiline regex over matching fences), so turn 0 names every tool with it
|
|
|
5461
5638
|
signature — one row per tool, paged like every survey. Capability attenuation
|
|
5462
5639
|
restricts that matcher to the admitted exact tools. No document is delivered
|
|
5463
5640
|
unasked.
|
|
5464
|
-
When the registry supplies {§executor-tool-catalog} definitions, the
|
|
5641
|
+
When the registry supplies {§executor-tool-catalog} definitions, the runtime
|
|
5465
5642
|
document links to its sibling `<runtime>.json`. The catalog contains exactly
|
|
5466
5643
|
the effective tools and is an ordinary `application/json` resource for READ,
|
|
5467
|
-
FIND, and JSONPath selection. It follows the same reconciliation as the
|
|
5644
|
+
FIND, and JSONPath selection. It follows the same reconciliation as the runtime
|
|
5468
5645
|
document and per-tool schemas; neither the catalog nor its definitions are
|
|
5469
5646
|
automatically included in turn 0 or expanded-tool surveys.
|
|
5470
5647
|
Attached tools are capabilities like every other runtime; the model never
|
|
@@ -5496,10 +5673,11 @@ The alias is a short name, suggested from the glob. `list` shows each
|
|
|
5496
5673
|
definition with what it resolved to — `include` or `exclude`, the pattern, the members it
|
|
5497
5674
|
admits or removes (count and a bounded sample), and for a model's inclusion the matches the
|
|
5498
5675
|
repository's ignore rules refused — so the model sees what its glob did and adapts.
|
|
5499
|
-
`discover` is introspection, never a catalog:
|
|
5500
|
-
(tracked, included by which pattern, a creation record,
|
|
5501
|
-
untracked, absent); a glob previews what `add` would include
|
|
5502
|
-
|
|
5676
|
+
`discover` is introspection, never a catalog: its one input, `query`, is a path or a glob. A path
|
|
5677
|
+
answers why it is or is not visible (tracked, included by which pattern, a creation record,
|
|
5678
|
+
excluded by which `!glob`, ignored, untracked, absent); a glob previews what `add` would include
|
|
5679
|
+
or exclude. A query that names neither, blank or a bare `!`, is 400 `query-invalid`. Names only,
|
|
5680
|
+
never content; nothing is added.
|
|
5503
5681
|
|
|
5504
5682
|
§members-configuration *Available definitions.* `PLURNK_MEMBERS_<alias>=<glob>`
|
|
5505
5683
|
declares one service-origin rule (`!glob` excludes). The shared naming and
|
|
@@ -5554,7 +5732,7 @@ same {§operator-config-env-defaults} renderer as the operator command, never th
|
|
|
5554
5732
|
effective environment. Native chapter files retain their owners and locations;
|
|
5555
5733
|
runtime-generated bytes have no invented disk location. Disable/enable,
|
|
5556
5734
|
shared workspace visibility, and project/global shadowing use the ordinary Skills lifecycle.
|
|
5557
|
-
Service-provided skills are
|
|
5735
|
+
Service-provided skills are host-provided trees, never fetched; removal follows {§skills-remove}.
|
|
5558
5736
|
|
|
5559
5737
|
The catalog and Turn0 describe Functionality under the current workspace
|
|
5560
5738
|
capability policy and service ceiling. A direct denied attempt receives the
|
|
@@ -5590,18 +5768,6 @@ surfaces with its cause and leaves no apparently initialized home.
|
|
|
5590
5768
|
After that bootstrap the file is user-owned: edits and deletion persist, and a
|
|
5591
5769
|
later boot never refreshes or recreates it.
|
|
5592
5770
|
|
|
5593
|
-
§legacy-home-transition A legacy `~/.plurnk` is never an ambient fallback. If
|
|
5594
|
-
legacy state exists while canonical destinations do not, ordinary startup
|
|
5595
|
-
fails with the exact `plurnk-service paths migrate` recovery. That explicit,
|
|
5596
|
-
idempotent command refuses destination conflicts and a live database owner,
|
|
5597
|
-
moves known user configuration and durable SQLite files to their semantic
|
|
5598
|
-
homes, byte-verifies the complete copied set before removing any source,
|
|
5599
|
-
discards only recognized generated references, and removes the empty legacy
|
|
5600
|
-
directory. A pre-commit failure rolls back canonical files and directories
|
|
5601
|
-
created by that attempt. Unknown legacy members or simultaneous
|
|
5602
|
-
legacy/canonical state fail without guessing. No dual read or dual write survives
|
|
5603
|
-
the transition.
|
|
5604
|
-
|
|
5605
5771
|
§schemes-self-doc-materialization **One generated reference tree per workspace.** `@plurnk/plurnk-schemes` owns `SchemeManifest.documentation` ({§manifest-self-doc}). Each reference carries an H2 `Summary` for ordinary catalog projection. `SchemeRegistry.docs(workspaceId)` resolves corpus-or-manifest documentation, and `referenceEntries` applies workspace capabilities to that source. One workspace materializer deletes vanished contributions and upserts current documents. Concurrent readers share the same reconciliation and outcome; independent workspaces do not serialize together. Ordinary runtime turns maintain {§worker-generated-subtree}, including under read-only workspace policy.
|
|
5606
5772
|
|
|
5607
5773
|
### §packet-git-status The Git status section — compact repository state
|
|
@@ -5635,6 +5801,13 @@ one dormant authored source. A failed read fails packet assembly with its cause.
|
|
|
5635
5801
|
The footer is one projection path and one authored source, not a second language
|
|
5636
5802
|
contract.
|
|
5637
5803
|
|
|
5804
|
+
§recap-lines The operator's recap lines lead the footer: every non-empty
|
|
5805
|
+
`PLURNK_SERVICE_RECAP_LINE_<alias>`, in alias order, renders as one callout ahead of the recap
|
|
5806
|
+
source, `> [!IMPORTANT]` for a `YOU MUST` line and `> [!TIP]` for `YOU SHOULD` and `YOU MAY`. A line
|
|
5807
|
+
that does not open with `YOU MUST`, `YOU MUST NOT`, `YOU MUST ONLY`, `YOU SHOULD`, `YOU SHOULD NOT` or
|
|
5808
|
+
`YOU MAY` is a configuration error naming its key, and an empty value turns a shipped line off. The
|
|
5809
|
+
shipped `recap.md` stays empty: it is the extension contract's source, not a home for core's lines.
|
|
5810
|
+
|
|
5638
5811
|
## Matcher selection and text regions
|
|
5639
5812
|
|
|
5640
5813
|
Matchers select resources and report evidence; text scopes independently
|
|
@@ -5960,8 +6133,10 @@ database is a benchmark artifact like any other: the lane's run directory lives
|
|
|
5960
6133
|
checkout holds source only — never run output. `test:intg` stamps `PLURNK_TEST_RUN` once and every
|
|
5961
6134
|
test process inherits it, so one suite's databases land in one directory without a pretest step, a
|
|
5962
6135
|
marker file or a sweep; an unstamped invocation is not a special case with its own rules, it is
|
|
5963
|
-
simply an unstamped run with its own directory. A
|
|
5964
|
-
|
|
6136
|
+
simply an unstamped run with its own directory. A lane whose suite boots Core through Core's test
|
|
6137
|
+
harness also exports `PLURNK_TEST_LANE`, its own lane name, so the daemon it boots writes into that
|
|
6138
|
+
lane's run directory and the lane's reclaim takes all of it; an unnamed run is Core's. A stamped run
|
|
6139
|
+
that passes is reclaimed when it exits; a failed suite's evidence is never touched and stays exactly where the run reported it. A cross-package test may reuse Core's migration fixture only by passing a path inside the
|
|
5965
6140
|
caller's own run directory.
|
|
5966
6141
|
|
|
5967
6142
|
§fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (every file row's origin is Git or constraint), and sig-coherence. Generated-pick incorporation and lifecycle require filesystem/Git evidence and are covered by the composed creation matrix rather than a false pure-database proxy. The harness runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
|
|
@@ -5975,7 +6150,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
5975
6150
|
| code | status | contract |
|
|
5976
6151
|
|---|---:|---|
|
|
5977
6152
|
| `target-required` | 400 | *OP* requires a target path. Recovery: Write the target in parentheses on the opening fence line: `OP (path)`. |
|
|
5978
|
-
| `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery})
|
|
6153
|
+
| `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery}) `Registered schemes: *names*.` |
|
|
5979
6154
|
| `scheme-metadata-unsupported` | 400 | *OP* on '*scheme*' does not accept the [metadata] modifier. |
|
|
5980
6155
|
| `operation-not-implemented` | 501 | Scheme '*name*' does not implement *OP* (or exec). |
|
|
5981
6156
|
| `entry-read-not-implemented` | 501 | The '*scheme*' scheme does not provide entry reads. |
|
|
@@ -5988,6 +6163,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
5988
6163
|
| `capability-denied` | 403 | Capability '*route*' is denied by *scope* policy. |
|
|
5989
6164
|
| `spawn-prompt-empty` | 422 | *OP* has no prompt text. Recovery: Write the prompt on the lines beneath the *OP* fence line. A prompt resource that is empty with no body says so: *OP* has no prompt text: the resource is empty and there is no body. Recovery: Write the prompt on the lines beneath the *OP* fence line, or name a resource that holds it. |
|
|
5990
6165
|
| `message-not-found` | 404 | No accepted message exists at *address*. |
|
|
6166
|
+
| `send-target-required` | 400 | SEND has no recipient and its loop has no published message. Recovery: Name a recipient address. |
|
|
5991
6167
|
| `edit-collision` | 409 | EDIT collided with the current resource state ({§edit-collision}). Recovery: *n* of *m* edits applied. READ the target for current coordinates. |
|
|
5992
6168
|
| `edit-target-required` | 400 | A line-anchored EDIT requires a target resource. Recovery: Provide the target that rendered the line anchor. |
|
|
5993
6169
|
| `kill-target-required` | 400 | KILL requires a target path. |
|
|
@@ -5998,15 +6174,13 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
5998
6174
|
| `channel-required` | 400 | The '*scheme*' scheme has no default channel. Recovery: Address a named channel with a URI fragment. |
|
|
5999
6175
|
| `binary-source-unsupported` | 415 | Channel #*name* is binary and its scheme keeps no bytes to transfer. |
|
|
6000
6176
|
| `metadata-unsupported` | 400 | *OP* takes only the env option; '*key*' is not one. |
|
|
6001
|
-
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace.
|
|
6177
|
+
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace. |
|
|
6002
6178
|
| `no-operation` | 422 | The turn performed no operation ({§empty-turn}). |
|
|
6003
|
-
| `send-target-not-a-recipient` | 400 | The addressed scheme is not a SEND recipient. Recovery:
|
|
6179
|
+
| `send-target-not-a-recipient` | 400 | The addressed scheme is not a SEND recipient. Recovery: Name a message address or a recipient that implements SEND. |
|
|
6004
6180
|
|
|
6005
|
-
§unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.**
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
otherwise it lists the schemes the workspace registers. READ, FIND, KILL and resource selection share
|
|
6009
|
-
the sentence.
|
|
6181
|
+
§unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.** Its recovery
|
|
6182
|
+
lists the schemes the workspace registers, and rebuilds the address into nothing else
|
|
6183
|
+
({§diagnostic-observation}). READ, FIND, KILL and resource selection share the sentence.
|
|
6010
6184
|
|
|
6011
6185
|
§problems-content **Content and transfer Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6012
6186
|
|
|
@@ -6038,11 +6212,11 @@ the sentence.
|
|
|
6038
6212
|
| `path-names-no-file` | 403 | The spelling '*path*' does not name a file: it is empty, or it names a directory. |
|
|
6039
6213
|
| `path-occupied-by-nonmember` | 403 | A non-member file already occupies '*path*'. Recovery: Choose an unoccupied member path. |
|
|
6040
6214
|
| `path-outside-workspace` | 403 | A symlink on '*path*' resolves outside the namespace. |
|
|
6041
|
-
| `binary-write-unsupported` | 415 | A text EDIT cannot author binary '*mimetype*'
|
|
6215
|
+
| `binary-write-unsupported` | 415 | A text EDIT cannot author binary '*mimetype*'. |
|
|
6042
6216
|
| `file-create-excluded` | 403 | A members exclusion (`!_glob_`) covers '*path*'. Recovery: Remove or disable the excluding members definition, or choose another path. |
|
|
6043
6217
|
| `file-create-gitignored` | 403 | Active Git policy ignores '*path*', and no members definition includes it. Recovery: Choose a Git-admitted path or add a members definition that includes it. |
|
|
6044
6218
|
| `file-materialization-limit` | 413 | The file exceeds the materialization byte limit and is not read into the workspace. |
|
|
6045
|
-
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery:
|
|
6219
|
+
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. A path beyond the root recovers instead to: '*path*' is outside the project root: only a members definition under the operator's namespace scope admits it. |
|
|
6046
6220
|
|
|
6047
6221
|
§problems-exec **Execution Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6048
6222
|
|
|
@@ -6071,12 +6245,12 @@ the sentence.
|
|
|
6071
6245
|
| code | status | contract |
|
|
6072
6246
|
|---|---:|---|
|
|
6073
6247
|
| `service-starting` | 503 | The PLURNK service owns this listener but has not admitted its client interface yet. |
|
|
6074
|
-
| `
|
|
6248
|
+
| `route-not-found` | 404 | The requested HTTP route does not exist. |
|
|
6075
6249
|
| `configuration-invalid` | 503 | The owning configuration reader's diagnostic, naming the invalid key. Recovery: Correct the named configuration input. Other capabilities remain available. |
|
|
6076
6250
|
| `name-reserved` | 400 | '*alias*' is plurnk's own: PLURNK_* configuration and provider credential names never reach a subprocess. |
|
|
6077
6251
|
| `value-invalid` | 400 | '*alias*' needs a string value. |
|
|
6078
6252
|
| `env-invalid` | 400 | `env` must be an object of string values; '*name*' is not a name a shell can export. |
|
|
6079
|
-
| `query-
|
|
6253
|
+
| `query-invalid` | 400 | '*query*' names no path or pattern. Recovery: Supply a path such as `docs/guide.md` or a pattern such as `docs/**`. |
|
|
6080
6254
|
| `headless` | 409 | The workspace has no project root, so there are no file members. Recovery: Open the workspace on a project root. |
|
|
6081
6255
|
| `definition-invalid` | 400 | A members definition is { glob }: a gitignore-style pattern, `!glob` to exclude. |
|
|
6082
6256
|
| `model-scope` | 403 | The model may not change membership here: the members scope is none. Recovery: `git add` the file so git tracks it, or ask the operator to add it (/members add) or raise PLURNK_SERVICE_MEMBERS_MODEL_SCOPE. |
|
|
@@ -6089,24 +6263,27 @@ the sentence.
|
|
|
6089
6263
|
| `offset-channel-required` | 400 | Recovery: Select the channel to read from the offset. |
|
|
6090
6264
|
| `target-invalid` | 400 | Recovery: Use a scheme://path target. |
|
|
6091
6265
|
| `proposal-not-pending` | 409 | Recovery: Refresh pending proposals before resolving one. |
|
|
6092
|
-
| `loop-policy-invalid` | 400 | An unattended loop cannot hold a proposal for review: nobody is present to answer. Recovery: State proposals accept or reject, or attend the loop. |
|
|
6093
6266
|
| `scope-cancelled` | 499 | The worker scope was cancelled: *reason*. |
|
|
6094
|
-
| `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery:
|
|
6267
|
+
| `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery: Trim one line with `<L>` or lines L through M with `<L,M>`; `KILL (log:///…/READ)` with no scope retires the whole row. |
|
|
6095
6268
|
|
|
6096
6269
|
§pinned-wording-core **Pinned wording.** Verbatim sentences tests pin: each is contract, and a change here is a change of contract.
|
|
6097
6270
|
|
|
6098
6271
|
| sentence | arises when |
|
|
6099
6272
|
|---|---|
|
|
6100
6273
|
| Nothing is in flight. Continuing. | a WAIT (or a premature terminal) with no live work ({§wait-obligation-matrix}) |
|
|
6101
|
-
|
|
|
6274
|
+
| All Open Messages resolved. Review new results; emit no OPs if finished. | resolved messages with unobserved results ({§loop-completion}) |
|
|
6102
6275
|
| Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn. | the over-budget row ({§context-over-budget-row}) |
|
|
6276
|
+
| YOU MUST NOT exceed budget. Context is at *N*% of budget. | a packet within its budget under pressure ({§context-pressure-notice}) |
|
|
6277
|
+
| YOU MUST use at least one NOTE per continuing turn. The turn continued without a NOTE. | a continuing or parked model turn without a NOTE ({§continued-without-note}) |
|
|
6278
|
+
| Each directive in the notice table | a notice of the model's own output ({§notice-directive}) |
|
|
6103
6279
|
| Context window overflow: the packet cannot fit the model's window even as receipts. | the wall ({§context-wall}) |
|
|
6104
|
-
|
|
|
6280
|
+
| No recipient implements the requested interaction. | The worker's owner is not interactive or does not declare the required client tool ({§client-interaction-routing}). |
|
|
6281
|
+
| Nobody is present to answer. Decide from what you already have, or conclude stating what you could not resolve. | dispatch of an interaction tool the worker's owner would not receive ({§owner-interaction-ring}) |
|
|
6105
6282
|
| Worker name '*name*' must match `[A-Za-z0-9][A-Za-z0-9_-]{0,62}`. Recovery: Use 1–63 ASCII letters, digits, '_' or '-', starting with a letter or digit. | an invalid worker name |
|
|
6106
6283
|
| Provide the client identifier. / Provide an absolute project path. / Use a positive integer limit. / prompt is not a non-empty string. | client input validation on the daemon's methods |
|
|
6107
6284
|
| The stream was cancelled by KILL. | a stream terminal after KILL |
|
|
6108
|
-
| '*
|
|
6109
|
-
| '*path*' is a directory, not a file; READ reads one file. Recovery:
|
|
6285
|
+
| '*runtime*' exited with code 127; `*program*` is a registered tool of `*owner*`. | a tool run as a shell command ({§exec-tool-fall-through}) |
|
|
6286
|
+
| '*path*' is a directory, not a file; READ reads one file. Recovery: `FIND (_path_/)` lists its files. | READ of a directory |
|
|
6110
6287
|
| The execution at ops://*worker*/*loop* has not concluded. | a bare READ of a running worker's result (425) |
|
|
6111
6288
|
| The child provider failed. | a child's provider failure read back by its parent |
|
|
6112
6289
|
| '*path*' exists on disk but is not a member of this workspace. Recovery: Admit it with `members (add)` and a `{"glob": "<path>"}` body. | a non-member on disk at the addressed path |
|