@plurnk/plurnk-service 1.29.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.defaults +14 -33
- package/INSTALL.md +68 -17
- package/README.md +9 -7
- package/SPEC.md +503 -741
- package/dist/build-info.json +1 -1
- package/dist/content/body-preview.d.ts.map +1 -1
- package/dist/content/body-preview.js +11 -2
- package/dist/content/body-preview.js.map +1 -1
- package/dist/content/edit-receipt.d.ts +1 -1
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +1 -1
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/line-marker.js +1 -1
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/path-mimetype.js +1 -1
- package/dist/content/path-mimetype.js.map +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +3 -12
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/AdministrativeLoop.d.ts +1 -1
- package/dist/core/AdministrativeLoop.d.ts.map +1 -1
- package/dist/core/AdministrativeLoop.js +2 -6
- package/dist/core/AdministrativeLoop.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts +4 -3
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +19 -17
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BareBatchRunner.d.ts +2 -2
- package/dist/core/BareBatchRunner.d.ts.map +1 -1
- package/dist/core/BareBatchRunner.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +1 -0
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +12 -0
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +2 -4
- package/dist/core/CapabilityPolicies.d.ts.map +1 -1
- package/dist/core/CapabilityPolicies.js +3 -23
- package/dist/core/CapabilityPolicies.js.map +1 -1
- package/dist/core/CapabilityResolver.d.ts +9 -2
- package/dist/core/CapabilityResolver.d.ts.map +1 -1
- package/dist/core/CapabilityResolver.js +34 -5
- package/dist/core/CapabilityResolver.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +0 -2
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ClientInteractions.d.ts +3 -2
- package/dist/core/ClientInteractions.d.ts.map +1 -1
- package/dist/core/ClientInteractions.js +21 -12
- package/dist/core/ClientInteractions.js.map +1 -1
- package/dist/core/ClientInteractions.sql +8 -2
- package/dist/core/CoreSchemeServices.d.ts +1 -0
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +1 -0
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/DataStatementRunner.js +1 -1
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +3 -2
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +15 -21
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +2 -2
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +4 -3
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/EnvFlags.d.ts.map +1 -1
- package/dist/core/EnvFlags.js +4 -3
- package/dist/core/EnvFlags.js.map +1 -1
- package/dist/core/ExecutorRegistry.d.ts +3 -17
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +6 -6
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/FabricatedLog.js +1 -1
- package/dist/core/FabricatedLog.js.map +1 -1
- package/dist/core/HostPaths.d.ts +2 -1
- package/dist/core/HostPaths.d.ts.map +1 -1
- package/dist/core/HostPaths.js +14 -2
- package/dist/core/HostPaths.js.map +1 -1
- package/dist/core/KillHandler.js +1 -1
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/LogVisibility.d.ts.map +1 -1
- package/dist/core/LogVisibility.js +8 -17
- package/dist/core/LogVisibility.js.map +1 -1
- package/dist/core/LoopDriver.d.ts.map +1 -1
- package/dist/core/LoopDriver.js +4 -6
- package/dist/core/LoopDriver.js.map +1 -1
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +4 -9
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +6 -6
- package/dist/core/OperatorConfig.d.ts +1 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -1
- package/dist/core/OperatorConfig.js +10 -2
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +5 -7
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +49 -119
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +15 -0
- package/dist/core/ProposalLifecycle.d.ts +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +18 -20
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProposalPolicies.d.ts +6 -0
- package/dist/core/ProposalPolicies.d.ts.map +1 -0
- package/dist/core/ProposalPolicies.js +28 -0
- package/dist/core/ProposalPolicies.js.map +1 -0
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +3 -4
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ResourceSelector.js +2 -2
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.js +3 -3
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/RuntimeWorker.sql +1 -2
- package/dist/core/SchemeRegistry.d.ts +5 -4
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +11 -12
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ToolInputSchema.d.ts +1 -0
- package/dist/core/ToolInputSchema.d.ts.map +1 -1
- package/dist/core/ToolInputSchema.js +8 -2
- package/dist/core/ToolInputSchema.js.map +1 -1
- package/dist/core/ToolResources.d.ts +1 -0
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +12 -6
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/Turn.js +1 -1
- package/dist/core/Turn.js.map +1 -1
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
- package/dist/core/TurnDispositionHandler.js +1 -7
- package/dist/core/TurnDispositionHandler.js.map +1 -1
- package/dist/core/TurnMaterialization.js +1 -1
- package/dist/core/TurnMaterialization.js.map +1 -1
- package/dist/core/TurnOps.d.ts +1 -1
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +4 -12
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts +1 -2
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +85 -81
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerControlHandler.d.ts.map +1 -1
- package/dist/core/WorkerControlHandler.js +1 -8
- package/dist/core/WorkerControlHandler.js.map +1 -1
- package/dist/core/WorkerName.d.ts +1 -0
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +2 -0
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +2 -2
- package/dist/core/WorkerOwners.d.ts +13 -0
- package/dist/core/WorkerOwners.d.ts.map +1 -0
- package/dist/core/WorkerOwners.js +44 -0
- package/dist/core/WorkerOwners.js.map +1 -0
- package/dist/core/WorkerOwners.sql +55 -0
- package/dist/core/caps/DbNotifyCaps.js +2 -2
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +1 -1
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/env-catalog.d.ts +3 -0
- package/dist/core/env-catalog.d.ts.map +1 -1
- package/dist/core/env-catalog.js +44 -9
- package/dist/core/env-catalog.js.map +1 -1
- package/dist/core/env-defaults.d.ts +2 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js +17 -9
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/fork.sql +3 -4
- package/dist/core/packet-inject.js +0 -2
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +2 -11
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +31 -111
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +4 -4
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/scheme-types.d.ts +2 -1
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/types.d.ts +0 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.d.ts +1 -3
- package/dist/core/unregistered-scheme.d.ts.map +1 -1
- package/dist/core/unregistered-scheme.js +3 -11
- package/dist/core/unregistered-scheme.js.map +1 -1
- package/dist/evidence/EvidenceReader.d.ts +14 -0
- package/dist/evidence/EvidenceReader.d.ts.map +1 -0
- package/dist/evidence/EvidenceReader.js +137 -0
- package/dist/evidence/EvidenceReader.js.map +1 -0
- package/dist/{digest → evidence}/digest.sql +1 -2
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +1 -10
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +19 -26
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +11 -17
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +14 -11
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +1 -3
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/{Skill.d.ts → ResourceTreeScheme.d.ts} +5 -6
- package/dist/schemes/ResourceTreeScheme.d.ts.map +1 -0
- package/dist/schemes/{Skill.js → ResourceTreeScheme.js} +63 -43
- package/dist/schemes/ResourceTreeScheme.js.map +1 -0
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +7 -9
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +1 -1
- package/dist/schemes/_entry-find.js +2 -2
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +1 -1
- package/dist/schemes/_entry-fts.d.ts.map +1 -1
- package/dist/schemes/_entry-fts.js +3 -9
- package/dist/schemes/_entry-fts.js.map +1 -1
- package/dist/schemes/_entry-manifest.js +1 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.js +1 -1
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/server/AgentRoots.d.ts +2 -1
- package/dist/server/AgentRoots.d.ts.map +1 -1
- package/dist/server/AgentRoots.js +13 -10
- package/dist/server/AgentRoots.js.map +1 -1
- package/dist/server/ConfigurationDiagnostics.d.ts +5 -3
- package/dist/server/ConfigurationDiagnostics.d.ts.map +1 -1
- package/dist/server/ConfigurationDiagnostics.js +24 -8
- package/dist/server/ConfigurationDiagnostics.js.map +1 -1
- package/dist/server/Daemon.d.ts +25 -16
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +137 -96
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +1 -4
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +1 -11
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/EnvFunctionality.d.ts +3 -5
- package/dist/server/EnvFunctionality.d.ts.map +1 -1
- package/dist/server/EnvFunctionality.js +5 -7
- package/dist/server/EnvFunctionality.js.map +1 -1
- package/dist/server/Functionality.d.ts +3 -2
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +43 -14
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +3 -4
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +17 -9
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/HttpListener.d.ts +2 -0
- package/dist/server/HttpListener.d.ts.map +1 -1
- package/dist/server/HttpListener.js +23 -9
- package/dist/server/HttpListener.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +2 -5
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +5 -3
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/ModuleHost.d.ts +33 -0
- package/dist/server/ModuleHost.d.ts.map +1 -0
- package/dist/server/ModuleHost.js +2 -0
- package/dist/server/ModuleHost.js.map +1 -0
- package/dist/server/PlurnkSkill.d.ts.map +1 -1
- package/dist/server/PlurnkSkill.js +54 -6
- package/dist/server/PlurnkSkill.js.map +1 -1
- package/dist/server/ServiceModules.d.ts +0 -2
- package/dist/server/ServiceModules.d.ts.map +1 -1
- package/dist/server/ServiceModules.js +5 -9
- package/dist/server/ServiceModules.js.map +1 -1
- package/dist/server/WorkspacePlugins.d.ts +2 -11
- package/dist/server/WorkspacePlugins.d.ts.map +1 -1
- package/dist/server/WorkspacePlugins.js.map +1 -1
- package/dist/server/WorkspaceResidency.d.ts +2 -1
- package/dist/server/WorkspaceResidency.d.ts.map +1 -1
- package/dist/server/WorkspaceStorage.d.ts.map +1 -1
- package/dist/server/WorkspaceStorage.js +7 -4
- package/dist/server/WorkspaceStorage.js.map +1 -1
- package/dist/server/client-input.d.ts +1 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +2 -13
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +1 -1
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +6 -6
- package/dist/server/envelope.d.ts +2 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +7 -17
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +5 -5
- package/dist/server/module-discovery.d.ts +11 -3
- package/dist/server/module-discovery.d.ts.map +1 -1
- package/dist/server/module-discovery.js +32 -18
- package/dist/server/module-discovery.js.map +1 -1
- package/dist/server/seam-proposal-list.sql +6 -4
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +58 -65
- package/dist/service.js.map +1 -1
- package/migrations/003_loops.sql +2 -2
- package/migrations/006_log.sql +1 -1
- package/migrations/016_selection_statements.sql +44 -0
- package/migrations/017_skills_module.sql +6 -0
- package/migrations/018_worker_owners.sql +102 -0
- package/migrations/019_interactive_owners.sql +6 -0
- package/migrations/020_log_projection.sql +143 -0
- package/package.json +71 -76
- package/dist/core/EmissionHead.d.ts +0 -8
- package/dist/core/EmissionHead.d.ts.map +0 -1
- package/dist/core/EmissionHead.js +0 -29
- package/dist/core/EmissionHead.js.map +0 -1
- package/dist/core/LegacyHome.d.ts +0 -10
- package/dist/core/LegacyHome.d.ts.map +0 -1
- package/dist/core/LegacyHome.js +0 -170
- package/dist/core/LegacyHome.js.map +0 -1
- package/dist/core/LoopPolicies.d.ts +0 -7
- package/dist/core/LoopPolicies.d.ts.map +0 -1
- package/dist/core/LoopPolicies.js +0 -42
- package/dist/core/LoopPolicies.js.map +0 -1
- package/dist/core/LoopPolicyReader.d.ts +0 -7
- package/dist/core/LoopPolicyReader.d.ts.map +0 -1
- package/dist/core/LoopPolicyReader.js +0 -33
- package/dist/core/LoopPolicyReader.js.map +0 -1
- package/dist/core/LoopPolicyReader.sql +0 -6
- package/dist/core/operation-target-groups.d.ts +0 -3
- package/dist/core/operation-target-groups.d.ts.map +0 -1
- package/dist/core/operation-target-groups.js +0 -77
- package/dist/core/operation-target-groups.js.map +0 -1
- package/dist/digest/Digest.d.ts +0 -10
- package/dist/digest/Digest.d.ts.map +0 -1
- package/dist/digest/Digest.js +0 -252
- package/dist/digest/Digest.js.map +0 -1
- package/dist/digest/DigestEvidence.d.ts +0 -11
- package/dist/digest/DigestEvidence.d.ts.map +0 -1
- package/dist/digest/DigestEvidence.js +0 -66
- package/dist/digest/DigestEvidence.js.map +0 -1
- package/dist/digest/DigestRender.d.ts +0 -18
- package/dist/digest/DigestRender.d.ts.map +0 -1
- package/dist/digest/DigestRender.js +0 -1044
- package/dist/digest/DigestRender.js.map +0 -1
- package/dist/digest/DigestRequiem.d.ts +0 -13
- package/dist/digest/DigestRequiem.d.ts.map +0 -1
- package/dist/digest/DigestRequiem.js +0 -337
- package/dist/digest/DigestRequiem.js.map +0 -1
- package/dist/digest/digest-db.d.ts +0 -3
- package/dist/digest/digest-db.d.ts.map +0 -1
- package/dist/digest/digest-db.js +0 -68
- package/dist/digest/digest-db.js.map +0 -1
- package/dist/digest/digest-paths.d.ts +0 -6
- package/dist/digest/digest-paths.d.ts.map +0 -1
- package/dist/digest/digest-paths.js +0 -14
- package/dist/digest/digest-paths.js.map +0 -1
- package/dist/digest/digest-rows.d.ts +0 -346
- package/dist/digest/digest-rows.d.ts.map +0 -1
- package/dist/digest/digest-rows.js +0 -2
- package/dist/digest/digest-rows.js.map +0 -1
- package/dist/index.d.ts +0 -15
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -23
- package/dist/index.js.map +0 -1
- package/dist/schemes/Skill.d.ts.map +0 -1
- package/dist/schemes/Skill.js.map +0 -1
- package/dist/server/DaemonModule.d.ts +0 -101
- package/dist/server/DaemonModule.d.ts.map +0 -1
- package/dist/server/DaemonModule.js +0 -2
- package/dist/server/DaemonModule.js.map +0 -1
- package/dist/server/SkillSource.d.ts +0 -37
- package/dist/server/SkillSource.d.ts.map +0 -1
- package/dist/server/SkillSource.js +0 -267
- package/dist/server/SkillSource.js.map +0 -1
- package/dist/server/SkillsFunctionality.d.ts +0 -45
- package/dist/server/SkillsFunctionality.d.ts.map +0 -1
- package/dist/server/SkillsFunctionality.js +0 -405
- package/dist/server/SkillsFunctionality.js.map +0 -1
- package/dist/server/skills-problems.d.ts +0 -8
- package/dist/server/skills-problems.d.ts.map +0 -1
- package/dist/server/skills-problems.js +0 -18
- package/dist/server/skills-problems.js.map +0 -1
- package/dist/share/Share.d.ts +0 -15
- package/dist/share/Share.d.ts.map +0 -1
- package/dist/share/Share.js +0 -106
- package/dist/share/Share.js.map +0 -1
- package/dist/share/share.sql +0 -6
- package/docs/skills.md +0 -73
package/SPEC.md
CHANGED
|
@@ -18,7 +18,7 @@ Canonical contracts plurnk-service exposes, architecture it implements, promises
|
|
|
18
18
|
- [Proposals and client interactions](#proposal-proposals-and-client-interactions)
|
|
19
19
|
- [Stream Model](#stream-stream-model)
|
|
20
20
|
- [Storage Model](#storage-model)
|
|
21
|
-
- [
|
|
21
|
+
- [Extension composition](#core-extension-composition-extension-composition)
|
|
22
22
|
- [Bundled Set](#bundled-set-bundled-set)
|
|
23
23
|
- [Grammar Dependency](#grammar-dependency)
|
|
24
24
|
- [Operator Configuration](#operator-config-operator-configuration)
|
|
@@ -55,7 +55,7 @@ flowchart LR
|
|
|
55
55
|
| **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
|
|
56
56
|
| **worker** | Core | Durable actor and history over one workspace. Owns its loops and log rows, may carry a `parent_worker_id`, and has one process-local cancellation scope while active. |
|
|
57
57
|
| **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 input-capacity failure · 429 model-turn ceiling · 499 cancelled · 500 failed · 504 execution timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
|
|
58
|
-
| **turn** | Core | One durable, producer-neutral batch of ordered operations. A turn may be authored by a model, client,
|
|
58
|
+
| **turn** | Core | One durable, producer-neutral batch of ordered operations. A turn may be authored by a model, client, or `_plurnk`; only a model turn assembles a packet and owns an emission call. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
|
|
59
59
|
| **model call** | Core/provider | One logical `provider.generate` invocation. Emission attempts and BARE inferences share this durable accounting owner; provider retries remain cardinal physical requests beneath it. Identity: `(turn_id, sequence)`. |
|
|
60
60
|
| **op** | Producer/core | One DSL operation a producer submits, parsed into a `PlurnkStatement`. Admission follows {§turn-ops-admission-path}. |
|
|
61
61
|
| **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
|
|
@@ -63,8 +63,6 @@ flowchart LR
|
|
|
63
63
|
| **dispatch** | Core | Routing a statement to its scheme's op handler. |
|
|
64
64
|
| **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
|
|
65
65
|
| **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
|
|
66
|
-
| **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
|
|
67
|
-
| **session** | Retired/unqualified | Not a PLURNK lifecycle noun. Use the actual core noun; a third-party standard may use only its explicitly qualified protocol term. <!-- lexicon-allow: this row defines the retired noun --> |
|
|
68
66
|
|
|
69
67
|
### Storage terms
|
|
70
68
|
|
|
@@ -72,7 +70,7 @@ flowchart LR
|
|
|
72
70
|
|---|---|
|
|
73
71
|
| **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
72
|
| **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
|
|
73
|
+
| **scheme** | An addressable namespace and its 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
74
|
| **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
75
|
| **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
76
|
|
|
@@ -91,9 +89,9 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
91
89
|
|
|
92
90
|
| Term | Meaning |
|
|
93
91
|
|---|---|
|
|
94
|
-
| **writer** | The identity authoring a write. One of `model \| client \| _plurnk
|
|
92
|
+
| **writer** | The identity authoring a write. One of `model \| client \| _plurnk`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
|
|
95
93
|
| **origin** | Synonym for writer in log_entries (`log_entries.origin`). Synonym for writer. |
|
|
96
|
-
| **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk
|
|
94
|
+
| **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk}`; empty means no operation writes the scheme. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
|
|
97
95
|
|
|
98
96
|
### Execution terms
|
|
99
97
|
|
|
@@ -105,8 +103,8 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
105
103
|
| **BARE inference** | One isolated child-provider model call whose response becomes an ordinary BARE log result. It has no worker, packet, tools, output grammar, or persistent child state ({§bare-inference}). |
|
|
106
104
|
| **cycle** | Repeated operational inputs and observed results under {§engine-cycle-evidence}. |
|
|
107
105
|
| **capability policy** | A purely subtractive `only`/`deny` selector layer over routed operation demands. Service and workspace layers compose without granting authority. |
|
|
108
|
-
| **
|
|
109
|
-
| **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition
|
|
106
|
+
| **approval owner** | One durable, workspace-scoped recipient for a worker's approval requests ({§worker-ownership}). |
|
|
107
|
+
| **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition selects owner review or automatic settlement ({§proposal-disposition}). |
|
|
110
108
|
| **resolution** | A client decision delivered through a standard resume entry. Proposal resolutions accept, reject, or cancel ({§methods-proposal-resolve}); client-interaction resolutions return a payload or cancel ({§methods-client-interaction-resolve}, {§agui-proposal-resolve}). |
|
|
111
109
|
|
|
112
110
|
### §packet-terms Packet terms
|
|
@@ -133,7 +131,7 @@ package map. The default installed composition is specified in {§bundled-set}.
|
|
|
133
131
|
|
|
134
132
|
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.
|
|
135
133
|
|
|
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 makes observability unavailable with a configuration diagnostic ({§configuration-repair-path}); offline checking rejects the same input before loading an SDK. 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
|
|
134
|
+
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 makes observability unavailable with a configuration diagnostic ({§configuration-repair-path}); offline checking rejects the same input before loading an SDK. 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 extension 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.
|
|
137
135
|
|
|
138
136
|
§observability-genai-conventions **GenAI convention projection.** Provider
|
|
139
137
|
request spans follow the [GenAI registry at `c88d504`](https://github.com/open-telemetry/semantic-conventions-genai/tree/c88d504ab3d9879f8e50d3cc87e69775e11db234),
|
|
@@ -157,39 +155,34 @@ draft convention is projected.
|
|
|
157
155
|
The process and package map is ARCHITECTURE.md's; this package's AGENTS.md maps core's internal
|
|
158
156
|
owners. Capability-specific behavior remains with the owning plug point.
|
|
159
157
|
|
|
160
|
-
§service-worker-composition The service launcher and the live/demo
|
|
161
|
-
helper
|
|
162
|
-
|
|
158
|
+
§service-worker-composition The service launcher composes no module: it and the live/demo
|
|
159
|
+
workspace helper both discover AG-UI, A2A, MCP, Schedule and command hooks ({§module-discovery}). The
|
|
160
|
+
management families and readable reference documents are
|
|
163
161
|
present even with no enabled definitions. Workspace capability policy controls every actor's
|
|
164
162
|
surface; registering a family does not enable its definitions. The real-model
|
|
165
163
|
profile ({§operator-config-real-model-profile}) leaves ambient MCP attachments and
|
|
166
164
|
service schedules disabled by default; specimens may add their own through the
|
|
167
|
-
ordinary management surface.
|
|
168
|
-
|
|
165
|
+
ordinary management surface. The one listener is the launcher's ({§http-host}); the helper binds
|
|
166
|
+
none, so its daemon leaves out AG-UI ({§module-http-mounts}).
|
|
169
167
|
|
|
170
168
|
### §service-package-exports Package export surface
|
|
171
169
|
|
|
172
|
-
| Export path | Current contract
|
|
173
|
-
|
|
174
|
-
| `@plurnk/plurnk-service`
|
|
175
|
-
| `@plurnk/plurnk-service/
|
|
176
|
-
| `@plurnk/plurnk-service/package.json` | Supported package metadata surface.
|
|
170
|
+
| Export path | Current contract |
|
|
171
|
+
|---------------------------------------|------------------|
|
|
172
|
+
| `@plurnk/plurnk-service/launch` | The daemon launcher ({§daemon-launch}). |
|
|
173
|
+
| `@plurnk/plurnk-service/evidence` | Canonical evidence reader consumed by the separate report package ({§digest-evidence-reader}). |
|
|
174
|
+
| `@plurnk/plurnk-service/package.json` | Supported package metadata surface. |
|
|
177
175
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
| Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry`, `Skill` |
|
|
181
|
-
| Types | `ChatMessage`, `EditResult`, `FlagDescriptor`, `MockAssistant`, `MockResponse`, `OpenFoldResult`, `ReadResult` |
|
|
182
|
-
|
|
183
|
-
New clients use AG-UI. A new library contract belongs in its owning package or
|
|
184
|
-
an explicitly specified subpath, not in the frozen root barrel.
|
|
176
|
+
These are the package's only export paths. Clients use AG-UI; a new library contract belongs in its
|
|
177
|
+
owning package or an explicitly specified subpath.
|
|
185
178
|
|
|
186
179
|
### §startup-admission Startup admission
|
|
187
180
|
|
|
188
181
|
```mermaid
|
|
189
182
|
flowchart LR
|
|
190
|
-
LISTENER["Bind
|
|
191
|
-
DB --> DAEMON["
|
|
192
|
-
DAEMON --> CLIENT["
|
|
183
|
+
LISTENER["Bind the daemon's listener<br/>unadmitted: HTTP 503"] --> DB["Acquire daemon lock<br/>and admit SQLite schema"]
|
|
184
|
+
DB --> DAEMON["Start the daemon:<br/>discover and start modules"]
|
|
185
|
+
DAEMON --> CLIENT["Admit the listener"]
|
|
193
186
|
CLIENT --> SELECT["Worker selects or first uses a model"]
|
|
194
187
|
SELECT --> PROVIDER["Construct and verify<br/>selected provider"]
|
|
195
188
|
LISTENER -. failure .-> FAIL["Fail startup<br/>durable state untouched"]
|
|
@@ -202,9 +195,9 @@ flowchart LR
|
|
|
202
195
|
({§http-host}) before creating, opening, replacing, rotating, migrating, or
|
|
203
196
|
otherwise mutating anything in the durable data directory. A process that loses
|
|
204
197
|
the listener race fails with the originating address error and byte-identical
|
|
205
|
-
durable storage. Core owns the socket continuously; it answers 503 until
|
|
206
|
-
|
|
207
|
-
ownership introduces neither traffic nor a close/rebind race.
|
|
198
|
+
durable storage. Core owns the socket continuously; it answers 503 until daemon
|
|
199
|
+
activation admits it after every module has started ({§module-http-mounts}), so
|
|
200
|
+
early ownership introduces neither traffic nor a close/rebind race.
|
|
208
201
|
|
|
209
202
|
§http-host **The daemon opens exactly one transport.** Core binds the HTTP
|
|
210
203
|
listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
|
|
@@ -212,12 +205,14 @@ listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
|
|
|
212
205
|
({§application-port}). A prefix is an absolute pathname. Each request goes to the
|
|
213
206
|
longest mounted prefix; a prefix claims itself and the subtree beneath it, never
|
|
214
207
|
a longer sibling name; `/` is the root and receives whatever nothing more
|
|
215
|
-
specific claimed
|
|
208
|
+
specific claimed when a module mounts it. An admitted listener returns an HTTP
|
|
209
|
+
`404 route-not-found` Problem for any path without a mounted handler; a root mount
|
|
210
|
+
is not required. Until daemon activation admits it the listener answers `503
|
|
216
211
|
service-starting` to every request: the service has not admitted its client
|
|
217
|
-
interface. Adapters
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
address by URL, never by port (#641): AG-UI mounts
|
|
212
|
+
interface. Adapters claim their prefixes before setup and mount them at
|
|
213
|
+
`start()`, after durable lifecycle recovery ({§module-http-mounts}), and
|
|
214
|
+
none opens a socket of its own. The standards
|
|
215
|
+
address by URL, never by port (#641): AG-UI mounts only `/agui`, A2A the
|
|
221
216
|
well-known card and its endpoint path, on the same address.
|
|
222
217
|
|
|
223
218
|
§startup-admission-order After listener ownership, database admission completes
|
|
@@ -230,7 +225,7 @@ preserving the originating failure: daemon, observability, database, listener.
|
|
|
230
225
|
|
|
231
226
|
§startup-readiness-line **Readiness is one stdout line.** After the client interface is mounted
|
|
232
227
|
the service prints exactly one line, `plurnk-service agui=<url> db=<json string> route=<json string>`:
|
|
233
|
-
the URL brackets an IPv6 host, and the database path and the route (the active model route or
|
|
228
|
+
the URL includes `/agui` and brackets an IPv6 host, and the database path and the route (the active model route or
|
|
234
229
|
`no model`, or `invalid model configuration`) are JSON strings, so a path or route containing spaces is exact and a consumer parses
|
|
235
230
|
the URL as a URL and the strings as JSON; nothing else the service prints on stdout before it has
|
|
236
231
|
that prefix. Before the line the listener answers `503 service-starting`; after it,
|
|
@@ -256,6 +251,49 @@ launchers consume the same contract by reading the line themselves.
|
|
|
256
251
|
|
|
257
252
|
## §actor-boundary Workers and workspace boundaries
|
|
258
253
|
|
|
254
|
+
### §worker-ownership Approval ownership
|
|
255
|
+
|
|
256
|
+
Every worker has one workspace-scoped approval owner. Ownership is independent of
|
|
257
|
+
origin, parentage, messages and connection presence. It controls approval routing,
|
|
258
|
+
not access to workspace resources ({§actor-boundary-no-mutex}).
|
|
259
|
+
|
|
260
|
+
| Event | Ownership |
|
|
261
|
+
| --- | --- |
|
|
262
|
+
| Root creation | Explicit owner, otherwise the runtime `_plurnk`. |
|
|
263
|
+
| WORK, FORK, or a fresh child | Inherit the parent's owner. |
|
|
264
|
+
| SEND, schedule occurrence, or other incoming message | Preserve the recipient's owner. |
|
|
265
|
+
| Explicit client control attachment | Claim a runtime-owned conversation and its runtime-owned descendants; never claim the runtime actor or replace another owner. |
|
|
266
|
+
| Observation or disconnect | No change. |
|
|
267
|
+
|
|
268
|
+
An owner declares its capability set: the client tool names it implements, and whether it
|
|
269
|
+
is interactive, that is, whether a person attends it. The declaration remains durable while it
|
|
270
|
+
is disconnected. A proposal requiring review waits for that owner; unsupported review fails at
|
|
271
|
+
the request boundary. Approval needs no person: a client that accepts automatically still
|
|
272
|
+
implements `request_approval`. Clarification and a park only a person can end need an
|
|
273
|
+
interactive owner. `_plurnk` implements no client tools and is never interactive. Server
|
|
274
|
+
approval policy may settle a proposal automatically; it cannot fabricate an interaction answer.
|
|
275
|
+
Kernel maintenance remains kernel work ({§actor-boundary-self-hosting}).
|
|
276
|
+
|
|
277
|
+
§worker-owner-creation Ownership, inheritance, and runtime-owner creation are
|
|
278
|
+
database invariants. A newly created worker cannot be left without an owner;
|
|
279
|
+
an unknown explicit owner is an error. Existing workers migrate to runtime ownership.
|
|
280
|
+
|
|
281
|
+
§worker-owner-resolution A proposal names its worker's owner and one disposition:
|
|
282
|
+
`review`, `accept`, or `reject`. Review routes to that owner, not to the sender,
|
|
283
|
+
the current observer, or whichever ancestor has a live Run. A decision is accepted
|
|
284
|
+
only for that owner and the still-pending gate. Disconnect does not substitute a
|
|
285
|
+
different owner. Capability admission remains independent and precedes approval.
|
|
286
|
+
|
|
287
|
+
§client-interaction-routing Clarification goes to the worker's owner, like approval, but
|
|
288
|
+
only a person can answer it. The owner receives it while it is interactive and declares
|
|
289
|
+
the requested tool; otherwise the request fails at once as unsupported and never parks.
|
|
290
|
+
The pending interaction records that recipient and accepts a response only from it,
|
|
291
|
+
through the ordinary response-schema validation and settlement path. A protocol caller,
|
|
292
|
+
such as an A2A client, converses by message and is never a recipient
|
|
293
|
+
({§a2a-worker-ownership}).
|
|
294
|
+
|
|
295
|
+
### Worker boundaries
|
|
296
|
+
|
|
259
297
|
```mermaid
|
|
260
298
|
flowchart LR
|
|
261
299
|
child["Child worker"] -->|"durable activity<br/>environment door"| parent["Direct parent log"]
|
|
@@ -277,11 +315,12 @@ filter a row.
|
|
|
277
315
|
|
|
278
316
|
§actor-boundary-attached-functionality **Attachment selects a conversation,
|
|
279
317
|
not an environment owner.** Client management commands mutate workspace
|
|
280
|
-
Functionality ({§module-workspace-capabilities});
|
|
318
|
+
Functionality ({§module-workspace-capabilities}); runtimes, runtime
|
|
281
319
|
schemes, and tools resolve by `workspaceId`. Operations journal in the
|
|
282
320
|
submitting actor's `workerId` ({§connection-lifecycle}), which must belong to
|
|
283
321
|
the workspace. Runtime and policy resolution require no second worker identity.
|
|
284
|
-
Attachment remains many-to-one
|
|
322
|
+
Attachment remains many-to-one and unrelated to parentage. Explicit control
|
|
323
|
+
attachment may claim approval ownership under {§worker-ownership}.
|
|
285
324
|
|
|
286
325
|
§actor-boundary-two-doors **Cross-worker arrival is limited to two doors.**
|
|
287
326
|
An explicit READ is not an arrival: the reading worker deliberately addresses a
|
|
@@ -363,7 +402,6 @@ narrow or omit the reference catalogs under {§capability-admission}.
|
|
|
363
402
|
| Project filesystem | `*` | File cap below; `project root member files` |
|
|
364
403
|
| Workspace entries | `worker:///*` | Markerless; `workspace knowledgebase entries` |
|
|
365
404
|
| Named scratch entries | `worker://<worker>/*` | Markerless; `worker knowledgebase entries` |
|
|
366
|
-
| The worker's own reasoning | `reasoning://<worker>/**` | Markerless; `this worker's reasoning, by loop and turn` |
|
|
367
405
|
|
|
368
406
|
Only the three namespace surveys carry asides; the other targets name
|
|
369
407
|
their surface. The word `skills` names Agent Skills and nothing else.
|
|
@@ -371,7 +409,7 @@ Catalogs select documents independently of their authored bodies; ordinary READ
|
|
|
371
409
|
supplies examples and complete instructions on demand. A shallow
|
|
372
410
|
result renders direct entries normally and every deeper first-segment directory
|
|
373
411
|
as an actionable `dir/**` summary with its recursive `items` and `tokens`;
|
|
374
|
-
|
|
412
|
+
runtime rows also carry the concise `{§scheme-catalog-aside}` that drives
|
|
375
413
|
on-demand capability discovery. Ordinary surveys use FIND without a scope
|
|
376
414
|
({§markerless-first-page}), whose range metadata reports the returned set against the
|
|
377
415
|
complete result total; only the small capability-reference surfaces
|
|
@@ -460,7 +498,7 @@ existing workspace worker in its own right.
|
|
|
460
498
|
|
|
461
499
|
§machine-processes-model-worker-readable **Packet membership is per-worker, not an access policy.** A packet contains its worker's log plus explicitly delivered activity ({§actor-boundary}). `readLog({ workspaceId, workerId })` may inspect any worker belonging to that workspace, and `listWorkers` enumerates them. A client-interface module chooses its conversation binding. Inspection does not inject another log into a model's packet.
|
|
462
500
|
|
|
463
|
-
§machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `_plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by WORK/FORK from the parent. A turn's producer is independent: a
|
|
501
|
+
§machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `_plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by WORK/FORK from the parent. A turn's producer is independent: a client-produced program in a model worker still delegates model workers. `listWorkers` returns actor class without interpreting names; a retained worker's name is immutable ({§machine-processes-worker-is-its-log}).
|
|
464
502
|
|
|
465
503
|
§worker-provider-identity **A worker owns a durable provider identity distinct
|
|
466
504
|
from its database id.** Creation mints a globally unique, opaque 128-bit value;
|
|
@@ -496,7 +534,7 @@ continues to decompose other authorities without treating them as mintable.
|
|
|
496
534
|
|
|
497
535
|
§worker-read-scope **Scratch is workspace-readable.** Any actor reads and searches any named or shared scratch address. Parentage and writer identity do not change resolution. Scratch namespaces do not require a namesake Worker. A pathless actor address requires a named Worker; an unknown actor returns 404.
|
|
498
536
|
|
|
499
|
-
§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.
|
|
537
|
+
§worker-write-scoping **Scratch is workspace-writable.** All workspace actors may EDIT, COPY, MOVE, or KILL entries in any named or shared scratch namespace, including generated documents. Workspace admission remains uniform. Intrinsically immutable evidence in other schemes retains its own contract ({§scheme-entry-matrix}); operation provenance and delegation lifecycle do not grant or restrict scratch access.
|
|
500
538
|
|
|
501
539
|
§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}).
|
|
502
540
|
|
|
@@ -551,7 +589,6 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
551
589
|
own work is a fresh loop, so an inherited mid-flight loop never makes the
|
|
552
590
|
branch look forever-live to the {§send-premature-terminate} gate.
|
|
553
591
|
- §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.
|
|
554
|
-
- §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.
|
|
555
592
|
- §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.
|
|
556
593
|
|
|
557
594
|
- §worker-scheme-collect **Collect** — each concluded child loop reaches its direct
|
|
@@ -595,7 +632,7 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
595
632
|
starts there too, then resets atomically when any published channel's content
|
|
596
633
|
changes, including replacement or clearing. Identical writes, empty appends,
|
|
597
634
|
READs, publication acknowledgements, metadata, and channel-state changes do
|
|
598
|
-
not reset it. The clock is durable;
|
|
635
|
+
not reset it. The clock is durable; a stream lacking that evidence
|
|
599
636
|
reports `output timing unknown` until its next content change, never a guessed
|
|
600
637
|
timestamp. These are observations, not new timeouts or wake conditions
|
|
601
638
|
({§exec-stream}). It is orienting state, never advice: the model sees its live
|
|
@@ -856,7 +893,6 @@ cancels work or fabricates a result.
|
|
|
856
893
|
With live work, each WAIT receipt exposes `waitSeconds`, the maximum accepted
|
|
857
894
|
for that operation. It is not elapsed time or a promised sleep: an ordinary wake
|
|
858
895
|
or a shorter sibling WAIT can resume the loop sooner. An idle WAIT has no bound.
|
|
859
|
-
Historical unbounded receipts do not acquire one during projection.
|
|
860
896
|
|
|
861
897
|
| Boundary | Outcome |
|
|
862
898
|
|---|---|
|
|
@@ -914,12 +950,6 @@ move it. The digest reports, per loop, the claim time and how long after it the
|
|
|
914
950
|
first model turn started, so a stall between claim and inference (a heartbeat has
|
|
915
951
|
waited 7.5 h, #703) is a number rather than a gap.
|
|
916
952
|
|
|
917
|
-
§digest-storage **The digest states the file's health.** Beside the database path it
|
|
918
|
-
reports the file size, the free pages it holds, its `auto_vacuum` mode, and the six
|
|
919
|
-
largest tables and indexes by allocated bytes (`dbstat`), so growth is a number in
|
|
920
|
-
every digest (#764). The digest reads loops as stored, so it tolerates databases
|
|
921
|
-
missing later lifecycle columns.
|
|
922
|
-
|
|
923
953
|
§loop-execution-allowance **One task has one execution allowance.** The first
|
|
924
954
|
execution snapshots `PLURNK_SERVICE_LOOP_TIMEOUT` on the loop. Active segments
|
|
925
955
|
consume that allowance cumulatively, measured with a monotonic clock; waits and
|
|
@@ -1079,7 +1109,7 @@ boundary.
|
|
|
1079
1109
|
| Independent arrival after cancellation | Admit a new loop above the cutoff using the ordinary worker policy. |
|
|
1080
1110
|
| Slow stream teardown after new admission | Reap only subscription identities captured by cancellation; late old-scope spawns follow {§worker-lifecycle-exec-epoch-bound}. |
|
|
1081
1111
|
|
|
1082
|
-
- §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
|
|
1112
|
+
- §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** The stream first persists its terminal state. A worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) then **awakens that loop in place** — the blocked loop *is* the continuation. An already-active worker's next packet reads the durable terminal state. Ambient stream closure starts no loop for a concluded worker. The result remains available in the stream's own state under every case.
|
|
1083
1113
|
- §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.
|
|
1084
1114
|
- §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.
|
|
1085
1115
|
- §worker-lifecycle-idle-is-concluded **Idle is not completion.** An empty WAIT continues; an eligible parameterless KILL with observed arrivals and results and no held work concludes under {§wait-obligation-matrix}, with or without an answer body. A concluded worker retains durable history; a later addressed arrival starts a new loop.
|
|
@@ -1093,11 +1123,11 @@ boundary.
|
|
|
1093
1123
|
|
|
1094
1124
|
A turn is the durable container for one producer's ordered operations. Packet
|
|
1095
1125
|
and provider fields are optional evidence belonging only to model inference;
|
|
1096
|
-
their absence never makes a client
|
|
1126
|
+
their absence never makes a client or `_plurnk` turn exceptional.
|
|
1097
1127
|
|
|
1098
1128
|
| Field | Contract |
|
|
1099
1129
|
|---|---|
|
|
1100
|
-
| `producer` | Required actor class: `model`, `client`,
|
|
1130
|
+
| `producer` | Required actor class: `model`, `client`, or `_plurnk`. |
|
|
1101
1131
|
| `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}). |
|
|
1102
1132
|
| `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. |
|
|
1103
1133
|
| 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. |
|
|
@@ -1106,9 +1136,8 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
|
|
|
1106
1136
|
|
|
1107
1137
|
One lifecycle owner opens, optionally records inference evidence, and completes
|
|
1108
1138
|
every turn. Initialization, maintenance, client dispatch, and model
|
|
1109
|
-
inference use that same path
|
|
1110
|
-
|
|
1111
|
-
parallel record or lifecycle. Producer and kind never change. Process-restart
|
|
1139
|
+
inference use that same path; a new producer joins it without a parallel
|
|
1140
|
+
record or lifecycle. Producer and kind never change. Process-restart
|
|
1112
1141
|
recovery completes any turn whose producer vanished.
|
|
1113
1142
|
|
|
1114
1143
|
§turn-exception-outcome An exceptional inference exit completes every still-open
|
|
@@ -1122,7 +1151,7 @@ The turn owner propagates the original exception unchanged.
|
|
|
1122
1151
|
| An `AggregateError` combining cancellation with other failures | 500; cancellation does not conceal another failure. |
|
|
1123
1152
|
|
|
1124
1153
|
§turn-ops-admission-path **Source acquisition varies; admitted-turn execution does not.**
|
|
1125
|
-
A provider response, deterministic `_plurnk` program, or future client
|
|
1154
|
+
A provider response, deterministic `_plurnk` program, or future client
|
|
1126
1155
|
program crosses one admission boundary into the same executor. That executor
|
|
1127
1156
|
parses once, dispatches the admitted statements in order, records their ordinary
|
|
1128
1157
|
outcomes, and completes the turn from its lifecycle ruling. Exact source is retained before dispatch.
|
|
@@ -1206,9 +1235,9 @@ retains only the current provider state; the next completed exchange notices
|
|
|
1206
1235
|
`provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
|
|
1207
1236
|
is spent the turn completes as `202` and the loop parks exactly like a
|
|
1208
1237
|
WAIT ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
|
|
1209
|
-
next prompt or wake with its log intact — **unless the
|
|
1210
|
-
({§
|
|
1211
|
-
|
|
1238
|
+
next prompt or wake with its log intact — **unless the worker's owner is not interactive
|
|
1239
|
+
({§worker-ownership}); then the loop concludes on the provider's exact failure because no
|
|
1240
|
+
person attends to wake that park.** Only a client cancel, the execution allowance
|
|
1212
1241
|
({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
|
|
1213
1242
|
authorization, quota, an invalid response) settles a loop on a provider failure.
|
|
1214
1243
|
|
|
@@ -1325,7 +1354,7 @@ The parser owns its boundaries; core admits determinate work and exposes its fai
|
|
|
1325
1354
|
| Lost boundary before any closed operation | Reject the attempt; outside text is no substitute for a closed operational statement. An admitted reasoning operation is one ({§reasoning-operations}). |
|
|
1326
1355
|
| Outside text carrying a log-entry heading, other than an emission row's | Reject the attempt ({§fabricated-log-entry}). |
|
|
1327
1356
|
|
|
1328
|
-
§fabricated-log-entry **Only the harness writes the log.** A line of outside response text that begins with a log-entry heading, `### log:///<loop>/<turn>/<sequence>/` ({§log-wire-format}), is the model continuing the packet's transcript instead of answering it: it writes the receipts it expects and then acts on them. The attempt is rejected under {§invalid-emission-attempts}, so neither that text nor any operation beside it runs or is stored as outside text ({§outside-text}), and its one diagnostic, at the heading's line, reads `` `### log:///2/1/5/READ` is a log entry, and only the harness writes the log.
|
|
1357
|
+
§fabricated-log-entry **Only the harness writes the log.** A line of outside response text that begins with a log-entry heading, `### log:///<loop>/<turn>/<sequence>/` ({§log-wire-format}), is the model continuing the packet's transcript instead of answering it: it writes the receipts it expects and then acts on them. The attempt is rejected under {§invalid-emission-attempts}, so neither that text nor any operation beside it runs or is stored as outside text ({§outside-text}), and its one diagnostic, at the heading's line, reads `` `### log:///2/1/5/READ` is a log entry, and only the harness writes the log. `` Text inside an operation body is not examined, so a SEND or KILL may quote a receipt. A heading whose leaf is `emission` is exempt: it names the worker's own source ({§emission-row}), and repeating it invents no receipt, so the attempt is admitted and the heading stays outside text, counted by the digest as an echo. In 10,486 recorded emissions, 101 carried such a heading in outside text, every one a fabrication: 85 of 1,675 from deepseek-flash, 81 of them opening with one, and 16 from glm-5.3-flash, deepseek-v4-pro and qwen3.8-flash, which appended an invented `## Log` after their own operations.
|
|
1329
1358
|
|
|
1330
1359
|
Warnings and closer recovery ({§closer-fallback}) do not reject. `finish=length`
|
|
1331
1360
|
discloses truncation and precludes completion; it is not independently a rejection.
|
|
@@ -1333,7 +1362,11 @@ Provider interruption is owned by {§provider-interrupted-attempt}. Accepted sou
|
|
|
1333
1362
|
and positions remain exact; execution follows {§op-execution-order}. WAIT remains
|
|
1334
1363
|
optional, with no omission warning or invented operation ({§turn-shape}).
|
|
1335
1364
|
|
|
1336
|
-
|
|
1365
|
+
The parser compiles target groups ({§target-group}, {§safe-uri-target-groups}) into ordinary
|
|
1366
|
+
statements before model or client admission. Core does not reinterpret target syntax. Each
|
|
1367
|
+
admitted member receives its independent dispatch outcome and log row, in authored order under
|
|
1368
|
+
{§op-execution-order}; one member's runtime failure does not suppress later members. The original
|
|
1369
|
+
emission in `turn_sources` remains exact and unexpanded.
|
|
1337
1370
|
|
|
1338
1371
|
Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `inference_calls` row with its `model_calls` specialization and emission-specific `turn_attempts` admission row. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. Beneath the logical call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone extends `turns.packet` with response evidence; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `<stem>.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
|
|
1339
1372
|
|
|
@@ -1371,10 +1404,10 @@ interrupted response evidence, Core stores it unaccepted without duplicating its
|
|
|
1371
1404
|
accounting. The failed turn still stores the exact request and never fabricates
|
|
1372
1405
|
an assistant or a zero-valued observation.
|
|
1373
1406
|
|
|
1374
|
-
### §attribution
|
|
1407
|
+
### §attribution Extension-authored attribution folksonomy
|
|
1375
1408
|
|
|
1376
|
-
|
|
1377
|
-
shared contract {§
|
|
1409
|
+
An extension may declare opaque attribution tags statically or at runtime under the
|
|
1410
|
+
shared contract {§extension-attribution}:
|
|
1378
1411
|
|
|
1379
1412
|
```jsonc
|
|
1380
1413
|
{ "plurnk": { "attribution": "@acme/widgets" } } // always-on string or string[]
|
|
@@ -1382,14 +1415,14 @@ shared contract {§plugin-attribution}:
|
|
|
1382
1415
|
|
|
1383
1416
|
| Stage | Contract |
|
|
1384
1417
|
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1385
|
-
| Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other
|
|
1418
|
+
| Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other extension. |
|
|
1386
1419
|
| Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
|
|
1387
|
-
| Meaning | Core neither verifies nor infers contribution. Tags are
|
|
1420
|
+
| Meaning | Core neither verifies nor infers contribution. Tags are extension-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§extension-attribution}). |
|
|
1388
1421
|
| Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every generation-kind `inference_calls` row carries that call's exact set, including response-less failures. |
|
|
1389
1422
|
| Derived reporting | Turn, loop, digest, and client views project the recorded sets. `loop/terminated.attributions` is their deduplicated sorted union and remains separate from provider usage and charge evidence. |
|
|
1390
1423
|
|
|
1391
|
-
Runtime
|
|
1392
|
-
failure is an internal
|
|
1424
|
+
Runtime `attributions` functions are synchronous and receive only the attempt coordinates.
|
|
1425
|
+
A function's failure is an internal extension-contract failure; Core does not silently discard
|
|
1393
1426
|
it or reinterpret a malformed tag list.
|
|
1394
1427
|
|
|
1395
1428
|
§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.
|
|
@@ -1402,7 +1435,7 @@ it or reinterpret a malformed tag list.
|
|
|
1402
1435
|
service-side caching, per-loop selection, context-cap handling, and admission
|
|
1403
1436
|
of an operator's grammar. Cataloged providers use Models.dev metadata and official AI SDK
|
|
1404
1437
|
bindings; an operator declaration covers an uncataloged compatible endpoint;
|
|
1405
|
-
|
|
1438
|
+
a provider extension is the last seam for a new protocol. Cache identity includes
|
|
1406
1439
|
the alias, wire route, and complete provider-knob projection; a registered
|
|
1407
1440
|
preconstructed handle occupies that same identity and cannot shadow changed
|
|
1408
1441
|
tuning.
|
|
@@ -1445,7 +1478,7 @@ First path segment = provider name; rest = provider-native model id.
|
|
|
1445
1478
|
|
|
1446
1479
|
### Mock provider (sibling fixture)
|
|
1447
1480
|
|
|
1448
|
-
§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
|
|
1481
|
+
§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 package export, this contract has no service-side `§`-ref.
|
|
1449
1482
|
|
|
1450
1483
|
---
|
|
1451
1484
|
|
|
@@ -1528,7 +1561,7 @@ Folders and globs select members in those same filesystem coordinates. Parent-di
|
|
|
1528
1561
|
|
|
1529
1562
|
### File scheme: creation and misses
|
|
1530
1563
|
|
|
1531
|
-
§fs-write-surface **The write surface — one admission and incorporation path.** Existing writes remain membership-gated. An absent path additionally crosses the effective creation scope and the complete constraint/Git policy before a proposal is issued. EDIT, COPY destinations, and MOVE destinations use this same path regardless of whether the producer is a model, client,
|
|
1564
|
+
§fs-write-surface **The write surface — one admission and incorporation path.** Existing writes remain membership-gated. An absent path additionally crosses the effective creation scope and the complete constraint/Git policy before a proposal is issued. EDIT, COPY destinations, and MOVE destinations use this same path regardless of whether the producer is a model, client, or `_plurnk`. A COPY or MOVE destination scope on an absent channel resolves against its empty pre-mutation value under {§empty-mutation-scope}; a valid scope creates the channel with the selected source as its complete value. A coordinate outside that empty value is 416. Binary scopes remain numeric byte positions or ranges under {§binary-parity}.
|
|
1532
1565
|
|
|
1533
1566
|
| Case | Required admission | Accepted result |
|
|
1534
1567
|
|------|--------------------|-----------------|
|
|
@@ -1583,9 +1616,9 @@ Every fact names the canonical key, never the host root or an echo of the
|
|
|
1583
1616
|
model's spelling. These classes let a caller distinguish a wrong address, an
|
|
1584
1617
|
invalid range, read-only authority, and occupied hidden state without guessing.
|
|
1585
1618
|
|
|
1586
|
-
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member key, never a `file://` URI. Recovery
|
|
1619
|
+
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member key, never a `file://` URI. Recovery offers listing with FIND, creation with EDIT, and admission with `members (add)` as alternatives and presumes none ({§diagnostic-observation}): `` FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. `` Admission takes a `{"glob": "<path>"}` body. The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo, and their recovery speaks of the address too, true under every members scope: `'<key>' is outside the project root: only a members definition under the operator's namespace scope admits it.` Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.`, with admission-only recovery; a path the repository ignores, which no model definition admits, carries the members discovery verdict instead: `The repository ignores it: a client or operator members definition can include it, a model definition cannot.` Occupancy may surface there; content never does ({§membership}).
|
|
1587
1620
|
|
|
1588
|
-
§file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file
|
|
1621
|
+
§file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file: READ and KILL answer 404, EDIT 403. The detail is `'<key>' is a directory, not a file; <OP> reads/removes/writes one file.`; a READ or KILL carries the listing as its recovery, `` `FIND (<key>/)` lists its files. ``, and an EDIT carries none. Beyond the root the disk stays dark and {§membership-read-refusal} holds unchanged.
|
|
1589
1622
|
|
|
1590
1623
|
§file-find-directory **FIND recognizes existing directories without requiring a trailing slash.** An exact target naming a directory inside the workspace root resolves to the same recursive collection as its slash-suffixed spelling, including content matching and result pagination. Only workspace members appear; an empty directory or one containing only non-members yields a successful empty survey. Exact files stay exact, genuinely absent paths retain their missing-entry error, and this resolution does not inspect disk paths beyond the root. Shared glob and non-file URI semantics are unchanged.
|
|
1591
1624
|
|
|
@@ -1857,8 +1890,6 @@ operator knobs in `.env.defaults`. Search indexing performs no inference.
|
|
|
1857
1890
|
|
|
1858
1891
|
§per-entry-channels-edit-writes-only-body EDIT writes one channel per call — the channel resolved from the path's fragment (or the scheme's `defaultChannel` when no fragment).
|
|
1859
1892
|
|
|
1860
|
-
No stored `preview` channel — channel content is pulled on READ, never previewed.
|
|
1861
|
-
|
|
1862
1893
|
Schemes MAY declare multiple channels (`node`: stdout/stderr; `http`: body/header; SSE: per-event-type). Each goes in `manifest.channels` with mimetype pinned; rendered independently. Execution input is control under {§exec-input}, not a stored channel.
|
|
1863
1894
|
|
|
1864
1895
|
For a multi-channel streaming READ, persistence and publication are distinct: the scheme may acquire and persist auxiliary channels, but a fragmentless target publishes only the manifest's `defaultChannel`. An explicit fragment publishes that channel. Thus an ordinary HTTP READ presents the sanitized `body`; response metadata and archival DOM remain addressable implementation/diagnostic surfaces rather than ambient model context.
|
|
@@ -2035,7 +2066,7 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
|
|
|
2035
2066
|
- §edit-null-clears Writes the body; `body: null` clears it.
|
|
2036
2067
|
- §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
|
|
2037
2068
|
`{ status: 200, entryId }` for a content update.
|
|
2038
|
-
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring a scoped KILL's idempotence ({§log-kill-scope}). Its terse detail states the observed equality
|
|
2069
|
+
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring a scoped KILL's idempotence ({§log-kill-scope}). Its terse detail states the observed equality, `No change: EDIT body matches the selected content.`, and nothing else ({§diagnostic-observation}).
|
|
2039
2070
|
- §edit-marker-required-on-existing **A markerless EDIT is CREATE-ONLY — there is no easy-clobber path on an existing entry.** A `<L>` marker scopes an EDIT to a range; without one, the body becomes the entry's WHOLE content — legitimate and required for a fresh entry (nothing exists to scope into), but on an EXISTING entry a missing marker is refused **400**, never a silent full replace. A deliberate full rewrite states that intent explicitly: `<1,-1>` resolves through the ordinary marker math to the same whole-content replacement, so the capability is available but cannot be selected by omission.
|
|
2040
2071
|
- §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
|
|
2041
2072
|
its endpoint checks as a core-private mutation precondition. Otherwise-valid
|
|
@@ -2109,7 +2140,7 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
2109
2140
|
when that differs from the channel's own mimetype the result names the
|
|
2110
2141
|
channel's as `sourceMimetype`, so a consumer can still run the channel's
|
|
2111
2142
|
handlers over a whole-resource `<1,-1>` read.
|
|
2112
|
-
- §log-range-miss-names-stream A 416 on a log execution item
|
|
2143
|
+
- §log-range-miss-names-stream A 416 on a log execution item addresses the row's invocation (its authored call body, often empty or one line), while the execution's output stays readable at the stream address the row records. When that stream link exists, the 416 carries it as the `stream` extension; its detail and recovery stay the generic slicer's, naming no cause ({§diagnostic-observation}).
|
|
2113
2144
|
- §read-pattern **A pattern selects the lines a READ renders.** With a heading
|
|
2114
2145
|
matcher ({§matcher-option} in the contracts SPEC) an exact-target READ stays a
|
|
2115
2146
|
READ: the matcher runs over the channel's complete text — a regex anchors
|
|
@@ -2238,7 +2269,7 @@ AST: `{ op: "KILL", target, matcher: MatcherBody | null, lineMarker: TextLineMar
|
|
|
2238
2269
|
|
|
2239
2270
|
KILL deletes context from the **log** (`log:///`, {§packet}). Without a scope it retires the selected rows from the active projection ({§log-history-projection}). With a one-line or inclusive two-line scope it removes only that body's intersecting body-relative physical lines from the readable projection, and the row stays active. An anchor may be one published on that body or one returned by READing its `log:///` coordinate ({§line-anchors}); an anchor absent from the current body selects no line, as with an out-of-bounds numeric line. Scoped KILL is one-way: intervals accumulate, the durable body is untouched, and subsequent access follows {§log-readable-projection}. A scoped KILL on a bodyless row is a friendly 200 no-op with `matched` reported. An emission row is curated whole ({§emission-row}): a scope covering every line retires it like an unscoped KILL; on its exact coordinate a narrower scope is 422 `emission-curated-whole`, whose recovery names both forms that retire it; a sweep leaves it intact. A KILL that addresses no row is 404 on an exact coordinate and 204 on a sweep ({§log-curation-folder-idiom}). Selection composes target/glob with an optional heading pattern ({§log-curation-set-selection}). Parameterless KILL instead requests completion ({§kill-conclusion}).
|
|
2240
2271
|
|
|
2241
|
-
§log-scope-recovery A log-body scope follows the file slicer's range rule ({§range-starts-at-one} in the schemes SPEC): a range starting at 0 — `<0,-1>` included — is refused 416 `range-not-satisfiable` on every body, empty ones too, and never clamped; its detail is the slicer's own sentence, `Range <0,-1> starts at 0, which is not a line; lines are numbered from 1.`, and its recovery names the forms a log body takes — `
|
|
2272
|
+
§log-scope-recovery A log-body scope follows the file slicer's range rule ({§range-starts-at-one} in the schemes SPEC): a range starting at 0 — `<0,-1>` included — is refused 416 `range-not-satisfiable` on every body, empty ones too, and never clamped; its detail is the slicer's own sentence, `Range <0,-1> starts at 0, which is not a line; lines are numbered from 1.`, and its recovery names the forms a log body takes — `Trim one line with <L> or lines L through M with <L,M>; KILL (log:///1/9/2/READ) with no scope retires the whole row.` — never the insert and append positions a body cannot take. Every other scope that names no line is 400 `curation-scope-invalid` with the same recovery: the forms that work on that row, never a rebuild of the written scope ({§diagnostic-observation}).
|
|
2242
2273
|
|
|
2243
2274
|
A READ carrying active native media is atomic: any KILL scope is ignored and the entire observation is retired, including its native context contribution ({§packet-attachment-parts}). For a model turn, native activity is the attachment selection in its actual input packet; without a model packet, a native observation is atomic by default. Text-only observations in the same selection retain ordinary scoped behavior. Neither form deletes source data or forensic evidence.
|
|
2244
2275
|
|
|
@@ -2246,7 +2277,7 @@ A READ carrying active native media is atomic: any KILL scope is ignored and the
|
|
|
2246
2277
|
|
|
2247
2278
|
| Fact | Owner | Effect |
|
|
2248
2279
|
| --- | --- | --- |
|
|
2249
|
-
| Initial body suppression | Immutable event `initial_folded` | Packet presentation only; explicit retrieval can read an initially hidden body. An emission row
|
|
2280
|
+
| Initial body suppression | Immutable event `initial_folded` | Packet presentation only; explicit retrieval can read an initially hidden body. An emission row remains folded; its program is separately eligible for {§previous-emission}. |
|
|
2250
2281
|
| Deliberate scoped KILL | Current projection `folded`, initially empty | Packet, READ, FIND, COPY, and search omit those lines; later retrieval cannot undo trimming. |
|
|
2251
2282
|
|
|
2252
2283
|
Packet display combines both masks. Other consumers use only deliberate trimming.
|
|
@@ -2284,7 +2315,7 @@ The `## Log` section is a sequence of ordinary Markdown records separated by one
|
|
|
2284
2315
|
| facts | One strict JSON object in stable alphabetical order. | Present only when a fact exists. Asides, scopes, opaque invocation metadata and result facts belong here, not on the H3. |
|
|
2285
2316
|
| body | Coordinate-prefixed lines. | Present when the row is visible. |
|
|
2286
2317
|
|
|
2287
|
-
An emission row's body is not in its record
|
|
2318
|
+
An emission row's body is not in its record ({§emission-row}); the optional previous program follows the user footer ({§previous-emission}). Patterns retain their literal spelling; a pattern containing a line break is JSON-quoted to keep the H3 on one physical line. Receipts are descriptive records, not reconstructed operation headings. Absent fields are not invented. Every physical body line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, so source text cannot create a record boundary. The section contains records only, with no leading prose or enclosing fence.
|
|
2288
2319
|
|
|
2289
2320
|
§log-address-metadata **Addresses name their relationship, not the row's producer.**
|
|
2290
2321
|
|
|
@@ -2366,7 +2397,7 @@ Authored `metadata` retains its opaque ordered block strings under {§scheme-met
|
|
|
2366
2397
|
records the exact READ coordinates sent without controlling retention. Missing immutable bytes are an
|
|
2367
2398
|
internal integrity failure, never silently dropped content. No ejection message or permanent teaching is
|
|
2368
2399
|
added. These stable curation weights are not provider-token measurements ({§tokenomics-render-weight-budget}).
|
|
2369
|
-
- §packet-token-accounting Every row reports one `tokens` charge on its H3 ({§log-wire-format}): its complete materialized H3, facts, visible body
|
|
2400
|
+
- §packet-token-accounting Every row reports one `tokens` charge on its H3 ({§log-wire-format}): its complete materialized H3, facts, visible body and selected native attachment. The previous-emission section is charged separately as user-slot text ({§previous-emission}). The completed record is measured to a fixed point, including the accounting field itself. Hidden text is not charged; metadata-only rows still have a reclaimable charge. Source/FIND-item `tokens` measure source content, not the observation's context footprint. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page differs. All use stable curation weights, not provider tokens or dollars. Native component accounting follows {§packet-attachment-parts}; ordinary addressability and truthful errors follow {§log-wire-format}.
|
|
2370
2401
|
|
|
2371
2402
|
### §retrieval-packet-metadata READ/FIND packet metadata
|
|
2372
2403
|
|
|
@@ -2416,37 +2447,37 @@ single line past the end, a reversed range, empty content, a command's log row
|
|
|
2416
2447
|
|
|
2417
2448
|
### §emission-row The emission row
|
|
2418
2449
|
|
|
2419
|
-
Every admitted emission is announced by one row of its own turn
|
|
2420
|
-
|
|
2421
|
-
like any other row.
|
|
2450
|
+
Every admitted content emission is announced by one curatable row of its own turn.
|
|
2451
|
+
The most recent eligible program supplies {§previous-emission}; older programs remain readable.
|
|
2422
2452
|
|
|
2423
2453
|
| Surface | Contract |
|
|
2424
2454
|
|---|---|
|
|
2425
2455
|
| When | An inference turn that admitted at least one content statement. Reasoning-only turns, including initialization ({§worker-initialization-entry}), a programmatic batch, an empty turn ({§empty-turn}), a client operation and a rejected attempt ({§rejected-emission-entry}) announce nothing. |
|
|
2426
2456
|
| Place | After the turn's inputs (arrivals, deltas, open-path READs) and before its reasoning NOTEs and operations, written after the selection snapshot ({§turn-ops-selection-snapshot}): the emission sits between what the worker had seen and what it caused. |
|
|
2427
2457
|
| Row | A `_plurnk` READ of the turn's own source, `ops://<worker>/L/T`, with `attrs.kind="emission"` and the canonical leaf `/emission`: `### log:///L/T/S/emission → ops://<worker>/L/T · N`. It renders its author, the turn's producer, as `origin`, so a model's row carries none. It is no operation: no receipt, tool call or strike, and outside the op mix. |
|
|
2428
|
-
| Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of admitted content statements, each
|
|
2429
|
-
|
|
|
2458
|
+
| Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of the admitted content statements, each whole in a closed fence. All heading operands, scopes, metadata, patterns and asides remain. Free text and unadmitted forms are absent; a recovered native call ({§native-tool-calls}) appears as the operation it was read as; an operation whose receipt failed stays. Reasoning operations retain their own source and normal receipts, never an assistant-content copy. No body text is inspected for nested operations. |
|
|
2459
|
+
| Wire | The record appears in the log; its complete program is eligible for {§previous-emission}. No operation family or body is filtered. Dispatch and the immutable `ops://` source keep complete bodies ({§turn-source-resources}); an explicit READ returns them. |
|
|
2430
2460
|
| Stability | The projection is fixed from its first appearance, never aged or resized under budget pressure. Already frozen announcements and historical request captures are not rewritten. |
|
|
2431
|
-
| Presentation | Born folded: the record shows its header,
|
|
2432
|
-
| Accounting | `tokens` charges
|
|
2461
|
+
| Presentation | Born folded: the log record shows its header, never an assistant message. |
|
|
2462
|
+
| Accounting | The row's `tokens` charges only its rendered record. The optional previous-emission section is measured once as user-slot text ({§packet-token-accounting}); replacing it never changes older row weights. An explicit source READ has its own ordinary charge. |
|
|
2433
2463
|
| Curation | Curated whole ({§log-kill-scope}): KILL retires it, and so does a scope covering every line (`<1,-1>`); on its exact coordinate a narrower scope is 422 `emission-curated-whole`, and a sweep whose scope would only trim it leaves it intact. |
|
|
2434
|
-
| Schema | Migration 12 admits `kind="emission"` only on this shape: one per turn, the turn's newest row when written, frozen, and curated whole
|
|
2435
|
-
| Echoes | A worker that repeats the heading in its own text is tolerated ({§fabricated-log-entry}); the digest counts the echoes.
|
|
2464
|
+
| Schema | Migration 12 admits `kind="emission"` only on this shape: one per turn, the turn's newest row when written, frozen, and curated whole; it backfills no announcement for earlier turns. FORK copies it with the inherited turns, still naming its writer. |
|
|
2465
|
+
| Echoes | A worker that repeats the heading in its own text is tolerated ({§fabricated-log-entry}); the digest counts the echoes. |
|
|
2436
2466
|
|
|
2437
2467
|
### §reasoning-row The reasoning row
|
|
2438
2468
|
|
|
2439
2469
|
The model's memory of its own reasoning, behind `PLURNK_SERVICE_REASONING_ROWS` (default `1`):
|
|
2440
2470
|
when it is `1`, every model turn that reasoned lands its reasoning as one row of its
|
|
2441
2471
|
own, `log:///<loop>/<turn>/<sequence>/reasoning → reasoning://<worker>/<loop>/<turn>`, the harness's
|
|
2442
|
-
READ of the turn's reasoning source, immediately before the turn's emission row
|
|
2443
|
-
|
|
2444
|
-
the
|
|
2472
|
+
READ of the turn's reasoning source, immediately before the turn's emission row (or its first
|
|
2473
|
+
operation or diagnostic when there is no content emission), so the transcript
|
|
2474
|
+
reads what the model thought and where its content program can be found
|
|
2475
|
+
({§emission-row}, {§packet-wire-envelope}).
|
|
2445
2476
|
|
|
2446
2477
|
| Concern | Rule |
|
|
2447
2478
|
|---|---|
|
|
2448
|
-
| Room |
|
|
2449
|
-
| Body | The model's own text when it fits the row's page — `PLURNK_SERVICE_REASONING_TRAILING_LINES` lines, unset meaning the shared `PLURNK_SERVICE_PREVIEW_LINES`, within `PLURNK_SERVICE_PREVIEW_CHARS` — and otherwise its **last page
|
|
2479
|
+
| Room | Admission occurs after all mandatory turn rows, including the emission and diagnostics, using the remaining room under {§context-fit}. Its earlier chronological coordinate is reserved without inserting a placeholder; if it does not fit, that coordinate remains unused. Nothing else changes: no partial preview, refusal, or other row touched. Reasoning-only and empty model turns follow the same rule; content operations are not required. |
|
|
2480
|
+
| Body | The model's own text when it fits the row's page — `PLURNK_SERVICE_REASONING_TRAILING_LINES` lines, unset meaning the shared `PLURNK_SERVICE_PREVIEW_LINES`, within `PLURNK_SERVICE_PREVIEW_CHARS` — and otherwise its **last page**. Keep complete final lines where possible; if the last line alone exceeds the character bound, select its suffix with the ordinary exact column scope. Unicode code points count once and CRLF is one indivisible separator, as in {§body-projection}. The statement carries the scope it took and the receipt its `range` ({§packet-extent-metadata}); the complete reasoning stays readable at its address by any scope ({§turn-source-resources}). |
|
|
2450
2481
|
| Weight | Charged like any row, visible in the gauge and its `largest` ({§context-gauge}). |
|
|
2451
2482
|
| Curation | The verbs alone: a KILL retires it like any row ({§context-verbs}); the daemon reorders nothing and un-bodies nothing on its account. |
|
|
2452
2483
|
| Absence | Means no room or no reasoning; the model tells them apart by reading `reasoning://` for the turn. |
|
|
@@ -2456,7 +2487,7 @@ the canonical program ({§emission-row}, {§packet-wire-envelope}).
|
|
|
2456
2487
|
| Surface | Contract |
|
|
2457
2488
|
|---|---|
|
|
2458
2489
|
| 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 `outside` source ({§outside-text}) has no address: no `outside://` scheme exists, and it is reached only through `outside/event`, FORK and the digest. 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. |
|
|
2459
|
-
| Source | `ops` is exact admitted `text/vnd.plurnk`, and its turn's emission row carries
|
|
2490
|
+
| Source | `ops` is exact admitted `text/vnd.plurnk`, and its turn's emission row carries its canonical projection ({§emission-row}); `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. |
|
|
2460
2491
|
| 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. |
|
|
2461
2492
|
| Retention | One ops source, one reasoning source and one outside 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. |
|
|
2462
2493
|
| 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. |
|
|
@@ -2467,7 +2498,7 @@ the canonical program ({§emission-row}, {§packet-wire-envelope}).
|
|
|
2467
2498
|
§rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program, and no emission row announces it ({§emission-row}). 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.
|
|
2468
2499
|
|
|
2469
2500
|
- §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with ```` ```READ (worker:///docs/) ````. A complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: the native operation name or invoked executor name, `/attempt` for a rejected emission, `/emission` for an admitted one's announcement ({§emission-row}). An executor leaf is derived from the durable submitted statement (its `runtime`), never an internal dispatch type or the current tool registry. Digits and punctuation in executor names remain part of the leaf. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. READ anchors use the canonical suffixed identity even when addressed by shorthand. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ`, `log:///**/python3`, `log:///**/attempt`, and `log:///**/emission` deliberately filter canonical leaves. Executor outputs instead use workspace-wide claims such as `sh:///ab3d5678#stdout` ({§execution-output-identity}); their source operation has log coordinates, but resource lifetime and identity are independent of that observation. Error pointers, Problem instances, source attribution, and search use this same identity; client stream coordinates retain the numeric triple. Within a turn, sequence is arrival order. Inbound SEND rows publish before the program runs ({§message-arrival}); a turn receiving messages holds the first at `log:///L/T/1/SEND`, followed by further arrivals oldest first, then its emission's announcement, then the model's operations ({§packet-current-turn} names `L/T`).
|
|
2470
|
-
- §log-near-miss **A log miss beside rows that exist names them.** A READ, FIND or KILL of an exact coordinate that names no row carries a recovery from the worker's own active rows: the row at that coordinate under its own leaf (``
|
|
2501
|
+
- §log-near-miss **A log miss beside rows that exist names them.** A READ, FIND or KILL of an exact coordinate that names no row carries a recovery from the worker's own active rows: the turn's rows carrying the leaf written come first, since the leaf is what the model asked for and the sequence its guess, followed by the row at that coordinate under its own leaf (`` Turn 1/44's reasoning is `log:///1/44/2/reasoning`; the entry at log:///1/44/1 is `log:///1/44/1/READ`. ``); with no row of that leaf, the row at the coordinate alone (`` The entry at log:///1/25/8 is `log:///1/25/8/sh`. ``), else the turn's rows, at most six named, else the loop's latest turn. A coordinate in a loop with no rows carries none. Recorded misses were near misses every time: a READ of `1/25/8/READ` when the row was `sh`, an EDIT one sequence off, and a KILL under the 413 that must curate (#1005).
|
|
2471
2502
|
- §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — KILL takes a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: ```` ```KILL (log:///1/2) <1,-1> ```` suppresses turn 1/2's bodies and retires its emission ({§emission-row}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. Parameterless KILL instead requests completion ({§kill-conclusion}).
|
|
2472
2503
|
- §log-curation-set-selection **Row selection and body scope are independent** — target/glob and an optional heading pattern (```` ```KILL (log:///**) [{"pattern": "~stale"}] ````, every dialect a FIND over rows accepts) compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. An emission row is curated whole instead: the scope retires it when it covers every line and otherwise leaves it ({§emission-row}). Thus ```` ```KILL (log:///**/READ) <17,-1> ```` may change long READs and no-op on short ones while reporting every selected row in `matched`.
|
|
2473
2504
|
|
|
@@ -2687,12 +2718,12 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2687
2718
|
|
|
2688
2719
|
### §find FIND
|
|
2689
2720
|
|
|
2690
|
-
- §log-uniform-query **Log speaks the universal query contract** — ```` ```FIND (log://…) ```` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~` full-text and `&graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not
|
|
2721
|
+
- §log-uniform-query **Log speaks the universal query contract** — ```` ```FIND (log://…) ```` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~` full-text and `&graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not an extension seam and grants no protocol scheme an alternate READ path.
|
|
2691
2722
|
- §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND works uniformly across schemes by construction: `EntryFind` and `Log.find` run the one shared primitive rather than re-implementing it per scheme. Log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
|
|
2692
2723
|
- §find-line-anchors **A FIND regex anchors each line**, as READ, EDIT and KILL do ({§read-pattern}, {§edit-pattern}): `^` and `$` are a line's ends in every FIND content match — over entries, log rows, turn sources and a binary channel's bytes — so ```` ```FIND (django/urls/resolvers.py) /^from|^import/ ```` locates the same import lines a READ with that pattern shows, never a false 204.
|
|
2693
2724
|
- §find-candidate-containment **One candidate's crash is that candidate's problem** — arbitrary member content can crash a mimetype handler mid-match (an unbalanced template partial crashed Readability and killed a 1,916-file FIND as a blank 500, #449). `Matcher.matchCandidates` contains a per-candidate handler throw: the candidate drops out exactly like unsupported content, the cause goes to daemon stderr, and only a FIND whose every candidate crashed reports a 415 whose Problem names the first crashing member and handler. The operation's other candidates always answer.
|
|
2694
2725
|
|
|
2695
|
-
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a native matcher reads it. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit
|
|
2726
|
+
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a native matcher reads it. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit extension contract, never inferred from URL punctuation.
|
|
2696
2727
|
|
|
2697
2728
|
Resource-authority globs select authorities independently of the path scope.
|
|
2698
2729
|
Matching resources retain their full addresses through pattern matching,
|
|
@@ -2707,7 +2738,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2707
2738
|
matches the selected channel's content or derivation; path globs select
|
|
2708
2739
|
resources through `(target)` ({§path-glob}).
|
|
2709
2740
|
- §find-fulltext-selection Every matcher operates only over the candidate set selected by `(target)`; indexed matchers do not bypass that selection. `~query` passes the native FTS5 expression to SQLite and ranks matching candidates by ascending BM25, with resource identity breaking ties. Native BM25 uses the shared index's term statistics; candidate visibility, owner, channel and target filters determine which resources can be returned. The ordinary FIND pager selects resources for broad targets or match locations for exact targets: markerless search uses {§markerless-first-page}, `<N>` selects position N and `<N,M>` selects an inclusive range. Fractions are invalid result coordinates, not similarity thresholds. Results expose addressable matched text regions; neither cosine scores nor percentage similarity is invented. Native query-syntax failures return 400 with SQLite's diagnostic; database and implementation failures propagate.
|
|
2710
|
-
- §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`).
|
|
2741
|
+
- §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`). An FTS5 failure keeps SQLite's own message as its `diagnostic`, and its recovery is the dialect's form, never a rewrite of the query ({§diagnostic-observation}): `` An FTS5 query is barewords, "quoted phrases", and AND, OR, NOT and NEAR between them. ``
|
|
2711
2742
|
- §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
|
|
2712
2743
|
- §find-result-projection **The resolved target selection determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsWeightTotal, returnedItemsWeightTotal }`:
|
|
2713
2744
|
|
|
@@ -2742,7 +2773,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2742
2773
|
derivation's `{§mimetype-summary}`. Prose is clipped to at most `PLURNK_SERVICE_CATALOG_SUMMARY_CHARS` Unicode
|
|
2743
2774
|
code points including a visible terminal ellipsis, so a row stays one line
|
|
2744
2775
|
of orientation; an invocation-form witness — a summary that is one fenced
|
|
2745
|
-
operation, the shape
|
|
2776
|
+
operation, the shape a runtime's tool summary takes
|
|
2746
2777
|
({§tools-resource-materialization}) — is shown whole, every tool named,
|
|
2747
2778
|
because the discovery row exists so the model can invoke without a READ and
|
|
2748
2779
|
a menu that is cut is no menu. Absent metadata is omitted.
|
|
@@ -2849,6 +2880,8 @@ accounting and model-visible failure evidence remain separately owned by
|
|
|
2849
2880
|
contains exactly one KILL without a target, scope, matcher or metadata, no hard
|
|
2850
2881
|
parse error or lost boundary, and was not cut at the provider's output allowance.
|
|
2851
2882
|
The operation limit must admit the entire program.
|
|
2883
|
+
The parser retains everything after that KILL heading as its answer region
|
|
2884
|
+
({§terminal-kill}); apparent operations there are body text, not siblings.
|
|
2852
2885
|
SEND, NOTE and log-targeted KILL may accompany it, as may outside text ({§outside-text});
|
|
2853
2886
|
every other operation requires continuation. This tolerance is unadvertised:
|
|
2854
2887
|
model teaching requests KILL alone. Reasoning-side NOTEs remain ordinary notes.
|
|
@@ -2968,7 +3001,7 @@ of which Worker launched it ({§execution-output-identity}).
|
|
|
2968
3001
|
| Backpressure | `PLURNK_SERVICE_EXEC_INPUT_TIMEOUT_MS` bounds each accepted delivery, including its queue residence. Expiry returns `504 input-timeout`; cancellation returns `499 input-cancelled`. Once delivery has begun, retire and abort input on either; delivery may be partial and is never replayed. The execution itself is not implicitly killed. |
|
|
2969
3002
|
| Settlement or teardown | Retire and abort input immediately when the execution settles or is cancelled. Existing stream completion and worker wake mechanics remain the only completion path. |
|
|
2970
3003
|
|
|
2971
|
-
|
|
3004
|
+
No operation writes a stored runtime entry: its scheme's `writableBy` is empty, and the execution writes its own streams. Input and termination are
|
|
2972
3005
|
control capabilities, not exceptions granting write access to stdout/resources.
|
|
2973
3006
|
|
|
2974
3007
|
### §exec Executions
|
|
@@ -2987,21 +3020,18 @@ target scheme, before effect admission or source acquisition. Core validates the
|
|
|
2987
3020
|
preparation result and retains its cwd; it neither parses option names nor
|
|
2988
3021
|
redirects metadata to a source scheme. An executor without preparation accepts
|
|
2989
3022
|
no metadata. A `script`-kind target ({§executor-invocation}) is the program: core inspects it before
|
|
2990
|
-
anything spawns — a file is the script; a directory is refused `400 target-not-a-program
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
recovery names that executor's fence — `` `python3` is its own executor; use that name on the
|
|
2996
|
-
opening fence and put the program in the body. ``; otherwise it points at an existing script or a bare shell-command body. A non-file resource
|
|
3023
|
+
anything spawns — a file is the script; a directory is refused `400 target-not-a-program`;
|
|
3024
|
+
an absent path is refused `400 target-not-found`, stating what exists and inferring nothing
|
|
3025
|
+
({§diagnostic-observation}): a registered tool of another executor is named with that executor,
|
|
3026
|
+
another available executor as its own executor (`` `python3` is its own executor. ``), and
|
|
3027
|
+
anything else as a target that must name an existing program resource. A non-file resource
|
|
2997
3028
|
target that cannot be read keeps the owning READ's failure identity (#163) and states
|
|
2998
|
-
the slot contract in its recovery
|
|
2999
|
-
a command belongs beneath a targetless heading — without guessing which was meant (#425). The started receipt always
|
|
3029
|
+
the slot contract in its recovery: the resource is the program and the body its stdin. The started receipt always
|
|
3000
3030
|
names the working directory only when it is not the project root, and then in the
|
|
3001
3031
|
project-relative form ({§fs-namespace}); the default directory is omitted rather
|
|
3002
3032
|
than repeated in every receipt. Native file addresses resolve from that same project
|
|
3003
3033
|
directory, while absolute input retains its filesystem meaning. The `(path)` is a program — a script for an interpreter, a tool name for a tool
|
|
3004
|
-
|
|
3034
|
+
runtime — and neither a command nor a working directory is ever a target. The default
|
|
3005
3035
|
shell is written as its own fence, ```` ```sh ````; no runtime-less form exists.
|
|
3006
3036
|
|
|
3007
3037
|
§exec-target-near-miss Two target near-misses have one reading each and are read
|
|
@@ -3015,15 +3045,14 @@ real stream id is always the program source.
|
|
|
3015
3045
|
|
|
3016
3046
|
§exec-target-documentation **Generated reference is never a program.** A resource target under
|
|
3017
3047
|
`worker:///_plurnk/` — the executor and scheme documentation the harness generates — is refused
|
|
3018
|
-
at admission, 400 `target-is-documentation`, before any source is realized or run: `` `worker:///_plurnk/plurnk/sh.md` is reference documentation the harness generated, not a program; sh cannot run it. ``
|
|
3048
|
+
at admission, 400 `target-is-documentation`, before any source is realized or run: `` `worker:///_plurnk/plurnk/sh.md` is reference documentation the harness generated, not a program; sh cannot run it. `` It carries no recovery ({§diagnostic-observation}). Admitting it realized the markdown as a host temporary file that a sandboxed runtime could not open (`cannot open /tmp/plurnk-exec-….md`), and ran markdown where it could.
|
|
3019
3049
|
|
|
3020
3050
|
§exec-tool-fall-through **A tool run as a shell command is named at the failure
|
|
3021
3051
|
site.** A bare shell command whose program is the name of a tool published by
|
|
3022
3052
|
another enabled runtime (`brave_web_search {…}` under the default shell) exits
|
|
3023
|
-
127; the stream's terminal receipt then says the program is
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
`tool`. The status stays the shell's 500, nothing is rerouted, and a program the
|
|
3053
|
+
127; the stream's terminal receipt then says the program is a tool of that
|
|
3054
|
+
runtime, names the tool's own document, and carries `toolRuntimes` and `tool`;
|
|
3055
|
+
it builds no invocation ({§diagnostic-observation}). The status stays the shell's 500, nothing is rerouted, and a program the
|
|
3027
3056
|
registry does not know keeps the plain exit-127 receipt.
|
|
3028
3057
|
|
|
3029
3058
|
| Declared target kind | Authored target | Canonical effect target | Executor realization |
|
|
@@ -3046,7 +3075,7 @@ effect classification or proposal creation.
|
|
|
3046
3075
|
A runtime with {§executor-tool-registry} admits only the snapshot's exact
|
|
3047
3076
|
literal targets. An absent target is 400; a target outside that closed enabled
|
|
3048
3077
|
set is 404; neither reaches effect classification or proposal creation. The
|
|
3049
|
-
selected entry's invocation—not the
|
|
3078
|
+
selected entry's invocation—not the runtime's structural fallback—owns body
|
|
3050
3079
|
requiredness and roles. The executor independently rejects an unregistered
|
|
3051
3080
|
target at its run boundary.
|
|
3052
3081
|
|
|
@@ -3134,12 +3163,12 @@ addressed to `<runtime>:///<id>` when the id holds an execution only under anoth
|
|
|
3134
3163
|
§exec-lifetime **How long a spawn may live is the fence's metadata, one field.**
|
|
3135
3164
|
`[{"lifetime": …}]` takes a duration (`30s`, `30m`, `2h`), or one of three words;
|
|
3136
3165
|
absent is `loop`. The key is one of the service's reserved metadata keys, withheld
|
|
3137
|
-
from every owner by the framework ({§service-metadata-keys}). An execution takes no scope: a
|
|
3138
|
-
|
|
3166
|
+
from every owner by the framework ({§service-metadata-keys}). An execution takes no scope: a scope on an
|
|
3167
|
+
execution is refused `scope-unsupported` (400).
|
|
3139
3168
|
|
|
3140
3169
|
| `lifetime` | The spawn |
|
|
3141
3170
|
| ------------ | --------- |
|
|
3142
|
-
| a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504** `execution-timeout`, distinct from a deliberate kill (499) or a clean exit (200): `` Execution of '*runtime*' outlived its *lifetime* lifetime. ``
|
|
3171
|
+
| a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504** `execution-timeout`, distinct from a deliberate kill (499) or a clean exit (200): `` Execution of '*runtime*' outlived its *lifetime* lifetime. `` |
|
|
3143
3172
|
| `loop` (absent) | Loop-life bounded: reaped on every loop terminal except 202, the background-stream behavior. |
|
|
3144
3173
|
| `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}). |
|
|
3145
3174
|
| `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. |
|
|
@@ -3151,7 +3180,7 @@ stream deltas. Calendar recurrence remains a schedule ({§schedule-delivery}).
|
|
|
3151
3180
|
|
|
3152
3181
|
§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}).
|
|
3153
3182
|
|
|
3154
|
-
§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.
|
|
3183
|
+
§entry-owner **Every entry belongs directly to one workspace.** Its immutable identity is `(workspace_id, scheme, authority, pathname)`. The workspace foreign key supplies lifetime; URI authority supplies the literal resource namespace. Core binds one canonical coordinate through {§entry-address-resolution} for every operation and consumer. Producer and subscriber Worker ids describe causal activity, not ownership.
|
|
3155
3184
|
|
|
3156
3185
|
§execution-output-identity **Execution output belongs to the workspace.**
|
|
3157
3186
|
Each invocation claims a collision-checked eight-character lowercase hexadecimal
|
|
@@ -3345,7 +3374,7 @@ body prefixes.
|
|
|
3345
3374
|
wholesale ({§log-sensitive-request-evidence}); the spawn's record names each such value's
|
|
3346
3375
|
provenance as the modifier's.
|
|
3347
3376
|
- §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env), 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.
|
|
3348
|
-
- §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. Web acquisition and materialization are the `https` handler's {§web-materialization-contract}, reached through the scheme registry; core names no
|
|
3377
|
+
- §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. Web acquisition and materialization are the `https` handler's {§web-materialization-contract}, reached through the scheme registry; core names no extension package.
|
|
3349
3378
|
|
|
3350
3379
|
| Input / effect | Consumer behavior |
|
|
3351
3380
|
| --- | --- |
|
|
@@ -3353,7 +3382,7 @@ body prefixes.
|
|
|
3353
3382
|
| Null path + supplied content | Publish beneath the invocation's `resources/` using {§resource-publication-names}, owned by the calling Worker. |
|
|
3354
3383
|
| Supplied bytes | Retain the original bytes and declared mimetype in an ordinary channel ({§binary-parity}). |
|
|
3355
3384
|
| Supplied text | Preserve text resources; HTTP/HTML materialization retains source and derived channels under {§html-materialization}. |
|
|
3356
|
-
| Null content | Acquire an HTTP(S) resource through the checked WebFetcher, using the same configured materializers as exact HTTP acquisition ({§http-materializer-
|
|
3385
|
+
| Null content | Acquire an HTTP(S) resource through the checked WebFetcher, using the same configured materializers as exact HTTP acquisition ({§http-materializer-extensions}). |
|
|
3357
3386
|
| Durable evidence | One typed EDIT event in the runtime actor, with the calling Worker as causal source. Binary evidence describes the resource; its complete bytes live in the resource channel. |
|
|
3358
3387
|
| Model orientation | The executor includes returned addresses in its result. Publication does not independently wake inference or broadcast an observer row ({§env-delta-entry-materialization}). READ controls content acquisition and native delivery. |
|
|
3359
3388
|
|
|
@@ -3393,10 +3422,10 @@ Core derives the contracts-owned `ProposalProjection` from the durable proposed
|
|
|
3393
3422
|
| `target` | canonical `{ scheme, authority, pathname }` from `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
|
|
3394
3423
|
| `body` | proposed operation result `rx.body`; absent means the empty review body |
|
|
3395
3424
|
| `attrs` | proposed log row `attrs` object |
|
|
3396
|
-
| `
|
|
3425
|
+
| `owner` | the worker's durable workspace-scoped approval owner ({§worker-ownership}) |
|
|
3397
3426
|
| `disposition` | {§proposal-disposition}; the same value drives automatic settlement and client presentation |
|
|
3398
3427
|
|
|
3399
|
-
Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes,
|
|
3428
|
+
Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes, owner registration, or final projection fails at core with its cause; after insertion, core terminalizes that row as a 500 `policy_failed` before propagating the internal failure, so no waiter or durable stopped world is orphaned.
|
|
3400
3429
|
|
|
3401
3430
|
### §client-interactions Client-owned interaction lifecycle
|
|
3402
3431
|
|
|
@@ -3405,7 +3434,8 @@ A scheme or executor may pause its current operation on one
|
|
|
3405
3434
|
pending-only `client_interactions` row bound to one exact
|
|
3406
3435
|
workspace/worker/loop/turn ownership chain, then publishes the same validated
|
|
3407
3436
|
`ClientInteractionProjection` through `loop/interaction` and reconnect
|
|
3408
|
-
discovery. The projection
|
|
3437
|
+
discovery. The projection names its recipient ({§client-interaction-routing}) but
|
|
3438
|
+
contains no workspace id or private upstream
|
|
3409
3439
|
continuation state; those remain respectively in the event envelope and the
|
|
3410
3440
|
awaiting operation owner.
|
|
3411
3441
|
|
|
@@ -3423,112 +3453,44 @@ composes it with the existing owner signal before registering the same waiter.
|
|
|
3423
3453
|
Reconnect discovery intersects durable rows with live waiters; restart
|
|
3424
3454
|
removes ownerless rows without fabricating cancellation, payload, or replay.
|
|
3425
3455
|
|
|
3426
|
-
###
|
|
3456
|
+
### Server disposition and client YOLO
|
|
3427
3457
|
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
| Mechanism | Authority path | Intended use |
|
|
3433
|
-
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
3434
|
-
| §proposal-ownership-loop-auto **Loop disposition** | `runLoop({ policy: { proposals: "accept" } })` persists a loop-owned disposition; core resolves proposals in process without a client. | Headless automation, benchmarks, CI, fixtures, and unattended use. |
|
|
3435
|
-
| **Client-side YOLO** (`--yolo` / `PLURNK_YOLO`) | A `proposals: "review"` loop emits the ordinary `loop/proposal`; the client returns an accepted proposal through its standard resolution path. | Interactive automatic review. |
|
|
3436
|
-
|
|
3437
|
-
Core cannot distinguish client-side YOLO from a fast human acceptance and does
|
|
3438
|
-
not need to. Loop auto keeps authority inside the loop; client-side YOLO acts
|
|
3439
|
-
only after authority crosses the client boundary.
|
|
3458
|
+
| Mechanism | Authority path |
|
|
3459
|
+
| --- | --- |
|
|
3460
|
+
| Server disposition | `PLURNK_SERVICE_PROPOSALS` selects review, accept, or reject. Core settles automatic decisions through the normal proposal lifecycle. |
|
|
3461
|
+
| Client-side YOLO | The owning client accepts review requests through the same resolution path as human review. It cannot override server rejection or capability admission. |
|
|
3440
3462
|
|
|
3441
|
-
§proposal-ownership-notification
|
|
3463
|
+
§proposal-ownership-notification The notification carries the selected
|
|
3464
|
+
`ProposalDisposition`, not policy inputs. Clients present only `decision: "review"`
|
|
3465
|
+
addressed to their owner identity; they never reconstruct authority from the
|
|
3466
|
+
operation, message sender, or attrs.
|
|
3442
3467
|
|
|
3443
3468
|
### §proposal-disposition Settlement authority and precedence
|
|
3444
3469
|
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
ring, the reason and the recovery — a subtracted tool must say why it is gone and what to do
|
|
3470
|
-
instead. Every other ring is operator configuration and speaks for itself; the loop ring is the
|
|
3471
|
-
one the model can act on. The 501 at the interaction itself is the backstop for the paths that
|
|
3472
|
-
do not cross dispatch (MCP elicitation raised inside a tool call, the execution-input bridge).
|
|
3473
|
-
The ring reaches dispatch but not the reserved tree's listing, which is one artifact per
|
|
3474
|
-
workspace: an unattended model still sees the question document and learns at dispatch that it
|
|
3475
|
-
is refused (#770).
|
|
3476
|
-
- **A provider-recovery park becomes a conclusion** ({§provider-recovery}), carrying the
|
|
3477
|
-
provider's own exact Problem. Never a substituted "the model gave up".
|
|
3478
|
-
|
|
3479
|
-
**A park is a promise that something will restart it.** `LoopLifecycle.park` takes the waker
|
|
3480
|
-
by name; `null` says nothing will. Parking an unattended loop with no waker is a contract
|
|
3481
|
-
violation and throws, so a park site added later fails loudly on its first unattended run
|
|
3482
|
-
instead of idling until some caller's clock notices. It is a tripwire, not a fallback: the
|
|
3483
|
-
provider-recovery path concludes before reaching it.
|
|
3484
|
-
|
|
3485
|
-
Attendance never converts a legitimate wait that has a real waker — a `WAIT`, an open stream,
|
|
3486
|
-
a delegated child — into a termination. Those have wakers; a human question
|
|
3487
|
-
does not. A prompt prefix states a disposition, never an attendance: typing `?` asks for review,
|
|
3488
|
-
and an unattended loop refuses that statement rather than conjuring a reviewer.
|
|
3489
|
-
|
|
3490
|
-
§loop-policy-composition **A loop's policy is what its creator stated over what the panel
|
|
3491
|
-
says.** A creator — a client's `loop.run`, a schedule definition, a transport module — states
|
|
3492
|
-
any part of a policy as a `LoopPolicyRequest`, or nothing. The request stays exactly as stated
|
|
3493
|
-
until a fresh loop is persisted: an omitted field is no opinion, so a fold compares only what
|
|
3494
|
-
was said ({§methods-loop-run-fold-consistency}). `LoopPolicies.compose` then makes it whole,
|
|
3495
|
-
once. `PLURNK_SERVICE_ATTENDED` answers an unstated attendance, and the attendance picks which
|
|
3496
|
-
knob answers an unstated disposition: `PLURNK_SERVICE_PROPOSALS` for an attended loop,
|
|
3497
|
-
`PLURNK_SERVICE_UNATTENDED_PROPOSALS` for an unattended one, whose vocabulary has no `review`.
|
|
3498
|
-
Every valid panel state is therefore lawful; an invalid knob is diagnosed at startup
|
|
3499
|
-
and refuses a loop that needs it ({§configuration-repair-path}). No code,
|
|
3500
|
-
schema or column holds a default ({§operator-config-only-home}): `loops.policy` and
|
|
3501
|
-
`loops.max_turns` carry none, so every insert states both. Client-authored administrative
|
|
3502
|
-
loops use the same composition.
|
|
3503
|
-
|
|
3504
|
-
§runtime-bookkeeping-policy **Runtime bookkeeping has no reviewer and cannot acquire
|
|
3505
|
-
new authority.** Its administrative loops explicitly state
|
|
3506
|
-
`{ attended: false, proposals: "reject" }`; this is a runtime invariant, not an
|
|
3507
|
-
interactive default. Generated reference publication and audit narration therefore
|
|
3508
|
-
do not depend on client policy configuration. Runtime-authored proposals do not
|
|
3509
|
-
use effect-policy auto-admission; bookkeeping proposals settle as failures through
|
|
3510
|
-
the ordinary proposal lifecycle, never wait for a client or auto-accept.
|
|
3511
|
-
|
|
3512
|
-
§loop-policy-effective-read `loops.policy` persists one complete immutable
|
|
3513
|
-
`LoopPolicy`; every runtime policy read validates that snapshot before use.
|
|
3514
|
-
Missing rows or invalid values fail with the owning loop coordinate and cause.
|
|
3515
|
-
Raw archival copies and forensic rendering do not interpret policy.
|
|
3516
|
-
|
|
3517
|
-
The cascade's rings are `service`, `workspace` and, innermost, `loop`. The loop ring exists only
|
|
3518
|
-
for an unattended run and is purely subtractive like every other layer, so it can never widen what
|
|
3519
|
-
its workspace allows; a capability denial names the ring that refused. The operator's capability
|
|
3520
|
-
projection and the shared reserved-document materialization take no loop coordinate on purpose:
|
|
3521
|
-
those questions are about a workspace, not about one run.
|
|
3522
|
-
|
|
3523
|
-
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
|
|
3524
|
-
|
|
3525
|
-
| `policy.proposals` | Disposition |
|
|
3526
|
-
| ------------------ | ---------------------------------------- |
|
|
3527
|
-
| `review` | client |
|
|
3528
|
-
| `accept` | loop accept |
|
|
3529
|
-
| `reject` | loop reject, outcome `no_review_channel` |
|
|
3530
|
-
|
|
3531
|
-
Capability admission precedes this decision, so proposal disposition cannot grant a denied capability. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
|
|
3470
|
+
| First applicable condition | Disposition |
|
|
3471
|
+
| --- | --- |
|
|
3472
|
+
| Runtime bookkeeping | reject, `runtime_bookkeeping` |
|
|
3473
|
+
| Server `accept` | accept |
|
|
3474
|
+
| Server `reject` | reject, `policy_veto` |
|
|
3475
|
+
| Server `review`, owner implements `request_approval` | review |
|
|
3476
|
+
| Server `review`, owner has no reviewer | reject, `no_review_channel` |
|
|
3477
|
+
|
|
3478
|
+
Core selects the disposition once for the pending gate. Its live event and
|
|
3479
|
+
reconnect projection use that same decision. Automatic settlement precedes
|
|
3480
|
+
observational notification; an observer failure cannot change authority or orphan
|
|
3481
|
+
a waiter. Invalid configuration is diagnosed at the proposal boundary without
|
|
3482
|
+
substituting authority ({§configuration-repair-path}). Client-authored
|
|
3483
|
+
administrative operations retain their client's owner.
|
|
3484
|
+
|
|
3485
|
+
§runtime-bookkeeping-policy Runtime bookkeeping cannot acquire new authority.
|
|
3486
|
+
Generated reference publication and audit narration have no reviewer and do not
|
|
3487
|
+
depend on interactive defaults. An unexpected bookkeeping proposal rejects through
|
|
3488
|
+
the ordinary lifecycle, even if the server would accept other operations.
|
|
3489
|
+
|
|
3490
|
+
A park requires a live obligation or an interactive owner. Connection presence
|
|
3491
|
+
does not determine capability. Ordinary WAIT on streams or delegated work is
|
|
3492
|
+
unchanged; a provider-recovery park whose owner is not interactive concludes on the
|
|
3493
|
+
provider failure ({§provider-recovery}).
|
|
3532
3494
|
|
|
3533
3495
|
---
|
|
3534
3496
|
|
|
@@ -3538,7 +3500,7 @@ Capability admission precedes this decision, so proposal disposition cannot gran
|
|
|
3538
3500
|
|
|
3539
3501
|
### §subscriptions Subscriptions
|
|
3540
3502
|
|
|
3541
|
-
§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
|
|
3503
|
+
§subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. Worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation callback or database access is part of the extension contract.
|
|
3542
3504
|
|
|
3543
3505
|
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.
|
|
3544
3506
|
|
|
@@ -3559,7 +3521,7 @@ the producer's already obtained outcome into a fictitious cancellation result.
|
|
|
3559
3521
|
At process restart every still-open row is necessarily missing its callable owner. Boot
|
|
3560
3522
|
settles it as interruption (`500`) and errors active channels before evaluating parked
|
|
3561
3523
|
loops ({§worker-lifecycle-restart-recovery}); it never reports cancellation (`499`) or
|
|
3562
|
-
pretends to reconstruct an opaque
|
|
3524
|
+
pretends to reconstruct an opaque extension connection.
|
|
3563
3525
|
|
|
3564
3526
|
§subscriptions-causal-resource A subscription's causal Worker belongs to the
|
|
3565
3527
|
entry's workspace. The active entry has
|
|
@@ -3615,12 +3577,12 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3615
3577
|
| Concern | Rule |
|
|
3616
3578
|
|---|---|
|
|
3617
3579
|
| §db-schema-baseline Baseline | Versions 1–8 of `migrations/` are the released baseline, as domain chapters — `001_workspaces`, `002_workers`, `003_loops`, `004_inference`, `005_entries`, `006_log`, `007_subscriptions`, `008_interactions` — each one `MIGRATE` block whose version is the file's numeric prefix. They create the shape 1.21.1 shipped: tables, indexes, views, the constraint triggers that are a table's invariants (guards that only `RAISE`), and a view's `INSTEAD OF` write path. No migration holds an `INIT` block or a trigger that writes a row. |
|
|
3618
|
-
| §db-migrations Evolution | A released version is frozen: only its comments may change. Every shape change is one new file at the next version
|
|
3580
|
+
| §db-migrations Evolution | A released version is frozen: only its comments may change. Every shape change is one new file at the next version, applied by sqlrite above the database's `PRAGMA user_version`, ascending, each in its own transaction with its version bump. A fresh database takes the same path as an existing one. Each migration carries upgrade coverage: `test/intg/schema-baseline.test.ts` pins the released shape's fingerprint and migrates a released database, asserting its rows survive. A process trigger's change needs no migration: its `INIT` block re-declares it on the next open ({§db-process-triggers}). A table anything references cannot be rebuilt in a migration: foreign keys stay enforced inside the migration transaction, so the drop cascades through its children (`011_settled.sql`); such a table evolves by adding columns or redeclaring its guard triggers. Only an unreferenced table is rebuilt (`010_outside_text.sql`). |
|
|
3619
3581
|
| §validation-topology Where an invariant is enforced | The SQL core owns each invariant: a chapter's CHECK constraints and guard triggers are its one statement, and a rule two tables share is the same expression over each column (`entry_channel_producer_result_contract` and `subscriptions_result_contract_update` hold the settled-result rule as one text, `011_settled`). Contracts (JSON Schema) are enforced at the gates: a scheme's result entering core (`Results` in plurnk-schemes) and the wire leaving to clients (plurnk-agui's `Validator` calls). Everything between trusts core and the gates and carries no defensive re-validation: a result read back from a row is parsed, never re-asserted. Witness: `test/intg/validation-topology.test.ts` applies one corpus of settled results to the gate, to chapter 5 and to chapter 7 and asserts the three agree on every row. |
|
|
3620
3582
|
| Open failure | A missing table or column after migration means the file's shape disagrees with its version: a database from a newer release, or one from an unreleased development build. The daemon refuses to open it and names both remedies. |
|
|
3621
3583
|
| §db-process-triggers Processes beside their owners | A trigger that writes rows — a cascade, a capture, an ambient event, a publication cursor, a landed curation — is a process, not shape. It is declared as an `-- INIT: <trigger name>` block in the `.sql` file beside the statements that fire it (`ambient.sql` for the ambient feed, `LoopLifecycle.sql`, `Turn.sql`, `Engine.sql` for model calls, `_entry-crud.sql`, `Log.sql`, `ChannelWrite.sql`), as `DROP TRIGGER IF EXISTS` then `CREATE TRIGGER`, so the definition is current on every open of a database whose shape is current. `MIGRATE` always precedes `INIT` and `INIT` runs on the writer only, so a process may reference any table regardless of file order and never runs on the read pool. `test/intg/schema-composition.test.ts` fails on a baseline trigger that writes, an `INIT` trigger that only guards, a block not named after its trigger or not dropping first, and a live trigger set that differs from the declared set after a first and a second open. |
|
|
3622
3584
|
| §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. |
|
|
3623
|
-
| §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.
|
|
3585
|
+
| §db-index-owners Every index has an owner | An explicit index earns its place one of three ways: a registry statement's plan uses it, its leading column is a foreign key whose check it serves, or it enforces uniqueness. The same test fails on any other index, naming it: an index nobody reads is a write on every insert. A column no statement reads is not stored. |
|
|
3624
3586
|
| §db-maintenance-optimize Statistics at shutdown | The daemon's last database step before the caller closes SQLite is `PRAGMA optimize` on the writer (`maintenance_optimize`), so `sqlite_stat1` reflects tables the connection planned against, bounded by SQLite's own analysis limit; a failure there is a reported shutdown error, never silent. Retention runs before it under the operator's policy ({§retention-policy}) and ends with a WAL truncation ({§db-space-reclamation}); no periodic `ANALYZE` runs. |
|
|
3625
3587
|
| §db-space-reclamation The daemon keeps its own file healthy | `PLURNK_SERVICE_AUTO_VACUUM` (`incremental` or `none`) names the mode the daemon keeps its file in. At start, before any drain, a database in another mode is converted (set the mode, one `VACUUM`, which rewrites the file and needs free disk about its size) and the journal says so with page counts before and after. Under `incremental`, every retention pass ends by stepping `PRAGMA incremental_vacuum` to completion once free pages reach `PLURNK_SERVICE_RECLAIM_MIN_FREE_BYTES` (0 = every pass), and reports `reclaimedPages`; below the floor, free pages stay for SQLite to reuse. Under `none` the file never shrinks and freed pages are reused. No operator step is involved beyond the knobs. The WAL stays bounded by SQLite's automatic checkpoint (#764). |
|
|
3626
3588
|
| §content-store Every body is stored once | `contents` holds each settled body once, addressed by its SHA-256, however many channels, workspaces, forks or derivations carry it; rows are immutable. `entry_channel_rows` points a settled channel at its body and keeps an active stream's body as a private buffer until it settles, when it is interned. Every reader and writer uses the `entry_channels` view, whose `INSTEAD OF` triggers intern bodies, refuse a bound `content_hash` that is not the content's, and write each column group only when it changed, so a search attachment is never a representation write. SQLite counts no changes for a view, so a write that must know whether its channel exists returns the channel's name; an outer join cannot flatten the view, so the two statements that need one read `entry_channel_rows` and `contents` directly. `derivation_fts` is an external-content index over `derivation_texts` (a derivation joined to its body); `derivations.content_id` names the indexed text, and the triggers in `_entry-fts.sql` move the index with it and forget it on delete. A body no channel holds and no derivation indexes is collected by retention under `PLURNK_SERVICE_COLLECT_CONTENTS`. Witnesses: `test/intg/retention.test.ts`, `test/intg/entries.test.ts`, `test/intg/fulltext-index.test.ts`. |
|
|
@@ -3645,7 +3607,7 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3645
3607
|
- Tokenization (provider-bound; hot-swap re-tokenizes per {§tokenomics}).
|
|
3646
3608
|
- Provider dispatch, request-accounting validation, and exact-decimal aggregate projection through the shared contracts-owned path.
|
|
3647
3609
|
- Scheme-handler invocation (connections, subprocesses, fetch).
|
|
3648
|
-
-
|
|
3610
|
+
- Extension loading ({§extension-discovery}).
|
|
3649
3611
|
- Stream AbortController lifecycle.
|
|
3650
3612
|
- CLI + daemon.
|
|
3651
3613
|
|
|
@@ -3653,16 +3615,16 @@ When SQL becomes onerous for a specific case, retreat for that case and document
|
|
|
3653
3615
|
|
|
3654
3616
|
---
|
|
3655
3617
|
|
|
3656
|
-
## §core-
|
|
3618
|
+
## §core-extension-composition Extension composition
|
|
3657
3619
|
|
|
3658
|
-
The metaproject contract owns installed membership, the one-
|
|
3659
|
-
shape, and the shared pre-import trust boundary ({§
|
|
3660
|
-
|
|
3661
|
-
Core owns only cross-
|
|
3620
|
+
The metaproject contract owns installed membership, the one-kind manifest
|
|
3621
|
+
shape, and the shared pre-import trust boundary ({§extension-discovery}). Each
|
|
3622
|
+
framework owns its typed discovery result and trusted loading path.
|
|
3623
|
+
Core owns only cross-kind composition, arbitration, and operator presentation
|
|
3662
3624
|
of skipped-package evidence.
|
|
3663
3625
|
|
|
3664
|
-
§
|
|
3665
|
-
For an installed
|
|
3626
|
+
§extension-namespace-arbitration **Every addressable scheme name has one claim.**
|
|
3627
|
+
For an installed extension, claim identity is its kind plus its npm
|
|
3666
3628
|
package name. Core's bundled names are reserved claims. A daemon module's
|
|
3667
3629
|
runtime registration names its module owner and makes one composite executor
|
|
3668
3630
|
claim: its ordinary output scheme and optional resource facet do not compete
|
|
@@ -3672,14 +3634,14 @@ claiming either name, for process-wide and workspace-scoped registrations alike.
|
|
|
3672
3634
|
| Existing claim | Incoming claim | Outcome |
|
|
3673
3635
|
|--------------------------------|---------------------------------------------------------|---------|
|
|
3674
3636
|
| None | Any valid claim | Register it. |
|
|
3675
|
-
| Same installed
|
|
3676
|
-
| Reserved core name | Any
|
|
3677
|
-
| Any
|
|
3637
|
+
| Same installed kind/package | Rescan of the same name | No-op; retain the one registered handler. |
|
|
3638
|
+
| Reserved core name | Any extension, a module included | Fail naming the reserved owner and claimant. |
|
|
3639
|
+
| Any extension | A different owner, including scheme/executor either way | Fail naming both owners. |
|
|
3678
3640
|
| Module runtime | Its optional same-registration scheme facet | Compose one handler under the runtime's single claim. |
|
|
3679
3641
|
|
|
3680
3642
|
Arbitration precedes host registry mutation. External scheme descriptors are
|
|
3681
3643
|
arbitrated before core imports their handlers; executor packages have already
|
|
3682
|
-
crossed their
|
|
3644
|
+
crossed their framework-owned trusted loading path when core arbitrates their
|
|
3683
3645
|
output faces. A rejected claim leaves both scheme and executor registries
|
|
3684
3646
|
unchanged, so registration order cannot turn a collision into precedence.
|
|
3685
3647
|
Installed third-party packages enter through the same scope-agnostic npm
|
|
@@ -3690,15 +3652,21 @@ registration.
|
|
|
3690
3652
|
|
|
3691
3653
|
## §bundled-set Bundled Set
|
|
3692
3654
|
|
|
3693
|
-
|
|
3655
|
+
Extension discovery ({§extension-discovery}) scans installed scoped and unscoped
|
|
3694
3656
|
packages carrying the applicable `plurnk.kind` declaration.
|
|
3695
3657
|
|
|
3696
|
-
§default-
|
|
3697
|
-
of the default
|
|
3698
|
-
|
|
3699
|
-
default
|
|
3700
|
-
framework consumer may intentionally omit
|
|
3701
|
-
documented
|
|
3658
|
+
§default-extension-ownership `@plurnk/plurnk-service` is the sole manifest owner
|
|
3659
|
+
of the default extensions. Frameworks own contracts, discovery, and loading;
|
|
3660
|
+
their runtime dependency graphs contain no extension of their kind. A required
|
|
3661
|
+
default extension missing from a service install is a broken install. A direct
|
|
3662
|
+
framework consumer may intentionally omit extensions and receives that framework's
|
|
3663
|
+
documented behavior for an absent extension.
|
|
3664
|
+
|
|
3665
|
+
`@plurnk/plurnk-tavily-plugin` is the separately installed, opt-in plugin showcase,
|
|
3666
|
+
not a service dependency. Its own tests own installation, native discovery,
|
|
3667
|
+
configuration, and HTTP materialization; service installation coverage proves it
|
|
3668
|
+
is absent from the default composition.
|
|
3669
|
+
|
|
3702
3670
|
Packed executor coverage distinguishes installation from enablement: verify
|
|
3703
3671
|
the package floor, explicit opt-in, and composed allowlist/disable behavior
|
|
3704
3672
|
through discovery and registration outside the development dependency graph
|
|
@@ -3708,32 +3676,31 @@ service runtime dependency, and an optional one ({§mimetype-optional-grammars})
|
|
|
3708
3676
|
must not be. Installation coverage loads each default grammar and verifies
|
|
3709
3677
|
source definitions, references, structural projections, and teardown outside
|
|
3710
3678
|
the checkout's development dependency graph, and proves each optional language
|
|
3711
|
-
degrades by name when its
|
|
3679
|
+
degrades by name when its grammar package is absent.
|
|
3712
3680
|
|
|
3713
3681
|
§install-root-advisory-ownership **The composed service install owns
|
|
3714
|
-
third-party advisory detection.** Only that install resolves the default
|
|
3682
|
+
third-party advisory detection.** Only that install resolves the default extensions
|
|
3715
3683
|
and their combined transitive tree. Its audit reports advisories at the
|
|
3716
3684
|
moderate floor without blocking by default; strict mode makes the same floor a
|
|
3717
3685
|
gate. A chain rooted through an `@plurnk/*` dependency routes to that package's
|
|
3718
3686
|
owner, while other direct roots remain service-owned. First-party package-pin
|
|
3719
|
-
freshness remains the owning
|
|
3687
|
+
freshness remains the owning package's concern.
|
|
3720
3688
|
|
|
3721
|
-
|
|
|
3689
|
+
| Kind | Lean framework | Service-owned default packages |
|
|
3722
3690
|
|-----------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
3723
3691
|
| Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
|
|
3724
|
-
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format
|
|
3725
|
-
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format
|
|
3726
|
-
| | | `image
|
|
3727
|
-
| Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite`
|
|
3692
|
+
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format extensions. |
|
|
3693
|
+
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format extensions. |
|
|
3694
|
+
| | | The `image` and `application-pdf` (header-only, {§mimetype-pdf-facts}) extensions, and every `grammar-{slug}` grammar package in the framework's tree-sitter registry ({§mimetype-grammar-packages}), all under `@plurnk/plurnk-mimetypes-*`. |
|
|
3695
|
+
| Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite` extensions under the `@plurnk/plurnk-execs-*` prefix. |
|
|
3728
3696
|
|
|
3729
|
-
The independently published `tokenizers` artifact is an opt-in
|
|
3697
|
+
The independently published `tokenizers` artifact is an opt-in package. Installing
|
|
3730
3698
|
it beside the service admits it through ordinary package resolution without
|
|
3731
|
-
changing the service manifest.
|
|
3732
|
-
native attachment like an image, and the daemon does no extraction (#542).
|
|
3699
|
+
changing the service manifest.
|
|
3733
3700
|
|
|
3734
3701
|
**Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
|
|
3735
3702
|
operator declarations, local adapters, and finally installed AI SDK provider
|
|
3736
|
-
|
|
3703
|
+
extensions. `Mock` is its integration fixture. Core contains no vendor protocol.
|
|
3737
3704
|
|
|
3738
3705
|
**Core schemes:** `file`, `log`, `prompt`, `skill`, and `worker` expose daemon
|
|
3739
3706
|
state or filesystem orchestration owned by core. `exec` is internal dispatch
|
|
@@ -3744,8 +3711,8 @@ dispatcher contract.
|
|
|
3744
3711
|
|
|
3745
3712
|
The executor registry discovers installed runtimes, probes availability, and
|
|
3746
3713
|
routes ```` ```<runtime> ````; core contributes orchestration and the output-scheme
|
|
3747
|
-
adapter, not runtime implementations. Optional and third-party
|
|
3748
|
-
each
|
|
3714
|
+
adapter, not runtime implementations. Optional and third-party extensions extend
|
|
3715
|
+
each kind by installation and discovery; they never require a framework or
|
|
3749
3716
|
service manifest edit.
|
|
3750
3717
|
|
|
3751
3718
|
---
|
|
@@ -3813,12 +3780,12 @@ Node's pre-script env-file form and the executable's post-script form share the
|
|
|
3813
3780
|
|
|
3814
3781
|
| Source | Panel | Admission |
|
|
3815
3782
|
|---|---|---|
|
|
3816
|
-
|
|
|
3817
|
-
| Agent Plugin
|
|
3783
|
+
| Extension package | `.env.defaults` at the package root | `@plurnk/*` or a `plurnk` package field; {§extension-trust-boundary} |
|
|
3784
|
+
| Agent Plugin extension | `ai.plurnk/.env.defaults` | The winning daemon-wide plugin in {§agent-plugins-hosting}, a valid native declaration, and the same trust gate |
|
|
3818
3785
|
|
|
3819
3786
|
Root and trust flags apply before collection. A project plugin contributes no native panel.
|
|
3820
|
-
Non-module native panels follow their npm-only
|
|
3821
|
-
a plain-folder declaration does not suppress an installed
|
|
3787
|
+
Non-module native panels follow their framework's npm-only discovery ({§extension-manifest-read});
|
|
3788
|
+
a plain-folder declaration does not suppress an installed extension's panel.
|
|
3822
3789
|
Linked packages resolve panels against the same canonical root as native code;
|
|
3823
3790
|
an absent panel is optional, but a panel escaping that root is rejected.
|
|
3824
3791
|
The file travels with its code and is its configuration reference. All admitted files compose
|
|
@@ -3828,6 +3795,24 @@ persisting another copy or exposing effective values. Duplicate key ownership fa
|
|
|
3828
3795
|
owners. Invalid optional native panels are diagnosed and prevent that extension from loading;
|
|
3829
3796
|
they do not block the remaining floor or the repair path ({§configuration-repair-path}).
|
|
3830
3797
|
|
|
3798
|
+
§operator-config-undeclared-key **A key no panel declares is reported, never refused.** At boot the
|
|
3799
|
+
daemon checks each `PLURNK_*` key the operator's configuration files set — `$XDG_CONFIG_HOME/plurnk/.env`
|
|
3800
|
+
and a `--config` file, never an `--env-file*` layer or the process environment — against the
|
|
3801
|
+
assembled panels' declarations, live and commented alike. A declaration whose name holds a
|
|
3802
|
+
`<placeholder>` segment declares a family and is only ever commented. A placeholder, like the scope
|
|
3803
|
+
after a declared name's `_`, stands for one or more letters, digits, `_`, `.` or `-`.
|
|
3804
|
+
|
|
3805
|
+
| Key the file sets | Outcome |
|
|
3806
|
+
|---|---|
|
|
3807
|
+
| A declared name | none |
|
|
3808
|
+
| A declared name, `_`, and a scope (`PLURNK_PROVIDERS_EFFORT_<alias>`, `PLURNK_MODEL_<alias>`) | none |
|
|
3809
|
+
| A family member (`# PLURNK_MCP_<alias>=` declares `PLURNK_MCP_docs_ENABLED`) | none |
|
|
3810
|
+
| Another component's: the client's `PLURNK_CLIENT_*` and `PLURNK_COMPOSITION_*`; the bench's `PLURNK_BENCH*`, `PLURNK_SWEBENCH_*`, `PLURNK_PI_*` and `PLURNK_CANDIDATE_*` | none |
|
|
3811
|
+
| Any other `PLURNK_*` key | one `info` Notice from `engine:configuration`, kind `configuration_undeclared`, naming the `key` and the file |
|
|
3812
|
+
|
|
3813
|
+
Boot continues. The notice is the operator's information: `start`, `config` and `config check` print
|
|
3814
|
+
it, `config check` still passes, and it never enters a model's packet.
|
|
3815
|
+
|
|
3831
3816
|
§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:
|
|
3832
3817
|
|
|
3833
3818
|
| Rule | What it refuses |
|
|
@@ -3839,7 +3824,6 @@ they do not block the remaining floor or the repair path ({§configuration-repai
|
|
|
3839
3824
|
| `tunable` | a numeric constant whose own name says duration, size, count or pacing, unless `scripts/env-surface-mechanism.json` registers why it is mechanism |
|
|
3840
3825
|
| `timer-literal` | a bare number handed to a timer or a deadline; it is named or read from the panel, and has no register |
|
|
3841
3826
|
| `dead-knob` | a live declaration nothing consumes |
|
|
3842
|
-
| `retired-declared` | a retired key still declared; a retired key is named only by the code that refuses it |
|
|
3843
3827
|
| `duplicate-owner` | a key two packages declare |
|
|
3844
3828
|
| `test-floor` | a package that ships a panel and tests off it |
|
|
3845
3829
|
|
|
@@ -3866,11 +3850,12 @@ names the offending variable or file/entry and retains its cause.
|
|
|
3866
3850
|
|
|
3867
3851
|
| Owner | Offline validation |
|
|
3868
3852
|
|---|---|
|
|
3869
|
-
| Core | Model selection, file-creation/effect/
|
|
3853
|
+
| Core | Model selection, file-creation/effect/approval policy, members definitions and controls, skill-fetch settings and root selection |
|
|
3870
3854
|
| MCP | Whole definitions from the environment and selected files (cwd is the project for this check), future-alias controls, catalog settings, timeouts, retry pacing and registry URL |
|
|
3871
3855
|
| A2A | Whole outbound definitions and controls, timeout/diagnostic bounds, configured inbound exposure |
|
|
3872
3856
|
| Schedule | Whole definitions and controls, recurrence syntax, time zone and preview count |
|
|
3873
3857
|
| Hooks | Command/argument/event configuration and delivery bounds |
|
|
3858
|
+
| Discovered modules | Each module's own configuration, as its factory constructs it ({§module-self-activation}) |
|
|
3874
3859
|
|
|
3875
3860
|
Disabled definitions and controls without a resource are validated, not skipped.
|
|
3876
3861
|
Checking creates no database, starts no process or listener, arms no schedule,
|
|
@@ -3894,14 +3879,14 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
|
|
|
3894
3879
|
|---|---|
|
|
3895
3880
|
| `PLURNK_SERVICE_DB_PATH` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
3896
3881
|
| `PLURNK_SERVICE_SHARE_FOLDER` | Parent of the shares written when no folder is named ({§share-folder}); empty is `$XDG_STATE_HOME/plurnk/shares`. |
|
|
3897
|
-
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The listener's bind address and TCP port
|
|
3882
|
+
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The daemon-owned listener's bind address and TCP port; modules mount their paths on that one listener ({§http-host}). **A key the daemon and its clients both read has a shared owner**: `@plurnk/plurnk-contracts` declares these two and the optional `PLURNK_AGUI_URL` on its own panel, the one package every side depends on. The daemon folds it like any installed member's, a client folds it beneath its own, and so neither holds the other's default. The service's `--host` and `--port` flags are generated from that panel. |
|
|
3898
3883
|
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
|
|
3899
3884
|
| §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. |
|
|
3900
3885
|
| `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
|
|
3901
3886
|
| `PLURNK_SERVICE_MAX_TURNS` | Operator model-call **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The durable worker-tree budget includes descendant calls, BARE, and park/resume under {§turn-cap-counts-the-tree}; non-model chronology consumes none. |
|
|
3902
|
-
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every
|
|
3887
|
+
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every compiled op dispatches. Each resolved target statement counts once, whether authored separately or in a group ({§target-group}). Overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. Lifecycle operations remain exempt ({§operator-config-workspace-max-commands-floor}). Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
3903
3888
|
| §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. |
|
|
3904
|
-
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks
|
|
3889
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks workers with a reviewer, otherwise concludes their loop, or returns BARE's failure under {§provider-recovery}. |
|
|
3905
3890
|
| `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
|
|
3906
3891
|
| `PLURNK_SERVICE_MAX_STRIKES` | Consecutive turn-contract strike threshold ({§engine-rails}). |
|
|
3907
3892
|
| `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}. |
|
|
@@ -3910,8 +3895,6 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
|
|
|
3910
3895
|
| `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
|
|
3911
3896
|
| `PLURNK_SERVICE_MIN_CYCLES` | Min repetitions before cycle detection fires ({§engine-rails}). |
|
|
3912
3897
|
| `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | Max period length cycle detection examines ({§engine-rails}). |
|
|
3913
|
-
| `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | Initial forensic witness output allowance ({§digest-requiem}). |
|
|
3914
|
-
| `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
|
|
3915
3898
|
| `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}). |
|
|
3916
3899
|
| `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}). |
|
|
3917
3900
|
| `PLURNK_SERVICE_EXEC_CONCURRENCY` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
|
|
@@ -3935,15 +3918,16 @@ instead of a user's boot, and a dead knob cannot ship.
|
|
|
3935
3918
|
|
|
3936
3919
|
Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
|
|
3937
3920
|
|
|
3938
|
-
External
|
|
3921
|
+
External extensions declare their own env vars in their own `.env.defaults`, assembled at boot ({§operator-config-env-defaults}).
|
|
3939
3922
|
|
|
3940
|
-
§operator-config-cli-flags **Admin CLI flags derive only from the service package's `.env.defaults`.** Every `PLURNK_*` declared there becomes `--<kebab-cased-name>` (prefix stripped, lowercased, underscores → dashes). A comment immediately above the declaration becomes its `-h` description. Installed
|
|
3923
|
+
§operator-config-cli-flags **Admin CLI flags derive only from the service package's `.env.defaults`.** Every `PLURNK_*` declared there becomes `--<kebab-cased-name>` (prefix stripped, lowercased, underscores → dashes). A comment immediately above the declaration becomes its `-h` description. Installed extension defaults join the environment floor and catalog but do not implicitly expand the service executable's flag surface.
|
|
3941
3924
|
|
|
3942
3925
|
### Loop limits
|
|
3943
3926
|
|
|
3944
3927
|
§turn-cap-counts-the-tree **The turn ceiling is the worker tree's budget of model
|
|
3945
3928
|
calls.** The owner is the current loop of the topmost ancestor-or-self worker that has
|
|
3946
|
-
one: for a tree a client started,
|
|
3929
|
+
one, excluding the runtime actor (origin `_plurnk`): for a tree a client started,
|
|
3930
|
+
the root worker's loop current when this loop began (its
|
|
3947
3931
|
`max_turns`: the client's `maxTurns` clamped by the operator ceiling below); a loop with no
|
|
3948
3932
|
such ancestor owns its own budget. Every model call on the owner's loop and on any later
|
|
3949
3933
|
loop of the owner's descendants spends it, emission turns and BARE calls alike, open or
|
|
@@ -3952,6 +3936,10 @@ terminal ({§loop-terminals}) when the ceiling is met; a BARE beyond the budget
|
|
|
3952
3936
|
429 `max-turns` before any provider call, so one turn cannot spend past it with a batch. A
|
|
3953
3937
|
child loop inherits the value and binds the same count.
|
|
3954
3938
|
|
|
3939
|
+
The runtime actor supplies no ceiling and does not combine otherwise independent model
|
|
3940
|
+
subtrees into one allowance. Its descendants still share their own model tree's ceiling.
|
|
3941
|
+
The shipped ceiling is `-1` (uncapped); client and transport defaults introduce no finite cap.
|
|
3942
|
+
|
|
3955
3943
|
§operator-config-max-turns-ceiling Enforcement is per-use-site — no central most-restrictive pass; each ceiling is checked where it bites. `PLURNK_SERVICE_MAX_TURNS` at `-1` is no cap; when an operator sets a positive value, the per-call request is `min()`-capped against it. Other termination rules remain independent ({§loop-terminals}).
|
|
3956
3944
|
|
|
3957
3945
|
### Workspace settings
|
|
@@ -3984,9 +3972,9 @@ leak into another.
|
|
|
3984
3972
|
workspace: a client tightens the runaway-op guard and never raises it past
|
|
3985
3973
|
the operator's.
|
|
3986
3974
|
- §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3975
|
+
WAIT and parameterless KILL are never counted and always dispatch, so `0` is a valid
|
|
3976
|
+
floor, admitting lifecycle intent with zero actions. Dropped actions still prevent
|
|
3977
|
+
successful completion under {§turn-disposition}.
|
|
3990
3978
|
- §operator-config-workspace-git `settings.git` (`false`) **denies** git for the workspace (`PLURNK_SERVICE_GIT_ALLOWED` AND workspace) — the client opts its workspace out of git membership and working-tree status; it can never re-enable git past the operator's service-wide lockout.
|
|
3991
3979
|
- §operator-config-workspace-file-create-scope `settings.fileCreateScope` narrows `PLURNK_SERVICE_FILE_CREATE_SCOPE` by the ordered lattice `none < root < namespace`; a workspace may disable creation or confine a namespace-enabled service to its root, but never widen the operator's ceiling. Unknown service values fail configuration validation and unknown workspace values fail `workspace.create`.
|
|
3992
3980
|
- `settings.membersModelScope` narrows `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` ({§members-model-scope}).
|
|
@@ -4004,7 +3992,7 @@ the policy renders in exactly one packet section. Every other tier runs the
|
|
|
4004
3992
|
test cascade, so shipped-default regressions are otherwise invisible by
|
|
4005
3993
|
construction.
|
|
4006
3994
|
|
|
4007
|
-
§operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture that is identical on every machine: complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, the operator's installed skills and plugins left unread ({§agent-roots}),
|
|
3995
|
+
§operator-config-real-model-profile **Real-model gate profile.** `plurnk-core/.env.test` is committed source and is the single shared profile for live, demo, and the candidate daemon used by benchlets. Live/demo load it after operator files; the candidate daemon loads it below its inherited environment. Direct shell/benchmark overrides win in both paths. Its exact allowlist is limited to gate-wide service posture that is identical on every machine: complete catalog orientation, automatic Git membership when the operator ceiling permits Git, ambient operator-file docs/packet notes cleared, the operator's installed skills and plugins left unread ({§agent-roots}), server approval set to accept ({§worker-owner-resolution}), and ambient MCP/A2A and schedules default disabled. The drivers also project per-alias `ENABLED=0` overrides for named MCP, A2A, schedule, membership, and skill resources in the operator's config file. Definitions remain inspectable; explicit shell/benchmark controls win. Mock-tier bootstrap clears these ambient families before loading its fixture floor. No operator file is rewritten. Configuration with a narrower or variable owner stays outside it:
|
|
4008
3996
|
|
|
4009
3997
|
| Owner | Configuration |
|
|
4010
3998
|
|---|---|
|
|
@@ -4043,9 +4031,10 @@ a fresh-user configuration.
|
|
|
4043
4031
|
|
|
4044
4032
|
## §rpc Module seam
|
|
4045
4033
|
|
|
4046
|
-
Core implements the contracts-owned {§application-port} and
|
|
4047
|
-
|
|
4048
|
-
action-name catalog
|
|
4034
|
+
Core implements the contracts-owned {§application-port} and hosts the module
|
|
4035
|
+
contract published in `@plurnk/plurnk-modules` ({§module-contract}). It owns the one
|
|
4036
|
+
listener modules mount on ({§http-host}), but no public action-name catalog or generic
|
|
4037
|
+
string-dispatched method registry. A
|
|
4049
4038
|
client-interface module such as `plurnk-agui` owns its public protocol, action
|
|
4050
4039
|
names, request validation, discovery result, and event projection.
|
|
4051
4040
|
|
|
@@ -4053,13 +4042,13 @@ names, request validation, discovery result, and event projection.
|
|
|
4053
4042
|
|
|
4054
4043
|
```mermaid
|
|
4055
4044
|
flowchart LR
|
|
4056
|
-
bind["Host
|
|
4057
|
-
register["
|
|
4045
|
+
bind["Host binds the daemon's listener<br/>unadmitted"] --> register
|
|
4046
|
+
register["Register explicit, then discovered modules"] --> setup["module.setup(ModuleSetupSeam)"]
|
|
4058
4047
|
setup --> capabilities["Register static capabilities,<br/>workspace activators, and actions"]
|
|
4059
4048
|
capabilities --> ready["Process-wide schemes ready"]
|
|
4060
4049
|
ready --> recovery["Reconcile durable lifecycle"]
|
|
4061
4050
|
recovery --> start["module.start(ApplicationPort)"]
|
|
4062
|
-
start --> interface["
|
|
4051
|
+
start --> interface["Listener admitted:<br/>module-owned client protocol ready"]
|
|
4063
4052
|
recovery -->|durable workspace work| demand["First workspace demand"]
|
|
4064
4053
|
interface -->|client workspace work| demand
|
|
4065
4054
|
demand --> lease["Acquire capability residency"]
|
|
@@ -4076,17 +4065,17 @@ flowchart LR
|
|
|
4076
4065
|
```
|
|
4077
4066
|
|
|
4078
4067
|
Every registered module's `setup` runs in registration order before any
|
|
4079
|
-
module's `start
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
{§startup-listener-admission}
|
|
4083
|
-
|
|
4068
|
+
module's `start` ({§module-phases}; failures follow {§module-failure}). Core
|
|
4069
|
+
then readies process-wide schemes, reconciles durable lifecycle, and starts
|
|
4070
|
+
modules in registration order. The daemon's listener is bound before durable admission
|
|
4071
|
+
({§startup-listener-admission}) and admitted once every module has started
|
|
4072
|
+
({§module-http-mounts}). Persisted workspaces with
|
|
4084
4073
|
no durable work stay passive until first demand; activation publishes their
|
|
4085
4074
|
complete capabilities and documentation before the demanding operation
|
|
4086
4075
|
proceeds. `setup` is the readiness boundary for every capability registered
|
|
4087
|
-
with Core: recovery may demand a workspace provider before `start`.
|
|
4088
|
-
|
|
4089
|
-
|
|
4076
|
+
with Core: recovery may demand a workspace provider before `start`. Requests on
|
|
4077
|
+
the listener remain unavailable until it is admitted; a module opens any other exterior
|
|
4078
|
+
ingress only after recovery. No
|
|
4090
4079
|
registered capability may depend on exterior ingress. A module, and any distinct
|
|
4091
4080
|
lifetime object returned by `start`, may implement the following phases:
|
|
4092
4081
|
|
|
@@ -4103,21 +4092,26 @@ even if setup fails. A returned object identical to its module is tracked once.
|
|
|
4103
4092
|
|
|
4104
4093
|
| Source | Declaration | Lifetime |
|
|
4105
4094
|
|---|---|---|
|
|
4106
|
-
|
|
|
4095
|
+
| Extension package | `package.json#plurnk` with `kind: "module"` and `module`, an export subpath resolved through the package's own exports as in {§executor-dynamic-runtimes} | Daemon-wide; the form every first-party default module uses |
|
|
4107
4096
|
| Agent Plugin | `plugin.json#extensions.ai.plurnk` with `kind: "module"` and a `module` path under `ai.plurnk/` | Daemon-wide; npm and selected user roots only |
|
|
4108
4097
|
| Project Agent Plugin | Portable components only | Workspace-scoped; native code is not imported |
|
|
4109
4098
|
|
|
4110
|
-
The export is one DaemonModule object or no-argument factory.
|
|
4099
|
+
The export is one DaemonModule ({§module-contract}) object or no-argument factory. The host
|
|
4100
|
+
records each module's owner, the package it came from, and its diagnostics name that owner. The
|
|
4101
|
+
service registers no module itself; a host that registers one explicitly, such as a test
|
|
4102
|
+
substituting a package, names it by its package the same way. Standard bundles follow
|
|
4111
4103
|
{§agent-plugins-hosting} source order, then other installed module packages load in package-name
|
|
4112
|
-
order. All trusted modules register before setup
|
|
4113
|
-
|
|
4104
|
+
order. All trusted modules register before setup; a daemon without a listener then leaves out
|
|
4105
|
+
every one that declares mounts ({§module-http-mounts}). A package the host registered explicitly is
|
|
4106
|
+
never also discovered: discovery skips that owner before importing it. Untrusted modules are reported and not imported. Invalid
|
|
4114
4107
|
declarations, unavailable module files and configuration errors during construction are diagnosed
|
|
4115
|
-
at the affected
|
|
4108
|
+
at the affected extension, a declaration's error owned by `extensions` and a
|
|
4109
|
+
module's own configuration error by `module:<package>`; healthy siblings remain available. A factory validates startup
|
|
4116
4110
|
configuration before `setup` acquires resources. Failures after registration begins follow
|
|
4117
4111
|
{§module-lifecycle} cleanup, not a partial-registration fallback.
|
|
4118
4112
|
An invalid module object, factory result or lifecycle member is an implementation contract failure,
|
|
4119
|
-
not configuration, and fails loudly.
|
|
4120
|
-
interfaces and
|
|
4113
|
+
not configuration, and fails loudly. What a module contributes registers through its owning public
|
|
4114
|
+
interfaces and is released during {§module-lifecycle} resource teardown.
|
|
4121
4115
|
|
|
4122
4116
|
§module-shutdown-order `Daemon.stop()` first rejects new capability demand and
|
|
4123
4117
|
aborts proposals, branches, derivations, and worker scopes. It begins module
|
|
@@ -4163,18 +4157,21 @@ flowchart LR
|
|
|
4163
4157
|
observers --> database[Maintain and release database]
|
|
4164
4158
|
```
|
|
4165
4159
|
|
|
4160
|
+
§module-host-capabilities **The coordinator's host interface is core's own.**
|
|
4161
|
+
The daemon passes one object implementing every published slice
|
|
4162
|
+
({§module-seam-slices}); these functions are on it too, for core's
|
|
4163
|
+
Functionality coordinator and core's own witnesses, and are not part of the
|
|
4164
|
+
published module contract.
|
|
4165
|
+
|
|
4166
4166
|
| Setup function | Contract |
|
|
4167
4167
|
|---|---|
|
|
4168
4168
|
| `registerRuntimes([{ decl, executor, availability, scheme? }, ...])` | Validates the complete canonical tag set under {§executor-runtime-declaration}, then publishes every process-wide executor and optional claimed scheme facet atomically. |
|
|
4169
|
-
| `registerScheme(name, handler)` | Adds one process-wide addressable scheme handler; scheme readiness and model-facing capability publication remain core-owned. |
|
|
4170
|
-
| §module-action-registration `registerModuleAction({ name, scope, residency, 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. `residency` is explicitly `required` or `none`: only the former acquires workspace capabilities and reconciles worker documents. Worldless actions require `none`. 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. |
|
|
4171
4169
|
| §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. |
|
|
4172
4170
|
| §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}). |
|
|
4173
|
-
| `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. |
|
|
4174
|
-
| §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. |
|
|
4175
|
-
| §module-functionality-adapter `registerFunctionalityAdapter(adapter)` | Registers one family beneath the shared coordinator ({§functionality-coordinator}). |
|
|
4176
4171
|
| §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. |
|
|
4177
4172
|
|
|
4173
|
+
Core keys each {§module-workspace-directory} by a stable random workspace
|
|
4174
|
+
storage key in its own `workspace_module_state` row.
|
|
4178
4175
|
Module directory allocation is lazy, atomic in SQLite, and independent of the
|
|
4179
4176
|
project root, daemon CWD, and workspace/worker environment overrides. New
|
|
4180
4177
|
directories use mode `0700`; existing permissions are not rewritten. Module
|
|
@@ -4264,12 +4261,33 @@ Retryability describes the actual failed condition, not its numeric status.
|
|
|
4264
4261
|
| Verb | Common contract |
|
|
4265
4262
|
|---|---|
|
|
4266
4263
|
| `list` | Project definitions, ownership (`origin`), winning configuration source (`provenance`), enabledness, and published preparation outcome: disabled, dormant, active, unavailable with its Problem, or authorization-required. No credential values. |
|
|
4267
|
-
| `discover` | Return inert candidates. Never install, persist, enable, or execute them. |
|
|
4264
|
+
| `discover` | Return inert candidates for the inputs the family serves ({§functionality-discover-advertisement}). Never install, persist, enable, or execute them. |
|
|
4268
4265
|
| `add` | Admit and persist a local definition, prepare it, and enable it atomically. It may override an inherited definition. Reapplying the same local definition enables it idempotently (200); a different local definition for that alias fails 409 without replacing it. |
|
|
4269
4266
|
| `enable` | Publish an available definition; retry preparation if unavailable. |
|
|
4270
4267
|
| `disable` | Withdraw live capability; retain its definition and saved results. |
|
|
4271
4268
|
| `remove` | Forget the locally owned definition and its enabledness override. Restore any inherited definition with its inherited enabledness. Inherited definitions cannot be removed at this scope. Saved results remain. |
|
|
4272
4269
|
|
|
4270
|
+
§functionality-discover-advertisement **A family's `discover` advertises exactly the inputs it
|
|
4271
|
+
serves.** The coordinator builds the family's discover input schema from its declared discovery
|
|
4272
|
+
({§functionality-discovery-inputs}): the declared inputs with their shared
|
|
4273
|
+
`FunctionalityDiscoverQuery` definitions and no other property (a multi-scope family adds
|
|
4274
|
+
`scope`), and, unless a request naming none lists everything, at least one of them: the one
|
|
4275
|
+
input required, or any of several. The client actions, the manager's tool documents and their
|
|
4276
|
+
schema documents carry that schema. Any other input, or a request naming none, is refused by the
|
|
4277
|
+
shared schema check as 400 `arguments-invalid`, its `errors` naming each field; no family mints
|
|
4278
|
+
its own refusal for an input it does not serve. A family without discovery has no `discover`
|
|
4279
|
+
action, and its manager teaches none. A value of a served input the family cannot use remains the
|
|
4280
|
+
family's own refusal.
|
|
4281
|
+
|
|
4282
|
+
| Family | Inputs | A request naming none |
|
|
4283
|
+
|---|---|---|
|
|
4284
|
+
| `skills` | `source` ({§skills-functionality}) | Refused |
|
|
4285
|
+
| `schedule` | `source` ({§schedule-clock}) | Refused |
|
|
4286
|
+
| `mcp` | `query`, while a registry is configured; otherwise no discovery ({§mcp-registry-discovery}) | Refused |
|
|
4287
|
+
| `a2a` | `source`, `configuration` ({§a2a-functionality}) | Refused |
|
|
4288
|
+
| `env` | `query`, `source` ({§env-functionality}) | The whole catalog |
|
|
4289
|
+
| `members` | `query` ({§members-functionality}) | Refused |
|
|
4290
|
+
|
|
4273
4291
|
§configuration-definition-resolution **Named resource definitions replace whole;
|
|
4274
4292
|
independent behavior controls remain independent.** Source readers and scope
|
|
4275
4293
|
overlays apply the same boundary:
|
|
@@ -4309,9 +4327,8 @@ composition boundaries, not arbitrary exceptions:
|
|
|
4309
4327
|
| Optional startup integration (hooks, hosted A2A, observability) cannot be configured | Withhold that integration and retain its exact configuration diagnostic. Activate the client interface and unrelated capabilities; never invent a replacement setting. |
|
|
4310
4328
|
| Invalid default model or child selector | Retain its diagnostic at startup; keep client inspection and explicit selection available. A request relying on the invalid selector fails with `daemon:configuration/configuration-invalid` (503), naming its key. Never substitute another model or silently inherit a child model. |
|
|
4311
4329
|
| Model construction or endpoint verification fails | Reject selection/use before inference or committing the selection. Keep the client available; a later selection can retry or choose another route. |
|
|
4312
|
-
| Invalid effect, file-creation, or
|
|
4330
|
+
| Invalid effect, file-creation, or server approval policy | Retain the startup diagnostic. Reject the affected operation as `daemon:configuration/configuration-invalid` (503); no guessed admission policy, external effect, or orphan approval wait. Independent operations remain usable. |
|
|
4313
4331
|
| Invalid retention configuration | Withhold collection and automatic storage conversion, including shutdown collection. Preserve stored evidence and expose the diagnostic; do not substitute a deletion policy. |
|
|
4314
|
-
| Invalid packet configuration or retired capacity knobs | Retain the startup diagnostic and keep client inspection available. Reject affected packet construction before inference with `daemon:configuration/configuration-invalid` (503). Never guess a capacity or projection setting. |
|
|
4315
4332
|
| Invalid executor construction/probe configuration | Keep the installed declaration and its diagnostic, but no executable instance or output scheme. Other executors and ordinary READ/EDIT remain usable. Invoking the unavailable tag returns its exact 503 configuration Problem. |
|
|
4316
4333
|
| Invalid execution scheduling, input, or scratch configuration | Diagnose at startup and validate on the affected execution path before admission, stream creation, or external effects. Scratch configuration applies only to resource-backed execution; inline programs remain independent. Never substitute concurrency, timeout, or directory settings. |
|
|
4317
4334
|
| Invalid model-alias catalog | Fail catalog inspection explicitly; omit its unavailable snapshot rather than report an empty catalog. Exact provider/model selection does not depend on aliases. |
|
|
@@ -4325,7 +4342,10 @@ composition boundaries, not arbitrary exceptions:
|
|
|
4325
4342
|
| Internal invariant, state, or implementation failure | Preserve the exception; never reclassify it as an operator configuration error. |
|
|
4326
4343
|
|
|
4327
4344
|
Client discovery and passive synchronization report startup diagnostics through the
|
|
4328
|
-
existing Notice channel, even without a usable model.
|
|
4345
|
+
existing Notice channel, even without a usable model. Each is a Notice from `engine:configuration`
|
|
4346
|
+
of kind `configuration_unavailable` that names the failed setting's `key` and its `owner`: the
|
|
4347
|
+
setting's reader (such as `retention`, `model` or `executor:<runtime>`), a family, `extensions` for an
|
|
4348
|
+
extension declaration, or a module as `module:<package>`. The first turn of a drain, and a changed diagnostic
|
|
4329
4349
|
thereafter, reports unresolved configuration to both client and model. An
|
|
4330
4350
|
unchanged diagnostic is not repeated every turn. Operation failures remain Problems.
|
|
4331
4351
|
|
|
@@ -4356,32 +4376,6 @@ publication contract, and creates no log entries or model Notices. Published
|
|
|
4356
4376
|
failures retain their exact Problems in `list`. Concurrent consumers share the
|
|
4357
4377
|
workspace activity; a client disconnect does not clear another consumer's work.
|
|
4358
4378
|
|
|
4359
|
-
§functionality-adapter **An adapter owns protocol truth.** It declares its
|
|
4360
|
-
family, namespace owner, definition schema, contributed defaults, discovery,
|
|
4361
|
-
admission, preparation, and teardown, and its alias grammar when that is not
|
|
4362
|
-
the shared lowercase-hyphen one: the coordinator enforces whichever grammar the
|
|
4363
|
-
family declares, at admission, in the service projection, and on persisted
|
|
4364
|
-
state, so an environment variable's name is an alias exactly as a skill name
|
|
4365
|
-
is. Admission distinguishes explicit client
|
|
4366
|
-
actions from model operations where the family contract requires it
|
|
4367
|
-
({§members-model-scope}). Preparation receives each complete definition with optional
|
|
4368
|
-
adapter-owned interpretation context. Context is source semantics, not policy or provenance;
|
|
4369
|
-
it participates in runtime identity and hot-load comparisons, is never projected as configuration
|
|
4370
|
-
or persisted into a workspace override, and cannot survive replacement by a local definition.
|
|
4371
|
-
Removing that override restores the current inherited definition and context together.
|
|
4372
|
-
Descriptive provenance alone does not change runtime identity. Preparation returns runtimes, documents, per-alias
|
|
4373
|
-
outcomes, and a snapshot with `commit`/`abort`. Successful publication commits;
|
|
4374
|
-
failure aborts; cooling tears down. Protocol continuations remain ordinary
|
|
4375
|
-
module actions. Optional `forget` releases an installed or provisioned
|
|
4376
|
-
definition before removal; failure rejects removal. The
|
|
4377
|
-
seam's shapes — the identity a verb acts under, its options, definition
|
|
4378
|
-
sources, outcomes, preparation, the prepared result and the family handle —
|
|
4379
|
-
are declared once in `plurnk-contracts` and imported by core and every
|
|
4380
|
-
module; core adds only its own face of the seam, the runtime registration a
|
|
4381
|
-
resident family prepares and the scheme facet it may expose.
|
|
4382
|
-
An adapter may expose current partial-source `configurationNotices`; these join the ordinary
|
|
4383
|
-
workspace diagnostics without preventing independently valid definitions from preparing.
|
|
4384
|
-
|
|
4385
4379
|
§functionality-hotload **Out-of-band state is admitted before the next turn.** An adapter whose
|
|
4386
4380
|
`available` reads state that changes outside the daemon, such as skill roots ({§skills-hotload}) or
|
|
4387
4381
|
installed plugins ({§agent-plugins-hosting}), implements `refreshIfChanged`. Turn admission calls it
|
|
@@ -4421,9 +4415,10 @@ its discovery roots explicitly ({§operator-config-real-model-profile}), so
|
|
|
4421
4415
|
operator roots do not shape a gate. Root selection does not restrict explicit
|
|
4422
4416
|
source definitions. Skills mutations change workspace bindings, not these roots
|
|
4423
4417
|
({§skills-functionality}); MCP mutations likewise remain workspace-owned. The module setup seam's
|
|
4424
|
-
`
|
|
4425
|
-
|
|
4426
|
-
|
|
4418
|
+
`workspacePaths` supplies selected `<project>/.agents`, `$XDG_CONFIG_HOME/plurnk`,
|
|
4419
|
+
and `~/.agents` directories in precedence order with their scopes, omitting project
|
|
4420
|
+
when no project is bound ({§module-workspace-paths}). Modules own their file formats;
|
|
4421
|
+
core owns discovery roots.
|
|
4427
4422
|
|
|
4428
4423
|
An adapter may expose a `scheme` facet beneath its family's runtime namespace
|
|
4429
4424
|
({§runtime-resource-binding}). A facet claims a path subtree and is the scheme's
|
|
@@ -4464,8 +4459,9 @@ set any name it lists or none of them — it answers which names have a **consum
|
|
|
4464
4459
|
a Worker learns the name of a value only the operator can supply. The catalog projects
|
|
4465
4460
|
declarations, never the host environment, so a credential the operator has filled in appears by
|
|
4466
4461
|
name with its documentation and an empty value ({§exec-env-scoped}: referred to by name, never
|
|
4467
|
-
read). `
|
|
4468
|
-
|
|
4462
|
+
read). `source` selects one declaring package, and a request naming neither input is the whole
|
|
4463
|
+
catalog. A client's own environment is no input: contributing candidates, it would be a second
|
|
4464
|
+
door past the ceiling.
|
|
4469
4465
|
|
|
4470
4466
|
The family publishes no process runtimes. Its values are read at the spawn that uses them,
|
|
4471
4467
|
not from a live process or a cached worker environment.
|
|
@@ -4478,11 +4474,12 @@ than capability — with worker overrides above workspace defaults. The adapter
|
|
|
4478
4474
|
coordinator keys durable state and the locally-owned `origin`
|
|
4479
4475
|
by it: a workspace-scoped family's own entries carry origin `workspace`, a worker-scoped
|
|
4480
4476
|
family's carry `worker`. Origin names ownership, never scope, so a projection never claims the
|
|
4481
|
-
workspace set a value one Worker set for itself. Nothing else in the contract varies
|
|
4482
|
-
|
|
4477
|
+
workspace set a value one Worker set for itself. Nothing else in the contract varies but the
|
|
4478
|
+
discovery inputs a family serves ({§functionality-discover-advertisement}): the verbs, the two
|
|
4479
|
+
projections, enabledness, and the service-baseline rules are one implementation
|
|
4483
4480
|
across every family, which is what keeps their idioms from drifting apart.
|
|
4484
4481
|
|
|
4485
|
-
A family projects `<scope>.<family>.<verb>` for each supported scope. The action's
|
|
4482
|
+
A family projects `<scope>.<family>.<verb>` for each verb it serves, in each supported scope. The action's
|
|
4486
4483
|
context binds that scope; a worker-scoped action also names the Worker. Its durable
|
|
4487
4484
|
value is the same shape per (worker, family) in `worker_module_state`, read
|
|
4488
4485
|
at each verb and at each spawn rather than held in the workspace snapshot. Its `list` and
|
|
@@ -4517,9 +4514,9 @@ Admission, tools, documents, Turn 0, and client status consume that publication.
|
|
|
4517
4514
|
The coordinator's synchronous `publish` participates in the registry commit;
|
|
4518
4515
|
its returned undo restores the previous view before rollback reconciles documents.
|
|
4519
4516
|
Neither callback performs fallible I/O. Publication failure restores the preceding
|
|
4520
|
-
configuration/runtime snapshot; it cannot roll back
|
|
4521
|
-
|
|
4522
|
-
reported as successful configuration
|
|
4517
|
+
configuration/runtime snapshot; it cannot roll back an external effect of preparation,
|
|
4518
|
+
such as a fetched skill source. A failed external effect retains its cause and must not be
|
|
4519
|
+
reported as a successful configuration change.
|
|
4523
4520
|
`settleFunctionality` joins queued
|
|
4524
4521
|
publications before inspection or shutdown.
|
|
4525
4522
|
|
|
@@ -4532,7 +4529,8 @@ definitions add no hot-path teaching. Their exact state and Problem remain
|
|
|
4532
4529
|
available through `list`.
|
|
4533
4530
|
|
|
4534
4531
|
§functionality-model-projection **Each family has one workspace manager
|
|
4535
|
-
executor.**
|
|
4532
|
+
executor.** Its verbs — `discover` only where the family serves discovery
|
|
4533
|
+
({§functionality-discover-advertisement}) — use their actual coordinator schemas and the ordinary
|
|
4536
4534
|
tool-document machinery. `list`/`discover` are read effects; mutations are host
|
|
4537
4535
|
effects and use normal proposals. Summary, signatures, and deep docs derive
|
|
4538
4536
|
from the same registry ({§tools-resource-materialization},
|
|
@@ -4584,10 +4582,10 @@ Core's behavior behind them.
|
|
|
4584
4582
|
|---------------------------------------------------|----------|---------------|
|
|
4585
4583
|
| §methods-event-subscribe Events | `subscribeToEvents(handler) -> unsubscribe` | Subscribes to the raw event source in {§notifications}. A subscriber failure is logged and cannot re-enter engine control flow. |
|
|
4586
4584
|
| §proposal-list Proposals | `pendingProposals(workspaceId)` | Intersects durable proposed rows with the lifecycle owner's live resolution waiters, then returns their validated {§proposal-projection}; persistence alone cannot advertise an unresolvable client interrupt. |
|
|
4587
|
-
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates
|
|
4585
|
+
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution, owner)` | Validates the workspace-scoped owner before delivering one accept, reject, or cancel decision. Unknown, mismatched, and already-resolved identities fail without consuming the gate; the adapter authenticates its owner identity. |
|
|
4588
4586
|
| §client-interaction-list Client interactions | `pendingClientInteractions(workspaceId)` | Intersects durable interaction rows with their live operation waiters and returns the contracts-owned projection; a row alone is not a resumable interaction. |
|
|
4589
|
-
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates
|
|
4590
|
-
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?,
|
|
4587
|
+
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution, respondent, message?)` | Validates the recorded recipient before delivering one resolved payload or cancellation. Unknown, mismatched, and already-resolved identities fail before affecting an operation. |
|
|
4588
|
+
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?, openPaths?, selector?, childSelector? })` | Validates a model worker and persists the request with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. A trusted adapter may identify the prompt's causal actor with one canonical `source`; ordinary clients cannot author it through their protocol surface. Messages carry no approval authority. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
|
|
4591
4589
|
| §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. |
|
|
4592
4590
|
| §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. |
|
|
4593
4591
|
| 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}). |
|
|
@@ -4599,7 +4597,10 @@ Core's behavior behind them.
|
|
|
4599
4597
|
| §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, and emits global `workspace/created`. Creation and attachment are passive: neither starts derivation nor activates workspace Functionality. `projectRoot` is established here or the workspace remains headless. |
|
|
4600
4598
|
| §methods-workspace-attach Workspace lifecycle | `attachWorkspace({ workspaceId, workerId?, workerName? })` | Validates ownership and returns a client envelope for an existing world. It does not retain caller or transport binding state in core. |
|
|
4601
4599
|
| §methods-model-worker Workspace lifecycle | `ensureModelWorker(workspaceId)` | Returns the workspace's stable default model worker, creating it on first use. A durable default-conversation role identifies it independently of worker name and root creation order. Repeated and concurrent calls return the same root; fresh conversations and forks do not replace it. |
|
|
4602
|
-
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin
|
|
4600
|
+
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name?, parentWorkerId?, owner? })` | Creates a distinct model-origin worker with empty history. A root may name a registered owner; a child names its parent and inherits ownership. Supplying both parent and owner is invalid ({§worker-owner-creation}). |
|
|
4601
|
+
| Worker ownership | `registerWorkerOwner(workspaceId, { address, tools, interactive })` | Declares or replaces an owner's supported client-tool names and whether a person attends it, in that workspace; `_plurnk` is reserved. |
|
|
4602
|
+
| Worker ownership | `claimWorkerOwner({ workspaceId, workerId, owner })` | Claims only runtime-owned work under {§worker-ownership}, returning its effective owner. The owner must already be registered. |
|
|
4603
|
+
| Runtime actor | `ensureRuntimeWorker(workspaceId)` | Returns the workspace's `_plurnk` actor, creating it if absent; it always retains runtime ownership. |
|
|
4603
4604
|
| Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
|
|
4604
4605
|
| §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
|
|
4605
4606
|
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?, workerId?)` | Returns nonempty loop-seed prompts a client addressed to the workspace's model workers, newest-first; `workerId` narrows to one worker. Authorship is the seed message's address ({§message-arrival}): a worker-issued seed (WORK, FORK, SEND to a worker) has none and is never history, whichever worker it seeded; a client prompt at a forked conversation worker is. An omitted limit is `PLURNK_SERVICE_PROMPTS_PAGE`. |
|
|
@@ -4619,7 +4620,6 @@ already durable on the loop remains authoritative:
|
|
|
4619
4620
|
|-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
|
|
4620
4621
|
| Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
|
|
4621
4622
|
| `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
|
|
4622
|
-
| `policy` request | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
|
|
4623
4623
|
|
|
4624
4624
|
The conflict names both selections and directs the caller to cancel or conclude
|
|
4625
4625
|
the loop before changing configuration. A newly enqueued loop instead persists
|
|
@@ -4678,7 +4678,8 @@ independent demands, and harness-authored initialization obeys workspace policy.
|
|
|
4678
4678
|
`workspaces.settings.capabilities` is the one mutable access policy under the
|
|
4679
4679
|
service ceiling. Every actor, including an existing child, uses the current
|
|
4680
4680
|
workspace policy; neither creation nor delegation snapshots authority. Workers
|
|
4681
|
-
own their log and scratchpad, not tools or resource grants
|
|
4681
|
+
own their log and scratchpad, not tools or resource grants; their owner decides only
|
|
4682
|
+
which interaction runtimes they are offered ({§owner-interaction-ring}). Intrinsic source
|
|
4682
4683
|
mutability, workspace separation, and proposal approval remain distinct
|
|
4683
4684
|
contracts. Input is validated before persistence; malformed stored policy fails
|
|
4684
4685
|
at its reader with the workspace coordinate and cause.
|
|
@@ -4692,7 +4693,8 @@ or observation, existing workers reconcile generated references against it. It r
|
|
|
4692
4693
|
conversation worker and returns the complete fresh projection.
|
|
4693
4694
|
|
|
4694
4695
|
§question-tool **The native request-user-input tool.** Core registers one
|
|
4695
|
-
in-process `question` runtime at boot
|
|
4696
|
+
in-process `question` runtime at boot and offers it only to a worker whose owner
|
|
4697
|
+
would receive it ({§owner-interaction-ring}). Its body is the MCP2 2026-07-28
|
|
4696
4698
|
form-elicitation shape verbatim — `{ message, requestedSchema }`. An
|
|
4697
4699
|
optional literal target is a descriptive label only: it neither routes the
|
|
4698
4700
|
question nor changes the body or recipient. The
|
|
@@ -4721,6 +4723,20 @@ weights, and catalog text agree. Turn0 surveys that same catalog. Dispatch evalu
|
|
|
4721
4723
|
same descriptor and policy cascade at the operation boundary, never at
|
|
4722
4724
|
registration; there is no separate per-tool availability system.
|
|
4723
4725
|
|
|
4726
|
+
§owner-interaction-ring **An interaction tool is offered only where an answer can come
|
|
4727
|
+
from.** An asking worker adds one ring inside that cascade, derived live from its owner
|
|
4728
|
+
and never stored. It denies each interaction runtime whose tool the owner would not
|
|
4729
|
+
receive under {§client-interaction-routing}; an interaction runtime asks under its own
|
|
4730
|
+
tag, as `question` does.
|
|
4731
|
+
|
|
4732
|
+
| Surface | With the ring |
|
|
4733
|
+
| --- | --- |
|
|
4734
|
+
| Turn 0 survey and the worker's FIND of the shared reserved tree | The runtime's documents are absent, from counts and folder summaries too. |
|
|
4735
|
+
| Dispatch | 403 `capability-denied` naming scope `owner`, with the recovery pinned in {§pinned-wording-core}. |
|
|
4736
|
+
| Workspace capability projection and reserved-tree materialization | Unaffected: they take no worker. |
|
|
4737
|
+
|
|
4738
|
+
A FIND or READ by exact path is not filtered.
|
|
4739
|
+
|
|
4724
4740
|
§model-catalog **Model discovery is a bounded local projection, not provider
|
|
4725
4741
|
activity.** Core composes the release-pinned Models.dev snapshot with
|
|
4726
4742
|
provider-owned `{§model-catalog-readiness}` and {§provider-effort}.
|
|
@@ -4859,13 +4875,13 @@ adding a loop to it. LOOK text anchors resolve through the same
|
|
|
4859
4875
|
| §notifications-loop-interaction `loop/interaction` | contracts-owned `ClientInteractionProjection` | An operation is paused on client input. Live delivery and reconnect discovery share {§client-interactions}; workspace scope remains the event envelope. |
|
|
4860
4876
|
| §notifications-workspace-created `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
|
|
4861
4877
|
| `workspace/preparation` | `{ workspaceId, preparation: FunctionalityPreparationActivity[] }` | Workspace capability preparation changes; snapshot and clearing semantics follow {§functionality-preparation-visibility}. |
|
|
4862
|
-
| §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, workerId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `workerId` is the initiating actor used for conversation routing, never entry ownership or access control. `target` is the canonical resource URI. Optional numeric coordinates identify the causal log item, independently of that URI. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic
|
|
4878
|
+
| §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, workerId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `workerId` is the initiating actor used for conversation routing, never entry ownership or access control. `target` is the canonical resource URI. Optional numeric coordinates identify the causal log item, independently of that URI. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic extension notification capability does not require it. It carries metadata, not content; consumers read bytes by canonical workspace address. |
|
|
4863
4879
|
| §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the initiating actor; `target` is the canonical resource URI. Optional numeric fields identify the causal log item, never parsed from `target`. Exact result truth is preserved. `wakeAction` reports `wake-pending` before settlement, `no-op-active-loop` when work is already executing, `no-loop`, or `skipped-aborted`/`skipped-cancelled` for an aborted worker scope. A pending wake predicts neither execution nor recipient count; subsequent ordinary loop events report actual progress and completion. |
|
|
4864
4880
|
| §notifications-notice-event `notice/event` | `{ workerId, loopId, notice: Notice }` | A transient observation or progress notice occurs. `workerId` owns loop activity; only workspace derivation progress uses `null` with `loopId=0`. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
|
|
4865
4881
|
| §notifications-outside-event `outside/event` | `{ workerId, loopId, turnId, coordinate, text, tokens }` | An admitted emission carried text outside every operation ({§outside-text}): once per admitted emission, the exact stored text, its packet weight, and the turn's `<worker>-<loop>-<turn>` coordinate. It is transient presentation evidence; the turn's `outside` source remains the durable authority. |
|
|
4866
4882
|
| §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, requestSequence, phase, delta? }` | A main emission call exposes readable reasoning. Each physical request that emits reasoning owns a distinct positive `requestSequence` and balanced start/content/end stream; opening a retry closes the preceding stream before any retry delta. Only content carries a nonempty exact delta. It is transient presentation evidence, never a log row, Notice, packet field, or BARE/child channel. The settled provider response remains the durable authority. |
|
|
4867
4883
|
|
|
4868
|
-
§notifications-stream-event-failure-isolation The
|
|
4884
|
+
§notifications-stream-event-failure-isolation The extension-facing
|
|
4869
4885
|
`NotifyCaps.streamEvent()` remains a synchronous advisory call while core
|
|
4870
4886
|
resolves its entry identity asynchronously.
|
|
4871
4887
|
|
|
@@ -4903,7 +4919,7 @@ without an origin filter ({§actor-boundary-isolation}).
|
|
|
4903
4919
|
## §packet-assembly Packet assembly
|
|
4904
4920
|
|
|
4905
4921
|
`PacketBuilder.buildRequestPacket` owns the engine's default ordered section
|
|
4906
|
-
list. Trusted scheme
|
|
4922
|
+
list. Trusted scheme extensions may transform that first-class list before it is
|
|
4907
4923
|
rendered or measured; {§context-fit} remains an engine-owned post-build rail.
|
|
4908
4924
|
|
|
4909
4925
|
```mermaid
|
|
@@ -4916,23 +4932,27 @@ flowchart LR
|
|
|
4916
4932
|
|
|
4917
4933
|
### §packet-wire-envelope The wire envelope
|
|
4918
4934
|
|
|
4919
|
-
The packet reaches the provider as
|
|
4935
|
+
The packet reaches the provider as two messages. No emission is replayed under `assistant`.
|
|
4920
4936
|
|
|
4921
4937
|
| Message | Role | Content |
|
|
4922
4938
|
|:--|:--|:--|
|
|
4923
4939
|
| 1 | `system` | the system slot, as rendered |
|
|
4924
|
-
| 2
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4940
|
+
| 2 | `user` | the user sections in {§packet-cache-monotone} order; native parts ({§packet-attachment-parts}) precede the optional final {§previous-emission} section |
|
|
4941
|
+
|
|
4942
|
+
The digest's packet artifacts record the sections, and `.wire.json` reconstructs their text-message
|
|
4943
|
+
envelope ({§share-packet-names}); it is not a serialized HTTP capture.
|
|
4944
|
+
|
|
4945
|
+
### §previous-emission Complete, optional continuity
|
|
4946
|
+
|
|
4947
|
+
| Concern | Contract |
|
|
4948
|
+
|---|---|
|
|
4949
|
+
| Selection | Only the immediately preceding completed model inference turn in this loop. Its admitted content program must have no syntax errors and its emission row must remain active. Never search backward for an older eligible program. Runtime failures do not disqualify it. |
|
|
4950
|
+
| Absence | No preceding model turn, rejected or syntactically partial emission, empty or reasoning-only turn, or retired emission row means no section. Initialization and other loops supply none. |
|
|
4951
|
+
| Content | The frozen canonical admitted content program, whole: every body, NOTE, WAIT and reply retained. No placeholders, redaction, preview or nested-body interpretation. Reasoning operations remain in their own source and receipts. |
|
|
4952
|
+
| Placement | `## Previous Emission`, singular, is the final user section and final transmission content, after native parts when present. Nothing follows it. It is replaced each turn, never inserted into the reusable log prefix. |
|
|
4953
|
+
| Authority | Core attaches this section after trusted section transforms; the extension seam does not rewrite the frozen program. The active emission row owns its curation lifetime. |
|
|
4954
|
+
| Capacity | At the hard context wall, omit the section whole before suppressing any result body or native part ({§context-own-rows-fit}). Omission lasts through rebuilds of that request; the next request decides afresh. No source, receipt, or stored historical packet is changed. |
|
|
4955
|
+
| Accounting | Its text is charged once within the user slot; the emission row charges only its record. |
|
|
4936
4956
|
|
|
4937
4957
|
### §packet-cache-monotone Default order and cache locality
|
|
4938
4958
|
|
|
@@ -4952,18 +4972,19 @@ Conditional absence never reorders the surviving default sections.
|
|
|
4952
4972
|
| 10 | user | `budget` | `Context Curation`; omitted when capacity is unknown. |
|
|
4953
4973
|
| 11 | user | `messages` | `Open Messages`: immutable message addresses and causal sources ({§message-arrival}). |
|
|
4954
4974
|
| 12 | user | `recap` | Optional authored operational recap. |
|
|
4975
|
+
| 13 | user | `previous-emission` | Complete previous program, if eligible and within capacity ({§previous-emission}); always last. |
|
|
4955
4976
|
|
|
4956
4977
|
The order favors prefix-cache locality where semantics permit: the definition
|
|
4957
4978
|
and privileged policy lead operator notes, while the append-mostly
|
|
4958
|
-
log leads the volatile user-status clump.
|
|
4959
|
-
|
|
4960
|
-
|
|
4979
|
+
log leads the volatile user-status clump. The previous program follows that clump, so replacing it
|
|
4980
|
+
does not rewrite the log prefix. Retiring an emission row breaks the prefix at its row like any
|
|
4981
|
+
other curation. It does **not** claim that every system byte is
|
|
4961
4982
|
immutable or that the complete packet is globally monotone in volatility:
|
|
4962
4983
|
operator notes and policies can change. Trust is a separate
|
|
4963
4984
|
admission rule. The system slot contains trusted control-plane material;
|
|
4964
4985
|
attacker-reachable content stays in the user slot.
|
|
4965
4986
|
|
|
4966
|
-
### §packet-
|
|
4987
|
+
### §packet-extension-transform Trusted whole-list extension seam
|
|
4967
4988
|
|
|
4968
4989
|
`SchemeRegistry.transformSections` pipes the complete default list through
|
|
4969
4990
|
every registered scheme implementing `transformSections(sections) -> sections`,
|
|
@@ -4973,10 +4994,10 @@ Each initial or returned list passes the schemes-owned validator, including
|
|
|
4973
4994
|
unique-name enforcement, before the next transformer or renderer. Each
|
|
4974
4995
|
transformer may inspect the section content and add, remove, or reorder
|
|
4975
4996
|
sections. It receives no separate engine, database, actor, or request context.
|
|
4976
|
-
|
|
4977
|
-
|
|
4997
|
+
Core then attaches the optional frozen previous program ({§previous-emission}); transforms own
|
|
4998
|
+
section drafts, not the worker's source evidence.
|
|
4978
4999
|
|
|
4979
|
-
This is strictly a trusted in-process seam, admitted through the common
|
|
5000
|
+
This is strictly a trusted in-process seam, admitted through the common extension
|
|
4980
5001
|
trust gate; an external client action cannot invoke it. Whole-list transformation is
|
|
4981
5002
|
the fork-avoidance valve for alternate packet shapes, while
|
|
4982
5003
|
overflow recovery and packet projection remain closed engine concerns.
|
|
@@ -4988,23 +5009,39 @@ time of measurement.
|
|
|
4988
5009
|
|
|
4989
5010
|
| Fact | Owner and unit | Time | Contract |
|
|
4990
5011
|
|:-----|:---------------|:-----|:---------|
|
|
4991
|
-
| Core curation weight | `contentWeight = ceil(chars/2)` over channel content, canonical log bodies, rendered packet slots
|
|
5012
|
+
| Core curation weight | `contentWeight = ceil(chars/2)` over channel content, canonical log bodies, rendered packet slots (including the optional previous emission) | Write/build | Stable, model-independent measure; never a tokenizer claim. The model meets it as `tokens`. |
|
|
4992
5013
|
| §tokenomics-context-envelope-admission Provider input capacity | Provider model limits, the configured output reservation and the output floor, in provider tokens | Before every logical request | The reservation `min(maxInputTokens, contextWindow − outputBudget)` sizes the room; the wall `min(maxInputTokens, contextWindow − outputFloor)` decides admission ({§provider-capacity-admission}). The provider alone measures the complete request and admits it — with the grant flexed when the prompt is over the reservation — defers it, or rejects it at the wall. |
|
|
4993
5014
|
| Provider generation envelope | Provider response grant and optional reasoning subset, in provider tokens | Before every logical request | The reservation includes hidden reasoning; its strict reasoning subset is never additive. The response grant follows {§provider-flexed-allowance}. |
|
|
4994
5015
|
| Provider usage and cost | Provider-reported input/output/cache/reasoning tokens and monetary evidence | After every physical request | Durable physical-request forensics under {§provider-usage}; never curation state or a preflight estimate. |
|
|
4995
5016
|
|
|
4996
|
-
|
|
5017
|
+
§context-admission **One request through the room.** Core fits the packet to the wall on its estimate, marks it over budget, then has the provider measure the exact request before it is sent. Shedding is the same at both measures, and only a packet that cannot fit even as receipts ends its loop.
|
|
5018
|
+
|
|
5019
|
+
```mermaid
|
|
5020
|
+
flowchart TD
|
|
5021
|
+
build["Build the packet at the budget"] --> wall{"Estimate over the wall?"}
|
|
5022
|
+
wall -- yes --> shed["Shed: the previous program whole, then the newest rows bodiless"]
|
|
5023
|
+
shed --> wall
|
|
5024
|
+
wall -- no --> over{"Over budget, no row yet?"}
|
|
5025
|
+
over -- yes --> row["One over-budget row at the head of the turn"]
|
|
5026
|
+
row --> wall
|
|
5027
|
+
over -- no --> assess{"The provider assesses the exact request"}
|
|
5028
|
+
assess -- "admit or defer" --> send["Send"]
|
|
5029
|
+
assess -- "exact refusal" --> shed
|
|
5030
|
+
shed -. "nothing left to take" .-> overflow["window-overflow 413, no inference request"]
|
|
5031
|
+
```
|
|
5032
|
+
|
|
5033
|
+
- §context-budget **One room.** The budget is the provider's input capacity through the current calibration, `floor(inputCapacity / factor)` ({§tokenomics-calibrated-readout}), and it bounds the whole packet — teaching, catalog, log and gauge together. Nothing on the service panel sizes a part of it: no projection share, no preview page, no pressure threshold. The budget follows the calibration both ways; a room that shrinks under the model is announced by the over-budget row ({§context-over-budget-row}), never hidden by keeping a larger figure.
|
|
4997
5034
|
- §context-gauge **One gauge.** Every packet carries one `## Context` section holding one JSON object: `tokens`, the packet's weight as rendered; `budget`, the room; and `largest`, the `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` heaviest retained log rows as `{path, tokens}` ranked by weight then path. Each log row heading carries its own `tokens`. The gauge is state: it never presents `budget − tokens` as response allowance, it carries no mandate, and it reads the same at one percent as at ninety-nine; over budget, `largest` is as complete as under it, since those rows are the handles the row asks the model to use ({§context-over-budget-row}).
|
|
4998
|
-
- §context-fit **One rule: whole if it fits, otherwise as much as fits, then its size and address.** A result the model asked for — a READ without a scope, a FIND, an exec result delivered on close — arrives complete when its weight fits within `budget − tokens` as of that turn, less the room the turn still owes — one receipt's measured weight for each result still to land in it and the
|
|
5035
|
+
- §context-fit **One rule: whole if it fits, otherwise as much as fits, then its size and address.** A result the model asked for — a READ without a scope, a FIND, an exec result delivered on close — arrives complete when its weight fits within `budget − tokens` as of that turn, less the room the turn still owes — one receipt's measured weight for each result still to land in it and the emission record that answers it, so that the receipts of a batch and the answer always fit. Otherwise the complete result stays where it was read from and the row is a `413` receipt naming the result's size, its weight, the remaining budget, and the two verbs: `READ` a range, or `KILL` first. A READ of lines carries, above its receipt, the longest prefix of those lines whose row fits that room — the lines with their anchors, the returned range closed on the last line delivered, and the receipt naming the lines delivered; a result whose first line does not fit, a FIND, a stream page and a byte view are bodiless receipts. An arrival the model did not ask for — an inbound `SEND`, a child's conclusion — takes the same bodiless receipt as a fact, not an error: its size and its address. Explicit scopes (`<a,b>`, a pattern, `<1,-1>`) are exact and take the same test. Result cuts are named where they happen: the first page of what came back unasked in size ({§markerless-first-page}) and the cut at the room in the receipt. The optional previous program is whole or absent ({§previous-emission}), never a cut.
|
|
4999
5036
|
- §context-verbs **The verbs are the curation.** `READ` with a range takes a piece of what did not fit ({§read-selection-projection}); `NOTE` keeps what the model learned; `KILL` retires rows, ranges and bodies ({§log-kill-scope}) and may carry what it keeps of them as its own NOTE ({§log-kill-distillation}). The daemon adds no other mechanism.
|
|
5000
5037
|
- §context-over-budget-row **Over budget is a row and a request, not an ending.** A packet whose weight exceeds `budget` is still submitted when it fits the window ({§context-wall}), and it carries one `_plurnk` error row at the head of its turn, `engine/context/packet-exceeds-budget` 413: "Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn." The row is the mandate and carries no figure: the gauge is the one home for `tokens` and `budget` ({§context-gauge}), and it shows the packet over with the row in it. The row recurs on every packet that is over, and nothing is hidden to make the packet smaller; the response grant is the window's remainder above the provider's output floor ({§provider-output-floor}). The limit protects a loop; it never ends one.
|
|
5001
|
-
- §context-wall **Only the window ends a loop.** The wall is the provider's physical input limit: `maxInputTokens`, and the context window less the output floor ({§provider-output-floor})
|
|
5002
|
-
- §context-
|
|
5003
|
-
- §context-
|
|
5038
|
+
- §context-wall **Only the window ends a loop.** The wall is the provider's physical input limit: `maxInputTokens`, and the context window less the output floor ({§provider-output-floor}). A request over the wall sheds ({§context-own-rows-fit}) and is measured again ({§context-wall-measure}); a packet that cannot fit even as receipts ends its loop with the exact `engine/context/window-overflow` 413 Problem, and no inference request is made. An unknown window has no wall ({§tokenomics-window-unpollable-deliberate}).
|
|
5039
|
+
- §context-wall-measure **The wall measures the request that will be sent.** The estimate is the packet's weight through its calibration factor ({§tokenomics-calibrated-readout}) and is never assumed to overestimate. A packet that fits by the estimate is assessed by the provider as the exact wire request ({§provider-capacity-admission}): an admission sends it; an exact refusal is the wall's verdict, and the request sheds by the refusal's excess and is assessed again. A provider that can only estimate defers, and the upstream provider is then the capacity oracle: its refusal ends the loop with the provider's own 413.
|
|
5040
|
+
- §context-own-rows-fit **The model's own rows take the same receipt.** When a request is over the wall by either measure ({§context-wall-measure}), its newest rows that still carry a body or a native part — NOTEs, receipts, delivered results, pictures — render bodiless in the fit rule's receipt shape, newest first and only as many as it takes for the request to fit: the heading, the facts, and `size`, the lines and tokens of what the row stood for. The optional previous program has already been omitted whole ({§previous-emission}); an emission record has no body to take. A row whose receipt would weigh no less than its body stays whole. Every body stays stored and readable at its address, the verbs restore the room ({§context-verbs}), and each packet decides afresh from its own newest rows. The daemon chooses nothing to summarize and hides nothing silently.
|
|
5004
5041
|
- §tokenomics-weight-stored-at-write **Curation weight, stored at write.** `entry_channels.weight` weighs the complete channel content. `log_entries.weight` weighs the complete canonical `LogBody` content before coordinate and packet presentation; persistence `tx`/`rx` envelopes contribute nothing merely by existing, and proposal settlement recomputes the value when the canonical result changes. Bodyless rows therefore weigh zero. The stored number is a stable content-depth measurement, not a provider-token prediction. `entry_channels.lines` is the channel's line count beside it, a stored generated column SQLite keeps on every write as the persisted mirror of {§logical-line-count} (a trailing newline terminates the last line; empty content has none), so a catalog lists extent without reading bodies.
|
|
5005
|
-
- §tokenomics-render-weight-budget **Packet curation budget.** `tokens` measures the *complete assembled packet* after section transforms and readout substitution, its rendered slots
|
|
5006
|
-
- §tokenomics-calibrated-readout **Convert capacity, never content costs.** Before packet assembly, Core obtains the answering model's last five settled emission responses pairing a measured packet weight with a provider-reported prompt count. The conversion factor is `sum(reported) / sum(weight)`; fewer than three samples use 1. `floor(inputCapacity / factor)` converts provider capacity into curation units
|
|
5007
|
-
- §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits, the configured output reservation, and each call's response grant. Its resolved `inputCapacity` supplies the physical denominator exposed to clients and the boundary conversion into curation units ({§tokenomics-calibrated-readout}). Core shapes context in curation units; provider request-shaped evidence alone admits or rejects physical I/O.
|
|
5042
|
+
- §tokenomics-render-weight-budget **Packet curation budget.** `tokens` measures the *complete assembled packet* after section transforms and readout substitution, its rendered slots (including {§previous-emission}) and native attachments; it is not a sum of stored row weights ({§tokenomics-weight-stored-at-write}). Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns final values into those widths; final substitution is length-invariant and the displayed total equals the stored request weight. Receipt, FIND-item, pressure-inventory, total, and ceiling figures all use the same curation ruler. A `SUM` of stored content weights measures a different artifact and cannot substitute for packet render weight.
|
|
5043
|
+
- §tokenomics-calibrated-readout **Convert capacity, never content costs.** Before packet assembly, Core obtains the answering model's last five settled emission responses pairing a measured packet weight with a provider-reported prompt count. The conversion factor is `sum(reported) / sum(weight)`; fewer than three samples use 1. `floor(inputCapacity / factor)` converts provider capacity into curation units, the budget ({§context-budget}); the same factor converts the packet's weight into the wall's estimate ({§context-wall-measure}). Zero means no whole curation unit fits; unknown input capacity remains `null`. The built packet captures this allowance and its factor once for its readout, pressure inventory, wall estimate, and persisted client gauge. Later responses cannot change that packet's allowance. Samples are model-keyed, not worker-local; a model with no samples starts at 1. Calibration never changes stored weights, rendered receipt costs, or the immutable request history ({§tokenomics-agnostic-ruler}).
|
|
5044
|
+
- §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits, the configured output reservation, and each call's response grant. Its resolved `inputCapacity` supplies the physical denominator exposed to clients and the boundary conversion into curation units ({§tokenomics-calibrated-readout}). Core shapes context in curation units; provider request-shaped evidence alone admits or rejects physical I/O. Local and custom deployments tune context window, total output budget and optional reasoning subset at their owning layers.
|
|
5008
5045
|
- §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays unknown.** When the provider cannot derive `inputCapacity`, there is no budget: the gauge carries `tokens` alone, every result arrives whole, and the provider remains the capacity oracle ({§provider-capacity-admission}). Core never invents a stand-in.
|
|
5009
5046
|
|
|
5010
5047
|
§tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest packet-bearing model-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. The curation pair is the packet's measured weight and captured allowance, exactly as displayed to the model, not a recalculation using newer usage evidence. Packetless chronology cannot erase an assembled-request gauge. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
|
|
@@ -5031,7 +5068,7 @@ execute, enter model history, or become a later request's successful output.
|
|
|
5031
5068
|
| 200 | Messages answered, results observed, held work settled |
|
|
5032
5069
|
| 499 | Worker-scope or client cancellation |
|
|
5033
5070
|
| 429 | Turn allowance exhausted |
|
|
5034
|
-
| 413 | A result that does not fit ({§context-fit}), a packet over the budget ({§context-over-budget-row}: a row; the request still goes), a packet
|
|
5071
|
+
| 413 | A result that does not fit ({§context-fit}), a packet over the budget ({§context-over-budget-row}: a row; the request still goes), a packet that cannot fit the window even as receipts ({§context-wall}), or an upstream provider's own refusal ({§context-wall-measure}) |
|
|
5035
5072
|
| 500 / 508 | Strike threshold or invalid-emission exhaustion / crossing strike caused by a cycle |
|
|
5036
5073
|
| 504 | Loop timeout or exec-timeout restamp |
|
|
5037
5074
|
|
|
@@ -5129,8 +5166,8 @@ header. A null header renders only its content. Empty content is omitted, traili
|
|
|
5129
5166
|
newlines are removed from each section, and rendered sections are separated by one
|
|
5130
5167
|
blank line. Any node whose content is empty is absent from the wire, except the
|
|
5131
5168
|
child-orientation sections, which state emptiness as `[]` ({§packet-empty-sections}).
|
|
5132
|
-
Core owns the order at {§packet-cache-monotone}; a trusted
|
|
5133
|
-
section list before rendering ({§packet-
|
|
5169
|
+
Core owns the order at {§packet-cache-monotone}; a trusted extension may transform the
|
|
5170
|
+
section list before rendering ({§packet-extension-transform}). The projection preserves
|
|
5134
5171
|
the evidence section owners supply: paths, URI fragments, log coordinates, scopes and
|
|
5135
5172
|
coordinate-prefixed body lines remain usable without translation; curation and log-row
|
|
5136
5173
|
measurements stay attached to what they measure ({§tokenomics-agnostic-ruler});
|
|
@@ -5149,9 +5186,10 @@ their boundaries ({§log-wire-format}).
|
|
|
5149
5186
|
| `errors` | user | JSON status/log-path pointers | {§operation-results} |
|
|
5150
5187
|
| `notices` | user | Terse observation bullets | {§notice-drain-on-read} |
|
|
5151
5188
|
| `git` | user | Working-tree state in a NOTE blockquote | {§packet-cache-monotone} |
|
|
5152
|
-
| `budget` | user | JSON curation usage and ceiling
|
|
5189
|
+
| `budget` | user | JSON curation usage and ceiling | {§context-gauge} |
|
|
5153
5190
|
| `messages` | user | JSON pointers to the loop's unanswered immutable messages, path and source | {§message-arrival} |
|
|
5154
5191
|
| `recap` | user | Optional authored operational recap | {§recap} |
|
|
5192
|
+
| `previous-emission` | user | Complete preceding content program, whole or absent; always last | {§previous-emission} |
|
|
5155
5193
|
|
|
5156
5194
|
§packet-stored-shape **A model packet preserves the rendered request and, only
|
|
5157
5195
|
when an emission is admitted, its response.** Core assembles and measures the
|
|
@@ -5164,7 +5202,7 @@ leaves the request-only record, while rejected exchanges remain in their
|
|
|
5164
5202
|
| Turn state | `turns.packet` (the bag) + `turn_sections` rows |
|
|
5165
5203
|
| ----------------------------- | ----------------------------------------------- |
|
|
5166
5204
|
| No admitted model request (including initialization and local capacity rejection) | SQL `NULL`, no rows |
|
|
5167
|
-
| Request assembled | `{ weight, attributions }` + the sections as items; the
|
|
5205
|
+
| Request assembled | `{ weight, attributions }` + the sections as items; the complete previous-emission section, or its empty content, is stored with the request ({§previous-emission}) |
|
|
5168
5206
|
| Response admitted | `{ weight, attributions, assistant, assistantRaw }` + the sections as items |
|
|
5169
5207
|
|
|
5170
5208
|
§packet-items **Sections are rows over content-addressed items; the bag never holds them.**
|
|
@@ -5179,7 +5217,7 @@ whose INSTEAD OF trigger refuses a turn that is not an open model inference turn
|
|
|
5179
5217
|
items, the composition, the bag, and the provider metadata together. Readers of a whole packet
|
|
5180
5218
|
select from `turn_packets`, which assembles `sections` back into the bag byte for byte (the digest,
|
|
5181
5219
|
and every test that inspects a stored packet); statements that need one field read the bag
|
|
5182
|
-
directly with `json_extract`. A packet transformed by
|
|
5220
|
+
directly with `json_extract`. A packet transformed by an extension, or any non-log section, is one
|
|
5183
5221
|
item. Items no composition references are transient data: `retention_collect_packet_items`
|
|
5184
5222
|
collects them under the retention policy ({§retention-policy}), which is how a deleted worker's or
|
|
5185
5223
|
workspace's packets release their space while shared items survive. A fork copies the composition
|
|
@@ -5203,62 +5241,12 @@ operation turns and therefore store `NULL`. Digest projects exact operation
|
|
|
5203
5241
|
source independently from this optional model-exchange record; a request-only
|
|
5204
5242
|
turn receives a note instead of a fabricated response.
|
|
5205
5243
|
|
|
5206
|
-
|
|
5207
|
-
After selectors are applied, digest retains every turn with exact content or reasoning source, a
|
|
5208
|
-
valid stored provider request, or malformed stored packet evidence; orders those
|
|
5209
|
-
turns by durable chronology; and names each by its log coordinate ({§share-packet-names}). The
|
|
5210
|
-
producer does not affect projection.
|
|
5211
|
-
|
|
5212
|
-
§share-packet-names **Packet artifacts carry the coordinate the log uses.** A turn's files are named
|
|
5213
|
-
`<worker>-<loop>-<turn>`, the worker's name and the loop and turn sequences that `log:///<loop>/<turn>/…`
|
|
5214
|
-
addresses: the model's first turn in its first loop is `<worker>-1-2`, because the initialization
|
|
5215
|
-
survey is turn 1 and writes no packet. A digest spanning several workspaces nests each workspace's
|
|
5216
|
-
files in a folder named for it; a name that cannot name a file (a workspace named by its path,
|
|
5217
|
-
`~/ptl/x`) is slugged for the folder, `ptl-x`, while the digest text keeps the name verbatim, and
|
|
5218
|
-
two names that slug alike are told apart by the row's id. `digest.json` records each turn's stem as `artifact`, so no
|
|
5219
|
-
consumer reconstructs a name. A name that cannot be a file name, or two turns sharing one, fails.
|
|
5220
|
-
|
|
5221
|
-
| Artifact | Present when | Authority |
|
|
5222
|
-
|----------|--------------|-----------|
|
|
5223
|
-
| `<stem>.assistant.md` | The turn has an `ops` source | Exact `turn_sources.content`, independent of log rows |
|
|
5224
|
-
| `<stem>.reasoning.md` | The turn has a `reasoning` source | Exact `turn_sources.content`, without relabeling it as content |
|
|
5225
|
-
| `<stem>.system.md`, `<stem>.user.md` | The turn stored a provider request | Stored text sections projected through `PacketWire`; native parts are not Markdown |
|
|
5226
|
-
| `<stem>.wire.json` | The turn stored a provider request | The request's text messages in order, its worker's emission rows placed ({§packet-wire-envelope}); `<stem>.wire.invalid.json` names a stored log that cannot be projected |
|
|
5227
|
-
| `digest.json` turn `attachments` | Every turn | Stored native attachment descriptors; `[]` means a request without attachments, `null` means no valid stored request. Selection is not proof of provider acceptance. |
|
|
5228
|
-
| `<stem>.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
|
|
5229
|
-
| `<stem>.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
|
|
5230
|
-
| `<stem>.packet.raw.txt` | The stored packet fails typed validation | Exact stored packet text |
|
|
5231
|
-
| `<stem>.packet.invalid.json` | The stored packet fails typed validation | Turn identity and complete validation error chain |
|
|
5232
|
-
|
|
5233
|
-
A source-backed turn without provider participation produces only its source-channel
|
|
5234
|
-
artifacts; a request-only turn produces no fabricated assistant. A
|
|
5235
|
-
source-less programmatic turn with no provider request has no forensic payload
|
|
5236
|
-
to project and writes no files.
|
|
5237
|
-
|
|
5238
|
-
The external tokenless draft and transformation boundary is owned by
|
|
5244
|
+
he external tokenless draft and transformation boundary is owned by
|
|
5239
5245
|
{§scheme-packet-transform}. Core alone extends each validated draft with its
|
|
5240
5246
|
measured `weight` field for storage. #74 tracks coverage that mistakes the sum
|
|
5241
5247
|
of section weights for the rendered request weight.
|
|
5242
5248
|
|
|
5243
|
-
§definition-table-projection The authored `plurnk.md` remains human-aligned. Its `definition` section deterministically removes Markdown table-cell padding and shortens separator cells to three dashes before
|
|
5244
|
-
|
|
5245
|
-
§lexicon **Vocabulary follows the standard of its audience.**
|
|
5246
|
-
|
|
5247
|
-
| Layer | Rule |
|
|
5248
|
-
|--------------------------|------|
|
|
5249
|
-
| Operator, wire, storage | Use the applicable industry term. Provider quantities follow the OpenAI vocabulary where it is standard: `contextWindow`, `reasoning`, `completion`, `finish_reason`, and usage nouns. |
|
|
5250
|
-
| Core lifecycle | Use the exact Workspace → Worker → Loop → Turn → Op hierarchy in {§lifecycle-terms}. An AG-UI Run or thread is always protocol-qualified. |
|
|
5251
|
-
| Model-facing packet | Use the model's training distribution: operations mirror HTTP and shell, while log records use ordinary Markdown headings, strict JSON metadata, and text coordinates. Renaming this vocabulary to internal API terminology would discard useful resonance for a standard the model never sees. |
|
|
5252
|
-
|
|
5253
|
-
| PLURNK-native term | Why it remains |
|
|
5254
|
-
|--------------------------------|----------------|
|
|
5255
|
-
| `worker` / `loop` / `turn` | The process hierarchy in {§lifecycle-terms}; unqualified `run` names no internal entity. |
|
|
5256
|
-
| `packet` | The assembled address space, a kernel concept rather than merely a provider request. |
|
|
5257
|
-
| `costUsd` | No standard cost field exists; the explicit currency avoids implied units, and the value remains an exact decimal string. |
|
|
5258
|
-
| `curationWeight` / `curationBudget` | Explicitly distinguish Core's model-independent context-shaping facts from physical provider tokens. |
|
|
5259
|
-
| the `chars/2` curation ruler | Model-agnostic by design ({§tokenomics-agnostic-ruler}); it is never presented as a tokenizer. |
|
|
5260
|
-
|
|
5261
|
-
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 -->
|
|
5249
|
+
§definition-table-projection The authored `plurnk.md` remains human-aligned. Its `definition` section deterministically removes Markdown table-cell padding and shortens separator cells to three dashes before extension transforms, measurement, storage, and wire rendering; alignment colons survive, while fenced blocks and all non-table whitespace remain exact.
|
|
5262
5250
|
|
|
5263
5251
|
§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:
|
|
5264
5252
|
|
|
@@ -5269,11 +5257,11 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
|
|
|
5269
5257
|
| inbound `SEND` from outside the workspace | the operator's: complete when it fit, otherwise its size and address ({§context-fit}, {§message-projection}); a peer worker's: its first page ({§markerless-first-page}) |
|
|
5270
5258
|
| structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
|
|
5271
5259
|
| every other nonempty body | the model's own: complete; what it did not author: its first page ({§markerless-first-page}); then {§context-fit} |
|
|
5272
|
-
| the `reasoning` row | the
|
|
5260
|
+
| the `reasoning` row | the optional reasoning preview under {§reasoning-row} |
|
|
5273
5261
|
| a row the wall took | its size and address, no body and no native part ({§context-own-rows-fit}) |
|
|
5274
5262
|
| bodyless row | heading and any facts; no coordinate lines; `tokens` includes any selected native part |
|
|
5275
5263
|
|
|
5276
|
-
§markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, and the command it handed an executor. Its own reasoning, when it lands as a row, stands whole only when it fits the row's page and otherwise takes its last page ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and
|
|
5264
|
+
§markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, and the command it handed an executor. Its own reasoning, when it lands as a row, stands whole only when it fits the row's page and otherwise takes its last page ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and emission rows remain folded ({§emission-row}); those are the only exceptions, so the model can reason about every page the same way. A page lands under {§context-fit} like any result: whole when it fits the remaining budget, otherwise the prefix and receipt. Retrievals take their page at the source, before storage, and the packet applies no second cut to a stored result; a stored body takes its page in the packet, and the rest stays readable at the row's address. No operation carries a page size of its own.
|
|
5277
5265
|
|
|
5278
5266
|
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). When a visible projection differs from its canonical body, metadata carries `preview` under {§packet-extent-metadata}; complete and fully suppressed bodies omit it. ```` ```READ (log:///<coordinate>/<OP>) ```` selects untrimmed lines in original coordinates under {§log-readable-projection}; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. ```` ```FIND (log:///...) ```` and search match that same readable view. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
|
|
5279
5267
|
|
|
@@ -5324,7 +5312,7 @@ message — an AG-UI message UUID, an A2A address — stays the durable `path` t
|
|
|
5324
5312
|
delivery and reply accounting use, and remains addressable in its own scheme; the short form is an
|
|
5325
5313
|
additional alias. Answering either reaches the same message.
|
|
5326
5314
|
|
|
5327
|
-
§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
|
|
5315
|
+
§message-causal-source **Message authorship and delivery are distinct facts.** The harness publishes every arrival row; the row's `source` carries the canonical address of the causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter supplies its own canonical actor address through {§methods-loop-run}: the AG-UI module names the client's message under `agui://` ({§agui-run-source}), the inbound A2A adapter under `a2a://`. An absent source is the operator. Attribution persists with the message through the inbox, parking, orphan recovery, restart, and later log projection; model syntax cannot author it. The wire renders the row's `source` in place of its `origin`, which is constant for every arrival, except where the source is the transport that minted this very message, which says nothing the address does not ({§message-short-identity}). The operator's message is then the one arrival with no sender to show, so it renders `"origin": "user"`; a bare arrival would read as the model's own SEND and hide the request it answers. The Open Messages pointer carries the same attribution ({§message-arrival}).
|
|
5328
5316
|
|
|
5329
5317
|
§message-projection **Message storage is unbounded by model context; its arrival in the packet is not.** Core persists every accepted message completely before packet assembly. An arrival renders complete when it fits the remaining budget ({§context-fit}) and otherwise as its size and address, where a READ of the message's log body, scoped or whole, retrieves it. A peer worker's message is received text and arrives as its first page ({§markerless-first-page}). No share of the capacity is set aside for arrivals, and no knob sizes one.
|
|
5330
5318
|
|
|
@@ -5350,7 +5338,7 @@ their row shape, and their ordering are ordinary FIND projections owned by
|
|
|
5350
5338
|
The model's runtime alert surface has two distinct kinds of information:
|
|
5351
5339
|
|
|
5352
5340
|
- **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They can be scoped-KILLed, retired, and budgeted like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery `emissionAttempt` under {§invalid-emission-attempts}.
|
|
5353
|
-
- **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `search_progress`, and `
|
|
5341
|
+
- **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `search_progress`, and `output_unaccounted` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
|
|
5354
5342
|
|
|
5355
5343
|
The `log` is durable product truth. The `errors` section points at its failures
|
|
5356
5344
|
while the separate `notices` section displays transient observations. The two
|
|
@@ -5376,12 +5364,12 @@ retain distinct contracts and lifetimes.
|
|
|
5376
5364
|
separate item is minted for operation failures. Actionless engine rails mint
|
|
5377
5365
|
`op='error'` items because no authored operation row exists. Invalid provider
|
|
5378
5366
|
emissions are outside this channel because they are not turns. A bare
|
|
5379
|
-
failure status
|
|
5367
|
+
failure status or mismatched result/problem
|
|
5380
5368
|
statuses violate the producer contract and fail hard. Genuine
|
|
5381
5369
|
engine-internal faults crash and never mint model-facing rows.
|
|
5382
5370
|
- **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.
|
|
5383
5371
|
- **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`.
|
|
5384
|
-
- **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
|
|
5372
|
+
- **Exact Problems cross durable and external boundaries.** Scheme capabilities, proposal application, subscription conclusion, loop settlement, AG-UI, clients, digests, and benchmark records preserve the originating Problem object. The model packet alone derives `{§problem-projection}` without mutating that object. An adapter may add a missing durable `instance`, never replace an existing one; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, or a scheduler projection. A failed boundary without a valid Problem is a contract violation and fails hard.
|
|
5385
5373
|
- **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.
|
|
5386
5374
|
- §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. Parking preserves pending notices for that loop's next packet; another loop cannot consume them. Terminal cleanup, including cancellation while parked, discards undelivered notices. This buffer is process-local, not restart-persistent. Stateful derivation progress and provider availability coalesce in the buffer, so clients observe every checkpoint live while a later model packet receives only the current state under ordinary level filtering.
|
|
5387
5375
|
- §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.
|
|
@@ -5396,12 +5384,12 @@ retain distinct contracts and lifetimes.
|
|
|
5396
5384
|
|
|
5397
5385
|
| notice `kind` | Source | Position |
|
|
5398
5386
|
|---|---|---|
|
|
5399
|
-
| `
|
|
5387
|
+
| `output_unaccounted` | a provider whose billed output tokens exceed those its content and reasoning hold | content-offset at the end of the content |
|
|
5400
5388
|
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
|
|
5401
5389
|
| `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 |
|
|
5402
5390
|
| `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 |
|
|
5403
5391
|
|
|
5404
|
-
§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 `
|
|
5392
|
+
§notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `output_unaccounted` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
|
|
5405
5393
|
|
|
5406
5394
|
§operation-result-no-error-scheme Private strike and cycle accounting stays engine-internal ({§rail-accounting-private}). Every failure within an accepted turn - a bounded parse error, failed action, or engine rail - is a LOG ITEM (`log:///<coord>`, `status_rx ≥ 400`) with Problem Details, independently curatable and exactly READable while active. The `errors` section surfaces a derived pointer to each. Rejected emissions stay in the forensic model-call and admission relations. There is **no bespoke `error://` scheme** and no ephemeral per-category failure buffer.
|
|
5407
5395
|
|
|
@@ -5424,83 +5412,14 @@ the same deadline through {§application-loop-observation}, not a restarted cloc
|
|
|
5424
5412
|
|
|
5425
5413
|
§share **A share is the database's record, ready to send.** `plurnk-service share [<file.db>] [<folder>]`, and `npm run share` from a checkout, take a consistent copy of the database (`VACUUM INTO`; a live database is never read in place), and write its digest into `<folder>`, an ordinary folder the user archives or attaches however they like. Without a database the service's own is shared. Nothing is overwritten: a folder that exists and is not empty is refused, and a caller reusing a place removes it first. The share is the user's bug report and our dogfood, benchmark and forensics artifact alike.
|
|
5426
5414
|
|
|
5427
|
-
§share-snapshot **A database is copied by SQLite, never by the filesystem.** `Share.snapshot(dbPath, copy)`, exported as `@plurnk/plurnk-service/share` with `Share.write`, is the one consistent copy: a byte copy of a WAL-mode database drops every committed page still in its `-wal` file. A harness that keeps the database beside its digest takes it through `snapshot`; an existing `copy` is refused.
|
|
5428
|
-
|
|
5429
5415
|
§share-scope **A share is unredacted.** `--workspace=<id>` limits a share to one workspace; without it the whole database is shared. Nothing is filtered, redacted or scanned: a share holds what the models saw and wrote in scope, including prompts, file contents read, command output and reasoning, and the command says so. `--requiem` adds the forensic interview ({§digest-requiem}), which calls a model; `plurnk-service requiem <file.db> <folder>` adds it later to a digest already written.
|
|
5430
5416
|
|
|
5431
5417
|
§share-folder **Shares land in one place.** With no folder named, a share is a stamped child, `share-<UTC stamp>`, of `PLURNK_SERVICE_SHARE_FOLDER` (a leading `~/` expands, as for every explicit Plurnk path) or of `$XDG_STATE_HOME/plurnk/shares`.
|
|
5432
5418
|
|
|
5433
|
-
§
|
|
5434
|
-
|
|
5435
|
-
| Surface | Contract |
|
|
5436
|
-
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
5437
|
-
| 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. |
|
|
5438
|
-
| `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
|
|
5439
|
-
| `digestDir` | Selects a nonempty output path. `run` refuses a folder that exists and is not empty, and `requiem` refuses an existing `requiem.json` or `requiem.md`, before database or provider I/O; neither deletes ({§share}). Concurrent callers use distinct folders. |
|
|
5440
|
-
| Reader lifetime | `run` reads heavy evidence on demand while rendering, then closes its reader on success or failure. `requiem` closes its reader before awaiting witness inference. |
|
|
5441
|
-
| §candidate-pinned-runtime Candidate runtime | At launch, after its optional build, the candidate copies every workspace's package projection (`files`) into `<state>/runtime`, links third-party dependencies, and resolves `@plurnk/*` to those copies. Its daemon and its digest export both run from that copy, never the shared checkout, so neither source edits nor a concurrent candidate's or developer's rebuild after launch changes the code a run finishes on. The copy is removed once the digest is written. |
|
|
5442
|
-
| Export completion | Packet and response bodies are read and serialized one record at a time, without discarding evidence. `digest.json` is promoted from a partial file only after every artifact is written; its absence identifies an incomplete export. |
|
|
5443
|
-
| `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. |
|
|
5444
|
-
| `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, when both selectors are present they intersect. |
|
|
5445
|
-
|
|
5446
|
-
§digest-cost-kind **Cost basis named.** A rendered Cost line carries the basis of its dollar figure: `(charged)` only when every settled request's cost is provider-charged; `(estimated — catalog rates)` when any settled request's cost is an estimate, because a mixed sum is no more trustworthy than its weakest term. A dollar figure without its basis reads as billed truth, and an estimate must never impersonate a charge.
|
|
5419
|
+
§candidate-pinned-runtime **Candidate runtime stays pinned.** At launch, after its optional build, the candidate copies every workspace's package projection (`files`) into `<state>/runtime`, links third-party dependencies, and resolves `@plurnk/*` to those copies. Its daemon and its digest export both run from that copy, never the shared checkout, so neither source edits nor a concurrent candidate's or developer's rebuild after launch changes the code a run finishes on. The copy is removed once the digest is written.
|
|
5447
5420
|
|
|
5448
5421
|
§output-allowance-notice **The output allowance is not disclosed; a ceiling cut names its cause.** The packet's budget section carries the curation state and no response allowance: a model does not plan in tokens and no harness tells it its output ceiling, so the number is a fact without a use (#826). Overflow tolerance (#482) is likewise never advertised; a cut's notice names the true per-call grant from the response's own capacity record. When a provider finish is `length`, the engine emits an `output_truncated` notice (source `engine:capacity`) naming the allowance — the fact alone, never advice on what to do about it — on every path — railed or not — and the rails verdict never blames the model's grammar for a cut the engine's own ceiling made. The same precedence governs a cut so deep no operation parses: the rejection notice names the truncation as the cause, not the parser's symptom, overriding {§invalid-emission-attempts}'s parser diagnostic for `length` finishes.
|
|
5449
5422
|
|
|
5450
|
-
§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.
|
|
5451
|
-
|
|
5452
|
-
§digest-cache-ledger **Measured cache reuse and estimated prompt overlap are separate.**
|
|
5453
|
-
|
|
5454
|
-
| Projection | Meaning |
|
|
5455
|
-
|---|---|
|
|
5456
|
-
| `digest.json` provider-request `cachedTokens`, `inputTokens` | Exact provider-reported cache reads and input tokens; absent quantities remain `null`, reported zero remains zero. Every physical request counts, including retries and first requests of new loops. Stored packet availability is irrelevant to these counters. |
|
|
5457
|
-
| Turn `cache=<cached>/<input>` | Sum each measured quantity over that turn's requests. If any request omits a quantity, that sum is `?`. |
|
|
5458
|
-
| Workspace `Cache: <cached> of <input> reported input tokens read from cache (<pct>%) over <n> requests` | Sum only requests reporting both counters. Percentage is cache reads / input, rounded to one decimal; zero input is `n/a`. Requests missing either counter are counted separately as `missing input or cache usage (excluded)`. |
|
|
5459
|
-
| `digest.json` provider-request `adjacentPrefixTokensEstimate` | Optional loop-local diagnostic: the longest common character prefix with the preceding request, weighted under {§tokenomics-agnostic-ruler} as a share of the current stored prompt, multiplied by reported input tokens. First request: `0`; missing current/preceding packet or current input: `null`. Empty prompts have zero overlap. |
|
|
5460
|
-
|
|
5461
|
-
The prefix estimate uses the stored emission packet's wire message order, roles
|
|
5462
|
-
and content. A BARE request's input is not that packet; its prefix estimate and
|
|
5463
|
-
the following request's comparison are unknown. The estimate is
|
|
5464
|
-
neither provider tokenization nor a cache ceiling, and never supplies a cache-ratio
|
|
5465
|
-
denominator. Caching across loops or against other provider-resident prefixes
|
|
5466
|
-
does not make the measured counters inconsistent.
|
|
5467
|
-
|
|
5468
|
-
§digest-edit-census **Every model EDIT by the form it authored, how it landed, and whether it came back.** For each worker the digest reads every model-authored EDIT row and classifies the form from the row's stored marker and the durable statement's pattern: `hash` (one anchor), `line` (one line number), `range` (two marks), `insert` (the zero-width `<L,1,L,1>` form, {§zero-width-column-one-insert}), `column` (any other four-mark region), `prepend` / `append` (`<0>` / `<-1>`), `offset` (a tolerated anchor offset, {§anchor-offset}), `pattern` (a selection matcher), `whole` (no marker: a creation when it lands 201). It counts the EDITs, those refused (status ≥ 400), and the *revisits*: an EDIT of a path the same worker had edited within its previous two model turns — the shape of a repair without the claim of one. Each worker summary renders `EDITs: <n> · <form>=<count>… · refused=<k> · revisits=<r>` (`(no edits)` for none); `digest.json` carries the census as `edit_census` on every worker and stamps every EDIT log entry with its `edit_form` and `edit_revisit`. A form is a fact about what was written, never about intent; the bench sheet reads the counts as friction and leaves the judgement to the reader.
|
|
5469
|
-
|
|
5470
|
-
§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 worker summary's `Emissions:` line counts its announced emission rows, those the worker KILLed, and the headings it echoed ({§emission-row}); its `Reasonings:` line counts its landed reasoning rows, those the worker KILLed, and the turns that reasoned ({§reasoning-row}); the op mix leaves both harness rows out. 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 consecutive 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, and non-consecutive events preserve their chronological order. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
|
|
5471
|
-
|
|
5472
|
-
Unrecognized actionless log rows are retained and labelled as such, not
|
|
5473
|
-
interpreted as executable turnOps or allowed to prevent the remaining digest.
|
|
5474
|
-
|
|
5475
|
-
§digest-executor-evidence **A red command is work, not a defect.** Engine-materialized
|
|
5476
|
-
completion rows for a failed command carry the executor's problem identity
|
|
5477
|
-
(`https://problems.plurnk.xyz/executor/*`), and the digest classifies them as
|
|
5478
|
-
evidence: they render like any row but never count toward a loop's error total,
|
|
5479
|
-
its health verdict, or the per-turn `errs=` badge — a loop that concluded green
|
|
5480
|
-
over red test runs is CLEAN, not DEGENERATE-WIN. This is the digest mirror of the
|
|
5481
|
-
strike rail's exemption ({§engine-rails}, #425 F1): structural violations count,
|
|
5482
|
-
executor evidence never does.
|
|
5483
|
-
|
|
5484
|
-
§digest-requiem **A requiem is an out-of-band forensic interview, not a worker
|
|
5485
|
-
turn.** It cannot execute operations or alter the audited history.
|
|
5486
|
-
|
|
5487
|
-
| Aspect | Contract |
|
|
5488
|
-
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
5489
|
-
| Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
|
|
5490
|
-
| 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}). |
|
|
5491
|
-
| Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
|
|
5492
|
-
| Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as the `workerId`, without asserting a live worker topology. |
|
|
5493
|
-
| 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`. |
|
|
5494
|
-
| 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. |
|
|
5495
|
-
|
|
5496
|
-
§digest-requiem-evidence-budget **Quoted evidence fits the witness.** The
|
|
5497
|
-
interview's user message is budgeted against the witness provider's context
|
|
5498
|
-
window minus the retry output allowance and system framing (chars/2, the
|
|
5499
|
-
capacity gate's own estimator). Overflow elides the oldest provider attempts
|
|
5500
|
-
behind an explicit `elidedOldestAttempts` count marker, never silently; the
|
|
5501
|
-
final packet and the newest attempts always testify. A windowless witness
|
|
5502
|
-
(`contextWindow` null) quotes unbudgeted.
|
|
5503
|
-
|
|
5504
5423
|
§turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. The completion beat carries the spend ({§turn-accounting-notice}). Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
|
|
5505
5424
|
|
|
5506
5425
|
§turn-accounting-notice **The completion beat carries the spend.** `turn_generated`
|
|
@@ -5509,7 +5428,7 @@ USD and token totals with separately named known subtotals across every physical
|
|
|
5509
5428
|
calls included. It is the shared exact derivation from the ledger, never a second
|
|
5510
5429
|
stored fact, so a live watcher accrues running loop cost per turn (#465).
|
|
5511
5430
|
|
|
5512
|
-
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `
|
|
5431
|
+
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `output_unaccounted` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's exact `ops://<worker>/<loop>/<turn>` source; the optional previous-emission section shows a canonical program ({§previous-emission}), so the position names a line of the source, which READ of its address shows. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
|
|
5513
5432
|
Reasoning normalization notices use source `grammar:reasoning` and omit the
|
|
5514
5433
|
content-offset position: reasoning coordinates do not address the content source.
|
|
5515
5434
|
|
|
@@ -5518,9 +5437,9 @@ content-offset position: reasoning coordinates do not address the content source
|
|
|
5518
5437
|
§tools-resource-discovery **Executable capability discovery uses ordinary
|
|
5519
5438
|
Plurnk resources.** No generated tool table rides the system packet. Every
|
|
5520
5439
|
runtime enabled for the current worker with an admitted invocation materializes one
|
|
5521
|
-
|
|
5440
|
+
runtime document at `worker:///_plurnk/plurnk/<runtime>.md`. A general runtime's
|
|
5522
5441
|
document contains its {§executor-tool-document}; a runtime with an exact
|
|
5523
|
-
{§executor-tool-registry} materializes a compact catalog at the same address. The
|
|
5442
|
+
{§executor-tool-registry} materializes a compact catalog at the same address. The runtime document summarizes
|
|
5524
5443
|
the server or runtime, lists every enabled target as a directly copyable
|
|
5525
5444
|
executable fence named for the runtime, with its input preview ({§operation-aside} carries the
|
|
5526
5445
|
target one-liner; no invocation dispatch would reject is ever advertised).
|
|
@@ -5529,15 +5448,15 @@ Schema-backed targets link from that aside to
|
|
|
5529
5448
|
preserve the full tool description and raw input schema under
|
|
5530
5449
|
{§executor-input-schema-preview}; their nested paths do not contribute extra
|
|
5531
5450
|
Turn0 rows. A schema-backed general runtime uses `<runtime>/input.md`.
|
|
5532
|
-
Non-schema targets retain supplemental details
|
|
5451
|
+
Non-schema targets retain supplemental details after the framework-owned sections.
|
|
5533
5452
|
Tool-result/output schemas remain ordinary evidence, not teaching. Unknown-target
|
|
5534
|
-
recovery names the published
|
|
5453
|
+
recovery names the published runtime document through the same path owner as
|
|
5535
5454
|
materialization, including a runtime's declared `resourcesPath`.
|
|
5536
5455
|
|
|
5537
5456
|
```mermaid
|
|
5538
5457
|
flowchart LR
|
|
5539
|
-
Survey["Turn 0 FIND<br/>tools/*.md"] -->
|
|
5540
|
-
|
|
5458
|
+
Survey["Turn 0 FIND<br/>tools/*.md"] --> Runtimes["runtime paths + summaries"]
|
|
5459
|
+
Runtimes --> Read["READ selected runtime<br/>only when needed"]
|
|
5541
5460
|
Read --> Exec["execution with an aside"]
|
|
5542
5461
|
Read --> Schema["READ linked input schema<br/>when the preview is insufficient"]
|
|
5543
5462
|
Schema --> Exec
|
|
@@ -5546,28 +5465,28 @@ flowchart LR
|
|
|
5546
5465
|
§tools-resource-materialization The runtime registry, workspace capability policy,
|
|
5547
5466
|
tool resources, and dispatch use one effective workspace snapshot. A
|
|
5548
5467
|
disabled, unavailable, detached, replaced, or removed runtime has no
|
|
5549
|
-
tool resource; an exact registry's empty set publishes no
|
|
5468
|
+
tool resource; an exact registry's empty set publishes no runtime and
|
|
5550
5469
|
admits no invocation. Reconciliation deletes stale documents
|
|
5551
5470
|
before upserting the current set. `PLURNK_SERVICE_DOCS_EXCLUDE` does not hide an
|
|
5552
5471
|
enabled executable; executor enablement is the sole user-configured filter
|
|
5553
5472
|
shared by discovery and dispatch. A runtime declaration may carry
|
|
5554
5473
|
`resourcesPath` — its generated-doc root relative to the workspace's generated
|
|
5555
5474
|
subtree ({§worker-generated-subtree}). Absent, its docs live in the internal
|
|
5556
|
-
`_plurnk/plurnk` namespace; present (attached MCP
|
|
5557
|
-
the
|
|
5558
|
-
shared scratch. Turn 0 surveys the
|
|
5475
|
+
`_plurnk/plurnk` namespace; present (attached MCP servers: `/tools`),
|
|
5476
|
+
the runtime document materializes at `_plurnk` + that root in the
|
|
5477
|
+
shared scratch. Turn 0 surveys the runtimes (`FIND
|
|
5559
5478
|
(worker:///_plurnk/tools/*.md)`, one row per
|
|
5560
5479
|
server carrying its summary) and, for each server named in
|
|
5561
|
-
`PLURNK_MCP_EXPANDED`, adds one FIND over its
|
|
5480
|
+
`PLURNK_MCP_EXPANDED`, adds one FIND over its runtime document matching the
|
|
5562
5481
|
complete executable blocks (`FIND (worker:///_plurnk/tools/<server>.md)`
|
|
5563
5482
|
with a multiline regex over matching fences), so turn 0 names every tool with its aside and
|
|
5564
5483
|
signature — one row per tool, paged like every survey. Capability attenuation
|
|
5565
5484
|
restricts that matcher to the admitted exact tools. No document is delivered
|
|
5566
5485
|
unasked.
|
|
5567
|
-
When the registry supplies {§executor-tool-catalog} definitions, the
|
|
5486
|
+
When the registry supplies {§executor-tool-catalog} definitions, the runtime
|
|
5568
5487
|
document links to its sibling `<runtime>.json`. The catalog contains exactly
|
|
5569
5488
|
the effective tools and is an ordinary `application/json` resource for READ,
|
|
5570
|
-
FIND, and JSONPath selection. It follows the same reconciliation as the
|
|
5489
|
+
FIND, and JSONPath selection. It follows the same reconciliation as the runtime
|
|
5571
5490
|
document and per-tool schemas; neither the catalog nor its definitions are
|
|
5572
5491
|
automatically included in turn 0 or expanded-tool surveys.
|
|
5573
5492
|
Attached tools are capabilities like every other runtime; the model never
|
|
@@ -5599,10 +5518,11 @@ The alias is a short name, suggested from the glob. `list` shows each
|
|
|
5599
5518
|
definition with what it resolved to — `include` or `exclude`, the pattern, the members it
|
|
5600
5519
|
admits or removes (count and a bounded sample), and for a model's inclusion the matches the
|
|
5601
5520
|
repository's ignore rules refused — so the model sees what its glob did and adapts.
|
|
5602
|
-
`discover` is introspection, never a catalog:
|
|
5603
|
-
(tracked, included by which pattern, a creation record,
|
|
5604
|
-
untracked, absent); a glob previews what `add` would include
|
|
5605
|
-
|
|
5521
|
+
`discover` is introspection, never a catalog: its one input, `query`, is a path or a glob. A path
|
|
5522
|
+
answers why it is or is not visible (tracked, included by which pattern, a creation record,
|
|
5523
|
+
excluded by which `!glob`, ignored, untracked, absent); a glob previews what `add` would include
|
|
5524
|
+
or exclude. A query that names neither, blank or a bare `!`, is 400 `query-invalid`. Names only,
|
|
5525
|
+
never content; nothing is added.
|
|
5606
5526
|
|
|
5607
5527
|
§members-configuration *Available definitions.* `PLURNK_MEMBERS_<alias>=<glob>`
|
|
5608
5528
|
declares one service-origin rule (`!glob` excludes). The shared naming and
|
|
@@ -5638,154 +5558,26 @@ definitions ({§actor-boundary-catalog-preview}), so the model sees why a file i
|
|
|
5638
5558
|
not a member before it asks. There is no other membership path: the client's `/members`
|
|
5639
5559
|
verbs are these verbs.
|
|
5640
5560
|
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
its adapter owns protocol truth for standard Agent Skills and nothing else. A
|
|
5644
|
-
definition is `SkillDefinition`: the standard skill `name`, its `source`, and
|
|
5645
|
-
optional Git `ref`/resolved `commit` ({§skills-sources}). Only a host-provided
|
|
5646
|
-
resource tree omits `source`. Source location is not mutation ownership: standard
|
|
5647
|
-
project/global roots are read-only configuration inputs; live changes belong to
|
|
5648
|
-
the workspace. Plurnk neither installs into nor deletes from those roots.
|
|
5649
|
-
|
|
5650
|
-
*Available definitions.* The filesystem is the only truth about installation:
|
|
5651
|
-
every `<root>/<name>/SKILL.md` directory under the project, plurnk, then global
|
|
5652
|
-
root is one service-origin definition, a nearer root shadowing a farther one and
|
|
5653
|
-
all of them shadowing host-provided trees by name. Each filesystem definition
|
|
5654
|
-
names its actual source directory. The workspace's durable state owns
|
|
5655
|
-
enablement ({§functionality-state}); a disabled skill stays client-visible and
|
|
5656
|
-
leaves no model-facing trace.
|
|
5657
|
-
|
|
5658
|
-
§skills-configuration **Skills use the shared definition cascade.**
|
|
5659
|
-
|
|
5660
|
-
| Layer, low to high | Definition source |
|
|
5661
|
-
|---|---|
|
|
5662
|
-
| Service | Host-provided trees |
|
|
5663
|
-
| Standard locations | Global, plurnk, then project roots selected by {§agent-roots} |
|
|
5664
|
-
| Cascading environment | `PLURNK_SKILLS_<name>={"name":"<name>","source":"…","ref"?:"…"}` replaces the complete definition |
|
|
5665
|
-
| Live workspace | `skills (add)` creates a workspace definition through {§functionality-coordinator} |
|
|
5666
|
-
|
|
5667
|
-
`PLURNK_SKILLS_ENABLED` supplies default enabledness; `<name>_ENABLED` overrides
|
|
5668
|
-
it independently ({§resource-environment}). The decoded environment alias must
|
|
5669
|
-
equal the standard skill name, including digit-leading and Unicode names.
|
|
5670
|
-
Blank definitions are invalid; controls may precede a definition. Environment
|
|
5671
|
-
validation checks shape, names, remote URL rules, and Git-only `ref` without
|
|
5672
|
-
fetching or opening a source; `commit` is service-recorded, not an input.
|
|
5673
|
-
|
|
5674
|
-
*Discovery is inert.* `discover {source}` lists the standard skills one source
|
|
5675
|
-
carries, each a candidate with `source` provenance and the exact definition to
|
|
5676
|
-
add; it never installs, persists, or enables. Agent Skills have no standard
|
|
5677
|
-
registry, so `discover {query}` is 400 `query-unsupported`, naming the source
|
|
5678
|
-
forms. Client `configuration` contributes nothing and is refused with 400.
|
|
5679
|
-
|
|
5680
|
-
*Admission.* `add {alias, definition}` requires `alias = name` and a `source`;
|
|
5681
|
-
the workspace definition may shadow a service skill of the same name. Relative
|
|
5682
|
-
sources require a project root; absolute sources work in headless workspaces.
|
|
5683
|
-
A local source is recorded as its absolute path.
|
|
5684
|
-
A git source records the `commit` its `ref` names at admission, or its default
|
|
5685
|
-
branch's when no `ref` is given; `ref` belongs to git sources, and a supplied
|
|
5686
|
-
`commit` is refused because the service records it. The family's aliases use
|
|
5687
|
-
the standard skill-name grammar ({§agent-skills-name}), including digit-leading
|
|
5688
|
-
and Unicode names, rather than the coordinator's generic default.
|
|
5689
|
-
|
|
5690
|
-
*Preparation.* For each enabled alias the adapter selects the host-provided
|
|
5691
|
-
tree or resolves the complete source definition ({§skills-sources}). Local
|
|
5692
|
-
folders and their `SKILL.md` files remain live references, including supporting
|
|
5693
|
-
resources and symlink retargeting. Git/archive sources are materialized only
|
|
5694
|
-
inside {§module-workspace-directory}; different workspaces and complete source
|
|
5695
|
-
definitions cannot reuse each other's materializations accidentally.
|
|
5696
|
-
The first fetched Git/archive copy remains stable across enable, cooling, and
|
|
5697
|
-
restart until the complete source definition changes. In particular, an
|
|
5698
|
-
operator-configured symbolic Git ref is not an implicit update subscription.
|
|
5699
|
-
Each admitted skill requires standard `name` and `description` frontmatter
|
|
5700
|
-
with `name` matching its directory. A missing, uninstallable, or invalid skill
|
|
5701
|
-
is `unavailable` with its exact Problem ({§problems-functionality}) under the
|
|
5702
|
-
coordinator's failure policy ({§functionality-model-mutation}); one bad skill
|
|
5703
|
-
never fails the family.
|
|
5704
|
-
|
|
5705
|
-
Removal follows {§skills-remove}.
|
|
5706
|
-
|
|
5707
|
-
§skills-sources **A source is a git remote, a folder, or a file, read with standard tools.**
|
|
5708
|
-
Fetching runs nothing it fetched. Materialized copies cannot contain references
|
|
5709
|
-
outside their skill; live resources retain {§agent-skills-directory} containment.
|
|
5710
|
-
|
|
5711
|
-
| Source | How it is read |
|
|
5712
|
-
|---|---|
|
|
5713
|
-
| Git remote: a full `https://` or `ssh://` URL, or `user@host:path` | `git ls-remote` resolves the ref at admission; preparation shallow-clones it with hooks and submodules off, and a checkout at any other commit is 409 `source-moved` |
|
|
5714
|
-
| Folder: absolute, `~/`, or relative to the project root | Live reference; standard directory/name matching applies |
|
|
5715
|
-
| A file named `SKILL.md` | Live reference to its skill directory and supporting resources |
|
|
5716
|
-
| A `.zip`, `.tar`, `.tgz`, `.tar.gz`, `.tar.bz2`, `.tar.xz`, or `.tar.zst` archive | Unpacked into private staging with `unzip` or `tar`; a lone top-level directory is the source's root |
|
|
5717
|
-
|
|
5718
|
-
Any other scheme, plain `http`, `owner/repo` shorthand, and an https URL carrying
|
|
5719
|
-
credentials are refused with `source-invalid` or `source-missing`: shorthand names no
|
|
5720
|
-
forge, and a recorded source is listed to every client. Git runs with the
|
|
5721
|
-
operator's configuration, credentials, and SSH agent, never plurnk's secrets, and
|
|
5722
|
-
never prompts; `PLURNK_SERVICE_SKILLS_FETCH_TIMEOUT_MS` bounds each fetch. The
|
|
5723
|
-
retired vendor-installer knobs (`PLURNK_SERVICE_SKILLS_CLI`, `_CLI_TIMEOUT_MS`,
|
|
5724
|
-
`_REGISTRY_URL`, `_REGISTRY_LIMIT`, `_REGISTRY_TIMEOUT_MS`) make the skills family
|
|
5725
|
-
unavailable when set, each naming what replaced it ({§configuration-repair-path}).
|
|
5726
|
-
|
|
5727
|
-
A source's skills are the directories holding a `SKILL.md`, found by walking
|
|
5728
|
-
from its root without entering `.git` or a skill already found. A fetched skill at
|
|
5729
|
-
the root is named by its frontmatter ({§agent-skills-name}); local references and
|
|
5730
|
-
directories below the root use the standard folder rule. A source with `plugin.json` at its root is an
|
|
5731
|
-
Agent Plugin and is refused with 422 `source-is-plugin`, so its skills keep the
|
|
5732
|
-
plugin's identity. Materialization copies the named skill beside its workspace-owned destination
|
|
5733
|
-
and renames it to `<root>/<name>`; a copy that holds a link out of the skill, or
|
|
5734
|
-
anything but files, directories, and inward links, is refused with 422
|
|
5735
|
-
`source-unsafe` and leaves nothing behind.
|
|
5736
|
-
|
|
5737
|
-
§skills-resources **A skill is a resource tree, not a rewritten document.**
|
|
5738
|
-
The family exposes enabled, available {§agent-skills-tree} sources through
|
|
5739
|
-
`skill://<name>/`. The source owns its bytes; commons entries are demand-loaded
|
|
5740
|
-
projections, not writable installations. Filesystem skills retain their original
|
|
5741
|
-
directories; service-provided trees need no generated filesystem directory.
|
|
5742
|
-
The authority is the name's WHATWG URI representation, including percent-encoding
|
|
5743
|
-
for non-ASCII names. Installation names remain unchanged; a raw spelling and its
|
|
5744
|
-
serialized URI address the same resource, not separate skill identities.
|
|
5745
|
-
|
|
5746
|
-
| Operation | Contract |
|
|
5747
|
-
| --- | --- |
|
|
5748
|
-
| Turn0 `FIND (skill://*/SKILL.md)` | One ordinary resource catalog: name, address, and standard frontmatter description via {§mimetype-summary}. No synthetic index, body injection, or execution. |
|
|
5749
|
-
| `READ (skill://<name>/SKILL.md)` | Original frontmatter and Markdown, unchanged; relative links remain relative to the source layout. |
|
|
5750
|
-
| `READ` / `FIND` below the authority | References, scripts, and assets retain their source paths and ordinary pattern, channel, byte, and multimodal semantics. Acquisition observes current source contents, including disappearance. |
|
|
5751
|
-
| ```` ```runtime (skill://<name>/scripts/program.ext) ```` | Ordinary resource execution and proposal policy; preserve the native file and its siblings under {§exec-source-temporary}. Discovery and READ never execute scripts. |
|
|
5752
|
-
| Model mutation | Read-only; no EDIT, SEND, or KILL of skill resources. Manage definitions and enablement through ```` ```skills ````. |
|
|
5753
|
-
| Disable / unavailable / remove | Withdraw the authority from new resource access and discovery. Existing log receipts remain historical evidence. |
|
|
5754
|
-
| WORK / FORK | Use the same workspace Functionality, not copied definitions or resource caches. |
|
|
5755
|
-
|
|
5756
|
-
Explicit skill URIs address these resources; bare operation paths still address
|
|
5757
|
-
project files, with no implicit current-skill directory. Source resolution follows
|
|
5758
|
-
{§agent-skills-directory}, including symlinked skill directories and containment of references.
|
|
5759
|
-
An uninstalled Git skill is not manufactured by repository detection.
|
|
5561
|
+
The skills module owns the Agent Skills family ({§skills-functionality}) and its resource trees
|
|
5562
|
+
({§skills-resources}); core supplies the Plurnk reference through {§provided-skills-module-slice}.
|
|
5760
5563
|
|
|
5761
5564
|
§plurnk-skill **Plurnk's own reference is an ordinary service-provided skill.**
|
|
5762
5565
|
`skill://plurnk/SKILL.md` is the standard frontmatter entry point, catalogued with
|
|
5763
|
-
other enabled skills. It links package-owned configuration, model,
|
|
5764
|
-
the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`,
|
|
5765
|
-
|
|
5766
|
-
|
|
5566
|
+
other enabled skills. It links package-owned configuration, model, COPY/MOVE and extensibility
|
|
5567
|
+
chapters, the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`, the
|
|
5568
|
+
installed contracts at `skill://plurnk/packages/<package name>/SPEC.md`, and the
|
|
5569
|
+
Worker's existing tool/resource references. The contracts are the service's own `SPEC.md` and
|
|
5570
|
+
each installed ecosystem package's that ships one, the same membership as the defaults
|
|
5571
|
+
aggregate, with that package's published type declarations beside it at
|
|
5572
|
+
`packages/<package name>/dist/**/*.d.ts`; the service's declarations are its internals and are not
|
|
5573
|
+
served. Contracts are listed when the tree is listed and read where each package installed them,
|
|
5574
|
+
never through a symbolic link. No chapter, contract or defaults body is injected merely because the
|
|
5575
|
+
skill is enabled. The defaults bytes come from the
|
|
5767
5576
|
same {§operator-config-env-defaults} renderer as the operator command, never the
|
|
5768
5577
|
effective environment. Native chapter files retain their owners and locations;
|
|
5769
5578
|
runtime-generated bytes have no invented disk location. Disable/enable,
|
|
5770
5579
|
shared workspace visibility, and project/global shadowing use the ordinary Skills lifecycle.
|
|
5771
|
-
Service-provided skills are
|
|
5772
|
-
|
|
5773
|
-
§skills-remove **`remove` forgets the workspace binding, not the source.**
|
|
5774
|
-
It withdraws that definition and restores any inherited definition and enabledness
|
|
5775
|
-
({§functionality-coordinator}). External folders are never deleted. Fetched
|
|
5776
|
-
materializations remain workspace-owned operational state, reusable only for the
|
|
5777
|
-
same complete definition; they confer no availability without a definition.
|
|
5778
|
-
Inherited definitions cannot be removed here; their enabledness can be overridden.
|
|
5779
|
-
|
|
5780
|
-
§skills-hotload **Skills placed out of band are admitted at the next turn** ({§functionality-hotload}). The
|
|
5781
|
-
family keeps one signature of the discovered roots, configured definitions, source locations, and `SKILL.md` sources
|
|
5782
|
-
per resident workspace, read before a publication loads the skills it describes. Turn admission
|
|
5783
|
-
recomputes it under the workspace gate before packet assembly: a changed signature republishes the
|
|
5784
|
-
family, and an unchanged one republishes only when the skills the coordinator would publish differ
|
|
5785
|
-
from the published ones. A skill installed, edited or removed by any other tool is therefore
|
|
5786
|
-
discoverable in the first subsequent model turn, while an unchanged set dispatches nothing. The model manages skills
|
|
5787
|
-
only through the generated ```` ```skills ```` family
|
|
5788
|
-
({§functionality-model-projection}); it is never taught a package manager.
|
|
5580
|
+
Service-provided skills are host-provided trees, never fetched; removal follows {§skills-remove}.
|
|
5789
5581
|
|
|
5790
5582
|
The catalog and Turn0 describe Functionality under the current workspace
|
|
5791
5583
|
capability policy and service ceiling. A direct denied attempt receives the
|
|
@@ -5808,7 +5600,7 @@ section because they are language extensions rather than executable tools.
|
|
|
5808
5600
|
|
|
5809
5601
|
### §inject system.inject — the operator injection
|
|
5810
5602
|
|
|
5811
|
-
§packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot (definition → policy → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard as {§policy-sections} rules. `~/` expands to home. It's the operator-side complement to the
|
|
5603
|
+
§packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot (definition → policy → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard as {§policy-sections} rules. `~/` expands to home. It's the operator-side complement to the extension packet transform — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
|
|
5812
5604
|
|
|
5813
5605
|
### §policy system.policy — the client's policy injection
|
|
5814
5606
|
|
|
@@ -5821,18 +5613,6 @@ surfaces with its cause and leaves no apparently initialized home.
|
|
|
5821
5613
|
After that bootstrap the file is user-owned: edits and deletion persist, and a
|
|
5822
5614
|
later boot never refreshes or recreates it.
|
|
5823
5615
|
|
|
5824
|
-
§legacy-home-transition A legacy `~/.plurnk` is never an ambient fallback. If
|
|
5825
|
-
legacy state exists while canonical destinations do not, ordinary startup
|
|
5826
|
-
fails with the exact `plurnk-service paths migrate` recovery. That explicit,
|
|
5827
|
-
idempotent command refuses destination conflicts and a live database owner,
|
|
5828
|
-
moves known user configuration and durable SQLite files to their semantic
|
|
5829
|
-
homes, byte-verifies the complete copied set before removing any source,
|
|
5830
|
-
discards only recognized generated references, and removes the empty legacy
|
|
5831
|
-
directory. A pre-commit failure rolls back canonical files and directories
|
|
5832
|
-
created by that attempt. Unknown legacy members or simultaneous
|
|
5833
|
-
legacy/canonical state fail without guessing. No dual read or dual write survives
|
|
5834
|
-
the transition.
|
|
5835
|
-
|
|
5836
5616
|
§schemes-self-doc-materialization **One generated reference tree per workspace.** `@plurnk/plurnk-schemes` owns `SchemeManifest.documentation` ({§manifest-self-doc}). Each reference carries an H2 `Summary` for ordinary catalog projection. `SchemeRegistry.docs(workspaceId)` resolves corpus-or-manifest documentation, and `referenceEntries` applies workspace capabilities to that source. One workspace materializer deletes vanished contributions and upserts current documents. Concurrent readers share the same reconciliation and outcome; independent workspaces do not serialize together. Ordinary runtime turns maintain {§worker-generated-subtree}, including under read-only workspace policy.
|
|
5837
5617
|
|
|
5838
5618
|
### §packet-git-status The Git status section — compact repository state
|
|
@@ -6201,12 +5981,12 @@ caller's own run directory.
|
|
|
6201
5981
|
|
|
6202
5982
|
Every Problem code core mints is named here under its family ({§problem-error-carrier} carries it); the root lint (`scripts/problem-codes.mjs`) refuses a code no owning SPEC names.
|
|
6203
5983
|
|
|
6204
|
-
§problems-dispatch **Dispatch Problems.** Every code
|
|
5984
|
+
§problems-dispatch **Dispatch Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6205
5985
|
|
|
6206
5986
|
| code | status | contract |
|
|
6207
5987
|
|---|---:|---|
|
|
6208
5988
|
| `target-required` | 400 | *OP* requires a target path. Recovery: Write the target in parentheses on the opening fence line: `OP (path)`. |
|
|
6209
|
-
| `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery})
|
|
5989
|
+
| `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery}) `Registered schemes: *names*.` |
|
|
6210
5990
|
| `scheme-metadata-unsupported` | 400 | *OP* on '*scheme*' does not accept the [metadata] modifier. |
|
|
6211
5991
|
| `operation-not-implemented` | 501 | Scheme '*name*' does not implement *OP* (or exec). |
|
|
6212
5992
|
| `entry-read-not-implemented` | 501 | The '*scheme*' scheme does not provide entry reads. |
|
|
@@ -6229,17 +6009,15 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
6229
6009
|
| `channel-required` | 400 | The '*scheme*' scheme has no default channel. Recovery: Address a named channel with a URI fragment. |
|
|
6230
6010
|
| `binary-source-unsupported` | 415 | Channel #*name* is binary and its scheme keeps no bytes to transfer. |
|
|
6231
6011
|
| `metadata-unsupported` | 400 | *OP* takes only the env option; '*key*' is not one. |
|
|
6232
|
-
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace.
|
|
6012
|
+
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace. |
|
|
6233
6013
|
| `no-operation` | 422 | The turn performed no operation ({§empty-turn}). |
|
|
6234
6014
|
| `send-target-not-a-recipient` | 400 | The addressed scheme is not a SEND recipient. Recovery: A targetless SEND answers the open messages; a directed SEND requires a recipient that implements SEND. |
|
|
6235
6015
|
|
|
6236
|
-
§unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.**
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
otherwise it lists the schemes the workspace registers. READ, FIND, KILL and resource selection share
|
|
6240
|
-
the sentence.
|
|
6016
|
+
§unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.** Its recovery
|
|
6017
|
+
lists the schemes the workspace registers, and rebuilds the address into nothing else
|
|
6018
|
+
({§diagnostic-observation}). READ, FIND, KILL and resource selection share the sentence.
|
|
6241
6019
|
|
|
6242
|
-
§problems-content **Content and transfer Problems.** Every code
|
|
6020
|
+
§problems-content **Content and transfer Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6243
6021
|
|
|
6244
6022
|
| code | status | contract |
|
|
6245
6023
|
|---|---:|---|
|
|
@@ -6256,7 +6034,7 @@ the sentence.
|
|
|
6256
6034
|
| `proposal-apply-missing` | 500 | The source scheme accepted its MOVE proposal without applying the source mutation. |
|
|
6257
6035
|
| `line-anchor-collision` | 409 | READ coordinates collided with current content at *target*. |
|
|
6258
6036
|
|
|
6259
|
-
§problems-file **File scheme Problems.** Every code
|
|
6037
|
+
§problems-file **File scheme Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6260
6038
|
|
|
6261
6039
|
| code | status | contract |
|
|
6262
6040
|
|---|---:|---|
|
|
@@ -6269,13 +6047,13 @@ the sentence.
|
|
|
6269
6047
|
| `path-names-no-file` | 403 | The spelling '*path*' does not name a file: it is empty, or it names a directory. |
|
|
6270
6048
|
| `path-occupied-by-nonmember` | 403 | A non-member file already occupies '*path*'. Recovery: Choose an unoccupied member path. |
|
|
6271
6049
|
| `path-outside-workspace` | 403 | A symlink on '*path*' resolves outside the namespace. |
|
|
6272
|
-
| `binary-write-unsupported` | 415 | A text EDIT cannot author binary '*mimetype*'
|
|
6050
|
+
| `binary-write-unsupported` | 415 | A text EDIT cannot author binary '*mimetype*'. |
|
|
6273
6051
|
| `file-create-excluded` | 403 | A members exclusion (`!_glob_`) covers '*path*'. Recovery: Remove or disable the excluding members definition, or choose another path. |
|
|
6274
6052
|
| `file-create-gitignored` | 403 | Active Git policy ignores '*path*', and no members definition includes it. Recovery: Choose a Git-admitted path or add a members definition that includes it. |
|
|
6275
6053
|
| `file-materialization-limit` | 413 | The file exceeds the materialization byte limit and is not read into the workspace. |
|
|
6276
|
-
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery:
|
|
6054
|
+
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. A path beyond the root recovers instead to: '*path*' is outside the project root: only a members definition under the operator's namespace scope admits it. |
|
|
6277
6055
|
|
|
6278
|
-
§problems-exec **Execution Problems.** Every code
|
|
6056
|
+
§problems-exec **Execution Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6279
6057
|
|
|
6280
6058
|
| code | status | contract |
|
|
6281
6059
|
|---|---:|---|
|
|
@@ -6284,7 +6062,7 @@ the sentence.
|
|
|
6284
6062
|
| `stream-not-found` | 404 | No execution exists at the requested address. Recovery, when the id holds an execution under another runtime ({§exec-near-miss}): The execution at /*id* is `*runtime*:///*id*`. |
|
|
6285
6063
|
| `input-closed` | 410 | Execution input is closed. |
|
|
6286
6064
|
|
|
6287
|
-
§problems-entries **Entry scheme Problems (log, worker, entries).** Every code
|
|
6065
|
+
§problems-entries **Entry scheme Problems (log, worker, entries).** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6288
6066
|
|
|
6289
6067
|
| code | status | contract |
|
|
6290
6068
|
|---|---:|---|
|
|
@@ -6297,33 +6075,20 @@ the sentence.
|
|
|
6297
6075
|
| `message-empty` | 400 | SEND has no message text or attachments. |
|
|
6298
6076
|
| `scope-unsupported` | 400 | A worker SEND takes no scope. |
|
|
6299
6077
|
|
|
6300
|
-
§problems-functionality **Server and Functionality Problems.** Every code
|
|
6078
|
+
§problems-functionality **Server and Functionality Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6301
6079
|
|
|
6302
6080
|
| code | status | contract |
|
|
6303
6081
|
|---|---:|---|
|
|
6304
6082
|
| `service-starting` | 503 | The PLURNK service owns this listener but has not admitted its client interface yet. |
|
|
6305
|
-
| `
|
|
6083
|
+
| `route-not-found` | 404 | The requested HTTP route does not exist. |
|
|
6306
6084
|
| `configuration-invalid` | 503 | The owning configuration reader's diagnostic, naming the invalid key. Recovery: Correct the named configuration input. Other capabilities remain available. |
|
|
6307
6085
|
| `name-reserved` | 400 | '*alias*' is plurnk's own: PLURNK_* configuration and provider credential names never reach a subprocess. |
|
|
6308
6086
|
| `value-invalid` | 400 | '*alias*' needs a string value. |
|
|
6309
6087
|
| `env-invalid` | 400 | `env` must be an object of string values; '*name*' is not a name a shell can export. |
|
|
6310
|
-
| `query-
|
|
6088
|
+
| `query-invalid` | 400 | '*query*' names no path or pattern. Recovery: Supply a path such as `docs/guide.md` or a pattern such as `docs/**`. |
|
|
6311
6089
|
| `headless` | 409 | The workspace has no project root, so there are no file members. Recovery: Open the workspace on a project root. |
|
|
6312
|
-
| `definition-invalid` | 400 | A members definition is { glob }: a gitignore-style pattern, `!glob` to exclude
|
|
6090
|
+
| `definition-invalid` | 400 | A members definition is { glob }: a gitignore-style pattern, `!glob` to exclude. |
|
|
6313
6091
|
| `model-scope` | 403 | The model may not change membership here: the members scope is none. Recovery: `git add` the file so git tracks it, or ask the operator to add it (/members add) or raise PLURNK_SERVICE_MEMBERS_MODEL_SCOPE. |
|
|
6314
|
-
| `query-unsupported` | 400 | Agent Skills have no standard registry to search; discover takes a source: a git remote as a full https or ssh URL, a folder, a lone SKILL.md, or a zip or tar archive. |
|
|
6315
|
-
| `source-invalid` | 400 | '*source*' is not a valid git remote URL; an https source carries no credentials (git's credential helper supplies them); is not a source: a git remote is a full https or ssh URL; is relative, and this workspace has no project root to resolve it against; or is neither a folder, a SKILL.md, nor a zip or tar archive. |
|
|
6316
|
-
| `source-missing` | 404 | No folder or file is at '*source*' (; owner/repo shorthand names no forge, so give the repository's full https or ssh URL). |
|
|
6317
|
-
| `source-unreadable` | 422 | '*source*' cannot be read: *cause*; or '*path*' could not be unpacked: *reason*. |
|
|
6318
|
-
| `source-unreachable` | 502 | git could not reach '*remote*', or fetch it (at '*ref*'): *reason*. |
|
|
6319
|
-
| `ref-missing` | 404 | '*remote*' has no branch or tag '*ref*', or names no default branch. |
|
|
6320
|
-
| `source-moved` | 409 | '*source*' *ref* now names *current*; this skill was added at *commit*. Recovery: Remove the skill and add it again to take the current commit. |
|
|
6321
|
-
| `source-is-plugin` | 422 | '*source*' is an Agent Plugin; install it as a plugin, so its skills keep the plugin's identity and servers. |
|
|
6322
|
-
| `source-unsafe` | 422 | '*path*' links outside its skill, or is neither a file, a directory, nor an inward link. |
|
|
6323
|
-
| `skill-not-found` | 404 | '*source*' carries no Agent Skill named '*name*'. |
|
|
6324
|
-
| `skill-ambiguous` | 409 | '*source*' carries *count* skills named '*name*'. |
|
|
6325
|
-
| `alias-mismatch` | 400 | Alias '*alias*' must equal the skill name '*name*'. |
|
|
6326
|
-
| `source-required` | 400 | Adding '*alias*' requires the source that provides it. |
|
|
6327
6092
|
| `workspace-not-found` | 404 | Workspace *id* does not exist. |
|
|
6328
6093
|
| `state-not-json` | 400 | Worker module state is not JSON-serializable. |
|
|
6329
6094
|
| `workspace-busy` | 409 | Workspace *id* is running an operation or another capability change. Recovery: Settle the current operation and retry the capability change. |
|
|
@@ -6333,12 +6098,8 @@ the sentence.
|
|
|
6333
6098
|
| `offset-channel-required` | 400 | Recovery: Select the channel to read from the offset. |
|
|
6334
6099
|
| `target-invalid` | 400 | Recovery: Use a scheme://path target. |
|
|
6335
6100
|
| `proposal-not-pending` | 409 | Recovery: Refresh pending proposals before resolving one. |
|
|
6336
|
-
| `loop-policy-invalid` | 400 | An unattended loop cannot hold a proposal for review: nobody is present to answer. Recovery: State proposals accept or reject, or attend the loop. |
|
|
6337
6101
|
| `scope-cancelled` | 499 | The worker scope was cancelled: *reason*. |
|
|
6338
|
-
| `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery:
|
|
6339
|
-
| `install-failed` | 500 | Agent Skill '*name*' could not be placed under *root*: *cause*. |
|
|
6340
|
-
| `skill-missing` | 404 | Agent Skill '*alias*' is not provided by this service. |
|
|
6341
|
-
| `skill-invalid` | 422 | Agent Skill '*alias*' is not a valid standard skill: *cause*. |
|
|
6102
|
+
| `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery: Trim one line with `<L>` or lines L through M with `<L,M>`; `KILL (log:///…/READ)` with no scope retires the whole row. |
|
|
6342
6103
|
|
|
6343
6104
|
§pinned-wording-core **Pinned wording.** Verbatim sentences tests pin: each is contract, and a change here is a change of contract.
|
|
6344
6105
|
|
|
@@ -6348,12 +6109,13 @@ the sentence.
|
|
|
6348
6109
|
| Completion deferred. Conclude with KILL alone. | a concluding KILL that carries other operations ({§kill-conclusion}) |
|
|
6349
6110
|
| Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn. | the over-budget row ({§context-over-budget-row}) |
|
|
6350
6111
|
| Context window overflow: the packet cannot fit the model's window even as receipts. | the wall ({§context-wall}) |
|
|
6351
|
-
|
|
|
6112
|
+
| No recipient implements the requested interaction. | The worker's owner is not interactive or does not declare the required client tool ({§client-interaction-routing}). |
|
|
6113
|
+
| Nobody is present to answer. Decide from what you already have, or conclude stating what you could not resolve. | dispatch of an interaction tool the worker's owner would not receive ({§owner-interaction-ring}) |
|
|
6352
6114
|
| Worker name '*name*' must match `[A-Za-z0-9][A-Za-z0-9_-]{0,62}`. Recovery: Use 1–63 ASCII letters, digits, '_' or '-', starting with a letter or digit. | an invalid worker name |
|
|
6353
6115
|
| Provide the client identifier. / Provide an absolute project path. / Use a positive integer limit. / prompt is not a non-empty string. | client input validation on the daemon's methods |
|
|
6354
6116
|
| The stream was cancelled by KILL. | a stream terminal after KILL |
|
|
6355
6117
|
| '*program*' exited with code *n*. | an execution's non-zero exit |
|
|
6356
|
-
| '*path*' is a directory, not a file; READ reads one file. Recovery:
|
|
6118
|
+
| '*path*' is a directory, not a file; READ reads one file. Recovery: `FIND (_path_/)` lists its files. | READ of a directory |
|
|
6357
6119
|
| The execution at ops://*worker*/*loop* has not concluded. | a bare READ of a running worker's result (425) |
|
|
6358
6120
|
| The child provider failed. | a child's provider failure read back by its parent |
|
|
6359
6121
|
| '*path*' exists on disk but is not a member of this workspace. Recovery: Admit it with `members (add)` and a `{"glob": "<path>"}` body. | a non-member on disk at the addressed path |
|