@plurnk/plurnk-service 1.10.1 → 1.12.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 +41 -17
- package/INSTALL.md +4 -4
- package/README.md +2 -2
- package/SPEC.md +573 -273
- package/digest-sql/curation/curation.sql +1 -0
- package/dist/Paths.d.ts +3 -3
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +9 -9
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/edit-collision.d.ts +1 -1
- package/dist/content/edit-collision.d.ts.map +1 -1
- package/dist/content/edit-collision.js +5 -4
- package/dist/content/edit-collision.js.map +1 -1
- package/dist/content/edit-receipt.d.ts +6 -5
- package/dist/content/edit-receipt.d.ts.map +1 -1
- package/dist/content/edit-receipt.js +28 -8
- package/dist/content/edit-receipt.js.map +1 -1
- package/dist/content/index.d.ts +2 -2
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +1 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/line-anchors.d.ts +2 -0
- package/dist/content/line-anchors.d.ts.map +1 -1
- package/dist/content/line-anchors.js +15 -6
- package/dist/content/line-anchors.js.map +1 -1
- package/dist/content/line-marker.d.ts +0 -1
- package/dist/content/line-marker.d.ts.map +1 -1
- package/dist/content/line-marker.js.map +1 -1
- package/dist/content/matcher.d.ts.map +1 -1
- package/dist/content/matcher.js +3 -2
- package/dist/content/matcher.js.map +1 -1
- package/dist/content/read-projector.js +3 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +6 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +38 -2
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/CapabilityPolicies.d.ts +15 -0
- package/dist/core/CapabilityPolicies.d.ts.map +1 -0
- package/dist/core/CapabilityPolicies.js +60 -0
- package/dist/core/CapabilityPolicies.js.map +1 -0
- package/dist/core/CapabilityResolver.d.ts +24 -0
- package/dist/core/CapabilityResolver.d.ts.map +1 -0
- package/dist/core/CapabilityResolver.js +180 -0
- package/dist/core/CapabilityResolver.js.map +1 -0
- package/dist/core/ChannelWrite.d.ts +4 -3
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.d.ts +2 -2
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +2 -2
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +5 -2
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +157 -165
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/DurableStatement.d.ts.map +1 -1
- package/dist/core/DurableStatement.js +19 -15
- package/dist/core/DurableStatement.js.map +1 -1
- package/dist/core/EmbeddingCall.d.ts +23 -0
- package/dist/core/EmbeddingCall.d.ts.map +1 -0
- package/dist/core/EmbeddingCall.js +149 -0
- package/dist/core/EmbeddingCall.js.map +1 -0
- package/dist/core/Engine.d.ts +6 -4
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +20 -9
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +119 -56
- package/dist/core/ExecutorRegistry.d.ts +3 -3
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +10 -6
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/GitBranch.d.ts +4 -1
- package/dist/core/GitBranch.d.ts.map +1 -1
- package/dist/core/GitBranch.js +12 -2
- package/dist/core/GitBranch.js.map +1 -1
- package/dist/core/InferenceCall.d.ts +18 -0
- package/dist/core/InferenceCall.d.ts.map +1 -0
- package/dist/core/InferenceCall.js +86 -0
- package/dist/core/InferenceCall.js.map +1 -0
- package/dist/core/LogEntryProjection.d.ts +1 -0
- package/dist/core/LogEntryProjection.d.ts.map +1 -1
- package/dist/core/LogEntryProjection.js +12 -4
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LoopPolicyReader.d.ts +7 -0
- package/dist/core/LoopPolicyReader.d.ts.map +1 -0
- package/dist/core/LoopPolicyReader.js +33 -0
- package/dist/core/LoopPolicyReader.js.map +1 -0
- package/dist/core/ModelCall.d.ts +4 -12
- package/dist/core/ModelCall.d.ts.map +1 -1
- package/dist/core/ModelCall.js +10 -74
- package/dist/core/ModelCall.js.map +1 -1
- package/dist/core/NoticeChannel.d.ts +2 -2
- package/dist/core/NoticeChannel.d.ts.map +1 -1
- package/dist/core/NoticeChannel.js +18 -9
- package/dist/core/NoticeChannel.js.map +1 -1
- package/dist/core/OperatorConfig.d.ts.map +1 -1
- package/dist/core/OperatorConfig.js +4 -0
- package/dist/core/OperatorConfig.js.map +1 -1
- package/dist/core/OverflowTurn.d.ts.map +1 -1
- package/dist/core/OverflowTurn.js +4 -3
- package/dist/core/OverflowTurn.js.map +1 -1
- package/dist/core/Owner.js +5 -5
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +2 -2
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +55 -35
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.d.ts.map +1 -1
- package/dist/core/ProblemLog.js +1 -0
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +16 -13
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ReasoningEvent.d.ts +1 -0
- package/dist/core/ReasoningEvent.d.ts.map +1 -1
- package/dist/core/ResourceMutations.d.ts +6 -4
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +209 -63
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +6 -3
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +14 -17
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ServiceTeardown.d.ts +1 -1
- package/dist/core/ServiceTeardown.d.ts.map +1 -1
- package/dist/core/ServiceTeardown.js +4 -8
- package/dist/core/ServiceTeardown.js.map +1 -1
- package/dist/core/StrikeRail.d.ts +1 -0
- package/dist/core/StrikeRail.d.ts.map +1 -1
- package/dist/core/StrikeRail.js +12 -3
- package/dist/core/StrikeRail.js.map +1 -1
- package/dist/core/ToolResources.d.ts +2 -2
- package/dist/core/ToolResources.d.ts.map +1 -1
- package/dist/core/ToolResources.js +18 -8
- package/dist/core/ToolResources.js.map +1 -1
- package/dist/core/Turn.sql +6 -3
- package/dist/core/TurnOps.d.ts.map +1 -1
- package/dist/core/TurnOps.js +22 -8
- package/dist/core/TurnOps.js.map +1 -1
- package/dist/core/TurnRunner.d.ts +7 -4
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +345 -83
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerControlAddress.d.ts.map +1 -1
- package/dist/core/WorkerControlAddress.js +1 -2
- package/dist/core/WorkerControlAddress.js.map +1 -1
- package/dist/core/WorkerName.d.ts +2 -0
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/WorkerName.js +3 -2
- package/dist/core/WorkerName.js.map +1 -1
- package/dist/core/WorkerName.sql +2 -1
- package/dist/core/caps/DbProjectionCaps.d.ts +2 -1
- package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
- package/dist/core/caps/DbProjectionCaps.js +12 -1
- package/dist/core/caps/DbProjectionCaps.js.map +1 -1
- package/dist/core/file-materialization.d.ts +22 -0
- package/dist/core/file-materialization.d.ts.map +1 -0
- package/dist/core/file-materialization.js +77 -0
- package/dist/core/file-materialization.js.map +1 -0
- package/dist/core/fork.d.ts +2 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +13 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +27 -11
- package/dist/core/git-membership.d.ts +25 -14
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +260 -164
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +2 -0
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +27 -1
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/operation-target-groups.d.ts.map +1 -1
- package/dist/core/operation-target-groups.js +8 -7
- package/dist/core/operation-target-groups.js.map +1 -1
- package/dist/core/owner.sql +7 -10
- package/dist/core/packet-wire.d.ts +11 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +98 -34
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/scheme-types.d.ts +2 -2
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/scheme-types.js +1 -1
- package/dist/core/scheme-types.js.map +1 -1
- package/dist/core/types.d.ts +3 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-settings.d.ts +4 -3
- package/dist/core/worker-settings.d.ts.map +1 -1
- package/dist/core/worker-settings.js +40 -19
- package/dist/core/worker-settings.js.map +1 -1
- package/dist/core/workspace-settings.d.ts +3 -1
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +6 -2
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +151 -42
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +48 -20
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/schemes/Exec.d.ts +4 -5
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +111 -94
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +24 -6
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/ExecScheduler.d.ts +15 -0
- package/dist/schemes/ExecScheduler.d.ts.map +1 -0
- package/dist/schemes/ExecScheduler.js +95 -0
- package/dist/schemes/ExecScheduler.js.map +1 -0
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +26 -19
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts +6 -4
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +132 -39
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +23 -18
- package/dist/schemes/QuestionTool.d.ts +17 -4
- package/dist/schemes/QuestionTool.d.ts.map +1 -1
- package/dist/schemes/QuestionTool.js +2 -4
- package/dist/schemes/QuestionTool.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +20 -20
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-chunk.d.ts.map +1 -1
- package/dist/schemes/_entry-chunk.js +6 -2
- package/dist/schemes/_entry-chunk.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +18 -17
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +9 -14
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-graph.js +12 -12
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-graph.sql +5 -5
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +15 -5
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-semantic.d.ts +5 -3
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +21 -9
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_path-scope.d.ts.map +1 -1
- package/dist/schemes/_path-scope.js +6 -1
- package/dist/schemes/_path-scope.js.map +1 -1
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +14 -2
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/server/BranchBatches.d.ts +3 -3
- package/dist/server/BranchBatches.d.ts.map +1 -1
- package/dist/server/BranchBatches.js +9 -2
- package/dist/server/BranchBatches.js.map +1 -1
- package/dist/server/Daemon.d.ts +12 -41
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +60 -93
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DaemonModule.d.ts +10 -1
- package/dist/server/DaemonModule.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +6 -5
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +14 -11
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/Functionality.d.ts +2 -2
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +8 -5
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +13 -1
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +82 -17
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +56 -0
- package/dist/server/MembersFunctionality.d.ts.map +1 -0
- package/dist/server/MembersFunctionality.js +350 -0
- package/dist/server/MembersFunctionality.js.map +1 -0
- package/dist/server/SkillsFunctionality.d.ts +12 -1
- package/dist/server/SkillsFunctionality.d.ts.map +1 -1
- package/dist/server/SkillsFunctionality.js +6 -1
- package/dist/server/SkillsFunctionality.js.map +1 -1
- package/dist/server/client-input.d.ts +5 -8
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +49 -108
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +3 -0
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +4 -4
- package/dist/server/envelope.d.ts +1 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +11 -10
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +1 -1
- package/dist/server/lifecycle-recovery.sql +14 -20
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +12 -5
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/seam-proposal-list.sql +2 -2
- package/dist/server/worker-capabilities.sql +9 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +18 -23
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +477 -131
- package/package.json +31 -33
- package/dist/core/LoopFlagsReader.d.ts +0 -7
- package/dist/core/LoopFlagsReader.d.ts.map +0 -1
- package/dist/core/LoopFlagsReader.js +0 -33
- package/dist/core/LoopFlagsReader.js.map +0 -1
- package/dist/core/resolveForLoop.d.ts +0 -5
- package/dist/core/resolveForLoop.d.ts.map +0 -1
- package/dist/core/resolveForLoop.js +0 -12
- package/dist/core/resolveForLoop.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -50,7 +50,7 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
|
|
|
50
50
|
| `kind` | Required purpose: `inference`, `initialization`, `overflow`, `operation`, or `maintenance`. Model iff inference; initialization, overflow, and maintenance require `_plurnk`. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
|
|
51
51
|
| `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the exact terminal SEND/operation disposition and timestamp; a completed 102 is therefore distinct from an open 102. |
|
|
52
52
|
| 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. |
|
|
53
|
-
| `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one
|
|
53
|
+
| `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one actionless `/ops` log item under {§turn-ops-entry}. The item supplements rather than replaces the executed operation rows. |
|
|
54
54
|
| Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
|
|
55
55
|
|
|
56
56
|
One lifecycle owner opens, optionally records inference evidence, and completes
|
|
@@ -117,6 +117,25 @@ These are the complete strike sources:
|
|
|
117
117
|
executor error is not a PLURNK contract violation. Cycle and terminal steering
|
|
118
118
|
remain independent strike sources.
|
|
119
119
|
|
|
120
|
+
§provider-recovery **A recoverable provider failure never ends a loop.** When a model
|
|
121
|
+
call fails with a network failure, rate limit, deadline, or interrupted resource after
|
|
122
|
+
the provider's own retries, the turn records the exact Problem as a `_plurnk` row,
|
|
123
|
+
notices the client (`engine:provider` / `provider_unavailable`), waits with
|
|
124
|
+
exponential backoff (`PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF`, doubling, capped at
|
|
125
|
+
twelve times itself), and re-issues the same call against the exact frozen model
|
|
126
|
+
messages whose response is still outstanding. Each reissue remains a distinct logical
|
|
127
|
+
model call with complete physical-request accounting, but the active turn's newly
|
|
128
|
+
recorded provider Problems do not recursively enter that request; they surface normally
|
|
129
|
+
only in a later genuinely new packet. No emission attempt is consumed and no strike is
|
|
130
|
+
scored. Every recovery checkpoint broadcasts live, while the model-facing Notice buffer
|
|
131
|
+
retains only the current provider state; the next completed exchange notices
|
|
132
|
+
`provider_recovered`. Recovery is bounded by `PLURNK_SERVICE_PROVIDER_RECOVERY`; when it
|
|
133
|
+
is spent the turn completes as `202` and the loop parks exactly like a
|
|
134
|
+
`## SEND0 [202]` wait ({§worker-lifecycle-wake-requeue-not-terminal}), resuming on the
|
|
135
|
+
next prompt or wake with its log intact. Only a client cancel, the loop deadline
|
|
136
|
+
({§operator-config-loop-timeout}), or a non-recoverable provider Problem (refusal,
|
|
137
|
+
authorization, quota, an invalid response) settles a loop on a provider failure.
|
|
138
|
+
|
|
120
139
|
A struck turn increments the consecutive streak once; a clean admitted turn
|
|
121
140
|
resets it to zero. Reaching `MAX_STRIKES` terminates at **508 Loop Detected**
|
|
122
141
|
when the crossing turn is cycle-detected, otherwise **500**. Rejected emission
|
|
@@ -130,11 +149,11 @@ shown. The current streak may ride first-party provider metadata
|
|
|
130
149
|
|------------------------------|---|
|
|
131
150
|
| **verdict** | The end-of-turn ruling computed inline in `Engine.runLoop` from the strike rail and independent loop terminals. No filter chain. |
|
|
132
151
|
| **strike** | One admitted turn matching at least one source above. |
|
|
133
|
-
| **emission attempt** | One completed provider exchange beneath an engine turn. ANTLR admits it when
|
|
152
|
+
| **emission attempt** | One completed provider exchange beneath an engine turn. ANTLR admits it when at least one source operation has a trustworthy effective envelope and no boundary-destroying tail. A hard error inside that envelope becomes a failed operation in the admitted turn; a rejected attempt is forensic evidence, not another turn or an engine strike. |
|
|
134
153
|
| **BARE inference** | One body-only 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}). |
|
|
135
154
|
| **cycle** | A repeated turn fingerprint across consecutive turns. Detection strikes silently under the rule above. |
|
|
136
|
-
|
|
|
137
|
-
| **
|
|
155
|
+
| **capability policy** | A purely subtractive `only`/`deny` selector layer over routed operation demands. Service, workspace, inherited delegation bound, worker, and loop layers compose without granting authority. |
|
|
156
|
+
| **loop policy** | One immutable loop snapshot containing capability attenuation and the independent `review`, `accept`, or `reject` proposal disposition. |
|
|
138
157
|
| **proposal** | A deferred side-effecting action. State machine: `proposed → resolved` (accept), `→ failed` (reject), or `→ cancelled` (cancel). Its core-owned disposition says whether the client or loop owns resolution ({§proposal-disposition}). |
|
|
139
158
|
| **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}). |
|
|
140
159
|
|
|
@@ -282,18 +301,28 @@ an explicitly specified subpath, not in the frozen root barrel.
|
|
|
282
301
|
|
|
283
302
|
```mermaid
|
|
284
303
|
flowchart LR
|
|
285
|
-
|
|
304
|
+
LISTENER["Bind client listener<br/>unready: HTTP 503"] --> DB["Acquire daemon lock<br/>and admit SQLite schema"]
|
|
305
|
+
DB --> PROVIDER["Resolve and verify<br/>selected provider"]
|
|
286
306
|
PROVIDER --> DAEMON["Construct and start<br/>daemon composition"]
|
|
287
|
-
DAEMON --> CLIENT["
|
|
288
|
-
|
|
307
|
+
DAEMON --> CLIENT["Activate client transport"]
|
|
308
|
+
LISTENER -. failure .-> FAIL["Fail startup<br/>durable state untouched"]
|
|
309
|
+
DB -. failure .-> CLOSE_LISTENER["Close listener"] --> FAIL
|
|
289
310
|
PROVIDER -. failure .-> CLOSE["Close database<br/>and release lock"] --> FAIL
|
|
290
311
|
DAEMON -. failure .-> TEARDOWN["Close every started owner"] --> FAIL
|
|
291
312
|
```
|
|
292
313
|
|
|
293
|
-
§startup-admission
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
314
|
+
§startup-listener-admission The production service binds its sole client
|
|
315
|
+
listener before creating, opening, replacing, rotating, migrating, or otherwise
|
|
316
|
+
mutating anything in the durable data directory. A process that loses the
|
|
317
|
+
listener race fails with the originating address error and byte-identical
|
|
318
|
+
durable storage. The client-interface module owns the socket continuously; it
|
|
319
|
+
answers 503 until activated, so early ownership introduces neither traffic nor a
|
|
320
|
+
close/rebind race.
|
|
321
|
+
|
|
322
|
+
§startup-admission-order After listener ownership, database admission completes
|
|
323
|
+
before provider or capability initialization can perform external work. Every
|
|
324
|
+
later startup failure closes resources in reverse ownership order while
|
|
325
|
+
preserving the originating failure: daemon, observability, database, listener.
|
|
297
326
|
|
|
298
327
|
### §actor-boundary The actor boundary: isolation by worker, two doors, self-hosting
|
|
299
328
|
|
|
@@ -321,8 +350,8 @@ filter a row.
|
|
|
321
350
|
attached to.** A client connection is attached to one conversation Worker; its
|
|
322
351
|
management commands mutate that Worker's Functionality ({§module-worker-capabilities}),
|
|
323
352
|
and its operations execute in that Worker's environment — executable families,
|
|
324
|
-
runtime schemes,
|
|
325
|
-
|
|
353
|
+
runtime schemes, tools, and capability policy resolve through the attached
|
|
354
|
+
Worker — while the operation
|
|
326
355
|
journals in the client's own worker ({§connection-lifecycle}) and any entry it
|
|
327
356
|
writes binds its principal through that client worker. Every dispatch therefore
|
|
328
357
|
carries two coordinates: `workerId`, the journaling and entry principal, and
|
|
@@ -358,7 +387,7 @@ plus a broadcast duplicate. Ordinary project files, private worker entries,
|
|
|
358
387
|
and remote resources do not acquire ambient attention merely because they are
|
|
359
388
|
workspace-addressable.
|
|
360
389
|
|
|
361
|
-
§actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership}
|
|
390
|
+
§actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership} overlay, a workspace policy, bounds every worker's visible surface uniformly — {§machine-processes}); stale writes reject at their anchor or compare-and-swap boundary rather than being prevented by a lock ({§line-anchors}, {§membership-edit-write-cas}). A branch-tagged WORK/FORK opts the whole workspace into the bounded, exclusive Git transaction in {§worker-branch-batch}. It is not a general entry mutex or a hidden per-worker filesystem.
|
|
362
391
|
|
|
363
392
|
§actor-boundary-passive-wake **Passive wake follows ownership.** A directed
|
|
364
393
|
voice wakes an idle worker. A parked continuation resumes when an obligation it
|
|
@@ -384,8 +413,8 @@ lineage activity and explicit commons mutations cross the environment door.
|
|
|
384
413
|
| Search derivation and catalog render | Kernel. | They are indexes and read-only projections, not entry operations. |
|
|
385
414
|
| Packet assembly and budget rails | Kernel. | They are the execution substrate on which actor operations depend. |
|
|
386
415
|
|
|
387
|
-
Git membership
|
|
388
|
-
|
|
416
|
+
Git membership is the repository's tracked files and nothing else ({§membership-baseline});
|
|
417
|
+
Plurnk never stages a file or runs `git add`.
|
|
389
418
|
|
|
390
419
|
§turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
|
|
391
420
|
`<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the current worker's private
|
|
@@ -404,14 +433,22 @@ neither a hidden database write nor a kernel-owned mirror.
|
|
|
404
433
|
|
|
405
434
|
§actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS`
|
|
406
435
|
foists turn-0 discovery into the worker's first turn, so a worker opens with a
|
|
407
|
-
navigable map instead of blank. An enabled preview executes exactly
|
|
408
|
-
bodyless FIND surveys in order:
|
|
409
|
-
(worker://~/_plurnk/skills/*.md) <1,-1>`),
|
|
410
|
-
(`## FIND0 [+init,+
|
|
411
|
-
|
|
412
|
-
enabled
|
|
413
|
-
<1,-1>`, {§a2a-agents-catalog}),
|
|
414
|
-
(
|
|
436
|
+
navigable map instead of blank. An enabled preview executes exactly eight baseline
|
|
437
|
+
bodyless FIND surveys in order: Agent Skills (`## FIND0
|
|
438
|
+
[+init,+skills] (worker://~/_plurnk/skills/*.md) <1,-1>`), plurnk references — the
|
|
439
|
+
executors, schemes, and family managers (`## FIND0 [+init,+plurnk]
|
|
440
|
+
(worker://~/_plurnk/plurnk/*.md) <1,-1>`), enabled tools (`## FIND0 [+init,+tools]
|
|
441
|
+
(worker://~/_plurnk/tools/*.md) <1,-1>`), enabled agents (`## FIND0 [+init,+agents]
|
|
442
|
+
(worker://~/_plurnk/agents/*.md) <1,-1>`, {§a2a-agents-catalog}), enabled members
|
|
443
|
+
(`## FIND0 [+init,+members] (worker://~/_plurnk/members/*.md) <1,-1>`,
|
|
444
|
+
{§members-projection}), workspace files (`## FIND0 [+init] (*) <!-- workspace files -->`),
|
|
445
|
+
workspace entries (`## FIND0 [+init] (worker:///*) <!-- workspace entries -->`), and
|
|
446
|
+
private worker entries (`## FIND0 [+init] (worker://~/*) <!-- private worker entries -->`).
|
|
447
|
+
Only those three namespace surveys carry annotations because the bare targets do not
|
|
448
|
+
name their surface; generated paths and classification tags already name every other
|
|
449
|
+
survey. Naming `~` private prevents a worker from offering its own `~` address to
|
|
450
|
+
another worker.
|
|
451
|
+
The word `skills` names Agent Skills and nothing else.
|
|
415
452
|
The catalogs select every direct document independently of its authored body;
|
|
416
453
|
ordinary READ supplies its examples and complete instructions on demand. Their
|
|
417
454
|
log classifications make the opening discovery one `init` set while retaining
|
|
@@ -430,7 +467,7 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
|
|
|
430
467
|
unset / `0` disables previews. `log://` is absent because the current worker's
|
|
431
468
|
log already renders in present mode.
|
|
432
469
|
|
|
433
|
-
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, one archiving COPY, orienting READ/FIND, and terminal `SEND0 [102]` rows (authored in their {§op-mode-phases} execution order). Every orienting row is structurally classified `_plurnk` and `init`; the archiving `COPY (prompt:///<loop>/1)` onto `worker://~/prompts.md <-1>` is classified `_plurnk` and `backup` — the worked COPY specimen, showing the private space as scratch, emitted whenever the loop publishes a prompt ({§prompt-entry}). The PLAN is the canonical {§plan-value} with
|
|
470
|
+
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, one archiving COPY, orienting READ/FIND, and terminal `SEND0 [102]` rows (authored in their {§op-mode-phases} execution order). Every orienting row is structurally classified `_plurnk` and `init`; the archiving `COPY (prompt:///<loop>/1)` onto `worker://~/prompts.md <-1>` is classified `_plurnk` and `backup` — the worked COPY specimen, showing the private space as scratch, emitted whenever the loop publishes a prompt ({§prompt-entry}). The PLAN is the canonical {§plan-value} with two entries in order: `Persist Determinations and Decisions` is `memory`, then `Discover the tooling available and survey the workspace file root.` is `in_progress`; SEND hands off with `Next: Address the prompt.` The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate. Client and `_plurnk` administrative workers execute operation turns and do not receive model initialization.
|
|
434
471
|
|
|
435
472
|
### §machine-processes The machine and its processes: workspace, worker, fork
|
|
436
473
|
|
|
@@ -466,8 +503,8 @@ terminal history.**
|
|
|
466
503
|
| Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
|
|
467
504
|
| Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
|
|
468
505
|
| Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
|
|
469
|
-
| Log items ({§machine-processes-fork-copies-the-log}) | Worker |
|
|
470
|
-
| §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but
|
|
506
|
+
| Log items ({§machine-processes-fork-copies-the-log}) | Worker | Durable events, curation effects, tags, current active/folded projection, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
|
|
507
|
+
| §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but turn-attached inference calls, their specializations, admission rows, and physical provider requests are not: one issued call or request has one causal branch. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
|
|
471
508
|
| §machine-processes-entry-inheritance **Worker-owned entries** | Worker | The scheme's mandatory `{§manifest-entry-inheritance}` decides: `snapshot` copies only entries whose channels are all quiescent and remaps ownership; `rederive` copies no bytes and lets the child materializer rebuild them from inherited Functionality; `none` carries nothing. Within a `snapshot` scheme the Worker scheme's generated subtree is always rederived ({§worker-generated-subtree}). Parent and child then diverge. |
|
|
472
509
|
| Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
|
|
473
510
|
|
|
@@ -529,7 +566,7 @@ continues to decompose other authorities without treating them as mintable.
|
|
|
529
566
|
| Any other spelling | Refused as `name-invalid` before lookup, insertion, or child startup. |
|
|
530
567
|
| Automatic name | Generated, then admitted through the same predicate. |
|
|
531
568
|
|
|
532
|
-
§worker-read-scope **Named spaces are
|
|
569
|
+
§worker-read-scope **Named spaces are workspace-wide reads**: any worker of the workspace reads `worker://<name>/…` for any other — a parent its child's `result`, a child its parent's, a sibling its sister's. The parent designs the topology by what it names to whom; the engine imposes none (operator ruling 2026-08-26, #394). An unknown name resolves 404. Reserved runtime workers obey the same rule; there is no unnamed world-readable space, and writability is untouched ({§worker-write-scoping}).
|
|
533
570
|
|
|
534
571
|
§worker-write-scoping **Writes are own-space-and-commons only**: a model writes `worker://~/` and `worker:///` — every ancestry-readable named authority is read-only to it (403), while an unreadable name remains 404 under {§worker-read-scope}. `owner_id` is engine-stamped from the dispatch context, never model-set. Nothing worker-authored can land under another principal. The entry-copy seam (COPY/MOVE) is pathname-keyed and addresses the commons; a space's content moves via READ + EDIT. The one exception inside a writable space is the generated subtree below.
|
|
535
572
|
|
|
@@ -579,7 +616,7 @@ literal `workers.name` value.
|
|
|
579
616
|
remapped (source → branch) — so the branch opens with the parent's notes and
|
|
580
617
|
diverges on its own edits: *fork = everything-in-common-but-name*.
|
|
581
618
|
- **Git branch batch** — `## WORK0 [feature/x] (worker://<name>)` and `## FORK0 [feature/x] (worker://<name>)`, each with a task body, retain their worker meanings while placing the child in the serialized Git transaction defined by {§worker-branch-batch}. The signal is one branch ref, not tags; an untagged WORK/FORK keeps the ordinary concurrent shared-world behavior.
|
|
582
|
-
- §worker-delegation-inherits-
|
|
619
|
+
- §worker-delegation-inherits-policy **Delegation cannot widen authority.** WORK and FORK copy the delegating actor's complete effective capability policy into the child's immutable `capability_bound`; later widening of any parent layer cannot enlarge that child. Every fresh delegated loop carries that complete effective attenuation and the delegating loop's proposal disposition, including a loop created by SEND to an idle Worker. SEND into an active or parked loop leaves that loop's immutable policy untouched. The bound is delegation authority captured by value, not a client binding or a live parent-policy link.
|
|
583
620
|
- §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.
|
|
584
621
|
|
|
585
622
|
Untagged worker control rides the daemon's inject seam (active→fold, idle→enqueue+drain), so the handler creates/branches the worker and hands off; the daemon owns provider + system prompt. Tagged WORK/FORK instead enqueue a fresh loop without starting its drain; {§worker-branch-batch} becomes its sole starter. FORK/WORK carry the seed task in the body and are their own ops, dispatched to worker control — never the entry-copy path.
|
|
@@ -589,6 +626,15 @@ Untagged worker control rides the daemon's inject seam (active→fold, idle→en
|
|
|
589
626
|
Branch-tagged WORK/FORK serializes ordinary Git branches over the one project
|
|
590
627
|
checkout. It creates no worktrees, alternate roots, hidden merges, or stashes.
|
|
591
628
|
|
|
629
|
+
§branch-delegation-disabled **Off the surface until specified (#396).** The form is
|
|
630
|
+
not offered to the model: the teaching carries no `[branch]` slot, and unless the
|
|
631
|
+
operator sets `PLURNK_SERVICE_BRANCH_DELEGATION=1` a WORK/FORK signal is refused up
|
|
632
|
+
front as `501 branch-delegation-disabled`, naming the signal-less form. Twelve
|
|
633
|
+
branch delegations across the benchmarks produced no organic success; the
|
|
634
|
+
preconditions below are invisible to the model until the refusal, and any label on
|
|
635
|
+
WORK/FORK reads as a branch order. The batches below remain the implementation behind
|
|
636
|
+
that knob and keep their witnesses.
|
|
637
|
+
|
|
592
638
|
§worker-branch-batch-exclusive **Stop the workspace; serialize
|
|
593
639
|
ordinary branches.** A branch signal on WORK/FORK creates a durable batch keyed
|
|
594
640
|
to the parent turn. The batch queues one exclusive workspace gate before that
|
|
@@ -647,8 +693,9 @@ The remaining worker surfaces are:
|
|
|
647
693
|
**2xx deliverable is born OPEN** (its body
|
|
648
694
|
materialized into the parent's packet, not hidden behind a fold): a child's
|
|
649
695
|
success must reach the parent open and awakening, never a bodyless row. An
|
|
650
|
-
non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly
|
|
651
|
-
|
|
696
|
+
non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly —
|
|
697
|
+
including a spawn that dies before its first turn, such as a branch batch refused at
|
|
698
|
+
git-preflight — so no child termination is silent to its owner; collection is lineage
|
|
652
699
|
supervision, never a
|
|
653
700
|
verb. The **pull** side mirrors the push: a path-absent
|
|
654
701
|
`## READ0 (worker://<name>)` collects that same result on demand for a
|
|
@@ -816,7 +863,7 @@ boundary.
|
|
|
816
863
|
- §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a SEND signal `202` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does signal `202` resolve like signal `200`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
|
|
817
864
|
- §worker-lifecycle-no-lost-loop **A loop is never stranded by a drain's exit.** A drain relinquishes its registry slot only after a lock-held re-claim confirms the queue is empty; a loop enqueued during that teardown is either re-claimed by the exiting drain or claimed by a fresh drain that a later inject starts. The relinquish and the start are serialized, so neither the lost-loop hang nor a transient double-drain can occur.
|
|
818
865
|
- §worker-lifecycle-durable-disposition **Durable disposition wins cancellation races.** At a turn boundary, the engine reads the loop's durable status before interpreting a process-local abort. A committed `202` park survives a later daemon-shutdown signal; only a loop still durably running at `102` can be terminalized by that cancellation.
|
|
819
|
-
- §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request
|
|
866
|
+
- §worker-lifecycle-restart-recovery **Restart is owner-loss reconciliation, not replay.** Before opening client transports, the service holds an exclusive database-adjacent daemon lock; a second live owner fails before touching SQLite, while a dead-PID crash claim is replaced atomically without a timeout lease. Boot preserves accepted `100` loops and restores their drains. A `102` loop belonged to a vanished drain/provider call, so it settles `500` with the interruption on its durable row—never replayed across an unknown effect boundary. Every pending physical provider request first settles as an error with absent usage and explicitly unknown cost; then its logical generation or embedding call closes, including a workspace-only embedding with no turn to invent. Recovery never fabricates zero evidence. Every durable proposed operation likewise lost its process-local resolution waiter and settles as a visible `500 owner_vanished` occurrence rather than an unresolvable interrupt ({§proposal-list}). A pending client interaction also lost its exact awaiting operation, so boot removes the orphan instead of replaying work or inventing a response ({§client-interactions}). Every durable-open subscription belonged to a vanished callable: active channels become errored and its row closes `500`. A `202` continuation survives only while a live child obligation remains; after reconciliation, an unblocked park requeues `202→100` and resumes in place. Child terminalization wakes its parked parent on every outcome, including provider exceptions, cancellation, and restart interruption, recursively through the durable parent edges. These operations are idempotent, so an interrupted recovery safely repeats.
|
|
820
867
|
|
|
821
868
|
---
|
|
822
869
|
|
|
@@ -834,6 +881,24 @@ Three current entry points:
|
|
|
834
881
|
|
|
835
882
|
§provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF admission also consumes `constrainsOutput` ({§grammar-configuration-admission}).
|
|
836
883
|
|
|
884
|
+
§inference-ledger **Logical inference is provider-neutral and physical requests
|
|
885
|
+
have one ledger.** Every inference opens one `inference_calls` identity with a
|
|
886
|
+
mandatory workspace, optional real causal turn, ordered kind, request model,
|
|
887
|
+
and forward-only lifecycle. Its specialization owns only domain evidence:
|
|
888
|
+
|
|
889
|
+
| Kind | Specialization | Causal scope |
|
|
890
|
+
|---|---|---|
|
|
891
|
+
| `emission`, `bare` | `model_calls`: normalized response/failure and capacity | A model/inference turn is required; only emission has `turn_attempts` admission evidence. |
|
|
892
|
+
| `embedding_query`, `embedding_documents` | `embedding_calls`: input/output cardinality, artifact metadata, or failure | Workspace is required; a turn is attached only when the operation has one. |
|
|
893
|
+
|
|
894
|
+
Every physical request is an ordered `provider_requests` child opened before
|
|
895
|
+
I/O and settled once. Hosted generation and embeddings use that same observer;
|
|
896
|
+
local embeddings retain their logical call and create no fictitious physical
|
|
897
|
+
request. Turn-attached embeddings contribute to turn, loop, worker, and
|
|
898
|
+
workspace accounting; workspace-only embeddings contribute only to workspace
|
|
899
|
+
accounting. Neither is packet occupancy, so only an emission may supply the
|
|
900
|
+
latest context gauge.
|
|
901
|
+
|
|
837
902
|
§meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
|
|
838
903
|
|
|
839
904
|
### §provider-guarantees Engine → provider guarantees
|
|
@@ -848,22 +913,29 @@ Three current entry points:
|
|
|
848
913
|
|
|
849
914
|
### §emission-admission Provider emission admission
|
|
850
915
|
|
|
851
|
-
A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission
|
|
916
|
+
A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission requires at least one parsed source operation, no `unparsedTail`, and a trustworthy effective envelope. Canonical source begins with PLAN and ends with a terminal SEND. If no valid leading PLAN or terminal SEND was parsed, the parser supplies an empty PLAN or bodyless `SEND [102]`, records its exact hard diagnostic, and Core admits the useful operations instead of resampling. Both diagnostics participate in one ordinary struck turn, never one strike apiece. An authored PLAN or terminal SEND remains a real boundary, so an error outside either authored edge, post-terminal content, a boundary-destroying tail, or no source operation rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}). The accepted packet retains the provider's source bytes exactly in response evidence and `turnOps`; synthetic envelope statements exist only in the normalized operation program and its durable rows.
|
|
852
917
|
|
|
853
|
-
§safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, or
|
|
918
|
+
§safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, OPEN, or KILL only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order; scheduling may still move the complete operation class under {§op-mode-phases}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
|
|
854
919
|
|
|
855
|
-
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 `
|
|
920
|
+
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 `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
|
|
856
921
|
|
|
857
|
-
The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `
|
|
922
|
+
The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice: `Response rejected before dispatch; no operations were performed.` followed by `Parser: <the latest attempt's first diagnostic>` with its `content-offset` position — the model sees why, at which line, against its own projected text. The Notice states only observed admission facts; it does not classify the response as unrecoverable, infer why generation ended, or prescribe intent beyond the parser-owned diagnostic. Attempt count and rail state never become model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
|
|
858
923
|
|
|
859
|
-
An admitted
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
924
|
+
An admitted program may contain bounded malformed statements or recovered
|
|
925
|
+
envelope defaults. Parsed operations still dispatch; each hard parser diagnostic
|
|
926
|
+
becomes one durable model-origin `error` row with the parser's exact detail under
|
|
927
|
+
{§parse-diagnostics} and status 400. These failures are committed before the
|
|
928
|
+
terminal disposition, participate in the ordinary strike rail, and prevent SEND
|
|
929
|
+
signal `200` or an already-drained signal `202` from concluding before the model
|
|
930
|
+
sees them in the next packet. This is operation recovery, not provider
|
|
931
|
+
resampling. A malformed statement's Problem records the factual
|
|
932
|
+
`siblingsRetained: true` extension; an envelope-default Problem states only the
|
|
933
|
+
observed boundary failure and exact default applied.
|
|
863
934
|
|
|
864
935
|
§invalid-emission-attempts Exhausting the emission-attempt budget opens the
|
|
865
936
|
single informed recovery turn above. Consecutive exhaustion of that turn
|
|
866
|
-
terminates the loop at 500 without spending an engine strike
|
|
937
|
+
terminates the loop at 500 without spending an engine strike, with detail `No
|
|
938
|
+
Plurnk turn was admitted after <N> emission attempts.`
|
|
867
939
|
|
|
868
940
|
§turn-never-blank An admitted turn whose operation fails — during parsing or
|
|
869
941
|
dispatch — is categorically different: its failed operation row enters
|
|
@@ -889,7 +961,7 @@ shared contract {§plugin-attribution}:
|
|
|
889
961
|
| 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 plugin capability. |
|
|
890
962
|
| Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
|
|
891
963
|
| Meaning | Core neither verifies nor infers contribution. Tags are plugin-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§plugin-attribution}). |
|
|
892
|
-
| Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every
|
|
964
|
+
| 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. |
|
|
893
965
|
| 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. |
|
|
894
966
|
|
|
895
967
|
Runtime hooks are synchronous and receive only the attempt coordinates. A hook
|
|
@@ -998,7 +1070,7 @@ meaning of an authored URI authority before any entry capability is exposed:
|
|
|
998
1070
|
host, non-default port, path, and serialized query are identity; query order,
|
|
999
1071
|
duplicates, and an explicit empty `?` survive. A fragment is a Plurnk channel
|
|
1000
1072
|
selector, not network identity or transport. URL userinfo is rejected and
|
|
1001
|
-
|
|
1073
|
+
scheme metadata never enters identity. Plain `http` routes through `https`,
|
|
1002
1074
|
just as `ws` routes through `wss`; those implementation aliases never alias
|
|
1003
1075
|
resources, and the secure face is the one taught — `http` stays supported
|
|
1004
1076
|
for the endpoint that requires it, never advertised as a peer. `SchemeCtx.entries` binds every cap to the addressed protocol.
|
|
@@ -1045,43 +1117,43 @@ render-time filtering.
|
|
|
1045
1117
|
|
|
1046
1118
|
§fs-canonical-name **One canonical name, storage ≡ wire: the git pathspec.** Member keys follow gitformat-index(5) verbatim (reference edition: git 2.47.3): relative to the workspace `project_root`, without leading slash, `/`-separated, no trailing slash or NUL. Directories are never entries and the root needs no name. When `project_root` is below the containing repository's top level, Git members above it naturally use the same `../`-prefixed CWD-relative names that `git ls-files` emits without `--full-name`; these are not outside-repository mounts. The database stores that root-relative key directly because workspace identity is rooted at the access point. Every model spelling canonicalizes before storage or comparison.
|
|
1047
1119
|
|
|
1048
|
-
§fs-visibility-grantors **File visibility has two represented grantors; Plurnk never invents a private third one.** A file member is admitted by the active Git substrate or by an ordinary `
|
|
1120
|
+
§fs-visibility-grantors **File visibility has two represented grantors; Plurnk never invents a private third one.** A file member is admitted by the active Git substrate or by an ordinary `include` row of the overlay. An `include` is either a projected `members` definition ({§members-projection}) or the exact, inspectable record of an accepted creation ({§fs-create-record}); both resolve to `constraint` membership. AGENTS.md remains auto-pulled as POLICY ({§policy-sections}), deliberately not a file member. A physically existing path that neither Git nor an `include` admits does not exist for the model and cannot be overwritten.
|
|
1049
1121
|
|
|
1050
|
-
§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, plugin, or `_plurnk`. A COPY or MOVE destination region on an absent entry
|
|
1122
|
+
§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, plugin, or `_plurnk`. A COPY or MOVE destination region on an absent entry creates the entry when it is `<-1>`, the whole-source form `<1,-1>`, or a whole-line range from line 1 whose final line exactly equals the selected source's resulting line count. These scopes all describe the complete new value; any other region on an absent entry is `destination-region-not-found`.
|
|
1051
1123
|
|
|
1052
1124
|
| Case | Required admission | Accepted result |
|
|
1053
1125
|
|------|--------------------|-----------------|
|
|
1054
1126
|
| §fs-create-disabled Absent path, effective scope `none` | None | Refuse without touching disk. |
|
|
1055
|
-
| §fs-create-root Absent path inside `project_root` | Effective scope `root` or `namespace`; no matching
|
|
1056
|
-
| §fs-create-namespace Absent canonical `../` path | Effective scope `namespace`; no matching
|
|
1057
|
-
| §fs-create-ignored Absent path ignored by active Git | Matching
|
|
1058
|
-
| §fs-create-git Absent in-root path admitted by active Git | Not ignored | Exclusive CREATE followed by
|
|
1059
|
-
| §fs-create-
|
|
1060
|
-
| §fs-write-member Existing in-root member | Git or
|
|
1061
|
-
| §fs-write-outside Existing canonical `../` member |
|
|
1127
|
+
| §fs-create-root Absent path inside `project_root` | Effective scope `root` or `namespace`; no matching exclusion | Exclusive CREATE (`open(O_CREAT\|O_EXCL)` semantics), then incorporation below. |
|
|
1128
|
+
| §fs-create-namespace Absent canonical `../` path | Effective scope `namespace`; no matching exclusion | Exclusive CREATE, then an exact creation record so the outside member is read-write. |
|
|
1129
|
+
| §fs-create-ignored Absent path ignored by active Git | Matching `members` definition | Exclusive CREATE through that definition; a creation record or model definition never overrides Git ignore. |
|
|
1130
|
+
| §fs-create-git Absent in-root path admitted by active Git | Not ignored | Exclusive CREATE followed by an exact creation record (`source: "create"`); never `git add` ({§membership-baseline}). |
|
|
1131
|
+
| §fs-create-definition Absent admitted path without Git incorporation | A projected `members` definition or automatic incorporation permitted | Exclusive CREATE followed by an exact creation record when no `members` definition already covers it. |
|
|
1132
|
+
| §fs-write-member Existing in-root member | Git or include membership | Proposal-gated EDIT. |
|
|
1133
|
+
| §fs-write-outside Existing canonical `../` member | Include membership | Proposal-gated EDIT. Git-only outside members are read-only. |
|
|
1062
1134
|
| §fs-write-nonmember Existing non-member | None | Refuse; reveal occupancy only, never content. |
|
|
1063
1135
|
|
|
1064
|
-
§fs-create-incorporation **Creation incorporation is durable workspace state, not a transient entry exception.** `workspace_constraints.source` distinguishes
|
|
1136
|
+
§fs-create-incorporation **Creation incorporation is durable workspace state, not a transient entry exception.** `workspace_constraints.source` distinguishes the engine's `create` record of a file Plurnk wrote from the `members` family's projected rows (`members`: human-authored, `model`: model-proposed — {§members-projection}). A projected row interprets `glob` as a pattern; a creation record is one exact canonical path, never reinterpreted as a pattern, and the family's projection never overwrites or retires it.
|
|
1065
1137
|
|
|
1066
|
-
| Event |
|
|
1138
|
+
| Event | Creation-record lifecycle |
|
|
1067
1139
|
|-------|--------------------------|
|
|
1068
|
-
| §fs-create-
|
|
1140
|
+
| §fs-create-record Successful creation not covered by a projected `members` definition | Insert exact `{ effect: "include", glob: canonicalPath, source: "create" }`. |
|
|
1069
1141
|
| §fs-create-copy COPY to a new path | Incorporate the destination independently; the source is unchanged. |
|
|
1070
|
-
| §fs-create-move MOVE to a new path | Incorporate the destination, then remove the source's
|
|
1071
|
-
| §fs-create-kill KILL or accepted whole-resource deletion | Remove the deleted path's
|
|
1072
|
-
| §fs-create-
|
|
1073
|
-
| §fs-create-masked A later
|
|
1074
|
-
| §fs-create-ambient-delete Reconciliation confirms a
|
|
1142
|
+
| §fs-create-move MOVE to a new path | Incorporate the destination, then remove the source's creation record after deleting the source. |
|
|
1143
|
+
| §fs-create-kill KILL or accepted whole-resource deletion | Remove the deleted path's creation record. |
|
|
1144
|
+
| §fs-create-definition-overlap A `members` definition projected at the same exact path | The creation record stays as it is; the definition keeps admitting the path after the record is retired. |
|
|
1145
|
+
| §fs-create-masked A later exclusion or active Git-ignore rule excludes a created member | Preserve the creation record as dormant provenance; removing the exclusion restores membership when the file still exists. |
|
|
1146
|
+
| §fs-create-ambient-delete Reconciliation confirms a created path disappeared outside Plurnk | Remove the creation record; projected definitions are untouched. |
|
|
1075
1147
|
|
|
1076
1148
|
The file-creation invariants are deliberately redundant with the matrices only
|
|
1077
1149
|
where the invariant closes an architectural failure mode:
|
|
1078
1150
|
|
|
1079
|
-
- §file-create-no-orphans A successful create always ends in
|
|
1151
|
+
- §file-create-no-orphans A successful create always ends in a projected definition or a creation record; no accepted file is orphaned from the workspace that created it.
|
|
1080
1152
|
- §file-create-no-clobber Creation is exclusive and an existing non-member remains unreadable and non-overwritable.
|
|
1081
|
-
- §file-create-exclusions-win
|
|
1153
|
+
- §file-create-exclusions-win An exclusion outranks all automatic creation; active Git ignore is overridden only by a `members` definition.
|
|
1082
1154
|
- §file-create-scope The effective creation scope is the minimum of the service ceiling and workspace setting; no call site or producer may widen it.
|
|
1083
1155
|
- §file-create-producer-neutral The file contract depends on the operation and target, never the producer identity.
|
|
1084
|
-
- §file-create-single-owner File membership owns prospective admission, incorporation choice, and
|
|
1156
|
+
- §file-create-single-owner File membership owns prospective admission, incorporation choice, and creation-record lifecycle; file operations consume that decision rather than re-deriving Git and constraint policy.
|
|
1085
1157
|
- §file-create-transaction Success requires both exclusive disk creation and durable incorporation. Approval re-resolves physical containment and policy, so a proposal-time parent cannot be swapped for an outside-pointing symlink. Incorporation failure removes the created entry and file; incomplete rollback is an explicit partial-failure Problem.
|
|
1086
1158
|
|
|
1087
1159
|
Refusing an occupied non-member follows the POSIX exclusive-create precedent:
|
|
@@ -1139,7 +1211,9 @@ Registration precedes loop affinity:
|
|
|
1139
1211
|
|
|
1140
1212
|
- §op-synchronous **Decisive operations settle before the next scheduled operation.** The dispatcher `await`s every decisive operation. Work remains in flight only when the operation's contract deliberately creates concurrency: `FORK`, `WORK`, stream-producing `EXEC`, and a streaming `READ` after its scheme-specific acquisition boundary. Such a READ first establishes its durable subscription, returns `102`, and then retains only its `StreamSubscription`; a later scheduled operation may address that live owner. MODE changes scheduling, not completion semantics. This is why a same-turn KILL followed by SEND signal `200` concludes ({§send-premature-terminate}): KILL synchronously flips the worker's live loops terminal (`engine_terminate_worker_live_loops`) before the End phase judges the pending set, while the physical scope reap rides `cancelWorker` asynchronously and invisibly.
|
|
1141
1213
|
|
|
1142
|
-
- §edit-batch **Same-resource EDITs are one mutation.** Every EDIT targeting the same canonical resource and channel in one turn applies to the resource's one pre-turn snapshot. The scheme validates the complete batch before writing, applies disjoint replacements from the highest original coordinate downward, and commits one resulting revision atomically; reversing the statements cannot change that revision. A failing statement rejects that resource batch without a partial write; independent resource batches remain independent. Whole-resource replacement or creation cannot coexist with another EDIT in the same batch, selected regions may not overlap, and a zero-length insertion may occur at most once at each boundary. Prepend (`<0>`), append (`<-1>`), and exact equal-endpoint insertions compose with non-overlapping replacements. Proposal-gated schemes expose one proposal for the resource batch and accept all or none. The public scheme contract is batch-shaped: a scheme must never emulate this guarantee by applying individual EDITs sequentially.
|
|
1214
|
+
- §edit-batch **Same-resource EDITs are one mutation.** Every EDIT targeting the same canonical resource and channel in one turn applies to the resource's one pre-turn snapshot. The scheme validates the complete batch before writing, applies disjoint replacements from the highest original coordinate downward, and commits one resulting revision atomically; reversing the statements cannot change that revision. A failing statement rejects that resource batch without a partial write; independent resource batches remain independent. When validation identifies one malformed statement, that row receives its exact 4xx Problem while every otherwise-valid sibling receives 424 Failed Dependency without borrowing the malformed statement's coordinates. Whole-resource replacement or creation cannot coexist with another EDIT in the same batch, selected regions may not overlap, and a zero-length insertion may occur at most once at each boundary. Prepend (`<0>`), append (`<-1>`), and exact equal-endpoint insertions compose with non-overlapping replacements. Proposal-gated schemes expose one proposal for the resource batch and accept all or none. The public scheme contract is batch-shaped: a scheme must never emulate this guarantee by applying individual EDITs sequentially.
|
|
1215
|
+
- §edit-batch-receipt **A refused batch names everything wrong with it.** Validation of a resource batch resolves every line anchor and checks every region pair before any verdict, so one receipt carries the complete correction. A `line-anchor-collision` lists every anchor that no longer resolves in `staleAnchors` (anchor, kind, and the matching lines when ambiguous). An `overlapping-edits` refusal lists every conflicting pair with its relation (same insertion point, duplicate, one contains the other, overlap) in `conflicts`, the regions that conflict with nothing in `cleanRegions`, and keeps the first pair in `conflictingRegions`. Both carry `editCount` and `applied: 0`, and their recovery prose states those counts, so the model never learns a batch's defects one resubmission at a time and never has to guess whether anything was written. Every row of the refused batch carries the same receipt.
|
|
1216
|
+
- §edit-batch-merges **Four resolutions are certain enough to apply; everything else stays a refusal, and every resolution is reported on its row.** Before the conflict check, core and the Slicer resolve exactly these shapes: (1) an identical twin (same region, same body up to trailing whitespace and trailing newlines — `whitespaceOnly: true` when they differed that way) is applied once and the twin's row carries `merged: {rule: "duplicate-of", of}` with no effect of its own; (2) two insertions at one point land in authored order (`same-insertion-point`); (3) two whole-line regions meeting on exactly one shared line, where that line's text appears verbatim in exactly one of the two bodies, give the line to that body and shrink the other by one (`shared-endpoint`, with the line, its text, the authored and applied coordinates, and `claimedBy`) — the inclusive `<SL,EL>` read as half-open, the commonest overlap on the 2026-08-29 runs; (4) a body whose every non-empty line carries this resource's own rendered `@xxxxx L:` prefix, hash-verified at its ordinal against the current anchors, is the READ rendering pasted back: the prefixes are stripped (`rendered-prefix-stripped`), and a look-alike that does not verify is written as authored with `rendered-prefix-unverified` reported — the hash is the proof, so intentional text of that shape is never altered. (5) one region inside another resolves when the inner region's original lines occur exactly once in the outer body: the inner change is relocated there (`contained-relocated`, with the outer index, the line within the outer body, and the authored coordinates); (6) an outer body that already carries the inner body makes the inner redundant (`contained-already-applied`). A shared endpoint that no body reproduces, and a containment whose inner lines occur zero or several times in the outer body, remain 409 with the line (and its text) or the containing region named. Each applied resolution is also a notice. Receipts are built from the edits as applied; a dropped twin's row carries its merge fact instead of an effect.
|
|
1143
1217
|
|
|
1144
1218
|
### §orchestration Cross-scheme orchestration
|
|
1145
1219
|
|
|
@@ -1174,7 +1248,7 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
|
|
|
1174
1248
|
- `## SEND0 [200] (path)` — write body into resource (WS message, exec stdin).
|
|
1175
1249
|
- `## SEND0 [499] (path)` — cancel active subscription ({§stream}).
|
|
1176
1250
|
|
|
1177
|
-
- §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (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`; `~semantic` and
|
|
1251
|
+
- §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (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`; `~semantic` 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}). A FIND signal classifies the FIND result row and never changes this candidate set ({§log-item-tags}). 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 a plugin seam and grants no protocol scheme an alternate READ path.
|
|
1178
1252
|
- §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.
|
|
1179
1253
|
- §channel-selection-visibility **Channel selection is decision-time information, not a guess** — every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, mimetype, tokens, and lines (default channel first), and matcher locations name the channel their line coordinates address. The packet never presents channels as equal and indistinguishable; extents derive from the stored channels by construction. Budget enforcement stays with {§overflow-turn} — this is information, not a second guard.
|
|
1180
1254
|
|
|
@@ -1217,7 +1291,7 @@ Engine → scheme guarantees:
|
|
|
1217
1291
|
- `ctx` is fresh per call. No mutation across calls.
|
|
1218
1292
|
- §universal-read-composition **Exact READ has one composition.** Core resolves
|
|
1219
1293
|
canonical identity and owner once, gives a data scheme its optional
|
|
1220
|
-
`prepareRepresentation({ target, authority, pathname })` opportunity, reads the complete
|
|
1294
|
+
`prepareRepresentation({ target, metadata, authority, pathname })` opportunity, reads the complete
|
|
1221
1295
|
canonical channels, selects the authored channel, applies binary and
|
|
1222
1296
|
text-coordinate rules, and finally composes that channel's durable producer
|
|
1223
1297
|
result. Preparation receives neither fragment nor `lineMarker`; finite work
|
|
@@ -1272,7 +1346,7 @@ consume these public methods:
|
|
|
1272
1346
|
| `detect`, `process` | Resolve mimetypes, extents, readable content, symbols, and references. |
|
|
1273
1347
|
| `projectionIdentity` | Identify installed reader behavior for derived entries and search artifacts that consume symbols and references. |
|
|
1274
1348
|
| `query` | Execute glob/regex/JSONPath/XPath through `@plurnk/plurnk-schemes/Matcher`, which maps typed outcomes to operation results. |
|
|
1275
|
-
| `embedderInfo`, `
|
|
1349
|
+
| `embedderInfo`, `embedDocuments`, `tokenizer` | Plan and derive semantic-search chunks without reaching into artifact packages. |
|
|
1276
1350
|
|
|
1277
1351
|
`@plurnk/plurnk-contracts` owns model-facing matcher syntax; parsed content
|
|
1278
1352
|
dialects pass to `Mimetypes.query` without reclassification. Mimetype handlers
|
|
@@ -1323,12 +1397,11 @@ internal contract failure, never a reason to substitute the pure heuristic.
|
|
|
1323
1397
|
| READ/EDIT and COPY/MOVE scope | Admit text regions or return 415. |
|
|
1324
1398
|
| Search derivation | Build graph/FTS/vector artifacts or mark nonsemantic. |
|
|
1325
1399
|
|
|
1326
|
-
The default service installation includes its structured, document,
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
discovery ({§mimetype-discovery}).
|
|
1400
|
+
The default service installation includes its structured, document, and
|
|
1401
|
+
embedding leaves through the service manifest. Exact tokenizer vocabularies,
|
|
1402
|
+
tree-sitter grammar WASM leaves, and third-party handlers remain independently
|
|
1403
|
+
installable and resolve from the same consumer-visible package graph under
|
|
1404
|
+
trust-gated discovery ({§mimetype-discovery}).
|
|
1332
1405
|
|
|
1333
1406
|
**Token accounting.** The daemon injects no tokenizer into `Mimetypes`; content
|
|
1334
1407
|
projection is independent of packet budgeting. Core uses the stable
|
|
@@ -1374,10 +1447,10 @@ flowchart LR
|
|
|
1374
1447
|
|
|
1375
1448
|
§derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected channel candidate—and every channel in graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Explicit membership changes may warm eagerly; every model turn joins exhaustive derivation before dispatch. Passive workspace creation and attachment do not launch it. The incomplete response is therefore an interface invariant and diagnostic, not a lazy-search mode.
|
|
1376
1449
|
|
|
1377
|
-
The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the
|
|
1450
|
+
The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the `&graph` matcher cannot name an empty symbol; that one definition is omitted from graph storage without suppressing FTS, vectors, or the remaining definitions. Invalid references and other persistence violations still fail the resource derivation explicitly.
|
|
1378
1451
|
|
|
1379
1452
|
The pass tiles the exact readable text into token-budgeted fragment strings and
|
|
1380
|
-
sends every tile for one resource through one ordered `mimetypes.
|
|
1453
|
+
sends every tile for one resource through one ordered `mimetypes.embedDocuments`
|
|
1381
1454
|
call; it never re-runs a format handler against partial fragments. Workspace
|
|
1382
1455
|
warms coalesce; a request arriving during a pass forces one final rescan.
|
|
1383
1456
|
Progress exposes `preparing`, `indexing`, `complete`, or `failed`. Producer
|
|
@@ -1466,12 +1539,17 @@ Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkState
|
|
|
1466
1539
|
A scheme declaring `lineAnchors: true`, or `textEditScopes: true` with model
|
|
1467
1540
|
write authority, publishes the contracts-owned {§text-line-anchor-syntax}.
|
|
1468
1541
|
Model-writable `textEditScopes` implies anchors; `lineAnchors` alone makes no EDIT claim. For canonical model-facing
|
|
1469
|
-
resource identity `R`,
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1542
|
+
resource identity `R`, configured non-negative neighbor count `C`, ordered
|
|
1543
|
+
content array `W` containing that line and up to `C` complete lines on either
|
|
1544
|
+
side (all excluding separators), and the line's offset `O` within `W`
|
|
1545
|
+
(`min(L-1, C)` for one-based ordinal `L`), core hashes the JSON tuple
|
|
1546
|
+
`["plurnk-line-anchor-v2",R,C,O,W]` with SHA-256, interprets the digest as a
|
|
1547
|
+
big-endian integer modulo `62^5`, and encodes five fixed-width characters with
|
|
1548
|
+
alphabet `0-9A-Za-z`. The ordinal itself is not hashed (#428): a line keeps its
|
|
1549
|
+
anchor wherever it moves while its content and neighborhood are unchanged, so
|
|
1550
|
+
edits above a line — the model's own earlier edits included — never stale the
|
|
1551
|
+
anchors below them; identical neighborhoods share one anchor and resolve as
|
|
1552
|
+
ambiguous with the matching lines, never as a silent landing on a twin. The universal READ projector derives
|
|
1475
1553
|
anchors from the complete canonical selected channel before applying the
|
|
1476
1554
|
authored text slice; its durable result retains the canonical derivation
|
|
1477
1555
|
identity and anchors aligned with returned lines. Packet rendering right-aligns
|
|
@@ -1486,7 +1564,11 @@ For READ/LOOK and COPY/MOVE source or destination selection, core resolves every
|
|
|
1486
1564
|
anchor against the addressed current complete content before applying the
|
|
1487
1565
|
ordinary numeric text-coordinate contract. Exactly one current match lowers to
|
|
1488
1566
|
its numeric line; zero or multiple matches return 409 `line-anchor-collision`,
|
|
1489
|
-
|
|
1567
|
+
with `retryable: false` because resolving the collision requires a new READ and
|
|
1568
|
+
different coordinates rather than automatic replay. An anchor in a column
|
|
1569
|
+
position returns 400 stating that four-coordinate
|
|
1570
|
+
column slots are numeric and that `<@start,@end>` is the whole-line anchor
|
|
1571
|
+
range. COPY/MOVE mutation owners retain
|
|
1490
1572
|
the resolved endpoint neighborhoods as compare-and-swap preconditions. There is
|
|
1491
1573
|
no revision sidecar or fuzzy relocation. A range authenticates both endpoint
|
|
1492
1574
|
neighborhoods, so every line of a range up to `2C + 2` lines is covered; a
|
|
@@ -1501,7 +1583,7 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
|
|
|
1501
1583
|
- §edit-null-clears Writes the body; `body: null` clears it.
|
|
1502
1584
|
- §edit-status-201-200 Returns `{ status: 201, entryId }` for a new entry and
|
|
1503
1585
|
`{ status: 200, entryId }` for a content update.
|
|
1504
|
-
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}). The operation's log classification remains independent ({§log-item-tags}).
|
|
1586
|
+
- §edit-noop-304 A write that changes nothing — identical content — returns `{ status: 304, entryId }`, mirroring OPEN/FOLD's idempotence ({§open-fold}). Its terse detail states the observed equality and the valid empty-body deletion shape; it never presumes that repetition or retrieval is the intended recovery. The operation's log classification remains independent ({§log-item-tags}).
|
|
1505
1587
|
- §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.
|
|
1506
1588
|
- §edit-line-anchors An anchored EDIT resolves under {§line-anchors} and carries
|
|
1507
1589
|
its endpoint checks as a core-private mutation precondition. Otherwise-valid
|
|
@@ -1518,9 +1600,11 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
|
|
|
1518
1600
|
that changes before mutation, or a representation that changes in the final
|
|
1519
1601
|
check/write gap returns the same neutral **409 `edit-collision`** and preserves
|
|
1520
1602
|
the winner's content. Its public detail says only that EDIT collided with
|
|
1521
|
-
another change and directs the model to READ
|
|
1522
|
-
|
|
1523
|
-
|
|
1603
|
+
another change and directs the model to READ before selecting current
|
|
1604
|
+
coordinates; `retryable: false` forbids automatic replay of the identical
|
|
1605
|
+
stale request. It does not assign fault or reveal which detection layer won.
|
|
1606
|
+
Concurrent correct workers are an ordinary cause. Core resolves anchors,
|
|
1607
|
+
scheme handlers receive only numeric
|
|
1524
1608
|
coordinates, the shared entry mutation owner rechecks selected endpoint
|
|
1525
1609
|
neighborhoods against its exact snapshot, and atomic identity/channel claims
|
|
1526
1610
|
and storage predicates close the remaining races.
|
|
@@ -1557,18 +1641,30 @@ operation requires a target, matcher, or unsigned tag. Add and remove terms for
|
|
|
1557
1641
|
the same tag conflict. Successful visibility and classification changes land as
|
|
1558
1642
|
one curation event whose exact per-row deltas are durable. Engine policy may
|
|
1559
1643
|
apply its separately specified diagnostic classifications, such as `overflow`.
|
|
1560
|
-
Every classification lives once in `log_tags`,
|
|
1561
|
-
copied with log history on fork.
|
|
1644
|
+
Every classification lives once in `log_tags`, remains forensic evidence when
|
|
1645
|
+
KILL retires its row's projection, and is copied with log history on fork.
|
|
1646
|
+
|
|
1647
|
+
### §log-history-projection Durable history and active projection
|
|
1648
|
+
|
|
1649
|
+
| Layer | Owner | Curation contract |
|
|
1650
|
+
|---|---|---|
|
|
1651
|
+
| Durable event | `log_entries` | One chronological execution fact. Ordinary Plurnk operations never erase it; its original body and initial folded state remain available to the client journal, digest, and fork forensics. Containing turn, worker, or workspace teardown may cascade the history. |
|
|
1652
|
+
| Active projection | `log_entry_projections` | One current worker-facing state per event. OPEN/FOLD change folded body intervals while active. Log-KILL atomically changes active to inactive and cannot be reversed; inactive rows are absent from packet rendering, log READ/FIND, failure pointers, semantic discovery, token accounting, and later curation. |
|
|
1653
|
+
|
|
1654
|
+
The successful curation operation and every exact target transition are durable
|
|
1655
|
+
in the same commit. KILL against another scheme retains that scheme's ordinary
|
|
1656
|
+
resource or process semantics; this projection contract is specific to
|
|
1657
|
+
`log:///`.
|
|
1562
1658
|
|
|
1563
1659
|
### §open-fold OPEN / FOLD
|
|
1564
1660
|
|
|
1565
1661
|
AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: TextLineMarker | null }`.
|
|
1566
1662
|
|
|
1567
|
-
OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded.
|
|
1663
|
+
OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded. An active row's canonical body remains complete through log READ/FIND regardless of folded visibility. Rows and bodies persist, and classification changes still land when visibility is a no-op. Malformed targets, unsupported coordinate arity, and nonexistent exact coordinates fail at their owning boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
|
|
1568
1664
|
|
|
1569
1665
|
### §jsonplurnk The Log's wire format
|
|
1570
1666
|
|
|
1571
|
-
The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The three body states are self-describing through field presence alone: a `body` field means open, `tokensBody` without `body` means folded (the value prices the OPEN), and neither means no canonical body; no `display` label exists. Two defaults are likewise field absence: `origin` is omitted for the worker's own model authorship (exactly as `source` absence means the owning worker), and `status` is omitted for a routine 200 on
|
|
1667
|
+
The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The three body states are self-describing through field presence alone: a `body` field means open, `tokensBody` without `body` means folded (the value prices the OPEN), and neither means no canonical body; no `display` label exists. Two defaults are likewise field absence: `origin` is omitted for the worker's own model authorship (exactly as `source` absence means the owning worker), and `status` is omitted for a routine 200 on an ordinary row. SEND always carries its submit code, KILL keeps an explicit 200 so destructive completion is decisive, and every non-200 stays explicit. A partially hidden open row also carries `"folded":["<scope>",...]`; coordinate gaps in its body make the omission explicit without renumbering later lines. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. It leads each entry object; the remaining members follow in stable alphabetical order. A present authored operation annotation appears as `annotation`; its absence omits the field. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an automatic bounded projection differs from the visibility-selected body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. Every row's accounting: {§packet-token-accounting}.
|
|
1572
1668
|
|
|
1573
1669
|
- §packet-token-accounting Every row reports its real weight so the packet self-reconciles against the budget: `tokensBody` is the projected body's nonzero weight whenever a canonical body would render (never `0` — a priceless OPEN is field absence), and `tokensActive` is the complete row's weight in the packet right now. The metadata share is derivable (`tokensActive − tokensBody` when open; `tokensActive` otherwise) and is never serialized — it feeds no curation decision. Thus FOLD removes the rendered body's weight while KILL removes `tokensActive`; on a folded row `tokensBody` previews the body share an OPEN would activate. The completed row, including its accounting field and framing, is measured to a fixed point. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body state). {§jsonplurnk} {§packet-jsonplurnk-exception}
|
|
1574
1670
|
|
|
@@ -1586,7 +1682,9 @@ The packet projects one actionable owner for each retrieval fact:
|
|
|
1586
1682
|
| exact matcher FIND | compact `matchLocation` range | each row's locator/region; a regex or glob row also carries `matched`, the matched text | none |
|
|
1587
1683
|
|
|
1588
1684
|
The compact range is `{ unit, total, requested: [first,last], returned?:
|
|
1589
|
-
[first,last] }` ({§range-extent}); empty results omit `returned`.
|
|
1685
|
+
[first,last] }` ({§range-extent}); empty results omit `returned`. An empty result
|
|
1686
|
+
set satisfies any well-formed page: zero matches is the answer, a 200 with no items,
|
|
1687
|
+
never a 416 (#425 F9). Transparent
|
|
1590
1688
|
coordinates let the model determine whether more material exists and choose
|
|
1591
1689
|
its own next request, so packet metadata never prescribes `next`, `complete`,
|
|
1592
1690
|
or `all`. FIND range cardinality replaces top-level `items`, `lines`, and
|
|
@@ -1600,17 +1698,17 @@ ordinary bounded bodies expose their displayed and complete chunk extents there.
|
|
|
1600
1698
|
|
|
1601
1699
|
### §turn-ops-entry The admitted turn program
|
|
1602
1700
|
|
|
1603
|
-
§turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the
|
|
1701
|
+
§turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the durable type, `origin` is the turn producer, no target exists, `tx` is empty, and the source lives in `rx.content`, typed `text/vnd.plurnk`. Its canonical model-facing address appends the lowercase `/ops` leaf to its three-part coordinate. The packet does not duplicate that identity as `kind` metadata. It is line-numbered and READ/FIND/OPEN/FOLD/KILL-able like any active log body. The worker-initialization `turnOps` is born OPEN because it is the worked orientation example; every other `turnOps`, including model inference and overflow recovery, is born FOLDED and remains available on demand. Log-KILL clears the `writableBy` gate for a model-authored item and retires only its active projection under {§log-history-projection}; the exact program remains forensic history. Log's handler surface keeps every other mutating op at 501. The shared executor writes exactly one after every admitted source-backed turn.
|
|
1604
1702
|
|
|
1605
|
-
§rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, and the exact latest rejected response. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
|
|
1703
|
+
§rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, the canonical model-facing `/attempt` leaf, and the exact latest rejected response. The packet does not duplicate that identity as `kind` metadata. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
|
|
1606
1704
|
|
|
1607
|
-
- §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 `## READ0 (worker:///docs/)`. A rendered
|
|
1705
|
+
- §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 `## READ0 (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: `/OP` for an operation, `/ops` for an admitted turn program, or `/attempt` for a rejected emission. 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. 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:///**/ops`, and `log:///**/attempt` deliberately filter canonical leaves.
|
|
1608
1706
|
- §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take 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: `## FOLD0 (log:///1/2)` folds turn 1/2's rows. OPEN and FOLD may instead take only a tag filter ({§log-item-tags}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless operation without tags or a matcher is 400.
|
|
1609
1707
|
- §log-curation-set-selection **Row selection and body scope are independent** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. Thus `## FOLD0 (log:///**/READ) <17,-1>` may change long READs and no-op on short ones while reporting every selected row in `matched`.
|
|
1610
1708
|
|
|
1611
|
-
§fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log**
|
|
1709
|
+
§fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** and **renders exactly once** — in the packet after its turn, as its path, target, and status — then dissolves from the projection ({§curation-receipt-dissolves}): the actor sees its `200` or `204` at the one moment it decides whether to conclude or repeat, the row exists for forensics (a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig, and how a model that deferred its confirmation re-issued a KILL into the turn ceiling), and the log never accumulates housekeeping — a permanent receipt row would be a crumb that itself needs sweeping. Its exact selected target set, each target's active/folded state before and after, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, projection changes, tag changes, and landed effects commit in one database statement with each before state as a collision guard. The authored program also survives verbatim in its `turnOps` item. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
|
|
1612
1710
|
|
|
1613
|
-
§
|
|
1711
|
+
§curation-receipt-dissolves **Successful log-curation receipts dissolve.** A model-authored OPEN, FOLD, or KILL of a log item renders in exactly the packet immediately after its turn — path, target, and status, no body — and leaves the active projection once a later model turn has rows; history keeps the row, the exact active/folded transition for every target, and the authored `turnOps`. Nothing is left to curate: a receipt that dissolves is not a log item to sweep. A KILL of a log item retires the selected rows from the worker's active projection under {§log-history-projection}; it does not delete their execution history. The dissolving is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or another stored artifact retains its scheme-owned world or process semantics and stays visible. A killed exact coordinate resolves 404 in ordinary log operations; a well-formed broad selection with no active matches remains the 204 no-op of {§log-curation-folder-idiom}, and that 204 renders once like any dissolving receipt. Failed OPEN/FOLD/KILL render like every operation error and persist.
|
|
1614
1712
|
|
|
1615
1713
|
### §log-sensitive-request-evidence Durable request evidence
|
|
1616
1714
|
|
|
@@ -1620,10 +1718,11 @@ secret detection.
|
|
|
1620
1718
|
|
|
1621
1719
|
| Surface | Durable rule |
|
|
1622
1720
|
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1623
|
-
| Operation target | Each non-null URL username or password becomes `__redacted__`;
|
|
1624
|
-
|
|
|
1721
|
+
| Operation target | Each non-null URL username or password becomes `__redacted__`; `raw` is rebuilt from that pure projected target. |
|
|
1722
|
+
| Scheme metadata modifier | Every present block becomes `__redacted__` wholesale; only ordered block count and represented-slot presence survive ({§scheme-metadata-modifier}). |
|
|
1723
|
+
| COPY/MOVE destination | The nested destination target receives the identical URL-credential projection. URI component columns derive from the projected primary target, so columns and `tx` cannot disagree. |
|
|
1625
1724
|
| Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
|
|
1626
|
-
| Parser failure | Preserves the structural diagnosis and source position without quoting
|
|
1725
|
+
| Parser failure | Preserves the structural diagnosis and source position without quoting scheme-metadata contents ({§scheme-metadata-modifier}). |
|
|
1627
1726
|
| Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
|
|
1628
1727
|
| Model-call evidence and source artifacts | `model_calls.response` under {§emission-admission}, `turnOps` under {§turn-ops-log-curation}, and `emissionAttempt` under {§rejected-emission-entry} remain exact forensic evidence and are the explicit exception. |
|
|
1629
1728
|
|
|
@@ -1640,8 +1739,9 @@ body: ResourceSelection (destination), signal: tags | null }`.
|
|
|
1640
1739
|
2. Resolve destination path, channel, and optional text scope. Source and
|
|
1641
1740
|
destination mimetypes must agree or the result is 415. Destination anchors
|
|
1642
1741
|
resolve independently under {§line-anchors}.
|
|
1643
|
-
3. A scoped destination must already exist and is mutated through the
|
|
1644
|
-
destination scheme's `editBatch`.
|
|
1742
|
+
3. A partial scoped destination must already exist and is mutated through the
|
|
1743
|
+
destination scheme's `editBatch`. A complete-value destination scope on an
|
|
1744
|
+
absent resource is creation under {§fs-write-surface}.
|
|
1645
1745
|
4. An unscoped destination writes only its selected channel. Existing other
|
|
1646
1746
|
channels survive.
|
|
1647
1747
|
- §copy-conflict-409 Different content in that channel is 409.
|
|
@@ -1687,7 +1787,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
1687
1787
|
|
|
1688
1788
|
AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal: tags | null, lineMarker? }`.
|
|
1689
1789
|
|
|
1690
|
-
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. 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 plugin contract, never inferred from URL punctuation.
|
|
1790
|
+
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; 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 (run67, 2026-08-29: a whole-repository search silently confined to the root). 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 plugin contract, never inferred from URL punctuation.
|
|
1691
1791
|
- An exact target resolves to the same canonical `(scheme, authority, pathname)` identity
|
|
1692
1792
|
as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
|
|
1693
1793
|
identity-bearing: `https://example.com/page` queries
|
|
@@ -1791,16 +1891,22 @@ the loop continue; repeated offenses terminate through the engine's 500.
|
|
|
1791
1891
|
| Idle turn | An engine-rail error row with the corrective disposition | One strike |
|
|
1792
1892
|
| Refused disposition | The final SEND's 409 row with its exact Problem Detail | One strike |
|
|
1793
1893
|
|
|
1894
|
+
Executor results are evidence, never strikes: a command's nonzero exit — surfaced
|
|
1895
|
+
as its completion READ ({§exec-stream}) or read by the model from the stream —
|
|
1896
|
+
carries an `executor/*` problem identity and does not enter the streak. Structural
|
|
1897
|
+
violations (a missing PLAN or terminal SEND, an operation dropped by a parse
|
|
1898
|
+
failure) do strike: six in a row is a degenerated run.
|
|
1899
|
+
|
|
1794
1900
|
- §send-target-recipient **A SEND target is a recipient.** A model's directed SEND
|
|
1795
1901
|
addresses a worker (`## SEND0 (worker://<name>)`), an outbound agent (`a2a://`),
|
|
1796
1902
|
or a scheme that implements SEND (an `https://` POST); with `[410]` it names a
|
|
1797
1903
|
resource to delete. A SEND to a scheme the model may not write (the prompt, the
|
|
1798
|
-
log) is refused 400 `send-target-not-a-recipient
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
answers 501
|
|
1803
|
-
- §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with `## SEND0 [200]`. If you're waiting on a child or stream you spawned, use `## SEND0 [202]` to block on it — a 202 with nothing to wait on simply concludes."* A successful same-turn FOLD is the exception: its `202` continues without a strike so the curated packet can support the next reasoning turn.
|
|
1904
|
+
log) is refused 400 `send-target-not-a-recipient`, never the unrelated writer
|
|
1905
|
+
rule. The detail states only that the addressed scheme is not a recipient;
|
|
1906
|
+
neutral recovery distinguishes targetless replies from directed SEND without
|
|
1907
|
+
guessing which one was intended. A scheme that does not implement SEND
|
|
1908
|
+
answers its ordinary factual 501 without grafting a guessed recovery onto it.
|
|
1909
|
+
- §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with `## SEND0 [200]`. If you're waiting on a child or stream you spawned, use `## SEND0 [202]` to block on it — a 202 with nothing to wait on simply concludes."* A successful same-turn FOLD is the exception: its `202` continues without a strike so the curated packet can support the next reasoning turn. **An empty `[102]` while the worker holds a live stream or child is a mis-spelled wait, not idleness**: the engine parks the turn as `[202]` — the same live-work predicate the `[200]` gate uses, so the shift never disagrees with the orientation the model reads — records the SEND as `202` with the correction in that row's annotation (a park drops transient notices; the row survives the wake); no strike. With nothing in flight the idle-turn 409 stands — it is the deterministic recovery for that case.
|
|
1804
1910
|
- §send-premature-terminate **Premature terminate — the pending set.**
|
|
1805
1911
|
A model's completion claim is gated by one rule: *nothing pending may be silently
|
|
1806
1912
|
discarded*. Pending work has two states: **live obligations** (open
|
|
@@ -1813,7 +1919,10 @@ the loop continue; repeated offenses terminate through the engine's 500.
|
|
|
1813
1919
|
retrieval members are unchanged. The set is judged at the disposition's own dispatch, after
|
|
1814
1920
|
earlier operations in the emission. `[200]` over any member is refused 409
|
|
1815
1921
|
and the loop continues; every refusal strikes uniformly, including a
|
|
1816
|
-
retrieval-only refusal.
|
|
1922
|
+
retrieval-only refusal. Its Problem reports only the bounded pending kinds
|
|
1923
|
+
`streams`, `workers`, `receipts`, `failed-stream-results`, and
|
|
1924
|
+
`worker-results`; it never embeds commands, stream handles, result bodies, or
|
|
1925
|
+
a presumed recovery. The pending kind changes the factual Problem class, not
|
|
1817
1926
|
rail accounting. `[499]` deliberately abandons regardless.
|
|
1818
1927
|
- §send-administrative-terminal **An administrative terminal closes its own
|
|
1819
1928
|
transaction.** A client, plugin, or `_plurnk` operation program runs in its
|
|
@@ -1842,12 +1951,22 @@ a relative target against the directory the command would run in — the project
|
|
|
1842
1951
|
root, or the shell's own cwd when the workspace has none — and inspects it
|
|
1843
1952
|
before anything spawns: a directory becomes the working directory, a file is the
|
|
1844
1953
|
script; anything else is refused `400 target-not-found`, naming that directory
|
|
1845
|
-
and
|
|
1846
|
-
|
|
1954
|
+
and giving the applicable accepted form without inferring what the model meant.
|
|
1955
|
+
When the target is a registered tool of another runtime, recovery gives that
|
|
1956
|
+
tool's exact runtime-qualified invocation; otherwise it distinguishes an existing
|
|
1957
|
+
directory/script target from a targetless shell-command body. A non-file resource
|
|
1958
|
+
target that cannot be read keeps the owning READ's failure identity (#163) and states
|
|
1959
|
+
the slot contract in its recovery — the resource is the program and the body its stdin;
|
|
1960
|
+
a command belongs beneath a targetless heading — without guessing which was meant (#425). The started receipt always
|
|
1961
|
+
names the working directory only when it is not the project root, and then in the
|
|
1962
|
+
model's own project-relative form ({§fs-namespace}: the root is the model's `/`, so it
|
|
1963
|
+
is never rendered, and no receipt or Problem carries a host-absolute path — the
|
|
1964
|
+
batch of 2026-08-29 showed the absolute `cwd` copied back into the target slot as
|
|
1965
|
+
`(cwd: /host/path)`). The EXEC `(path)` is one of cwd, script, or tool
|
|
1847
1966
|
name — the runtime's declaration decides which (interpreters: cwd or script;
|
|
1848
1967
|
tool families: tool name) — and a command is never a target. The default shell
|
|
1849
|
-
is taught as
|
|
1850
|
-
|
|
1968
|
+
is taught as targetless bare `EXEC`; `[sh]` remains the explicit form, and an
|
|
1969
|
+
authored directory target remains an optional cwd override.
|
|
1851
1970
|
|
|
1852
1971
|
| Declared target kind | Authored target | Canonical effect target | Executor realization |
|
|
1853
1972
|
| -------------------- | --------------------------------------- | ----------------------- | --------------------------------------------------------- |
|
|
@@ -1899,7 +2018,7 @@ Loop-flag authority follows the selected runtime's declaration:
|
|
|
1899
2018
|
| Absent, `literal`, local `path`, or local `resource` | `exec` |
|
|
1900
2019
|
| Non-file `resource` | `exec` and the addressed source scheme |
|
|
1901
2020
|
|
|
1902
|
-
Worker and runtime-stream authorities, query, fragment,
|
|
2021
|
+
Worker and runtime-stream authorities, query, fragment, the scheme metadata modifier, and
|
|
1903
2022
|
every other component of a `resource` address retain their owning READ
|
|
1904
2023
|
semantics. A failed source READ is preserved as the proposal-application
|
|
1905
2024
|
failure. A successful READ with no string representation is refused 422; an
|
|
@@ -1918,9 +2037,10 @@ Worker Functionality providers may atomically overlay additional names under
|
|
|
1918
2037
|
{§module-worker-capabilities}; a name has one owner within a worker, while
|
|
1919
2038
|
independent workers may use the same name. An absent or empty tag selects
|
|
1920
2039
|
`sh`; a non-empty tag selects exactly that registered executable tool. Unknown
|
|
1921
|
-
tags are refused 501 with
|
|
1922
|
-
|
|
1923
|
-
|
|
2040
|
+
tags are refused 501 with the advertised catalogue and are never reinterpreted
|
|
2041
|
+
as shell command words. The common mistaken `[shell]` alias is narrowly told to
|
|
2042
|
+
omit that signal for the default shell; arbitrary unknown tags receive no guessed
|
|
2043
|
+
alternative intent. An unavailable runtime is also 501 and carries the probe
|
|
1924
2044
|
`detail`.
|
|
1925
2045
|
|
|
1926
2046
|
For a family runtime, `ExecutorRegistry.toolRegistry(tag, workerId)`
|
|
@@ -1932,8 +2052,9 @@ catalogue.
|
|
|
1932
2052
|
Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands under `## EXEC0` or `## EXEC0 [sh]`. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
|
|
1933
2053
|
|
|
1934
2054
|
**Timeout and poll — `<T,P>` on the `<L>` slot (grammar 0.74.20).** EXEC
|
|
1935
|
-
repurposes the line-marker slot as `<timeout, poll>` in **
|
|
1936
|
-
|
|
2055
|
+
repurposes the line-marker slot as `<timeout, poll>` in **minutes** — agentic
|
|
2056
|
+
latencies make a sub-minute horizon a trap — converted at the parse boundary to the
|
|
2057
|
+
catalog's internal `stream.seconds`. The SEND `[202] <T>` wait horizon is minutes too.
|
|
1937
2058
|
|
|
1938
2059
|
§exec-timeout `T` (`mark[0]`) caps the spawn's lifetime. At `T>0` the service
|
|
1939
2060
|
aborts it — a bounded reap, polite signal then SIGKILL after
|
|
@@ -1947,7 +2068,7 @@ its terminal output surfaces born-OPEN like any close ({§exec-stream}).
|
|
|
1947
2068
|
§exec-poll `P` (`mark[1]`) is the **poll cadence**, stored on the subscription.
|
|
1948
2069
|
While the loop is blocked on a SEND signal `202` wait for that stream, the daemon arms
|
|
1949
2070
|
a per-worker timer for the tightest open poll cadence and resumes the blocked
|
|
1950
|
-
loop every P
|
|
2071
|
+
loop every P minutes, floored by `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS` so it cannot tick
|
|
1951
2072
|
faster than the optimistic settlement scale, to inspect progress. It does **nothing while the
|
|
1952
2073
|
loop is active** because ambient stream deltas already surface progress. An
|
|
1953
2074
|
open stream without `P` uses exponential backoff
|
|
@@ -1978,10 +2099,12 @@ may use a semantic Worker name there, but the private numeric id never appears
|
|
|
1978
2099
|
in a URI or packet. `plurnk` and `commons` are reserved Workers, and `~` is the
|
|
1979
2100
|
current-Worker sigil; none can be minted by a spawn or client.
|
|
1980
2101
|
|
|
1981
|
-
§stream-owner-scoped **Capability streams are owner-scoped.** Concurrent workers' stream coordinates are loop-relative and IDENTICAL (every worker's first loop is sequence 1), so the entry identity keys on the owner and identical coordinates across workers are distinct rows. The address's authority names the owner: **empty = the calling worker** — your own streams need no qualifier, so a fan-out sibling's output can never surface under your READ — and a **named authority** reaches that worker's streams
|
|
2102
|
+
§stream-owner-scoped **Capability streams are owner-scoped.** Concurrent workers' stream coordinates are loop-relative and IDENTICAL (every worker's first loop is sequence 1), so the entry identity keys on the owner and identical coordinates across workers are distinct rows. The address's authority names the owner: **empty = the calling worker** — your own streams need no qualifier, so a fan-out sibling's output can never surface under your READ — and a **named authority** reaches that worker's streams for any worker of the workspace (the parent designs the topology by what it names to whom; the engine imposes none, #394; an unknown name resolves 404). A child is told its parent's name in its packet (`parent-worker`). KILL stays self-only — a parent controls a child through the worker lifecycle, never by reaching into its streams. The storage pathname stays the bare loop coordinate; the owner rides the column, so nothing model-facing carries a worker id. A stream 404 never discloses existence, but it names the address space: the coordinate shape, the unqualified self, the descendant-by-name form, and that a tool's own ids are arguments, not addresses.
|
|
1982
2103
|
|
|
1983
2104
|
§worker-auto-name **Auto-names are id-free ordinals** — worker names are the addressable authority, so an auto-name is `<prefix>-<N>` (per-workspace monotonic count, the fork `<parent>-fork-<N>` pattern), never a timestamp-hash that would leak machine identity through the hostname. The semantic suffix remains intact; when the complete name would exceed `WORKER_NAME`, generation shortens only the inherited prefix until the predicate admits it. Auto-names never reuse an existing literal and pass through {§worker-name-minting} like explicit names. Name selection and worker creation are one atomic claim: concurrent allocators receive distinct literals, while concurrent ensures of a workspace's default conversation converge on one root worker.
|
|
1984
2105
|
|
|
2106
|
+
§workspace-auto-name **Workspace auto-names are five anchor-alphabet characters.** A `workspace.create` without a name draws five characters from the {§line-anchors} alphabet `0-9A-Za-z` (uniformly, from a cryptographic source), redrawing on the astronomically rare collision. No prefix, timestamp, or origin marker: a name never encodes where a workspace came from, so nothing can grow load-bearing on it.
|
|
2107
|
+
|
|
1985
2108
|
§exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of newly publishable stream content each turn, {§exec-stream}), never a same-turn receipt.
|
|
1986
2109
|
|
|
1987
2110
|
§effect-policy-tunable **Effect admission is deployment-tunable.** The default
|
|
@@ -2000,7 +2123,22 @@ two states and no others:
|
|
|
2000
2123
|
| state | what the model receives |
|
|
2001
2124
|
|---|---|
|
|
2002
2125
|
| active | nothing in the Log. The `## Child Streams` pointer names the stream with each channel's size and its growth since the last packet ({§child-orientation}); the model READs any range it wants. |
|
|
2003
|
-
| terminal | ONE `origin=_plurnk` READ at `<runtime>:///<coord>#<channel>`, born OPEN, that is exactly a markerless READ of the channel — its first page ({§read-selection-projection}: lines 1–16, the whole channel when it fits, the channel's own mimetype), the `range` extent, and
|
|
2126
|
+
| terminal | ONE `origin=_plurnk` READ at `<runtime>:///<coord>#<channel>`, born OPEN, that is exactly a markerless READ of the channel — its first page ({§read-selection-projection}: lines 1–16, the whole channel when it fits, the channel's own mimetype), the `range` extent, terminal status and Problem, `terminal: true`, any producer-supplied integer `exitCode`, and `source: log:///<coord>/EXEC` linking the causal invocation. The packet renders that address under `stream`, exactly as the invocation row links its output, never under `target`: a stream is observed, not a slot to author. |
|
|
2127
|
+
|
|
2128
|
+
§exec-concurrency **Bounded admission per workspace (#389).** At most
|
|
2129
|
+
`PLURNK_SERVICE_EXEC_CONCURRENCY` executions run at once in one workspace (shipped `12`;
|
|
2130
|
+
`-1` unbounded); the scope is the workspace, so neither delegation nor later turns
|
|
2131
|
+
bypass it and no other workspace can starve it. Every admitted EXEC still creates its
|
|
2132
|
+
entry, channels, and open subscription before its receipt returns, so queued work is
|
|
2133
|
+
cancellable, restart-reconcilable, completion-gated, and observed through the ordinary
|
|
2134
|
+
stream mechanics ({§exec-stream}). The receipt tells the truth once and never rewrites
|
|
2135
|
+
it: an immediate slot is `200 { outcome: "started" }`; delayed work is
|
|
2136
|
+
`202 { outcome: "queued", executionsAhead, concurrency }`, and the channel stays
|
|
2137
|
+
`active` in the existing live sense — output growth and terminal settlement are the
|
|
2138
|
+
current truth. Admission is FIFO within the workspace; queue residence does not consume
|
|
2139
|
+
the execution timeout; a KILL while queued never invokes the executor and closes the
|
|
2140
|
+
stream through the normal 499 path. The scheduler is the EXEC scheme's; the knob is the
|
|
2141
|
+
service's ({§operator-config}), fail-hard on any other value.
|
|
2004
2142
|
|
|
2005
2143
|
§exec-stream-page **An unrequested delivery never exceeds the retrieval page.** The
|
|
2006
2144
|
terminal observation is the same page a markerless READ returns, whatever the
|
|
@@ -2015,7 +2153,8 @@ to the model — by the Child Streams pointer while active, by the terminal
|
|
|
2015
2153
|
observation at close — so the pointer can state growth and no partial document
|
|
2016
2154
|
or record ever reaches the model. The terminal observation and its cursor
|
|
2017
2155
|
transition commit atomically; a terminal state with an empty channel still
|
|
2018
|
-
produces one bodyless conclusion row
|
|
2156
|
+
produces one bodyless conclusion row whose terminal fact, causal EXEC link, and
|
|
2157
|
+
available exit code make completion explicit without invented narration. OPEN, FOLD, or KILL may curate
|
|
2019
2158
|
that log row without rewinding the cursor or publishing the terminal result
|
|
2020
2159
|
again; the exact terminal result and channel content remain READable at the
|
|
2021
2160
|
stream address. Every READ then obeys {§body-projection} and therefore renders
|
|
@@ -2055,7 +2194,7 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
|
|
|
2055
2194
|
|
|
2056
2195
|
§proposal-outcome-terse-error A caller-supplied `outcome` overrides the default. On an **accept** it stays forensics-only; a **non-accept** carries it as the `rx`'s terse `error` token (`write_failed` / `rejected` / `timeout` — one word, never prose), because "the action didn't occur" without the mechanical why leaves the model acting on a phantom success (the fan-out dead-park: an ENOENT apply rendered as a mute 400).
|
|
2057
2196
|
|
|
2058
|
-
§proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from
|
|
2197
|
+
§proposal-proposed-hidden **A proposed row is invisible until it resolves.** A `state='proposed'` / 202 row is withheld from both packet materialization and `log/entry`; it surfaces exactly once after resolution, carrying its terminal status — models and clients see outcomes, never pending proposals.
|
|
2059
2198
|
|
|
2060
2199
|
### §proposal-projection One durable proposal, one client projection
|
|
2061
2200
|
|
|
@@ -2067,7 +2206,7 @@ Core derives the contracts-owned `ProposalProjection` from the durable proposed
|
|
|
2067
2206
|
| `target` | canonical `{ scheme, authority, pathname }` from `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
|
|
2068
2207
|
| `body` | proposed operation result `rx.body`; absent means the empty review body |
|
|
2069
2208
|
| `attrs` | proposed log row `attrs` object |
|
|
2070
|
-
| `
|
|
2209
|
+
| `policy` | validated complete persisted loop policy |
|
|
2071
2210
|
| `disposition` | {§proposal-disposition}; the same value drives automatic settlement and client presentation |
|
|
2072
2211
|
|
|
2073
2212
|
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, loop policy, 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.
|
|
@@ -2091,15 +2230,15 @@ removes ownerless rows without fabricating cancellation, payload, or replay.
|
|
|
2091
2230
|
|
|
2092
2231
|
### §proposal-disposition Settlement authority and precedence
|
|
2093
2232
|
|
|
2094
|
-
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The
|
|
2233
|
+
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The persisted loop policy determines it exactly:
|
|
2095
2234
|
|
|
2096
|
-
| `
|
|
2097
|
-
|
|
|
2098
|
-
|
|
|
2099
|
-
|
|
|
2100
|
-
|
|
|
2235
|
+
| `policy.proposals` | Disposition |
|
|
2236
|
+
| ------------------ | ---------------------------------------- |
|
|
2237
|
+
| `review` | client |
|
|
2238
|
+
| `accept` | loop accept |
|
|
2239
|
+
| `reject` | loop reject, outcome `no_review_channel` |
|
|
2101
2240
|
|
|
2102
|
-
|
|
2241
|
+
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.
|
|
2103
2242
|
|
|
2104
2243
|
---
|
|
2105
2244
|
|
|
@@ -2137,6 +2276,7 @@ Model sees lifecycle events in the `log` section per turn.
|
|
|
2137
2276
|
### §stream-control Stream control and writes
|
|
2138
2277
|
|
|
2139
2278
|
- **Cancel:** `## SEND0 [499] (https://feed.example/x)` — the service invokes the handle registered by `subscriptions.open()` and aborts the composed subscription signal.
|
|
2279
|
+
- **Kill:** `## KILL0 (sh:///1/2/3)` — the model terminates its own runtime stream. This is stream control, not a write: the output scheme's `writableBy` never gates it, `Exec.kill` scopes the address to the caller ({§stream-owner-scoped}), and a finished stream answers 410 under its own tag. A queued execution ({§exec-concurrency}) is cancelled the same way and never enters its executor.
|
|
2140
2280
|
- **WebSocket write:** `## EDIT0 (wss://feed/x)` or `## SEND0 [200] (wss://feed/x)` with a body sends one whole text frame through the active owner. SEND can follow the opening READ in the same turn; EDIT runs before READ ({§op-mode-phases}) and therefore addresses an owner already open at turn start.
|
|
2141
2281
|
- **Other stream write:** `## SEND0 [200] (…)` remains scheme-defined, including exec stdin.
|
|
2142
2282
|
|
|
@@ -2257,15 +2397,15 @@ freshness remains the owning family's concern.
|
|
|
2257
2397
|
| Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
|
|
2258
2398
|
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format leaves. |
|
|
2259
2399
|
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format leaves. |
|
|
2260
|
-
| | | Fixed `embeddings` artifact. All names use the `@plurnk/plurnk-mimetypes-*` prefix.
|
|
2261
|
-
| Executors | `@plurnk/plurnk-execs` | `common`, `
|
|
2400
|
+
| | | Fixed `embeddings` artifact, including exact counters for its built-in profiles. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
|
|
2401
|
+
| Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite` leaves under the `@plurnk/plurnk-execs-*` prefix. |
|
|
2262
2402
|
|
|
2263
|
-
The independently published `application-pdf` handler and `tokenizers`
|
|
2403
|
+
The independently published `application-pdf` handler and general `tokenizers`
|
|
2264
2404
|
artifact are opt-in leaves. Installing either beside the service admits it
|
|
2265
|
-
through ordinary package
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2405
|
+
through ordinary package resolution without changing the service manifest.
|
|
2406
|
+
The service-owned embedding artifact owns exact counters for its built-in local
|
|
2407
|
+
and hosted profiles; a custom profile may resolve another vocabulary through
|
|
2408
|
+
the optional general artifact.
|
|
2269
2409
|
|
|
2270
2410
|
**Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
|
|
2271
2411
|
operator declarations, local adapters, and finally installed AI SDK provider
|
|
@@ -2303,7 +2443,7 @@ service manifest edit.
|
|
|
2303
2443
|
- Backpressure caps — none ({§stream-constraints}).
|
|
2304
2444
|
- Stream cancel — SEND signal `499` ({§stream-control}).
|
|
2305
2445
|
- Delete — `KILL` (entry-KILL, the canonical delete, {§move}); SEND signal `410` also deletes as a side-effect ({§send-dispatch}).
|
|
2306
|
-
- §loop-
|
|
2446
|
+
- §loop-policy-effective-read Per-loop policy — `loops.policy` persists one complete immutable `LoopPolicy`; every runtime policy read validates that snapshot before use. Missing rows or invalid values fail with the owning loop coordinate and cause. Raw archival copies and forensic rendering do not interpret policy.
|
|
2307
2447
|
- Default-channel wire rendering — {§channel-selection}.
|
|
2308
2448
|
|
|
2309
2449
|
---
|
|
@@ -2362,12 +2502,15 @@ Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-
|
|
|
2362
2502
|
|-------------------------------------------------------------|---------|---------|
|
|
2363
2503
|
| `PLURNK_SERVICE_DB_PATH` | `$XDG_DATA_HOME/plurnk/plurnk.db` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
2364
2504
|
| `PLURNK_HOST` | `127.0.0.1` | Bind address for the listener. Local-only by default. |
|
|
2365
|
-
| `PLURNK_PORT` | `
|
|
2366
|
-
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, branch batching
|
|
2505
|
+
| `PLURNK_PORT` | `1066` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
|
|
2506
|
+
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, and branch batching; every other value denies them. |
|
|
2367
2507
|
| §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | `root` | 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. |
|
|
2508
|
+
| `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | `104857600` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
|
|
2368
2509
|
| `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
|
|
2369
2510
|
| `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
2370
2511
|
| §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
|
|
2512
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | `900000` | ms a turn keeps re-issuing its provider call after a recoverable provider failure before the loop parks ({§provider-recovery}); `0` parks at once. |
|
|
2513
|
+
| `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | `5000` | First recovery delay (ms); doubles per failure, capped at twelve times itself ({§provider-recovery}). |
|
|
2371
2514
|
| `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
|
|
2372
2515
|
| `PLURNK_SERVICE_EMISSION_ATTEMPTS` | `3` | Completed provider responses allowed beneath one engine turn before an untrustworthy model-turn frame exhausts admission. Bounded interior operation errors are admitted and do not spend this budget. Consecutive exhaustion after the one informed recovery turn terminates independently of strikes. |
|
|
2373
2516
|
| `PLURNK_SERVICE_PREVIEW_LINES` | `16` | Maximum lines in an ordinary bounded log-body projection ({§body-projection}). |
|
|
@@ -2380,6 +2523,8 @@ Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-
|
|
|
2380
2523
|
| `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
|
|
2381
2524
|
| `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
|
|
2382
2525
|
| `PLURNK_SERVICE_FILES_ITEMS` | `-1` | 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}). |
|
|
2526
|
+
| `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | `none` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
|
|
2527
|
+
| `PLURNK_SERVICE_EXEC_CONCURRENCY` | `12` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
|
|
2383
2528
|
| `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
|
|
2384
2529
|
| §operator-config-worker-warm `PLURNK_SERVICE_WORKER_WARM_MS` | `900000` | Milliseconds a lease-free worker Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-worker-residency}). |
|
|
2385
2530
|
| `PLURNK_SERVICE_WORKER_WARM_MAX` | `2` | Maximum lease-free worker Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-worker-residency}). |
|
|
@@ -2407,8 +2552,8 @@ instead of a user's boot, and a dead knob cannot ship.
|
|
|
2407
2552
|
|
|
2408
2553
|
| Owner | Configuration |
|
|
2409
2554
|
|---|---|
|
|
2410
|
-
| `.env.test` | Safe default model selection and universal real-model gate posture; no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
|
|
2411
|
-
| Live/demo scripts | The repository
|
|
2555
|
+
| `.env.test` | Safe default model selection and universal real-model gate posture, including the bundled embedder (an ambient operator embedding route never becomes a gate dependency); no alias declarations, routes, secrets, model tuning, or cost/sandbox ceilings. |
|
|
2556
|
+
| Live/demo scripts | The repository policy path and runner topology. |
|
|
2412
2557
|
| Benchlets | Their snapshotted policy, workspace restrictions, and task-specific exceptions; direct env wins over the profile. |
|
|
2413
2558
|
| Operator env/shell | Model alias declarations and explicit selection overrides, provider capability such as GBNF, endpoints, credentials, tuning, and deliberate ceiling overrides. |
|
|
2414
2559
|
| `test/setup.ts` | Mock-only alias, envelope, resource, storage, and isolation fixtures; unit/integration never consume the real-model profile. |
|
|
@@ -2447,7 +2592,7 @@ boundary. Operator-arcane knobs stay environment-only.
|
|
|
2447
2592
|
| `settings.git` | Boolean | Tightening denial {§operator-config-workspace-git} |
|
|
2448
2593
|
| `settings.fileCreateScope` | `none`, `root`, or `namespace` | Tightening ceiling {§operator-config-workspace-file-create-scope} |
|
|
2449
2594
|
| `settings.client` | Nonempty string | Stable self-identification {§client-metadata} |
|
|
2450
|
-
| `settings.
|
|
2595
|
+
| `settings.capabilities` | `CapabilityPolicy` | Subtractive capability layer {§operator-config-workspace-capabilities} |
|
|
2451
2596
|
|
|
2452
2597
|
The composition families remain distinct so one setting's semantics never
|
|
2453
2598
|
leak into another.
|
|
@@ -2462,22 +2607,17 @@ leak into another.
|
|
|
2462
2607
|
workspace: a client tightens the runaway-op guard and never raises it past
|
|
2463
2608
|
the operator's.
|
|
2464
2609
|
- §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
|
|
2465
|
-
PLAN
|
|
2610
|
+
PLAN and the final disposition `SEND` (`102`, `200`, `202`,
|
|
2466
2611
|
`300`, or `499`) are never counted and always dispatch, so `0` is a valid
|
|
2467
2612
|
floor — the tightest — admitting a plan and disposition with zero actions.
|
|
2468
2613
|
- §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.
|
|
2469
2614
|
- §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`.
|
|
2470
|
-
- §operator-config-workspace-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
intersects it: settings cannot register or re-enable a runtime. A canonical
|
|
2477
|
-
key for a currently absent tag is accepted as inert policy and applies if a
|
|
2478
|
-
worker Functionality provider later publishes that tag. Dispatch and
|
|
2479
|
-
model-facing tool-resource materialization use the same registered-set intersection and policy
|
|
2480
|
-
predicate, so a workspace-disabled tag is neither executable nor taught.
|
|
2615
|
+
- §operator-config-workspace-members-model-scope `settings.membersModelScope` narrows `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` by the same lattice; a workspace may refuse the model's definitions entirely under a permissive service ({§members-model-scope}).
|
|
2616
|
+
- §operator-config-workspace-capabilities `settings.capabilities` is one
|
|
2617
|
+
workspace-stable `CapabilityPolicy` layer in {§capability-admission}. It may
|
|
2618
|
+
narrow any registered operation, scheme, runtime, tool, access class, or
|
|
2619
|
+
trait through the canonical `only`/`deny` selectors; it cannot register a
|
|
2620
|
+
capability or restore one removed by the service layer.
|
|
2481
2621
|
|
|
2482
2622
|
Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
|
|
2483
2623
|
|
|
@@ -2499,12 +2639,13 @@ names, request validation, discovery result, and event projection.
|
|
|
2499
2639
|
|
|
2500
2640
|
```mermaid
|
|
2501
2641
|
flowchart LR
|
|
2642
|
+
bind["Host may pre-bind client-interface listener<br/>unready"] --> register
|
|
2502
2643
|
register["Daemon.registerModule"] --> setup["module.setup(ModuleSetupSeam)"]
|
|
2503
2644
|
setup --> capabilities["Register static capabilities,<br/>workspace activators, and actions"]
|
|
2504
2645
|
capabilities --> ready["Process-wide schemes ready"]
|
|
2505
2646
|
ready --> recovery["Reconcile durable lifecycle"]
|
|
2506
2647
|
recovery --> start["module.start(ApplicationPort)"]
|
|
2507
|
-
start --> interface["Module-owned
|
|
2648
|
+
start --> interface["Module-owned client protocol<br/>ready"]
|
|
2508
2649
|
recovery -->|durable workspace work| demand["First workspace demand"]
|
|
2509
2650
|
interface -->|client workspace work| demand
|
|
2510
2651
|
demand --> lease["Acquire capability residency"]
|
|
@@ -2522,14 +2663,19 @@ flowchart LR
|
|
|
2522
2663
|
|
|
2523
2664
|
Every registered module's `setup` runs in registration order before any
|
|
2524
2665
|
module's `start`. Core then readies process-wide schemes, reconciles durable
|
|
2525
|
-
lifecycle, and starts modules in registration order.
|
|
2666
|
+
lifecycle, and starts modules in registration order. The production
|
|
2667
|
+
client-interface module may already own its socket under
|
|
2668
|
+
{§startup-listener-admission}; its `start` activates request handling without
|
|
2669
|
+
rebinding. Persisted workspaces with
|
|
2526
2670
|
no durable work stay passive until first demand; activation publishes their
|
|
2527
2671
|
complete capabilities and documentation before the demanding operation
|
|
2528
2672
|
proceeds. `setup` is the readiness boundary for every capability registered
|
|
2529
|
-
with Core: recovery may demand a workspace provider before `start`.
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2673
|
+
with Core: recovery may demand a workspace provider before `start`. For a
|
|
2674
|
+
pre-bound client interface, requests remain unavailable until `start`; every
|
|
2675
|
+
other module opens its module-owned exterior ingress only after recovery. No
|
|
2676
|
+
registered capability may depend on exterior ingress. Shutdown begins started
|
|
2677
|
+
and self-closing module closure in reverse order and surfaces aggregated close
|
|
2678
|
+
failures.
|
|
2533
2679
|
|
|
2534
2680
|
§module-discovery **Third-party daemon-module composition is manifest
|
|
2535
2681
|
discovery.** A package declares `plurnk: { kind: "module", module:
|
|
@@ -2650,6 +2796,11 @@ accepted model proposal converge on the same coordinator method; no family
|
|
|
2650
2796
|
invents a third management grammar, configuration path, proposal policy, or
|
|
2651
2797
|
hotload mechanism.
|
|
2652
2798
|
|
|
2799
|
+
Problem retryability is never inferred from numeric status. A coordinator
|
|
2800
|
+
failure names `retryable` only when its owning condition establishes whether an
|
|
2801
|
+
identical automatic replay is valid; in particular, absent Worker residency
|
|
2802
|
+
requires activation and is non-retryable as submitted.
|
|
2803
|
+
|
|
2653
2804
|
| Verb | Common contract |
|
|
2654
2805
|
|---|---|
|
|
2655
2806
|
| `list` | Project every definition with its origin, desired enabledness, and current state — `disabled`, `active`, `unavailable` with its exact Problem, or `authorization-required` — without exposing credentials. |
|
|
@@ -2663,7 +2814,9 @@ hotload mechanism.
|
|
|
2663
2814
|
declares its family (the action segment and EXEC tag), its one namespace owner,
|
|
2664
2815
|
the exact definition schema one `add` accepts, its service-contributed
|
|
2665
2816
|
definitions with their default enabledness, inert discovery, admission of an
|
|
2666
|
-
authored definition
|
|
2817
|
+
authored definition — told whether a client action or a model operation authored it, so a
|
|
2818
|
+
family may bound the model's authority ({§members-model-scope}) — two-phase preparation of
|
|
2819
|
+
the enabled set, and teardown.
|
|
2667
2820
|
Preparation returns the family's runtimes, its generated documents, one outcome
|
|
2668
2821
|
per enabled alias, and a snapshot with `commit`/`abort`; the coordinator
|
|
2669
2822
|
never tears down a previous snapshot behind the adapter — it commits after a
|
|
@@ -2713,8 +2866,12 @@ family per Worker.** Every activated Worker publishes, for each registered
|
|
|
2713
2866
|
family, one executor tagged with the family name whose registered targets are
|
|
2714
2867
|
exactly the six verbs; its documents render through
|
|
2715
2868
|
{§tools-resource-materialization} like every family, so the model learns the
|
|
2716
|
-
manager from `_plurnk/
|
|
2717
|
-
teaching.
|
|
2869
|
+
manager from `_plurnk/plurnk/<family>.md` and never from hand-written
|
|
2870
|
+
teaching. That document lists the six verbs in lifecycle order and teaches the
|
|
2871
|
+
definition from the family's own schema — one exact `add` example and a table of
|
|
2872
|
+
every field with its type, requirement, and meaning — and carries the family's own
|
|
2873
|
+
`discover` contract when the generic one does not fit; the model composes an `add`
|
|
2874
|
+
from the document alone, without a probe. `list` and `discover` are `read` effects and run ungated; `add`,
|
|
2718
2875
|
`enable`, `disable`, and `remove` are `host` effects and propose through
|
|
2719
2876
|
the ordinary Exec proposal lifecycle. A verb's JSON outcome streams into the
|
|
2720
2877
|
family's output entry. `ExecArgs` carries no Worker identity, which is why
|
|
@@ -2745,7 +2902,7 @@ Core's behavior behind them.
|
|
|
2745
2902
|
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates and delivers one accept, reject, or cancel decision to the engine. An unknown or already-resolved id fails; the client protocol owns how the decision arrived. |
|
|
2746
2903
|
| §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. |
|
|
2747
2904
|
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates and delivers one resolved payload or cancellation. Unknown, ownerless, and already-resolved identities fail before affecting an operation. |
|
|
2748
|
-
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?,
|
|
2905
|
+
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?, policy?, openPaths?, selector?, childSelector? })` | Validates a model worker and complete loop policy, persists it 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. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
|
|
2749
2906
|
| §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. |
|
|
2750
2907
|
| §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, functionalityWorkerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop in the client worker, executing in the attached Worker'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. |
|
|
2751
2908
|
| Client observation | `look({ workspaceId, workerId, functionalityWorkerId, statement })` | Runs an already-parsed READ through the full resolver in the attached Worker's Functionality without a log row. A non-READ statement is rejected ({§op-look}). |
|
|
@@ -2754,13 +2911,12 @@ Core's behavior behind them.
|
|
|
2754
2911
|
| Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
|
|
2755
2912
|
| Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
|
|
2756
2913
|
| Client capabilities | `listClientDisplayCapabilities()` | Composes sorted scheme declarations ({§manifest-client-display}) followed by sorted MIME declarations ({§mimetype-client-display}) into the validated shared wire ({§client-display-capabilities}). The internal `exec` operation handler is excluded; its addressable runtime-tag scheme faces remain included. |
|
|
2757
|
-
| §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings
|
|
2914
|
+
| §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 worker Functionality. `projectRoot` is established here or the workspace remains headless. |
|
|
2758
2915
|
| §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. |
|
|
2759
2916
|
| §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. |
|
|
2760
2917
|
| §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin root worker with empty private history: a fresh conversation over the same world, not a fork or the stable default. |
|
|
2761
2918
|
| Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
|
|
2762
2919
|
| §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
|
|
2763
|
-
| Workspace metadata | `constrain(...)`, `unconstrain(...)`, `listConstraints(...)`, `listMembers(...)` | Owns the membership overlay and returns its resolved effects; clients do not reimplement constraint semantics. |
|
|
2764
2920
|
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. The positive limit defaults to 100; spawned and forked child prompts are excluded. |
|
|
2765
2921
|
| Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
|
|
2766
2922
|
| §methods-worker-read Worker topology | `readWorker({ workspaceId, identity })` | Ownership-bounds an exact id-or-name lookup and returns one durable Worker projection or `null` under {§application-worker-observation}. Supplying both identities or neither is invalid. |
|
|
@@ -2777,7 +2933,7 @@ already durable on the loop remains authoritative:
|
|
|
2777
2933
|
|-----------------------|------------------------------------------------------|--------------------------------|--------------------------------------|
|
|
2778
2934
|
| Provider/model | The resolved request selection must still agree. | Fold. | 409 provider conflict. |
|
|
2779
2935
|
| `maxTurns` | Keep the durable ceiling. | Fold. | 409 turn-ceiling conflict. |
|
|
2780
|
-
| Partial `
|
|
2936
|
+
| Partial `policy` | Keep the complete durable loop policy. | Fold. | 409 policy conflict. |
|
|
2781
2937
|
|
|
2782
2938
|
The conflict names both selections and directs the caller to cancel or conclude
|
|
2783
2939
|
the loop before changing configuration. A newly enqueued loop instead persists
|
|
@@ -2813,17 +2969,43 @@ creation. A client therefore cannot forge or resume an internal worker, insert
|
|
|
2813
2969
|
a non-mintable spelling, or make the client registry diverge from model worker
|
|
2814
2970
|
control.
|
|
2815
2971
|
|
|
2972
|
+
§capability-admission **One admission path owns external authority.** Core
|
|
2973
|
+
derives one or more `CapabilityDescriptor` demands from each routed statement,
|
|
2974
|
+
then evaluates the service, workspace, immutable worker-bound, mutable worker,
|
|
2975
|
+
and loop policy layers in that order. Every demand of a composed operation must
|
|
2976
|
+
survive before execution or proposal creation. A denial is an exact terse 403
|
|
2977
|
+
identifying the denied descriptor and owning policy scope; it never guesses the
|
|
2978
|
+
model's intent or recommends an alternate operation. COPY demands observation
|
|
2979
|
+
of its source and mutation of its destination; MOVE additionally demands
|
|
2980
|
+
mutation of its source; resource-backed EXEC demands its runtime plus source
|
|
2981
|
+
observation. Unknown schemes, runtimes,
|
|
2982
|
+
and tools continue to their ordinary resolver so capability policy cannot turn
|
|
2983
|
+
absence into a misleading restriction. The same resolver shapes generated
|
|
2984
|
+
resource examples, worker tool documents, and Turn0 surveys. PLAN, OPEN, FOLD,
|
|
2985
|
+
log KILL, and targetless SEND are log/program control rather than routed
|
|
2986
|
+
external demands and therefore remain outside capability selectors.
|
|
2987
|
+
|
|
2816
2988
|
§worker-settings **The worker carries its own behavioral rules.** The
|
|
2817
2989
|
workspace is the world — how things are; each worker is an actor inside it,
|
|
2818
2990
|
carrying the rules its loops obey. Those rules live in one JSON bag
|
|
2819
2991
|
(`workers.settings`), declared by the client at worker creation and mutable
|
|
2820
|
-
between loops through `
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2992
|
+
between loops through `readWorkerCapabilities`/`setWorkerCapabilities`; the
|
|
2993
|
+
public operation is specifically capability-shaped rather than exposing the
|
|
2994
|
+
internal persistence bag. Input is validated at the client boundary, and
|
|
2995
|
+
unknown keys never persist. A fork begins with a default empty mutable bag, but
|
|
2996
|
+
its immutable `capability_bound` captures the delegating actor's effective
|
|
2997
|
+
authority under {§worker-delegation-inherits-policy}. Service and workspace
|
|
2998
|
+
policies remain live ceilings; worker and loop policies may narrow but never
|
|
2999
|
+
widen them. Malformed persisted settings or bounds fail at their owning reader
|
|
3000
|
+
with the worker coordinate and cause rather than silently granting defaults.
|
|
3001
|
+
|
|
3002
|
+
§worker-capability-inspection **Client inspection uses the admission
|
|
3003
|
+
resolver.** The Worker capability actions return the contracts-owned
|
|
3004
|
+
`CapabilityProjection` {§capability-policy-projection}: service, workspace, immutable Worker bound, mutable
|
|
3005
|
+
Worker policy, and their normalized effective intersection. The projection is
|
|
3006
|
+
computed by the same resolver used by dispatch and packet shaping. Changing
|
|
3007
|
+
the mutable layer returns a fresh complete projection, so a client cannot
|
|
3008
|
+
mistake a requested widening for effective authority.
|
|
2827
3009
|
|
|
2828
3010
|
§question-tool **The native request-user-input tool.** Core registers one
|
|
2829
3011
|
in-process `question` runtime at boot. Its body is the MCP2 2026-07-28
|
|
@@ -2836,17 +3018,17 @@ client-interaction lifecycle — durable pause, reconnect discovery,
|
|
|
2836
3018
|
cancellation, and the answer-as-resolution all come from
|
|
2837
3019
|
{§client-interactions}; there is no loopback MCP and no proposal masquerade.
|
|
2838
3020
|
Effect `read`: the tool observes the human's answer and is never
|
|
2839
|
-
proposal-gated.
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
weights, and
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
3021
|
+
proposal-gated. Its runtime declares the `interaction` trait, which the shared
|
|
3022
|
+
resolver projects as access class `interact`; any capability-policy layer may
|
|
3023
|
+
therefore admit or deny it without a question-specific switch.
|
|
3024
|
+
|
|
3025
|
+
§worker-tool-admission **Tool visibility and execution share admission.** The
|
|
3026
|
+
reserved tool tree's FIND/READ faces drop a runtime or tool document whenever
|
|
3027
|
+
the effective worker-level capability layers deny its descriptor, before
|
|
3028
|
+
matching and rendering, so counts, weights, and catalog text agree. Turn0
|
|
3029
|
+
applies its loop layer to the same catalog projection. Dispatch evaluates that
|
|
3030
|
+
same descriptor and policy cascade at the operation boundary, never at
|
|
3031
|
+
registration; there is no separate per-tool availability system.
|
|
2850
3032
|
|
|
2851
3033
|
§model-catalog **Model discovery is a bounded local projection, not provider
|
|
2852
3034
|
activity.** Core composes the release-pinned Models.dev snapshot with
|
|
@@ -2955,7 +3137,7 @@ active lifecycle behind. LOOK text anchors resolve through the same
|
|
|
2955
3137
|
|
|
2956
3138
|
| Event | Payload | When fired |
|
|
2957
3139
|
|--------------------------------------------------------------|---------|------------|
|
|
2958
|
-
| §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A `log_entries` row is committed. |
|
|
3140
|
+
| §notifications-log-entry-notify `log/entry` | `{ entry: LogEntry }` | A non-proposed `log_entries` row is committed, or a proposed row reaches terminal settlement under {§proposal-proposed-hidden}. Delivery completes before a later event may terminate the owning Loop. |
|
|
2959
3141
|
| §notifications-loop-terminated `loop/terminated` | `{ workerId, loopId, result, hitMaxTurns, turnIds, usage: { accounting, curationWeight, curationBudget, contextTokens, contextCapacity, meta }, attributions }` | One loop reaches a terminal state. `result` is the exact universal operation result, including its RFC 9457 Problem Details on failure. `accounting` is the loop's contracts-owned {§provider-accounting}; the two curation facts and two physical-context facts follow {§tokenomics-client-gauge}; `meta` is that turn's opaque provider bag. `attributions` is the sorted union of exact provider-request evidence ({§attribution}), separate from accounting. Worker and loop are an inseparable owning coordinate. |
|
|
2960
3142
|
| §notifications-loop-packet `loop/packet` | `{ workerId, loopId, packetCount }` | One provider packet becomes durable. `packetCount` is the exact count of packet-bearing turns in that Loop; packetless producer turns and physical provider retries never contribute. |
|
|
2961
3143
|
| §notifications-loop-proposal `loop/proposal` | contracts-owned `ProposalProjection` | Dispatch pauses on a durable 202 proposal. `disposition` is the sole authority for whether a client presents review UI; live and reconnect share {§proposal-projection}. |
|
|
@@ -2964,8 +3146,8 @@ active lifecycle behind. LOOK text anchors resolve through the same
|
|
|
2964
3146
|
| §notifications-workspace-branch-batch `workspace/branch-batch` | Branch-batch lifecycle payload | A branch batch enters queued, running, completed, failed, or recovery-required state. |
|
|
2965
3147
|
| §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 entry owner and read perspective; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic plugin notification capability does not require it. It carries metadata, not content; consumers read bytes from the stated worker perspective. |
|
|
2966
3148
|
| §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the entry owner; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
|
|
2967
|
-
| §notifications-notice-event `notice/event` | `{ loopId, notice: Notice }` | A transient observation or progress notice occurs. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
|
|
2968
|
-
| §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, phase, delta? }` | A main emission call exposes readable reasoning.
|
|
3149
|
+
| §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. |
|
|
3150
|
+
| §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. |
|
|
2969
3151
|
|
|
2970
3152
|
§notifications-stream-event-failure-isolation The plugin-facing
|
|
2971
3153
|
`NotifyCaps.streamEvent()` remains a synchronous advisory call while core
|
|
@@ -3042,11 +3224,12 @@ Conditional absence never reorders the surviving default sections.
|
|
|
3042
3224
|
| 6 | user | `log` | Append-mostly model-visible history. |
|
|
3043
3225
|
| 7 | user | `child-streams` | Per-turn status; empty content is omitted. |
|
|
3044
3226
|
| 8 | user | `child-workers` | Per-turn status; empty content is omitted. |
|
|
3045
|
-
| 9 | user | `
|
|
3046
|
-
| 10 | user | `
|
|
3047
|
-
| 11 | user | `
|
|
3048
|
-
| 12 | user | `
|
|
3049
|
-
| 13 | user | `
|
|
3227
|
+
| 9 | user | `parent-worker` | The worker's parent by name; omitted for a root worker. |
|
|
3228
|
+
| 10 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
|
|
3229
|
+
| 11 | user | `notices` | Per-turn observations; empty content is omitted. |
|
|
3230
|
+
| 12 | user | `git` | Per-turn workspace status; empty content is omitted. |
|
|
3231
|
+
| 13 | user | `budget` | `Context Token Budget`; omitted when capacity is unknown. |
|
|
3232
|
+
| 14 | user | `prompt` | Current prompt-entry pointers. |
|
|
3050
3233
|
|
|
3051
3234
|
The order favors prefix-cache locality where semantics permit: the definition
|
|
3052
3235
|
and privileged policy lead the resource directory, while the append-mostly
|
|
@@ -3102,9 +3285,10 @@ time of measurement.
|
|
|
3102
3285
|
- **Derivation is exhaustive and demand-led.** Explicit searchable-resource changes may start one coalesced warm. Passive creation and attachment do not. The first model turn starts or joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
|
|
3103
3286
|
- §membership-binary-sniff **Binary truth beats the label; no entry dominates the corpus.** A tracked member whose HEAD bytes contain NUL enters {§membership-source-projection} as `application/octet-stream` **regardless of what extension-based detection claims**; byte-level evidence outranks a default label. Every eligible text is tiled losslessly to the embedder window and every tile is embedded before its derivation attaches; semantic ranking max-pools the best chunk per candidate.
|
|
3104
3287
|
- §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
|
|
3105
|
-
- §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section
|
|
3288
|
+
- §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section begins with exactly two fields on separate lines: `tokensActiveTotal: N (P%)` and `tokensActiveMax: M`. It never presents their difference as free response tokens. The protocol definition directly requires FOLD, KILL, or trimming of irrelevant log items to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Generic packet composition and physical-token speculation are absent.
|
|
3289
|
+
- §tokenomics-pressure-inventory **Pressure identifies its reclaimable concentration.** When the ordinary two-field packet measurement reaches 80% of `tokensActiveMax`, the budget section may append `YOU MUST FOLD, KILL, or trim superseded, stale, or irrelevant log content.` followed by `Largest Log Items`: at most five currently OPEN, addressed log bodies, ordered by `tokensActive` descending and then `log:///` path. Each item repeats only that row's `tokensBody` and `tokensActive`. Folded and bodyless rows cannot enter the list because FOLD would reclaim no body from them. The largest prefix that fits may be shown; this conditional block never pushes an otherwise admissible packet over its maximum. Its own weight participates in the final fixed-point `tokensActiveTotal`.
|
|
3106
3290
|
- §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as stable content identity. `weight` is stored beside that content and is never keyed or recomputed by model.
|
|
3107
|
-
- §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own
|
|
3291
|
+
- §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity beneath the normalized {§inference-ledger} and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` and `embedding_calls` own domain response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, embeddings, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. Each derived aggregate usage field independently sums its reported quantity, so heterogeneous detail coverage remains partial rather than becoming fictitiously complete. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
|
|
3108
3292
|
- §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `tokensActiveTotal` and its percentage above `tokensActiveMax`. Crossing the maximum diverts that would-be model turn into {§overflow-turn}; no over-ceiling packet reaches `provider.generate`. Automatic recovery does not create a strike or consume a model-turn allowance.
|
|
3109
3293
|
|
|
3110
3294
|
### §membership Workspace identity, membership, disk co-location
|
|
@@ -3114,16 +3298,13 @@ not participate in this disk loop.
|
|
|
3114
3298
|
|
|
3115
3299
|
```mermaid
|
|
3116
3300
|
flowchart LR
|
|
3117
|
-
git["Git tracked
|
|
3118
|
-
|
|
3119
|
-
|
|
3301
|
+
git["Git tracked"] --> resolve["Resolve workspace membership"]
|
|
3302
|
+
include["include"] --> resolve
|
|
3303
|
+
exclude["exclude"] -->|subtract| resolve
|
|
3120
3304
|
resolve --> materialize["Pre-turn materialize<br/>disk → file snapshot"]
|
|
3121
3305
|
materialize --> read["READ snapshot"]
|
|
3122
3306
|
materialize --> edit["EDIT against snapshot"]
|
|
3123
|
-
edit -->
|
|
3124
|
-
view["view"] -->|marks member read-only| gate
|
|
3125
|
-
gate -->|yes| refused["403; no proposal"]
|
|
3126
|
-
gate -->|no| proposal["Proposal"]
|
|
3307
|
+
edit --> proposal["Proposal"]
|
|
3127
3308
|
proposal -->|"client accepts or loop auto"| cas["synced_sig compare-and-swap"]
|
|
3128
3309
|
cas -->|"file snapshot → disk"| project["Project file"]
|
|
3129
3310
|
project --> materialize
|
|
@@ -3132,11 +3313,11 @@ flowchart LR
|
|
|
3132
3313
|
| Concern | Owner and representation |
|
|
3133
3314
|
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3134
3315
|
| Workspace identity | `workspaces.project_root`; null is headless. There is no separate project entity. |
|
|
3135
|
-
| File visibility | Workspace-tier resolved membership: `(
|
|
3316
|
+
| File visibility | Workspace-tier resolved membership: `(tracked files ∪ include) − exclude` ({§membership-baseline}). Every worker sees the same result. |
|
|
3136
3317
|
| File reads | READ returns the materialized file snapshot stored in the entry body channel; it does not read disk directly. |
|
|
3137
3318
|
| File writes | EDIT proposes against that snapshot. Only accepted resolution with the captured `synced_sig` writes the project file. |
|
|
3138
3319
|
| Internal entries | Workspace or worker entries are canonical store state. Writing one never implies a project-file write. |
|
|
3139
|
-
| Authority | Service flags set the membership ceiling;
|
|
3320
|
+
| Authority | Service flags set the membership ceiling; the `members` family's definitions include and exclude within it; client or loop auto resolves proposals. `origin` is attribution. |
|
|
3140
3321
|
|
|
3141
3322
|
§web-search-retrieval **Web discovery is an ordinary MCP concern; retrieval is a first-class composition.** PLURNK owns no search runtime: a search-capable MCP server (e.g. Brave Search) participates through the ordinary MCP contract — admission, read-effect classification, tool documentation, and packet projection are identical to every other MCP tool ({§mcp-tool-presentation}). An executor that wants to materialize discovered pages uses the generic `content: null` `entry()` request ({§exec-entry-sink}): the guarded `WebFetcher` sink fetches candidates in parallel, off the write-serialization chain, and materializes successful bodies as ordinary HTTP entries. Every candidate whose `entry()` call rejects, regardless of failure reason, is mechanically omitted from the model-facing result directory; survivors retain upstream order. Without an entry sink the executor cannot test materialization and omits the verdict.
|
|
3142
3323
|
|
|
@@ -3155,31 +3336,58 @@ and never re-fetch a match.
|
|
|
3155
3336
|
|
|
3156
3337
|
**Git is the substrate and the repository is the boundary:**
|
|
3157
3338
|
|
|
3339
|
+
- §membership-baseline **The baseline contract — chiseled (#400).** To a workspace a
|
|
3340
|
+
project file is exactly one of three things: **invisible**, **added**, or **tracked
|
|
3341
|
+
by git**. There is no fourth category. Membership — what the model can READ and
|
|
3342
|
+
FIND, what is materialized into the store, what a packet can ship to a provider — is
|
|
3343
|
+
the allowlist `(tracked ∪ include) − exclude` and nothing else. No file is a member because
|
|
3344
|
+
it exists on disk, because git does not ignore it, or because a model would find it
|
|
3345
|
+
convenient: ambient admission of untracked files is prohibited, so a workspace rooted
|
|
3346
|
+
in a home directory or a monorepo exposes exactly what was committed or added (the
|
|
3347
|
+
non-member rule, {§fs-write-nonmember}: no read, no leak, no overwrite). Every
|
|
3348
|
+
exception is a named clause in the register ({§membership-model-universe}), admits
|
|
3349
|
+
files by an exact creation record with recorded provenance, and never by `git add`.
|
|
3350
|
+
Changing this clause, the register, or the composition is an operator ruling recorded
|
|
3351
|
+
on the issue that lands it — never an implementation convenience, never a side effect
|
|
3352
|
+
of making a file visible to solve the problem at hand. The 2026-07-12 – 2026-08-27
|
|
3353
|
+
"untracked-but-not-ignored" ambient admission is retired.
|
|
3354
|
+
- §membership-model-universe **The exception register — files in the model's universe.**
|
|
3355
|
+
Admitted by exact creation records (`source: "create"`, origin `constraint`), never
|
|
3356
|
+
staged: (1) a file an accepted EDIT creates; (2) a COPY/MOVE destination
|
|
3357
|
+
({§membership-create-parents}). Admitted by a published standard as projected
|
|
3358
|
+
instruction documents — never as members: (3) the project's `AGENTS.md` and nested
|
|
3359
|
+
`AGENTS.md` files ({§turn0-agents-stunt}, #346), read from disk regardless of git status
|
|
3360
|
+
and materialized as `worker://~/_plurnk/agents.md` and
|
|
3361
|
+
`worker://~/_plurnk/instructions/<subtree>/AGENTS.md`; the file itself is a member
|
|
3362
|
+
only when tracked or added, and the standard never overrides the operator's
|
|
3363
|
+
exclusions — an `AGENTS.md` the repository ignores or an exclusion matches
|
|
3364
|
+
is not projected. (4) A definition the model proposes through the `members`
|
|
3365
|
+
family ({§members-functionality}), admitted only under the operator's ceiling
|
|
3366
|
+
`PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` (shipped `none`), projected with source
|
|
3367
|
+
`model`, and never admitted past the repository's ignore rules or an exclusion.
|
|
3368
|
+
Nothing else.
|
|
3158
3369
|
- §membership-git-membership The workspace owns the Git repository containing
|
|
3159
3370
|
`project_root`. Its tracked files (`git ls-files` semantics) are members with
|
|
3160
3371
|
no explicit overlay; when the root is a package inside a monorepo, the
|
|
3161
3372
|
repository's other packages are members at root-relative paths. An unrelated
|
|
3162
3373
|
or nested independent repository is not discovered or managed by this
|
|
3163
|
-
workspace. When Git is absent there is no filesystem walk;
|
|
3164
|
-
sole source.
|
|
3374
|
+
workspace. When Git is absent there is no filesystem walk; member definitions are
|
|
3375
|
+
then the sole source.
|
|
3165
3376
|
- §git-native-default **Core Git reads use native Git.** Membership and status
|
|
3166
3377
|
execute the installed Git binary. An absent or failed binary yields no
|
|
3167
3378
|
automatic Git membership or status; core has no alternate implementation or
|
|
3168
|
-
fallback.
|
|
3169
|
-
model-invoked subset for shellless deployments, not an ambient Git backend.
|
|
3379
|
+
fallback.
|
|
3170
3380
|
- §membership-git-hermetic Native Git runs with ambient `GIT_*` and
|
|
3171
3381
|
global/system config scrubbed, so repository identity follows `project_root`,
|
|
3172
3382
|
never the daemon's launch environment.
|
|
3173
3383
|
- §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** crosses the creation matrix in {§fs-write-surface}; proposal acceptance cannot bypass its scope, exclusion, or incorporation rules. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
|
|
3174
3384
|
- §membership-create-parents **Parent-complete creation.** An accepted File creation—whether authored as EDIT or as a COPY/MOVE destination—recursively creates missing parent directories before writing and registering the new member.
|
|
3175
3385
|
|
|
3176
|
-
**The overlay — `
|
|
3386
|
+
**The overlay — `include | exclude`.** `workspace_constraints` holds the `members` family's projected definitions and the engine's creation records ({§members-projection}). Resolved membership is `(project repository files ∪ include) − exclude`.
|
|
3177
3387
|
|
|
3178
|
-
- §membership-auto-add **Auto-add** — the project repository's ambient membership is its tracked `ls-files`
|
|
3179
|
-
- §membership-overlay-
|
|
3180
|
-
- §membership-overlay-
|
|
3181
|
-
- §membership-overlay-view **`view`** — keep a member readable but refuse `File.edit`, 403'd at the membership check before any diff. (Admitting an untracked file as `view` rides on `pick`'s scan.)
|
|
3182
|
-
- §membership-resolved-effects **Resolved effect is a read, not a re-derivation.** `workspace.members` surfaces each candidate's resolved effect — `(ls-files ∪ pick) − hide` tagged `member` / `view`, plus the `hide`-excluded `hidden` set — so a client signs file visibility (member / read-only / ignored) without reimplementing the overlay glob-matching. The daemon owns git + the globs; the per-file effect is its to resolve, the client's to render.
|
|
3388
|
+
- §membership-auto-add **Auto-add** — the project repository's ambient membership is its tracked `ls-files`, with `git` origin; an untracked file is never an ambient member ({§membership-baseline}). An accepted creation is incorporated by an exact creation record, never by `git add` ({§membership-model-universe}); a record that cannot be written fails the creation transaction, never an orphan ({§file-create-no-orphans}).
|
|
3389
|
+
- §membership-overlay-include **`include`** — admit a file Git misses through a targeted pattern scan (files only), with `constraint` origin. `source: "members"` is a projected human definition, `source: "model"` a projected model definition, `source: "create"` the exact durable record of an accepted creation. Only `members` inclusions override active Git ignore. In a Git-absent root, inclusions are the sole file-membership source.
|
|
3390
|
+
- §membership-overlay-exclude **`exclude`** — a `!glob` definition removes a tracked or included file: resolution drops matches (`node:path.matchesGlob`) and reconciles so the entry set *equals* the member set. The lever to exclude a committed-but-oversized or sensitive tracked file; exclusions mask creation records without deleting their provenance ({§fs-create-masked}).
|
|
3183
3391
|
|
|
3184
3392
|
**File ops act on the entry, not the disk; the two reconcile only at gates.** A `file:///` member is a row whose body channel holds its *materialized model-readable snapshot*. READ returns that channel; EDIT diffs against editable text snapshots — neither reaches the filesystem directly. Entry and disk reconcile at exactly two gates: the **pre-turn materialize** (disk → entry, below) and the **accept-time write-back** (entry → disk, {§proposal}). Between the gates the entry is the truth the model curates against, and `synced_sig` — the member's last-synced disk stat (`mtime:size`) — is the version token both gates compare on.
|
|
3185
3393
|
|
|
@@ -3194,7 +3402,21 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
|
|
|
3194
3402
|
| Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
|
|
3195
3403
|
| Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
|
|
3196
3404
|
|
|
3197
|
-
§
|
|
3405
|
+
§membership-materialization-limit **A pathological member degrades, never the
|
|
3406
|
+
workspace.** `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` is a required positive
|
|
3407
|
+
byte ceiling over one disk source before Core reads it into the canonical file
|
|
3408
|
+
snapshot. Its valid range is `1..104857600`, bounded by the channel storage
|
|
3409
|
+
contract, and it ships at that 100 MiB maximum. An oversized path remains a real member
|
|
3410
|
+
with an empty body channel carrying a durable 413 producer result; no diagnostic
|
|
3411
|
+
sentinel impersonates file content. READ therefore names the path, observed bytes,
|
|
3412
|
+
ceiling, and recovery through the ordinary result contract, while EDIT returns the
|
|
3413
|
+
same 413 instead of diffing against a fictitious empty baseline. Core records the
|
|
3414
|
+
materialization disposition and ceiling privately, so an unchanged disk member is
|
|
3415
|
+
reconsidered when the operator changes the policy and otherwise remains a stat-only
|
|
3416
|
+
no-op. The file write gate independently stats the source against the same ceiling,
|
|
3417
|
+
so safety does not depend on a background warm winning a client-operation race.
|
|
3418
|
+
|
|
3419
|
+
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling inference or its accounting. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
|
|
3198
3420
|
|
|
3199
3421
|
The artifact also retains a positive `{§mimetype-parse-issues}` count and the
|
|
3200
3422
|
full normalized `{§mimetype-summary}` when the exact parsed channel reported
|
|
@@ -3215,13 +3437,13 @@ every non-vector attachment with its disposition and reason. Successful
|
|
|
3215
3437
|
optional projection degradations continue indexing and surface their framework
|
|
3216
3438
|
Notice once per identical observation in a maintenance pass.
|
|
3217
3439
|
|
|
3218
|
-
§semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
|
|
3440
|
+
§semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter and deterministic tiling revision to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, tiling behavior, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
|
|
3219
3441
|
|
|
3220
3442
|
Lossless chunk admission requires either the embedder's own counter or an exact fallback tokenizer. An empirical estimate never proves that content fits the declared token window. When pending readable content would require vectors and only an estimate is available, maintenance surfaces its degradation Notice and fails before embedding or attaching a derivation; no/disabled embedding and the established empty, binary, excluded, and maximum-size dispositions remain non-vector outcomes.
|
|
3221
3443
|
|
|
3222
|
-
§semantic-max-embed-size **Embedding has
|
|
3444
|
+
§semantic-max-embed-size **Embedding has a bounded size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is the maximum UTF-8 byte size eligible for vectors; the shipped default is 262144 and `0` is the explicit unlimited override. The measured value is the exact addressed channel representation READ exposes and the embedder receives. When the ceiling rejects an oversized representation, its channel remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected channels. Client notices report compact aggregate progress; the digest records every non-vector address, terminal disposition, and reason for forensic inspection.
|
|
3223
3445
|
|
|
3224
|
-
§membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
|
|
3446
|
+
§membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature and materialization policy is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection} and {§membership-materialization-limit}.
|
|
3225
3447
|
|
|
3226
3448
|
§membership-emi-divergence-signal **EMI divergence evidence.** The detector that gates the work *is* the one that records this — one mechanism, not a second full read. When change detection finds a member moved out-of-band, the runtime actor records an `EDIT`-shaped row naming the file with `source="file"`; it does not broadcast that workspace change into unrelated workers' logs ({§env-delta-filesystem-narration}). The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence. The current file remains ordinarily addressable. A stale anchored edit rejects under {§line-anchors}; a disk race after proposal rejects under {§membership-edit-write-cas}.
|
|
3227
3449
|
|
|
@@ -3231,13 +3453,13 @@ The version travels *with the proposal*, never re-read from the entry at accept:
|
|
|
3231
3453
|
|
|
3232
3454
|
The CAS is the **hard backstop**, at the moment of writing, on every accept path. It composes with the model-facing {§line-anchors}: an anchor rejects a target whose relevant neighborhood changed before dispatch, while the CAS refuses to write against a snapshot disk left after proposal. An unanchored edit deliberately claims no pre-dispatch stale-view guarantee.
|
|
3233
3455
|
|
|
3234
|
-
§membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` (default) includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving
|
|
3456
|
+
§membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` (default) includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving member definitions as the only membership source. `ALLOWED` gates `AUTO`.
|
|
3235
3457
|
|
|
3236
3458
|
**Rationale.** Workspace is the right scope unit and the containing Git repository is its ordinary development boundary. Membership curation is tiered: Git bounds it by tracking, the client supersedes by overlay, and the model curates its render by READ/FOLD. Supporting several independent repositories as one world would require Plurnk-owned topology, synchronization, and model teaching that Git already solves cleanly by treating them as separate workspaces.
|
|
3237
3459
|
|
|
3238
|
-
**Schema.** The version-1 baseline stores
|
|
3239
|
-
|
|
3240
|
-
|
|
3460
|
+
**Schema.** The version-1 baseline stores the normalized {§inference-ledger},
|
|
3461
|
+
its generation or embedding specialization, emission admission, and cardinal
|
|
3462
|
+
physical requests. Its constraints distinguish pending calls, response
|
|
3241
3463
|
evidence, and response-less errors while monetary classification remains
|
|
3242
3464
|
explicit.
|
|
3243
3465
|
|
|
@@ -3271,11 +3493,15 @@ provider I/O.** After packet assembly, Core compares render weight
|
|
|
3271
3493
|
({§tokenomics}) with the provider-derived curation ceiling. An admitted packet
|
|
3272
3494
|
ships untouched. An over-ceiling candidate is never stored as a model request
|
|
3273
3495
|
and never reaches `provider.generate`; its already-created database turn instead
|
|
3274
|
-
becomes a packetless `_plurnk` turn.
|
|
3496
|
+
becomes a packetless `_plurnk` turn. Engine-side inference already booked to that
|
|
3497
|
+
turn (embedding work from semantic attachment) never blocks the transition; only
|
|
3498
|
+
a model emission or BARE call does, because those are model history and the
|
|
3499
|
+
producer cannot change beneath them (run67, 2026-08-29: a 90k-window model died
|
|
3500
|
+
at its first overflow because four embedding calls were counted as history). Packetless initialization and recovery turns
|
|
3275
3501
|
remain ordinary turn chronology but do not consume `maxTurns`, model-call,
|
|
3276
3502
|
emission-attempt, usage, or cost accounting.
|
|
3277
3503
|
|
|
3278
|
-
- §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its canonical {§plan-value} has one `medium`, `in_progress` entry whose content is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk
|
|
3504
|
+
- §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its canonical {§plan-value} has one `medium`, `in_progress` entry whose content is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk.` The final sentence requires the successor's substantive operations to be one dedicated, comprehensive bulk-curation program. Core authors this internal program with canonical PLAN and SEND framing. Its exact `turnOps` is born FOLDED; successful FOLD rows follow {§fold-open-meta-operations} and therefore remain durable but packet-suppressed. Every recovery row carries `_plurnk` and `overflow`; no model call, synthetic receipt, or parallel explanation exists.
|
|
3279
3505
|
- §overflow-turn-curation **The preceding turn owns the pressure it introduced.** Core deterministically selects every body already created in the packetless candidate turn, every body created by the immediately preceding completed turn in that worker's chronology, and every older body whose visibility that preceding turn's successful OPEN increased. Every selected body is FOLDed whole (`<1,-1>`) through ordinary dispatch. Already-wholly-folded and bodyless rows require no operation. Core performs no relevance judgment, exempts no operation or resource kind, reconstructs no interval delta, re-runs no authored selector, and chooses no unrelated older history.
|
|
3280
3506
|
- §overflow-turn-hard-413 **Recovery fails hard when the causal fold cannot fit.** After the ordinary FOLDs land, Core rebuilds and remeasures once. If the plan changes no visibility or the rebuilt request still exceeds the ceiling, the loop terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem; Core neither submits excess bytes nor chooses unrelated older history. Separately, every `provider.generate` assesses physical capacity under {§provider-surface-capacity}. Core may retry a provider capacity rejection only after withholding automatic prompt-body projection when that changes the request. If it cannot produce changed bytes or the changed request is still rejected, the request-only model turn and provider-owned Problem terminalize at **413 Content Too Large**.
|
|
3281
3507
|
|
|
@@ -3353,7 +3579,7 @@ ordinary operation evidence still reaches that child's direct parent.
|
|
|
3353
3579
|
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3354
3580
|
| `worker_id` | The worker whose self-contained log owns the materialized row. |
|
|
3355
3581
|
| `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
|
|
3356
|
-
| `source` | The immediate causal identity in this log
|
|
3582
|
+
| `source` | The immediate causal identity in this log: a lineage or commons observation uses canonical `worker://<producer>`, a terminal stream observation uses its causal `log:///<coord>/EXEC`, and a subsystem observation may use its stable token (for example `file`). Self-authored rows omit it. |
|
|
3357
3583
|
|
|
3358
3584
|
§env-delta-no-coalescing **Activity is never coalesced.** Each admitted child
|
|
3359
3585
|
operation and each commons mutation has one occurrence identity. Combining
|
|
@@ -3389,6 +3615,8 @@ flowchart LR
|
|
|
3389
3615
|
body --> recall["READ log:///…<br/>recalls canonical body"]
|
|
3390
3616
|
```
|
|
3391
3617
|
|
|
3618
|
+
§edit-receipt-anchored-context **An applied EDIT's resulting context carries anchors.** The bounded resulting context each effect renders (`PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` around and inside the landed region) is rendered exactly as a READ renders — `@xxxxx L:text`, hashed with the resource's READ identity ({§line-anchors}) — so the next batch cites the landed lines by anchor without a READ; both requiems of 2026-08-29 asked for this. A scheme that supplies no identity keeps the line-numbered form.
|
|
3619
|
+
|
|
3392
3620
|
§edit-result-receipt-projection **EDIT projects the scheme-owned batch
|
|
3393
3621
|
receipt.** The scheme framework owns the exact aggregate shape
|
|
3394
3622
|
({§scheme-edit-batch-receipt}). Core validates it and projects the result
|
|
@@ -3401,7 +3629,7 @@ the aggregate remains dispatch coordination state.
|
|
|
3401
3629
|
| -------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
3402
3630
|
| Full `revision` | `rev` abbreviated to `PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS` | SHA-256 identity of the complete landed channel body; display correlation only, never a lookup or compare-and-swap token. |
|
|
3403
3631
|
| `unit`, `before`, `after` | `extent` | Whole-line batches use line counts. A batch containing any exact four-coordinate edit uses Unicode code-point counts. |
|
|
3404
|
-
| `parseIssues`
|
|
3632
|
+
| `parseIssues.before`, `parseIssues.after` | `parseIssues` as `before→after` | Parser-recovery counts for complete source and landed revisions; omitted when both are clean or either is unavailable. |
|
|
3405
3633
|
| `effect.requested`, `source`, `result` | `range` | The admitted marker and its normalized mapping from the common source snapshot into the landed body. |
|
|
3406
3634
|
| `effect.removed`, `inserted` | `change` | Removed and inserted counts in the receipt unit. |
|
|
3407
3635
|
| `effect.context` | Canonical row body | Numbered physical lines at each landed boundary, bounded symmetrically by `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES`. |
|
|
@@ -3410,7 +3638,7 @@ the aggregate remains dispatch coordination state.
|
|
|
3410
3638
|
|
|
3411
3639
|
§edit-result-receipt-truth **Receipts describe committed state.** Every row in
|
|
3412
3640
|
one resource-channel EDIT batch carries the same landed revision, extent, and
|
|
3413
|
-
optional
|
|
3641
|
+
optional `parseIssues` transition for the complete source and landed revisions.
|
|
3414
3642
|
When the proposed batch lands unchanged, each row also carries its own requested
|
|
3415
3643
|
marker, source/result mapping, counts, and context. For configured count `C`,
|
|
3416
3644
|
the context contains up to `C` surrounding lines and the first and last `C`
|
|
@@ -3467,7 +3695,7 @@ inspection is advisory and occurs against complete resulting text after
|
|
|
3467
3695
|
successful application. A handler or parser failure emits a Notice, omits
|
|
3468
3696
|
`parseIssues`, and never changes the mutation outcome.
|
|
3469
3697
|
|
|
3470
|
-
### §proposal-ownership Loop
|
|
3698
|
+
### §proposal-ownership Loop disposition and client YOLO
|
|
3471
3699
|
|
|
3472
3700
|
Side-effecting operations propose ({§exec}) and pause dispatch at 202 for an
|
|
3473
3701
|
authority decision ({§engine-rails}, {§methods}). Automatic acceptance has two
|
|
@@ -3475,14 +3703,14 @@ distinct owners:
|
|
|
3475
3703
|
|
|
3476
3704
|
| Mechanism | Authority path | Intended use |
|
|
3477
3705
|
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
3478
|
-
| §proposal-ownership-loop-auto **Loop
|
|
3479
|
-
| **Client-side YOLO** (`--yolo` / `PLURNK_YOLO`) |
|
|
3706
|
+
| §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. |
|
|
3707
|
+
| **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. |
|
|
3480
3708
|
|
|
3481
3709
|
Core cannot distinguish client-side YOLO from a fast human acceptance and does
|
|
3482
3710
|
not need to. Loop auto keeps authority inside the loop; client-side YOLO acts
|
|
3483
3711
|
only after authority crosses the client boundary.
|
|
3484
3712
|
|
|
3485
|
-
§proposal-ownership-notification **The notification carries disposition, not policy inputs.** `loop/proposal` carries the core-owned `ProposalDisposition` ({§notifications}, {§proposal-disposition}). A connected client presents only `owner="client"`; it never reimplements
|
|
3713
|
+
§proposal-ownership-notification **The notification carries disposition, not policy inputs.** `loop/proposal` carries the core-owned `ProposalDisposition` ({§notifications}, {§proposal-disposition}). A connected client presents only `owner="client"`; it never reimplements policy from operation or attrs.
|
|
3486
3714
|
|
|
3487
3715
|
---
|
|
3488
3716
|
|
|
@@ -3492,8 +3720,9 @@ only after authority crosses the client boundary.
|
|
|
3492
3720
|
when an emission is admitted, its response.** Core assembles and measures the
|
|
3493
3721
|
request under {§packet-assembly}. An admitted response extends that same record
|
|
3494
3722
|
before the turn closes; a failed provider call or exhausted invalid emission
|
|
3495
|
-
leaves the request-only record, while rejected exchanges remain in
|
|
3496
|
-
`model_calls` with
|
|
3723
|
+
leaves the request-only record, while rejected exchanges remain in their
|
|
3724
|
+
`inference_calls`/`model_calls` evidence with classification in
|
|
3725
|
+
`turn_attempts`.
|
|
3497
3726
|
|
|
3498
3727
|
| Turn state | `turns.packet` |
|
|
3499
3728
|
| ----------------------------- | ----------------------------------------------- |
|
|
@@ -3520,9 +3749,10 @@ source independently from this optional model-exchange record; a request-only
|
|
|
3520
3749
|
turn receives a note instead of a fabricated response.
|
|
3521
3750
|
|
|
3522
3751
|
§digest-turn-artifact-identity **Digest packet artifacts project durable turns.**
|
|
3523
|
-
After selectors are applied, digest retains every turn with exact `turnOps
|
|
3524
|
-
|
|
3525
|
-
them contiguously from `packet000`. The
|
|
3752
|
+
After selectors are applied, digest retains every turn with exact `turnOps`, a
|
|
3753
|
+
valid stored provider request, or malformed stored packet evidence; orders those
|
|
3754
|
+
turns by durable chronology; and names them contiguously from `packet000`. The
|
|
3755
|
+
producer does not affect projection.
|
|
3526
3756
|
|
|
3527
3757
|
| Artifact | Present when | Authority |
|
|
3528
3758
|
|----------|--------------|-----------|
|
|
@@ -3530,6 +3760,8 @@ them contiguously from `packet000`. The producer does not affect projection.
|
|
|
3530
3760
|
| `packetNNN.system.md`, `packetNNN.user.md` | The turn stored a provider request | Stored packet sections projected through `PacketWire` |
|
|
3531
3761
|
| `packetNNN.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
|
|
3532
3762
|
| `packetNNN.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
|
|
3763
|
+
| `packetNNN.packet.raw.txt` | The stored packet fails typed validation | Exact stored packet text |
|
|
3764
|
+
| `packetNNN.packet.invalid.json` | The stored packet fails typed validation | Turn identity and complete validation error chain |
|
|
3533
3765
|
|
|
3534
3766
|
A source-backed turn without provider participation therefore produces only
|
|
3535
3767
|
`assistant.md`; a request-only turn produces no fabricated assistant. A
|
|
@@ -3633,7 +3865,9 @@ retain distinct contracts and lifetimes.
|
|
|
3633
3865
|
- §log-row-self-explains **Every ≥400 pointer names a record that states its
|
|
3634
3866
|
why.** A model-operation failure is the model's own operation result; its
|
|
3635
3867
|
Problem Details `instance` is that row's `log:///` URI and packet wire renders
|
|
3636
|
-
the
|
|
3868
|
+
the contracts-owned compact `{§problem-projection}` on its meta line whether
|
|
3869
|
+
folded or open. The enclosing row owns status, model-facing path, source, and target;
|
|
3870
|
+
an identical extension is not repeated inside the projection. No
|
|
3637
3871
|
separate item is minted for operation failures. Actionless engine rails mint
|
|
3638
3872
|
`op='error'` items because no authored operation row exists. Invalid provider
|
|
3639
3873
|
emissions are outside this channel because they are not turns. A bare
|
|
@@ -3642,9 +3876,9 @@ retain distinct contracts and lifetimes.
|
|
|
3642
3876
|
engine-internal faults crash and never mint model-facing rows.
|
|
3643
3877
|
- **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 assigns the committed `log:///.../READ` Problem instance. 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.
|
|
3644
3878
|
- **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`.
|
|
3645
|
-
- **Exact Problems cross
|
|
3879
|
+
- **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 the durable `instance`; it must not rebuild failure truth from `status`, `detail`, `RUN_ERROR`, a scheduler projection, or a legacy string. A failed boundary without a valid Problem is a contract violation and fails hard.
|
|
3646
3880
|
- **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.
|
|
3647
|
-
- §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;
|
|
3881
|
+
- §notice-drain-on-read **Notices** - the few observations that are not log rows render one terse line under their distinct `## Notices` section, never a JSON dump. Packet rendering normalizes whitespace, bounds the producer message with the shared preview limits, and appends any typed position. The notice buffer drains on read; event Notices appear on at most one packet. Stateful derivation progress and provider availability coalesce in the buffer, so clients observe every checkpoint live while a later model packet receives only the current state under ordinary level filtering.
|
|
3648
3882
|
- §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.
|
|
3649
3883
|
|
|
3650
3884
|
**The error rows (one channel) + the only non-log notices:**
|
|
@@ -3666,7 +3900,7 @@ retain distinct contracts and lifetimes.
|
|
|
3666
3900
|
|
|
3667
3901
|
§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, foldable and re-OPENable. 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.
|
|
3668
3902
|
|
|
3669
|
-
§notice-event-notify **Client surface.** Engine Notices broadcast live via the `notice/event`
|
|
3903
|
+
§notice-event-notify **Client surface.** Engine Notices broadcast live via the `notice/event` notification — `{ workerId, loopId, notice: { source, kind, level, message?, position?, …kind-specific } }` per the grammar's `Notice` schema — the moment they land. A loop Notice names its owning Worker; workspace derivation progress alone carries `workerId=null, loopId=0`. AG-UI projects the same observation as the custom `plurnk.notice` event. Failures do not broadcast on this surface: they are log rows, and the client reads them through `log.read` / the `log/entry` notification, the durable log.
|
|
3670
3904
|
|
|
3671
3905
|
§digest-programmatic-surface **The digest is an importable forensic surface.**
|
|
3672
3906
|
|
|
@@ -3675,10 +3909,10 @@ retain distinct contracts and lifetimes.
|
|
|
3675
3909
|
| 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. |
|
|
3676
3910
|
| `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
|
|
3677
3911
|
| `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
|
|
3678
|
-
| `workerId` | Narrows workers and every dependent loop, turn, logical
|
|
3679
|
-
| `workspaceId` | Narrows workers and dependent evidence
|
|
3912
|
+
| `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. Workspace-only embeddings are excluded. |
|
|
3913
|
+
| `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, including workspace-only embeddings; when both selectors are present they intersect. |
|
|
3680
3914
|
|
|
3681
|
-
§digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log
|
|
3915
|
+
§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`, tags, and structured `attrs`; every exact OPEN/FOLD/log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result; and every ordered physical provider request. KILLed `turnOps` still produce their chronological `assistant.md` artifacts because curation cannot rewrite what a producer submitted. 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. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
|
|
3682
3916
|
|
|
3683
3917
|
§digest-requiem **A requiem is an out-of-band forensic interview, not a worker
|
|
3684
3918
|
turn.** It cannot execute operations or alter the audited history.
|
|
@@ -3701,7 +3935,7 @@ turn.** It cannot execute operations or alter the audited history.
|
|
|
3701
3935
|
§tools-resource-discovery **Executable capability discovery uses ordinary
|
|
3702
3936
|
Plurnk resources.** No generated tool table rides the system packet. Every
|
|
3703
3937
|
runtime enabled for the current worker with an admitted invocation materializes exactly one
|
|
3704
|
-
family document at `worker://~/_plurnk/
|
|
3938
|
+
family document at `worker://~/_plurnk/plurnk/<runtime>.md`. A general runtime's
|
|
3705
3939
|
document contains its {§executor-tool-document}; a runtime with an exact
|
|
3706
3940
|
{§executor-tool-registry} materializes the same single document — per-target
|
|
3707
3941
|
child documents do not exist, shown or stored. The family document summarizes
|
|
@@ -3731,7 +3965,7 @@ enabled executable; executor enablement is the sole user-configured filter
|
|
|
3731
3965
|
shared by discovery and dispatch. A runtime declaration may carry
|
|
3732
3966
|
`resourcesPath` — its generated-doc root relative to the worker's generated
|
|
3733
3967
|
subtree ({§worker-generated-subtree}). Absent, its docs live in the internal
|
|
3734
|
-
`_plurnk/
|
|
3968
|
+
`_plurnk/plurnk` namespace; present (attached MCP families: `/tools`),
|
|
3735
3969
|
the family document materializes at `_plurnk` + that root in the
|
|
3736
3970
|
worker's private entry space. Turn 0 surveys the families (`## FIND0 [+init,+tools]
|
|
3737
3971
|
(worker://~/_plurnk/tools/*.md)`, one row per
|
|
@@ -3744,6 +3978,57 @@ unasked.
|
|
|
3744
3978
|
Attached tools are capabilities like every other runtime; the model never
|
|
3745
3979
|
learns an origin.
|
|
3746
3980
|
|
|
3981
|
+
§members-functionality **File membership is one Worker Functionality family.**
|
|
3982
|
+
Core registers the `members` family with the coordinator ({§functionality-coordinator}):
|
|
3983
|
+
the model, the client, and the operator learn one surface — `list | discover | add |
|
|
3984
|
+
enable | disable | remove`, `worker.members.<verb>` for the client, `## EXEC0 [members]
|
|
3985
|
+
(<verb>)` for the model — for what the model may see, exactly as they do for skills and
|
|
3986
|
+
MCP servers. A definition is one gitignore-style glob, `{ glob }`, relative to the project
|
|
3987
|
+
root; a leading `!` excludes matching members, and an exclusion wins over every inclusion.
|
|
3988
|
+
The coordinator's provenance (`service-configuration`, `client-action`, `model-proposal`)
|
|
3989
|
+
rides the definition; its alias is a short name, suggested from the glob. `list` shows each
|
|
3990
|
+
definition with what it resolved to — `include` or `exclude`, the pattern, the members it
|
|
3991
|
+
admits or removes (count and a bounded sample), and for a model's inclusion the matches the
|
|
3992
|
+
repository's ignore rules refused — so the model sees what its glob did and adapts.
|
|
3993
|
+
`discover` is introspection, never a catalog: a path answers why it is or is not visible
|
|
3994
|
+
(tracked, included by which pattern, a creation record, excluded by which `!glob`, ignored,
|
|
3995
|
+
untracked, absent); a glob previews what `add` would include or exclude. Names only, never
|
|
3996
|
+
content; nothing is added.
|
|
3997
|
+
|
|
3998
|
+
§members-configuration *Available definitions.* The operator's `PLURNK_MEMBERS_<ALIAS>=<glob>`
|
|
3999
|
+
(`!glob` excludes) and `PLURNK_MEMBERS_ENABLED=[…]` (absent or `[]` enables none) are the
|
|
4000
|
+
service-origin definitions, the shape `PLURNK_MCP_*` already has; an empty glob, a bare `!`,
|
|
4001
|
+
or an unknown enabled alias fails the daemon at boot.
|
|
4002
|
+
|
|
4003
|
+
§members-model-scope *The model's authority.* A model's `add` is admitted against
|
|
4004
|
+
`PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` in the file-creation lattice `none < root <
|
|
4005
|
+
namespace`, narrowed by `settings.membersModelScope` (most restrictive wins). Shipped `none`
|
|
4006
|
+
refuses every model definition — inclusion or exclusion — as `403
|
|
4007
|
+
members/functionality/model-scope`, naming `git add` and the operator's `/members add` as
|
|
4008
|
+
the paths that remain; `root` admits patterns inside the root; `namespace` admits `../` too.
|
|
4009
|
+
`auto` loops self-approve proposals, so the ceiling — not the proposal — is the guard
|
|
4010
|
+
({§membership-baseline}). The coordinator hands `admit` the caller (`action` | `operation`)
|
|
4011
|
+
so the family bounds the model without a second grammar.
|
|
4012
|
+
|
|
4013
|
+
§members-projection *One overlay.* Definitions are desired state per Worker
|
|
4014
|
+
({§functionality-state}); the workspace overlay (`workspace_constraints`) is their union
|
|
4015
|
+
across every worker of the workspace (ruling (a)): inclusions union and an exclusion wins.
|
|
4016
|
+
A child's birth snapshot counts as its own desire: a parent's `disable` or `remove`
|
|
4017
|
+
withdraws nothing the child still holds, and a file goes dark only when no worker of the
|
|
4018
|
+
workspace holds an inclusion for it. Human-authored definitions project with source
|
|
4019
|
+
`members`, model-proposed ones with source `model`; the same pattern from both keeps
|
|
4020
|
+
`members`. A `model` inclusion is a pattern scan like a human one but never admits a path
|
|
4021
|
+
the repository ignores ({§membership-model-universe}). The engine's creation records
|
|
4022
|
+
(`source: "create"`, {§fs-create-record}) are not definitions: the projection never
|
|
4023
|
+
overwrites or retires them. Projection happens at the family's publication commit and
|
|
4024
|
+
re-resolves membership; a Worker cooling changes nothing, because desired state is
|
|
4025
|
+
durable. Each enabled definition is one generated document at
|
|
4026
|
+
`worker://~/_plurnk/members/<alias>.md` ({§functionality-documents}) — its glob, origin,
|
|
4027
|
+
provenance, and what it resolved to — surveyed at turn 0 like every family's enabled
|
|
4028
|
+
definitions ({§actor-boundary-catalog-preview}), so the model sees why a file is or is
|
|
4029
|
+
not a member before it asks. There is no other membership path: the client's `/members`
|
|
4030
|
+
verbs are these verbs.
|
|
4031
|
+
|
|
3747
4032
|
§skills-functionality **Agent Skills are one Worker Functionality family.**
|
|
3748
4033
|
Core registers the `skills` family with the coordinator ({§functionality-coordinator});
|
|
3749
4034
|
its adapter owns protocol truth for standard Agent Skills and nothing else. A
|
|
@@ -3811,15 +4096,16 @@ model turn while an unchanged set dispatches nothing. The model manages skills
|
|
|
3811
4096
|
only through the generated `EXEC [skills]` family
|
|
3812
4097
|
({§functionality-model-projection}); it is never taught a package manager.
|
|
3813
4098
|
|
|
3814
|
-
The catalog describes this worker's Functionality
|
|
3815
|
-
|
|
3816
|
-
|
|
4099
|
+
The catalog describes this worker's Functionality under its durable capability
|
|
4100
|
+
ceilings. Turn0 narrows its surveys and examples through the current loop policy,
|
|
4101
|
+
and a direct denied attempt receives the same exact 403 from dispatch rather
|
|
4102
|
+
than a second documentation policy.
|
|
3817
4103
|
Optional non-EXEC operations remain a separate `## Enabled Optional Operations`
|
|
3818
4104
|
section because they are language extensions rather than executable tools.
|
|
3819
4105
|
|
|
3820
4106
|
### §schemes user.schemes — the resource directory
|
|
3821
4107
|
|
|
3822
|
-
§schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available to this worker, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized as the worker-private skill `worker://~/_plurnk/
|
|
4108
|
+
§schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available to this worker, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized as the worker-private skill `worker://~/_plurnk/plurnk/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+skills] (worker://~/_plurnk/plurnk/*.md)` survey ({§skills-functionality}), keeping the raw packet free of doc links. Meta-owned `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc. The directory includes only examples admitted by the effective worker-level capability layers, and Turn0 further narrows discovery through its loop policy using the same resolver ({§capability-admission}); the packet never baits an operation its own admission path will refuse. Materialized pull docs remain worker state, while their discoverability and execution remain policy-bound.
|
|
3823
4109
|
|
|
3824
4110
|
### §inject system.inject — the operator injection
|
|
3825
4111
|
|
|
@@ -3830,7 +4116,7 @@ section because they are language extensions rather than executable tools.
|
|
|
3830
4116
|
§policy-sections One section rides the system slot **after the definition and before capability teaching**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}). Policy is the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker://~/_plurnk/agents.md` entry ({§turn0-agents-stunt}); all other reference material is skills under the worker's private skills tree ({§skills-functionality}).
|
|
3831
4117
|
|
|
3832
4118
|
On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
|
|
3833
|
-
`AGENTS.md` from `@plurnk/plurnk-meta/
|
|
4119
|
+
`AGENTS.md` from `@plurnk/plurnk-meta/POLICY.md` ({§teaching-corpus}).
|
|
3834
4120
|
It reads that required source before creating the service home; a failed read
|
|
3835
4121
|
surfaces with its cause and leaves no apparently initialized home.
|
|
3836
4122
|
After that bootstrap the file is user-owned: edits and deletion persist, and a
|
|
@@ -3848,36 +4134,44 @@ created by that attempt. Unknown legacy members or simultaneous
|
|
|
3848
4134
|
legacy/canonical state fail without guessing. No dual read or dual write survives
|
|
3849
4135
|
the transition.
|
|
3850
4136
|
|
|
3851
|
-
§schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workerId)` renders the effective directory, `SchemeRegistry.docs(workerId)` resolves corpus-or-manifest documentation, and `referenceEntries(workerId)` supplies the current `/
|
|
4137
|
+
§schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workerId)` renders the effective directory, `SchemeRegistry.docs(workerId)` resolves corpus-or-manifest documentation, and `referenceEntries(workerId)` supplies the current `/plurnk/` generated-skill set when core publishes worker Functionality ({§skills-functionality}). One materializer reconciles the worker's private scope exactly: vanished contributions are deleted before current documents are upserted, so an excluded scheme or disabled, detached, replaced, or removed runtime cannot leave a stale model-facing contract.
|
|
3852
4138
|
|
|
3853
4139
|
### §packet-git-status The Git status section — compact repository state
|
|
3854
4140
|
|
|
3855
4141
|
When Git is admitted for the workspace, `## Git Status` reports the current
|
|
3856
|
-
branch, upstream ahead/behind counts, and staged/unstaged/untracked totals
|
|
4142
|
+
branch, upstream ahead/behind counts, and staged/unstaged/untracked totals, then
|
|
4143
|
+
one bounded line per non-empty class (at most eight paths, `+K more`): staged,
|
|
4144
|
+
unstaged, `untracked members` — each path with the inclusion pattern that admits it or
|
|
4145
|
+
`created` for a creation record — and `untracked (not members)`, named because such a
|
|
4146
|
+
file is not a member ({§membership-baseline}) and a human must `git add` it or add a
|
|
4147
|
+
members definition before the model can read it. The section never contradicts the
|
|
4148
|
+
catalog: an untracked file a definition admits is named as the member it is. The
|
|
3857
4149
|
active direct child of a running branch batch additionally receives its assigned
|
|
3858
4150
|
branch and the requirement to commit any project changes and leave the checkout
|
|
3859
4151
|
clean before concluding ({§worker-branch-batch-return}); no other worker receives
|
|
3860
|
-
that instruction. The section never
|
|
4152
|
+
that instruction. The section never carries an unbounded path list. Per-path state belongs to
|
|
3861
4153
|
the runtime actor's durable causal evidence: its `source=file` row carries
|
|
3862
4154
|
the exact two-character porcelain `XY` value as `git` metadata when the status
|
|
3863
4155
|
snapshot names that path. The engine takes one snapshot after membership
|
|
3864
4156
|
reconciliation and uses it for both projections; no per-file Git process exists.
|
|
3865
4157
|
|
|
3866
|
-
### §
|
|
4158
|
+
### §recap Optional Recap footer
|
|
3867
4159
|
|
|
3868
|
-
The user slot
|
|
3869
|
-
operational law already owned by `plurnk.md`. A non-empty `runLoop` /
|
|
3870
|
-
`
|
|
3871
|
-
`
|
|
3872
|
-
|
|
3873
|
-
|
|
4160
|
+
The user slot may end with `## Recap`, a compact recency-biased reminder of
|
|
4161
|
+
selected operational law already owned by `plurnk.md`. A non-empty `runLoop` /
|
|
4162
|
+
`runTurn` `recap` value overrides the default; otherwise core reads
|
|
4163
|
+
`PLURNK_SERVICE_RECAP` or the required meta-owned `recap.md` source for every
|
|
4164
|
+
packet. Empty content intentionally omits the rendered section while retaining
|
|
4165
|
+
one dormant authored source. A failed read fails packet assembly with its cause.
|
|
4166
|
+
The footer is one projection path and one authored source, not a second language
|
|
4167
|
+
contract.
|
|
3874
4168
|
|
|
3875
4169
|
## §matcher Matcher selection and text regions
|
|
3876
4170
|
|
|
3877
4171
|
Body matchers and text scopes are independent. Matcher prefixes choose a
|
|
3878
|
-
dialect (`//` xpath, `/` regex, `$` jsonpath,
|
|
3879
|
-
resources and report evidence. A text scope always addresses
|
|
3880
|
-
text, regardless of mimetype.
|
|
4172
|
+
dialect (`//` xpath, `/` regex, `$` jsonpath, `~` semantic, `&` graph, otherwise
|
|
4173
|
+
glob); they select resources and report evidence. A text scope always addresses
|
|
4174
|
+
the exact readable text, regardless of mimetype.
|
|
3881
4175
|
|
|
3882
4176
|
### §matcher-dispatch Matcher dispatch
|
|
3883
4177
|
|
|
@@ -3889,9 +4183,9 @@ One parsed content matcher crosses three ownership layers:
|
|
|
3889
4183
|
| `@plurnk/plurnk-schemes/Matcher` | Map framework results and typed failures to the universal scheme-result contract. |
|
|
3890
4184
|
| Core `Matcher.matchCandidates` | Apply that operation adapter across caller-supplied `{key, content, mimetype}` candidates and preserve source identity. |
|
|
3891
4185
|
|
|
3892
|
-
§relation-indexed-dialects `~semantic` and
|
|
3893
|
-
the content matcher.
|
|
3894
|
-
|
|
4186
|
+
§relation-indexed-dialects `~semantic` and `&graph` are indexed relation dialects and never route through
|
|
4187
|
+
the content matcher. Language admission accepts exactly one graph symbol (`&sym`, `&<sym`, `&>sym`);
|
|
4188
|
+
runtime validation is only a defensive boundary for typed callers. When the candidates' persistent index is still
|
|
3895
4189
|
deriving, the engine settles the workspace's derivations once and re-runs the selection; a still-incomplete
|
|
3896
4190
|
index is a 503 that is retryable — never a refusal to wait paired with an instruction to wait. Candidate composition has no dependency on the table that
|
|
3897
4191
|
stored a resource.
|
|
@@ -3905,9 +4199,9 @@ container identity.
|
|
|
3905
4199
|
|
|
3906
4200
|
| Matcher body | Selected resources | Match evidence |
|
|
3907
4201
|
| ------------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
3908
|
-
|
|
|
3909
|
-
|
|
|
3910
|
-
|
|
|
4202
|
+
| `&<symbol` | In-scope resources that reference `symbol` | Each matching reference's source span |
|
|
4203
|
+
| `&>symbol` | In-scope resources defining names referenced by each definition of `symbol` | Each referenced symbol's definition span |
|
|
4204
|
+
| `&symbol` | Union of definitions of `symbol`, referrers, and definitions of referenced names | Corresponding definition/reference spans, deduplicated by resource + span |
|
|
3911
4205
|
|
|
3912
4206
|
| Result | HTTP status |
|
|
3913
4207
|
|---|---|
|
|
@@ -3917,6 +4211,12 @@ container identity.
|
|
|
3917
4211
|
| Source unparseable for its mimetype | 203 (soft fallback: raw content as text with `reason`) |
|
|
3918
4212
|
| Dialect unsupported by the resource | 415 |
|
|
3919
4213
|
|
|
4214
|
+
§matcher-invalid-expression A malformed matcher Problem identifies the dialect
|
|
4215
|
+
and includes the bounded native parser cause as `diagnostic` when available. Core applies
|
|
4216
|
+
`PLURNK_SERVICE_ERROR_DETAIL_LIMIT` before the cause crosses into the schemes
|
|
4217
|
+
adapter; the Problem offers only the deterministic recovery to revise the
|
|
4218
|
+
expression, never a guess about the intended pattern.
|
|
4219
|
+
|
|
3920
4220
|
§matcher-dispatch-203-soft-fallback On parse failure, 203 returns raw content as the text primitive with `reason`
|
|
3921
4221
|
so the model can use ordinary text retrieval or repair the source.
|
|
3922
4222
|
|
|
@@ -3946,7 +4246,7 @@ resources according to {§find-result-projection}.
|
|
|
3946
4246
|
| jsonpath `$.path` | resources whose deep JSON resolves the path | canonical locator plus exact/enclosing text region when honest |
|
|
3947
4247
|
| xpath `//sel` | resources whose deep XML resolves the selector | canonical locator plus exact/enclosing text region when honest |
|
|
3948
4248
|
| `~`semantic `~q` | resources ranked by indexed chunks | chunk text region when available |
|
|
3949
|
-
|
|
|
4249
|
+
| `&`graph `&<sym` | resources with matching symbol relations | symbol text region when available |
|
|
3950
4250
|
|
|
3951
4251
|
Match evidence is navigation evidence, never an implicit body projection. The
|
|
3952
4252
|
model uses broad FIND to select and page resources, exact FIND to page that
|