@plurnk/plurnk-service 1.18.0 → 1.19.1
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 +76 -13
- package/README.md +5 -3
- package/SPEC.md +925 -697
- package/dist/Paths.js +3 -3
- package/dist/build-info.json +1 -1
- package/dist/content/body-preview.d.ts +1 -0
- package/dist/content/body-preview.d.ts.map +1 -1
- package/dist/content/body-preview.js +8 -10
- package/dist/content/body-preview.js.map +1 -1
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +30 -29
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/line-anchors.d.ts.map +1 -1
- package/dist/content/line-anchors.js +17 -5
- package/dist/content/line-anchors.js.map +1 -1
- package/dist/content/read-projector.d.ts +2 -2
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +79 -37
- package/dist/content/read-projector.js.map +1 -1
- package/dist/content/scope-format.d.ts +9 -0
- package/dist/content/scope-format.d.ts.map +1 -0
- package/dist/content/scope-format.js +28 -0
- package/dist/content/scope-format.js.map +1 -0
- package/dist/core/AdministrativeLoop.d.ts +8 -0
- package/dist/core/AdministrativeLoop.d.ts.map +1 -0
- package/dist/core/AdministrativeLoop.js +16 -0
- package/dist/core/AdministrativeLoop.js.map +1 -0
- package/dist/core/AdmittedTurnExecutor.d.ts +2 -1
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +19 -19
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BareBatchRunner.d.ts +1 -2
- package/dist/core/BareBatchRunner.d.ts.map +1 -1
- package/dist/core/BareBatchRunner.js +7 -12
- package/dist/core/BareBatchRunner.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +3 -4
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +4 -2
- package/dist/core/CapabilityPolicies.d.ts.map +1 -1
- package/dist/core/CapabilityPolicies.js +23 -2
- package/dist/core/CapabilityPolicies.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +2 -2
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +6 -3
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +3 -6
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +8 -8
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +17 -11
- package/dist/core/ClientInteractions.d.ts +11 -1
- package/dist/core/ClientInteractions.d.ts.map +1 -1
- package/dist/core/ClientInteractions.js +26 -2
- package/dist/core/ClientInteractions.js.map +1 -1
- 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 +6 -6
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +12 -4
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +112 -90
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Dispatcher.sql +11 -26
- package/dist/core/DurableStatement.d.ts +4 -1
- package/dist/core/DurableStatement.d.ts.map +1 -1
- package/dist/core/DurableStatement.js +4 -4
- package/dist/core/DurableStatement.js.map +1 -1
- package/dist/core/EditMutations.d.ts.map +1 -1
- package/dist/core/EditMutations.js +5 -2
- package/dist/core/EditMutations.js.map +1 -1
- package/dist/core/Engine.d.ts +11 -9
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +27 -65
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +2 -22
- package/dist/core/EnvFlags.d.ts.map +1 -1
- package/dist/core/EnvFlags.js +4 -2
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +2 -1
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/KillHandler.d.ts.map +1 -1
- package/dist/core/KillHandler.js +7 -12
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/Knob.d.ts +9 -0
- package/dist/core/Knob.d.ts.map +1 -0
- package/dist/core/Knob.js +50 -0
- package/dist/core/Knob.js.map +1 -0
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +6 -35
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.d.ts.map +1 -1
- package/dist/core/LogEntryProjection.js +4 -0
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +2 -1
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LogWriter.js +2 -2
- package/dist/core/LogWriter.js.map +1 -1
- package/dist/core/LoopDriver.d.ts +1 -1
- package/dist/core/LoopDriver.d.ts.map +1 -1
- package/dist/core/LoopDriver.js +23 -29
- package/dist/core/LoopDriver.js.map +1 -1
- package/dist/core/LoopLifecycle.d.ts +4 -17
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +20 -22
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +36 -49
- package/dist/core/LoopOutcome.d.ts +10 -0
- package/dist/core/LoopOutcome.d.ts.map +1 -0
- package/dist/core/LoopOutcome.js +28 -0
- package/dist/core/LoopOutcome.js.map +1 -0
- package/dist/core/LoopPolicies.d.ts +7 -0
- package/dist/core/LoopPolicies.d.ts.map +1 -0
- package/dist/core/LoopPolicies.js +37 -0
- package/dist/core/LoopPolicies.js.map +1 -0
- package/dist/core/MessageResources.d.ts +15 -0
- package/dist/core/MessageResources.d.ts.map +1 -0
- package/dist/core/MessageResources.js +46 -0
- package/dist/core/MessageResources.js.map +1 -0
- package/dist/core/MessageResources.sql +36 -0
- package/dist/core/OperatorConfig.d.ts +2 -1
- package/dist/core/OperatorConfig.d.ts.map +1 -1
- package/dist/core/OperatorConfig.js +14 -6
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +20 -35
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +24 -6
- package/dist/core/PatternSelection.d.ts +1 -1
- package/dist/core/PatternSelection.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts +3 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +85 -22
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts +1 -0
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +12 -7
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ReasoningView.d.ts +1 -2
- package/dist/core/ReasoningView.d.ts.map +1 -1
- package/dist/core/ReasoningView.js +9 -20
- package/dist/core/ReasoningView.js.map +1 -1
- package/dist/core/ResourceBindings.d.ts.map +1 -1
- package/dist/core/ResourceBindings.js +5 -4
- package/dist/core/ResourceBindings.js.map +1 -1
- package/dist/core/ResourceMutations.d.ts +4 -4
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +2 -3
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/ResourceSelector.d.ts +10 -3
- package/dist/core/ResourceSelector.d.ts.map +1 -1
- package/dist/core/ResourceSelector.js +52 -13
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.d.ts.map +1 -1
- package/dist/core/ResourceTransfers.js +4 -2
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +2 -0
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +11 -5
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/StoredPacket.d.ts +3 -1
- package/dist/core/StoredPacket.d.ts.map +1 -1
- package/dist/core/StoredPacket.js +7 -3
- package/dist/core/StoredPacket.js.map +1 -1
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +9 -3
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/TerminalResult.d.ts +2 -2
- package/dist/core/TerminalResult.d.ts.map +1 -1
- package/dist/core/TerminalResult.js +15 -8
- package/dist/core/TerminalResult.js.map +1 -1
- package/dist/core/ToolInputSchema.d.ts.map +1 -1
- package/dist/core/ToolInputSchema.js +24 -8
- 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 +45 -23
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/Turn.d.ts +3 -1
- package/dist/core/Turn.d.ts.map +1 -1
- package/dist/core/Turn.js +4 -1
- package/dist/core/Turn.js.map +1 -1
- package/dist/core/Turn.sql +14 -2
- package/dist/core/TurnDispositionHandler.d.ts +13 -21
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
- package/dist/core/TurnDispositionHandler.js +32 -190
- package/dist/core/TurnDispositionHandler.js.map +1 -1
- package/dist/core/TurnMaterialization.d.ts +9 -7
- package/dist/core/TurnMaterialization.d.ts.map +1 -1
- package/dist/core/TurnMaterialization.js +63 -41
- package/dist/core/TurnMaterialization.js.map +1 -1
- package/dist/core/TurnMaterialization.sql +23 -6
- package/dist/core/TurnOps.js +1 -1
- package/dist/core/TurnRunner.d.ts +1 -3
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +148 -189
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/TurnRunner.sql +1 -24
- package/dist/core/TurnSources.sql +42 -11
- package/dist/core/WorkerName.d.ts +1 -1
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +3 -3
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/ambient.sql +45 -19
- package/dist/core/attachments.d.ts +3 -1
- package/dist/core/attachments.d.ts.map +1 -1
- package/dist/core/attachments.js +4 -0
- package/dist/core/attachments.js.map +1 -1
- package/dist/core/caps/CoreInteractionCaps.d.ts +1 -1
- package/dist/core/caps/CoreInteractionCaps.d.ts.map +1 -1
- package/dist/core/caps/CoreInteractionCaps.js +4 -2
- package/dist/core/caps/CoreInteractionCaps.js.map +1 -1
- package/dist/core/caps/DbChannelCaps.js +6 -6
- package/dist/core/caps/DbChannelCaps.js.map +1 -1
- package/dist/core/caps/DbEntryCaps.js +1 -1
- package/dist/core/caps/DbEntryCaps.js.map +1 -1
- package/dist/core/caps/DbMessageCaps.d.ts +10 -0
- package/dist/core/caps/DbMessageCaps.d.ts.map +1 -0
- package/dist/core/caps/DbMessageCaps.js +39 -0
- package/dist/core/caps/DbMessageCaps.js.map +1 -0
- package/dist/core/caps/DbProjectionCaps.d.ts +2 -2
- package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +10 -4
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +3 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +11 -0
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/fork.sql +7 -6
- package/dist/core/git-state.d.ts +3 -2
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +37 -20
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/packet-inject.js +1 -1
- package/dist/core/packet-wire.d.ts +11 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +112 -88
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +4 -5
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +10 -31
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/scheme-types.d.ts +3 -1
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +2 -1
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/types.d.ts +1 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-ops.sql +3 -8
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +35 -30
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/DigestRender.d.ts +1 -0
- package/dist/digest/DigestRender.d.ts.map +1 -1
- package/dist/digest/DigestRender.js +53 -1
- package/dist/digest/DigestRender.js.map +1 -1
- package/dist/digest/DigestRequiem.d.ts.map +1 -1
- package/dist/digest/DigestRequiem.js +13 -15
- package/dist/digest/DigestRequiem.js.map +1 -1
- package/dist/digest/digest-db.d.ts +3 -0
- package/dist/digest/digest-db.d.ts.map +1 -0
- package/dist/digest/digest-db.js +68 -0
- package/dist/digest/digest-db.js.map +1 -0
- package/dist/digest/digest-paths.d.ts +6 -0
- package/dist/digest/digest-paths.d.ts.map +1 -0
- package/dist/digest/digest-paths.js +23 -0
- package/dist/digest/digest-paths.js.map +1 -0
- package/dist/digest/digest-rows.d.ts +15 -0
- package/dist/digest/digest-rows.d.ts.map +1 -1
- package/dist/digest/digest.sql +13 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/observe/genai.d.ts +2 -2
- package/dist/observe/genai.d.ts.map +1 -1
- package/dist/observe/genai.js +15 -5
- package/dist/observe/genai.js.map +1 -1
- package/dist/schemes/EffectPolicy.d.ts +0 -2
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +25 -36
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts +4 -5
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +74 -62
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +6 -5
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +49 -16
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +28 -20
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +4 -4
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +29 -9
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +14 -1
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/TurnSource.d.ts +3 -2
- package/dist/schemes/TurnSource.d.ts.map +1 -1
- package/dist/schemes/TurnSource.js +80 -35
- package/dist/schemes/TurnSource.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +22 -56
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.js +6 -6
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +19 -17
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +6 -5
- 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 +6 -3
- package/dist/schemes/_entry-fts.js.map +1 -1
- package/dist/schemes/_entry-fts.sql +25 -6
- package/dist/schemes/_entry-manifest.d.ts +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +5 -3
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.js +4 -4
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +2 -2
- package/dist/schemes/_entry-readable.d.ts.map +1 -1
- package/dist/schemes/_entry-readable.js +5 -4
- package/dist/schemes/_entry-readable.js.map +1 -1
- package/dist/schemes/_entry-send.js +2 -2
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/_search-exclusion.d.ts +1 -0
- package/dist/schemes/_search-exclusion.d.ts.map +1 -1
- package/dist/schemes/_search-exclusion.js +12 -0
- package/dist/schemes/_search-exclusion.js.map +1 -1
- package/dist/schemes/_search-index.js +4 -4
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/schemes/exec-abort.d.ts.map +1 -1
- package/dist/schemes/exec-abort.js +4 -3
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/schemes/exec-lifetime.d.ts +11 -0
- package/dist/schemes/exec-lifetime.d.ts.map +1 -0
- package/dist/schemes/exec-lifetime.js +29 -0
- package/dist/schemes/exec-lifetime.js.map +1 -0
- package/dist/server/ClientReads.d.ts.map +1 -1
- package/dist/server/ClientReads.js +3 -1
- package/dist/server/ClientReads.js.map +1 -1
- package/dist/server/Daemon.d.ts +30 -7
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +107 -48
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +19 -5
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +13 -11
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +87 -98
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/EnvFunctionality.d.ts +12 -3
- package/dist/server/EnvFunctionality.d.ts.map +1 -1
- package/dist/server/EnvFunctionality.js +19 -14
- package/dist/server/EnvFunctionality.js.map +1 -1
- package/dist/server/Functionality.d.ts +2 -2
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +97 -62
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +3 -1
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +11 -5
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/HttpListener.d.ts +16 -0
- package/dist/server/HttpListener.d.ts.map +1 -0
- package/dist/server/HttpListener.js +81 -0
- package/dist/server/HttpListener.js.map +1 -0
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +12 -16
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/PlurnkSkill.d.ts.map +1 -1
- package/dist/server/PlurnkSkill.js +1 -0
- package/dist/server/PlurnkSkill.js.map +1 -1
- package/dist/server/Retention.d.ts +11 -0
- package/dist/server/Retention.d.ts.map +1 -1
- package/dist/server/Retention.js +47 -2
- package/dist/server/Retention.js.map +1 -1
- package/dist/server/Retention.sql +32 -1
- package/dist/server/ServiceModules.d.ts.map +1 -1
- package/dist/server/ServiceModules.js +2 -0
- package/dist/server/ServiceModules.js.map +1 -1
- package/dist/server/SkillsFunctionality.d.ts +2 -0
- package/dist/server/SkillsFunctionality.d.ts.map +1 -1
- package/dist/server/SkillsFunctionality.js +22 -15
- package/dist/server/SkillsFunctionality.js.map +1 -1
- package/dist/server/WorkspaceCapabilities.d.ts.map +1 -1
- package/dist/server/WorkspaceCapabilities.js +1 -0
- package/dist/server/WorkspaceCapabilities.js.map +1 -1
- package/dist/server/WorkspaceStorage.d.ts +8 -0
- package/dist/server/WorkspaceStorage.d.ts.map +1 -0
- package/dist/server/WorkspaceStorage.js +26 -0
- package/dist/server/WorkspaceStorage.js.map +1 -0
- package/dist/server/client-input.d.ts +4 -3
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +24 -26
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +2 -2
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +69 -132
- package/dist/server/envelope.d.ts +2 -2
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +7 -9
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +10 -6
- package/dist/server/exec-poll-backoff.js +3 -3
- package/dist/server/exec-poll-backoff.js.map +1 -1
- package/dist/server/lifecycle-recovery.sql +8 -35
- package/dist/server/logEntry.sql +2 -2
- package/dist/server/loopDocs.js +3 -3
- package/dist/server/loopDocs.sql +4 -2
- package/dist/server/model-catalog.d.ts.map +1 -1
- package/dist/server/model-catalog.js +2 -2
- package/dist/server/model-catalog.js.map +1 -1
- package/dist/server/seam-loop.sql +0 -1
- package/dist/server/workspace-storage.sql +8 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +21 -10
- package/dist/service.js.map +1 -1
- package/docs/copy-move.md +31 -0
- package/docs/env.md +19 -7
- package/docs/skills.md +2 -2
- package/migrations/002_workers.sql +26 -17
- package/migrations/003_loops.sql +82 -28
- package/migrations/005_entries.sql +135 -22
- package/migrations/006_log.sql +77 -25
- package/migrations/007_subscriptions.sql +10 -15
- package/package.json +35 -36
- package/dist/core/PromptFrames.d.ts +0 -12
- package/dist/core/PromptFrames.d.ts.map +0 -1
- package/dist/core/PromptFrames.js +0 -28
- package/dist/core/PromptFrames.js.map +0 -1
- package/dist/schemes/Prompt.d.ts +0 -8
- package/dist/schemes/Prompt.d.ts.map +0 -1
- package/dist/schemes/Prompt.js +0 -25
- package/dist/schemes/Prompt.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -4,35 +4,35 @@ Canonical contracts plurnk-service exposes, architecture it implements, promises
|
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
7
|
-
- [Glossary](#glossary
|
|
7
|
+
- [Glossary](#glossary)
|
|
8
8
|
- [Architecture](#arch-architecture)
|
|
9
9
|
- [Workers and workspace boundaries](#actor-boundary-workers-and-workspace-boundaries)
|
|
10
10
|
- [File membership and project roots](#membership-file-membership-and-project-roots)
|
|
11
11
|
- [Loop scheduling and lifecycle](#worker-loop-lifecycle-loop-scheduling-and-lifecycle)
|
|
12
|
-
- [Provider Contract](#provider-
|
|
12
|
+
- [Provider Contract](#provider-contract)
|
|
13
13
|
- [Scheme Contract](#scheme-scheme-contract)
|
|
14
14
|
- [Mimetype Contract](#mimetype-mimetype-contract)
|
|
15
15
|
- [Search indexing](#persistent-search-index-search-indexing)
|
|
16
16
|
- [Channel Topology](#channels-channel-topology)
|
|
17
|
-
- [Op Surface](#op-
|
|
17
|
+
- [Op Surface](#op-surface)
|
|
18
18
|
- [Proposals and client interactions](#proposal-proposals-and-client-interactions)
|
|
19
19
|
- [Stream Model](#stream-stream-model)
|
|
20
|
-
- [Storage Model](#storage-
|
|
20
|
+
- [Storage Model](#storage-model)
|
|
21
21
|
- [Plugin composition](#core-plugin-composition-plugin-composition)
|
|
22
22
|
- [Bundled Set](#bundled-set-bundled-set)
|
|
23
|
-
- [Grammar Dependency](#grammar-
|
|
23
|
+
- [Grammar Dependency](#grammar-dependency)
|
|
24
24
|
- [Operator Configuration](#operator-config-operator-configuration)
|
|
25
25
|
- [Module seam](#rpc-module-seam)
|
|
26
|
-
- [Workspace Functionality](#
|
|
26
|
+
- [Workspace Functionality](#workspace-functionality)
|
|
27
27
|
- [Application interface](#methods-application-interface)
|
|
28
28
|
- [Packet assembly](#packet-assembly-packet-assembly)
|
|
29
29
|
- [Packet shape](#packet-packet-shape)
|
|
30
|
-
- [Matcher selection and text regions](#matcher-
|
|
31
|
-
- [Testing and evidence](#
|
|
30
|
+
- [Matcher selection and text regions](#matcher-selection-and-text-regions)
|
|
31
|
+
- [Testing and evidence](#testing-and-evidence)
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
|
-
##
|
|
35
|
+
## Glossary
|
|
36
36
|
|
|
37
37
|
Canonical meanings. When a doc, comment, test name, or commit message uses one of these words, it means exactly what's written here. Drift is a bug.
|
|
38
38
|
|
|
@@ -66,28 +66,28 @@ flowchart LR
|
|
|
66
66
|
| **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
|
|
67
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
68
|
|
|
69
|
-
###
|
|
69
|
+
### Storage terms
|
|
70
70
|
|
|
71
71
|
| Term | Meaning |
|
|
72
72
|
|---|---|
|
|
73
73
|
| **entry** | The unit of canonical state. Identity: `(workspace_id, scheme, authority, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus scheme-private `attributes`. |
|
|
74
74
|
| **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, curation `weight`, and lifecycle `state`. |
|
|
75
|
-
| **scheme** | An addressed capability family + handler. Built-ins include `worker`, `
|
|
76
|
-
| **mimetype** | A channel's content type. Drives the handler that produces the structural projections (`symbols`, `deepJson`, `deepXml`). Consumption surface {§mimetype
|
|
77
|
-
| **provider** | An LLM transport implementing the `@plurnk/plurnk-providers` `Provider` interface. Core supplies an assembled request and generation context; the provider owns endpoint adaptation and normalized response evidence. Consumption surface {§provider}; author contract: [plurnk-providers](../plurnk-providers/SPEC.md). |
|
|
75
|
+
| **scheme** | An addressed capability family + handler. Built-ins include `worker`, `log`, `ops`, `reasoning`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes executions but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
|
|
76
|
+
| **mimetype** | A channel's content type. Drives the handler that produces the structural projections (`symbols`, `deepJson`, `deepXml`). Consumption surface {§mimetype}; author contract: [plurnk-mimetypes](../plurnk-mimetypes/SPEC.md). |
|
|
77
|
+
| **provider** | An LLM transport implementing the `@plurnk/plurnk-providers` `Provider` interface. Core supplies an assembled request and generation context; the provider owns endpoint adaptation and normalized response evidence. Consumption surface {§provider-surface}; author contract: [plurnk-providers](../plurnk-providers/SPEC.md). |
|
|
78
78
|
|
|
79
|
-
###
|
|
79
|
+
### State / status
|
|
80
80
|
|
|
81
81
|
Independent axes on entries and channels. Confusion across them is a recurring source of bugs.
|
|
82
82
|
|
|
83
83
|
| Term | Type | Meaning |
|
|
84
84
|
|---|---|---|
|
|
85
|
-
| **status** | HTTP int | Outcome of an operation. Carried on `log_entries.status_rx`, returned from op handlers. Per the catalogue ({§
|
|
85
|
+
| **status** | HTTP int | Outcome of an operation. Carried on `log_entries.status_rx`, returned from op handlers. Per the catalogue ({§operation-results}). |
|
|
86
86
|
| **channel state** | `static \| active \| closed \| errored` | Streaming lifecycle of a channel's content. Metadata, not gating — engine renders content regardless of state. |
|
|
87
87
|
| **proposal state** | `proposed \| resolved \| failed \| cancelled` | Proposal lifecycle (`log_entries.state`) under {§proposal}; distinct from entry identity and channel state. |
|
|
88
88
|
| **outcome** | `string \| null` | Short reason for `failed`/`cancelled` (`"permission:403"`, `"aborted"`, `"not_found"`). Opaque to most callers. |
|
|
89
89
|
|
|
90
|
-
###
|
|
90
|
+
### Writer / authority
|
|
91
91
|
|
|
92
92
|
| Term | Meaning |
|
|
93
93
|
|---|---|
|
|
@@ -95,7 +95,7 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
95
95
|
| **origin** | Synonym for writer in log_entries (`log_entries.origin`). Historical naming; treat as equivalent. |
|
|
96
96
|
| **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
|
|
97
97
|
|
|
98
|
-
###
|
|
98
|
+
### Execution terms
|
|
99
99
|
|
|
100
100
|
| Term | Meaning |
|
|
101
101
|
|------------------------------|---|
|
|
@@ -124,17 +124,11 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
124
124
|
Daemon composition and startup. Worker attention and workspace state follow
|
|
125
125
|
{§actor-boundary} and {§machine-processes}.
|
|
126
126
|
|
|
127
|
-
###
|
|
127
|
+
### Ecosystem
|
|
128
128
|
|
|
129
129
|
The root [`ARCHITECTURE.md`](../ARCHITECTURE.md) owns the platform process and
|
|
130
130
|
package map. The default installed composition is specified in {§bundled-set}.
|
|
131
131
|
|
|
132
|
-
§ecosystem-composed-host Core is the composed runtime: it owns persistence,
|
|
133
|
-
scheduling, packet assembly, dispatch, and cross-capability orchestration while
|
|
134
|
-
consuming the language and each capability family's author contract. Domain
|
|
135
|
-
logic stays with its owning package. AG-UI projects that runtime to clients;
|
|
136
|
-
clients render and submit actions but contain no engine logic.
|
|
137
|
-
|
|
138
132
|
### §observability-boundary Observability boundary
|
|
139
133
|
|
|
140
134
|
OpenTelemetry may observe PLURNK; it never becomes product state, failure transport, scheduler input, model teaching, or client protocol. Domain and client activity remain on AG-UI. Reusable packages depend on the OTel API only; the daemon constructs only the explicitly configured trace and metric providers. An unconfigured or standards-valid disabled process loads no SDK or exporter implementation and keeps the API's no-op behavior with bounded overhead. OTel Logs have no provider or initialization path.
|
|
@@ -142,11 +136,15 @@ OpenTelemetry may observe PLURNK; it never becomes product state, failure transp
|
|
|
142
136
|
Configuration uses the standard `OTEL_*` environment: `OTEL_TRACES_EXPORTER` / `OTEL_METRICS_EXPORTER` select `otlp` or `console` per signal (a missing or `none` value keeps that signal off; no SDK default selects an exporter), `OTEL_SERVICE_NAME` names the service (default `plurnk-service`), case-insensitive `true` in `OTEL_SDK_DISABLED` turns the boundary off, and OTLP exporters honor `OTEL_EXPORTER_OTLP_*`. An unknown exporter name fails daemon boot; a typo never silently disables observation. OTel Logs and direct draft semantic-convention use are excluded. HTTP spans carry only an AG-UI-owned bounded route class, never an input pathname or query. Spans otherwise carry high-cardinality identifiers; metric labels stay low-cardinality. Prompts, reasoning, file bodies, arbitrary URLs, secrets, and plugin payloads are never recorded as attributes or metric values by default. Exporter failure cannot change product results or client lifecycle. Daemon, telemetry, and database teardown are independent reverse-ownership phases; every phase runs and aggregate failure preserves every cause.
|
|
143
137
|
|
|
144
138
|
§observability-genai-conventions **GenAI convention projection.** Provider
|
|
145
|
-
request spans
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
request spans follow the [GenAI registry at `c88d504`](https://github.com/open-telemetry/semantic-conventions-genai/tree/c88d504ab3d9879f8e50d3cc87e69775e11db234),
|
|
140
|
+
which depends on core semantic conventions v1.44.0: a CLIENT-kind
|
|
141
|
+
`chat {model}` span carrying `gen_ai.operation.name` (`chat`),
|
|
142
|
+
`gen_ai.provider.name` (the constructed route's provider ID in the registry's
|
|
143
|
+
spelling, never its tuning alias; unmatched IDs are preserved, `other` for an
|
|
144
|
+
unregistered handle), and `gen_ai.request.model`;
|
|
148
145
|
on settlement it gains `gen_ai.usage.input_tokens` and
|
|
149
|
-
`gen_ai.usage.output_tokens`
|
|
146
|
+
`gen_ai.usage.output_tokens` by aggregating every reported request quantity in
|
|
147
|
+
validated accounting ({§tokenomics-provider-usage}), plus
|
|
150
148
|
`gen_ai.response.finish_reasons`; failures carry `error.type` as the class
|
|
151
149
|
name only. Plurnk custom attributes (attempt, kind, status, loop/turn ids)
|
|
152
150
|
ride alongside and never replace the convention attributes. The redaction
|
|
@@ -154,59 +152,34 @@ boundary is unchanged — no prompts, reasoning, bodies, or URLs. This is the
|
|
|
154
152
|
sanctioned exception to the blanket draft-convention exclusion; no other
|
|
155
153
|
draft convention is projected.
|
|
156
154
|
|
|
157
|
-
###
|
|
158
|
-
|
|
159
|
-
Seven principles govern which exterior standards Plurnk conforms to (#299):
|
|
160
|
-
|
|
161
|
-
1. **UVP first.** Never conform away what users chose Plurnk for; the OP grammar, curated log, packet, and worker graph are the product, not a compatibility gap.
|
|
162
|
-
2. **Right-fit.** Hobbyist-first: an enterprise-grade feature is acceptable only when its cost lands on the party that wants it, never on general adoption.
|
|
163
|
-
3. **Traction.** Count running counterparties today; integration horizon must be shorter than the standard's expected half-life. Sockets stay configurable with no default until a candidate earns it.
|
|
164
|
-
4. **POSIX app identity.** Decades-stable host-ecosystem conventions (XDG, NO_COLOR, man, completions, service units) outrank months-stable AI-pipeline fashions.
|
|
165
|
-
5. **Faces, never organs.** A standard adopts as one adapter or projection behind an existing seam; if it cannot, that is the alarm, and it goes to a design gate.
|
|
166
|
-
6. **Deletion is the price of admission.** A standard earns adoption by deleting bespoke surface (the ACP Plan object deleted the Markdown plan microformat); parallel representations, second discovery paths, and compatibility grammars are refused.
|
|
167
|
-
7. **Two arbiters.** Model-facing surfaces change only on measured model evidence; human-facing surfaces follow host-ecosystem convention without ceremony. Standards bodies get a vote on neither.
|
|
168
|
-
|
|
169
|
-
### §in-process In-process architecture
|
|
170
|
-
|
|
171
|
-
Composed daemon internals + admin CLI. Four plug points:
|
|
172
|
-
|
|
173
|
-
- **Providers** ({§provider}) — LLM transports. Engine sends a turn's messages, receives raw content + usage; engine parses the content into `PlurnkStatement[]`.
|
|
174
|
-
- **Schemes** ({§scheme}) — addressed capabilities. A scheme handler interprets targets under its prefix and owns its storage substrate.
|
|
175
|
-
- **Mimetypes** ({§mimetype}) — content interpretation. Render-time handlers consume channel content; framework owns the dispatch.
|
|
176
|
-
- **Executors** ({§exec} / {§bundled-set}) — execution dispatch for subprocess, data, and pure-computation runtimes; web discovery rides the ordinary MCP surface.
|
|
177
|
-
|
|
178
|
-
Core's internal owners compose without becoming new package or public seams:
|
|
179
|
-
|
|
180
|
-
| Owner | Machine |
|
|
181
|
-
|-------|---------|
|
|
182
|
-
| `Daemon` | Process/module lifecycle, dependency composition, provider policy, notifications, and the external client façade. |
|
|
183
|
-
| `DrainSupervisor` | One worker's queue consumer, drain identity, wake obligations, cancellation scope, poll/park timers, and terminal cleanup. |
|
|
184
|
-
| `Engine` | Loop lifecycle and the public turn, dispatch, derivation, and proposal façades. |
|
|
185
|
-
| `TurnRunner` | Model inference and `_plurnk` initialization, from materialization and output admission through operation settlement. |
|
|
186
|
-
| `Dispatcher` | Operation admission/routing, scheme execution, proposal waiting, curation, and durable log writes. |
|
|
187
|
-
| `ResourceMutations` | EDIT/COPY/MOVE selection, anchor preconditions, cross-scheme effects, and mutation settlement. |
|
|
188
|
-
|
|
189
|
-
Capability-specific behavior remains with the owning plug point.
|
|
155
|
+
### In-process architecture
|
|
190
156
|
|
|
191
|
-
The
|
|
192
|
-
|
|
193
|
-
Server posture: this package is the one long-running runtime process. `plurnk-agui` exposes its external protocol; user-facing clients run separately and do not call core's in-process seam directly.
|
|
157
|
+
The process and package map is ARCHITECTURE.md's; this package's AGENTS.md maps core's internal
|
|
158
|
+
owners. Capability-specific behavior remains with the owning plug point.
|
|
194
159
|
|
|
195
160
|
§service-worker-composition The service launcher and the live/demo workspace
|
|
196
|
-
helper share one registration of default worker-facing modules: MCP
|
|
197
|
-
A2A. Their management families and readable reference documents are
|
|
198
|
-
with no enabled
|
|
199
|
-
surface; registering a family does not enable
|
|
161
|
+
helper share one registration of default worker-facing modules: MCP, outbound
|
|
162
|
+
A2A, and Schedule. Their management families and readable reference documents are
|
|
163
|
+
present even with no enabled definitions. Workspace capability policy controls every actor's
|
|
164
|
+
surface; registering a family does not enable its definitions. The real-model
|
|
165
|
+
profile ({§operator-config-real-model-profile}) leaves ambient MCP attachments and
|
|
166
|
+
service schedules disabled by default; specimens may add their own through the
|
|
167
|
+
ordinary management surface. Client and
|
|
200
168
|
inbound-A2A listeners and host hooks remain launcher-owned.
|
|
201
169
|
|
|
202
170
|
### §service-package-exports Package export surface
|
|
203
171
|
|
|
204
172
|
| Export path | Current contract |
|
|
205
173
|
|---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
206
|
-
| `@plurnk/plurnk-service` | Frozen 1.x compatibility barrel
|
|
174
|
+
| `@plurnk/plurnk-service` | Frozen 1.x compatibility barrel of the exports below. It gains no new APIs and is not the client boundary. Removal is SemVer-major. |
|
|
207
175
|
| `@plurnk/plurnk-service/digest` | Supported programmatic forensic surface owned by {§digest-programmatic-surface}. |
|
|
208
176
|
| `@plurnk/plurnk-service/package.json` | Supported package metadata surface. |
|
|
209
177
|
|
|
178
|
+
| Root exports | Names |
|
|
179
|
+
|--------------|-------|
|
|
180
|
+
| Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry`, `Skill` |
|
|
181
|
+
| Types | `ChatMessage`, `EditResult`, `FlagDescriptor`, `MockAssistant`, `MockResponse`, `OpenFoldResult`, `ReadResult` |
|
|
182
|
+
|
|
210
183
|
New clients use AG-UI. A new library contract belongs in its owning package or
|
|
211
184
|
an explicitly specified subpath, not in the frozen root barrel.
|
|
212
185
|
|
|
@@ -224,13 +197,27 @@ flowchart LR
|
|
|
224
197
|
DAEMON -. failure .-> TEARDOWN["Close every started owner"] --> FAIL
|
|
225
198
|
```
|
|
226
199
|
|
|
227
|
-
§startup-listener-admission The production service binds its
|
|
228
|
-
|
|
229
|
-
mutating anything in the durable data directory. A process that loses
|
|
230
|
-
listener race fails with the originating address error and byte-identical
|
|
231
|
-
durable storage.
|
|
232
|
-
|
|
233
|
-
close/rebind race.
|
|
200
|
+
§startup-listener-admission The production service binds its one listener
|
|
201
|
+
({§http-host}) before creating, opening, replacing, rotating, migrating, or
|
|
202
|
+
otherwise mutating anything in the durable data directory. A process that loses
|
|
203
|
+
the listener race fails with the originating address error and byte-identical
|
|
204
|
+
durable storage. Core owns the socket continuously; it answers 503 until the
|
|
205
|
+
client-interface module mounts the root at daemon activation, so early
|
|
206
|
+
ownership introduces neither traffic nor a close/rebind race.
|
|
207
|
+
|
|
208
|
+
§http-host **The daemon opens exactly one transport.** Core binds the HTTP
|
|
209
|
+
listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
|
|
210
|
+
`registerHttpRoute(prefix, handler)` and `httpAddress()` on the application port
|
|
211
|
+
({§application-port}). A prefix is an absolute pathname. Each request goes to the
|
|
212
|
+
longest mounted prefix; a prefix claims itself and the subtree beneath it, never
|
|
213
|
+
a longer sibling name; `/` is the root and receives whatever nothing more
|
|
214
|
+
specific claimed. Until a root is mounted the listener answers `503
|
|
215
|
+
service-starting` to every request: the service has not admitted its client
|
|
216
|
+
interface. Adapters mount at `start()`, after durable lifecycle recovery, and
|
|
217
|
+
none opens a socket of its own under the daemon — a module hosted *without* a
|
|
218
|
+
daemon may bind a private one, which is outside this contract. The standards
|
|
219
|
+
address by URL, never by port (#641): AG-UI mounts `/` and `/agui`, A2A the
|
|
220
|
+
well-known card and its endpoint path, on the same address.
|
|
234
221
|
|
|
235
222
|
§startup-admission-order After listener ownership, database admission completes
|
|
236
223
|
before provider or capability initialization can perform external work. Every
|
|
@@ -254,7 +241,7 @@ shared workspace state ({§packet}, {§membership}). Other journals are not
|
|
|
254
241
|
automatically injected. This follows "one packet, one worker," not an access
|
|
255
242
|
filter over workspace resources.
|
|
256
243
|
|
|
257
|
-
§actor-boundary-origin-not-filter `origin` ({§
|
|
244
|
+
§actor-boundary-origin-not-filter `origin` (the writer, {§scheme-surface-writableby-403}) is
|
|
258
245
|
**attribution** — the delta's provenance ({§env-delta}) — and is never read to
|
|
259
246
|
filter a row.
|
|
260
247
|
|
|
@@ -273,13 +260,14 @@ file or entry through its ordinary read-authority boundary ({§worker-read-scope
|
|
|
273
260
|
| Door | Carries | Wake behavior |
|
|
274
261
|
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
275
262
|
| Environment | A direct child's durable activity to its parent, plus a successful mutation of the deliberately global `worker:///` commons to every worker. | Intermediate activity and commons never wake; a child's terminal disposition wakes its parent. |
|
|
276
|
-
| Voice | A directed `loop.inject` or ```` ```SEND (worker://name) ```` message.
|
|
263
|
+
| Voice | A directed `loop.inject` or ```` ```SEND (worker://name) ```` request, or an exact-message reply ({§message-reply-delivery}). | Requests enter the next packet or start queued work; replies wake existing assigned/native-sender work without creating a request. |
|
|
277
264
|
|
|
278
265
|
§actor-boundary-lineage-attention **Addressability is workspace-wide; attention
|
|
279
266
|
is lineage-scoped.** Project files, registered resources, and named scratch
|
|
280
267
|
entries remain addressable throughout the workspace, but ordinary changes do
|
|
281
|
-
not enter unrelated workers' logs.
|
|
282
|
-
|
|
268
|
+
not enter unrelated workers' logs. Eligible child actions ({§env-delta-child-activity})
|
|
269
|
+
reach only the direct parent; exploration and local curation do not. That
|
|
270
|
+
observer row carries the source occurrence identity and never
|
|
283
271
|
republishes, so grandparents observe what their own direct children do without
|
|
284
272
|
receiving an automatic recursive mirror of every descendant.
|
|
285
273
|
|
|
@@ -317,8 +305,10 @@ Plurnk never stages a file or runs `git add`.
|
|
|
317
305
|
|
|
318
306
|
§turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
|
|
319
307
|
`<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the workspace's shared
|
|
320
|
-
`worker:///_plurnk/
|
|
321
|
-
that model worker's first turn — visible, logged, line-addressable.
|
|
308
|
+
`worker:///_plurnk/AGENTS.md` entry and the engine foists one READ of it into
|
|
309
|
+
that model worker's first turn — visible, logged, line-addressable. The entry
|
|
310
|
+
keeps the standard's own name, as a nested instruction file does: that name is
|
|
311
|
+
in the model's prior, and no other generated document is called it. Absent
|
|
322
312
|
file: no entry, no stunt, nothing 404s. The global XDG configuration `AGENTS.md`
|
|
323
313
|
remains system-prompt policy ({§policy-sections}); the stunt carries only
|
|
324
314
|
local repo guidance.
|
|
@@ -338,11 +328,11 @@ narrow or omit the reference catalogs under {§capability-admission}.
|
|
|
338
328
|
| Agent Skills | `skill://*/SKILL.md` | `<1,-1>`; {§skills-resources} |
|
|
339
329
|
| Plurnk references: executors, schemes, family managers | `worker:///_plurnk/plurnk/*.md` | `<1,-1>` |
|
|
340
330
|
| Enabled tools | `worker:///_plurnk/tools/*.md` | `<1,-1>`; configured expansions follow under {§tools-resource-materialization} |
|
|
341
|
-
| Enabled agents | `worker:///_plurnk/
|
|
331
|
+
| Enabled agents | `worker:///_plurnk/a2a/*.md` | `<1,-1>`; {§a2a-catalog} |
|
|
342
332
|
| Enabled members | `worker:///_plurnk/members/*.md` | `<1,-1>`; {§members-projection} |
|
|
343
|
-
| Project filesystem | `*` | File cap below; `project
|
|
344
|
-
| Workspace entries | `worker:///*` | Markerless; `workspace entries` |
|
|
345
|
-
| Named scratch entries | `worker://<worker>/*` | Markerless; `worker
|
|
333
|
+
| Project filesystem | `*` | File cap below; `project root member files` |
|
|
334
|
+
| Workspace entries | `worker:///*` | Markerless; `workspace knowledgebase entries` |
|
|
335
|
+
| Named scratch entries | `worker://<worker>/*` | Markerless; `worker knowledgebase entries` |
|
|
346
336
|
|
|
347
337
|
Only the three namespace surveys carry asides; the other targets name
|
|
348
338
|
their surface. The word `skills` names Agent Skills and nothing else.
|
|
@@ -351,8 +341,8 @@ supplies examples and complete instructions on demand. A shallow
|
|
|
351
341
|
result renders direct entries normally and every deeper first-segment directory
|
|
352
342
|
as an actionable `dir/**` summary with its recursive `items` and `tokens`;
|
|
353
343
|
tool-family rows also carry the concise `{§scheme-catalog-aside}` that drives
|
|
354
|
-
on-demand capability discovery. Ordinary surveys use FIND's markerless first
|
|
355
|
-
page, whose range metadata reports the requested and returned page against the
|
|
344
|
+
on-demand capability discovery. Ordinary surveys use FIND's markerless first
|
|
345
|
+
page ({§markerless-first-page}), whose range metadata reports the requested and returned page against the
|
|
356
346
|
complete result total; only the small capability-reference surfaces
|
|
357
347
|
explicitly select all. The opening survey demonstrates both `*` and `**` without
|
|
358
348
|
normalizing an all-results override. Every survey executes even when empty
|
|
@@ -362,7 +352,14 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
|
|
|
362
352
|
unset / `0` disables previews. `log://` is absent because the current worker's
|
|
363
353
|
log already renders in present mode.
|
|
364
354
|
|
|
365
|
-
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program
|
|
355
|
+
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its reasoning and program are stored before execution. NOTEs from its reasoning and program, the orienting READ/FIND surveys, and the reasoning and program READs in {§reasoning-initial-read} execute under {§op-execution-order}. The full `<1,-1>` READ of its own `ops://<worker>/<loop>/<turn>` source supplies the worked program example; no actionless source row or simulated READ is added. Every orienting row is structurally classified `_plurnk` and `init`. The namespace surveys and their asides follow {§actor-boundary-catalog-preview}.
|
|
356
|
+
|
|
357
|
+
Incoming messages publish once as inbound SEND rows in the first model turn
|
|
358
|
+
({§message-arrival}); initialization neither READs nor archives them. The turn
|
|
359
|
+
continues without a lifecycle declaration. The first model
|
|
360
|
+
request occupies database/log turn sequence 2; “turn zero” names the
|
|
361
|
+
initialization phase, not a zero-based database coordinate. Client and
|
|
362
|
+
`_plurnk` administrative workers execute operation turns without model initialization.
|
|
366
363
|
|
|
367
364
|
### §machine-processes Workspace and worker state
|
|
368
365
|
|
|
@@ -378,7 +375,7 @@ flowchart TB
|
|
|
378
375
|
workspace --> parentEntries["Named scratch<br/>worker://a/..."]
|
|
379
376
|
parent --> parentWork["Loops, turns, cancellation scope"]
|
|
380
377
|
parent -->|FORK| child["Worker B"]
|
|
381
|
-
parentLog -.->|"copy rows
|
|
378
|
+
parentLog -.->|"copy rows and visibility state"| childLog["Worker B log"]
|
|
382
379
|
parentEntries -.->|"snapshot under new name"| childEntries["Named scratch<br/>worker://b/..."]
|
|
383
380
|
workspace --> childEntries
|
|
384
381
|
child --> childLog
|
|
@@ -399,9 +396,9 @@ terminal history.**
|
|
|
399
396
|
| Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
|
|
400
397
|
| Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
|
|
401
398
|
| Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
|
|
402
|
-
| Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects,
|
|
399
|
+
| Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects, current active/body-suppression projection, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
|
|
403
400
|
| §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but turn-attached inference calls, their specializations, admission rows, and physical provider requests are not: one issued call or request has one causal branch. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
|
|
404
|
-
| §machine-processes-entry-inheritance **Named scratch and evidence** | Workspace | FORK snapshots quiescent `worker
|
|
401
|
+
| §machine-processes-entry-inheritance **Named scratch and evidence** | Workspace | FORK snapshots quiescent `worker` entries whose authority is the source Worker name into the child name. Bytes, attributes, and channel results remain exact; embedded addresses are not rewritten. Other resources, including `worker:///_plurnk/**`, stay shared. |
|
|
405
402
|
| Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
|
|
406
403
|
|
|
407
404
|
§worker-fork-trigger **The branch's claimed row is the fork.** `worker_name_claim` with a fork
|
|
@@ -437,13 +434,10 @@ existing workspace worker in its own right.
|
|
|
437
434
|
§worker-provider-identity **A worker owns a durable provider identity distinct
|
|
438
435
|
from its database id.** Creation mints a globally unique, opaque 128-bit value;
|
|
439
436
|
forks mint their own value. Core supplies it as the provider `workerId` for every
|
|
440
|
-
emission
|
|
441
|
-
({§provider-cache-identity}). Database ids remain the internal relational and
|
|
437
|
+
emission ({§provider-cache-identity}). Database ids remain the internal relational and
|
|
442
438
|
client coordinate. BARE calls use isolated per-call provider identities rather
|
|
443
439
|
than either worker value.
|
|
444
440
|
|
|
445
|
-
§worker-primary **The primary worker is the lineage root.** The PRIMARY worker of a turn's lineage is the no-parent root reached by walking `parent_worker_id` up; a no-parent worker is its own primary. Core supplies it on the first-party metadata channel alongside `Worker-Id` (same gate, computed per turn), stamped on EVERY turn including the primary's own (where it equals `Worker-Id`) — absent-with-a-Worker-Id is a contract violation, never a silent "assume primary." An unresolvable root (a corrupt/cyclic parent chain the `parent != id` CHECK forbids) fails hard. Providers emits it as `Plurnk-Worker-Primary`; a consumer routes primary-vs-spawned by equality (`Worker-Primary == Worker-Id` ⇒ the primary; `!=` ⇒ any-depth spawn, no depth math) and groups the worker tree by the shared root.
|
|
446
|
-
|
|
447
441
|
§machine-processes-fork-shares-the-world **A fork copies history and named
|
|
448
442
|
scratch while sharing the workspace.** It is a new worker in the
|
|
449
443
|
same workspace (`workers.parent_worker_id`, {§lifecycle-terms}); project files,
|
|
@@ -460,7 +454,7 @@ or membership overlay requires a new workspace.
|
|
|
460
454
|
|
|
461
455
|
§worker-name-minting **URI ingestion is permissive; worker minting is not.**
|
|
462
456
|
Every model/client worker-creation door applies the contracts-owned
|
|
463
|
-
`WORKER_NAME` predicate through one core admission path. Generic URL parsing
|
|
457
|
+
`WORKER_NAME` predicate ({§worker-name}) through one core admission path. Generic URL parsing
|
|
464
458
|
continues to decompose other authorities without treating them as mintable.
|
|
465
459
|
|
|
466
460
|
| Candidate | Minting result |
|
|
@@ -473,7 +467,7 @@ continues to decompose other authorities without treating them as mintable.
|
|
|
473
467
|
|
|
474
468
|
§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. There is no creator-only, self-only, ancestor-only, or runtime-only grant. 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.
|
|
475
469
|
|
|
476
|
-
§worker-generated-subtree **Generated documents share `worker:///_plurnk/`.** Project instructions (`
|
|
470
|
+
§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}).
|
|
477
471
|
|
|
478
472
|
The subtree has ordinary scratch access, not an ACL. Runtime maintenance reconciles it from workspace Functionality through the runtime actor's ordinary turns ({§actor-boundary-doc-injection}); reconciliation may replace manual edits. There are no per-Worker copies or fork rederivation. A runtime's `resourcesPath` is relative to this root ({§tools-resource-materialization}).
|
|
479
473
|
|
|
@@ -526,31 +520,34 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
526
520
|
own work is a fresh loop, so an inherited mid-flight loop never makes the
|
|
527
521
|
branch look forever-live to the {§send-premature-terminate} gate.
|
|
528
522
|
- §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.
|
|
529
|
-
- §worker-
|
|
530
|
-
delegation was removed outright (#396). A model manages git branches through ordinary
|
|
531
|
-
the `git` runtime — never engine machinery.
|
|
532
|
-
- §worker-delegation-inherits-policy **Fresh delegated loops inherit proposal disposition.** WORK, FORK, and SEND to an idle Worker carry the sender's proposal disposition. 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.
|
|
523
|
+
- §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.
|
|
533
524
|
- §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.
|
|
534
525
|
|
|
535
|
-
- §worker-scheme-collect **Collect** —
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
silent to its owner; collection is lineage
|
|
546
|
-
supervision, never a
|
|
547
|
-
verb. The **pull** side mirrors the push: a path-absent
|
|
526
|
+
- §worker-scheme-collect **Collect** — each concluded child loop reaches its direct
|
|
527
|
+
parent as an `_plurnk` READ of `ops://<name>/<sequence>` ({§loop-answer}), not a message,
|
|
528
|
+
and that row carries what the child said.
|
|
529
|
+
The occurrence retains that loop's exact terminal result; the READ uses ordinary
|
|
530
|
+
bounded projection. Its body, when present, is initially visible. Replies are
|
|
531
|
+
independent deliveries ({§message-reply-delivery}), never copied into this outcome. Failures and
|
|
532
|
+
cancellations retain their exact status, Problem, and visible explanation,
|
|
533
|
+
including a spawn that fails before its first turn. Observation and wake-up
|
|
534
|
+
follow {§env-delta-child-termination}; a later child loop cannot replace the
|
|
535
|
+
retained result. The **pull** side mirrors the push: a path-absent
|
|
548
536
|
```` ```READ (worker://<name>) ```` collects that same result on demand for a
|
|
549
|
-
concluded worker
|
|
550
|
-
returns **425** (Too Early).
|
|
537
|
+
concluded worker and names its canonical loop URI in `resource`; **unfinished loops** have not concluded, so the READ
|
|
538
|
+
returns **425** (Too Early). An explicit lifecycle declaration chooses whether to continue
|
|
551
539
|
or wait for that worker ({§join-blocking-collect}). A
|
|
552
540
|
missing name is 404. The model therefore reads the worker itself for its
|
|
553
541
|
outcome or a wait rather than guessing a scratch path to "check on" it.
|
|
542
|
+
- §worker-loop-result `ops://<name>/<sequence>` selects one worker-local positive safe-integer
|
|
543
|
+
loop sequence ({§loop-answer}; the retired `loop://` scheme is gone, and one address now serves
|
|
544
|
+
both what a loop said and how it ended). It is a read-only resource, not an actor control
|
|
545
|
+
address: READ, FIND and COPY use ordinary projections; EDIT, MOVE-source, and KILL cannot change
|
|
546
|
+
it. No query, userinfo, or port is accepted. A coordinate that is not a positive safe integer is
|
|
547
|
+
400; a missing loop 404; a loop that has not answered and has not concluded 425. A concluded
|
|
548
|
+
loop remains readable after newer loops, log curation, or a reply to its originating message.
|
|
549
|
+
A failure reports its problem even when the loop answered earlier: the failure is the news.
|
|
550
|
+
READs and completion observations use the same resolution, representation and projector.
|
|
554
551
|
- §child-orientation **Child orientation.** Beyond the conclusion delta, every
|
|
555
552
|
turn the packet's status clump surfaces the live things this worker currently
|
|
556
553
|
holds under the teaching's own word for handing work out: `## Delegation` is
|
|
@@ -560,11 +557,13 @@ the `git` runtime — never engine machinery.
|
|
|
560
557
|
history; this section is the current inventory that keeps an active obligation
|
|
561
558
|
visible even when no new activity arrived. Each open stream pointer carries
|
|
562
559
|
its channels' sizes and growth since the last packet in `detail`
|
|
563
|
-
(`{"status":"active","path":"sh:///
|
|
560
|
+
(`{"status":"active","path":"sh:///ab3d5678","detail":"stdout 340 lines (+2048 bytes)"}`)
|
|
564
561
|
— the only thing the model learns about a stream before it closes
|
|
565
562
|
({§exec-stream}). It is orienting state, never advice: the model sees its live
|
|
566
563
|
subtree (`{"status":102,"path":"worker://worker-x"}`) and reasons for itself —
|
|
567
564
|
READ, SEND, or KILL via the path.
|
|
565
|
+
Workspace schedules are not held work: an occurrence arrives as a message
|
|
566
|
+
({§schedule-delivery}).
|
|
568
567
|
- §packet-empty-sections **Emptiness is stated where the model decides on it.**
|
|
569
568
|
`## Delegation` renders every turn, each of its two lists `[]` when empty: the
|
|
570
569
|
model decides whether to wait or complete on exactly these facts, so their
|
|
@@ -576,8 +575,8 @@ the `git` runtime — never engine machinery.
|
|
|
576
575
|
- §packet-current-turn **The packet says who and which turn, below the log.** The
|
|
577
576
|
`## Worker` block is the first section after the log, carrying
|
|
578
577
|
`{"path": "worker://<name>", "parent": <address or null>, "loop": L, "turn": T}`: the actor,
|
|
579
|
-
whose child it is, and the coordinate this packet's response becomes, so `reasoning
|
|
580
|
-
and `ops
|
|
578
|
+
whose child it is, and the coordinate this packet's response becomes, so `reasoning://<worker>/L/T`
|
|
579
|
+
and `ops://<worker>/L/T` are the model's own and `log:///L/T/*` its rows; a model never infers the
|
|
581
580
|
present from the last row's coordinate, which may or may not be its own turn. The block
|
|
582
581
|
changes every turn, so nothing of it precedes the log, and the packet carries no date, time
|
|
583
582
|
or zone anywhere (operator, 2026-09-13: no date or time injection, and nothing volatile above
|
|
@@ -627,8 +626,6 @@ under that exact URL—never raw HTML, response headers, or a channel-selection
|
|
|
627
626
|
lesson. FIND consumes the addressed stored channel representation
|
|
628
627
|
and never re-fetch a match.
|
|
629
628
|
|
|
630
|
-
§web-retrieval-live Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin materialize→FIND and persistence/publication separation. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page; live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions.
|
|
631
|
-
|
|
632
629
|
**Git is the substrate and the repository is the boundary:**
|
|
633
630
|
|
|
634
631
|
- §membership-baseline **The baseline contract — chiseled (#400).** To a workspace a
|
|
@@ -652,7 +649,7 @@ and never re-fetch a match.
|
|
|
652
649
|
({§membership-create-parents}). Admitted by a published standard as projected
|
|
653
650
|
instruction documents — never as members: (3) the project's `AGENTS.md` and nested
|
|
654
651
|
`AGENTS.md` files ({§turn0-agents-stunt}, #346), read from disk regardless of git status
|
|
655
|
-
and materialized as `worker:///_plurnk/
|
|
652
|
+
and materialized as `worker:///_plurnk/AGENTS.md` and
|
|
656
653
|
`worker:///_plurnk/instructions/<subtree>/AGENTS.md`; the file itself is a member
|
|
657
654
|
only when tracked or added, and the standard never overrides the operator's
|
|
658
655
|
exclusions — an `AGENTS.md` the repository ignores or an exclusion matches
|
|
@@ -725,7 +722,7 @@ reconsidered when the operator changes the policy and otherwise remains a stat-o
|
|
|
725
722
|
no-op. The file write gate independently stats the source against the same ceiling,
|
|
726
723
|
so safety does not depend on a background warm winning a client-operation race.
|
|
727
724
|
|
|
728
|
-
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row and one symbol graph without copying. The identity hashes the representation's own SHA-256 ({§tokenomics-content-hash-identity}), never its body, so a maintenance pass judges an entry channel from its stored `content_hash` without the body crossing into the process; a body is acquired only for a derivation that runs, under that same identity (a representation that moved on since it was judged returns nothing and is judged again next pass), or for a channel with no stored identity, an open or streamed channel, which must be read to be judged. Log rows and turn sources still arrive whole. The pass reports the bytes it acquired beside the derivations it ran, and an unchanged workspace acquires none of its channel bodies at any concurrency. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling derivations. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
|
|
725
|
+
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row and one symbol graph without copying, and the FTS index reads its text from the content store ({§content-store}) instead of keeping a copy. The identity hashes the representation's own SHA-256 ({§tokenomics-content-hash-identity}), never its body, so a maintenance pass judges an entry channel from its stored `content_hash` without the body crossing into the process; a body is acquired only for a derivation that runs, under that same identity (a representation that moved on since it was judged returns nothing and is judged again next pass), or for a channel with no stored identity, an open or streamed channel, which must be read to be judged. Log rows and turn sources still arrive whole. The pass reports the bytes it acquired beside the derivations it ran, and an unchanged workspace acquires none of its channel bodies at any concurrency. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling derivations. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
|
|
729
726
|
|
|
730
727
|
The artifact also retains a positive `{§mimetype-parse-issues}` count and the
|
|
731
728
|
full normalized `{§mimetype-summary}` when the exact parsed channel reported
|
|
@@ -783,14 +780,14 @@ explicit.
|
|
|
783
780
|
|
|
784
781
|
## §worker-loop-lifecycle Loop scheduling and lifecycle
|
|
785
782
|
|
|
786
|
-
- §join-blocking-collect **Collection and scheduling are independent.** A path-absent ```` ```READ (worker://<running-child>) ```` returns **425** (Too Early), without a strike or scheduler side effect.
|
|
783
|
+
- §join-blocking-collect **Collection and scheduling are independent.** A path-absent ```` ```READ (worker://<running-child>) ```` returns **425** (Too Early), without a strike or scheduler side effect. WAIT joins live obligations; ordinary operations without WAIT keeps working. A child reaching any terminal status wakes a waiting parent with its result, including completion racing the park boundary. Children retain their own limits. Collection never arms an implicit disposition override.
|
|
787
784
|
|
|
788
785
|
A worker is a **log plus a cancellation scope** — one `AbortController` per worker, reused while live and replaced only once aborted, so a cancel ends the worker as a unit and a later `runLoop` request is never born cancelled. A worker's queued loops are advanced by a **drain**: a single per-worker drain that claims loops atomically (status 100→102) and runs each under the worker's scope. A loop may spawn **streams** (execs) that outlive it; each is a row in the subscription registry ({§subscriptions}) — the durable record of what the worker holds open. Cancellation and conclusion are defined against these structures, never wall-clock timing.
|
|
789
786
|
|
|
790
787
|
```mermaid
|
|
791
788
|
stateDiagram-v2
|
|
792
789
|
[*] --> Queued: runLoop request
|
|
793
|
-
Queued --> Running:
|
|
790
|
+
Queued --> Running: queued task claimed by drain
|
|
794
791
|
Running --> Parked: wait with live obligations
|
|
795
792
|
Parked --> Queued: obligation settles or arrival
|
|
796
793
|
Running --> Terminal: conclude or fail
|
|
@@ -807,80 +804,21 @@ newer terminal loop cannot mask older queued, running, or parked work. Name
|
|
|
807
804
|
collision, workspace worker caps, child obligations, orientation, and recovery
|
|
808
805
|
all use that one definition.
|
|
809
806
|
|
|
810
|
-
### §worker-scheduled-send Scheduled worker tasks
|
|
811
|
-
|
|
812
|
-
A numeric scope on `SEND (worker://name)` queues a new task with the authored
|
|
813
|
-
body, even when the recipient has unfinished work. Unscoped SEND retains its
|
|
814
|
-
ordinary arrival semantics. Timing is whole minutes, not text coordinates.
|
|
815
|
-
|
|
816
|
-
| Directed SEND scope | First occurrence | Subsequent occurrences |
|
|
817
|
-
|---|---|---|
|
|
818
|
-
| `<D>`, `D ≥ 0` | Eligible after D minutes. | None. |
|
|
819
|
-
| `<D,I>`, `D ≥ 0`, `I > 0` | Eligible after D minutes. | Fixed cadence of I minutes from the initial due time. |
|
|
820
|
-
|
|
821
|
-
- Queued tasks carry a durable due time and the recipient's model selection,
|
|
822
|
-
sender's delegated policy, and original prompt source. They do not activate
|
|
823
|
-
provider inference or workspace Functionality before eligibility. Due tasks are
|
|
824
|
-
claimed in queue order; an earlier future task cannot block ready work.
|
|
825
|
-
- A recurrence has at most one unfinished occurrence. A successful terminal
|
|
826
|
-
transition atomically queues its successor; all-failed inventory, engine failure, and
|
|
827
|
-
cancellation queue none. Continuing or waiting TASKs retain the same occurrence and limits.
|
|
828
|
-
- At first claim, overdue ticks coalesce into the latest due cadence slot. There is
|
|
829
|
-
no catch-up backlog. Each occurrence has its own loop/turn/execution limits
|
|
830
|
-
and the original task's generation/capability snapshot; injected corrections
|
|
831
|
-
and response bodies are not recurrence instructions. Resuming a wait neither
|
|
832
|
-
rechecks the occurrence's initial delay nor changes its selected cadence slot.
|
|
833
|
-
- Ownership is the existing durable recipient worker and lineage, never its
|
|
834
|
-
reclaimable name. Future queued work remains live for parent obligations,
|
|
835
|
-
cancellation, name collision, and model-policy protection. KILL cancels its
|
|
836
|
-
current and future work; later explicit SEND may authorize new work.
|
|
837
|
-
- Restart retains queued and parked occurrences and their due times. Interrupted
|
|
838
|
-
active work follows the ordinary owner-loss failure rule, without replaying
|
|
839
|
-
uncertain effects or automatically rearming a failed recurrence.
|
|
840
|
-
- Ordinary loop inspection exposes due time, recurrence identity, and interval.
|
|
841
|
-
SEND acknowledges the accepted task identity and timing. Parent orientation
|
|
842
|
-
includes queued future tasks; a completed occurrence is not a concluded
|
|
843
|
-
recurring assignment.
|
|
844
|
-
|
|
845
|
-
```mermaid
|
|
846
|
-
stateDiagram-v2
|
|
847
|
-
[*] --> Queued: explicitly scheduled task
|
|
848
|
-
Queued --> Running: due claim; coalesce elapsed ticks
|
|
849
|
-
Running --> Parked: TASK waiting
|
|
850
|
-
Parked --> Queued: same occurrence wakes
|
|
851
|
-
Running --> Success: TASK terminal with at least one completed item
|
|
852
|
-
Success --> Queued: atomic successor for recurrence
|
|
853
|
-
Success --> [*]: one-shot
|
|
854
|
-
Running --> Failed: TASK all failed, or engine failure
|
|
855
|
-
Queued --> Cancelled: KILL
|
|
856
|
-
Parked --> Cancelled: KILL
|
|
857
|
-
Running --> Cancelled: KILL
|
|
858
|
-
Failed --> [*]
|
|
859
|
-
Cancelled --> [*]
|
|
860
|
-
```
|
|
861
|
-
|
|
862
807
|
### §worker-wait-timing Durable waits and wake ownership
|
|
863
808
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
| `<T,P>`, `P > 0` | T as above, or unbounded for -1. | Resume after P, or earlier on deadline, completion, or a message. |
|
|
873
|
-
| `<T,0>` | T as above. | Disable periodic observation for this wait; events and deadline still wake it. |
|
|
874
|
-
|
|
875
|
-
Polling observes, never repeats operations. A wake ends this wait; a subsequent
|
|
876
|
-
waiting TASK is a new wait with its own timing. Deadline expiry does not cancel a child
|
|
877
|
-
or declare its execution failed. Ordinary terminal and cancellation rules
|
|
878
|
-
remain authoritative.
|
|
809
|
+
WAIT has no timing operand; its optional path is a label ({§send-wait-scope}).
|
|
810
|
+
With live work—an open stream or a live child worker—the loop parks durably
|
|
811
|
+
and wakes on settlement, on a
|
|
812
|
+
message, or on the inherited observation cadence of its open streams
|
|
813
|
+
({§exec-lifetime}); without live work it continues at once, told so. A wake
|
|
814
|
+
continues the same loop with the same messages, generation policy, and
|
|
815
|
+
cumulative turn ceiling; it never creates another assignment. Scheduled messages
|
|
816
|
+
exist independently of a loop's optional attachment to one occurrence.
|
|
879
817
|
|
|
880
818
|
```mermaid
|
|
881
819
|
stateDiagram-v2
|
|
882
|
-
Running --> Parked: atomically persist wait identity
|
|
883
|
-
Parked --> Queued: arrival / completion /
|
|
820
|
+
Running --> Parked: atomically persist the wait identity
|
|
821
|
+
Parked --> Queued: arrival / completion / inherited observation, guarded by wait identity
|
|
884
822
|
Parked --> Terminal: cancellation
|
|
885
823
|
Queued --> Running: same loop claimed by its worker's drain
|
|
886
824
|
```
|
|
@@ -893,18 +831,35 @@ obligations, not merely its latest parked loop. A completion crossing an active
|
|
|
893
831
|
loop's park boundary is owed to that loop, never a future unrelated loop.
|
|
894
832
|
|
|
895
833
|
Each loop captures the worker's completion revision when its program begins.
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
their evidence.
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
834
|
+
Before inference, it acknowledges the current revision only after every addressed
|
|
835
|
+
terminal/reply occurrence has crossed the ambient observation cursor and every
|
|
836
|
+
closed stream has published its terminal channels. The publication check and
|
|
837
|
+
revision acknowledgement are atomic; an arrival beyond either materialization
|
|
838
|
+
snapshot remains owed. Stream closure, direct-child terminalization and addressed
|
|
839
|
+
replies advance the revision in the same database mutation as their evidence.
|
|
840
|
+
An unobserved completion remains owed through parking and restart; another loop's
|
|
841
|
+
turn cannot consume it. Waking is guarded by both the wait identity and the
|
|
842
|
+
relevant due/event predicate, so delayed callbacks do not wake programs that
|
|
843
|
+
already observed their evidence.
|
|
844
|
+
|
|
845
|
+
Wait identity commits with the parked transition. The drain persists any
|
|
846
|
+
inherited stream-observation due time; process timers only arrange a bounded
|
|
847
|
+
next check. Restart reconciles obligations under {§worker-lifecycle-restart-recovery}.
|
|
848
|
+
Waking or terminalizing invalidates the old wait. Duplicate and racing wakes
|
|
849
|
+
have one durable winner, and cancellation cannot be reversed by a timer.
|
|
850
|
+
|
|
851
|
+
§loop-claim-latency **A loop's first claim is durable.** `loops.claimed_at` is
|
|
852
|
+
stamped by trigger the first time a loop enters status 102, at insertion for a
|
|
853
|
+
loop created running and on the move from queued otherwise; later re-claims never
|
|
854
|
+
move it. The digest reports, per loop, the claim time and how long after it the
|
|
855
|
+
first model turn started, so a stall between claim and inference (a heartbeat has
|
|
856
|
+
waited 7.5 h, #703) is a number rather than a gap.
|
|
857
|
+
|
|
858
|
+
§digest-storage **The digest states the file's health.** Beside the database path it
|
|
859
|
+
reports the file size, the free pages it holds, its `auto_vacuum` mode, and the six
|
|
860
|
+
largest tables and indexes by allocated bytes (`dbstat`), so growth is a number in
|
|
861
|
+
every digest (#764). The digest reads loops as stored, so a database made before a
|
|
862
|
+
lifecycle column was added still digests.
|
|
908
863
|
|
|
909
864
|
§loop-execution-allowance **One task has one execution allowance.** The first
|
|
910
865
|
execution snapshots `PLURNK_SERVICE_LOOP_TIMEOUT` on the loop. Active segments
|
|
@@ -926,21 +881,21 @@ superseded exclusive lineage permission.
|
|
|
926
881
|
An exhausted allowance aborts in-flight execution and produces `504`; a late
|
|
927
882
|
callback cannot override a committed disposition. Restart preserves parked
|
|
928
883
|
allowances; interrupted active tasks follow ordinary owner-loss recovery,
|
|
929
|
-
never replay interrupted effects to reconstruct time.
|
|
930
|
-
the separate
|
|
884
|
+
never replay interrupted effects to reconstruct time. Future messages use
|
|
885
|
+
the separate schedule contract ({§schedule-delivery}).
|
|
931
886
|
|
|
932
887
|
§worker-message-admission **Recipient selection and admission are one decision.**
|
|
933
888
|
An arrival to a worker selects its running loop, otherwise its oldest parked
|
|
934
889
|
loop, otherwise a new queued loop. Compatibility is checked against the exact
|
|
935
|
-
loop that receives the
|
|
936
|
-
The worker's admission lock covers selection, compatibility,
|
|
890
|
+
loop that receives the message; the writer does not reselect another recipient.
|
|
891
|
+
The worker's admission lock covers selection, compatibility, message admission,
|
|
937
892
|
and the park-boundary wake check against orphan recovery. Fresh task insertion
|
|
938
893
|
includes its complete generation policy, proposal disposition, and initial paths
|
|
939
894
|
atomically; no drain may claim partially configured work.
|
|
940
895
|
|
|
941
896
|
| Message at the receiving task's end | Disposition |
|
|
942
897
|
|---|---|
|
|
943
|
-
| Delivered to an unfinished loop | Append one ordered
|
|
898
|
+
| Delivered to an unfinished loop | Append one ordered message to the loop's inbox; waking does not repeat earlier messages. |
|
|
944
899
|
| Admitted but not observed before ordinary completion | Preserve through the existing orphan-message admission path. |
|
|
945
900
|
| Cancelled as part of the worker scope | Preserve the frame as evidence; never promote it into executable work, including after restart. |
|
|
946
901
|
| Explicit new arrival after cancellation | Admit under ordinary current worker policy; never revive a terminal loop. |
|
|
@@ -967,26 +922,24 @@ stateDiagram-v2
|
|
|
967
922
|
Observed --> [*]
|
|
968
923
|
```
|
|
969
924
|
|
|
970
|
-
| §worker-lifecycle-subscription-matrix Subscription state at
|
|
925
|
+
| §worker-lifecycle-subscription-matrix Subscription state at WAIT | Terminal observation already in a packet | Result |
|
|
971
926
|
|-------------------------------------------------------------------------|---:|---|
|
|
972
927
|
| open | no | park; polling or closure may wake it |
|
|
973
928
|
| closed, any status, empty or non-empty | no | continue directly to the observation turn |
|
|
974
929
|
| closed, any status, empty or non-empty | yes | no stream obligation remains |
|
|
975
930
|
| cancelled as part of worker cancellation | irrelevant | terminate the cancelled worker; never resurrect it |
|
|
976
931
|
|
|
977
|
-
|
|
978
|
-
completion. Closure is always a wake edge
|
|
932
|
+
Observation watches a still-open stream; it never changes ownership or manufactures
|
|
933
|
+
completion. Closure is always a wake edge.
|
|
979
934
|
|
|
980
|
-
| §worker-lifecycle-poll-matrix
|
|
935
|
+
| §worker-lifecycle-poll-matrix stream | While open | On closure |
|
|
981
936
|
|------------------------------------------------|---|---|
|
|
982
|
-
|
|
|
983
|
-
|
|
|
984
|
-
| zero | no observation wakes | resume once |
|
|
985
|
-
| turn-scoped `<0>` | reap at the next pre-turn boundary | surface the terminal outcome |
|
|
937
|
+
| any lifetime but `turn` | the daemon's exponential-backoff observation wakes ({§exec-lifetime}) | resume once with terminal observation |
|
|
938
|
+
| `[{"lifetime":"turn"}]` | reap at the next pre-turn boundary | surface the terminal outcome |
|
|
986
939
|
|
|
987
940
|
The structured-concurrency sequence is identical whether a child performs an
|
|
988
|
-
execution, retrieval, or pure inference. Intermediate
|
|
989
|
-
child
|
|
941
|
+
execution, retrieval, or pure inference. Intermediate status does not drain the
|
|
942
|
+
child obligation; explicit replies may arrive earlier ({§message-reply-delivery}).
|
|
990
943
|
|
|
991
944
|
```mermaid
|
|
992
945
|
sequenceDiagram
|
|
@@ -994,9 +947,9 @@ sequenceDiagram
|
|
|
994
947
|
participant C as Child loop
|
|
995
948
|
participant S as Child stream
|
|
996
949
|
P->>C: WORK or FORK
|
|
997
|
-
P->>P:
|
|
950
|
+
P->>P: WAIT parks on live child
|
|
998
951
|
C->>S: execution opens subscription
|
|
999
|
-
C->>C:
|
|
952
|
+
C->>C: WAIT parks on live stream
|
|
1000
953
|
loop backoff, fixed cadence, or explicit arrival
|
|
1001
954
|
S-->>C: optional progress observation
|
|
1002
955
|
C->>C: continue or park
|
|
@@ -1017,16 +970,16 @@ sequenceDiagram
|
|
|
1017
970
|
| cancelled or failed terminal | no | same wake/delivery path as success; outcome remains non-2xx |
|
|
1018
971
|
|
|
1019
972
|
A stream's close status and a loop's terminal status are separate layers. A
|
|
1020
|
-
stream may close 4xx/5xx and wake its worker to recover.
|
|
1021
|
-
loop's
|
|
1022
|
-
({§send}). Only a concluded loop
|
|
973
|
+
stream may close 4xx/5xx and wake its worker to recover. The lifecycle resolver adjudicates the
|
|
974
|
+
loop's answered messages, observation boundaries, and held work independently of
|
|
975
|
+
stream and message-delivery statuses ({§send}). Only a concluded loop drains the child obligation.
|
|
1023
976
|
|
|
1024
977
|
§worker-lifecycle-terminal-result **Terminal truth is a result, not a lifecycle code.** `loops.terminal_result`
|
|
1025
978
|
stores the exact universal operation result. A failure therefore retains its
|
|
1026
979
|
RFC 9457 Problem Details and exact status through persistence, restart,
|
|
1027
|
-
parent collection, and `loop/terminated
|
|
1028
|
-
|
|
1029
|
-
are derived presentation, never a second stored outcome. The constrained `loops.status`
|
|
980
|
+
parent collection, and `loop/terminated`. Message delivery and execution outcome
|
|
981
|
+
are independent: neither completion nor cancellation borrows the last reply's body.
|
|
982
|
+
Cancellation markers are derived presentation, never a second stored outcome. The constrained `loops.status`
|
|
1030
983
|
column remains only the scheduler's compact lifecycle projection: known
|
|
1031
984
|
terminal classes remain themselves, other 2xx/3xx statuses project to `200`,
|
|
1032
985
|
and other 4xx/5xx statuses project to `500`; exact `202` is forbidden because
|
|
@@ -1053,28 +1006,27 @@ observe their terminal results. No effect is replayed across an unknown
|
|
|
1053
1006
|
boundary.
|
|
1054
1007
|
|
|
1055
1008
|
- §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; concurrent accepted prompts remain distinct ordered queue items.
|
|
1056
|
-
- §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel
|
|
1009
|
+
- §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 (bare KILL uses the executor's SIGHUP default; ```` ```KILL [9] ```` uses SIGKILL).
|
|
1057
1010
|
- §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.
|
|
1058
|
-
- §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
|
|
1059
|
-
- §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,
|
|
1060
|
-
- §worker-causal-admission **Admission and cancellation have one ordering.** DrainSupervisor serializes message admission,
|
|
1011
|
+
- §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.
|
|
1012
|
+
- §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.
|
|
1013
|
+
- §worker-causal-admission **Admission and cancellation have one ordering.** DrainSupervisor serializes message admission, orphan-message recovery, and subtree cancellation within the workspace, taking the worker queue lock inside that control boundary. No provider, tool, fork-history copying, or stream reap holds it. WORK, FORK, and directed SEND identify their originating loop; admission requires that task still running. An accepted message to an independent recipient is a committed effect, not retroactively withdrawn by cancelling its sender.
|
|
1061
1014
|
|
|
1062
1015
|
| Boundary outcome | Durable consequence |
|
|
1063
1016
|
|---|---|
|
|
1064
1017
|
| Admission before cancellation | Owned work is included in cancellation. |
|
|
1065
|
-
| Recurring success during cancellation | Its successor is cancelled and reported from the durable cutoff, not a previously sampled task list. |
|
|
1066
1018
|
| Cancellation before admission | The cancelled task cannot deliver further messages or start children. Created identities and evidence are retained. |
|
|
1067
|
-
| Cancellation with
|
|
1019
|
+
| Cancellation with unpublished messages on completed tasks | Atomically record each worker's greatest admitted loop sequence as `cancelled_through_sequence` and cancel unresolved tasks. Orphan-message recovery, including boot recovery, excludes sources at or below that cutoff; completed results and message evidence are unchanged. |
|
|
1068
1020
|
| Independent arrival after cancellation | Admit a new loop above the cutoff using the ordinary worker policy. |
|
|
1069
1021
|
| Slow stream teardown after new admission | Reap only subscription identities captured by cancellation; late old-scope spawns follow {§worker-lifecycle-exec-epoch-bound}. |
|
|
1070
1022
|
|
|
1071
1023
|
- §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, so there is no fresh loop and no summary-as-prompt fiction. An already-active worker needs no injected prompt or second wake because its next packet reads the durable terminal state. A concluded worker receives no synthetic loop from ambient stream closure. The result remains available in the stream's own state under every case.
|
|
1072
1024
|
- §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.
|
|
1073
|
-
- §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
|
|
1074
|
-
- §worker-lifecycle-idle-is-concluded **
|
|
1025
|
+
- §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.
|
|
1026
|
+
- §worker-lifecycle-idle-is-concluded **Idle is not unanswered.** An empty WAIT continues; an answered, observed program without held work concludes under {§wait-obligation-matrix}. A concluded worker retains durable history; a later addressed arrival starts a new loop.
|
|
1075
1027
|
- §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.
|
|
1076
1028
|
- §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.
|
|
1077
|
-
- §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
|
|
1029
|
+
- §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.
|
|
1078
1030
|
|
|
1079
1031
|
---
|
|
1080
1032
|
|
|
@@ -1088,7 +1040,7 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
|
|
|
1088
1040
|
|---|---|
|
|
1089
1041
|
| `producer` | Required actor class: `model`, `client`, `plugin`, or `_plurnk`. |
|
|
1090
1042
|
| `kind` | Required purpose: `inference`, `initialization`, `operation`, or `maintenance`. Model iff inference; initialization and maintenance require `_plurnk`. Producer and kind are immutable. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
|
|
1091
|
-
| `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the
|
|
1043
|
+
| `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the program outcome and timestamp; a completed 102 is distinct from an open 102. A successful administrative program completes at 200 without concluding its host model loop. |
|
|
1092
1044
|
| Operations | Ordered by `(turn_id, sequence)` on one exact worker/loop/turn chain. Each row's `origin` is the turn producer or `_plurnk` making a system observation; the observation does not impersonate the producer. |
|
|
1093
1045
|
| Program source | Every admitted source-backed turn preserves its exact program before dispatch in `turn_sources`, independently of log receipts, under {§turn-ops-entry}. |
|
|
1094
1046
|
| Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
|
|
@@ -1104,7 +1056,7 @@ recovery completes any turn whose producer vanished.
|
|
|
1104
1056
|
A provider response, deterministic `_plurnk` program, or future client/plugin
|
|
1105
1057
|
program crosses one admission boundary into the same executor. That executor
|
|
1106
1058
|
parses once, dispatches the admitted statements in order, records their ordinary
|
|
1107
|
-
outcomes, and completes the turn from its
|
|
1059
|
+
outcomes, and completes the turn from its lifecycle ruling. Exact source is retained before dispatch.
|
|
1108
1060
|
Provider attempts, grammar recovery, reasoning, and accounting end before this
|
|
1109
1061
|
shared seam. A programmatic operation batch that supplied no Plurnk source does
|
|
1110
1062
|
not fabricate verbatim source.
|
|
@@ -1113,7 +1065,7 @@ not fabricate verbatim source.
|
|
|
1113
1065
|
Immediately before statement dispatch, the shared executor captures that worker's
|
|
1114
1066
|
append-only log high-water mark. Every log-targeted KILL in the program resolves
|
|
1115
1067
|
row membership at or below that same boundary, while prior curation effects still
|
|
1116
|
-
compose normally.
|
|
1068
|
+
compose normally. Message arrivals and other pre-program rows already present in the turn
|
|
1117
1069
|
remain selectable; preceding and later operation rows cannot be captured by
|
|
1118
1070
|
their own program. A directly dispatched
|
|
1119
1071
|
single operation captures the equivalent boundary before dispatch. This limits
|
|
@@ -1129,7 +1081,6 @@ These are the complete strike sources:
|
|
|
1129
1081
|
| Strike source | Exact trigger | Model-visible occurrence |
|
|
1130
1082
|
|---------------------|------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
|
|
1131
1083
|
| Hard result | An admitted non-execution operation or bounded parse-error status is `>= 400`, except the soft set `404`, `409`, `416`, `425`, `501`. | The originating failure row. |
|
|
1132
|
-
| Inventory steering | Retired (2026-09-14): a completion claimed over live work joins it ({§completion-joins-live-work}) and one over settled results defers ({§completion-defers-to-results}); every answer to a TASK claim, an empty inventory's soft 409 included, is a receipt and never a strike; a malformed TASK (`400 wait-timing-invalid`) is a hard result like any other operation's. | The TASK receipt. |
|
|
1133
1084
|
| Cycle | The executed operations and their observed results repeat under {§engine-cycle-evidence}. | None; cycle detection itself is private engine accounting. |
|
|
1134
1085
|
|
|
1135
1086
|
Execution results remain exact model-visible evidence but are always soft: an
|
|
@@ -1142,9 +1093,10 @@ other violations in the same turn still strike normally.
|
|
|
1142
1093
|
|
|
1143
1094
|
§engine-cycle-evidence Cycle identity contains the ordered executed operations
|
|
1144
1095
|
and their dispatch results, including complete operands, scopes, bodies, and
|
|
1145
|
-
scheme metadata, including the complete
|
|
1096
|
+
scheme metadata, including the complete NOTE and response bodies. Source
|
|
1146
1097
|
positions and asides are excluded. Engine-assigned
|
|
1147
|
-
Problem `instance` addresses
|
|
1098
|
+
Problem `instance` addresses and NOTE's assigned storage `resource` coordinate
|
|
1099
|
+
are excluded from results; the complete note body still distinguishes activity. Object member order is
|
|
1148
1100
|
irrelevant; operation and array order are preserved. Only the configured
|
|
1149
1101
|
`MIN_CYCLES × MAX_CYCLE_PERIOD` history window is retained. Repeated addresses
|
|
1150
1102
|
alone are not a cycle: changing inputs or observations distinguish activity.
|
|
@@ -1156,8 +1108,8 @@ effects. Ordinary contract strikes and operator budgets remain independent.
|
|
|
1156
1108
|
call fails with a network failure, rate limit, deadline, or interrupted resource after
|
|
1157
1109
|
the provider's own retries, the turn records the exact Problem as a `_plurnk` row,
|
|
1158
1110
|
notices the client (`engine:provider` / `provider_unavailable`), waits with
|
|
1159
|
-
exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling
|
|
1160
|
-
|
|
1111
|
+
exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling up to
|
|
1112
|
+
`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX`), and re-issues the same call against the exact frozen model
|
|
1161
1113
|
messages whose response is still outstanding. Each reissue remains a distinct logical
|
|
1162
1114
|
model call with complete physical-request accounting, but the active turn's newly
|
|
1163
1115
|
recorded provider Problems do not recursively enter that request; they surface normally
|
|
@@ -1166,8 +1118,10 @@ scored. Every recovery checkpoint broadcasts live, while the model-facing Notice
|
|
|
1166
1118
|
retains only the current provider state; the next completed exchange notices
|
|
1167
1119
|
`provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
|
|
1168
1120
|
is spent the turn completes as `202` and the loop parks exactly like a
|
|
1169
|
-
|
|
1170
|
-
next prompt or wake with its log intact
|
|
1121
|
+
WAIT ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
|
|
1122
|
+
next prompt or wake with its log intact — **unless the run is unattended
|
|
1123
|
+
({§loop-attendance}), in which case the loop concludes on the provider's exact failure
|
|
1124
|
+
instead, because parking stops the execution clock and no wake would ever arrive.** Only a client cancel, the execution allowance
|
|
1171
1125
|
({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
|
|
1172
1126
|
authorization, quota, an invalid response) settles a loop on a provider failure.
|
|
1173
1127
|
|
|
@@ -1183,15 +1137,14 @@ The contracts, and the violation of each that strikes:
|
|
|
1183
1137
|
| Contract | Violation that strikes |
|
|
1184
1138
|
|---|---|
|
|
1185
1139
|
| operation contract | a hard operation failure (status ≥ 400) in an admitted turn — soft statuses below excluded |
|
|
1186
|
-
| review contract | none
|
|
1140
|
+
| review contract | none: answered work joins live obligations ({§completion-joins-live-work}) or continues to observe results ({§completion-defers-to-results}) |
|
|
1187
1141
|
| progress contract | a detected operation cycle (`MIN_CYCLES` × period), or an admitted turn with no operation ({§empty-turn}) |
|
|
1188
1142
|
| frame contract | emission attempts exhausted with no admissible turn |
|
|
1189
1143
|
| provider response contract | the provider returned an invalid response |
|
|
1190
1144
|
|
|
1191
1145
|
Errors and issues are NOT contract violations. Each keeps its own disposition
|
|
1192
1146
|
and never strikes: exploration misses (404, 416) and unsupported capability
|
|
1193
|
-
(501) are how discovery works; raw 409 outcomes are soft
|
|
1194
|
-
steer's alone); execution outcomes and `executor/*` problem rows are world evidence;
|
|
1147
|
+
(501) are how discovery works; raw 409 outcomes are soft; execution outcomes and `executor/*` problem rows are world evidence;
|
|
1195
1148
|
provider weather (rate limit, network failure, deadline, interruption) recovers
|
|
1196
1149
|
({§provider-recovery}); provider capacity has its own packet recovery and
|
|
1197
1150
|
terminal ({§provider-capacity-failure}); request rejection
|
|
@@ -1201,9 +1154,7 @@ attempts are forensic evidence beneath their turn ({§emission-admission}) —
|
|
|
1201
1154
|
only their exhaustion surfaces, as one frame-contract violation. The
|
|
1202
1155
|
independent turn ceiling terminates at **429** ({§loop-terminals}). The streak
|
|
1203
1156
|
and cycle verdict are absent from model packets; only the concrete occurrences
|
|
1204
|
-
in the table are shown. The
|
|
1205
|
-
metadata ({§strikes-first-party-metadata}), which does not make it
|
|
1206
|
-
model-facing.
|
|
1157
|
+
in the table are shown. The streak never leaves the daemon.
|
|
1207
1158
|
|
|
1208
1159
|
§loop-rail-continuity Rail state belongs to the durable loop, not its execution
|
|
1209
1160
|
segment. The strike streak and bounded cycle history survive driver cleanup and
|
|
@@ -1217,13 +1168,13 @@ restart; curation of log evidence cannot alter them.
|
|
|
1217
1168
|
| Recoverable provider outage | No assessment; preserve the streak. | Preserve until an actual park. |
|
|
1218
1169
|
| New loop | Start at zero. | Start empty. |
|
|
1219
1170
|
|
|
1220
|
-
The turn belongs to the wait revision under which it began. A rejected
|
|
1171
|
+
The turn belongs to the wait revision under which it began. A rejected WAIT or
|
|
1221
1172
|
one resolved without parking does not close a window. Periodic observations
|
|
1222
1173
|
separated by actual waits are not an uninterrupted cycle; cumulative turn and
|
|
1223
1174
|
execution allowances remain independent bounds. A committed terminal result
|
|
1224
1175
|
cannot be replaced by a later rail assessment ({§worker-lifecycle-state-machine}).
|
|
1225
1176
|
|
|
1226
|
-
##
|
|
1177
|
+
## Provider Contract
|
|
1227
1178
|
|
|
1228
1179
|
Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md). Below: consumption surface + engine→provider guarantees.
|
|
1229
1180
|
|
|
@@ -1231,7 +1182,7 @@ Author-facing contract: [`@plurnk/plurnk-providers`](../plurnk-providers/SPEC.md
|
|
|
1231
1182
|
|
|
1232
1183
|
Three current entry points:
|
|
1233
1184
|
|
|
1234
|
-
- §provider-surface-generate `provider.generate(args)` — once per logical model call. An emission attempt supplies the complete packet messages, worker/turn coordinates, generation envelope, optional local grammar, first-party metadata, and `callKind: "emission"`. A BARE inference supplies only one user message containing its resolved prompt plus non-prompt call identity and accounting metadata, including `callKind: "bare"` ({§bare-inference} {§provider-call-kind}). Both receive a durable physical-request observer; provider-owned retry and failover may issue several ordered requests beneath either call. A successful `ProviderResponse` reaches its call-specific consumer; a `ProviderError.attempt` remains failed response evidence under {§provider-interrupted-attempt}. Core persists normalized response evidence separately from physical accounting
|
|
1185
|
+
- §provider-surface-generate `provider.generate(args)` — once per logical model call. An emission attempt supplies the complete packet messages, worker/turn coordinates, generation envelope, optional local grammar, first-party metadata, and `callKind: "emission"`. A BARE inference supplies only one user message containing its resolved prompt plus non-prompt call identity and accounting metadata, including `callKind: "bare"` ({§bare-inference} {§provider-call-kind}). Both receive a durable physical-request observer; provider-owned retry and failover may issue several ordered requests beneath either call. A successful `ProviderResponse` reaches its call-specific consumer; a `ProviderError.attempt` remains failed response evidence under {§provider-interrupted-attempt}. Core persists normalized response evidence separately from physical accounting.
|
|
1235
1186
|
- §provider-surface-capacity `provider.assessRequestCapacity(messages, maxOutputTokens?, signal?)` — provider-owned intersection of request-shaped token evidence and every known physical input limit. It admits, rejects only a proven exact overflow, or defers ambiguity to upstream ({§tokenomics-context-envelope-admission}). `generate` performs this assessment for its exact request and preserves the evidence on success and capacity failure.
|
|
1236
1187
|
- §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — the cancellable complete-request measurement primitive used by provider capacity assessment, with `exact`, `upper_bound`, `estimate`, or `unavailable` provenance. Core never substitutes this physical fact for its curation ruler.
|
|
1237
1188
|
|
|
@@ -1241,7 +1192,7 @@ Three current entry points:
|
|
|
1241
1192
|
|
|
1242
1193
|
§meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
|
|
1243
1194
|
|
|
1244
|
-
###
|
|
1195
|
+
### Engine → provider guarantees
|
|
1245
1196
|
|
|
1246
1197
|
- `messages` is a complete prompt (the section list, pre-assembled into the system + user messages). Provider does not reorder.
|
|
1247
1198
|
- §provider-guarantees-signal-wired `signal` is wired to the worker's AbortController.
|
|
@@ -1253,7 +1204,7 @@ Three current entry points:
|
|
|
1253
1204
|
|
|
1254
1205
|
### §emission-admission Provider emission admission
|
|
1255
1206
|
|
|
1256
|
-
A completed provider exchange is an **emission attempt**, not necessarily an engine turn.
|
|
1207
|
+
A completed provider exchange is an **emission attempt**, not necessarily an engine turn. **The harness admits every program whose meaning it can determine, runs what it admitted, and reports — never refuses — what it could not read**; a refusal is for undecidable text alone. ANTLR admits at least one parsed source operation. WAIT is optional under {§turn-shape}; omission invents no operation, diagnostic, warning or strike; any number of WAITs are one park, scheduled last ({§disposition-anywhere}), and statements after them remain admitted in authored order. Bounded operation errors retain useful siblings and participate in the ordinary struck turn. An unfinished heading slot ({§unparsed-tail-boundary}) refuses only what follows it: the statements that closed before it run, and the loss is one more hard diagnostic — a failed row with the lexer's own reason; an exchange that lost its boundary before any statement closed has nothing admissible and is rejected. A missing closer never rejects ({§closer-fallback}). An exchange with no operation and no other hard error is not rejected: it is admitted as an empty turn ({§empty-turn}). Parser warnings remain admissible. `finish=length` is evidence of likely truncation, not an independent rejection rule. Provider-declared interruption never reaches admission ({§provider-interrupted-attempt}). Accepted source bytes and statement positions remain exact in response evidence and `turnOps`. Execution follows {§op-execution-order}.
|
|
1257
1208
|
|
|
1258
1209
|
§safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ or KILL only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order at that operation's position under {§op-execution-order}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
|
|
1259
1210
|
|
|
@@ -1262,16 +1213,16 @@ Core retries a rejected emission against the exact same packet beneath the same
|
|
|
1262
1213
|
When the loop continues after exhaustion under {§invalid-emission-attempts}, the next ordinary turn's packet projects the latest rejected response visibly from a durably body-suppressed emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `Response rejected before dispatch; no operations were performed.` followed by `Parser: <the latest attempt's first diagnostic>` with its `content-offset` position — the model sees why, at which line, against its own projected text. The Notice states only observed admission facts; it does not classify the response as unrecoverable, infer why generation ended, or prescribe intent beyond the parser-owned diagnostic. Attempt count and rail state never become model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats that malformed body unless the model explicitly READs its exact address. Admission clears the recovery projection; another exhaustion replaces it with the latest rejected response if the loop continues.
|
|
1263
1214
|
|
|
1264
1215
|
Outside-block text has no execution, message, or receipt semantics under
|
|
1265
|
-
{§whitespace-contract}. The `ops
|
|
1216
|
+
{§whitespace-contract}. The `ops://<worker>/` source retains it verbatim under
|
|
1266
1217
|
{§turn-ops-log-curation}; execution never reconstructs source from the AST.
|
|
1267
1218
|
|
|
1268
|
-
An admitted program may contain bounded malformed statements
|
|
1269
|
-
Parsed operations still dispatch; each hard parser diagnostic
|
|
1270
|
-
becomes one durable model-origin `error` row with the
|
|
1271
|
-
{§parse-diagnostics} and status 400. These failures are committed before the
|
|
1272
|
-
explicit
|
|
1273
|
-
|
|
1274
|
-
|
|
1219
|
+
An admitted program may contain bounded malformed statements, or end in a lost
|
|
1220
|
+
boundary. Parsed operations still dispatch; each hard parser diagnostic — the
|
|
1221
|
+
tail's reason included — becomes one durable model-origin `error` row with the
|
|
1222
|
+
parser's exact detail under {§parse-diagnostics} and status 400. These failures are committed before the
|
|
1223
|
+
explicit WAIT, or at the end of a program without WAIT, participate in the ordinary strike rail, and prevent
|
|
1224
|
+
completion before the model sees them in the next packet.
|
|
1225
|
+
WAIT without a live obligation continues to those results.
|
|
1275
1226
|
This is operation recovery, not provider
|
|
1276
1227
|
resampling. A malformed statement's Problem records the factual
|
|
1277
1228
|
`siblingsRetained: true` extension.
|
|
@@ -1314,9 +1265,7 @@ Runtime hooks are synchronous and receive only the attempt coordinates. A hook
|
|
|
1314
1265
|
failure is an internal plugin-contract failure; Core does not silently discard
|
|
1315
1266
|
it or reinterpret a malformed tag list.
|
|
1316
1267
|
|
|
1317
|
-
§
|
|
1318
|
-
|
|
1319
|
-
§client-metadata **The workspace's `client` id rides the same wire.** A frontend self-identifies (e.g. `plurnk.nvim/1.4.0`) at `workspace.create({ settings: { client } })`; the engine forwards it per turn on `generate({ client })`, which only the `plurnk` provider emits (as `Plurnk-Client`). Workspace-stable and self-reported — distinct from attribution's install-grounded tags — and omitted when unset.
|
|
1268
|
+
§client-metadata **The workspace records which frontend opened it.** A frontend self-identifies (e.g. `@plurnk/plurnk-tui/1.4.0`) at `workspace.create({ settings: { client } })` and the daemon stores it with the workspace. It is validated on write, never forwarded to a provider, and never model-facing. Workspace-stable and self-reported — distinct from attribution's install-grounded tags — and omitted when unset.
|
|
1320
1269
|
|
|
1321
1270
|
### §provider-instantiation Provider instantiation
|
|
1322
1271
|
|
|
@@ -1367,7 +1316,7 @@ PLURNK_MODEL=gemma
|
|
|
1367
1316
|
|
|
1368
1317
|
First path segment = provider name; rest = provider-native model id.
|
|
1369
1318
|
|
|
1370
|
-
###
|
|
1319
|
+
### Mock provider (sibling fixture)
|
|
1371
1320
|
|
|
1372
1321
|
§mock-provider-mock-fixture `Mock` (exported from `@plurnk/plurnk-providers`) — intg fixture + reference implementation. `{ contextWindow, responses }` constructor; `generate` shifts from the queue. `MockResponse.assistant.ops?: PlurnkStatement[]` is a pre-parsed escape hatch the engine consumes directly when present; production providers don't expose this — and being a plugin export, this contract has no service-side `§`-ref.
|
|
1373
1322
|
|
|
@@ -1411,14 +1360,24 @@ meaning of an authored URI authority before any entry capability is exposed:
|
|
|
1411
1360
|
| Project files | Filesystem namespace | Workspace policy | Shared live |
|
|
1412
1361
|
| `worker:///...` | Empty, shared scratch | Any workspace actor | Shared live |
|
|
1413
1362
|
| `worker://alice/...` | Named scratch | Any workspace actor | Snapshot source namespace into new name |
|
|
1414
|
-
| `
|
|
1415
|
-
| `
|
|
1363
|
+
| `ops://<worker>/<loop>/<turn>`, `reasoning://<worker>/<loop>/<turn>` | Named worker's turn history | Immutable for every actor | Snapshot sources at identical coordinates under the child's name |
|
|
1364
|
+
| `note://<worker>/<loop>/<turn>/<item>` | Named worker's NOTE history | Immutable for every actor | Snapshot sources at identical coordinates under the child's name |
|
|
1365
|
+
| `ops://<worker>/<loop>` | Named worker's loop | Immutable: what it said, or how it ended | Snapshot terminal history under the child's name |
|
|
1366
|
+
| `message://<worker>/<id>` | Native message admitted to the named worker | Immutable; SEND records a separate reply | Retain original addresses |
|
|
1367
|
+
| `log:///<loop>/<turn>/<item>/<op>` | Implicit observing worker | KILL curates the projection, not its source | Snapshot projection; explicit source addresses stay unchanged |
|
|
1368
|
+
| `<executor>:///<id>` | Empty, workspace output namespace | Executor stream contract | Shared live; no copied process |
|
|
1416
1369
|
| `skill://recipe/...` | Installed skill name | Skill resource contract | Shared installation |
|
|
1417
1370
|
| HTTP, WebSocket, executor/MCP, A2A resources | Scheme's canonical namespace | Scheme contract and workspace policy | Shared live; no copied connection |
|
|
1418
1371
|
|
|
1419
1372
|
Copied bodies and log references remain verbatim. Explicit source addresses continue to name the source; only copied scratch/evidence resources' own authority becomes the child's name ({§machine-processes-entry-inheritance}).
|
|
1420
1373
|
|
|
1421
|
-
|
|
1374
|
+
The scheme identifies the resource kind, the authority names its namespace, and
|
|
1375
|
+
the path identifies the resource within it. History uses worker-local loop/turn/item
|
|
1376
|
+
sequences; native messages and workspace outputs use opaque identifiers rather than
|
|
1377
|
+
pretending to be turn coordinates. `worker://<name>` addresses the actor, not a
|
|
1378
|
+
historical execution. No address grants ownership or access restrictions.
|
|
1379
|
+
|
|
1380
|
+
§fs-namespace **The workspace is a mount namespace; `project_root` is the model's `/`.** A namespace *names*; it does not confine. Host paths do not exist in it, and no engine surface folds a host-absolute spelling onto a member — not because a wall refuses them, but because those coordinates have no meaning here. What the model can reach is exactly the mount table, which the operator composes: a membership overlay routinely mounts a path from above the root (`../house-policy.md` is an ordinary `include` grantor, {§fs-visibility-grantors}), and it arrives named in namespace coordinates like everything else. Plurnk is therefore not a sandbox and claims no containment — confinement is the host's job; what Plurnk owns is authority, consent and audit. The root is **fixed immutably at workspace creation** (headless is forever); the mount table changes only through the declared membership overlay ({§membership}), never by re-rooting. At `project_root = /` the namespace is the whole filesystem and every rule below degenerates to identity — the design's proof case, and the common benchmark topology.
|
|
1422
1381
|
|
|
1423
1382
|
§fs-namei **Resolution is namei over the mount table.** The model's CWD is permanently `/`, so `src/x.md` and `/src/x.md` are the same name — the slash rule is a corollary, never a legislated equivalence. Resolution is lexical: `.` and `..` resolve before anything touches storage (`..` is legal *during* traversal); the final name lands in the root subtree (a bare key), on a declared outside-root mount (a `../`-prefixed key — the git-style overlay), or names nothing (404 carrying the resolved form). Containment is the resolution semantics — there is no separate traversal check to forget.
|
|
1424
1383
|
|
|
@@ -1481,7 +1440,7 @@ Every fact names the canonical key, never the host root or an echo of the
|
|
|
1481
1440
|
model's spelling. These classes let a caller distinguish a wrong address, an
|
|
1482
1441
|
invalid range, read-only authority, and occupied hidden state without guessing.
|
|
1483
1442
|
|
|
1484
|
-
§membership-read-refusal **A
|
|
1443
|
+
§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 COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, with a recovery naming both doors: EDIT creates a member at the path, and ```` ```members (add) ```` with a `{"glob": "<path>"}` body admits a file that already exists. 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. 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.` Occupancy may surface there; content never does ({§membership}).
|
|
1485
1444
|
|
|
1486
1445
|
§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.
|
|
1487
1446
|
|
|
@@ -1498,13 +1457,14 @@ own a more specific operation. A stored-entry publication atomically upserts
|
|
|
1498
1457
|
one workspace identity, metadata, and its complete channel set. Concurrent
|
|
1499
1458
|
publications expose one complete result, never a mix of channels; a failed
|
|
1500
1459
|
publication leaves the prior entry unchanged. Omitted attributes preserve the
|
|
1501
|
-
existing bag.
|
|
1460
|
+
existing bag. Unchanged channel representations retain their derivations;
|
|
1461
|
+
changed representations invalidate them and omitted channels are removed.
|
|
1462
|
+
Reads observe metadata and channels in one snapshot. There is no
|
|
1502
1463
|
cross-scheme SQL transaction. Core's create-only publication claims the same
|
|
1503
1464
|
identity atomically: an existing identity returns 409 without changing its
|
|
1504
|
-
metadata or channels.
|
|
1505
|
-
upsert another prompt's contents ({§prompt-address}).
|
|
1465
|
+
metadata or channels.
|
|
1506
1466
|
|
|
1507
|
-
###
|
|
1467
|
+
### Op methods
|
|
1508
1468
|
|
|
1509
1469
|
§op-methods-op-dispatch Engine operation ownership follows the public scheme contract:
|
|
1510
1470
|
|
|
@@ -1521,7 +1481,7 @@ Registration precedes loop affinity:
|
|
|
1521
1481
|
| Registered but inactive under flag | The flag gate returns `403 scheme-unavailable`. |
|
|
1522
1482
|
| Registered and active | Dispatch continues to the operation owner. |
|
|
1523
1483
|
|
|
1524
|
-
- §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. Only
|
|
1484
|
+
- §op-execution-order **An admitted turn is an ordered program.** Model, client, and harness operations execute in authored order. Only 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 WAIT; 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.
|
|
1525
1485
|
|
|
1526
1486
|
§bare-inference **BARE is isolated, synchronous retrieval over the durable child-provider policy.**
|
|
1527
1487
|
|
|
@@ -1538,11 +1498,12 @@ Registration precedes loop affinity:
|
|
|
1538
1498
|
- §op-synchronous **Decisive operations settle before the next operation.** The dispatcher awaits each operation and its proposal resolution. Work remains in flight only when the operation's contract deliberately creates concurrency: FORK, WORK, a stream-producing execution, and streaming READ after acquisition. Such a READ first establishes its durable subscription and returns `102`; a later operation may address that live owner. Dispatching an execution before KILL does not wait for the process to finish using a resource. KILL of a worker synchronously ends its live loops before disposition checks the pending set; physical scope cleanup remains asynchronous.
|
|
1539
1499
|
- §edit-execution **One authored EDIT is one mutation.** Each EDIT resolves against current resource state when dispatch reaches it, owns its proposal when gated, and records its own resulting revision. No later EDIT is prepared or applied in advance. Numeric scopes address current coordinates; an earlier EDIT may change what those numbers select. Rejection applies only to that operation, not its successful siblings.
|
|
1540
1500
|
- §edit-anchor-continuity **Own EDITs preserve untouched hash targets within one program.** Core carries an anchor through exact, successfully applied EDIT splices when its line survives unchanged, even if its ordinal or neighborhood changes. Scoped entry KILL uses the same deletion path. Target-line replacement or deletion invalidates that binding. Continuity is private to the admitted program and canonical resource/channel; it is not a new published anchor format. The complete normalized line content must match the expected result of the preceding recorded EDIT, otherwise retained bindings are discarded and ordinary current-state validation applies. Reviewer replacement and results without an applied EDIT receipt do not carry bindings forward. Normalization is the same line-content representation used by READ and line hashing; file-write revision checks remain independent. No approximate text matching is used. Lowered coordinates retain a current-anchor precondition at the mutation owner; ambiguous matches and concurrent changes remain collisions.
|
|
1501
|
+
- §anchor-offset **An anchor offset is tolerated, never taught (#749).** A line mark may carry an offset from its anchor (`@abcde+1`, `@abcde-2`), and a bare `+N` after an anchor counts from that anchor (`<@abcde,+1>`). The anchor resolves as usual and the offset is added; a result before line 1 is an invalid mark, and past the end is the ordinary range refusal. Continuity and current-anchor preconditions check the anchor's own line. No teaching text, scope table or receipt mentions offsets; `plurnk.md` keeps its two anchor forms. A bare `+N` with no anchor before it is refused as before.
|
|
1541
1502
|
- §edit-batch **One compound operation may require atomic splices.** The scheme's `editBatch` primitive validates all supplied numeric edits against one snapshot and commits one revision or none. Core supplies one statement for an authored EDIT; same-resource MOVE can supply multiple splices as one operation. This primitive does not group separate authored operations. Its replacement, insertion, conflict, and receipt rules remain owned by the shared Slicer.
|
|
1542
1503
|
- §edit-batch-receipt **A refusal describes its own unapplied work.** An anchor collision lists every distinct unresolved anchor in that EDIT, including both range endpoints, in `unresolvedAnchors` (`anchor`, `kind: missing | ambiguous`, and matching `lines` when ambiguous). Missing is not proof of earlier validity or subsequent change. It carries `editCount: 1`, `applied: 0`, and recovery directing a READ for current coordinates; it makes no claim about other operations. A refused compound splice batch lists all conflicting pairs in `conflicts`, non-conflicting regions in `cleanRegions`, its first pair in `conflictingRegions`, and its own `editCount` and `applied: 0`.
|
|
1543
1504
|
- §edit-batch-merges **Normalizations require evidence and a receipt.** An EDIT body carrying only this resource's published `@xxxxx L:` prefixes is stripped when those prefixes verify against current anchors or this worker's preserved READ receipts (`rendered-prefix-stripped`); otherwise it remains literal content (`rendered-prefix-unverified`). Within a single atomic splice batch, the Slicer can deduplicate identical regions/bodies, concatenate same-boundary insertions, assign a shared endpoint to the sole body reproducing that line, or relocate an inner change when its original content occurs exactly once in the outer body. An already-applied inner body can be dropped. Unevidenced overlap remains a collision. These batch resolutions never reinterpret separate authored EDITs. Applied normalizations carry their exact merge facts and a notice; receipts describe only the applied effects.
|
|
1544
1505
|
|
|
1545
|
-
###
|
|
1506
|
+
### Cross-scheme orchestration
|
|
1546
1507
|
|
|
1547
1508
|
Core owns same- and cross-scheme transfers under {§copy} and {§move}; handlers
|
|
1548
1509
|
provide the underlying resource operations. Each operand independently selects
|
|
@@ -1550,16 +1511,40 @@ a resource, channel, and optional text scope ({§transfer-resource-selections}).
|
|
|
1550
1511
|
Source acquisition follows {§universal-read-composition}; landed mutation
|
|
1551
1512
|
effects follow {§edit-result-copy-move-effects}.
|
|
1552
1513
|
|
|
1553
|
-
###
|
|
1514
|
+
### SEND dispatch (a message to a recipient)
|
|
1554
1515
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1516
|
+
Targetless and exact-message SENDs follow the reply accounting at
|
|
1517
|
+
{§send-response-receipt}. Other directed SENDs route to the recipient scheme's
|
|
1518
|
+
`send`: the body is the message — a WebSocket frame, exec stdin, an HTTP POST,
|
|
1519
|
+
an A2A message, or new work for a worker.
|
|
1559
1520
|
|
|
1560
|
-
§send-dispatch-entry-schemes-501
|
|
1521
|
+
§send-dispatch-entry-schemes-501 A SEND aimed at a resource entry, rather than a
|
|
1522
|
+
message or actor endpoint, returns 501. Its recovery distinguishes replying to
|
|
1523
|
+
Open Messages from sending new work to a worker, without assuming either intent.
|
|
1561
1524
|
|
|
1562
|
-
|
|
1525
|
+
#### §send-resource-attachments Explicit message attachments
|
|
1526
|
+
|
|
1527
|
+
Targetless replies, worker messages, and A2A messages accept
|
|
1528
|
+
`[{"attachments":["report.pdf","worker://alice/result.json"]}]` on SEND.
|
|
1529
|
+
The body remains the authored message, not an attachment envelope.
|
|
1530
|
+
|
|
1531
|
+
| Boundary | Contract |
|
|
1532
|
+
|---|---|
|
|
1533
|
+
| Selection | An ordered array of exact resource/channel addresses; no implicit export, glob expansion, or Markdown-link interpretation. |
|
|
1534
|
+
| Acquisition | The same source selection and representation preparation as COPY, under ordinary READ capability admission; acquire every source before delivering the message. A failed source produces its normal failure and delivers nothing. |
|
|
1535
|
+
| Snapshot | Preserve the selected bytes, media type, name, and source address at SEND time. Later source mutation, deletion, or log curation cannot alter the delivered content. |
|
|
1536
|
+
| Receipt | Safe attachment descriptors identify immutable content; binary payloads do not enter ordinary log text. |
|
|
1537
|
+
| Ownership | Message recipients opt into this option. HTTP headers and executor stdin retain their own metadata contracts. |
|
|
1538
|
+
| Arrival | Publish attachments as ordinary typed resources and link them from the inbound SEND. Arrival alone does not inject native media; READ does. |
|
|
1539
|
+
|
|
1540
|
+
#### §message-envelope-evidence Durable message evidence
|
|
1541
|
+
|
|
1542
|
+
The ordinary inbox retains an optional transport envelope alongside the
|
|
1543
|
+
model-facing body and attachments. Exterior adapters own its protocol shape;
|
|
1544
|
+
Core preserves it without interpreting protocol fields. History reads this
|
|
1545
|
+
durable evidence, not a curated text projection. Accepted interaction answers
|
|
1546
|
+
retain their envelope before waking the waiting operation; rejected answers
|
|
1547
|
+
create no message evidence.
|
|
1563
1548
|
|
|
1564
1549
|
### §scheme-surface Consumption surface
|
|
1565
1550
|
|
|
@@ -1634,9 +1619,9 @@ Handler authority, discovery, projection identity, and failures follow
|
|
|
1634
1619
|
persistence, packet accounting ({§tokenomics-agnostic-ruler}), and subscriptions
|
|
1635
1620
|
({§subscriptions}); handlers do not.
|
|
1636
1621
|
|
|
1637
|
-
###
|
|
1622
|
+
### Consumption surface
|
|
1638
1623
|
|
|
1639
|
-
plurnk-service is mimetype-illiterate.
|
|
1624
|
+
plurnk-service is mimetype-illiterate. A channel's `lines` is stored when its content is written, so the catalog reads no bodies and calls no handler; `Mimetypes.process({content, hint})` serves search derivation ({§persistent-search-index}) and parse-issue probes. Content reaches the model on READ, not as a rendered preview.
|
|
1640
1625
|
|
|
1641
1626
|
§mimetype-owned-lifecycle `Daemon` owns and disposes the `Mimetypes` instance
|
|
1642
1627
|
it constructs. A constructor-injected instance remains caller-owned. Shutdown
|
|
@@ -1664,7 +1649,7 @@ model-independent ruler for stored/catalog weights and the model-facing curation
|
|
|
1664
1649
|
confined to provider-owned physical capacity assessment
|
|
1665
1650
|
({§tokenomics-context-envelope-admission}).
|
|
1666
1651
|
|
|
1667
|
-
**Conformance.** Mimetype-specific behavioral tests live in each handler's own surface. plurnk-service intg covers integration: the engine routes through `Mimetypes.process` with the right hint and the catalog reflects
|
|
1652
|
+
**Conformance.** Mimetype-specific behavioral tests live in each handler's own surface. plurnk-service intg covers integration: the engine routes through `Mimetypes.process` with the right hint and the catalog reflects the stored line count; tests use auto-discovery (production handler set); a custom-handler test injects a stub `BaseHandler` via `loader + discovery`.
|
|
1668
1653
|
|
|
1669
1654
|
## §persistent-search-index Search indexing
|
|
1670
1655
|
|
|
@@ -1682,6 +1667,15 @@ empty setting excludes nothing, and the first match is the observable reason.
|
|
|
1682
1667
|
| Other-scheme channel | Always eligible; its pathname is a resource identity. |
|
|
1683
1668
|
| Log projection | Always eligible; it has no repository-path membership. |
|
|
1684
1669
|
|
|
1670
|
+
§search-size-bound Every search subject, whatever its scheme, is also bounded
|
|
1671
|
+
by size when the operator sets one: a body longer than
|
|
1672
|
+
`PLURNK_SERVICE_SEARCH_MAX_BYTES` (default empty = unbounded) is `excluded` with the reason `larger than N bytes`, before
|
|
1673
|
+
its body is read. It is neither parsed for symbols nor full-text indexed; READ,
|
|
1674
|
+
FIND by path, and membership are unaffected. The reason joins the derivation
|
|
1675
|
+
identity, so changing the bound re-derives the affected bodies and retention
|
|
1676
|
+
collects what they leave. Origin (#729): the dogfood workspaces indexed 29
|
|
1677
|
+
tokenizer vocabularies (up to 31 MB each) as full text.
|
|
1678
|
+
|
|
1685
1679
|
A match produces the `excluded` derivation disposition and suppresses graph
|
|
1686
1680
|
and FTS while leaving the stored channel and direct READ unchanged. The
|
|
1687
1681
|
same reason participates in the derivation hash and is surfaced by diagnostics
|
|
@@ -1714,7 +1708,7 @@ operator knobs in `.env.defaults`. Search indexing performs no inference.
|
|
|
1714
1708
|
|
|
1715
1709
|
## §channels Channel Topology
|
|
1716
1710
|
|
|
1717
|
-
§channels-
|
|
1711
|
+
§channels-entry-name-key Every entry has named channels: **content stores keyed by `(entry_id, name)`**, one row per name. Schemes write content — appending to a channel, replacing it, or deleting it; mimetype handlers interpret it.
|
|
1718
1712
|
|
|
1719
1713
|
### §per-entry-channels Per-entry channels
|
|
1720
1714
|
|
|
@@ -1753,17 +1747,17 @@ Rules:
|
|
|
1753
1747
|
| URI | Channel |
|
|
1754
1748
|
| ------------------------------------ | ------------------------------------ |
|
|
1755
1749
|
| `worker:///france/capital` | body (default) |
|
|
1756
|
-
| `sh:///
|
|
1757
|
-
| `sh:///
|
|
1750
|
+
| `sh:///a3b7c921#stdout` | stdout |
|
|
1751
|
+
| `sh:///a3b7c921#stderr` | stderr |
|
|
1758
1752
|
| `https://feed.example/y#body` | body |
|
|
1759
|
-
| `log:///
|
|
1753
|
+
| `log:///1/2/3/READ` | (no channel concept; atomic log row) |
|
|
1760
1754
|
|
|
1761
1755
|
Op implications:
|
|
1762
1756
|
|
|
1763
1757
|
- EDIT to undeclared channel → 404; read-only channel → 405.
|
|
1764
1758
|
- COPY/MOVE source and destination fragments independently select channels.
|
|
1765
1759
|
|
|
1766
|
-
Client-interface target parameters carry fragments inline (`{ target: "sh:///
|
|
1760
|
+
Client-interface target parameters carry fragments inline (`{ target: "sh:///a3b7c921#stderr" }`).
|
|
1767
1761
|
|
|
1768
1762
|
**Wire rendering: default channel is path-only.** A rendered target omits `#channel` when channel matches `defaultChannel`. Single-channel entries render path-only; multi-channel entries render the default path-only and only non-default carries `#name`.
|
|
1769
1763
|
|
|
@@ -1802,7 +1796,7 @@ Model uses state to anticipate growth between turns. Clients use state for UI (s
|
|
|
1802
1796
|
|
|
1803
1797
|
---
|
|
1804
1798
|
|
|
1805
|
-
##
|
|
1799
|
+
## Op Surface
|
|
1806
1800
|
|
|
1807
1801
|
Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkStatement`. Engine dispatches by `op`; scheme implements per author contract ({§scheme}).
|
|
1808
1802
|
|
|
@@ -1947,6 +1941,7 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
1947
1941
|
when that differs from the channel's own mimetype the result names the
|
|
1948
1942
|
channel's as `sourceMimetype`, so a consumer can still run the channel's
|
|
1949
1943
|
handlers over a whole-resource `<1,-1>` read.
|
|
1944
|
+
- §log-range-miss-names-stream A 416 on a log execution item is the range twin of its channel miss ({§log-channel-miss-names-stream}): the coordinate 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 gains it as `stream`, the detail appends where the command's streams live, and `recovery` is `READ <stream> for the command's stream`, whether the invocation's extent is empty or merely shorter than the range (#759). A 416 on a row with no recorded stream stays byte-identical to the generic slicer's.
|
|
1950
1945
|
- §read-pattern **A pattern selects the lines a READ renders.** With a heading
|
|
1951
1946
|
matcher ({§matcher-option} in the contracts SPEC) an exact-target READ stays a
|
|
1952
1947
|
READ: the matcher runs over the channel's text line by line — a regex anchors
|
|
@@ -1983,13 +1978,14 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
1983
1978
|
resources, not lines, so that READ dispatches as the FIND survey. Operator,
|
|
1984
1979
|
2026-09-13: "give it what it asked for" — a model that asked to read the pantry
|
|
1985
1980
|
looped five turns on the catalog it was handed instead.
|
|
1986
|
-
- §read-bytes A binary channel
|
|
1981
|
+
- §read-bytes A binary channel, and the `#bytes` view of
|
|
1987
1982
|
any resource whose scheme supplies bytes, reads as the source bytes one hexadecimal
|
|
1988
1983
|
octet per line: coordinate = line = byte, so `<a,b>` selects bytes, the markerless
|
|
1989
|
-
default is the
|
|
1984
|
+
default is the shared first page ({§markerless-first-page}), `<1,-1>` is the whole resource, and the extent carries
|
|
1990
1985
|
`unit: "byte"`. The result keeps the source mimetype and names `projection: "hex"`;
|
|
1991
1986
|
anchors do not exist there (400). Bytes are read from the source at READ time, sized
|
|
1992
|
-
then windowed
|
|
1987
|
+
then windowed: `file:` supplies them from the member on disk, DB-backed schemes
|
|
1988
|
+
recover their stored bytes under {§binary-parity}, and a
|
|
1993
1989
|
scheme that keeps no bytes answers 501 `bytes-unavailable` for `#bytes` and 415 for a
|
|
1994
1990
|
binary channel, as before. An execution whose target is a file member already runs the
|
|
1995
1991
|
bytes on disk. Byte selection affects only this hexadecimal projection: when the
|
|
@@ -2017,8 +2013,11 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
2017
2013
|
window is preserved, and the whole spliced result is re-written through the proposal gate. A binary
|
|
2018
2014
|
**lives in a DB entry** as its bytes base64 in the channel's TEXT content; the same READ, byte range,
|
|
2019
2015
|
and COPY/MOVE recover them through a byte source synthesized from that content, so a File member and a
|
|
2020
|
-
`worker://` entry hold and yield a binary identically.
|
|
2021
|
-
|
|
2016
|
+
`worker://` entry hold and yield a binary identically. An empty binary channel represents
|
|
2017
|
+
zero bytes, not an unsupported format; whole COPY/MOVE preserves it. Failed acquisition
|
|
2018
|
+
is not an empty success: its producer outcome remains authoritative for READ and transfer.
|
|
2019
|
+
This supersedes the older blanket refusal (#140)
|
|
2020
|
+
for both the file and the entry case. Native image/PDF/audio attachment facts come from the configured
|
|
2022
2021
|
mimetype handler over original bytes, whether supplied by a file or stored channel
|
|
2023
2022
|
({§packet-attachment-parts}); the hexadecimal view remains available. The exceptions are narrow and
|
|
2024
2023
|
defined, each a clear receipt rather than a dead end: a binary region addressed by a **textual anchor**
|
|
@@ -2051,30 +2050,23 @@ same transitions the dispatcher's atomic curation event makes, without the row.
|
|
|
2051
2050
|
| Surface | Contract |
|
|
2052
2051
|
|---|---|
|
|
2053
2052
|
| Evidence | Original provider reasoning remains verbatim in immutable model-call responses and admitted packets. Resource and log operations never rewrite it. Only an admitted response, or the final exhausted emission attempt, produces a model reasoning source; missing provider reasoning creates no substitute. A non-model producer may record its own authored rationale under {§turn-source-resources}. |
|
|
2054
|
-
| Resource | `reasoning
|
|
2053
|
+
| Resource | `reasoning://<worker>/<loop>/<turn>` is immutable text/plain source belonging to the named workspace worker's turn under {§turn-source-resources}. Every workspace actor may READ, FIND, search and COPY from it; none may EDIT, KILL, COPY into or MOVE it. |
|
|
2055
2054
|
| Delivery | Initialization READs its own authored rationale under {§reasoning-initial-read}. Further observations require deliberate READs. The selected model reasoning source is stored before its OPs execute, so an ordinary READ of the current turn resolves immediately and is visible in subsequent packets. Every READ retains its authored scope and ordinary range metadata, without edit anchors. |
|
|
2056
2055
|
| Curation | Scoped log KILL suppresses receipt lines; whole log KILL retires the receipt. Neither affects the source. Explicit log READs retain ordinary curation anchors. A mutable working copy requires ordinary COPY into an editable resource. |
|
|
2057
|
-
| Lifecycle | Restart retains sources and observations. FORK snapshots sources at the same
|
|
2056
|
+
| Lifecycle | Restart retains sources and observations. FORK snapshots sources under the child's name at the same loop/turn coordinates and receipts with independent curation. No curation or lifecycle event automatically READs model reasoning. A turn the provider left without reasoning reads empty; absent workers and turns return the ordinary missing result ({§turn-source-resources}). |
|
|
2058
2057
|
| Client | Standard live reasoning events and replay retain original provider reasoning; working resources and READ receipts never substitute for or replay that stream. |
|
|
2059
2058
|
|
|
2060
2059
|
### §reasoning-initial-read Initial reasoning observation
|
|
2061
2060
|
|
|
2062
|
-
The
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
({§naked-pattern} in the contracts SPEC), so the first model packet shows the
|
|
2070
|
-
maneuver working rather than described: only the note lands. The model's own
|
|
2071
|
-
coordinate is inferable from the `## Worker` block below the log
|
|
2072
|
-
({§packet-current-turn}), so the note teaches nothing the packet already says
|
|
2073
|
-
(operator, 2026-09-12: "Recursive Reasoning" — mark what must survive `Note:`,
|
|
2074
|
-
pluck it, and let the rest of the reasoning go). Each resolves through ordinary
|
|
2075
|
-
READ dispatch.
|
|
2061
|
+
The initialization turn records a short `_plurnk`-authored rationale containing
|
|
2062
|
+
a fenced NOTE. The shared reasoning extractor ({§reasoning-notes}) executes that
|
|
2063
|
+
NOTE through ordinary dispatch, creating its log item and immutable source.
|
|
2064
|
+
The program begins with its own NOTE and READs its reasoning and persisted ops,
|
|
2065
|
+
demonstrating both NOTE placements and their ordinary results. The initial message arrives separately as an
|
|
2066
|
+
inbound SEND ({§message-arrival}). Neither initialization nor later turns
|
|
2067
|
+
manufacture a task inventory.
|
|
2076
2068
|
`PLURNK_REASONING_VIEW_LINES` (default `-1`, alias-scoped) selects this one READ's
|
|
2077
|
-
scope: `0` omits it, `-1`
|
|
2069
|
+
scope: `0` omits it, `-1` reads the complete rationale, and a positive integer
|
|
2078
2070
|
bounds it to the first N lines. Source retention, deliberate READs, and client
|
|
2079
2071
|
streaming are independent. No later turn automatically requests reasoning.
|
|
2080
2072
|
|
|
@@ -2118,18 +2110,66 @@ The `## Log` section is a sequence of ordinary Markdown records separated by one
|
|
|
2118
2110
|
<coordinate-prefixed body lines when visible>
|
|
2119
2111
|
```
|
|
2120
2112
|
|
|
2121
|
-
The H3 is the row's complete model-facing identity and canonical READ
|
|
2113
|
+
The H3 is the row's complete model-facing identity and canonical READ address; metadata never repeats that identity or its operation. The following line is one strict JSON object: addressed operands ({§log-address-metadata}) precede `aside`, then all remaining members use stable alphabetical order. 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.
|
|
2114
|
+
|
|
2115
|
+
§log-address-metadata **Addresses name their relationship, not the row's producer.**
|
|
2116
|
+
|
|
2117
|
+
| Metadata | Meaning | Order |
|
|
2118
|
+
|---|---|---|
|
|
2119
|
+
| `path` | The operation's addressed operand, matching `OP (path)`: read resource, mutation subject, message recipient, or executor operand. Explicit and automatic READs use the same field. Pathless operations omit it. | First |
|
|
2120
|
+
| `from`, `to` | COPY/MOVE's two operand selections, each retaining its optional scope; neither replaces actor attribution or is repeated as `path`. | First, in that order |
|
|
2121
|
+
| `stream` | An executor invocation's separately created output address, never a READ's alternative spelling of `path`. | Remaining facts |
|
|
2122
|
+
| `resource` | A distinct returned resource under {§operation-resource-receipt}. | Remaining facts |
|
|
2123
|
+
|
|
2124
|
+
Nested mutation effects and delivered attachments name their resource with `path`.
|
|
2125
|
+
These packet spellings do not rename the submitted AST, durable operation results,
|
|
2126
|
+
or client protocol fields. Invocation correlation remains on the subscription and
|
|
2127
|
+
its publication identity; an automatic stream READ does not copy the invocation's
|
|
2128
|
+
log address into its `source`. Actual actor/subsystem attribution remains governed
|
|
2129
|
+
by {§env-delta-attribution}.
|
|
2122
2130
|
|
|
2123
|
-
Coordinate-prefixed lines are the text currently in context; a metadata-only row contributes no text body.
|
|
2131
|
+
Coordinate-prefixed lines are the text currently in context; a metadata-only row contributes no text body. Selection, preview, and curation metadata follow {§packet-extent-metadata}; coordinate gaps expose omissions without renumbering.
|
|
2132
|
+
|
|
2133
|
+
§packet-extent-metadata **One scope notation, distinct coordinate owners.**
|
|
2134
|
+
|
|
2135
|
+
| Field | Coordinate owner | Representation |
|
|
2136
|
+
|---|---|---|
|
|
2137
|
+
| `range` | The resource addressed by a successful READ/FIND | `<first,last> of N lines/resources/match locations/bytes`; singleton scopes use `<first>`. A complete dense selection reduces to `N units`; an empty selection from a nonempty extent is `none of N units`. |
|
|
2138
|
+
| `range` for exact text | The addressed text resource | `<startLine,startColumn,endLine,endColumn>`; no invented available extent. |
|
|
2139
|
+
| `preview` | The retained receipt body | Only when displayed incompletely: selected scope(s) `of N lines`, or exact selected region `of` complete region for an in-line cut. Replaces the body's otherwise redundant `lines` count. |
|
|
2140
|
+
| `trimmed` | The receipt's original physical body lines | Array of deliberately removed `<scope>`s on a partially visible row; initial suppression is not curation. |
|
|
2141
|
+
| `effect` | The mutation's source and landed revisions | Resolved `<source> -> <result>`; counts and complete-resource extent remain separate facts. |
|
|
2142
|
+
|
|
2143
|
+
Scopes use the existing inclusive line/item/byte coordinates or start-inclusive,
|
|
2144
|
+
end-exclusive Unicode-code-point text regions ({§text-scope-semantics}). Sparse
|
|
2145
|
+
retrieval ranges are enclosing spans; body ordinals and matcher counts retain
|
|
2146
|
+
the gaps, and a sparse span covering both endpoints is not abbreviated as a
|
|
2147
|
+
complete acquisition. Sparse previews list their selected contiguous runs.
|
|
2148
|
+
Retrieval `range` records acquisition, not subsequent visibility: KILL changes
|
|
2149
|
+
the log projection, never the original source selection. A READ's source line
|
|
2150
|
+
numbers and its receipt's body-relative curation coordinates remain distinct
|
|
2151
|
+
({§log-kill-scope}). Byte ranges describe the hex selection, not native-media
|
|
2152
|
+
cropping ({§packet-attachment-parts}).
|
|
2153
|
+
|
|
2154
|
+
Successful retrieval metadata omits requested coordinates; durable results and
|
|
2155
|
+
submitted programs retain them. Failed selections keep requested coordinates
|
|
2156
|
+
and available extent in their owning Problem. Projection never parses its
|
|
2157
|
+
display strings to recover typed facts. A hidden body has no `preview`; a
|
|
2158
|
+
complete non-retrieval body retains `lines` where no other field supplies its
|
|
2159
|
+
navigable extent. None of these spellings changes acquisition, delivery,
|
|
2160
|
+
curation, admission, or immutable evidence.
|
|
2124
2161
|
|
|
2125
2162
|
Field absence carries defaults: `origin` is omitted for the owning model, `source` for the owning worker, and `status` for a routine 200. Dispositions always carry their lifecycle status, SEND its delivery status, KILL keeps an explicit 200, and every non-200 stays explicit. A present authored aside appears as `aside`. Every row's accounting follows {§packet-token-accounting}.
|
|
2126
2163
|
|
|
2164
|
+
- §operation-resource-receipt A result's nonempty `resource` address remains visible in receipt metadata when distinct from its `path` and `stream`. It identifies returned material without replacing the addressed operand or injecting that material into context; ordinary READ acquires it.
|
|
2127
2165
|
- §packet-attachment-parts A successful READ of an attachable resource carries projection facts with its
|
|
2128
2166
|
result ({§mimetype-projection-facts}): an image ({§mimetype-image}) as
|
|
2129
2167
|
`image: { mimetype, width, height, bytes }`, a PDF ({§mimetype-pdf-facts}) as
|
|
2130
2168
|
`document: { mimetype, pages, bytes }` (`pages` null when the page tree is unreadable; the
|
|
2131
|
-
attachment then weighs by bytes and carries no page count)
|
|
2132
|
-
|
|
2169
|
+
attachment then weighs by bytes and carries no page count), or audio ({§mimetype-audio-facts}) as
|
|
2170
|
+
`audio: { mimetype, duration, bytes }` (`duration` in seconds, null when unknown). READ snapshots complete source bytes through
|
|
2171
|
+
the scheme's byte supplier or ordinary stored binary channel ({§binary-parity}), checking
|
|
2172
|
+
{§mimetype-binary-input} before loading the native snapshot; the text/hex projection
|
|
2133
2173
|
and native observation use those same bytes. Immutable content-addressed `native_contents` stores each
|
|
2134
2174
|
byte sequence once; the result's `nativeContentHash`, enforced by the log's foreign key, identifies it.
|
|
2135
2175
|
This is retained evidence, not a separate visibility or delivery lifecycle. Source mutation/deletion
|
|
@@ -2140,12 +2180,13 @@ Field absence carries defaults: `origin` is omitted for the owning model, `sourc
|
|
|
2140
2180
|
suppresses the complete native part under {§context-output-admission}. Unsupported routes receive only the
|
|
2141
2181
|
text projection and no native charge; switching back to a compatible route exposes still-retained media.
|
|
2142
2182
|
Each included part contributes `tokensAttachment` within `logTokens`: `ceil(width × height / 750)` for an
|
|
2143
|
-
image, `pages × 1500` for a document, or `ceil(bytes / 4)` when
|
|
2183
|
+
image, `pages × 1500` for a document, `ceil(duration × 32)` for audio, or `ceil(bytes / 4)` when page count
|
|
2184
|
+
or duration is unknown. Byte ranges select
|
|
2144
2185
|
hexadecimal text, never crop the native resource. Retries reuse the frozen request; model-call evidence
|
|
2145
2186
|
records the exact READ coordinates sent without controlling retention. Missing immutable bytes are an
|
|
2146
2187
|
internal integrity failure, never silently dropped content. No ejection message or permanent teaching is
|
|
2147
2188
|
added. These stable curation weights are not provider-token measurements ({§tokenomics-render-weight-budget}).
|
|
2148
|
-
- §packet-token-accounting Every row reports one `logTokens` charge: its complete materialized H3, metadata, visible body, and selected native attachment. The completed record is measured to a fixed point, including the accounting field itself. No `tokensBody`, `tokensMetadata`, or `tokensActive` field is serialized. 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}
|
|
2189
|
+
- §packet-token-accounting Every row reports one `logTokens` charge: its complete materialized H3, metadata, visible body, and selected native attachment. The completed record is measured to a fixed point, including the accounting field itself. No `tokensBody`, `tokensMetadata`, or `tokensActive` field is serialized. 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}.
|
|
2149
2190
|
|
|
2150
2191
|
### §retrieval-packet-metadata READ/FIND packet metadata
|
|
2151
2192
|
|
|
@@ -2153,33 +2194,41 @@ The packet projects one actionable owner for each retrieval fact:
|
|
|
2153
2194
|
|
|
2154
2195
|
| Result mode | Extent | Result-body evidence | Additional aggregate fact |
|
|
2155
2196
|
|---|---|---|---|
|
|
2156
|
-
| line READ |
|
|
2157
|
-
| exact-coordinate READ |
|
|
2197
|
+
| line READ | `range` in line scopes | none | none |
|
|
2198
|
+
| exact-coordinate READ | `range` in exact text coordinates | none | none |
|
|
2158
2199
|
| READ-shaped materialization notice | none | none | generic body `lines` |
|
|
2159
|
-
| catalog/path FIND |
|
|
2160
|
-
| broad matcher FIND |
|
|
2161
|
-
| exact matcher FIND |
|
|
2162
|
-
| pattern READ ({§read-pattern}) |
|
|
2200
|
+
| catalog/path FIND | `range` in resources | none | none |
|
|
2201
|
+
| broad matcher FIND | `range` in resources | per-resource match-location counts; a resource with exactly one match also carries that match's `locator`/`region` | nonzero complete `matchLocationCount` |
|
|
2202
|
+
| exact matcher FIND | `range` in match locations | each row's locator/region; a regex or glob row also carries `matched`, the matched text | none |
|
|
2203
|
+
| pattern READ ({§read-pattern}) | `range` over the physical lines | the selected lines with their ordinals and anchors | `matcher` and `matched`, the selected line count |
|
|
2163
2204
|
|
|
2164
2205
|
Any row whose statement carried a heading pattern ({§matcher-option}) names it as
|
|
2165
2206
|
`matcher`, and a pattern mutation ({§edit-pattern}, {§kill-pattern},
|
|
2166
2207
|
{§copy-move-pattern}) carries its `matched` count beside its receipt, so a
|
|
2167
2208
|
digest can show what a pattern selected and how much it touched.
|
|
2168
2209
|
|
|
2169
|
-
The
|
|
2170
|
-
|
|
2210
|
+
The packet formats the typed {§range-extent} and {§text-region} facts under
|
|
2211
|
+
{§packet-extent-metadata}; the operation result retains its structured facts.
|
|
2212
|
+
An empty result
|
|
2171
2213
|
set satisfies any well-formed page: zero matches is the answer, a 200 with no items,
|
|
2172
2214
|
never a 416 (#425 F9). Transparent
|
|
2173
2215
|
coordinates let the model determine whether more material exists and choose
|
|
2174
2216
|
its own next request, so packet metadata never prescribes `next`, `complete`,
|
|
2175
2217
|
or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
|
|
2176
2218
|
`matchingPathCount`; line READ likewise omits the rendered-body `lines` count
|
|
2177
|
-
and its internally resolved whole-line region. Exact READ
|
|
2178
|
-
|
|
2179
|
-
repeating it at top level.
|
|
2219
|
+
and its internally resolved whole-line region. Exact READ formats its region
|
|
2220
|
+
as `range`. A failed retrieval's Problem owns its range extension rather than
|
|
2221
|
+
repeating it at top level. `logTokens` weighs the complete rendered record
|
|
2222
|
+
under {§packet-token-accounting};
|
|
2180
2223
|
generic body `lines` remains available on READ-shaped materialization notices
|
|
2181
2224
|
that have no retrieval extent. FIND content weights follow {§log-wire-format};
|
|
2182
|
-
ordinary bounded bodies expose their displayed and complete
|
|
2225
|
+
ordinary bounded bodies expose their displayed and complete extents as `preview`
|
|
2226
|
+
under {§packet-extent-metadata}.
|
|
2227
|
+
|
|
2228
|
+
§read-past-end A line READ whose range starts past the end of nonempty content is
|
|
2229
|
+
answered like an empty FIND page: with no lines and its extent (`none of N lines`), not a 416; a
|
|
2230
|
+
single line past the end, a reversed range, empty content, a command's log row
|
|
2231
|
+
({§log-range-miss-names-stream}) and every write keep their refusal (#759).
|
|
2183
2232
|
|
|
2184
2233
|
### §turn-ops-entry The admitted turn program
|
|
2185
2234
|
|
|
@@ -2189,17 +2238,18 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
|
|
|
2189
2238
|
|
|
2190
2239
|
| Surface | Contract |
|
|
2191
2240
|
|---|---|
|
|
2192
|
-
| Identity | `ops
|
|
2193
|
-
| Source | `ops` is exact admitted `text/vnd.plurnk`; `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a
|
|
2194
|
-
|
|
|
2195
|
-
|
|
|
2241
|
+
| Identity | `ops://<worker>/<loop>/<turn>`, `reasoning://<worker>/<loop>/<turn>`, and `note://<worker>/<loop>/<turn>/<item>` name a worker in the current workspace and its durable coordinates. A note's item is its dispatched NOTE ordinal. The worker authority is required and case-sensitive; userinfo, ports, and queries are invalid. Source identity never depends on the reading worker. `log:///` remains local; READ, FIND and KILL reject log authorities, userinfo, ports and queries with 400, never substitute the caller's log. |
|
|
2242
|
+
| Source | `ops` is exact admitted `text/vnd.plurnk`; `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a worker or turn that does not exist is 404. |
|
|
2243
|
+
| Notes | Each dispatched NOTE stores its exact literal body as an immutable `text/plain` source and returns its worker-qualified address. There may be multiple notes in a turn, from reasoning, content, or another producer. A missing note is 404, not an empty invented note. Sharing its URI uses ordinary SEND; the receiver deliberately READs it. NOTE itself sends no ambient update. |
|
|
2244
|
+
| Retention | One ops source and one reasoning source per turn; one note source per NOTE ordinal. An optional inference-call link records provenance. Source removal follows deletion of its owning turn, never log curation. |
|
|
2245
|
+
| Operations | Ordinary scoped READ, FIND, content search and COPY from any named worker's source within the workspace. FIND accepts authority and path patterns, retaining complete worker-qualified identities in results and folder selectors. READ returns data and never executes it. Sources are read-only for every actor and have no edit hashes. |
|
|
2196
2246
|
| Index | Source text uses the existing derivation, FTS and graph machinery; only its derivation attachment is replaceable. |
|
|
2197
|
-
| FORK | Sources copy with the inherited turns at identical
|
|
2247
|
+
| FORK | Sources copy with the inherited turns at identical loop/turn/item coordinates under the fork's own authority. Bytes and embedded source references are preserved verbatim; an explicit reference still names its original worker. Branch receipt curation is independent; neither branch can rewrite source evidence. |
|
|
2198
2248
|
| Forensics | Digest assistant artifacts read source directly, independently of receipt presence or curation. Original provider responses retain all attempts and opaque fields separately. |
|
|
2199
2249
|
|
|
2200
2250
|
§rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, the canonical model-facing `/attempt` leaf, and the exact latest rejected response. The packet does not duplicate that identity as `kind` metadata. It is born durably body-suppressed and projected visibly only in the informed recovery packet; every other rejected attempt remains forensic-only.
|
|
2201
2251
|
|
|
2202
|
-
- §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. 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`, and `log:///**/attempt` deliberately filter canonical leaves.
|
|
2252
|
+
- §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. 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`, and `log:///**/attempt` 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 the model's operations ({§packet-current-turn} names `L/T`).
|
|
2203
2253
|
- §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. A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless KILL is 400.
|
|
2204
2254
|
- §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. Thus ```` ```KILL (log:///**/READ) <17,-1> ```` may change long READs and no-op on short ones while reporting every selected row in `matched`.
|
|
2205
2255
|
|
|
@@ -2207,7 +2257,8 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
|
|
|
2207
2257
|
|
|
2208
2258
|
| KILL result | Packet receipt |
|
|
2209
2259
|
|---|---|
|
|
2210
|
-
| Successful log-item or line curation
|
|
2260
|
+
| Successful log-item or line curation (200) | Not shown, including the first packet after the operation: the rows that are gone are the receipt. |
|
|
2261
|
+
| A curation that matched nothing (204) | Shown once, in the packet of the very next turn, then retired like any other row. A success and a mismatch are not both silent: the model cannot otherwise tell that its earlier KILL is what emptied the selection (#779). |
|
|
2211
2262
|
| Failed log curation | Visible with its ordinary Problem. |
|
|
2212
2263
|
| Non-log target: file, worker, stream, or other resource | Ordinary scheme-owned receipt. |
|
|
2213
2264
|
|
|
@@ -2257,7 +2308,7 @@ flowchart LR
|
|
|
2257
2308
|
body --> recall["READ log:///…<br/>selects untrimmed content"]
|
|
2258
2309
|
```
|
|
2259
2310
|
|
|
2260
|
-
§edit-receipt-removed-text **A pure deletion's receipt quotes what it removed.** An applied effect that inserted nothing and removed at least one line carries `removedText` — the removed text, first
|
|
2311
|
+
§edit-receipt-removed-text **A pure deletion's receipt quotes what it removed.** An applied effect that inserted nothing and removed at least one line carries `removedText` — the removed text, its first `PLURNK_SERVICE_EDIT_RECEIPT_REMOVED_LINES` lines — projected on the wire as `removed`; an effect that inserted anything carries no such field, its resulting context shows the change.
|
|
2261
2312
|
|
|
2262
2313
|
§edit-receipt-anchored-context **An applied EDIT's resulting context carries anchors.** The bounded resulting context each effect renders (`PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` around and inside the landed region) is rendered exactly as a READ renders — `@xxxxx L:text`, hashed with the resource's READ identity ({§line-anchors}) — so a later operation can cite the landed lines by anchor without a READ. A scheme that supplies no identity keeps the line-numbered form.
|
|
2263
2314
|
|
|
@@ -2273,9 +2324,9 @@ per-operation projection on `rx`; the aggregate remains inside dispatch.
|
|
|
2273
2324
|
| Full `revision` | not projected | SHA-256 identity of the complete landed channel body, retained for forensics. No operation takes a revision; it is neither a lookup nor a compare-and-swap token. |
|
|
2274
2325
|
| `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
|
|
2275
2326
|
| `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. |
|
|
2276
|
-
| `effect.
|
|
2327
|
+
| `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`. |
|
|
2277
2328
|
| `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
|
|
2278
|
-
| `effect.removedText` | `removed` | {§edit-receipt-removed-text}: a pure deletion's removed text, first
|
|
2329
|
+
| `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. |
|
|
2279
2330
|
| `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
|
|
2280
2331
|
| `disposition`, `requested` | `disposition`, `requested` | A reviewer-replaced batch preserves the authored marker while stating that its attributed effect was superseded. |
|
|
2281
2332
|
| `replacement` | `replacement`, `change`, canonical proposal-owner body | The one whole-resource effect actually applied by the reviewer replacement; never duplicated across authored rows. |
|
|
@@ -2283,8 +2334,8 @@ per-operation projection on `rx`; the aggregate remains inside dispatch.
|
|
|
2283
2334
|
§edit-result-receipt-truth **Receipts describe committed state.** Each EDIT
|
|
2284
2335
|
carries its own landed revision, extent, and optional `parseIssues` transition
|
|
2285
2336
|
for its complete source and landed revisions. When the proposal lands
|
|
2286
|
-
unchanged, the row
|
|
2287
|
-
marker
|
|
2337
|
+
unchanged, the row carries its source/result mapping, counts, and context;
|
|
2338
|
+
the authored marker remains in durable evidence. For configured count `C`,
|
|
2288
2339
|
the context contains up to `C` surrounding lines and the first and last `C`
|
|
2289
2340
|
landed lines at the result boundaries. Overlapping windows coalesce; coordinate
|
|
2290
2341
|
jumps expose an omitted middle. A deletion instead shows up to `C` lines on
|
|
@@ -2469,7 +2520,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2469
2520
|
channel derivation under `{§scheme-catalog-parse-issues}`.
|
|
2470
2521
|
|
|
2471
2522
|
§scheme-catalog-aside **Catalog aside.** `aside` is the exact channel
|
|
2472
|
-
derivation's `{§mimetype-summary}`. Prose is clipped to at most
|
|
2523
|
+
derivation's `{§mimetype-summary}`. Prose is clipped to at most `PLURNK_SERVICE_CATALOG_SUMMARY_CHARS` Unicode
|
|
2473
2524
|
code points including a visible terminal ellipsis, so a row stays one line
|
|
2474
2525
|
of orientation; an invocation-form witness — a summary that is one fenced
|
|
2475
2526
|
operation, the shape every tool family's summary takes
|
|
@@ -2484,8 +2535,8 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2484
2535
|
that shape, while deeper first-segment directories collapse to the one-element
|
|
2485
2536
|
group `[{ path: "dir/**", items, weight }]`, where the selector and both aggregates
|
|
2486
2537
|
describe the exact recursive subtree. Scope summaries are navigation
|
|
2487
|
-
metadata, not resources. Markerless FIND returns
|
|
2488
|
-
selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
|
|
2538
|
+
metadata, not resources. Markerless FIND returns the first page
|
|
2539
|
+
({§markerless-first-page}) of positions in the selected unit; `<N,M>` selects an inclusive page and `<1,-1>` explicitly
|
|
2489
2540
|
selects all. `range` reports the unit, complete result total, normalized
|
|
2490
2541
|
request, and returned positions ({§range-extent}). `itemsWeightTotal` weighs the complete matched set while
|
|
2491
2542
|
`returnedItemsWeightTotal` weighs the returned resource page; in exact
|
|
@@ -2507,40 +2558,47 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2507
2558
|
|
|
2508
2559
|
SEND AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, metadata, lineMarker }`.
|
|
2509
2560
|
|
|
2510
|
-
- **Message:** SEND
|
|
2511
|
-
- **
|
|
2561
|
+
- **Message:** SEND delivers to an actor, endpoint or exact message address. Targetless SEND answers observed Open Messages.
|
|
2562
|
+
- **Workflow:** WAIT yields; successful reply delivery and settled work permit completion at the end of the whole program. NOTE retains memory.
|
|
2512
2563
|
|
|
2513
|
-
§
|
|
2564
|
+
§worker-obligations A worker holds its unresolved children and open non-detached
|
|
2565
|
+
streams (`worker_obligations`); `loop_obligations` names them per loop. The
|
|
2566
|
+
packet's Delegation list, WAIT, completion and drain wake settlement use that
|
|
2567
|
+
same durable liveness.
|
|
2514
2568
|
|
|
2515
|
-
§
|
|
2569
|
+
§wait-obligation-matrix **End-of-program resolution.** Execute all admitted operations and settle optimistic work before applying this table. WAIT is an optional yield, not an end-of-program delimiter.
|
|
2516
2570
|
|
|
2517
|
-
|
|
|
2518
|
-
|
|
2519
|
-
|
|
|
2520
|
-
|
|
|
2521
|
-
|
|
|
2522
|
-
|
|
|
2523
|
-
|
|
|
2524
|
-
|
|
|
2525
|
-
|
|
|
2526
|
-
|
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
A
|
|
2533
|
-
|
|
2534
|
-
|
|
2571
|
+
| Condition, in evaluation order | Outcome |
|
|
2572
|
+
|---|---|
|
|
2573
|
+
| Worker or loop already cancelled/terminal | Preserve that result. |
|
|
2574
|
+
| Administrative program | Finish its transaction without adjudicating another model loop's work. |
|
|
2575
|
+
| New unpublished message | Continue; publish it in the next packet. |
|
|
2576
|
+
| Live work and either WAIT or no unanswered messages | Park the same loop; message arrival, child or stream settlement, or stream cadence wakes it. |
|
|
2577
|
+
| WAIT without live work | Continue; never invent a future wake. |
|
|
2578
|
+
| Unanswered messages | Continue. |
|
|
2579
|
+
| Unobserved operation results, failures, child results or stream conclusions | Continue; the next packet presents them. |
|
|
2580
|
+
| No outstanding messages, live work or unobserved results | Conclude successfully, without a synthetic operation. |
|
|
2581
|
+
|
|
2582
|
+
An empty emission is handled by {§empty-turn}, not this completion rule. Ordinary strikes,
|
|
2583
|
+
cycles and execution limits remain independent. NOTE and successful KILL do not themselves
|
|
2584
|
+
require another observation turn. Failed KILL and every other operational result do.
|
|
2585
|
+
|
|
2586
|
+
§loop-response-messages **A response is a recorded delivery.** A successful SEND reply records
|
|
2587
|
+
the exact message addresses it answers. All replies remain independently recoverable in
|
|
2588
|
+
message history, in execution order, regardless of producer. An actor-addressed SEND that
|
|
2589
|
+
does not answer a message, WAIT, NOTE, asides, inherited rows and ambient observations are
|
|
2590
|
+
not replies. Curation cannot retract delivery; cancellation or later failure retains it.
|
|
2591
|
+
Attachment-only replies retain their attachments without replacing earlier text. A child
|
|
2592
|
+
conclusion carries its execution outcome under {§send-undelivered-child-term}, not a second delivery.
|
|
2535
2593
|
|
|
2536
2594
|
§loop-terminal-authorship **Terminal authorship is explicit when external.**
|
|
2537
2595
|
|
|
2538
2596
|
| `terminated_by` | Meaning | Presentation |
|
|
2539
2597
|
|---|---|---|
|
|
2540
2598
|
| `NULL` | The model's own terminal or an engine verdict whose exact result already carries the story. | No authorship marker. |
|
|
2541
|
-
| `cancel` |
|
|
2599
|
+
| `cancel` | The structured scope was explicitly cancelled, through the client or worker KILL ({§methods-loop-cancel}). | COLLECT and the termination delta prepend a cancellation marker to the exact Problem's presentation, so cancellation cannot masquerade as a deliverable. The model's prior log rows remain untouched. |
|
|
2542
2600
|
|
|
2543
|
-
The engine's failure terminals — **500** (strike threshold) and **508** (cycle), {§engine-rails} — are never the model's to pick; they are the engine ruling the loop failed. The
|
|
2601
|
+
The engine's failure terminals — **500** (strike threshold) and **508** (cycle), {§engine-rails} — are never the model's to pick; they are the engine ruling the loop failed. The model answers, waits or cancels its scope; the engine derives the lifecycle outcome from that state.
|
|
2544
2602
|
|
|
2545
2603
|
Disposition outcomes follow {§wait-obligation-matrix},
|
|
2546
2604
|
{§completion-joins-live-work}, and {§completion-defers-to-results}. Strike
|
|
@@ -2549,29 +2607,44 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2549
2607
|
|
|
2550
2608
|
- §send-target-recipient **A SEND target is a recipient.** A model's directed SEND
|
|
2551
2609
|
addresses a worker (```` ```SEND (worker://<name>) ````), an outbound agent (`a2a://`),
|
|
2552
|
-
or a scheme that implements SEND (an `https://` POST). A SEND to a scheme the model may not write (the
|
|
2610
|
+
or a scheme that implements SEND (an `https://` POST). A SEND to a scheme the model may not write (the
|
|
2553
2611
|
log) is refused 400 `send-target-not-a-recipient`, never the unrelated writer
|
|
2554
2612
|
rule. The detail states only that the addressed scheme is not a recipient;
|
|
2555
2613
|
neutral recovery distinguishes targetless replies from directed SEND without
|
|
2556
2614
|
guessing which one was intended. A scheme that does not implement SEND
|
|
2557
2615
|
answers its ordinary factual 501 without grafting a guessed recovery onto it.
|
|
2558
|
-
- §send-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2616
|
+
- §send-response-receipt **A reply records exactly which messages it answers.** A successful
|
|
2617
|
+
reply carries `answers`, the immutable message addresses it answered, not recipient actors. Targetless SEND
|
|
2618
|
+
answers this loop's published, unanswered messages, oldest first. SEND to an exact message
|
|
2619
|
+
address answers only that message; SEND to an actor endpoint remains ordinary communication
|
|
2620
|
+
and answers no assignment implicitly. An unpublished arrival cannot be answered by the
|
|
2621
|
+
targetless shorthand. Failed delivery answers nothing. Reply accounting reads executed
|
|
2622
|
+
delivery evidence, never log visibility or the mere existence of a later SEND.
|
|
2623
|
+
- §prose-conclusion **Prose is the answer.** An admitted response whose content has no
|
|
2624
|
+
operation, attempts none ({§operation-attempt}), was not cut at the output
|
|
2625
|
+
allowance, is not empty, says something outside its quotations ({§quotation}: a reply that is
|
|
2626
|
+
nothing but quoted material is a misfenced program) and holds no misplaced operation fence
|
|
2627
|
+
(`must start its line to run`) is the model's answer (operator, 2026-09-18, #761): the engine
|
|
2628
|
+
admits it as a targetless SEND whose body is the trimmed content, positioned on line 1. It
|
|
2629
|
+
answers the open messages, reaches clients and a parent exactly as a SEND does, and meets the
|
|
2630
|
+
completion barrier as a SEND does ({§completion-joins-live-work},
|
|
2631
|
+
{§completion-defers-to-results}). Reasoning NOTEs ride with it. The model is taught
|
|
2632
|
+
"respond without performing any OPs" and is never taught the SEND. A reply wrapped whole in one
|
|
2633
|
+
`markdown` or `md` fence is delivered as that fence's content ({§quotation}). Its row is stored as the
|
|
2634
|
+
SEND that delivers it (reply accounting, delivery and clients read SEND rows) but carries
|
|
2635
|
+
`attrs.answer = "prose"` and `resource: ops://<worker>/<loop>`, and is addressed and rendered
|
|
2636
|
+
under the leaf `answer` (`log:///1/2/2/answer`), never as a SEND the model did not write.
|
|
2637
|
+
- §loop-answer **A loop's address is what it said.** READ `ops://<worker>/<loop>` resolves to
|
|
2638
|
+
the latest reply the loop gave to the message that started it: a prose conclusion's text or
|
|
2639
|
+
the body of a SEND that targeted that message. A running loop without one is 425; a loop that
|
|
2640
|
+
ended without one is its terminal problem (404 when it ended 2xx). `ops://<worker>/<loop>/<turn>`
|
|
2641
|
+
remains that turn's emission. A concluded child's `loop_termination` row to its parent carries
|
|
2642
|
+
`answer: ops://<child>/<loop>` beside its status. Witness: `test/intg/loop-answer.test.ts`.
|
|
2643
|
+
- §empty-turn **A response with no operation that is not an answer is a turn, not a retry.**
|
|
2644
|
+
When the parser finds no operation and no other hard error, and the response is not an
|
|
2645
|
+
answer under {§prose-conclusion} — an operation attempt, prose cut at the output allowance,
|
|
2646
|
+
or an empty response — it is admitted as an empty turn (operator, 2026-09-12): its text and
|
|
2647
|
+
reasoning are stored like any turn's (`ops://<worker>/`, `reasoning://<worker>/`), the model's own message
|
|
2575
2648
|
stays in the next packet's history, that packet carries one `turn_no_operations` notice and
|
|
2576
2649
|
any {§bare-heading-advisory} notices, the turn continues at 102, and the strike rail counts
|
|
2577
2650
|
one progress-contract strike, so a model that only talks strikes out at the ordinary
|
|
@@ -2581,8 +2654,9 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2581
2654
|
EDIT or KILL carrying `[metadata]` for a scheme whose manifest takes none runs without it,
|
|
2582
2655
|
and the packet carries one `metadata_ignored` notice naming the scheme (operator,
|
|
2583
2656
|
2026-09-12: a gentle warning, never a refusal). The `pattern` option never reaches this
|
|
2584
|
-
path; it is lifted into the matcher at parse time ({§matcher-option}).
|
|
2585
|
-
own their
|
|
2657
|
+
path; it is lifted into the matcher at parse time ({§matcher-option}). SEND recipients,
|
|
2658
|
+
executions, WORK and FORK own their input and receive it whole ({§send-resource-attachments},
|
|
2659
|
+
{§env-option}); a key they do not take is their own 400.
|
|
2586
2660
|
- §send-looks-like-operation **A reply never begins with an operation heading.** When a model's
|
|
2587
2661
|
untargeted SEND has, as its first non-blank line, a line that parses alone as one clean
|
|
2588
2662
|
heading naming an operation this worker could perform — a Plurnk operation, or a registered
|
|
@@ -2600,75 +2674,29 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2600
2674
|
as a literal — on a reply's first line that is prose. Origin: the 2026-09-11 dogfood,
|
|
2601
2675
|
where four operations on the line after their fences were delivered as four 200 replies and the
|
|
2602
2676
|
loop then parked fifteen minutes on receipts that could never arrive.
|
|
2603
|
-
- §send-idle-turn **
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
that says done while its own work runs — an open stream, a live child worker —
|
|
2625
|
-
is asking to leave with that work unfinished, and the two exits structured
|
|
2626
|
-
concurrency allows are join and cancel. The `completed` inventory takes the
|
|
2627
|
-
join: the TASK answers 202, the loop parks untimed on the live obligation
|
|
2628
|
-
exactly as a `waiting` inventory would, and the settle edge wakes it with what
|
|
2629
|
-
concluded in the packet; the model's next TASK decides with that result in
|
|
2630
|
-
front of it, so nothing completes on an answer written before the work
|
|
2631
|
-
finished. The `failed` inventory takes the cancel. The join's `detail` is read
|
|
2632
|
-
when the wake lands and speaks from that moment; its `attrs` carry `waiting`
|
|
2633
|
-
and the pending kinds. It is never a strike: the review contract has no
|
|
2634
|
-
violation left, and the rail's remaining sources are hard results, cycles and
|
|
2635
|
-
empty turns ({§engine-rails}). A stream the model meant to leave running parks
|
|
2636
|
-
the loop until it ends, as a model-written `waiting` would; KILL before the
|
|
2637
|
-
claim is the way to leave it running (operator, 2026-09-14: "politely
|
|
2638
|
-
converting completed into waiting when there are streams or workers in-flight").
|
|
2639
|
-
- §completion-defers-to-results **Settled results defer a terminal; they never strike.**
|
|
2640
|
-
A completion or abandonment claimed over results the model could not yet have
|
|
2641
|
-
seen — this turn's failed operations, this turn's receipts (successful execution
|
|
2642
|
-
results included, not only READ/FIND), a concluded stream's result, a terminated
|
|
2643
|
-
child's result — is deferred: the TASK answers 102 with no Problem and no strike,
|
|
2644
|
-
the loop continues, and the next packet carries what deferred it. The engine
|
|
2645
|
-
owns every observe edge, so such a claim is early in the observation order, not
|
|
2646
|
-
false about the world. After observing the results, the model can continue work,
|
|
2647
|
-
revise its response, or conclude with TASK alone while retaining its last SEND
|
|
2648
|
-
({§loop-response-messages}, {§send-undelivered-child-term}).
|
|
2649
|
-
The deferral's `detail` is read one packet later, beside the results it names,
|
|
2650
|
-
and speaks from that moment: a receipts-only deferral names the distinct
|
|
2651
|
-
blocking operations in execution order using their model-facing log names
|
|
2652
|
-
({§log-coordinate-hierarchy}), plus `stream completion` for undelivered terminal
|
|
2653
|
-
stream results; a results deferral names the landed kinds; a failure deferral
|
|
2654
|
-
counts the failures. These deferrals and the live-work join receipt share the
|
|
2655
|
-
conditional guidance: `If your final response has already been sent and these
|
|
2656
|
-
results require no further work or response revision, submit only TASK.` This
|
|
2657
|
-
avoids repeating a delivered response, not delivering one; newly arrived prompts
|
|
2658
|
-
retain their distinct feedback under {§completion-defers-to-prompts}. Their
|
|
2659
|
-
`attrs` carry the pending kinds or the failure count. The rail's streak never
|
|
2660
|
-
enters the decision: a deferral is admissible at any streak, and a loop that
|
|
2661
|
-
keeps issuing operations before each claim pays one packet per claim, never a
|
|
2662
|
-
strike, until the cycle detector rules its repetition ({§engine-cycle-evidence}).
|
|
2663
|
-
Operator, 2026-09-14: the barrier is safety and the rail is liveness; fail is
|
|
2664
|
-
completed with a frowny face and crosses the same barrier.
|
|
2665
|
-
- §send-administrative-terminal **An administrative terminal closes its own
|
|
2666
|
-
transaction.** A client, plugin, or `_plurnk` operation program runs in its
|
|
2667
|
-
own administrative loop. Its all-`completed` TASK concludes exactly that loop;
|
|
2668
|
-
it neither claims nor consumes the Worker's model-visible pending set. Model
|
|
2669
|
-
completion rails therefore apply only to a model-authored disposition.
|
|
2677
|
+
- §send-idle-turn **NOTE is memory, not a yield.** NOTE does not imply parking.
|
|
2678
|
+
With unanswered messages it continues; after replies and observation it may be the only
|
|
2679
|
+
operation in the program that concludes. Repetition remains subject to {§engine-cycle-evidence}.
|
|
2680
|
+
- §send-premature-terminate **Completion follows observation.** Every fired operation except
|
|
2681
|
+
SEND, NOTE, WAIT and successful KILL requires a subsequent packet. This barrier uses durable
|
|
2682
|
+
executed evidence, not curated rows. Fast completion, an empty result or curation cannot
|
|
2683
|
+
erase it. New arrivals are protected by {§completion-defers-to-messages}; no terminal verb
|
|
2684
|
+
or prose overrides this rule.
|
|
2685
|
+
- §completion-joins-live-work **Answered work still joins its live obligations.** Once all
|
|
2686
|
+
observed messages are answered, live children, non-detached streams park the same loop
|
|
2687
|
+
as WAIT does. Each ordinary wake presents the newly settled state; completion is evaluated
|
|
2688
|
+
again after the next program. KILL owns cancellation; a reply never cancels work implicitly.
|
|
2689
|
+
- §completion-defers-to-results **Results keep the loop running until observed.** Same-turn
|
|
2690
|
+
operations and failures, plus undelivered child or stream conclusions, require the next
|
|
2691
|
+
packet. This is ordinary continuation, not a strike or a synthetic refusal receipt.
|
|
2692
|
+
The already-delivered answer remains delivered. If observation warrants no further work
|
|
2693
|
+
or revision, a NOTE or curation-only program can conclude without repeating the answer.
|
|
2694
|
+
- §send-administrative-terminal **Administrative programs close their own transaction.**
|
|
2695
|
+
Their caller closes the administrative loop after execution; no terminal operation is
|
|
2696
|
+
manufactured. Initialization runs in the model loop without concluding it.
|
|
2697
|
+
|
|
2670
2698
|
- §send-undelivered-child-term **Completion is not delivery.** A result becomes
|
|
2671
|
-
observed only after crossing a packet boundary.
|
|
2699
|
+
observed only after crossing a packet boundary. WAIT parks only on
|
|
2672
2700
|
live obligations. If work has completed but is unobserved, it continues
|
|
2673
2701
|
directly to the next packet because the wake edge has already fired. A genuinely
|
|
2674
2702
|
empty wait also continues under {§wait-obligation-matrix}, never concluding implicitly.
|
|
@@ -2725,6 +2753,15 @@ batch of 2026-08-29 showed the absolute `cwd` copied back into the target slot a
|
|
|
2725
2753
|
family — and neither a command nor a working directory is ever a target. The default
|
|
2726
2754
|
shell is written as its own fence, ```` ```sh ````; no runtime-less form exists.
|
|
2727
2755
|
|
|
2756
|
+
§exec-target-near-miss Two target near-misses have one reading each and are read
|
|
2757
|
+
without a diagnostic (#758). A directory target is never a program: with a body
|
|
2758
|
+
and no explicit `cwd`, the body runs with that directory as its working
|
|
2759
|
+
directory; without a body it is still `target-not-a-program`. A target in the
|
|
2760
|
+
executor's own scheme whose path can never be a stream (`sh:///daemon-env`;
|
|
2761
|
+
streams are eight hex digits) is the writer's name for the run: with a body, the
|
|
2762
|
+
body runs as if targetless; without one, the source read refuses as before. A
|
|
2763
|
+
real stream id is always the program source.
|
|
2764
|
+
|
|
2728
2765
|
§exec-tool-fall-through **A tool run as a shell command is named at the failure
|
|
2729
2766
|
site.** A bare shell command whose program is the name of a tool published by
|
|
2730
2767
|
another enabled runtime (`brave_web_search {…}` under the default shell) exits
|
|
@@ -2820,45 +2857,30 @@ Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor
|
|
|
2820
2857
|
**Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** An execution
|
|
2821
2858
|
repurposes the line-marker slot as `<timeout, poll>` in **minutes** — agentic
|
|
2822
2859
|
latencies make a sub-minute horizon a trap — converted at the parse boundary to the
|
|
2823
|
-
catalog's internal `stream.seconds`.
|
|
2824
|
-
|
|
2825
|
-
§exec-
|
|
2826
|
-
|
|
2827
|
-
`
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
the worker's
|
|
2835
|
-
without opening a loop.
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
(`PLURNK_SERVICE_EXEC_POLL_SEC` and `PLURNK_SERVICE_EXEC_POLL_TURNS`); explicit
|
|
2848
|
-
`<,P>` wins and `<,0>` disables polling for that stream. Open subscriptions
|
|
2849
|
-
aggregate into each wait's inherited observation policy as follows; an explicit
|
|
2850
|
-
TASK poll interval overrides this aggregation ({§worker-wait-timing}):
|
|
2851
|
-
|
|
2852
|
-
| Open-stream policies | Worker timer |
|
|
2853
|
-
| --------------------------------------------- | ----------------------------- |
|
|
2854
|
-
| Any positive `P` | The smallest positive cadence |
|
|
2855
|
-
| No positive `P`, at least one omitted `P` | Exponential backoff |
|
|
2856
|
-
| Every `P` is explicit zero | Disabled |
|
|
2857
|
-
|
|
2858
|
-
Child-only joins never use this timer: child settlement is their durable wake
|
|
2859
|
-
edge. Stream closure remains a wake edge under every poll policy.
|
|
2860
|
-
|
|
2861
|
-
§exec-host-proposes **Effect-gating.** Each executor declares an `effect` (`pure` | `read` | `host`); the service maps it to policy (`EffectPolicy`). A `host` runtime (subprocess; file-backed sqlite) proposes under {§proposal}. 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}).
|
|
2860
|
+
catalog's internal `stream.seconds`. WAIT takes no timing; future wakes belong to the schedule family.
|
|
2861
|
+
|
|
2862
|
+
§exec-lifetime **How long a spawn may live is the fence's metadata, one field.**
|
|
2863
|
+
`[{"lifetime": …}]` takes a duration (`30s`, `30m`, `2h`), or one of three words;
|
|
2864
|
+
absent is `loop`. An execution takes no scope: a numeric coordinate on an
|
|
2865
|
+
executor target is refused `scope-unsupported` (400), naming the field.
|
|
2866
|
+
|
|
2867
|
+
| `lifetime` | The spawn |
|
|
2868
|
+
| ------------ | --------- |
|
|
2869
|
+
| 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**, distinct from a deliberate kill (499) or a clean exit (200). |
|
|
2870
|
+
| `loop` (absent) | Loop-life bounded: reaped on every loop terminal except 202, the background-stream behavior. |
|
|
2871
|
+
| `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}). |
|
|
2872
|
+
| `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. |
|
|
2873
|
+
|
|
2874
|
+
**Cadence is the daemon's, never the model's.** While a loop is parked on an open
|
|
2875
|
+
stream the daemon wakes it on the worker's exponential backoff
|
|
2876
|
+
(`PLURNK_SERVICE_EXEC_POLL_SEC`, `PLURNK_SERVICE_EXEC_POLL_TURNS`, floored by
|
|
2877
|
+
`PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`) to inspect progress; it does nothing while
|
|
2878
|
+
the loop is active, because ambient stream deltas already surface progress.
|
|
2879
|
+
Closure is a wake edge regardless. Child-only joins never use this timer: child
|
|
2880
|
+
settlement is their durable wake edge. A recurring check on the calendar is a
|
|
2881
|
+
schedule targeting yourself ({§schedule-delivery}), not a loop that polls.
|
|
2882
|
+
|
|
2883
|
+
§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}).
|
|
2862
2884
|
|
|
2863
2885
|
§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. There is no entry-owner Worker, synthetic commons actor, caller-relative alias, or per-Worker access grant. Core binds one canonical coordinate through {§entry-address-resolution} for every operation and consumer. Producer and subscriber Worker ids describe causal activity, not ownership.
|
|
2864
2886
|
|
|
@@ -2908,15 +2930,14 @@ inventory; allocation never rewrites the submitted operation's target.
|
|
|
2908
2930
|
|
|
2909
2931
|
§exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of newly publishable stream content each turn, {§exec-stream}), never a same-turn receipt.
|
|
2910
2932
|
|
|
2911
|
-
§effect-policy-tunable **Effect admission is
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
loudly rather than degrading admission.
|
|
2933
|
+
§effect-policy-tunable **Effect admission is one knob per effect.**
|
|
2934
|
+
`PLURNK_SERVICE_EFFECT_HOST`, `PLURNK_SERVICE_EFFECT_READ` and
|
|
2935
|
+
`PLURNK_SERVICE_EFFECT_PURE` each say `propose` or `auto`, and together they are
|
|
2936
|
+
the whole map: no effect's admission is held in code, so a deployment that
|
|
2937
|
+
proposes even reads says so in one place an operator can read. An invalid value
|
|
2938
|
+
fails daemon boot by the knob's name rather than degrading admission.
|
|
2918
2939
|
|
|
2919
|
-
After all non-
|
|
2940
|
+
After all non-WAIT operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the execution streams it started, then resolves the whole program against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before completion, not sibling-operation serialization: dependent executions remain separate observed turns.
|
|
2920
2941
|
|
|
2921
2942
|
§exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*, in
|
|
2922
2943
|
two states and no others:
|
|
@@ -2924,7 +2945,16 @@ two states and no others:
|
|
|
2924
2945
|
| state | what the model receives |
|
|
2925
2946
|
|---|---|
|
|
2926
2947
|
| active | nothing in the Log. The `## Delegation` stream pointer names the stream with each channel's size and its growth since the last packet ({§child-orientation}); the model READs any range it wants, and every READ of a stream channel carries `terminal: false` while it runs and `terminal: true` once it has concluded, so an empty page is never mistaken for a finished command that printed nothing (operator, 2026-09-13). |
|
|
2927
|
-
| terminal | ONE `origin=_plurnk` READ at the execution's channel address, born visible, that is exactly a markerless READ of the channel — its bounded first page ({§read-selection-projection}, the whole channel when it fits, the channel's own mimetype), the `range` or `region`, terminal status and Problem, `terminal: true`, any producer-supplied integer `exitCode
|
|
2948
|
+
| terminal | ONE `origin=_plurnk` READ at the execution's channel address, born visible, that is exactly a markerless READ of the channel — its bounded first page ({§read-selection-projection}, the whole channel when it fits, the channel's own mimetype), the `range` or `region`, terminal status and Problem, `terminal: true`, and any producer-supplied integer `exitCode`. The packet identifies the read resource with `path`, exactly as an explicit READ does ({§log-address-metadata}). |
|
|
2949
|
+
|
|
2950
|
+
§stream-observation-result **One liveness fact.** The durable READ result owns
|
|
2951
|
+
`terminal`, derived from its selected channel's state, for explicit and automatic
|
|
2952
|
+
observations alike, independently of mimetype: `active` gives false, `closed` or
|
|
2953
|
+
`errored` gives true, and `static` has no streaming liveness field. Packet
|
|
2954
|
+
projection preserves that Boolean and any included
|
|
2955
|
+
integer `exitCode`, even for an empty body. An automatic observation's atomic
|
|
2956
|
+
publication transition consumes the same result flag; private log attributes
|
|
2957
|
+
retain only the publication offset, not a second liveness value.
|
|
2928
2958
|
|
|
2929
2959
|
§exec-concurrency **Bounded admission per workspace (#389).** At most
|
|
2930
2960
|
`PLURNK_SERVICE_EXEC_CONCURRENCY` executions run at once in one workspace (shipped `12`;
|
|
@@ -2974,19 +3004,40 @@ remains pending until every selected channel's terminal READ crosses the next
|
|
|
2974
3004
|
packet boundary. The execution row separately records the authored invocation.
|
|
2975
3005
|
|
|
2976
3006
|
```` ```KILL (<runtime>:///<eight-hex-id>) ```` cancels an active subprocess via
|
|
2977
|
-
the subscription registry's stored controller. A terminal stream is immutable
|
|
2978
|
-
|
|
2979
|
-
|
|
3007
|
+
the subscription registry's stored controller. A terminal stream is immutable,
|
|
3008
|
+
and KILL of one is satisfied rather than refused: it returns 200 carrying the
|
|
3009
|
+
recorded `terminalStatus` (499 when it was already killed); an unknown address
|
|
3010
|
+
returns 404 (#757).
|
|
2980
3011
|
The runtime scheme participates in the durable lookup; a completed `sh:///`
|
|
2981
3012
|
stream cannot fall through an internal `exec`-only query. {§stream-control}
|
|
2982
3013
|
|
|
3014
|
+
§workspace-env **Workspace environment.** The `env` family has workspace defaults and
|
|
3015
|
+
worker overrides. Its six verbs accept `scope: "workspace" | "worker"`; model calls
|
|
3016
|
+
default to `worker`. Client actions bind the scope in `workspace.env.*` or
|
|
3017
|
+
`worker.env.*`. An explicit scope must agree with that action's context.
|
|
3018
|
+
|
|
3019
|
+
| Consumer | Composition, later layers win |
|
|
3020
|
+
|---|---|
|
|
3021
|
+
| Worker command | Admitted ambient environment → workspace entries → worker entries → invocation `env` |
|
|
3022
|
+
| Shared capability process | Admitted ambient environment → workspace entries → explicit capability launch options |
|
|
3023
|
+
|
|
3024
|
+
Each layer uses the same value and masking rules. A worker's list includes workspace
|
|
3025
|
+
defaults by reference with `origin: "workspace"`; worker overrides and masks remain
|
|
3026
|
+
worker-owned. Enabling an inherited entry clears this layer's mask, not a mask in a
|
|
3027
|
+
lower layer; an explicit local value can override that lower layer. A mask follows
|
|
3028
|
+
the name even when its lower-layer origin changes. Removing an override reveals the lower entry disabled, as for a service
|
|
3029
|
+
baseline. Forking copies only worker state, not the workspace defaults. Workspace edits
|
|
3030
|
+
affect subsequent launches, not existing processes or other workspaces. A shared
|
|
3031
|
+
capability never acquires an invoking worker's overrides or ownership.
|
|
3032
|
+
|
|
2983
3033
|
§exec-env-scoped **Scoped environment.** An execution subprocess receives a composed
|
|
2984
3034
|
environment, never the host's. Two mechanisms apply in order, and they are different kinds
|
|
2985
3035
|
of thing. First the **ambient policy**, a ceiling: `PLURNK_SERVICE_EXEC_ENV_INHERIT` names
|
|
2986
3036
|
what the host's environment may contribute at all and `_EXCLUDE` narrows that, both taking
|
|
2987
3037
|
exact names or one trailing-`*` prefix glob, both ordinary operator knobs under
|
|
2988
3038
|
{§operator-config-env-defaults}. A worker document or a heading modifier narrows the ceiling
|
|
2989
|
-
further; nothing downstream widens
|
|
3039
|
+
further; nothing downstream widens ambient admission. Explicit entries may supply their
|
|
3040
|
+
own non-reserved values. Workspace defaults precede the Worker's `env` state
|
|
2990
3041
|
({§env-functionality}), read at the spawn: an enabled worker entry sets its own value, a disabled
|
|
2991
3042
|
entry of either origin withholds the name, and what `list` projects is what the command
|
|
2992
3043
|
receives. Then the **invariant**, which is not a knob:
|
|
@@ -3006,14 +3057,16 @@ nothing ambient — the allowlist is declared in `.env.defaults`, so an empty on
|
|
|
3006
3057
|
policy rather than an unconfigured install.
|
|
3007
3058
|
|
|
3008
3059
|
The full composition for one spawn, nearest setter winning for defaults and ceilings immune,
|
|
3009
|
-
is package floors → operator cascade → ambient policy → worker
|
|
3060
|
+
is package floors → operator cascade → ambient policy → workspace entries → worker entries → the op's modifier →
|
|
3010
3061
|
body prefixes.
|
|
3011
3062
|
|
|
3012
3063
|
- §env-option **The op's environment.** `env` is the service's key in the heading's `[metadata]`
|
|
3013
3064
|
({§scheme-metadata-modifier}): `[{"env": {"NAME": "value"}}]`, an object of string values.
|
|
3014
3065
|
On an executor fence it is that process's environment over the Worker's own
|
|
3015
3066
|
({§env-functionality}) — the layer nearest the spawn, never entering the registry; a runtime
|
|
3016
|
-
that runs in-process
|
|
3067
|
+
that runs in-process has no process environment to change. A capability manager may
|
|
3068
|
+
retain explicit launch overrides when adding a process-backed definition; it never
|
|
3069
|
+
persists the composed ambient environment. On
|
|
3017
3070
|
WORK and FORK it is the child's starting environment: after the copy the child inherits
|
|
3018
3071
|
({§functionality-scope}), each name lands as the child's own entry through the family's `add`,
|
|
3019
3072
|
so a parent hands down its registry and overrides specific names for one child in one heading.
|
|
@@ -3022,7 +3075,7 @@ body prefixes.
|
|
|
3022
3075
|
key WORK or FORK does not take is refused the same way. The durable row redacts the block
|
|
3023
3076
|
wholesale ({§log-sensitive-request-evidence}); the spawn's record names each such value's
|
|
3024
3077
|
provenance as the modifier's.
|
|
3025
|
-
- §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits an executor fence followed by
|
|
3078
|
+
- §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits an executor fence, optionally followed by WAIT; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
|
|
3026
3079
|
- §exec-entry-sink **The entry() sink** implements {§executor-entry-sink} over ordinary scheme-owned entries. Core owns allocation, materialization, and persistence; executors receive only the returned resource address.
|
|
3027
3080
|
|
|
3028
3081
|
| Input / effect | Consumer behavior |
|
|
@@ -3045,7 +3098,7 @@ body prefixes.
|
|
|
3045
3098
|
|
|
3046
3099
|
- **Client disposition** ({§methods-proposal-resolve}) — a client interface delivers accept, reject, or cancel; AG-UI uses standard resume entries ({§agui-proposal-resolve}).
|
|
3047
3100
|
- **Loop disposition** ({§proposal-disposition}) — core applies the exact automatic accept/reject before observational subscribers run; automatic policy is not an event listener or client fallback.
|
|
3048
|
-
- §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait.
|
|
3101
|
+
- §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait. Indefinite is with respect to the clock alone: the wait ends with its loop. A loop whose signal aborts — its own timeout, `loop.cancel`, worker `KILL` — settles every proposal it is holding through {§proposal-cancel-aborts}, carrying the abort's reason as the outcome, because a cancelled loop is not a loop awaiting a decision.
|
|
3049
3102
|
|
|
3050
3103
|
**The decision drives a one-way state transition** on `log_entries.state` (resolution is idempotent — `WHERE state='proposed'`, so a second resolution 404s):
|
|
3051
3104
|
|
|
@@ -3055,7 +3108,7 @@ body prefixes.
|
|
|
3055
3108
|
| §proposal-reject-fails reject | `failed` | 400 | `rejected` | none — the action did not occur. |
|
|
3056
3109
|
| §proposal-cancel-aborts cancel | `cancelled` | 499 | `loop_aborted` | none — the loop is abandoning. |
|
|
3057
3110
|
|
|
3058
|
-
§proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it
|
|
3111
|
+
§proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it rides the result as the forensic `outcome` field; a **non-accept** is a Problem that carries the same `outcome` field (`write_failed` / `rejected` / `timeout` — one word) and names it in its detail, because "the action didn't occur" without the mechanical why leaves the model acting on a phantom success (the fan-out dead-park: an ENOENT apply rendered as a mute 400). A settlement the **harness itself** decided — nobody attending, no answer before a deadline, a loop or daemon ending while the proposal waited — also states that condition and an exit in its detail and `recovery`, because a reviewer's outcome is a reviewer's word but these have no author present to explain them; the one-word token stays as the forensic `outcome` either way.
|
|
3059
3112
|
|
|
3060
3113
|
§proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from both packet materialization and `log/entry`; it surfaces exactly once after resolution, carrying its terminal status — models and clients see outcomes, never pending proposals.
|
|
3061
3114
|
|
|
@@ -3094,10 +3147,12 @@ issues; the same request remains pending and answerable. Cancellation requires n
|
|
|
3094
3147
|
payload. Owner abort deletes the row and rejects the
|
|
3095
3148
|
waiter with that owner's cancellation reason. An executor's waiter follows its
|
|
3096
3149
|
execution signal, including KILL and deadline, not just its enclosing loop.
|
|
3150
|
+
Scheme and executor interaction requests may supply a narrower signal; Core
|
|
3151
|
+
composes it with the existing owner signal before registering the same waiter.
|
|
3097
3152
|
Reconnect discovery intersects durable rows with live waiters; restart
|
|
3098
3153
|
removes ownerless rows without fabricating cancellation, payload, or replay.
|
|
3099
3154
|
|
|
3100
|
-
###
|
|
3155
|
+
### Loop disposition and client YOLO
|
|
3101
3156
|
|
|
3102
3157
|
Side-effecting operations propose ({§exec}) and pause dispatch at 202 for an
|
|
3103
3158
|
authority decision ({§engine-rails}, {§methods}). Automatic acceptance has two
|
|
@@ -3116,11 +3171,76 @@ only after authority crosses the client boundary.
|
|
|
3116
3171
|
|
|
3117
3172
|
### §proposal-disposition Settlement authority and precedence
|
|
3118
3173
|
|
|
3174
|
+
§loop-attendance **A loop says whether anyone is attending, and a wait nobody could end is
|
|
3175
|
+
never taken.** `LoopPolicy.attended` is the whole of it: `true` says an interactive partner is
|
|
3176
|
+
present, `false` declares an unattended loop. It is one field of the loop's complete policy, so
|
|
3177
|
+
its creator states it or leaves it to the panel ({§loop-policy-composition}); the client's
|
|
3178
|
+
`--auto` is exactly the statement `attended: false`. A fresh delegated loop inherits it with the
|
|
3179
|
+
rest of the policy ({§worker-delegation-inherits-policy}), so a child of a headless run is
|
|
3180
|
+
headless too.
|
|
3181
|
+
|
|
3182
|
+
Unattended, three things follow and nothing else does:
|
|
3183
|
+
|
|
3184
|
+
- **A proposal is never held for review.** `{ proposals: "review", attended: false }` is not a
|
|
3185
|
+
`LoopPolicy`: the schema refuses the pair, so no loop can persist it. The panel cannot produce
|
|
3186
|
+
it, because attendance picks which disposition knob answers. Only a creator's own statement
|
|
3187
|
+
can ask for it, and that is refused **400 `loop-policy-invalid`** naming the way out.
|
|
3188
|
+
- **No interactive partner is offered.** `ClientInteractions.request` refuses **501
|
|
3189
|
+
`loop-unattended`** instead of writing the request down and waiting. Every wiring funnels
|
|
3190
|
+
through that one request — the `question` runtime ({§question-tool}), the execution input
|
|
3191
|
+
bridge, the scheme interaction caps, and MCP elicitation — so one refusal covers them all. The
|
|
3192
|
+
`question` runtime's effect is `read`, so it is never proposal-gated and a disposition does
|
|
3193
|
+
nothing for it. The refusal is the asking executor's **own result**, never a thrown contract
|
|
3194
|
+
violation: the model has to read why it cannot ask.
|
|
3195
|
+
|
|
3196
|
+
Dispatch refuses it first, at the **loop ring** of the capability cascade: an unattended loop's
|
|
3197
|
+
own layer denies the `interact` access class ({§worker-tool-admission}), and that 403 names the
|
|
3198
|
+
ring, the reason and the recovery — a subtracted tool must say why it is gone and what to do
|
|
3199
|
+
instead. Every other ring is operator configuration and speaks for itself; the loop ring is the
|
|
3200
|
+
one the model can act on. The 501 at the interaction itself is the backstop for the paths that
|
|
3201
|
+
do not cross dispatch (MCP elicitation raised inside a tool call, the execution-input bridge).
|
|
3202
|
+
The ring reaches dispatch but not the reserved tree's listing, which is one artifact per
|
|
3203
|
+
workspace: an unattended model still sees the question document and learns at dispatch that it
|
|
3204
|
+
is refused (#770).
|
|
3205
|
+
- **A provider-recovery park becomes a conclusion** ({§provider-recovery}), carrying the
|
|
3206
|
+
provider's own exact Problem. Never a substituted "the model gave up".
|
|
3207
|
+
|
|
3208
|
+
**A park is a promise that something will restart it.** `LoopLifecycle.park` takes the waker
|
|
3209
|
+
by name; `null` says nothing will. Parking an unattended loop with no waker is a contract
|
|
3210
|
+
violation and throws, so a park site added later fails loudly on its first unattended run
|
|
3211
|
+
instead of idling until some caller's clock notices. It is a tripwire, not a fallback: the
|
|
3212
|
+
provider-recovery path concludes before reaching it.
|
|
3213
|
+
|
|
3214
|
+
Attendance never converts a legitimate wait that has a real waker — a `WAIT`, an open stream,
|
|
3215
|
+
a delegated child — into a termination. Those have wakers; a human question
|
|
3216
|
+
does not. A prompt prefix states a disposition, never an attendance: typing `?` asks for review,
|
|
3217
|
+
and an unattended loop refuses that statement rather than conjuring a reviewer.
|
|
3218
|
+
|
|
3219
|
+
§loop-policy-composition **A loop's policy is what its creator stated over what the panel
|
|
3220
|
+
says.** A creator — a client's `loop.run`, a schedule definition, a transport module — states
|
|
3221
|
+
any part of a policy as a `LoopPolicyRequest`, or nothing. The request stays exactly as stated
|
|
3222
|
+
until a fresh loop is persisted: an omitted field is no opinion, so a fold compares only what
|
|
3223
|
+
was said ({§methods-loop-run-fold-consistency}). `LoopPolicies.compose` then makes it whole,
|
|
3224
|
+
once. `PLURNK_SERVICE_ATTENDED` answers an unstated attendance, and the attendance picks which
|
|
3225
|
+
knob answers an unstated disposition: `PLURNK_SERVICE_PROPOSALS` for an attended loop,
|
|
3226
|
+
`PLURNK_SERVICE_UNATTENDED_PROPOSALS` for an unattended one, whose vocabulary has no `review`.
|
|
3227
|
+
Every panel state is therefore lawful, and an invalid knob fails boot by its name. No code,
|
|
3228
|
+
schema or column holds a default ({§operator-config-only-home}): `loops.policy` and
|
|
3229
|
+
`loops.max_turns` carry none, so every insert states both, and an administrative loop — a
|
|
3230
|
+
client's direct statements, the runtime's own narration — states the panel's policy like any
|
|
3231
|
+
other loop whose creator said nothing.
|
|
3232
|
+
|
|
3119
3233
|
§loop-policy-effective-read `loops.policy` persists one complete immutable
|
|
3120
3234
|
`LoopPolicy`; every runtime policy read validates that snapshot before use.
|
|
3121
3235
|
Missing rows or invalid values fail with the owning loop coordinate and cause.
|
|
3122
3236
|
Raw archival copies and forensic rendering do not interpret policy.
|
|
3123
3237
|
|
|
3238
|
+
The cascade's rings are `service`, `workspace` and, innermost, `loop`. The loop ring exists only
|
|
3239
|
+
for an unattended run and is purely subtractive like every other layer, so it can never widen what
|
|
3240
|
+
its workspace allows; a capability denial names the ring that refused. The operator's capability
|
|
3241
|
+
projection and the shared reserved-document materialization take no loop coordinate on purpose:
|
|
3242
|
+
those questions are about a workspace, not about one run.
|
|
3243
|
+
|
|
3124
3244
|
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
|
|
3125
3245
|
|
|
3126
3246
|
| `policy.proposals` | Disposition |
|
|
@@ -3139,7 +3259,7 @@ Capability admission precedes this decision, so proposal disposition cannot gran
|
|
|
3139
3259
|
|
|
3140
3260
|
### §subscriptions Subscriptions
|
|
3141
3261
|
|
|
3142
|
-
§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.
|
|
3262
|
+
§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 hook or database access is part of the plugin contract.
|
|
3143
3263
|
|
|
3144
3264
|
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.
|
|
3145
3265
|
|
|
@@ -3160,7 +3280,7 @@ live executor's current declaration.
|
|
|
3160
3280
|
|
|
3161
3281
|
§subscriptions-fold-keeps-subscription A scoped KILL changes a log row's readable projection ({§log-kill-scope}), never the subscription registry. Curation of a streaming entry's log body leaves the live stream and its source running; it is not cancellation.
|
|
3162
3282
|
|
|
3163
|
-
###
|
|
3283
|
+
### Chunk accumulation
|
|
3164
3284
|
|
|
3165
3285
|
§chunk-accumulation-chunks-accumulate SSE event types, WS message types, exec stdout/stderr each map to a named channel. Each stored channel carries `content`, `mimetype`, curation `weight`, and lifecycle `state` ({§channel-state}). The subscription registry owns durable subscription identity and process-local cancellation routing, not a second channel-state representation. Chunks accumulate into the channel as they arrive — not buffered until close.
|
|
3166
3286
|
|
|
@@ -3170,20 +3290,16 @@ live executor's current declaration.
|
|
|
3170
3290
|
|
|
3171
3291
|
Model sees lifecycle events in the `log` section per turn.
|
|
3172
3292
|
|
|
3173
|
-
### §deep-slices Deep slices on demand
|
|
3174
|
-
|
|
3175
|
-
```` ```READ (https://feed.example/x#body) <N-M> ```` pulls a slice into a log row when the model wants a specific line-range of an SSE stream.
|
|
3176
|
-
|
|
3177
3293
|
### §stream-control Stream control and writes
|
|
3178
3294
|
|
|
3179
3295
|
- **Cancel:** ```` ```KILL (https://feed.example/x) ```` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
|
|
3180
|
-
- **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.
|
|
3296
|
+
- **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.
|
|
3181
3297
|
- **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}.
|
|
3182
3298
|
- **Other stream write:** ```` ```SEND (…) ```` remains scheme-defined, including exec stdin.
|
|
3183
3299
|
|
|
3184
3300
|
### §stream-constraints Engine constraints
|
|
3185
3301
|
|
|
3186
|
-
ONE engine-level constraint: **100 MiB char-length cap per channel body**. `CHECK (length(content) <= 104857600)` on `
|
|
3302
|
+
ONE engine-level constraint: **100 MiB char-length cap per channel body**. `CHECK (length(content) <= 104857600)` on `contents.content` and on an active stream's `entry_channel_rows.buffer` in `migrations/005_entries.sql` ({§content-store}). Violations → SQLITE_CONSTRAINT; action-entry captures rejection at status 500.
|
|
3187
3303
|
|
|
3188
3304
|
§stream-constraints-engine-one-cap All other limits are extrinsic — providers (request size, model context, fetch timeouts), schemes (per-call validation), mimetypes (render budgets). Engine does not throttle, batch, rate-limit, or cap anything else.
|
|
3189
3305
|
|
|
@@ -3195,11 +3311,11 @@ The model is NOT a stream/event consumer — turn-based only; sees whatever's in
|
|
|
3195
3311
|
|
|
3196
3312
|
---
|
|
3197
3313
|
|
|
3198
|
-
##
|
|
3314
|
+
## Storage Model
|
|
3199
3315
|
|
|
3200
3316
|
SQLite (`node:sqlite`) with WAL mode and STRICT tables. Hand-written DDL; CI-aligned against grammar schemas.
|
|
3201
3317
|
|
|
3202
|
-
###
|
|
3318
|
+
### DDL strategy
|
|
3203
3319
|
|
|
3204
3320
|
No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, explicit `NOT NULL`, indexed query paths, deliberate FK `ON DELETE`/`ON UPDATE`, `WITHOUT ROWID` where access pattern warrants, generated columns, FTS5.
|
|
3205
3321
|
|
|
@@ -3213,10 +3329,11 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3213
3329
|
| §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. |
|
|
3214
3330
|
| §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. Duplicates of a `UNIQUE` constraint's own index and sort-only indexes no plan selects were removed on this rule; a column no statement reads (`symbol_refs.col`, `ambient_events.created_at`) is not stored. |
|
|
3215
3331
|
| §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}); no explicit checkpoint and no periodic `ANALYZE` run. |
|
|
3216
|
-
| §
|
|
3332
|
+
| §db-space-reclamation The daemon keeps its own file healthy | `PLURNK_SERVICE_AUTO_VACUUM` (`incremental`, the default, 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, the default, = 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). |
|
|
3333
|
+
| §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` (1). Witnesses: `test/intg/retention.test.ts`, `test/intg/entries.test.ts`, `test/intg/fulltext-index.test.ts`. |
|
|
3334
|
+
| §retention-policy Retention is the operator's policy; information is kept by default | `Retention` (`src/server/Retention.ts`, statements in `Retention.sql`) reads ten knobs from `.env.defaults` once at daemon construction (the two storage knobs are {§db-space-reclamation}) and runs four set statements in dependency order — on `PLURNK_SERVICE_RETENTION_INTERVAL_MS` cadence while the daemon runs (0 = shutdown only) and once more at shutdown before `PRAGMA optimize`. `PLURNK_SERVICE_RETAIN_PACKET_TURNS` (-1 = every packet) and `PLURNK_SERVICE_RETAIN_PACKET_MS` (-1 = no age limit) retire a completed turn's packet composition (`turn_sections`, {§packet-items}) once it is beyond the newest N packet-bearing turns of its loop or older than the age; the turn, its bag, its log rows and its accounting stay, and an open turn is never retired. `PLURNK_SERVICE_COLLECT_PACKET_ITEMS` (1) collects items no composition references. `PLURNK_SERVICE_COLLECT_CONTENTS` (1) collects stored bodies nothing holds ({§content-store}), after the collectors that release them. `PLURNK_SERVICE_COLLECT_DERIVATIONS` (1) collects derivations no channel, turn source, or log row cites — superseded editions — with their symbols (cascade) and their full-text shadow (`derivations_delete_fts`, a process trigger beside the FTS statements, on every delete path). `PLURNK_SERVICE_RETAIN_RESPONSE_TURNS` (-1) and `PLURNK_SERVICE_RETAIN_RESPONSE_MS` (-1) retire a settled call's response body (`model_call_responses`) once it is beyond the newest N body-bearing calls of its loop or its turn is older than the age; the call's identity, failure, capacity, admission and accounting stay, and the digest renders such a call request-only. Under the shipped defaults nothing that is information leaves; only what no row references. A malformed knob refuses daemon construction. Witness: `test/intg/retention.test.ts`. |
|
|
3217
3335
|
|
|
3218
|
-
-
|
|
3219
|
-
- DDL = storage truth; JSON Schemas = wire truth. Tested-aligned, allowed to differ where ergonomics demand.
|
|
3336
|
+
- DDL = storage truth; JSON Schemas = wire truth. They are allowed to differ where ergonomics demand.
|
|
3220
3337
|
- §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`.
|
|
3221
3338
|
|
|
3222
3339
|
### §sql-ts-boundary SQL/TS responsibility boundary
|
|
@@ -3336,10 +3453,10 @@ service manifest edit.
|
|
|
3336
3453
|
|
|
3337
3454
|
---
|
|
3338
3455
|
|
|
3339
|
-
##
|
|
3456
|
+
## Grammar Dependency
|
|
3340
3457
|
|
|
3341
3458
|
Core consumes the language, schemas, and generated types under
|
|
3342
|
-
{§contract-
|
|
3459
|
+
{§contract-representations}. Provider emissions cross
|
|
3343
3460
|
{§emission-admission}; admitted programs execute through
|
|
3344
3461
|
{§turn-ops-admission-path}. Core owns execution and persisted state, not a second
|
|
3345
3462
|
language definition.
|
|
@@ -3358,7 +3475,7 @@ and is ignored rather than resolved against the working directory.
|
|
|
3358
3475
|
|---|---|---|
|
|
3359
3476
|
| Configuration | `$XDG_CONFIG_HOME` (default `~/.config`) | `plurnk/.env`, `plurnk/AGENTS.md` |
|
|
3360
3477
|
| Durable user data | `$XDG_DATA_HOME` (default `~/.local/share`) | `plurnk/plurnk.db` and SQLite sidecars |
|
|
3361
|
-
| Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) |
|
|
3478
|
+
| Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) | On-demand workspace/module directories ({§module-workspace-directory}). |
|
|
3362
3479
|
| Reproducible cache | `$XDG_CACHE_HOME` (default `~/.cache`) | Reserved; no directory is created without an owned artifact. |
|
|
3363
3480
|
| Shared global Agent Skills | User home | `.agents/skills/<name>/SKILL.md` |
|
|
3364
3481
|
|
|
@@ -3384,6 +3501,23 @@ Node's pre-script env-file form and the executable's post-script form share the
|
|
|
3384
3501
|
|
|
3385
3502
|
§operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics) and applies it set-if-unset under every operator source. `plurnk-service config defaults` renders the same complete, owner-labelled aggregate to stdout on demand, preserving comments and optional declarations without persisting a second copy or exposing effective secret values. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
|
|
3386
3503
|
|
|
3504
|
+
§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:
|
|
3505
|
+
|
|
3506
|
+
| Rule | What it refuses |
|
|
3507
|
+
|---|---|
|
|
3508
|
+
| `undeclared` | a knob read that no panel declares, live or as an optional knob; a computed name is covered by one declared example of its family |
|
|
3509
|
+
| `fallback` | a read that carries its own value |
|
|
3510
|
+
| `reader-fallback` | a reader whose signature accepts one, so a caller could state what the panel did not |
|
|
3511
|
+
| `default-constant` | a constant named `DEFAULT_*`: *default* is a word reserved for a value on the panel |
|
|
3512
|
+
| `tunable` | a numeric constant whose own name says duration, size, count or pacing, unless `scripts/env-surface-mechanism.json` registers why it is mechanism |
|
|
3513
|
+
| `timer-literal` | a bare number handed to a timer or a deadline; it is named or read from the panel, and has no register |
|
|
3514
|
+
| `dead-knob` | a live declaration nothing consumes |
|
|
3515
|
+
| `retired-declared` | a retired key still declared; a retired key is named only by the code that refuses it |
|
|
3516
|
+
| `duplicate-owner` | a key two packages declare |
|
|
3517
|
+
| `test-floor` | a package that ships a panel and tests off it |
|
|
3518
|
+
|
|
3519
|
+
Reading the system environment directly is the mechanism and never a finding. The allowance file is a ratchet — new debt is refused, and so is a paid debt left on the books — and it is empty. The register is not a debt: it is the reviewed list of deliberate non-knobs, each with its reason, and an entry whose number is gone is refused.
|
|
3520
|
+
|
|
3387
3521
|
§operator-config-source-errors An optional member file may be absent; other read failures surface with the
|
|
3388
3522
|
owning package and original cause, never as an incomplete successful catalog.
|
|
3389
3523
|
|
|
@@ -3399,36 +3533,37 @@ complete installed option catalog.
|
|
|
3399
3533
|
|
|
3400
3534
|
Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` optionally declares a friendly route and tuning scope; `PLURNK_MODEL=<selector>` selects either that alias or an exact provider/model route. `PLURNK_MODEL_CHILD=<selector>` uses the same vocabulary for the default child provider; unset means inherit the spawning loop's provider. Operator selections and alias declarations live in `.env`, not `.env.defaults`.
|
|
3401
3535
|
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
|
3405
|
-
|
|
3406
|
-
| `
|
|
3407
|
-
| §operator-config-
|
|
3408
|
-
| §operator-config-
|
|
3409
|
-
| `
|
|
3410
|
-
| `
|
|
3411
|
-
| `
|
|
3412
|
-
|
|
|
3413
|
-
|
|
|
3414
|
-
| `
|
|
3415
|
-
| `
|
|
3416
|
-
| `
|
|
3417
|
-
| `
|
|
3418
|
-
| `
|
|
3419
|
-
| `
|
|
3420
|
-
| `
|
|
3421
|
-
| `
|
|
3422
|
-
| `
|
|
3423
|
-
| `
|
|
3424
|
-
| `
|
|
3425
|
-
| `
|
|
3426
|
-
| `
|
|
3427
|
-
| `
|
|
3428
|
-
| `
|
|
3429
|
-
| `
|
|
3430
|
-
|
|
|
3431
|
-
|
|
|
3536
|
+
Each knob's value lives on its panel and nowhere else (`plurnk-service config defaults` prints them all); this table says what the service's knobs mean.
|
|
3537
|
+
|
|
3538
|
+
| Var | Purpose |
|
|
3539
|
+
|---|---|
|
|
3540
|
+
| `PLURNK_SERVICE_DB_PATH` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
3541
|
+
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The listener's bind address and TCP port — THE client surface, the AG-UI+ listener the plurnk-agui module binds at boot; production is single-listener. **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. |
|
|
3542
|
+
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
|
|
3543
|
+
| §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. |
|
|
3544
|
+
| `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
|
|
3545
|
+
| `PLURNK_SERVICE_MAX_TURNS` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
|
|
3546
|
+
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. The final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
3547
|
+
| §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. |
|
|
3548
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms a turn keeps re-issuing its provider call after a recoverable provider failure before the loop parks ({§provider-recovery}); `0` parks at once. |
|
|
3549
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
|
|
3550
|
+
| `PLURNK_SERVICE_MAX_STRIKES` | Consecutive turn-contract strike threshold ({§engine-rails}). |
|
|
3551
|
+
| `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}. |
|
|
3552
|
+
| `PLURNK_SERVICE_PREVIEW_LINES` | First page of every markerless retrieval, in the projection's own units, and the head bound of an automatic preview ({§markerless-first-page}, {§body-projection}). |
|
|
3553
|
+
| `PLURNK_SERVICE_PREVIEW_CHARS` | Independent Unicode code-point bound on the same previews, with CRLF treated as one indivisible separator ({§body-projection}). |
|
|
3554
|
+
| `PLURNK_SERVICE_PROMPT_PROJECTION` | Aggregate curation-weight share of the provider-derived input capacity available to the automatic projection of arrivals from outside the workspace ({§message-projection}); alias-scoped overrides are supported. |
|
|
3555
|
+
| `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | Complete neighboring lines hashed on each side of a model-facing line anchor ({§line-anchors}). |
|
|
3556
|
+
| `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
|
|
3557
|
+
| `PLURNK_SERVICE_MIN_CYCLES` | Min repetitions before cycle detection fires ({§engine-rails}). |
|
|
3558
|
+
| `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | Max period length cycle detection examines ({§engine-rails}). |
|
|
3559
|
+
| `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | Initial forensic witness output allowance ({§digest-requiem}). |
|
|
3560
|
+
| `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
|
|
3561
|
+
| `PLURNK_SERVICE_FILES_ITEMS` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
|
|
3562
|
+
| `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
|
|
3563
|
+
| `PLURNK_SERVICE_EXEC_CONCURRENCY` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
|
|
3564
|
+
| `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
|
|
3565
|
+
| §operator-config-worker-warm `PLURNK_SERVICE_WORKSPACE_WARM_MS` | Milliseconds a lease-free workspace Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-workspace-residency}). |
|
|
3566
|
+
| `PLURNK_SERVICE_WORKSPACE_WARM_MAX` | Maximum lease-free workspace Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-workspace-residency}). |
|
|
3432
3567
|
|
|
3433
3568
|
Every core knob listed is enforced at its owning read site; `.env.defaults` is the authoritative default ({§operator-config-env-defaults}). Provider, scheme, executor, mimetype, and client-interface knobs are documented by their owning packages and appear in the assembled catalog.
|
|
3434
3569
|
|
|
@@ -3449,11 +3584,11 @@ template both ways: every `PLURNK_SERVICE_*` the service reads has a
|
|
|
3449
3584
|
declared `PLURNK_SERVICE_*` is read. A half-landed rename therefore fails a test
|
|
3450
3585
|
instead of a user's boot, and a dead knob cannot ship.
|
|
3451
3586
|
|
|
3452
|
-
§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
|
|
3587
|
+
§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, ambient MCP selections and schedules disabled, and `PLURNK_EXECS_QUESTION=0` for unattended runs. The ordinary executor switch removes the question tool and its teaching; an explicit override can opt into an attended drill. Configuration with a narrower or variable owner stays outside it:
|
|
3453
3588
|
|
|
3454
3589
|
| Owner | Configuration |
|
|
3455
3590
|
|---|---|
|
|
3456
|
-
| `.env.test` |
|
|
3591
|
+
| `.env.test` | Universal real-model gate posture, with no model selection, alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
|
|
3457
3592
|
| Live/demo scripts | The repository policy path and runner topology. |
|
|
3458
3593
|
| Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
|
|
3459
3594
|
| Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
|
|
@@ -3631,9 +3766,22 @@ flowchart LR
|
|
|
3631
3766
|
| §module-action-registration `registerModuleAction({ name, scope, inputSchema, outputSchema, handler })` | Adds one non-empty, extension-unique action with resolvable JSON Schemas. `scope` is exactly `worldless`, `workspace`, or `worker`; the handler receives schema-validated params and a separate matching context. Scoped contexts contain trusted bound identifiers, never client parameters. A client-interface module decides whether and how the name becomes public, validates successful output, and owns collisions with its built-ins. |
|
|
3632
3767
|
| §module-workspace-provider `registerWorkspaceCapabilityProvider(namespaceOwner, provider)` | Registers one extension-unique Functionality provider. `activate({ workspaceId, retain })` reconstructs the workspace snapshot; idempotent `deactivate({ workspaceId })` releases process resources. Core coalesces demand and supplies residency leases for work that outlives its caller. |
|
|
3633
3768
|
| §module-workspace-state `readWorkspaceModuleState(workspaceId, namespaceOwner)` | Reads one nullable JSON state value per workspace and provider. Core owns storage and lifecycle; the provider owns its schema. Store symbolic credential references, not copied secrets. A worker-scoped family's coordinator reads and replaces the same shape per worker in `worker_module_state` ({§functionality-scope}). |
|
|
3769
|
+
| `readWorkspaceEnvironment(workspaceId)` | Captures the workspace env layer ({§workspace-env}) and returns its composer. No argument uses admitted host values; a supplied environment supplies a module's reference-resolution context. Both apply the same captured values and masks, without worker overrides. |
|
|
3770
|
+
| §module-workspace-directory `workspaceStateDirectory(workspaceId, namespaceOwner)` | Returns and creates the module's absolute operational-state directory under the daemon's XDG state home. Core owns path resolution and a stable random workspace storage key in its own `workspace_module_state` row. The key survives workspace renames and daemon restarts; independently created workspaces, including in other databases, receive different keys. The module owns its contents and child-directory lifetimes. |
|
|
3634
3771
|
| §module-functionality-adapter `registerFunctionalityAdapter(adapter)` | Registers one family beneath the shared coordinator ({§functionality-coordinator}). |
|
|
3635
3772
|
| §module-workspace-capabilities `replaceWorkspaceCapabilities({ workspaceId, namespaceOwner, state, runtimes })` | Atomically replaces one provider's durable state and runtime/scheme snapshot at the workspace operation boundary. Namespace claims are validated before mutation. Failure restores the prior state and publication. |
|
|
3636
3773
|
|
|
3774
|
+
Module directory allocation is lazy, atomic in SQLite, and independent of the
|
|
3775
|
+
project root, daemon CWD, and workspace/worker environment overrides. New
|
|
3776
|
+
directories use mode `0700`; existing permissions are not rewritten. Module
|
|
3777
|
+
names occupy a single encoded path component. Missing workspaces, invalid
|
|
3778
|
+
stored keys, and filesystem failures are errors, never a fallback to CWD.
|
|
3779
|
+
Allocated state is not erased on cooling, disable, removal, or shutdown: its
|
|
3780
|
+
contents may be persistent or referenced by retained results. Deleting a
|
|
3781
|
+
workspace forgets its storage key through the existing foreign key; old disk
|
|
3782
|
+
state is not reassigned or automatically purged. A database copy preserves its
|
|
3783
|
+
storage identities; the directory is operational state, not a backup of it.
|
|
3784
|
+
|
|
3637
3785
|
§workspace-environment-sharing **The workspace owns its shared environment.**
|
|
3638
3786
|
Workers own their logs; delegation retains its existing lifecycle.
|
|
3639
3787
|
Creating, attaching, forking, cancelling, or deleting a worker does not create,
|
|
@@ -3692,7 +3840,7 @@ The version-1 baseline table `workspace_module_state` stores one JSON value
|
|
|
3692
3840
|
per `(workspace_id, namespace_owner)`. It is configuration, not an executable
|
|
3693
3841
|
registry. Deleting the workspace cascades its state; worker lifecycle does not.
|
|
3694
3842
|
|
|
3695
|
-
##
|
|
3843
|
+
## Workspace Functionality
|
|
3696
3844
|
|
|
3697
3845
|
§functionality-coordinator **One coordinator owns the common lifecycle.**
|
|
3698
3846
|
Agent Skills, MCP, outbound A2A agents, and membership are adapters beneath
|
|
@@ -3727,14 +3875,27 @@ failure aborts; cooling tears down. Protocol continuations remain ordinary
|
|
|
3727
3875
|
module actions. Optional `forget` releases an installed or provisioned
|
|
3728
3876
|
definition before removal; failure rejects removal ({§skills-remove}).
|
|
3729
3877
|
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3878
|
+
An adapter may expose a `scheme` facet beneath its family's runtime namespace
|
|
3879
|
+
({§runtime-resource-binding}). A facet claims a path subtree and is the scheme's
|
|
3880
|
+
whole live half there: READ and FIND preparation, FIND, SEND, WAIT and KILL are
|
|
3881
|
+
its own wherever it implements them. A claimed KILL the facet does not implement
|
|
3882
|
+
is the ordinary entry KILL ({§stream-control}); an unclaimed coordinate keeps the
|
|
3883
|
+
stored-execution behaviour, SEND to a process included. Where its resources are
|
|
3884
|
+
not shaped like the executor's output, the facet states their representation —
|
|
3885
|
+
resource authority, channels, the default channel — and that manifest governs
|
|
3886
|
+
every claimed coordinate: its address, its fragmentless READ, the channel a
|
|
3887
|
+
subscription publishes. An adapter states the `traits` of its runtime — `web`
|
|
3888
|
+
for a family that reaches the network — so {§capability-admission} selects its
|
|
3889
|
+
manager and its resources alike.
|
|
3890
|
+
|
|
3891
|
+
§env-functionality **Environment is a scoped family.** Ambient names admitted by the
|
|
3892
|
+
operator's ceiling ({§exec-env-scoped}, service origin) precede workspace defaults and
|
|
3893
|
+
worker overrides ({§workspace-env}). `add` takes
|
|
3733
3894
|
the name as the alias and `{ "value": "…" }` as the definition, used verbatim with no
|
|
3734
|
-
interpolation. `disable`
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3895
|
+
interpolation. `disable` withholds a name in the selected scope while retaining it;
|
|
3896
|
+
`remove` forgets a locally-owned entry and a same-name lower baseline reappears
|
|
3897
|
+
disabled, so removal never silently changes what the next spawn sees. Definitions
|
|
3898
|
+
from a lower layer are disable-only in the current scope.
|
|
3738
3899
|
|
|
3739
3900
|
`list` projects effective values with their origin. Values are shown: the ceiling is the security
|
|
3740
3901
|
boundary, not the projection, and any admitted name is already readable by every command the
|
|
@@ -3755,23 +3916,24 @@ name with its documentation and an empty value ({§exec-env-scoped}: referred to
|
|
|
3755
3916
|
read). `configuration` is refused: a client's own environment contributing candidates would be a
|
|
3756
3917
|
second door past the ceiling.
|
|
3757
3918
|
|
|
3758
|
-
The family publishes no runtimes.
|
|
3759
|
-
|
|
3919
|
+
The family publishes no process runtimes. Its values are read at the spawn that uses them,
|
|
3920
|
+
not from a live process or a cached worker environment.
|
|
3760
3921
|
|
|
3761
|
-
§functionality-scope **A family declares
|
|
3922
|
+
§functionality-scope **A family declares its supported scopes.** Skills, MCP, members
|
|
3762
3923
|
and outbound A2A describe what exists in a **workspace**: a capability, resident or installable,
|
|
3763
3924
|
that every Worker there shares. Environment describes how one **Worker** works — context rather
|
|
3764
|
-
than capability —
|
|
3765
|
-
(absent means workspace
|
|
3925
|
+
than capability — with worker overrides above workspace defaults. The adapter declares
|
|
3926
|
+
`scopes` (absent means `["workspace"]`; the first is the model default), and the
|
|
3927
|
+
coordinator keys durable state and the locally-owned `origin`
|
|
3766
3928
|
by it: a workspace-scoped family's own entries carry origin `workspace`, a worker-scoped
|
|
3767
3929
|
family's carry `worker`. Origin names ownership, never scope, so a projection never claims the
|
|
3768
3930
|
workspace set a value one Worker set for itself. Nothing else in the contract varies: the six
|
|
3769
3931
|
verbs, the two projections, enabledness, and the service-baseline rules are one implementation
|
|
3770
3932
|
across every family, which is what keeps their idioms from drifting apart.
|
|
3771
3933
|
|
|
3772
|
-
A
|
|
3773
|
-
|
|
3774
|
-
|
|
3934
|
+
A family projects `<scope>.<family>.<verb>` for each supported scope. The action's
|
|
3935
|
+
context binds that scope; a worker-scoped action also names the Worker. Its durable
|
|
3936
|
+
value is the same shape per (worker, family) in `worker_module_state`, read
|
|
3775
3937
|
at each verb and at each spawn rather than held in the workspace snapshot. Its `list` and
|
|
3776
3938
|
mutations serialize on the Worker's own lane and take no workspace exclusivity: nothing
|
|
3777
3939
|
resident changes, and the next spawn reads the state, so a Worker shapes its own environment
|
|
@@ -3791,8 +3953,8 @@ option lands as the child's own entries through `add`, after the copy ({§env-op
|
|
|
3791
3953
|
is stored under the provider namespace in `workspace_module_state`; a
|
|
3792
3954
|
worker-scoped family ({§functionality-scope}) stores the same value per worker
|
|
3793
3955
|
and family in `worker_module_state`.
|
|
3794
|
-
A
|
|
3795
|
-
|
|
3956
|
+
A locally-owned entry persists its exact definition; a lower-layer entry persists
|
|
3957
|
+
only enabledness, never a copied value. Active, unavailable, and authorization-required are preparation
|
|
3796
3958
|
outcomes, not durable desired state. The configuration cascade contributes
|
|
3797
3959
|
defaults; one workspace snapshot is effective authority.
|
|
3798
3960
|
|
|
@@ -3829,6 +3991,10 @@ binds that Worker to the manager at the operation, so the published manager
|
|
|
3829
3991
|
stays one per workspace and the executor framework's arguments carry no
|
|
3830
3992
|
identity ({§functionality-scope}).
|
|
3831
3993
|
|
|
3994
|
+
Expected adapter failures retain their exact status and Problem in both client
|
|
3995
|
+
actions and the model operation's stream/result ({§problem-error-carrier}). An
|
|
3996
|
+
unexpected exception remains an executor fault, not a managed refusal.
|
|
3997
|
+
|
|
3832
3998
|
§functionality-document-body **A family's teaching is an authored file beneath
|
|
3833
3999
|
its generated header.** The adapter names its package directory (`docsDir`);
|
|
3834
4000
|
that package's `docs/<family>.md` is read once, by the same rule runtimes use
|
|
@@ -3871,7 +4037,7 @@ Core's behavior behind them.
|
|
|
3871
4037
|
| §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. |
|
|
3872
4038
|
| §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. |
|
|
3873
4039
|
| 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}). |
|
|
3874
|
-
| §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. `limit`
|
|
4040
|
+
| §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. An omitted `limit` is `PLURNK_SERVICE_LOG_READ_PAGE`, and any `limit` is capped at `PLURNK_SERVICE_LOG_READ_MAX`. |
|
|
3875
4041
|
| §methods-entry-read Reads | `readEntry({ workspaceId, workerId, target, channel?, offset? })` | Resolves the selector from that worker's perspective and returns {§entry-read-result}, either complete or as one channel suffix, without creating action evidence. |
|
|
3876
4042
|
| Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
|
|
3877
4043
|
| Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
|
|
@@ -3882,10 +4048,10 @@ Core's behavior behind them.
|
|
|
3882
4048
|
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin root worker with empty history: a fresh conversation over the same world, not a fork or the stable default. |
|
|
3883
4049
|
| Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
|
|
3884
4050
|
| §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
|
|
3885
|
-
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first.
|
|
4051
|
+
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. An omitted limit is `PLURNK_SERVICE_PROMPTS_PAGE`; spawned and forked child prompts are excluded. |
|
|
3886
4052
|
| Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
|
|
3887
4053
|
| §methods-worker-read Worker topology | `readWorker({ workspaceId, identity })` | Ownership-bounds an exact id-or-name lookup and returns one durable Worker projection or `null` under {§application-worker-observation}. Supplying both identities or neither is invalid. |
|
|
3888
|
-
| §methods-worker-list Worker topology | `listWorkers(workspaceId, query?)` | Returns the workspace's durable Worker projections under {§application-worker-observation}. The origin filter is exact; an explicitly present `parentWorkerId` filters roots (`null`) or one immediate parent (id), while omission returns every lineage position. Each projection carries `kind` (`conversation`, `fork` for a child with a fork boundary, `work` for any other child) and `lifecycle`, the
|
|
4054
|
+
| §methods-worker-list Worker topology | `listWorkers(workspaceId, query?)` | Returns the workspace's durable Worker projections under {§application-worker-observation}. The origin filter is exact; an explicitly present `parentWorkerId` filters roots (`null`) or one immediate parent (id), while omission returns every lineage position. Each projection carries `kind` (`conversation`, `fork` for a child with a fork boundary, `work` for any other child) and `lifecycle`, the representative work loop's status through {§loop-lifecycle-vocabulary} (`idle` with no work loop), so a directory row shows the same lifecycle glyph the bound worker's own status gauge shows; clients infer neither (#523). |
|
|
3889
4055
|
| §methods-worker-loops Loop lifecycle | `listWorkerLoops({ workspaceId, workerId })` | Ownership-checks the Worker and returns its Loops in sequence order under {§application-loop-observation}, including the validated exact terminal result when one exists. It performs no scheduling or event replay. |
|
|
3890
4056
|
| Extension actions | `listModuleActions()`, `invokeModuleAction(name, params, context)` | Lists setup-registered `{ name, scope, inputSchema, outputSchema }` descriptors in sorted order. Invocation requires a context matching the registered scope; missing names, forged scope, and missing workspace identity fail before the owner runs. Handler values remain opaque to core. |
|
|
3891
4057
|
|
|
@@ -3898,26 +4064,26 @@ already durable on the loop remains authoritative:
|
|
|
3898
4064
|
|-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
|
|
3899
4065
|
| Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
|
|
3900
4066
|
| `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
|
|
3901
|
-
|
|
|
4067
|
+
| `policy` request | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
|
|
3902
4068
|
|
|
3903
4069
|
The conflict names both selections and directs the caller to cancel or conclude
|
|
3904
4070
|
the loop before changing configuration. A newly enqueued loop instead persists
|
|
3905
4071
|
the requested configuration normally.
|
|
3906
4072
|
|
|
3907
4073
|
§methods-loop-run-open-paths **Workspace paths are core-owned context reads.**
|
|
3908
|
-
`openPaths` belongs to the
|
|
4074
|
+
`openPaths` belongs to the message submitted by the client. The client
|
|
3909
4075
|
sends paths, never duplicated file bytes; core dispatches one ordinary
|
|
3910
4076
|
`plurnk`-origin READ per path from inside the owning workspace, and successes
|
|
3911
4077
|
and failures surface through the normal operation-result contract.
|
|
3912
4078
|
|
|
3913
|
-
| `runLoop` disposition |
|
|
3914
|
-
|
|
3915
|
-
| New loop | Persist with the initial
|
|
3916
|
-
| Active loop | Persist with the injected
|
|
3917
|
-
| Parked loop | Persist with the waking
|
|
4079
|
+
| `runLoop` disposition | Message and path behavior |
|
|
4080
|
+
|-----------------------|------------------------------------------------------------------------------------------------------|
|
|
4081
|
+
| New loop | Persist with the initial message; publish it and READ its paths on turn 1. |
|
|
4082
|
+
| Active loop | Persist with the injected message; publish it and READ its paths together on the next turn. |
|
|
4083
|
+
| Parked loop | Persist with the waking message; publish it and READ its paths together on the resumed turn. |
|
|
3918
4084
|
|
|
3919
|
-
If an
|
|
3920
|
-
{§
|
|
4085
|
+
If an unpublished message is promoted into subsequent work under
|
|
4086
|
+
{§message-loop-containment}, its selected paths travel with it.
|
|
3921
4087
|
|
|
3922
4088
|
§methods-rebind **Binding belongs to the client-interface module.** Core's
|
|
3923
4089
|
workspace lifecycle calls return exactly the workspace and selected client actor
|
|
@@ -3945,7 +4111,7 @@ mutation of its source; a resource-backed execution demands its runtime plus sou
|
|
|
3945
4111
|
observation. Unknown schemes, runtimes,
|
|
3946
4112
|
and tools continue to their ordinary resolver so capability policy cannot turn
|
|
3947
4113
|
absence into a misleading restriction. The same resolver shapes generated
|
|
3948
|
-
scheme references, worker tool documents, and Turn0 surveys.
|
|
4114
|
+
scheme references, worker tool documents, and Turn0 surveys. NOTE, lifecycle declarations, log KILL,
|
|
3949
4115
|
and label or targetless SEND are log/program control rather than routed
|
|
3950
4116
|
external demands and therefore remain outside capability selectors.
|
|
3951
4117
|
Runtime mutations of owned generated entries ({§worker-generated-subtree})
|
|
@@ -4105,9 +4271,8 @@ beside database ids, so a client can render and resolve the logical `L/T/S`
|
|
|
4105
4271
|
coordinate without fetching all rows and matching locally.
|
|
4106
4272
|
|
|
4107
4273
|
§methods-log-entry-wire **Log entry wire fidelity.** `readLog` and `log/entry`
|
|
4108
|
-
preserve causal `source` and parse the row's JSON `attrs` into structured data
|
|
4109
|
-
|
|
4110
|
-
interfaces do not reconstruct these fields from operation or origin.
|
|
4274
|
+
preserve causal `source` and parse the row's JSON `attrs` into structured data.
|
|
4275
|
+
Client interfaces do not reconstruct these fields from operation or origin.
|
|
4111
4276
|
|
|
4112
4277
|
§methods-readable-reasoning **Readable provider reasoning remains derived
|
|
4113
4278
|
provider evidence.** On model SEND and disposition rows, `readLog` and `log/entry`
|
|
@@ -4122,8 +4287,8 @@ hands the AST to core's `look`; core owns the full resolver and the no-log
|
|
|
4122
4287
|
invariant. The internal closed, rowless observation segment supplies an honest
|
|
4123
4288
|
numeric loop coordinate for relative `log:///` addressing without leaving
|
|
4124
4289
|
active lifecycle behind. The segment belongs to the acting worker (`workerId`);
|
|
4125
|
-
the READ resolves as `perspectiveWorkerId` when one is given
|
|
4126
|
-
|
|
4290
|
+
the READ resolves `log:///` as `perspectiveWorkerId` when one is given; explicit source
|
|
4291
|
+
authorities retain their identity under {§turn-source-resources}. A client can look at a conversation without
|
|
4127
4292
|
adding a loop to it. LOOK text anchors resolve through the same
|
|
4128
4293
|
{§line-anchors} path as READ.
|
|
4129
4294
|
|
|
@@ -4175,13 +4340,6 @@ defining the public client lifecycle. Multiple client actors have distinct worke
|
|
|
4175
4340
|
only the model worker's private log; client action rows are structurally absent
|
|
4176
4341
|
without an origin filter ({§actor-boundary-isolation}).
|
|
4177
4342
|
|
|
4178
|
-
### §versioning Versioning
|
|
4179
|
-
|
|
4180
|
-
The typed module seam is released with the service package. Core exposes no
|
|
4181
|
-
runtime version or update-advertising action. External protocol compatibility
|
|
4182
|
-
and any protocol-level version negotiation belong to the client-interface
|
|
4183
|
-
module that publishes that protocol.
|
|
4184
|
-
|
|
4185
4343
|
---
|
|
4186
4344
|
|
|
4187
4345
|
## §packet-assembly Packet assembly
|
|
@@ -4214,7 +4372,7 @@ Conditional absence never reorders the surviving default sections.
|
|
|
4214
4372
|
| 8 | user | `notices` | Per-turn observations; empty content is omitted. |
|
|
4215
4373
|
| 9 | user | `git` | Per-turn workspace status; empty content is omitted. |
|
|
4216
4374
|
| 10 | user | `budget` | `Context Curation`; omitted when capacity is unknown. |
|
|
4217
|
-
| 11 | user | `
|
|
4375
|
+
| 11 | user | `messages` | `Open Messages`: immutable message addresses and causal sources ({§message-arrival}). |
|
|
4218
4376
|
| 12 | user | `recap` | Optional authored operational recap. |
|
|
4219
4377
|
|
|
4220
4378
|
The order favors prefix-cache locality where semantics permit: the definition
|
|
@@ -4238,7 +4396,7 @@ sections. It receives no separate engine, database, actor, or request context.
|
|
|
4238
4396
|
|
|
4239
4397
|
This is strictly a trusted in-process seam, admitted through the common plugin
|
|
4240
4398
|
trust gate; an external client action cannot invoke it. Whole-list transformation is
|
|
4241
|
-
the fork-avoidance valve for alternate packet shapes
|
|
4399
|
+
the fork-avoidance valve for alternate packet shapes, while
|
|
4242
4400
|
overflow recovery and packet projection remain closed engine concerns.
|
|
4243
4401
|
|
|
4244
4402
|
### §tokenomics Tokenomics: four facts, one curation ruler
|
|
@@ -4274,9 +4432,9 @@ time of measurement.
|
|
|
4274
4432
|
- **Derivation is exhaustive and demand-led.** Explicit searchable-resource changes may start one coalesced warm. Passive creation and attachment do not. The first model turn starts or joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or full-text coverage. Progress notices make the wait visible. {§derivation-exhaustive}
|
|
4275
4433
|
- §membership-binary-sniff **Binary truth beats a text label.** Filesystem source acquisition, including tracked members and installed skill resources, inspects up to the first 8192 bytes when extension detection does not identify a binary type. NUL marks `application/octet-stream`; existing binary types retain their declared type. Member projections follow {§membership-source-projection}; installed skill projections follow {§skills-resources}.
|
|
4276
4434
|
- §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
|
|
4277
|
-
- §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Curation` section is one JSON object carrying `logTokensTotal` and `logTokensMax` (and `tokensResponseMax` when an output floor is disclosed)
|
|
4278
|
-
- §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** At
|
|
4279
|
-
- §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.**
|
|
4435
|
+
- §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Curation` section is one JSON object carrying `logTokensTotal` and `logTokensMax` (and `tokensResponseMax` when an output floor is disclosed). It never presents their difference as free response tokens. The protocol definition directly requires KILL of irrelevant log items and ranges to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe visible cost and curation savings. Generic packet composition and physical-token speculation are absent.
|
|
4436
|
+
- §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** At `PLURNK_SERVICE_BUDGET_PRESSURE` of `logTokensMax`, a Markdown `> [!WARNING]` block follows the JSON with `> YOU MUST KILL superseded, stale, or irrelevant log items and ranges.` New output withholding replaces that mandate under {§context-output-warning}. The JSON may include `logTokensLargest`: at most `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` retained log items, each `{path, logTokens}`, ranked by that charge descending and then path. Native-only, suppressed, and metadata-only items remain eligible: whole-item KILL can reclaim their actual contribution. Include the largest prefix that fits; drop the optional list before the warning. Both participate in the final fixed-point total and complete request admission check.
|
|
4437
|
+
- §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** A settled channel's `content_hash` (SHA-256) is its body's identity in the content store ({§content-store}); a writer may bind it, a bound hash must match the content, and an active stream has none until it settles. `weight` is stored beside that content and is never keyed or recomputed by model.
|
|
4280
4438
|
- §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity beneath the normalized {§inference-ledger} and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. Each derived aggregate usage field independently sums its reported quantity, so heterogeneous detail coverage remains partial rather than becoming fictitiously complete. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot KILL, so they never alter the model-facing Budget ledger.
|
|
4281
4439
|
- §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `logTokensTotal` above `logTokensMax`. Crossing the maximum withholds new returned output under {§context-output-admission}; no over-ceiling packet reaches `provider.generate`. Output admission creates neither a strike nor another turn.
|
|
4282
4440
|
|
|
@@ -4284,7 +4442,7 @@ time of measurement.
|
|
|
4284
4442
|
|
|
4285
4443
|
Operations and their results are execution history. Packet admission controls
|
|
4286
4444
|
only whether newly presented returned output fits, never what executed or what
|
|
4287
|
-
the model's
|
|
4445
|
+
the model's lifecycle declaration means.
|
|
4288
4446
|
|
|
4289
4447
|
```mermaid
|
|
4290
4448
|
flowchart TD
|
|
@@ -4302,7 +4460,7 @@ flowchart TD
|
|
|
4302
4460
|
prompt -->|no| stop
|
|
4303
4461
|
```
|
|
4304
4462
|
|
|
4305
|
-
§context-output-selection **First presentation, not a turn-number heuristic, owns admission.** Canonical log-body resolution distinguishes authored input from returned output. Before provider I/O, the run boundary records the first admission turn of each newly visible returned body. On measured overflow, that batch's returned bodies and native parts are withheld together. Already-admitted output, authored
|
|
4463
|
+
§context-output-selection **First presentation, not a turn-number heuristic, owns admission.** Canonical log-body resolution distinguishes authored input from returned output. Before provider I/O, the run boundary records the first admission turn of each newly visible returned body. On measured overflow, that batch's returned bodies and native parts are withheld together. Already-admitted output, authored NOTE/lifecycle/program/message bodies, actual statuses and Problems, effects, child state, and immutable evidence remain unchanged. Bodyless and initially suppressed rows require no admission. Packet assembly is pure. No recovery turn, generated lifecycle declaration, KILL operation, strike, or extra model attempt is manufactured.
|
|
4306
4464
|
|
|
4307
4465
|
| Projection fact | Meaning |
|
|
4308
4466
|
|---|---|
|
|
@@ -4314,11 +4472,25 @@ flowchart TD
|
|
|
4314
4472
|
|
|
4315
4473
|
§context-output-warning **New omission escalates the one curation warning.** The admitting request renders `> [!WARNING]` followed by `> YOU MUST ONLY KILL superseded, stale, or irrelevant log content in bulk.` beneath its JSON readout, replacing the ordinary pressure mandate even when withholding brings usage below 80%. Historical omission alone does not retrigger it. The warning participates in exact packet measurement; optional largest-items entries yield space first.
|
|
4316
4474
|
|
|
4317
|
-
§context-output-hard-413 **Unfittable retained context fails honestly.** If the request still exceeds the ceiling after withholding newly presented output, it terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem without provider I/O. No unrelated older history or authored
|
|
4475
|
+
§context-output-hard-413 **Unfittable retained context fails honestly.** If the request still exceeds the ceiling after withholding newly presented output, it terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem without provider I/O. No unrelated older history or authored memory is pruned. Separately, provider capacity failures follow {§provider-surface-capacity}: withholding automatic prompt-body projection permits a retry only when it changes the request; otherwise the exact provider-owned 413 terminates the request-only model turn.
|
|
4318
4476
|
|
|
4319
4477
|
- §tokenomics-fetch-fits-free **Withholding is not deletion.** The complete result lands once. READ/FIND of its original log address retain the readable body and original coordinates; scoped READ creates a fresh output occurrence subject to the same admission rule. Source resources and forensic evidence remain unchanged. Deliberate scoped KILL, unlike withholding, removes lines from subsequent readable projections ({§log-readable-projection}).
|
|
4320
4478
|
|
|
4321
|
-
- §loop-terminals **
|
|
4479
|
+
- §loop-terminals **Lifecycle outcomes are HTTP-precise.**
|
|
4480
|
+
|
|
4481
|
+
| Status | Outcome |
|
|
4482
|
+
|---|---|
|
|
4483
|
+
| 100 / 102 | Queued / running |
|
|
4484
|
+
| 202 | WAIT or answered work joining a live obligation ({§wait-obligation-matrix}, {§worker-wait-timing}) |
|
|
4485
|
+
| 200 | Messages answered, results observed, held work settled |
|
|
4486
|
+
| 499 | Worker-scope or client cancellation |
|
|
4487
|
+
| 429 | Turn allowance exhausted |
|
|
4488
|
+
| 413 | Token-ceiling recovery failure or provider input-capacity failure after changed-request recovery |
|
|
4489
|
+
| 500 / 508 | Strike threshold or invalid-emission exhaustion / crossing strike caused by a cycle |
|
|
4490
|
+
| 504 | Loop timeout or exec-timeout restamp |
|
|
4491
|
+
|
|
4492
|
+
An empty WAIT continues at 102. The exact terminal result retains its Problem;
|
|
4493
|
+
status classes are not catch-all replacements for that evidence.
|
|
4322
4494
|
|
|
4323
4495
|
### §env-delta The environment delta: what changed since the model last looked
|
|
4324
4496
|
|
|
@@ -4356,7 +4528,10 @@ pre-existing broadcast history stays out while later occurrences remain
|
|
|
4356
4528
|
deliverable even before its first packet. A fork instead copies the parent's
|
|
4357
4529
|
cursor and captures its own fork high-water atomically with worker creation
|
|
4358
4530
|
({§machine-processes-fork-pending-activity}). Observer rows retain the source
|
|
4359
|
-
identity and never publish another occurrence.
|
|
4531
|
+
identity and never publish another occurrence. Newly materialized ambient and
|
|
4532
|
+
terminal-stream rows emit the ordinary client notification
|
|
4533
|
+
({§notifications-log-entry-notify}) before the next inference; an idempotent
|
|
4534
|
+
pull does not emit an existing row again.
|
|
4360
4535
|
|
|
4361
4536
|
§env-delta-worker-entry-visibility **The commons is global; every other
|
|
4362
4537
|
resource follows lineage.** A successful state-changing `EDIT`, `COPY`, `MOVE`,
|
|
@@ -4368,8 +4543,8 @@ ordinary operation evidence still reaches that child's direct parent.
|
|
|
4368
4543
|
|
|
4369
4544
|
| Producer / event | Durable occurrence | Observer projection |
|
|
4370
4545
|
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
4371
|
-
| §env-delta-child-activity Direct-child activity |
|
|
4372
|
-
| §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.
|
|
4546
|
+
| §env-delta-child-activity Direct-child activity | Child-authored final EDIT, COPY, MOVE, SEND, executor invocation, WORK, FORK, and 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. |
|
|
4547
|
+
| §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 target selects its exact loop result ({§worker-loop-result}). | Direct parent only; an ordinary bounded READ projection of the retained occurrence, never a fresh lookup of the child's latest loop. The outcome's own body is visible within the ordinary READ bound; replies are separate messages and are never copied or deduplicated by content ({§worker-scheme-collect}). Excluded administrative loops create no pending child-result edge. |
|
|
4373
4548
|
| §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. |
|
|
4374
4549
|
| §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. |
|
|
4375
4550
|
| §env-delta-entry-materialization Executor `entry()` sink | The runtime records typed materialization evidence under its owning actor. | No ambient observer row unless the resulting operation itself is direct-child activity or a commons mutation ({§exec-entry-sink}). |
|
|
@@ -4380,19 +4555,19 @@ ordinary operation evidence still reaches that child's direct parent.
|
|
|
4380
4555
|
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
4381
4556
|
| `worker_id` | The worker whose self-contained log owns the materialized row. |
|
|
4382
4557
|
| `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
|
|
4383
|
-
| `source` | The
|
|
4558
|
+
| `source` | The attributed actor or subsystem: a lineage or commons observation uses canonical `worker://<producer>`; a subsystem observation may use its stable token (for example `file`). Self-authored rows omit it. Stream invocation correlation belongs to the subscription/publication relationship, not this field. |
|
|
4384
4559
|
|
|
4385
|
-
§env-delta-no-coalescing **Activity is never coalesced.** Each
|
|
4386
|
-
|
|
4560
|
+
§env-delta-no-coalescing **Activity is never coalesced.** Each eligible child
|
|
4561
|
+
action and each commons mutation has one occurrence identity. Combining
|
|
4387
4562
|
them would destroy causal order and conflate event replay with a state
|
|
4388
4563
|
comparison.
|
|
4389
4564
|
|
|
4390
|
-
§env-delta-passive **
|
|
4565
|
+
§env-delta-passive **Passive observation never forces a turn.** Deltas materialize only
|
|
4391
4566
|
while a packet is already assembling. Intermediate child activity and commons
|
|
4392
4567
|
broadcasts therefore cannot wake an idle worker. Urgent directed communication
|
|
4393
|
-
uses the voice door ({§actor-boundary-two-doors});
|
|
4394
|
-
|
|
4395
|
-
|
|
4568
|
+
uses the voice door ({§actor-boundary-two-doors}); child conclusions and addressed
|
|
4569
|
+
replies use {§worker-lifecycle-child-wake} and {§message-reply-delivery}.
|
|
4570
|
+
Stream progress remains owned by {§exec-stream}.
|
|
4396
4571
|
|
|
4397
4572
|
---
|
|
4398
4573
|
|
|
@@ -4423,12 +4598,12 @@ their boundaries ({§log-wire-format}).
|
|
|
4423
4598
|
| `inject` | system | Authored Markdown | {§packet-inject} |
|
|
4424
4599
|
| `log` | user | Markdown H3 records with JSON metadata | {§log-wire-format} |
|
|
4425
4600
|
| `worker` | user | JSON `path` with the literal Worker address, `parent` (address or `null`), `loop`, `turn` | {§packet-current-turn} |
|
|
4426
|
-
| `delegation` | user | JSON `{workers, streams}`
|
|
4601
|
+
| `delegation` | user | JSON `{workers, streams}` | {§child-orientation} |
|
|
4427
4602
|
| `errors` | user | JSON status/log-path pointers | {§operation-results} |
|
|
4428
4603
|
| `notices` | user | Terse observation bullets | {§notice-drain-on-read} |
|
|
4429
4604
|
| `git` | user | Working-tree state in a NOTE blockquote | {§packet-cache-monotone} |
|
|
4430
4605
|
| `budget` | user | JSON curation usage and ceiling; pressure guidance when needed | {§tokenomics-neutral-telemetry} |
|
|
4431
|
-
| `
|
|
4606
|
+
| `messages` | user | JSON pointers to the loop's unanswered immutable messages, path and source | {§message-arrival} |
|
|
4432
4607
|
| `recap` | user | Optional authored operational recap | {§recap} |
|
|
4433
4608
|
|
|
4434
4609
|
§packet-stored-shape **A model packet preserves the rendered request and, only
|
|
@@ -4528,50 +4703,92 @@ of section weights for the rendered request weight.
|
|
|
4528
4703
|
|
|
4529
4704
|
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 -->
|
|
4530
4705
|
|
|
4531
|
-
§encrypted-reasoning-carrier **Encrypted reasoning remains opaque provider evidence.**
|
|
4532
|
-
Original normalized provider responses retain every encrypted item, identity,
|
|
4533
|
-
format and ordering under {§provider-encrypted-reasoning}. Core neither decodes
|
|
4534
|
-
nor copies these blobs into source resources, log rows, client reasoning events
|
|
4535
|
-
or subsequent model requests. This is evidence retention, not native provider
|
|
4536
|
-
reasoning continuation. Readable reasoning remains independent.
|
|
4537
|
-
|
|
4538
4706
|
§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:
|
|
4539
4707
|
|
|
4540
4708
|
| row producer | ordinary visible projection |
|
|
4541
4709
|
|---|---|
|
|
4542
4710
|
| any `READ` or `FIND` | complete selected operation result |
|
|
4543
|
-
| `
|
|
4544
|
-
|
|
|
4711
|
+
| `NOTE`, `WAIT` | complete literal authored text |
|
|
4712
|
+
| inbound `SEND` from outside the workspace | budgeted head under {§message-projection} |
|
|
4545
4713
|
| structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
|
|
4546
4714
|
| every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
|
|
4547
4715
|
| bodyless row | metadata only; no coordinate lines; `logTokens` includes any selected native part |
|
|
4548
4716
|
|
|
4717
|
+
§markerless-first-page **Every markerless retrieval takes the same implicit marker.** A marker's
|
|
4718
|
+
unit is whatever its projection counts, so `PLURNK_SERVICE_PREVIEW_LINES` is the first page of
|
|
4719
|
+
all of them: lines of text, bytes of a byte view ({§read-bytes}), positions of a FIND. It is one
|
|
4720
|
+
choice with one home; no operation carries a page size of its own.
|
|
4721
|
+
|
|
4549
4722
|
Markerless text READs select their page with the same line/character bound as
|
|
4550
4723
|
ordinary previews, before result storage and packet rendering. Explicit scopes
|
|
4551
4724
|
remain exact. Automatic stream delivery uses that markerless selector too;
|
|
4552
4725
|
its range or region describes the selected content and the complete stream
|
|
4553
4726
|
remains addressable. This selection is not a second rendering-time cut.
|
|
4554
4727
|
|
|
4555
|
-
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result.
|
|
4556
|
-
|
|
4557
|
-
§prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt://<worker>/<loop>/<id>` as an explicitly addressed text/markdown entry — written before any turn of its loop executes — then published to its first model turn as one actionless lowercase `prompt` log row; that row, not the entry, records publication. No synthetic EDIT or READ operation is invented. The row is born visible and obeys {§body-projection}. The **Active Prompts** section closes the user-slot status clump as a paths-only list (`* prompt://<worker>/<loop>/<id>`), so every frame remains directly READable after its log row's body is suppressed or its active projection is retired.
|
|
4558
|
-
|
|
4559
|
-
§prompt-causal-source **Prompt authorship and delivery are distinct facts.** The harness publishes every prompt row with `origin="_plurnk"`; the row's existing `source` carries the canonical address of a different causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter may supply its own canonical actor address through {§methods-loop-run}. An absent source means the owning worker itself. Attribution persists with the prompt frame through active delivery, parking, orphan recovery, restart, and later log projection; model syntax cannot author it.
|
|
4560
|
-
|
|
4561
|
-
§prompt-projection **Prompt storage is unbounded by model context; automatic materialization is not.** Core persists every accepted prompt completely before packet assembly. The selected provider's derived `inputCapacity` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate curation-weight allowance for visible prompt bodies. Complete prompt bodies render when their aggregate weight fits. Otherwise all visible prompt rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries its exact `chunk` metadata. The canonical `prompt://<worker>/` entry remains complete and READ/FIND-addressable; its `log:///` body additionally obeys deliberate curation under {§log-readable-projection}. When provider input capacity is unknown the percentage is underivable, so prompt rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a prompt because it exceeds a context window.
|
|
4728
|
+
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. NOTE and lifecycle bodies are complete literal text while visible, never preview-clipped. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). Arrivals from outside the workspace follow their separate adaptive projection contract ({§message-projection}). Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Rejected-emission artifacts, SEND/WORK/FORK bodies, execution commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. 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.
|
|
4562
4729
|
|
|
4563
|
-
§
|
|
4730
|
+
§message-arrival **A message source, its log observations and its reply state are distinct.**
|
|
4564
4731
|
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
at
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4732
|
+
| Fact | Owner | Curation effect |
|
|
4733
|
+
|---|---|---|
|
|
4734
|
+
| Accepted body, attachments, address and causal source | Durable inbox message | None; ordinary READ/FIND/COPY can recover the source. |
|
|
4735
|
+
| Arrival seen at a turn boundary | One inbound SEND log row, `origin="_plurnk"`, `attrs.kind="message"` | Ordinary KILL can trim or remove this observation. |
|
|
4736
|
+
| Answered messages | Successful executed reply, {§send-response-receipt} | None; curation cannot retract delivery. |
|
|
4737
|
+
|
|
4738
|
+
Every accepted message enters its recipient loop's inbox in arrival order, with its selected
|
|
4739
|
+
paths, and publishes exactly once at the next turn boundary. **Open Messages** lists the
|
|
4740
|
+
unanswered messages by their immutable source address (`path`) and optional causal `source`,
|
|
4741
|
+
not a log coordinate. Each arrival receipt's `resource` names that same retained source.
|
|
4742
|
+
Trusted protocol modules supply message addresses in their own scheme;
|
|
4743
|
+
native arrivals use `message://<recipient>/<opaque-id>`, separate from the worker's
|
|
4744
|
+
actor and scratch addresses. Ordinary worker scratch remains writable. Source bodies
|
|
4745
|
+
are not edited or deleted through resource operations; independently curatable READs and
|
|
4746
|
+
arrival rows obey {§log-readable-projection}. No curation operation answers a message.
|
|
4747
|
+
Within a workspace an address identifies exactly one accepted message. Reusing it for
|
|
4748
|
+
another admission is a 409 conflict, not a second message or an implicit content update.
|
|
4749
|
+
|
|
4750
|
+
§message-reply-delivery **A reply is delivered once, not re-enqueued as a request.**
|
|
4751
|
+
|
|
4752
|
+
| Audience | Delivery | Effect |
|
|
4753
|
+
|---|---|---|
|
|
4754
|
+
| Assigned worker | Its conversation, even when another actor answered | Visible reply; wakes eligible parked work without a new Open Message or loop. |
|
|
4755
|
+
| Original native sender | That worker, if distinct from the assigned worker | The same reply, through the same wake and observation path. |
|
|
4756
|
+
| Exterior sender | The assigned conversation's protocol adapter | The adapter delivers the answer through its standard message channel. |
|
|
4757
|
+
| Replying actor | Its own executed SEND | No duplicate ambient occurrence. |
|
|
4758
|
+
|
|
4759
|
+
The successful SEND and its addressed occurrences commit together. Reply occurrences use
|
|
4760
|
+
the ordinary durable ambient cursor and wake revision; curation cannot revoke delivery or
|
|
4761
|
+
replay it. An addressed reply replaces the same parent's generic activity observation.
|
|
4762
|
+
Child completion is a separate READ of its execution outcome; replies are not outcome bodies.
|
|
4763
|
+
The complete outcome remains available at its {§worker-loop-result} address.
|
|
4764
|
+
Unobserved replies prevent conclusion just as unobserved child results do. All operation
|
|
4765
|
+
producers notify the same settlement path after durable execution; reply wake-up shares
|
|
4766
|
+
{§worker-optimistic-settlement}, without delaying the replying program.
|
|
4767
|
+
|
|
4768
|
+
§message-short-identity **The model addresses a message by its short name.** Every message carries
|
|
4769
|
+
`message://<worker>/<key>` (`key_path`), the form the worker docs teach, and that is what the packet
|
|
4770
|
+
shows in Open Messages and in an arrival row's `resource`. A client's own identity for the same
|
|
4771
|
+
message — an AG-UI message UUID, an A2A address — stays the durable `path` that correlation,
|
|
4772
|
+
delivery and reply accounting use, and remains addressable in its own scheme; the short form is an
|
|
4773
|
+
additional alias. Answering either reaches the same message. Origin (operator, 2026-09-18): the
|
|
4774
|
+
packet showed a 77-character `agui://anonymous/threads/…/messages/<uuid>` twice per open message,
|
|
4775
|
+
while the docs taught the short form.
|
|
4776
|
+
|
|
4777
|
+
§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 bridge names the client's message under `agui://` ({§agui-run-source}), the inbound A2A adapter under `a2a://`. An absent source means the owning worker itself. 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` and omits its `origin`, which is constant for every arrival; the Open Messages pointer carries the same source ({§message-arrival}) — except where the source is the transport that minted this very message, which says nothing the address does not ({§message-short-identity}).
|
|
4778
|
+
|
|
4779
|
+
§message-projection **Message storage is unbounded by model context; automatic materialization is not.** Core persists every accepted message completely before packet assembly. The selected provider's derived `inputCapacity` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate curation-weight allowance for the visible bodies of arrivals other than a peer worker's — every `source` that is not a `worker://` address, the loop's own assignment included. Complete bodies render when their aggregate weight fits. Otherwise all such visible rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries `preview` under {§packet-extent-metadata}. The row remains complete and READable by coordinate; its `log:///` body additionally obeys deliberate curation under {§log-readable-projection}. A peer worker's message takes the ordinary bounds. When provider input capacity is unknown the percentage is underivable, so arrival rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a message because it exceeds a context window.
|
|
4780
|
+
|
|
4781
|
+
§message-loop-containment A loop contains every message that arrives before it
|
|
4782
|
+
concludes; the next turn boundary publishes every inbox row the loop has not yet
|
|
4783
|
+
published, oldest first, and stamps each with the row it became. Ordinal 1 is the loop's
|
|
4784
|
+
own assignment and shares the loop's fate: a loop that fails before its first turn does
|
|
4785
|
+
not replay it. Every other still-unpublished message at conclusion moves into one
|
|
4786
|
+
source-keyed recovery loop, renumbered from its first, whose headline it becomes; that loop's first turn publishes the complete
|
|
4787
|
+
ordered set exactly once. Recovery retries complete the same queued loop and never
|
|
4788
|
+
mint duplicate work. Output withholding preserves readable arrival rows; explicit
|
|
4789
|
+
KILL follows the ordinary log contract.
|
|
4790
|
+
|
|
4791
|
+
§completion-defers-to-messages **Conclusion does not cross an unanswered arrival.** The end-of-program check includes messages that arrived during inference. The final database transition rechecks unanswered messages atomically. An arrival that wins the race continues the current loop; one admitted after conclusion belongs to a new loop. Orphan recovery preserves messages accepted before an independently forced termination.
|
|
4575
4792
|
|
|
4576
4793
|
§packet-catalog **Catalogs are query results, not packet state.** The packet
|
|
4577
4794
|
stores no materialized manifest. Complete and one-level entry directories,
|
|
@@ -4601,7 +4818,8 @@ retain distinct contracts and lifetimes.
|
|
|
4601
4818
|
an unfittable retained context fails before inference ({§context-output-hard-413}).
|
|
4602
4819
|
- §log-row-self-explains **Every ≥400 pointer names a record that states its
|
|
4603
4820
|
why.** A model-operation failure is the model's own operation result; its
|
|
4604
|
-
Problem Details `instance`
|
|
4821
|
+
Problem Details `instance` retains the originating occurrence URI; when absent,
|
|
4822
|
+
persistence assigns that row's `log:///` URI. Packet wire renders
|
|
4605
4823
|
the contracts-owned compact `{§problem-projection}` on its meta line whether
|
|
4606
4824
|
its body is visible or suppressed. The enclosing row owns status, model-facing path, source, and target;
|
|
4607
4825
|
an identical extension is not repeated inside the projection. No
|
|
@@ -4611,9 +4829,9 @@ retain distinct contracts and lifetimes.
|
|
|
4611
4829
|
failure status, a top-level string `error`, or mismatched result/problem
|
|
4612
4830
|
statuses violate the producer contract and fail hard. Genuine
|
|
4613
4831
|
engine-internal faults crash and never mint model-facing rows.
|
|
4614
|
-
- **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
|
|
4832
|
+
- **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.
|
|
4615
4833
|
- **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`.
|
|
4616
|
-
- **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
|
|
4834
|
+
- **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, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
|
|
4617
4835
|
- **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.
|
|
4618
4836
|
- §notice-drain-on-read **Notices** - the few observations that are not log rows render one terse line under their distinct `## Notices` section, 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. 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.
|
|
4619
4837
|
- §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.
|
|
@@ -4630,7 +4848,7 @@ retain distinct contracts and lifetimes.
|
|
|
4630
4848
|
|---|---|---|
|
|
4631
4849
|
| `grammar_unenforced` | engine rail verdict, or a forwarded provider transport anomaly such as a discarded-channel escape | content-offset when the observed position maps into content; none for a reasoning-prefix divergence |
|
|
4632
4850
|
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
|
|
4633
|
-
| `search_progress` | repository materialization/indexing lifecycle ({§
|
|
4851
|
+
| `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 |
|
|
4634
4852
|
| `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 |
|
|
4635
4853
|
|
|
4636
4854
|
§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 `grammar_unenforced` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
|
|
@@ -4645,7 +4863,8 @@ retain distinct contracts and lifetimes.
|
|
|
4645
4863
|
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
4646
4864
|
| Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its package-owned SqlRite statements; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
|
|
4647
4865
|
| `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
|
|
4648
|
-
| `digestDir` | Selects
|
|
4866
|
+
| `digestDir` | Selects a nonempty output directory. Both `run` and `requiem` refuse an output containing the input pathname or its resolved database before database/provider I/O or output writes; normalized and real paths participate in that check. `run` removes and recreates output so stale artifacts cannot survive; concurrent callers use distinct directories. |
|
|
4867
|
+
| Reader lifetime | Both methods close their database reader on successful or failed reads, before rendering output or awaiting witness inference. |
|
|
4649
4868
|
| `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. |
|
|
4650
4869
|
| `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, when both selectors are present they intersect. |
|
|
4651
4870
|
|
|
@@ -4655,7 +4874,7 @@ retain distinct contracts and lifetimes.
|
|
|
4655
4874
|
|
|
4656
4875
|
§digest-wire-line **Wire health aggregated.** Each worker summary renders a `Wire:` line — total physical provider requests, error-outcome count, and the error percentage when nonzero. Provider-level failures are absorbed by retries below the packet stream, so without this aggregate a rate-limit storm is invisible in every summary while the model's experience stays clean.
|
|
4657
4876
|
|
|
4658
|
-
§digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`,
|
|
4877
|
+
§digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`, and structured `attrs`; every exact log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result, settlement time, scheduled due time, recurring interval, and recurrence lineage; and every ordered physical provider request. Programs still produce chronological `assistant.md` artifacts after every READ receipt is KILLed; source is independent of log curation. Each stored packet validates independently: one malformed historical packet remains exact raw evidence with its complete validation error chain and never prevents healthy turns from being projected. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. A worker's Cost line names how many settled requests carry no usage at all (errored or aborted exchanges) — their server-side spend is unrecorded rather than silently priced as zero. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
|
|
4659
4878
|
|
|
4660
4879
|
Unrecognized actionless log rows are retained and labelled as such, not
|
|
4661
4880
|
interpreted as executable turnOps or allowed to prevent the remaining digest.
|
|
@@ -4677,7 +4896,7 @@ turn.** It cannot execute operations or alter the audited history.
|
|
|
4677
4896
|
| Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
|
|
4678
4897
|
| Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. Quoted evidence is budgeted to the witness window ({§digest-requiem-evidence-budget}). |
|
|
4679
4898
|
| Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
|
|
4680
|
-
| Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as
|
|
4899
|
+
| Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as the `workerId`, without asserting a live worker topology. |
|
|
4681
4900
|
| Attempts | One call at `PLURNK_SERVICE_REQUIEM_MAX_TOKENS`; only an empty length-limited response receives one retry at `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS`. |
|
|
4682
4901
|
| Artifacts | `requiem.md` carries testimony and exact nullable USD accounting. `requiem.json` is durably materialized before each call and preserves logical call state, messages, normalized responses, every physical request's state and accounting, and their shared aggregate projection. |
|
|
4683
4902
|
|
|
@@ -4697,9 +4916,9 @@ USD, and token totals across every physical exchange the turn paid for, failed
|
|
|
4697
4916
|
calls included. It is the shared exact derivation from the ledger, never a second
|
|
4698
4917
|
stored fact, so a live watcher accrues running loop cost per turn (#465).
|
|
4699
4918
|
|
|
4700
|
-
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops
|
|
4919
|
+
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops://<worker>/<loop>/<turn>` source. 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.
|
|
4701
4920
|
|
|
4702
|
-
###
|
|
4921
|
+
### Executable tool resources
|
|
4703
4922
|
|
|
4704
4923
|
§tools-resource-discovery **Executable capability discovery uses ordinary
|
|
4705
4924
|
Plurnk resources.** No generated tool table rides the system packet. Every
|
|
@@ -4716,7 +4935,9 @@ preserve the full tool description and raw input schema under
|
|
|
4716
4935
|
{§executor-input-schema-preview}; their nested paths do not contribute extra
|
|
4717
4936
|
Turn0 rows. A schema-backed general runtime uses `<runtime>/input.md`.
|
|
4718
4937
|
Non-schema targets retain supplemental details in family sections.
|
|
4719
|
-
Tool-result/output schemas remain ordinary evidence, not teaching.
|
|
4938
|
+
Tool-result/output schemas remain ordinary evidence, not teaching. Unknown-target
|
|
4939
|
+
recovery names the published family document through the same path owner as
|
|
4940
|
+
materialization, including a runtime's declared `resourcesPath`.
|
|
4720
4941
|
|
|
4721
4942
|
```mermaid
|
|
4722
4943
|
flowchart LR
|
|
@@ -4781,7 +5002,7 @@ untracked, absent); a glob previews what `add` would include or exclude. Names o
|
|
|
4781
5002
|
content; nothing is added.
|
|
4782
5003
|
|
|
4783
5004
|
§members-configuration *Available definitions.* The operator's `PLURNK_MEMBERS_<ALIAS>=<glob>`
|
|
4784
|
-
(`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (
|
|
5005
|
+
(`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (`[]` enables none) are the
|
|
4785
5006
|
service-origin definitions, the shape `PLURNK_MCP_*` already has; an empty glob, a bare `!`,
|
|
4786
5007
|
or an unknown enabled alias fails the daemon at boot.
|
|
4787
5008
|
|
|
@@ -4840,7 +5061,9 @@ contributes nothing and is refused with 400.
|
|
|
4840
5061
|
|
|
4841
5062
|
*Admission.* `add {alias, definition}` requires `alias = name`, a `source`,
|
|
4842
5063
|
and a project root when `scope` is `project`; the workspace definition may
|
|
4843
|
-
shadow a service skill of the same name.
|
|
5064
|
+
shadow a service skill of the same name. The family's aliases use the standard
|
|
5065
|
+
skill-name grammar ({§agent-skills-name}), including digit-leading and Unicode
|
|
5066
|
+
names, rather than the coordinator's generic default.
|
|
4844
5067
|
|
|
4845
5068
|
*Preparation.* For each enabled alias the adapter selects the host-provided
|
|
4846
5069
|
tree for `service` scope or locates the directory at the filesystem scope;
|
|
@@ -4867,6 +5090,9 @@ The family exposes enabled, available {§agent-skills-tree} sources through
|
|
|
4867
5090
|
`skill://<name>/`. The source owns its bytes; commons entries are demand-loaded
|
|
4868
5091
|
projections, not writable installations. Filesystem skills retain their original
|
|
4869
5092
|
directories; service-provided trees need no generated filesystem directory.
|
|
5093
|
+
The authority is the name's WHATWG URI representation, including percent-encoding
|
|
5094
|
+
for non-ASCII names. Installation names remain unchanged; a raw spelling and its
|
|
5095
|
+
serialized URI address the same resource, not separate skill identities.
|
|
4870
5096
|
|
|
4871
5097
|
| Operation | Contract |
|
|
4872
5098
|
| --- | --- |
|
|
@@ -4885,7 +5111,7 @@ An uninstalled Git skill is not manufactured by repository detection.
|
|
|
4885
5111
|
|
|
4886
5112
|
§plurnk-skill **Plurnk's own reference is an ordinary service-provided skill.**
|
|
4887
5113
|
`skill://plurnk/SKILL.md` is the standard frontmatter entry point, catalogued with
|
|
4888
|
-
other enabled skills. It links package-owned configuration and
|
|
5114
|
+
other enabled skills. It links package-owned configuration, model, and COPY/MOVE chapters,
|
|
4889
5115
|
the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`, and the
|
|
4890
5116
|
Worker's existing tool/resource references. No chapter or defaults body is
|
|
4891
5117
|
injected merely because the skill is enabled. The defaults bytes come from the
|
|
@@ -4920,7 +5146,7 @@ same exact 403 from dispatch rather than a second documentation policy.
|
|
|
4920
5146
|
Optional non-execution operations remain a separate `## Enabled Optional Operations`
|
|
4921
5147
|
section because they are language extensions rather than executable tools.
|
|
4922
5148
|
|
|
4923
|
-
###
|
|
5149
|
+
### Scheme-reference discovery
|
|
4924
5150
|
|
|
4925
5151
|
§schemes-directory Scheme references are ordinary workspace entries at `worker:///_plurnk/plurnk/<scheme>.md`. Turn0's FIND survey projects their summaries ({§worker-initialization-entry}); the model READs details on demand. No Resources section or separate example catalog is injected into the system packet.
|
|
4926
5152
|
|
|
@@ -4938,7 +5164,7 @@ section because they are language extensions rather than executable tools.
|
|
|
4938
5164
|
|
|
4939
5165
|
### §policy system.policy — the client's policy injection
|
|
4940
5166
|
|
|
4941
|
-
§policy-sections One section rides the system slot **after the definition**: the contents of `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}), with no engine-generated heading. The policy document owns its Markdown structure. Policy is the client's authoritative rules promoted into the privileged zone — NOT a log entry; the model cannot READ or KILL it. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker:///_plurnk/
|
|
5167
|
+
§policy-sections One section rides the system slot **after the definition**: the contents of `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}), with no engine-generated heading. The policy document owns its Markdown structure. Policy is the client's authoritative rules promoted into the privileged zone — NOT a log entry; the model cannot READ or KILL it. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker:///_plurnk/AGENTS.md` entry ({§turn0-agents-stunt}); references and skills use native discovery ({§skills-functionality}).
|
|
4942
5168
|
|
|
4943
5169
|
On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
|
|
4944
5170
|
`AGENTS.md` from `@plurnk/plurnk-meta/POLICY.md` ({§teaching-corpus}).
|
|
@@ -4966,7 +5192,7 @@ the transition.
|
|
|
4966
5192
|
When Git is admitted for the workspace, `## Git Status` contains a Markdown
|
|
4967
5193
|
`> [!NOTE]` block. Its quoted lines report the current
|
|
4968
5194
|
branch, upstream ahead/behind counts, and staged/unstaged/untracked totals, then
|
|
4969
|
-
one bounded line per non-empty class (at most
|
|
5195
|
+
one bounded line per non-empty class (at most `PLURNK_SERVICE_GIT_STATUS_PATHS` paths, `+K more`): staged,
|
|
4970
5196
|
unstaged, `untracked members` — each path with the inclusion pattern that admits it or
|
|
4971
5197
|
`created` for a creation record — and `untracked (not members)`, named because such a
|
|
4972
5198
|
file is not a member ({§membership-baseline}) and a human must `git add` it or add a
|
|
@@ -4976,6 +5202,10 @@ the runtime actor's durable causal evidence: its `source=file` row carries
|
|
|
4976
5202
|
the exact two-character porcelain `XY` value as `git` metadata when the status
|
|
4977
5203
|
snapshot names that path. The engine takes one snapshot after membership
|
|
4978
5204
|
reconciliation and uses it for both projections; no per-file Git process exists.
|
|
5205
|
+
Porcelain v2 NUL-delimited records supply these facts: an unborn branch retains
|
|
5206
|
+
its actual name with `no commits`; detached HEAD is identified as detached,
|
|
5207
|
+
never as a branch named `HEAD`. Pathnames and rename sources retain their exact
|
|
5208
|
+
bytes; the internal two-character status uses spaces for unchanged coordinates.
|
|
4979
5209
|
|
|
4980
5210
|
### §recap Optional Recap footer
|
|
4981
5211
|
|
|
@@ -4988,7 +5218,7 @@ one dormant authored source. A failed read fails packet assembly with its cause.
|
|
|
4988
5218
|
The footer is one projection path and one authored source, not a second language
|
|
4989
5219
|
contract.
|
|
4990
5220
|
|
|
4991
|
-
##
|
|
5221
|
+
## Matcher selection and text regions
|
|
4992
5222
|
|
|
4993
5223
|
Matchers select resources and report evidence; text scopes independently
|
|
4994
5224
|
address the exact readable text, regardless of mimetype. Syntax belongs to
|
|
@@ -5050,7 +5280,7 @@ one binary marker to fail a repository-wide text search.
|
|
|
5050
5280
|
Glob anchoring (`TODO*` starts-with, `*TODO*` contains, `*.log` ends-with,
|
|
5051
5281
|
`[Tt]odo*` character class) lives in the mimetypes framework.
|
|
5052
5282
|
|
|
5053
|
-
###
|
|
5283
|
+
### Matcher selection and evidence
|
|
5054
5284
|
|
|
5055
5285
|
- §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{channel?,locator?,region?}`; `channel` names the entry channel the finding was located in and is absent for channel-less resources such as log rows, so line coordinates cannot be mis-attributed across channels of the same resource ({§channel-selection-visibility}). `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
|
|
5056
5286
|
|
|
@@ -5132,7 +5362,7 @@ an existing channel retain its stored type. Effective mimetype is stored in
|
|
|
5132
5362
|
`entry_channels.mimetype` and drives matcher, projection, and binary handling.
|
|
5133
5363
|
Text scope meaning does not vary by mimetype.
|
|
5134
5364
|
|
|
5135
|
-
###
|
|
5365
|
+
### Render rule
|
|
5136
5366
|
|
|
5137
5367
|
§render-rule-line-navigable-prefix Every textual content body with a source
|
|
5138
5368
|
`startLine` renders with a coordinate prefix on each physical line, independent
|
|
@@ -5147,13 +5377,13 @@ presentation aid, never part of canonical content; matchers and mutations
|
|
|
5147
5377
|
consume canonical bytes before rendering. A producer may set `startLine: null`
|
|
5148
5378
|
only when its content is already source-numbered, such as an effect receipt.
|
|
5149
5379
|
|
|
5150
|
-
§render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT and scoped entry KILL use their structured receipt, while environment-delta EDIT uses its resulting span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`;
|
|
5380
|
+
§render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT and scoped entry KILL use their structured receipt, while environment-delta EDIT uses its resulting span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; NOTE and lifecycle operations retain their literal `text/plain` bodies; executions and SEND/WORK/FORK use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search use the same body with deliberate trims applied under {§log-readable-projection}, without packet-only suppression or preview limits. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
|
|
5151
5381
|
|
|
5152
5382
|
An EDIT or scoped entry KILL log row renders its bounded effect receipt (`rx.receipt`) as row
|
|
5153
5383
|
metadata and join context, not its input statement. Proposal-gated file EDITs
|
|
5154
5384
|
compute the accepted receipt from what actually lands. Environment-delta EDITs
|
|
5155
5385
|
render their resulting `rx.span`. COPY/MOVE rows render compact ordered
|
|
5156
|
-
`
|
|
5386
|
+
`from` and `to` selections ({§log-address-metadata}), compact ordered `effects` metadata, and
|
|
5157
5387
|
any scoped textual receipt contexts under their `log:///` address, never under
|
|
5158
5388
|
one operand's resource address. All generated bodies remain under
|
|
5159
5389
|
{§body-projection}. {§edit-result-render}
|
|
@@ -5195,7 +5425,7 @@ Carried from the contract walk; durable.
|
|
|
5195
5425
|
Any scoped textual transfer materializes create/update receipts; whole-channel
|
|
5196
5426
|
changes do not. Operand selections remain independently visible per
|
|
5197
5427
|
{§copy-move-observation}.
|
|
5198
|
-
- **READ rx** prefixes every textual line under {§render-rule}; eligible
|
|
5428
|
+
- **READ rx** prefixes every textual line under {§render-rule-line-navigable-prefix}; eligible
|
|
5199
5429
|
editable resources carry `@hash N:`, and all others carry `N:`.
|
|
5200
5430
|
- **FIND pattern** (`[{"pattern": …}]` in the heading, {§matcher-option}) applies to the addressed entry channel (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope and channel select candidates; the path-glob is the (target). On READ, EDIT, KILL, COPY and MOVE the same heading pattern selects lines within one resource ({§read-pattern}, {§edit-pattern}, {§kill-pattern}, {§copy-move-pattern}).
|
|
5201
5431
|
- **Scoped KILL** on the **log** (`log:///`) removes a body span from its readable projection ({§log-kill-scope}); on an entry it deletes that span through the EDIT path ({§kill-scope-entry}). A whole-entry KILL deletes the entry, or one `#fragment` channel.
|
|
@@ -5209,7 +5439,7 @@ A KILL with a text-coordinate scope aimed at an entry-bearing scheme deletes exa
|
|
|
5209
5439
|
|
|
5210
5440
|
---
|
|
5211
5441
|
|
|
5212
|
-
##
|
|
5442
|
+
## Testing and evidence
|
|
5213
5443
|
|
|
5214
5444
|
| Tier | Location | LLM | Substrate |
|
|
5215
5445
|
|---|---|---|---|
|
|
@@ -5241,15 +5471,13 @@ execution. The ledger and classification taxonomy live in
|
|
|
5241
5471
|
distinct from model failures and repeated stochastic failures separately from
|
|
5242
5472
|
stable ones, never with weakened assertions.
|
|
5243
5473
|
|
|
5244
|
-
§test-artifact-retention **
|
|
5245
|
-
|
|
5246
|
-
`
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
explicitly when isolation matters. Live/demo run directories are benchmark
|
|
5255
|
-
artifacts outside `.tmp` and retain their separate lifecycle.
|
|
5474
|
+
§test-artifact-retention **Every harness writes its run into one home.** A file-backed test
|
|
5475
|
+
database is a benchmark artifact like any other: the lane's run directory lives under
|
|
5476
|
+
`PLURNK_BENCHMARKS` (`~/benchmarks` by default) beside live, demo and benchlet runs, and the
|
|
5477
|
+
checkout holds source only — never run output. `test:intg` stamps `PLURNK_TEST_RUN` once and every
|
|
5478
|
+
test process inherits it, so one suite's databases land in one directory without a pretest step, a
|
|
5479
|
+
marker file or a sweep; an unstamped invocation is not a special case with its own rules, it is
|
|
5480
|
+
simply an unstamped run with its own directory. Nothing counts, reuses, moves, hides or
|
|
5481
|
+
conditionally clears an artifact, so a failed suite's evidence is exactly where the run reported
|
|
5482
|
+
it. A cross-package test may reuse Core's migration fixture only by passing a path inside the
|
|
5483
|
+
caller's own run directory.
|