@plurnk/plurnk-service 3.1.0 → 3.3.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 +24 -19
- package/INSTALL.md +20 -1
- package/SPEC.md +448 -121
- package/dist/build-info.json +1 -1
- package/dist/completions/_plurnk-service +1 -1
- package/dist/completions/plurnk-service.bash +1 -1
- package/dist/completions/plurnk-service.fish +1 -0
- package/dist/content/path-mimetype.d.ts.map +1 -1
- package/dist/content/path-mimetype.js +2 -8
- package/dist/content/path-mimetype.js.map +1 -1
- package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
- package/dist/core/AdmittedTurnExecutor.js +22 -10
- package/dist/core/AdmittedTurnExecutor.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts +1 -3
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +43 -46
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/{schemes/_derivation-use.d.ts → core/ContentUse.d.ts} +3 -3
- package/dist/core/ContentUse.d.ts.map +1 -0
- package/dist/{schemes/_derivation-use.js → core/ContentUse.js} +8 -7
- package/dist/core/ContentUse.js.map +1 -0
- package/dist/core/CoreSchemeServices.d.ts.map +1 -1
- package/dist/core/CoreSchemeServices.js +1 -0
- package/dist/core/CoreSchemeServices.js.map +1 -1
- package/dist/core/DataStatementRunner.d.ts.map +1 -1
- package/dist/core/DataStatementRunner.js +8 -20
- package/dist/core/DataStatementRunner.js.map +1 -1
- package/dist/core/Dispatcher.d.ts +9 -1
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +151 -76
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/EditMutations.js +1 -1
- package/dist/core/EditMutations.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +3 -3
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/FileAddress.d.ts +12 -0
- package/dist/core/FileAddress.d.ts.map +1 -0
- package/dist/core/FileAddress.js +73 -0
- package/dist/core/FileAddress.js.map +1 -0
- package/dist/core/FilePublication.d.ts +15 -0
- package/dist/core/FilePublication.d.ts.map +1 -0
- package/dist/core/FilePublication.js +143 -0
- package/dist/core/FilePublication.js.map +1 -0
- package/dist/core/FileSnapshot.d.ts +26 -0
- package/dist/core/FileSnapshot.d.ts.map +1 -0
- package/dist/core/FileSnapshot.js +179 -0
- package/dist/core/FileSnapshot.js.map +1 -0
- package/dist/core/KillHandler.d.ts.map +1 -1
- package/dist/core/KillHandler.js +2 -1
- package/dist/core/KillHandler.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +3 -2
- package/dist/core/MembershipMaterialization.d.ts.map +1 -1
- package/dist/core/MembershipMaterialization.js +87 -143
- package/dist/core/MembershipMaterialization.js.map +1 -1
- package/dist/core/MutationEffects.d.ts +2 -1
- package/dist/core/MutationEffects.d.ts.map +1 -1
- package/dist/core/MutationEffects.js +14 -1
- package/dist/core/MutationEffects.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +16 -13
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/PacketBuilder.sql +22 -0
- package/dist/core/PathGlob.d.ts +6 -0
- package/dist/core/PathGlob.d.ts.map +1 -0
- package/dist/core/PathGlob.js +24 -0
- package/dist/core/PathGlob.js.map +1 -0
- package/dist/core/ProposalLifecycle.d.ts +3 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +46 -33
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProposalLifecycle.sql +4 -0
- package/dist/core/ResourceBindings.d.ts.map +1 -1
- package/dist/core/ResourceBindings.js +4 -3
- package/dist/core/ResourceBindings.js.map +1 -1
- package/dist/core/ResourceSelector.d.ts +1 -2
- package/dist/core/ResourceSelector.d.ts.map +1 -1
- package/dist/core/ResourceSelector.js +30 -9
- package/dist/core/ResourceSelector.js.map +1 -1
- package/dist/core/ResourceTransfers.d.ts +1 -1
- package/dist/core/ResourceTransfers.d.ts.map +1 -1
- package/dist/core/ResourceTransfers.js +26 -11
- package/dist/core/ResourceTransfers.js.map +1 -1
- package/dist/core/TurnDispositionHandler.d.ts +1 -1
- package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
- package/dist/core/TurnDispositionHandler.js +5 -3
- package/dist/core/TurnDispositionHandler.js.map +1 -1
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +6 -4
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerControlHandler.d.ts.map +1 -1
- package/dist/core/WorkerControlHandler.js +38 -2
- package/dist/core/WorkerControlHandler.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +2 -0
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +7 -0
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/fork.sql +2 -2
- package/dist/core/git-membership.d.ts +1 -0
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +9 -11
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/glob_match.js +3 -3
- package/dist/core/glob_match.js.map +1 -1
- package/dist/core/mutation-types.d.ts +4 -0
- package/dist/core/mutation-types.d.ts.map +1 -1
- package/dist/core/namespace.d.ts +4 -1
- package/dist/core/namespace.d.ts.map +1 -1
- package/dist/core/namespace.js +14 -3
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/packet-wire.d.ts +1 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +17 -11
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +4 -3
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +24 -12
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/scheme-types.d.ts +2 -0
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/sqlite-synchronous.d.ts +2 -0
- package/dist/core/sqlite-synchronous.d.ts.map +1 -0
- package/dist/core/sqlite-synchronous.js +4 -0
- package/dist/core/sqlite-synchronous.js.map +1 -0
- package/dist/evidence/EvidenceReader.d.ts.map +1 -1
- package/dist/evidence/EvidenceReader.js +8 -1
- package/dist/evidence/EvidenceReader.js.map +1 -1
- package/dist/evidence/digest.sql +6 -1
- package/dist/man/plurnk-service.1 +35 -24
- package/dist/schemes/Env.d.ts +1 -1
- package/dist/schemes/Env.d.ts.map +1 -1
- package/dist/schemes/Env.js +2 -2
- package/dist/schemes/Env.js.map +1 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +5 -1
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecutionInput.d.ts +2 -1
- package/dist/schemes/ExecutionInput.d.ts.map +1 -1
- package/dist/schemes/ExecutionInput.js +44 -6
- package/dist/schemes/ExecutionInput.js.map +1 -1
- package/dist/schemes/File.d.ts +1 -0
- package/dist/schemes/File.d.ts.map +1 -1
- package/dist/schemes/File.js +246 -269
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +68 -8
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +24 -1
- package/dist/schemes/Worker.js +1 -1
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.d.ts +2 -0
- package/dist/schemes/_entry-crud.d.ts.map +1 -1
- package/dist/schemes/_entry-crud.js +8 -5
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +15 -15
- package/dist/schemes/_entry-find.d.ts +1 -0
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +15 -10
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-manifest.d.ts +2 -2
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +7 -5
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +9 -7
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_path-scope.d.ts.map +1 -1
- package/dist/schemes/_path-scope.js +12 -4
- package/dist/schemes/_path-scope.js.map +1 -1
- package/dist/schemes/_search-index.js +3 -3
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/schemes/exec-env.d.ts.map +1 -1
- package/dist/schemes/exec-env.js +7 -22
- package/dist/schemes/exec-env.js.map +1 -1
- package/dist/server/Daemon.d.ts +7 -1
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +90 -69
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +3 -3
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +46 -5
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/EnvFunctionality.d.ts.map +1 -1
- package/dist/server/EnvFunctionality.js +19 -11
- package/dist/server/EnvFunctionality.js.map +1 -1
- package/dist/server/Functionality.d.ts.map +1 -1
- package/dist/server/Functionality.js +89 -45
- package/dist/server/Functionality.js.map +1 -1
- package/dist/server/FunctionalityManager.d.ts +2 -5
- package/dist/server/FunctionalityManager.d.ts.map +1 -1
- package/dist/server/FunctionalityManager.js +10 -6
- package/dist/server/FunctionalityManager.js.map +1 -1
- package/dist/server/MembersFunctionality.d.ts +7 -8
- package/dist/server/MembersFunctionality.d.ts.map +1 -1
- package/dist/server/MembersFunctionality.js +94 -62
- package/dist/server/MembersFunctionality.js.map +1 -1
- package/dist/server/MessageAbandonment.d.ts +7 -0
- package/dist/server/MessageAbandonment.d.ts.map +1 -0
- package/dist/server/MessageAbandonment.js +57 -0
- package/dist/server/MessageAbandonment.js.map +1 -0
- package/dist/server/Retention.d.ts.map +1 -1
- package/dist/server/Retention.js +5 -5
- package/dist/server/Retention.js.map +1 -1
- package/dist/server/Retention.sql +49 -23
- package/dist/server/Rollback.d.ts +29 -0
- package/dist/server/Rollback.d.ts.map +1 -0
- package/dist/server/Rollback.js +111 -0
- package/dist/server/Rollback.js.map +1 -0
- package/dist/server/drain.sql +9 -0
- package/dist/server/lifecycle-recovery.sql +4 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +4 -0
- package/dist/service.js.map +1 -1
- package/docs/copy-move.md +3 -0
- package/docs/env.md +12 -6
- package/docs/members.md +30 -10
- package/migrations/023_file_revisions.sql +54 -0
- package/migrations/024_proposal_decisions.sql +34 -0
- package/migrations/025_response_retention.sql +30 -0
- package/migrations/026_message_obligations.sql +32 -0
- package/migrations/027_members_identity.sql +20 -0
- package/migrations/028_mutation_patch.sql +20 -0
- package/package.json +35 -34
- package/dist/schemes/_derivation-use.d.ts.map +0 -1
- package/dist/schemes/_derivation-use.js.map +0 -1
package/SPEC.md
CHANGED
|
@@ -349,7 +349,7 @@ plus a broadcast duplicate. Runtime maintenance turns produce no broadcast ({§a
|
|
|
349
349
|
and remote resources do not acquire ambient attention merely because they are
|
|
350
350
|
workspace-addressable.
|
|
351
351
|
|
|
352
|
-
§actor-boundary-no-mutex
|
|
352
|
+
§actor-boundary-no-mutex Workers share workspace state without worker-owned locks or reservations. Coordination is cooperative; membership bounds their visible surface uniformly ({§machine-processes}). Stale writes reject at their anchor or commit boundary ({§line-anchors}, {§membership-edit-write-revision}). Internal storage serialization does not confer ownership: {§file-commit-serialization} holds no file across reasoning, operation selection, or approval.
|
|
353
353
|
|
|
354
354
|
§actor-boundary-passive-wake **Passive wake follows ownership.** A directed
|
|
355
355
|
voice wakes an idle worker. A parked continuation resumes when an obligation it
|
|
@@ -422,7 +422,7 @@ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
|
|
|
422
422
|
unset / `0` disables previews. `log://` is absent because the current worker's
|
|
423
423
|
log already renders in present mode.
|
|
424
424
|
|
|
425
|
-
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` operation turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program — the READ/FIND surveys, led by one NOTE when the surveys run — is recorded as the turn's `ops://` source and executed through {§op-execution-order} exactly as a model's program is; it authors no reasoning and reads none back. The NOTE keeps the example turn within the card's NOTE-per-turn teaching and reads, exactly, `Surveyed tooling, documentation, extended context, and project root.` No emission row is fabricated ({§emission-row}): the first request sees the NOTE and the surveys' ordinary results, never an assistant-content copy of the program. The initial message arrives as an inbound SEND in the first model turn ({§message-arrival}); initialization never READs it, and neither initialization nor later turns manufacture a task inventory. Every orienting row is structurally classified `_plurnk` and `init`. The namespace surveys and their asides follow {§actor-boundary-catalog-preview}.
|
|
425
|
+
§worker-initialization-entry **Model-worker initialization is a real `_plurnk` operation turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. Its program — the READ/FIND surveys, led by one NOTE when the surveys run — is recorded as the turn's `ops://` source and executed through {§op-execution-order} exactly as a model's program is; it authors no reasoning and reads none back. The NOTE keeps the example turn within the card's NOTE-per-turn teaching: it carries the aside of the card's first NOTE example, `<!-- summary -->`, and reads, exactly, `Surveyed tooling, documentation, extended context, and project root.` No emission row is fabricated ({§emission-row}): the first request sees the NOTE and the surveys' ordinary results, never an assistant-content copy of the program. The initial message arrives as an inbound SEND in the first model turn ({§message-arrival}); initialization never READs it, and neither initialization nor later turns manufacture a task inventory. Every orienting row is structurally classified `_plurnk` and `init`. The namespace surveys and their asides follow {§actor-boundary-catalog-preview}.
|
|
426
426
|
|
|
427
427
|
Incoming messages publish once as inbound SEND rows in the first model turn
|
|
428
428
|
({§message-arrival}); initialization neither READs nor archives them. The turn
|
|
@@ -566,7 +566,7 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
566
566
|
| `READ` | existing literal name | Collect the named worker's deliverable. |
|
|
567
567
|
| `KILL` | existing literal name | Terminate the named worker or caller. |
|
|
568
568
|
|
|
569
|
-
- §worker-scheme-spawn **Spawn** — ```` ```WORK (worker://<name>)? ```` with a task body creates a new child worker (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. Names remain unique within a workspace for the lifetime of retained Worker rows, including after termination.
|
|
569
|
+
- §worker-scheme-spawn **Spawn** — ```` ```WORK (worker://<name>)? ```` with a task body creates a new child worker (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. Names remain unique within a workspace for the lifetime of retained Worker rows, including after termination. A WORK whose name a worker already holds is the voice door ({§worker-scheme-irc}): its body is delivered to that worker as a message, nothing is created, the receipt names the worker and `delivered: message`, and an `env` option is refused by name since a message takes none. A FORK whose name a worker holds is `409 worker-name-conflict` whose recovery names the working forms, WORK or `SEND (worker://<name>)` to message the live worker, or a name no worker holds to branch; concurrent claims cannot redirect a published address or expose a raw uniqueness failure.
|
|
570
570
|
- §worker-spawn-prompt-resource **The spawn slot is overloaded by scheme.** A `worker://` path is
|
|
571
571
|
the child's address and keeps the address rules ({§worker-control-addressing}). A path of any
|
|
572
572
|
other scheme is the child's prompt resource: it is read whole (`<1,-1>`) under the caller's read capabilities, composed with
|
|
@@ -620,9 +620,10 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
620
620
|
- §child-orientation **Child orientation.** Beyond the conclusion delta, every
|
|
621
621
|
turn the packet's status clump surfaces the live things this worker currently
|
|
622
622
|
holds under the teaching's own word for handing work out: `## Delegation` is
|
|
623
|
-
one JSON object, `{"workers": [...], "streams": [...]}`, its
|
|
624
|
-
workers
|
|
625
|
-
|
|
623
|
+
one JSON object, `{"workers": [...], "streams": [...], "messages": [...]}`, its
|
|
624
|
+
unconcluded child workers, its open streams and the messages it sent that await
|
|
625
|
+
completion ({§worker-obligations}) as `{status, path}` pointers (the same shape as
|
|
626
|
+
the errors section); a message pointer carries the recipient loop's status. Body-suppressed child activity is durable
|
|
626
627
|
history; this section is the current inventory that keeps an active obligation
|
|
627
628
|
visible even when no new activity arrived. Each open stream pointer carries
|
|
628
629
|
elapsed runtime, output inactivity, and its channels' sizes and growth since
|
|
@@ -649,15 +650,17 @@ Every admitted authority is a literal `workers.name`; self-addressing uses the c
|
|
|
649
650
|
notices, and the rest keep that rule. The parent is not a section: the
|
|
650
651
|
`## Worker` identity block carries `"parent": "worker://<name>"`, or
|
|
651
652
|
`"parent": null` at a root, so a worker never infers its rank from silence.
|
|
652
|
-
- §packet-current-turn **The packet says who and
|
|
653
|
+
- §packet-current-turn **The packet says who, which turn and who attends, below the log.** The
|
|
653
654
|
`## Worker` block, in the status clump below the log ({§packet-cache-monotone}), carries
|
|
654
|
-
`{"path": "worker://<name>", "parent": <address or null>, "loop": L, "turn": T
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
or
|
|
660
|
-
|
|
655
|
+
`{"path": "worker://<name>", "parent": <address or null>, "loop": L, "turn": T, "owner":
|
|
656
|
+
{"address": "<owner>", "interactive": <boolean>}}`: the actor, whose child it is, the coordinate
|
|
657
|
+
this packet's response becomes, so `reasoning://<worker>/L/T` and `ops://<worker>/L/T` are the
|
|
658
|
+
model's own and `log:///L/T/*` its rows, and its approval owner ({§worker-ownership}) with whether
|
|
659
|
+
a person attends that owner; a model never infers the present from the last row's coordinate,
|
|
660
|
+
which may or may not be its own turn, and never infers from a missing tool alone that nobody can
|
|
661
|
+
answer. The block changes every turn, so nothing of it precedes the log, and the packet carries no
|
|
662
|
+
date, time or zone anywhere. The coordinate only; the source addresses stay documented, not
|
|
663
|
+
taught.
|
|
661
664
|
|
|
662
665
|
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. FORK/WORK carry the seed task in the body and are their own ops, dispatched to worker control — never the entry-copy path.
|
|
663
666
|
|
|
@@ -677,7 +680,7 @@ flowchart LR
|
|
|
677
680
|
materialize --> read["READ snapshot"]
|
|
678
681
|
materialize --> edit["EDIT against snapshot"]
|
|
679
682
|
edit --> proposal["Proposal"]
|
|
680
|
-
proposal -->|"client accepts or loop auto"| cas["
|
|
683
|
+
proposal -->|"client accepts or loop auto"| cas["Validate captured file revision"]
|
|
681
684
|
cas -->|"file snapshot → disk"| project["Project file"]
|
|
682
685
|
project --> materialize
|
|
683
686
|
```
|
|
@@ -761,18 +764,18 @@ and never re-fetch a match.
|
|
|
761
764
|
`engine:membership` / `git_inspection_refused` notice names the key, once per
|
|
762
765
|
workspace until it changes or clears. User- and model-requested Git commands
|
|
763
766
|
stay on their explicit execution path.
|
|
764
|
-
- §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
|
|
767
|
+
- §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its materialized entry snapshot, not an empty body or a fresh disk read at approval ({§membership-edit-write-revision}). An existing **non-member** is refused (403) *before* any content read or write: its bytes never leak into the proposal. A **new path** crosses the creation matrix in {§fs-write-surface}; proposal acceptance cannot bypass its scope, exclusion, or incorporation rules. Shell execution reaches beyond file membership; the file scheme does not.
|
|
765
768
|
- §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.
|
|
766
769
|
|
|
767
770
|
**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`.
|
|
768
771
|
|
|
769
772
|
- §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}).
|
|
770
773
|
- §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.
|
|
771
|
-
- §membership-overlay-exclude **`exclude`** — a `!glob` definition removes a tracked or included file: resolution drops matches (
|
|
774
|
+
- §membership-overlay-exclude **`exclude`** — a `!glob` definition removes a tracked or included file: resolution drops matches ({§path-glob-matching}) 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}).
|
|
772
775
|
- §membership-reconcile-sets **Reconciliation is two set statements.** Once the desired set is composed — `(git ls-files ∪ include) − exclude`, glob evaluation and Git shell-outs being the process's own — it lands as one `INSERT … SELECT FROM json_each` with the same idempotent provenance update as a single registration, and every overlay-owned member outside it leaves in one `DELETE … WHERE pathname NOT IN (json_each) RETURNING`, its prior body riding out of the statement. A path that also left disk truth (no longer a candidate at all) becomes a divergence from that prior content; an exclusion is silent. No per-path statement, no set difference outside the database.
|
|
773
|
-
- §membership-glob-in-sql **A constraint is evaluated where it lives.** `glob_match(pathname, glob)`
|
|
776
|
+
- §membership-glob-in-sql **A constraint is evaluated where it lives.** `glob_match(pathname, glob)` exposes {§path-glob-matching} to SQLite (`src/core/glob_match.ts`, deterministic), the same matcher every overlay decision uses, so a lookup that asks the constraints table a question — which exclusion covers this key, whether a members definition includes it, which inclusion owns each untracked path — is one statement over `workspace_constraints`, never a listing filtered in the process. Transient inputs the process already holds (a `git ls-files` listing against the exclude globs) stay filtered in the process; the function exists so the database's own rows can be asked, not so process data makes a round trip.
|
|
774
777
|
|
|
775
|
-
**File ops act on the entry, not the disk; the two reconcile
|
|
778
|
+
**File ops act on the entry, not the disk; the two reconcile at gates.** A `file:///` member's body is its materialized model-readable snapshot. READ returns that channel; EDIT computes against it, not a newly read replacement. Pre-turn materialization acquires disk state; accepted write-back validates the captured revision before changing disk ({§proposal}, {§membership-edit-write-revision}).
|
|
776
779
|
|
|
777
780
|
§membership-source-projection Binary acquisition is transient and bounded by
|
|
778
781
|
{§mimetype-binary-input}; durable entry channels remain Unicode text. Core-private
|
|
@@ -795,10 +798,12 @@ with an empty body channel carrying a durable 413 producer result; no diagnostic
|
|
|
795
798
|
sentinel impersonates file content. READ therefore names the path, observed bytes,
|
|
796
799
|
ceiling, and recovery through the ordinary result contract, while EDIT returns the
|
|
797
800
|
same 413 instead of diffing against a fictitious empty baseline. Core records the
|
|
798
|
-
materialization disposition and ceiling privately
|
|
799
|
-
reconsidered when the
|
|
800
|
-
|
|
801
|
+
materialization disposition and ceiling privately; an unchanged oversized marker
|
|
802
|
+
is reconsidered when the policy changes and otherwise remains stat-gated.
|
|
803
|
+
Ordinary members follow {§membership-change-gated-sync}.
|
|
804
|
+
The file write gate independently stats the source against the same ceiling,
|
|
801
805
|
so safety does not depend on a background warm winning a client-operation race.
|
|
806
|
+
Whole-file deletion does not need a materialized body ({§file-delete-revision}).
|
|
802
807
|
|
|
803
808
|
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row and one symbol graph without copying, and the FTS index reads its text from the content store ({§content-store}) instead of keeping a copy. The identity hashes the representation's own SHA-256 ({§tokenomics-content-hash-identity}), never its body, so a maintenance pass judges an entry channel from its stored `content_hash` without the body crossing into the process; a body is acquired only for a derivation that runs, under that same identity (a representation that moved on since it was judged returns nothing and is judged again next pass), or for a channel with no stored identity, an open or streamed channel, which must be read to be judged. Log rows and turn sources still arrive whole. The pass reports the bytes it acquired beside the derivations it ran, and an unchanged workspace acquires none of its channel bodies at any concurrency. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every launched worker settles before the maintenance pass reports success or failure, so one failed artifact cannot orphan sibling derivations. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. A changed pass emits one immediate `preparing` state, intermediate `indexing` heartbeats at `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`, and one immediate `complete` or `failed` state. A no-op pass emits no lifecycle, an indexing heartbeat never claims 100%, and the model-facing Notice buffer retains only the current derivation state while live clients observe each heartbeat.
|
|
804
809
|
|
|
@@ -836,15 +841,29 @@ with their reasons. Successful optional projection degradations continue indexin
|
|
|
836
841
|
and surface their framework Notice once per identical observation in a maintenance
|
|
837
842
|
pass.
|
|
838
843
|
|
|
839
|
-
§membership-change-gated-sync **
|
|
844
|
+
§membership-change-gated-sync **Projection is idempotent and change-gated.** Membership checks every member's physical identity and raw-byte digest within the materialization ceiling; timestamps alone never establish content identity. Unchanged source revision and policy avoid projection and database publication. Binary projections also compare their reader identity. Input-limited markers remain stat-gated because they expose no acquired body. An acquisition whose observed file identity or metadata changes is discarded and retried on the next pass. An observed absence removes stale channels and records `absent`; reappearance is a divergence, not first sight. This is observed state subject to {§file-external-race}, not an instantaneous snapshot of a concurrently changing project.
|
|
840
845
|
|
|
841
|
-
§membership-emi-divergence-signal **EMI divergence evidence.** The
|
|
846
|
+
§membership-emi-divergence-signal **EMI divergence evidence.** The materialization pass records observed source changes as an `EDIT`-shaped row naming the file with `source="file"`; it does not broadcast them into unrelated workers' logs ({§env-delta-filesystem-narration}). A native write publishes its own projection and revision, so unchanged landed bytes are not narrated as external divergence. Later external changes remain independently detectable. A stale anchored edit rejects under {§line-anchors}; write-back protection and its external race limit are defined by {§membership-edit-write-revision} and {§file-external-race}.
|
|
842
847
|
|
|
843
|
-
§membership-edit-write-
|
|
848
|
+
§membership-edit-write-revision **File write-back is conditional on its captured revision.** EDIT computes against the materialized text; COPY/MOVE mutations retain the revision of the state they selected. Approval never substitutes a newer baseline. Immediately before publication, physical identity and exact content must still match; otherwise the operation returns `edit-collision` (409) without changing the target. A member without a recorded source revision must be materialized before mutation, not treated as permission to overwrite. New-path publication is exclusive. Anchors separately protect the addressed text neighborhood before proposal ({§line-anchors}); an unanchored edit does not claim to preserve an earlier READ's view.
|
|
844
849
|
|
|
845
|
-
|
|
850
|
+
§file-snapshot-revision A materialized source revision records its physical path, filesystem identity/change fingerprint and raw-byte digest, distinct from the derived readable body. Its revision and channels publish in one database statement. An input-limited marker has no acquired digest; it cannot authorize a content replacement. Successful writes stamp the revision acquired from their own bytes, never a later pathname stat. Unversioned projections are rematerialized, including those retained through an upgrade.
|
|
846
851
|
|
|
847
|
-
|
|
852
|
+
§file-commit-serialization Final validation, publication/deletion, and projection settlement are serialized per physical path within one daemon, across workers and workspaces. Unrelated paths remain concurrent. No reservation survives a commit, and no lock is held awaiting model inference, approval, or MIME projection. Membership acquires and projects outside this boundary, then revalidates its source inside it before publishing; an older projection cannot overwrite a newer daemon write.
|
|
853
|
+
|
|
854
|
+
§file-publication A native file write stages complete bytes beside the target, then publishes them atomically; failures before publication leave the original intact. Creation never replaces an occupied name. Existing-file replacement preserves permission bits and ownership, but replaces the inode: other hard-link names and already-open descriptors retain their previous file. Inode-specific extended attributes are not a promised projection. The file/directory operations and SQLite commit are not one transaction or a filesystem power-loss durability guarantee. If publication succeeds but incorporation/projection fails, the result identifies that partial effect; it never claims nothing happened.
|
|
855
|
+
|
|
856
|
+
§file-delete-revision KILL and MOVE source removal validate the captured source revision immediately before unlinking or editing. Whole-file KILL of an input-limited member acquires a streaming digest before proposal without materializing its body. Deferred MOVE retains its original source selection through destination approval. A changed source is preserved; a destination already written remains reported under {§move-cross-scheme-move}. Creation rollback may remove only the unchanged file that creation published; a changed or replaced path is retained and reported as incomplete rollback.
|
|
857
|
+
|
|
858
|
+
§file-external-race The file boundary is optimistic with respect to external programs, executors and other daemons. Portable filesystem APIs provide no atomic expected-content-and-replace/unlink primitive. Plurnk detects drift through its final validation, but cannot exclude a writer racing after that check. It neither advertises such exclusion nor silently merges changed files. Physical-path revalidation prevents a changed symlink from redirecting an approved operation to a different target, subject to the same external race limit.
|
|
859
|
+
|
|
860
|
+
| Commit boundary | Filesystem effect | Result and settlement |
|
|
861
|
+
| --- | --- | --- |
|
|
862
|
+
| Unknown baseline or observed drift | No mutation | 409; refresh and prepare again ({§membership-edit-write-revision}). |
|
|
863
|
+
| Staging or prepublication I/O failure | Original target remains intact | Failure; retain cleanup failures too ({§file-publication}). |
|
|
864
|
+
| Existing file published; projection fails | Complete replacement remains | Failure identifies the update; ordinary reconciliation reads disk truth ({§file-publication}). |
|
|
865
|
+
| New file published; incorporation fails | Remove only the unchanged creation | Report rollback, or partial failure if another writer changed it or cleanup fails ({§file-delete-revision}). |
|
|
866
|
+
| MOVE destination published; source changed | Keep destination and changed source | Conflict identifies the completed destination effect ({§move-cross-scheme-move}). |
|
|
848
867
|
|
|
849
868
|
§membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving member definitions as the only membership source. `ALLOWED` gates `AUTO`.
|
|
850
869
|
|
|
@@ -1555,16 +1574,30 @@ historical execution. No address grants ownership or access restrictions.
|
|
|
1555
1574
|
| `src/x.md`, `./src/x.md`, `/work/project/src/x.md` | `src/x.md` |
|
|
1556
1575
|
| `/src/x.md` | `../../src/x.md` |
|
|
1557
1576
|
| `../policy.md`, `/work/policy.md` | `../policy.md` |
|
|
1577
|
+
| `~/x.md` (daemon home `/home/user`) | `../../home/user/x.md` |
|
|
1578
|
+
| `./~/x.md` | Key `~/x.md`, addressed as `./~/x.md` |
|
|
1558
1579
|
| `.`, `/work/project/` | The project collection, not a file entry |
|
|
1559
1580
|
| `/` | `../../`, the operating-system root collection |
|
|
1560
1581
|
|
|
1561
|
-
At `project_root=/`, `/src/x.md` and `src/x.md` resolve to the same key. Without a project root, absolute
|
|
1582
|
+
At `project_root=/`, `/src/x.md` and `src/x.md` resolve to the same key. Without a project root, absolute and home-relative spellings cannot be translated; no implicit filesystem base is supplied.
|
|
1583
|
+
|
|
1584
|
+
§fs-home **Home expansion belongs to authored file spellings, not resource identities.** A leading `~` or `~/` resolves from the daemon user's home (`os.homedir()`) before project-relative translation. Bare `~` names that directory. Other tilde-prefixed names, `./~` and embedded tilde segments are literal. This applies to file operations and client attachments regardless of producer; pattern-slot `~` remains full-text search. Bound entry addresses, Git paths, stored keys and membership patterns remain literal. Expansion grants neither membership nor write authority. A literal key `~` or `~/…` is rendered with a leading `./`, so resolving the displayed address recovers the same key without expanding it again. Existing identities and historical evidence are unchanged.
|
|
1562
1585
|
|
|
1563
|
-
|
|
1586
|
+
§file-url **Explicit file URLs have native URL meaning; stored keys stay literal.** Reads, mutations, client attachments and rendered addresses share this boundary:
|
|
1564
1587
|
|
|
1565
|
-
|
|
1588
|
+
| Surface | Contract |
|
|
1589
|
+
|---|---|
|
|
1590
|
+
| `file://` input | Native `fileURLToPath` interpretation, once, before {§fs-namei}; `%2528` names literal `%28`, not `(`. Query does not change the native filename; fragment selects a channel, while `%23` names a literal `#`. |
|
|
1591
|
+
| Invalid URL | Invalid encoding, host-unsupported authorities or encoded separators, and NUL refuse the operation with 400. |
|
|
1592
|
+
| Bare input / bound key | Bare spelling retains {§path-parentheses}, not general URI decoding. Bound keys are never decoded or home-expanded again. |
|
|
1593
|
+
| Resource rendering | Ordinary names stay project-relative. Names that bare target syntax would reinterpret use absolute native file URLs from `project_root`; no identity or membership changes. |
|
|
1594
|
+
| Selectors | Encoded metacharacters are filename data, separate from authored glob syntax ({§path-glob-matching}). URL selector receipts preserve that distinction; generated folder links quote the literal folder before appending `/**`. Literal backslashes remain within their filename segment, including beside glob syntax. |
|
|
1595
|
+
|
|
1596
|
+
Folders and globs select members in those same filesystem coordinates. Parent-directory selectors may include in-root and outside-root members; they never scan or admit unrelated disk contents. Catalog paths and grouped subtree selectors use the reusable spelling in {§file-url}.
|
|
1566
1597
|
|
|
1567
|
-
§
|
|
1598
|
+
§file-path-normalization An authored model file operation using an absolute or home-relative path receives a `scheme:file/path_normalized` warning Notice naming its project-relative address. COPY/MOVE cover each such operand. The Notice neither changes the operation result nor causes a strike, and does not repeat for automatic observations or already-relative paths. Root-mounted workspaces and spellings that must remain file URLs ({§file-url}) need no such notice. It never suggests that an unadmitted path has become a member.
|
|
1599
|
+
|
|
1600
|
+
§fs-canonical-name **One canonical identity: the literal Git-relative key.** 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. Authored spellings resolve before storage or comparison; stored keys are lexical fixpoints, never reinterpreted as authored input. Rendering quotes target-slot syntax ({§path-parentheses}) and home-like literal names ({§fs-home}), using a file URL where necessary ({§file-url}); resolving the rendered spelling returns the same key.
|
|
1568
1601
|
|
|
1569
1602
|
§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.
|
|
1570
1603
|
|
|
@@ -1605,12 +1638,12 @@ where the invariant closes an architectural failure mode:
|
|
|
1605
1638
|
- §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.
|
|
1606
1639
|
- §file-create-producer-neutral The file contract depends on the operation and target, never the producer identity.
|
|
1607
1640
|
- §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.
|
|
1608
|
-
- §file-create-transaction Success requires both exclusive disk creation and durable incorporation. Approval re-resolves physical containment and policy
|
|
1641
|
+
- §file-create-transaction Success requires both exclusive disk creation and durable incorporation. Approval re-resolves physical containment and policy. Incorporation failure rolls back only the unchanged creation ({§file-delete-revision}); incomplete rollback is an explicit partial-failure Problem. Publication and its filesystem limits are defined by {§file-publication} and {§file-external-race}.
|
|
1609
1642
|
|
|
1610
1643
|
Refusing an occupied non-member follows the POSIX exclusive-create precedent:
|
|
1611
1644
|
namespace occupancy is not secret, but content remains dark.
|
|
1612
1645
|
|
|
1613
|
-
§fs-answer-in-canon **The engine answers
|
|
1646
|
+
§fs-answer-in-canon **The engine answers with the resolved identity.** Log-row pathname columns retain literal canonical keys. Model-facing addresses in receipts, FIND results, the catalog and recovery use their round-trippable spelling ({§fs-canonical-name}); filename facts and native diffs may name the literal key. A miss names the resolved identity, never an echo of the model's spelling. The model's own emission text remains verbatim — history is never rewritten. Rendering does not create another resource identity.
|
|
1614
1647
|
|
|
1615
1648
|
§fs-errno **errno discipline — one error, one meaning, each with its fact.** Error facts speak wire canon and state the occurrence, never a tutorial.
|
|
1616
1649
|
|
|
@@ -1625,7 +1658,7 @@ Every fact names the canonical key, never the host root or an echo of the
|
|
|
1625
1658
|
model's spelling. These classes let a caller distinguish a wrong address, an
|
|
1626
1659
|
invalid range, read-only authority, and occupied hidden state without guessing.
|
|
1627
1660
|
|
|
1628
|
-
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member
|
|
1661
|
+
§membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the reusable member address ({§fs-answer-in-canon}, {§file-url}). Recovery offers listing with FIND, creation with EDIT, and admission with `members (add)` as alternatives and presumes none ({§diagnostic-observation}): `` FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"alias": "<name>", "definition": {"glob": "<path>"}}` body. `` The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo, and their recovery speaks of the address too, true under every members scope: `'<key>' is outside the project root: only a members definition under the operator's namespace scope admits it.` Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.`, with admission-only recovery; a path the repository ignores, which no model definition admits, carries the members discovery verdict instead: `The repository ignores it: a client or operator members definition can include it, a model definition cannot.` Occupancy may surface there; content never does ({§membership}).
|
|
1629
1662
|
|
|
1630
1663
|
§file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file: READ and KILL answer 404, EDIT 403. The detail is `'<key>' is a directory, not a file; <OP> reads/removes/writes one file.`; a READ or KILL carries the listing as its recovery, `` `FIND (<key>/)` lists its files. ``, and an EDIT carries none. Beyond the root the disk stays dark and {§membership-read-refusal} holds unchanged.
|
|
1631
1664
|
|
|
@@ -1654,7 +1687,7 @@ metadata or channels.
|
|
|
1654
1687
|
|
|
1655
1688
|
§op-methods-op-dispatch Engine operation ownership follows the public scheme contract:
|
|
1656
1689
|
|
|
1657
|
-
- Each
|
|
1690
|
+
- Each resolved EDIT target dispatches through `editBatch` with one statement.
|
|
1658
1691
|
- A log KILL dispatches only to the core-owned log curation handler ({§log-kill-scope}); an entry scheme's `kill` method never sees a `log:///` target.
|
|
1659
1692
|
- Other delegated operations use the corresponding lowercase `SchemeHandler` method, with standard FIND supplied for a data scheme that omits a custom implementation.
|
|
1660
1693
|
- COPY and MOVE are engine-owned compositions over CRUD primitives ({§copy}/{§move}).
|
|
@@ -1682,10 +1715,10 @@ Registration precedes loop affinity:
|
|
|
1682
1715
|
| Observation | Responses are unseen retrieval work; completion follows {§send-premature-terminate}. |
|
|
1683
1716
|
|
|
1684
1717
|
- §op-synchronous **Decisive operations settle before the next operation.** The dispatcher awaits each operation and its proposal resolution. Work remains in flight only when the operation's contract deliberately creates concurrency: FORK, WORK, a stream-producing execution, and streaming READ after acquisition. Such a READ first establishes its durable subscription and returns `102`; a later operation may address that live owner. Dispatching an execution before KILL does not wait for the process to finish using a resource. KILL of a worker synchronously ends its live loops before disposition checks the pending set; physical scope cleanup remains asynchronous.
|
|
1685
|
-
- §edit-execution **One
|
|
1718
|
+
- §edit-execution **One resolved EDIT target is one mutation.** Each EDIT resolves against current resource state when dispatch reaches it, owns its proposal when gated, and records its own resulting revision. No later EDIT is prepared or applied in advance. Numeric scopes address current coordinates; an earlier EDIT may change what those numbers select. Rejection applies only to that operation, not its successful siblings.
|
|
1686
1719
|
- §edit-anchor-continuity **Own EDITs preserve untouched hash targets within one program.** Core carries an anchor through exact, successfully applied EDIT splices when its line survives unchanged, even if its ordinal or neighborhood changes. Scoped entry KILL uses the same deletion path. Target-line replacement or deletion invalidates that binding. Continuity is private to the admitted program and canonical resource/channel; it is not a new published anchor format. The complete normalized line content must match the expected result of the preceding recorded EDIT, otherwise retained bindings are discarded and ordinary current-state validation applies. Reviewer replacement and results without an applied EDIT receipt do not carry bindings forward. A retained binding resolves alone: a twin neighbourhood this program's own splice created elsewhere does not make the carried anchor ambiguous, and an anchor the program never bound resolves against current state. Normalization is the same line-content representation used by READ and line hashing; file-write revision checks remain independent. No approximate text matching is used. Lowered coordinates retain a current-anchor precondition at the mutation owner; ambiguous matches and concurrent changes remain collisions.
|
|
1687
1720
|
- §anchor-offset **An anchor offset is tolerated, never taught (#749).** A line mark may carry an offset from its anchor (`@abcde+1`, `@abcde-2`), and a bare `+N` after an anchor counts from that anchor (`<@abcde,+1>`). The anchor resolves as usual and the offset is added; a result before line 1 is an invalid mark, and past the end is the ordinary range refusal. Continuity and current-anchor preconditions check the anchor's own line. `plurnk.md` keeps its two anchor forms. Numeric relative endpoints normalize under {§scope-range-recovery}; a reversed range produced by anchor resolution is never reinterpreted as a count.
|
|
1688
|
-
- §edit-batch **One compound operation may require atomic splices.** The scheme's `editBatch` primitive validates all supplied numeric edits against one snapshot and commits one revision or none. Core supplies one statement
|
|
1721
|
+
- §edit-batch **One compound operation may require atomic splices.** The scheme's `editBatch` primitive validates all supplied numeric edits against one snapshot and commits one revision or none. Core supplies one statement per resolved EDIT target; same-resource MOVE can supply multiple splices as one operation. This primitive does not group separate targets or authored operations. Its replacement, insertion, conflict, and receipt rules remain owned by the shared Slicer.
|
|
1689
1722
|
- §edit-batch-receipt **A refusal describes its own unapplied work.** An anchor collision lists every distinct unresolved anchor in that EDIT, including both range endpoints, in `unresolvedAnchors` (`anchor`, `kind: missing | ambiguous`, and matching `lines` when ambiguous). Missing is not proof of earlier validity or subsequent change. It carries `editCount: 1`, `applied: 0`, and recovery directing a READ for current coordinates; it makes no claim about other operations. A refused compound splice batch lists all conflicting pairs in `conflicts`, non-conflicting regions in `cleanRegions`, its first pair in `conflictingRegions`, and its own `editCount` and `applied: 0`.
|
|
1690
1723
|
- §edit-batch-merges **Normalizations require evidence and a receipt.** An EDIT body carrying only this resource's published `L<@xxxxx>` prefixes (the number right-aligned) is stripped when those prefixes verify against current anchors or this worker's preserved READ receipts (`rendered-prefix-stripped`); otherwise it remains literal content (`rendered-prefix-unverified`). Within a single atomic splice batch, the Slicer can deduplicate identical regions/bodies, concatenate same-boundary insertions, assign a shared endpoint to the sole body reproducing that line, or relocate an inner change when its original content occurs exactly once in the outer body. An already-applied inner body can be dropped. Unevidenced overlap remains a collision. These batch resolutions never reinterpret separate authored EDITs. Applied normalizations carry their exact merge facts and a notice; receipts describe only the applied effects.
|
|
1691
1724
|
|
|
@@ -1697,6 +1730,34 @@ a resource, channel, and optional text scope ({§transfer-resource-selections}).
|
|
|
1697
1730
|
Source acquisition follows {§universal-read-composition}; landed mutation
|
|
1698
1731
|
effects follow {§edit-result-copy-move-effects}.
|
|
1699
1732
|
|
|
1733
|
+
§bulk-resource-targeting **Path selectors resolve before resource operations.** Core
|
|
1734
|
+
uses ordinary FIND selection, without a FIND receipt, to resolve glob/extglob
|
|
1735
|
+
operands ({§path-glob-matching}). Resolution occurs when dispatch reaches the
|
|
1736
|
+
operation, not when the turn is parsed. Each selected address retains the
|
|
1737
|
+
authored channel; scopes and content matchers belong to the selected resource.
|
|
1738
|
+
|
|
1739
|
+
| Operation | Selection and execution |
|
|
1740
|
+
|---|---|
|
|
1741
|
+
| READ | The ordinary FIND resource page, optionally filtered by the content matcher; each target receives an exact READ ({§read-fan-out}). |
|
|
1742
|
+
| EDIT, resource KILL | The complete matching path set, not the FIND preview page. Content matchers do not filter this set: each target independently validates and applies its scope, matcher and body through the ordinary mutation owner. No paths means one 204 receipt and no mutation. |
|
|
1743
|
+
| COPY, MOVE | Each glob operand must resolve to exactly one resource. Zero or multiple matches refuse the pair with `target-cardinality` before either side changes. Exact destinations retain ordinary creation semantics. Explicit pairs express bulk transfers; no implicit concatenation, folder mapping or positional pairing. |
|
|
1744
|
+
| Log KILL | The existing curation selector owns the complete operation ({§log-kill-scope}), including its snapshot and distillation. |
|
|
1745
|
+
|
|
1746
|
+
Fan-out resolves the address set once and executes in FIND order. Each target
|
|
1747
|
+
has its own admission, current-state validation, proposal and durable receipt;
|
|
1748
|
+
successful siblings survive a later refusal. Fail-on-error stops before the
|
|
1749
|
+
next target ({§op-execution-order}). No cross-resource transaction is implied.
|
|
1750
|
+
Per-target rows carry `attrs.fanout` (`target`, the authored selector; `matched`,
|
|
1751
|
+
the selected resource count; zero-based `index`; `count`, the admitted target
|
|
1752
|
+
count). One authored operation still produces one lifecycle notification pair.
|
|
1753
|
+
The configured command ceiling counts each admitted concrete operation; WAIT
|
|
1754
|
+
remains exempt ({§operator-config-workspace-max-commands}). It never counts an
|
|
1755
|
+
internal survey or a distillation as another command. An entirely omitted
|
|
1756
|
+
statement is not surveyed just to count its possible targets.
|
|
1757
|
+
Dispatch returns core-owned `commandsExecuted` and `commandsOmitted` totals to
|
|
1758
|
+
the turn executor outside operation results, receipts and lifecycle events;
|
|
1759
|
+
scheme result extensions cannot supply these counts.
|
|
1760
|
+
|
|
1700
1761
|
### SEND dispatch (a message to a recipient)
|
|
1701
1762
|
|
|
1702
1763
|
Targetless and exact-message SENDs follow the reply accounting at
|
|
@@ -1913,7 +1974,7 @@ Every entry is uniformly listed in the catalog (```` ```FIND (scheme:///**) ````
|
|
|
1913
1974
|
|
|
1914
1975
|
Mimetype is declared by scheme manifest ({§scheme-manifest}) or supplied per-call for dynamic schemes. Writing a channel without a declared mimetype throws. No default mimetype anywhere.
|
|
1915
1976
|
|
|
1916
|
-
- §channel-mimetype-cross-mimetype-415 COPY/MOVE compatibility follows {§mimetype-verbatim-transfer}; incompatible pairs return 415. Transfers preserve content verbatim and retain the destination's declared type, resolving
|
|
1977
|
+
- §channel-mimetype-cross-mimetype-415 COPY/MOVE compatibility follows {§mimetype-verbatim-transfer}; incompatible pairs return 415. Transfers preserve content verbatim and retain the destination's declared type, resolving an absent channel under {§copy-destination-mimetype}.
|
|
1917
1978
|
|
|
1918
1979
|
### §channel-selection Channel selection in the DSL
|
|
1919
1980
|
|
|
@@ -2126,14 +2187,14 @@ AST: `{ op: "EDIT", target, body: string | null, signal: tags | null, lineMarker
|
|
|
2126
2187
|
({§edit-anchor-continuity}) does not carry through a pattern batch; the next
|
|
2127
2188
|
anchored EDIT validates against current state.
|
|
2128
2189
|
|
|
2129
|
-
A `file:///` member EDIT
|
|
2190
|
+
A `file:///` member EDIT computes against its materialized body and **proposes** (202) conditional file publication under {§membership-edit-write-revision}, {§file-external-race}, and {§proposal}. The marker-required rule applies identically: an existing file is never markerlessly replaced.
|
|
2130
2191
|
|
|
2131
2192
|
### §read READ
|
|
2132
2193
|
|
|
2133
2194
|
AST: `{ op: "READ", target, body: null, signal: tags | null, lineMarker? }`.
|
|
2134
2195
|
|
|
2135
2196
|
A READ is never rewritten into a FIND ({§read-find-normalization}); a path-glob
|
|
2136
|
-
READ
|
|
2197
|
+
READ uses the common resource selector ({§bulk-resource-targeting}, {§read-fan-out}).
|
|
2137
2198
|
|
|
2138
2199
|
- §read-read-content Returns channel content and mimetype.
|
|
2139
2200
|
- §read-read-404 Returns 404 when the channel is absent.
|
|
@@ -2175,16 +2236,16 @@ READ is the one fan-out core performs ({§read-fan-out}).
|
|
|
2175
2236
|
scope, matcher and aside ({§read-selection-projection}, {§read-pattern}), one
|
|
2176
2237
|
receipt row per path in the FIND's order, so every rendered line keeps its path,
|
|
2177
2238
|
physical ordinal and anchor and remains a coordinate source for EDIT and KILL.
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
statement once and folds the paths beneath it without inferring the group.
|
|
2239
|
+
Rows use the shared `attrs.fanout` identity ({§bulk-resource-targeting}), so a
|
|
2240
|
+
client can group the exact receipts under the authored statement.
|
|
2181
2241
|
Without a scope each path uses {§markerless-first-page}; with a pattern
|
|
2182
2242
|
only the matching lines, `grep -n` style. The authored statement contributes
|
|
2183
2243
|
`rowsWritten`, the receipt count, to its turn's sequence. No path is one 204
|
|
2184
2244
|
receipt on the authored glob (`matched: 0` when a pattern selected nothing); a
|
|
2185
2245
|
FIND failure is that failure on the authored glob. The FIND's resource page bounds
|
|
2186
|
-
the fan-out: when more paths matched than
|
|
2187
|
-
notice names both counts.
|
|
2246
|
+
the fan-out: when more paths matched than its page selected, one
|
|
2247
|
+
`read_fanout_bounded` notice names both counts. A separate command ceiling may
|
|
2248
|
+
further limit dispatch ({§bulk-resource-targeting}). Every dialect follows this same READ fan-out;
|
|
2188
2249
|
none substitutes a FIND receipt for the requested content.
|
|
2189
2250
|
|
|
2190
2251
|
§read-pattern-evidence **Match regions survive line-oriented presentation.** A patterned
|
|
@@ -2278,6 +2339,10 @@ AST: `{ op: "KILL", target, matcher: MatcherBody | null, lineMarker: TextLineMar
|
|
|
2278
2339
|
|
|
2279
2340
|
KILL deletes context from the **log** (`log:///`, {§packet}). Without a scope it retires the selected rows from the active projection ({§log-history-projection}). With a one-line or inclusive two-line scope it removes only that body's intersecting body-relative physical lines from the readable projection, and the row stays active. An anchor may be one published on that body or one returned by READing its `log:///` coordinate ({§line-anchors}); an anchor absent from the current body selects no line, as with an out-of-bounds numeric line. Scoped KILL is one-way: intervals accumulate, the durable body is untouched, and subsequent access follows {§log-readable-projection}. A scoped KILL on a bodyless row is a friendly 200 no-op with `matched` reported. An emission row is curated whole ({§emission-row}): the unscoped KILL retires it; a line scope on its exact coordinate addresses its legend and retires the NOTEs on the lines it selects, the row staying; on a row with no legend lines the scope is 422 `emission-curated-whole`, whose recovery names the unscoped KILL; a sweep leaves it intact. A KILL that addresses no row is 404 on an exact coordinate and 204 on a sweep ({§log-curation-folder-idiom}). Selection composes target/glob with an optional heading pattern ({§log-curation-set-selection}).
|
|
2280
2341
|
|
|
2342
|
+
§log-target-tolerances **The log target reader accepts four near-misses of the taught form and reads each as the one target it can only have meant.** The card teaches `KILL (log:///1/[1-7]/*/{READ,emission})`; none of the following is taught, and no diagnostic text accompanies any of them. A `|` between complete KILL targets, each a coordinate, prefix or glob ({§log-coordinate-hierarchy}) written bare or as a full `log:///` address, is their union: `log:///1/25/2/EDIT|log:///1/24/3/EDIT` retires both rows; a piece that is none of those refuses the whole target, 400 `kill-failed`, naming the piece; a list that selects nothing is the sweep's 204 unless every piece is an exact coordinate, when it is the exact miss's 404. `|` is not a character of a coordinate, and file paths, where it is one, are untouched. For KILL and FIND alike: a bracketed comma list in a numeric slot is a set, `log:///1/[19,24]/**/sh` reading as `log:///1/{19,24}/**/sh`, since a character class can never match a turn number; a non-numeric literal in a numeric slot, after at least one numeric slot, is the leaf with the missing slots `*`, `log:///1/*/READ` reading as `log:///1/*/*/READ`; and `*` segments between the sequence and the leaf are dropped, `log:///1/3/3/*/READ` reading as `log:///1/3/3/READ`, since no coordinate holds a segment there.
|
|
2343
|
+
|
|
2344
|
+
§log-target-shape **The refusal of a log target nothing can read shows the working form.** A malformed KILL or FIND target, 400, carries as its recovery the one sentence `` A log target is `log:///<loop>/<turn>/<sequence>` with an optional `/<op>` leaf; a shorter path is a prefix, and `*`, `**`, `[1-7]` or `{a,b}` may stand in any segment. `` It names the shape and presumes nothing about what the author meant ({§diagnostic-observation}). A sweep that matches nothing stays the bare 204 of {§log-curation-folder-idiom} and an exact miss beside rows that exist names them ({§log-near-miss}); neither carries the sentence, so no text rides the packet for the ordinary case.
|
|
2345
|
+
|
|
2281
2346
|
§log-scope-recovery A log-body scope follows the file slicer's range rule ({§range-starts-at-one} in the schemes SPEC): a range starting at 0 — `<0,-1>` included — is refused 416 `range-not-satisfiable` on every body, empty ones too, and never clamped; its detail is the slicer's own sentence, `Range <0,-1> starts at 0, which is not a line; lines are numbered from 1.`, and its recovery names the forms a log body takes — `Trim one line with <L> or lines L through M with <L,M>; KILL (log:///1/9/2/READ) with no scope retires the whole row.` — never the insert and append positions a body cannot take. Every other scope that names no line is 400 `curation-scope-invalid` with the same recovery: the forms that work on that row, never a rebuild of the written scope ({§diagnostic-observation}).
|
|
2282
2347
|
|
|
2283
2348
|
A READ carrying active native media is atomic: any KILL scope is ignored and the entire observation is retired, including its native context contribution ({§packet-attachment-parts}). For a model turn, native activity is the attachment selection in its actual input packet; without a model packet, a native observation is atomic by default. Text-only observations in the same selection retain ordinary scoped behavior. Neither form deletes source data or forensic evidence.
|
|
@@ -2326,6 +2391,32 @@ The `## Log` section is a sequence of ordinary Markdown records separated by one
|
|
|
2326
2391
|
|
|
2327
2392
|
An emission row's body is not in its record ({§emission-row}); its eligible program follows it as a separate assistant message ({§emission-history}). Patterns retain their literal spelling; a pattern containing a line break is JSON-quoted to keep the H3 on one physical line. Receipts are descriptive records, not reconstructed operation headings. Absent fields are not invented. Every physical body line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, so source text cannot create a record boundary. The section contains records only, with no leading prose or enclosing fence.
|
|
2328
2393
|
|
|
2394
|
+
§log-mutation-patch **A settled file mutation's row keeps what it did.** When an accepted EDIT,
|
|
2395
|
+
COPY, MOVE or KILL writes or removes a text member, the file scheme appends the unified diff of
|
|
2396
|
+
that write, `current` to `proposed`, to the operation row it is settling (`log_entries.patch`); a
|
|
2397
|
+
row that settles several writes keeps them in application order. The row serves it as its `patch`
|
|
2398
|
+
channel, `log:///<loop>/<turn>/<item>/<OP>#patch`, `text/x-diff`, for the life of the row: a fork
|
|
2399
|
+
copies it with the row, and it never enters a receipt or a packet unasked. Nothing is kept for a
|
|
2400
|
+
byte write, a member past the materialization bound, or a row settled before this version, and
|
|
2401
|
+
nothing is reconstructed for them: such a row has no `patch` channel, and whatever reads one, a
|
|
2402
|
+
rollback included, fails by name rather than inventing one.
|
|
2403
|
+
|
|
2404
|
+
§rollback **Rollback reverses a worker's settled file mutations, latest first, through ordinary
|
|
2405
|
+
operations.** `rollback({ workspaceId, workerId, clientWorkerId, to })` (`workspace.rollback { to,
|
|
2406
|
+
workerId? }` for a client) names a log coordinate of `workerId`, `<loop>/<turn>/<item>`; the state
|
|
2407
|
+
after that item is what remains. Every settled EDIT, COPY, MOVE or KILL row after it, latest first,
|
|
2408
|
+
has its patch ({§log-mutation-patch}) reversed against the file as it is now and written back as an
|
|
2409
|
+
operation of the acting client in `clientWorkerId`, settled under that worker's owner: a rewrite as
|
|
2410
|
+
`EDIT <1,-1>`, a removed file as a creating `EDIT`, a created file as `KILL`. Each reversal is a
|
|
2411
|
+
proposal, a row and a patch of its own, so a rollback is reviewable afterwards and reversible by the
|
|
2412
|
+
same means. The report (`RollbackReport`) lists what was restored, the rows skipped because they
|
|
2413
|
+
kept no patch or were reversed already (the file is in the state before that mutation, as an earlier
|
|
2414
|
+
rollback left it), and where it stopped: `drift`, the file no longer holds what that mutation wrote,
|
|
2415
|
+
leaves that file and everything earlier untouched; `refused` carries the reversing operation's
|
|
2416
|
+
Problem. A coordinate that is not one of the worker's rows is `404 coordinate-not-found`, a
|
|
2417
|
+
malformed one `400 coordinate-invalid`, and a workspace without a project root `400
|
|
2418
|
+
project-root-required`. Nothing is reconstructed for a patchless row, and the log is never rewritten.
|
|
2419
|
+
|
|
2329
2420
|
§log-address-metadata **Addresses name their relationship, not the row's producer.**
|
|
2330
2421
|
|
|
2331
2422
|
| Spelling | Meaning | Where |
|
|
@@ -2524,6 +2615,7 @@ reads what the model thought and where its content program can be found
|
|
|
2524
2615
|
| A curation that matched nothing (204) | Shown once, in the packet of the very next turn, then retired like any other row. A success and a mismatch are not both silent: the model cannot otherwise tell that its earlier KILL is what emptied the selection (#779). |
|
|
2525
2616
|
| Failed log curation | Visible with its ordinary Problem. |
|
|
2526
2617
|
| Non-log target: file, worker, stream, or other resource | Ordinary scheme-owned receipt. |
|
|
2618
|
+
| The over-budget mandate row ({§context-over-budget-row}) | The same once-shown lifetime: the packet it describes, then retired from the projection, durable and readable at its coordinate. |
|
|
2527
2619
|
|
|
2528
2620
|
This packet filter does not retire the receipt: the operation, result, authored
|
|
2529
2621
|
`turnOps`, and each target's curation effects remain durable under
|
|
@@ -2694,6 +2786,23 @@ Operand syntax: {§transfer-resource-selections}. Result projection: {§copy-mov
|
|
|
2694
2786
|
202 when the owning scheme requires proposal review. Same- and cross-scheme
|
|
2695
2787
|
COPY use this one orchestrator.
|
|
2696
2788
|
|
|
2789
|
+
§copy-destination-mimetype **A transfer carries a type into an untyped destination.**
|
|
2790
|
+
Resolve the destination channel's type in this order, then apply
|
|
2791
|
+
{§mimetype-verbatim-transfer}; a refusal leaves both operands unchanged.
|
|
2792
|
+
|
|
2793
|
+
| Destination evidence | Type |
|
|
2794
|
+
| --- | --- |
|
|
2795
|
+
| Existing channel | Its stored source type, not a derived readable projection. |
|
|
2796
|
+
| Absent channel with a recognized pathname extension | The extension's type under {§ext-mimetype}. |
|
|
2797
|
+
| Absent channel without a recognized extension, with a declared manifest type | The declared channel type, including explicit `text/plain`. |
|
|
2798
|
+
| Absent channel without either declaration | The source's declared type, with automatic `text/plain` normalization under {§markdown-primitive}. |
|
|
2799
|
+
|
|
2800
|
+
The admitted type accompanies the content through proposal review and publication.
|
|
2801
|
+
This rule applies to whole and scoped transfers across entry-bearing schemes;
|
|
2802
|
+
the scheme's text-creation fallback does not override a transfer's supplied type.
|
|
2803
|
+
Filesystem reconciliation retains that type while the verified source revision is
|
|
2804
|
+
unchanged, including readable reprojection; a changed disk source is detected afresh.
|
|
2805
|
+
|
|
2697
2806
|
### §move MOVE (engine-orchestrated)
|
|
2698
2807
|
|
|
2699
2808
|
- §move-relocation-deletes-source MOVE first performs the destination mutation under {§copy}, then removes only
|
|
@@ -2721,7 +2830,10 @@ COPY use this one orchestrator.
|
|
|
2721
2830
|
- A cross-resource destination failure leaves the source untouched. A source
|
|
2722
2831
|
failure after destination success is an explicit partial failure with
|
|
2723
2832
|
`destinationWritten: true` and the destination's identity. Proposal
|
|
2724
|
-
acceptance/rejection follows the same ordered rule.
|
|
2833
|
+
acceptance/rejection follows the same ordered rule. Each approval uses the
|
|
2834
|
+
operand whose effect is pending: its target, metadata, authority and manifest.
|
|
2835
|
+
Source removal retains this binding whether the destination wrote immediately
|
|
2836
|
+
or required its own approval.
|
|
2725
2837
|
- §move-cross-scheme-move Same- and cross-scheme resources use the same
|
|
2726
2838
|
contract; there is no global cross-scheme transaction.
|
|
2727
2839
|
- §move-missing-source-404 A missing source is 404.
|
|
@@ -2737,7 +2849,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2737
2849
|
- §find-line-anchors **A FIND regex anchors each line**, as READ, EDIT and KILL do ({§read-pattern}, {§edit-pattern}): `^` and `$` are a line's ends in every FIND content match — over entries, log rows, turn sources and a binary channel's bytes — so ```` ```FIND (django/urls/resolvers.py) /^from|^import/ ```` locates the same import lines a READ with that pattern shows, never a false 204.
|
|
2738
2850
|
- §find-candidate-containment **One candidate's crash is that candidate's problem** — arbitrary member content can crash a mimetype handler mid-match (an unbalanced template partial crashed Readability and killed a 1,916-file FIND as a blank 500, #449). `Matcher.matchCandidates` contains a per-candidate handler throw: the candidate drops out exactly like unsupported content, the cause goes to daemon stderr, and only a FIND whose every candidate crashed reports a 415 whose Problem names the first crashing member and handler. The operation's other candidates always answer.
|
|
2739
2851
|
|
|
2740
|
-
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a
|
|
2852
|
+
- §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a standard matcher reads it. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns use {§path-glob-matching}. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit extension contract, never inferred from URL punctuation.
|
|
2741
2853
|
|
|
2742
2854
|
Resource-authority globs select authorities independently of the path scope.
|
|
2743
2855
|
Matching resources retain their full addresses through pattern matching,
|
|
@@ -2824,6 +2936,23 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
|
|
|
2824
2936
|
hidden complete row or location collection is retained behind the public
|
|
2825
2937
|
projection.
|
|
2826
2938
|
|
|
2939
|
+
§path-glob-matching Core's `PathGlob` owns shell-path matching and targeted disk
|
|
2940
|
+
traversal through the public `minimatch` and `glob` packages. Resource selection,
|
|
2941
|
+
membership scans, inspection and the membership SQL predicate share this dialect.
|
|
2942
|
+
|
|
2943
|
+
| Input | Meaning |
|
|
2944
|
+
| --- | --- |
|
|
2945
|
+
| `/` | Segment separator; `*` and `?` do not cross it. |
|
|
2946
|
+
| `\*`, `\?`, `\[`, `\\` | Literal wildcard, bracket or backslash, after target-slot decoding ({§path-parentheses}). A backslash is never a pattern's directory separator. |
|
|
2947
|
+
| Braces, character classes, extglobs, `**` | Standard matcher semantics; operation catalogs additionally apply {§find-scope-prefix-filter}. |
|
|
2948
|
+
| Leading `#` or `!` | Filename syntax, not matcher-level comment or negation. The members family owns its leading `!` exclusion marker. |
|
|
2949
|
+
| Dot-prefixed entries | Require an explicit dot except in the complete structural catalogs above. |
|
|
2950
|
+
| Filesystem base | Literal, outside the pattern; its metacharacters and backslashes never become selector syntax. |
|
|
2951
|
+
|
|
2952
|
+
Matching retains the host's conventional case behavior (case-insensitive on
|
|
2953
|
+
Windows/macOS, case-sensitive otherwise). Membership traversal remains
|
|
2954
|
+
pattern-bounded and admits files only; it does not become an unrestricted walk.
|
|
2955
|
+
|
|
2827
2956
|
### §send Messaging and turn disposition
|
|
2828
2957
|
|
|
2829
2958
|
SEND AST: `{ op: "SEND", target: ParsedPath | null, body: SendBody | null, metadata, lineMarker }`.
|
|
@@ -2879,10 +3008,22 @@ When all messages are resolved but new results require another packet, the engin
|
|
|
2879
3008
|
reports only: `All Open Messages resolved. Review new results; emit no OPs if finished.`
|
|
2880
3009
|
The notice creates no state and does not demand another final reply.
|
|
2881
3010
|
|
|
2882
|
-
§worker-obligations A worker holds its unresolved children
|
|
2883
|
-
streams
|
|
2884
|
-
|
|
2885
|
-
|
|
3011
|
+
§worker-obligations A worker holds its unresolved children, its open non-detached
|
|
3012
|
+
streams, and the messages it sent to other workers that await completion while the
|
|
3013
|
+
recipient's loop is live (`worker_obligations`); `loop_obligations` names them per
|
|
3014
|
+
loop. The packet's Delegation list, WAIT, completion and drain wake settlement use
|
|
3015
|
+
that same durable liveness: a worker that messaged another worker parks on an
|
|
3016
|
+
authored WAIT until the completion arrives ({§message-completion}), and with no WAIT
|
|
3017
|
+
joins that work with the bounded park rather than concluding idle.
|
|
3018
|
+
|
|
3019
|
+
§message-abandonment **An ended loop answers what it left open.** When a loop ends,
|
|
3020
|
+
every message another worker sent it that has no completion is completed `499` by the
|
|
3021
|
+
daemon: one `_plurnk` SEND to the message's address in a maintenance turn of the
|
|
3022
|
+
recipient, "Loop *N* ended with status *S*; this message was not answered.",
|
|
3023
|
+
delivered to the sender like any reply ({§message-reply-delivery}). A message the
|
|
3024
|
+
ending loop had not yet published is re-homed first ({§message-loop-containment}) and
|
|
3025
|
+
is not abandoned. The sender's hold ends with the recipient's loop either way; the
|
|
3026
|
+
completion is what wakes it and tells it.
|
|
2886
3027
|
|
|
2887
3028
|
§wait-obligation-matrix **End-of-program resolution.** Execute all admitted operations and settle optimistic work before applying this table. WAIT is an optional yield, not an end-of-program delimiter.
|
|
2888
3029
|
|
|
@@ -3044,7 +3185,9 @@ of which Worker launched it ({§execution-output-identity}).
|
|
|
3044
3185
|
| --- | --- |
|
|
3045
3186
|
| Admission | Require SEND control and the original invocation's runtime/tool capabilities. Preserve its classified effect: host input proposes; pure/read input uses the same effect policy as launch. |
|
|
3046
3187
|
| Acceptance | Recheck both capabilities, workspace, and the exact live subscription. Stale approval cannot reach a replacement invocation. |
|
|
3047
|
-
|
|
|
3188
|
+
| Launched without input | The invocation's preparation declared no receiver ({§executor-live-input}): `409 input-unavailable`, immediately, naming the launch form that opens input. |
|
|
3189
|
+
| Queued for a slot | `409 input-unavailable`, immediately and `retryable`; never wait for an execution slot while blocking another input-dependent execution. |
|
|
3190
|
+
| Admitted, receiver declared, not yet open | Delivery waits for the receiver to register, within the backpressure bound; the execution settling first returns `410 input-closed`. A receiver registered without the declaration is the executor's defect and fails its run. |
|
|
3048
3191
|
| Unknown address | `404 stream-not-found`. A terminal execution or retired input returns `410 input-closed`. |
|
|
3049
3192
|
| Delivery | Serialize accepted inputs per invocation. Preserve authored body and receiver-owned metadata. Receiver success means delivery only, not completion. |
|
|
3050
3193
|
| Backpressure | `PLURNK_SERVICE_EXEC_INPUT_TIMEOUT_MS` bounds each accepted delivery, including its queue residence. Expiry returns `504 input-timeout`; cancellation returns `499 input-cancelled`. Once delivery has begun, retire and abort input on either; delivery may be partial and is never replayed. The execution itself is not implicitly killed. |
|
|
@@ -3363,7 +3506,7 @@ The runtime scheme participates in the durable lookup; a completed `sh:///`
|
|
|
3363
3506
|
stream cannot fall through an internal `exec`-only query. {§stream-control}
|
|
3364
3507
|
|
|
3365
3508
|
§workspace-env **Workspace environment.** The `env` family has workspace defaults and
|
|
3366
|
-
worker overrides. Its
|
|
3509
|
+
worker overrides. Its management verbs accept `scope: "workspace" | "worker"`; model calls
|
|
3367
3510
|
default to `worker`. Client actions bind the scope in `workspace.env.*` or
|
|
3368
3511
|
`worker.env.*`. An explicit scope must agree with that action's context.
|
|
3369
3512
|
|
|
@@ -3381,35 +3524,26 @@ lower entry and its enabledness ({§configuration-definition-resolution}). Forki
|
|
|
3381
3524
|
affect subsequent launches, not existing processes or other workspaces. A shared
|
|
3382
3525
|
capability never acquires an invoking worker's overrides or ownership.
|
|
3383
3526
|
|
|
3384
|
-
§exec-env-scoped **
|
|
3385
|
-
environment
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
`NPM_TOKEN` to every command a model writes. Membership is an allowlist: the shipped
|
|
3405
|
-
`INHERIT` is what a shell, git, node and python need to run, and an operator who wants a
|
|
3406
|
-
tool's credential reachable by model-written commands adds it by name. An empty policy admits
|
|
3407
|
-
nothing ambient — the allowlist is declared in `.env.defaults`, so an empty one is a cleared
|
|
3408
|
-
policy rather than an unconfigured install.
|
|
3409
|
-
|
|
3410
|
-
The full composition for one spawn, nearest setter winning for defaults and ceilings immune,
|
|
3411
|
-
is package floors → operator cascade → ambient policy → workspace entries → worker entries → the op's modifier →
|
|
3412
|
-
body prefixes.
|
|
3527
|
+
§exec-env-scoped **Command environment admission.** Core composes an ordinary executor's
|
|
3528
|
+
environment; the executor spawns with the environment it is handed ({§workspace-env}).
|
|
3529
|
+
|
|
3530
|
+
| Input | Admission |
|
|
3531
|
+
|---|---|
|
|
3532
|
+
| Ambient host values | `PLURNK_SERVICE_EXEC_ENV_INHERIT` admits exact names or one trailing-`*` prefix glob; `_EXCLUDE` removes names with the same syntax. An empty inherit list admits nothing. |
|
|
3533
|
+
| Reserved names | `PLURNK_*` and provider credential names from the model catalog or `PLURNK_PROVIDERS_PROVIDER_<ID>_API_KEY_ENV` are excluded from the ambient base regardless of those selectors. |
|
|
3534
|
+
| Workspace and worker entries | Explicit non-reserved values and masks compose at spawn under {§env-functionality}. Reserved names are refused at admission. |
|
|
3535
|
+
| Invocation `env` | Explicit non-reserved values override the composed environment under {§env-option}; the same reserved-name refusal applies. |
|
|
3536
|
+
|
|
3537
|
+
Explicit values do not widen ambient inheritance. The allowlist is declared under
|
|
3538
|
+
{§operator-config-env-defaults}; it limits other host credentials too, not only provider keys.
|
|
3539
|
+
Each spawn records admitted values and their provenance (host, workspace, worker, inherited
|
|
3540
|
+
worker, modifier, or masked); the digest renders that record beside the operation.
|
|
3541
|
+
|
|
3542
|
+
This is environment admission, not process containment or a prohibition on an approved
|
|
3543
|
+
program setting its own variables. Module-owned launches use the owning module's contract:
|
|
3544
|
+
the host supplies a filtered ambient base through {§module-seam-slices}, while explicit
|
|
3545
|
+
MCP bindings resolve under {§mcp-launch-environment}. The env family's reservation does not
|
|
3546
|
+
filter those explicit bindings or create a second approval path.
|
|
3413
3547
|
|
|
3414
3548
|
- §env-option **The op's environment.** `env` is the service's key in the heading's `[metadata]`
|
|
3415
3549
|
({§scheme-metadata-modifier}): `[{"env": {"NAME": "value"}}]`, an object of string values.
|
|
@@ -3419,7 +3553,8 @@ body prefixes.
|
|
|
3419
3553
|
retain explicit launch overrides when adding a process-backed definition; it never
|
|
3420
3554
|
persists the composed ambient environment. On
|
|
3421
3555
|
WORK and FORK it is the child's starting environment: after the copy the child inherits
|
|
3422
|
-
({§functionality-scope}), each name
|
|
3556
|
+
({§functionality-scope}), each supplied name replaces its copied definition as an enabled child-owned entry
|
|
3557
|
+
through the family's `replace` and `enable`,
|
|
3423
3558
|
so a parent hands down its registry and overrides specific names for one child in one heading.
|
|
3424
3559
|
Names follow the family's admission — a name a shell can export, never plurnk's own — and a
|
|
3425
3560
|
refusal names the key and the reason at the operation, before anything runs or is created; a
|
|
@@ -3451,7 +3586,21 @@ body prefixes.
|
|
|
3451
3586
|
- **Loop disposition** ({§proposal-disposition}) — core applies the exact automatic accept/reject before observational subscribers run; automatic policy is not an event listener or client fallback.
|
|
3452
3587
|
- §proposal-timeout-cancels **Timeout is OPT-IN; an empty deadline WAITS** - an empty `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait. Indefinite is with respect to the clock alone: the wait ends with its loop. A loop whose signal aborts — its own timeout, `loop.cancel`, worker `KILL` — settles every proposal it is holding through {§proposal-cancel-aborts}, carrying the abort's reason as the outcome, because a cancelled loop is not a loop awaiting a decision.
|
|
3453
3588
|
|
|
3454
|
-
|
|
3589
|
+
§proposal-decision-evidence Each proposal has at most one immutable decision record,
|
|
3590
|
+
committed before application. It contains the original accept/reject/cancel,
|
|
3591
|
+
resolver identity, decision time, and any submitted body override and outcome.
|
|
3592
|
+
Client decisions name the authenticated worker owner; automatic policy, timeout,
|
|
3593
|
+
abort, and shutdown decisions name `_plurnk`. This records the resolving authority,
|
|
3594
|
+
not an assertion that a human reviewed the operation. A failed decision write
|
|
3595
|
+
prevents application and surfaces its cause. The applied result is separate:
|
|
3596
|
+
acceptance followed by failure remains acceptance. Restart preserves recorded
|
|
3597
|
+
decisions, marks interrupted application uncertain, and never replays it
|
|
3598
|
+
({§worker-lifecycle-restart-recovery}). Decision evidence follows its operation's
|
|
3599
|
+
history lifetime, survives log curation, and appears in forensic output, not in
|
|
3600
|
+
the model packet. Historical rows receive no invented decisions.
|
|
3601
|
+
|
|
3602
|
+
**The decision drives a one-way state transition** on `log_entries.state`.
|
|
3603
|
+
A second resolution is refused with `409 proposal-not-pending`:
|
|
3455
3604
|
|
|
3456
3605
|
| decision | state | `status_rx` | default outcome | effect |
|
|
3457
3606
|
|---------------------------------|---|---|---|---|
|
|
@@ -3624,6 +3773,26 @@ The model is NOT a stream/event consumer — turn-based only; sees whatever's in
|
|
|
3624
3773
|
|
|
3625
3774
|
SQLite (`node:sqlite`) with WAL mode and STRICT tables. Hand-written DDL; CI-aligned against grammar schemas.
|
|
3626
3775
|
|
|
3776
|
+
### §db-durability Connection durability
|
|
3777
|
+
|
|
3778
|
+
The service launcher applies `PLURNK_SERVICE_SQLITE_SYNCHRONOUS` through SqlRite's
|
|
3779
|
+
connection options before migrations or `INIT` write anything. The same policy
|
|
3780
|
+
reaches the writer and read pool on every open, including `migrate` and reopening
|
|
3781
|
+
an existing database. Its default lives in `.env.defaults`; an invalid value is
|
|
3782
|
+
diagnosed by `config check` and refuses database admission, never silently choosing
|
|
3783
|
+
a weaker mode. Configuration inspection and editing remain available.
|
|
3784
|
+
|
|
3785
|
+
| Mode | WAL guarantee |
|
|
3786
|
+
| --- | --- |
|
|
3787
|
+
| `FULL` | Each committed transaction is synchronized to storage, surviving application/OS crashes and power loss when the filesystem and device honor synchronization. |
|
|
3788
|
+
| `EXTRA` | Same guarantee as `FULL` in WAL mode. |
|
|
3789
|
+
| `NORMAL` | Consistent after a crash, but recent commits may be lost after an OS crash or power loss. |
|
|
3790
|
+
| `OFF` | Unsynchronized writes; a crash may corrupt the database. |
|
|
3791
|
+
|
|
3792
|
+
These are [SQLite's guarantees](https://www.sqlite.org/pragma.html#pragma_synchronous),
|
|
3793
|
+
not filesystem-write atomicity, external-effect rollback, a backup, or protection
|
|
3794
|
+
against storage hardware that fails to honor synchronization.
|
|
3795
|
+
|
|
3627
3796
|
### DDL strategy
|
|
3628
3797
|
|
|
3629
3798
|
No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, explicit `NOT NULL`, indexed query paths, deliberate FK `ON DELETE`/`ON UPDATE`, `WITHOUT ROWID` where access pattern warrants, generated columns, FTS5.
|
|
@@ -3640,7 +3809,19 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
|
|
|
3640
3809
|
| §db-maintenance-optimize Statistics at shutdown | The daemon's last database step before the caller closes SQLite is `PRAGMA optimize` on the writer (`maintenance_optimize`), so `sqlite_stat1` reflects tables the connection planned against, bounded by SQLite's own analysis limit; a failure there is a reported shutdown error, never silent. Retention runs before it under the operator's policy ({§retention-policy}) and ends with a WAL truncation ({§db-space-reclamation}); no periodic `ANALYZE` runs. |
|
|
3641
3810
|
| §db-space-reclamation The daemon keeps its own file healthy | `PLURNK_SERVICE_AUTO_VACUUM` (`incremental` or `none`) names the mode the daemon keeps its file in. At start, before any drain, a database in another mode is converted (set the mode, one `VACUUM`, which rewrites the file and needs free disk about its size) and the journal says so with page counts before and after. Under `incremental`, every retention pass ends by stepping `PRAGMA incremental_vacuum` to completion once free pages reach `PLURNK_SERVICE_RECLAIM_MIN_FREE_BYTES` (0 = every pass), and reports `reclaimedPages`; below the floor, free pages stay for SQLite to reuse. Under `none` the file never shrinks and freed pages are reused. No operator step is involved beyond the knobs. The WAL stays bounded by SQLite's automatic checkpoint (#764). |
|
|
3642
3811
|
| §content-store Every body is stored once | `contents` holds each settled body once, addressed by its SHA-256, however many channels, workspaces, forks or derivations carry it; rows are immutable. `entry_channel_rows` points a settled channel at its body and keeps an active stream's body as a private buffer until it settles, when it is interned. Every reader and writer uses the `entry_channels` view, whose `INSTEAD OF` triggers intern bodies, refuse a bound `content_hash` that is not the content's, and write each column group only when it changed, so a search attachment is never a representation write. SQLite counts no changes for a view, so a write that must know whether its channel exists returns the channel's name; an outer join cannot flatten the view, so the two statements that need one read `entry_channel_rows` and `contents` directly. `derivation_fts` is an external-content index over `derivation_texts` (a derivation joined to its body); `derivations.content_id` names the indexed text, and the triggers in `_entry-fts.sql` move the index with it and forget it on delete. A body no channel holds and no derivation indexes is collected by retention under `PLURNK_SERVICE_COLLECT_CONTENTS`. Witnesses: `test/intg/retention.test.ts`, `test/intg/entries.test.ts`, `test/intg/fulltext-index.test.ts`. |
|
|
3643
|
-
| §retention-policy Retention
|
|
3812
|
+
| §retention-policy Retention separates evidence classes | `Retention` reads the owning `.env.defaults` policy at daemon start and runs on its configured cadence and at shutdown. Packet count/age controls retire completed turns' `turn_sections`. Response controls atomically retire a logical call's normalized response and every physical-request payload, including failed retries; its immutable retirement timestamp remains. Count means the newest payload-bearing logical calls per loop, not individual retries, and retired calls retain their chronological place. Either bound can expire an item; `-1` disables only that bound. Open turns, calls and requests are excluded. Messages, log rows, turn sources, approval decisions, request identities, status, admission, failure, capacity and accounting follow their containing history's lifetime. Collectors remove unreferenced packet items, derivations, text and native contents ({§native-content-lifetime}); derivation deletion removes its search projections. These controls are not a whole-database size bound or content-erasure policy: canonical history can retain text also captured in a retired payload. Invalid policy withholds retention and storage conversion, reports a configuration diagnostic and leaves the repair environment available ({§configuration-repair-path}); storage I/O failures remain failures. Reclamation follows {§db-space-reclamation}. |
|
|
3813
|
+
|
|
3814
|
+
§native-content-lifetime Native snapshots remain while any retained READ result,
|
|
3815
|
+
message attachment (inbound or outbound), or stored packet references their hash.
|
|
3816
|
+
Log curation, reply completion, source replacement and source deletion do not
|
|
3817
|
+
release those historical references. `COLLECT_CONTENTS` removes only unreferenced
|
|
3818
|
+
native bytes, alongside unreferenced text. Resource operations and message
|
|
3819
|
+
admission share the in-flight content-use boundary with derivation work
|
|
3820
|
+
({§derivation-in-flight}): collection skips a busy boundary, new producers wait
|
|
3821
|
+
for an active collection, and success or failure releases the use. Operations
|
|
3822
|
+
remain concurrent; this boundary grants neither file ownership nor reservation.
|
|
3823
|
+
Interrupted, unpublished snapshots become collectible after restart. Containing
|
|
3824
|
+
history deletion releases its references normally.
|
|
3644
3825
|
|
|
3645
3826
|
- DDL = storage truth; JSON Schemas = wire truth. They are allowed to differ where ergonomics demand.
|
|
3646
3827
|
- §entry-identity-no-null **Identity components are never NULL.** `(workspace_id, scheme, authority, pathname)` is a unique key. `workspace_id` references the workspace directly with cascading deletion. Namespace schemes use empty authority; resource schemes retain their canonical authority. File members use nonempty `scheme="file"` and render as bare paths. Registration refuses `storedScheme: null`.
|
|
@@ -3952,19 +4133,20 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
|
|
|
3952
4133
|
| Var | Purpose |
|
|
3953
4134
|
|---|---|
|
|
3954
4135
|
| `PLURNK_SERVICE_DB_PATH` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
4136
|
+
| `PLURNK_SERVICE_SQLITE_SYNCHRONOUS` | Connection-time WAL durability: `OFF`, `NORMAL`, `FULL` or `EXTRA` ({§db-durability}). |
|
|
3955
4137
|
| `PLURNK_SERVICE_SHARE_FOLDER` | Parent of the shares written when no folder is named ({§share-folder}); empty is `$XDG_STATE_HOME/plurnk/shares`. |
|
|
3956
4138
|
| §operator-config-shared-keys `PLURNK_HOST`, `PLURNK_PORT` | The daemon-owned listener's bind address and TCP port; modules mount their paths on that one listener ({§http-host}). **A key the daemon and its clients both read has a shared owner**: `@plurnk/plurnk-contracts` declares these two and the optional `PLURNK_AGUI_URL` on its own panel, the one package every side depends on. The daemon folds it like any installed member's, a client folds it beneath its own, and so neither holds the other's default. The service's `--host` and `--port` flags are generated from that panel. |
|
|
3957
4139
|
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | Hard service ceiling: only `1` admits Git membership and status; every other value denies them. |
|
|
3958
4140
|
| §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
|
|
3959
4141
|
| `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
|
|
3960
4142
|
| `PLURNK_SERVICE_MAX_TURNS` | Operator model-call **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The durable worker-tree budget includes descendant calls, BARE, and park/resume under {§turn-cap-counts-the-tree}; non-model chronology consumes none. |
|
|
3961
|
-
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every
|
|
4143
|
+
| `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every resolved op dispatches. Each concrete operation counts once, whether authored separately, in a group ({§target-group}), or selected by a glob ({§bulk-resource-targeting}). Overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. Lifecycle operations remain exempt ({§operator-config-workspace-max-commands-floor}). Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
3962
4144
|
| §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | Positive ms of cumulative active execution per loop ({§loop-execution-allowance}); excludes parked/queued time. Snapshotted on first execution, retained across wakes. Exhaustion aborts in-flight work and terminates `504 loop_timeout`, including a stuck provider call. |
|
|
3963
4145
|
| `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks workers with a reviewer, otherwise concludes their loop, or returns BARE's failure under {§provider-recovery}. |
|
|
3964
4146
|
| `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
|
|
3965
4147
|
| `PLURNK_SERVICE_MAX_STRIKES` | Consecutive turn-contract strike threshold ({§engine-rails}). |
|
|
3966
4148
|
| `PLURNK_SERVICE_EMISSION_ATTEMPTS` | Completed provider responses allowed beneath one engine turn before frame admission is exhausted. Bounded interior operation errors are admitted without spending this budget. Exhaustion contributes one frame-contract strike under {§invalid-emission-attempts}. |
|
|
3967
|
-
| `PLURNK_SERVICE_BUDGET_PRESSURE` | Budget percentage above which the gauge names its largest rows ({§context-gauge})
|
|
4149
|
+
| `PLURNK_SERVICE_BUDGET_PRESSURE` | Budget percentage above which the gauge names its largest rows ({§context-gauge}); measured before adding the inventory. |
|
|
3968
4150
|
| `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` | How many of the heaviest retained log rows the pressured gauge names ({§context-gauge}). |
|
|
3969
4151
|
| `PLURNK_SERVICE_LINE_ANCHOR_CONTEXT_LINES` | Minimum neighboring lines hashed on each side; repeated handles expand their context ({§line-anchor-disambiguation}). |
|
|
3970
4152
|
| `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
|
|
@@ -4332,7 +4514,7 @@ registry. Deleting the workspace cascades its state; worker lifecycle does not.
|
|
|
4332
4514
|
|
|
4333
4515
|
§functionality-coordinator **One coordinator owns the common lifecycle.**
|
|
4334
4516
|
Functionality families are adapters beneath
|
|
4335
|
-
`list | discover | add | enable | disable | remove`. State and mutations
|
|
4517
|
+
`list | discover | add | replace | enable | disable | remove`. State and mutations
|
|
4336
4518
|
serialize per workspace and family. Scope-bound client actions
|
|
4337
4519
|
`workspace.<family>.<verb>` / `worker.<family>.<verb>` and model manager executors invoke the same
|
|
4338
4520
|
coordinator. Families do not invent another management grammar, proposal
|
|
@@ -4345,10 +4527,52 @@ Retryability describes the actual failed condition, not its numeric status.
|
|
|
4345
4527
|
| `list` | Project definitions, ownership (`origin`), winning configuration source (`provenance`), enabledness, and published preparation outcome: disabled, dormant, active, unavailable with its Problem, or authorization-required. No credential values. |
|
|
4346
4528
|
| `discover` | Return inert candidates for the inputs the family serves ({§functionality-discover-advertisement}). Never install, persist, enable, or execute them. |
|
|
4347
4529
|
| `add` | Admit and persist a local definition, prepare it, and enable it atomically. It may override an inherited definition. Reapplying the same local definition enables it idempotently (200); a different local definition for that alias fails 409 without replacing it. |
|
|
4530
|
+
| `replace` | Assign a complete definition to an explicit alias through {§functionality-replacement}. Preserve existing enabledness; a new alias is enabled. |
|
|
4348
4531
|
| `enable` | Publish an available definition; retry preparation if unavailable. |
|
|
4349
4532
|
| `disable` | Withdraw live capability; retain its definition and saved results. |
|
|
4350
4533
|
| `remove` | Forget the locally owned definition and its enabledness override. Restore any inherited definition with its inherited enabledness. Inherited definitions cannot be removed at this scope. Saved results remain. |
|
|
4351
4534
|
|
|
4535
|
+
§functionality-replacement **Replacement is a named whole-definition assignment.**
|
|
4536
|
+
The shared coordinator admits it through the family's existing schema and adapter,
|
|
4537
|
+
then uses the same serialized preparation and publication path as other mutations.
|
|
4538
|
+
It neither removes the old definition first nor merges omitted fields.
|
|
4539
|
+
|
|
4540
|
+
| Boundary | Outcome |
|
|
4541
|
+
|---|---|
|
|
4542
|
+
| Existing local or inherited alias | Persist the complete admitted definition in the selected scope, retaining the alias's effective enabledness. A local override replaces inherited interpretation context and provenance. |
|
|
4543
|
+
| Absent alias | Create the named local definition, enabled. The alias is required; replacement never derives one. |
|
|
4544
|
+
| Disabled candidate | Persist without preparing that alias. Editing a definition does not enable it. |
|
|
4545
|
+
| Admission, preparation, or publication refuses | Keep the preceding definition, enabledness, attachment and documents. Return the exact failure to either client or model caller. External effects of preparation retain the limits of {§functionality-publication}. |
|
|
4546
|
+
| Authorization required | Publish the existing authorization-required handoff; this is not a failed preparation. |
|
|
4547
|
+
| Identical definition | Retain enabledness and normal attachment reuse; this is not an explicit enable/restart. |
|
|
4548
|
+
|
|
4549
|
+
§functionality-addressing **A family may name definitions by their content.** An adapter that
|
|
4550
|
+
declares `addressing` supplies the input of `add` and the input of `enable`, `disable` and `remove`,
|
|
4551
|
+
and reads from a select input the alias it names; its alias grammar ({§functionality-adapter}) is
|
|
4552
|
+
the identity's own, and the generated teaching's `add` example is that input. Every other rule of
|
|
4553
|
+
the coordinator — ownership, enabledness, `alias-exists`, `alias-unknown`, publication, documents —
|
|
4554
|
+
reads the alias as that identity. The members family names its definitions by their glob
|
|
4555
|
+
({§members-functionality}).
|
|
4556
|
+
|
|
4557
|
+
| Verb | Addressing family |
|
|
4558
|
+
|---|---|
|
|
4559
|
+
| `add` | Admits every definition the body names, or none: one refusal refuses the whole body. Reapplying a definition the scope holds is idempotent; a different definition under the same name is `alias-exists` (409), whose recovery is remove and add. The receipt lists the admitted definitions in body order (`definitions`) and names no one `alias`. Preparation receives them all as its admissions. |
|
|
4560
|
+
| `replace` | Not served: when the name is the definition there is nothing to reassign, so neither projection offers it ({§functionality-discover-advertisement}). |
|
|
4561
|
+
| `enable`, `disable`, `remove` | Take the family's select input; the receipt names the one alias it concerned. |
|
|
4562
|
+
|
|
4563
|
+
§functionality-mutation-status **Mutation status describes the committed resource
|
|
4564
|
+
outcome, not the management invocation's stream lifetime.** Apply these rows in
|
|
4565
|
+
order; refusals retain their own Problems and do not commit a replacement.
|
|
4566
|
+
|
|
4567
|
+
| Outcome | Status |
|
|
4568
|
+
|---|---:|
|
|
4569
|
+
| The resulting definition requires authorization | 202 |
|
|
4570
|
+
| `add` or `replace` creates a local definition, including an override of an inherited definition; an `add` naming several ({§functionality-addressing}) creates any of them | 201 |
|
|
4571
|
+
| `add` reapplies the identical local definition, every one it names; `replace` assigns an existing local definition; `enable`, `disable`, or `remove` settles | 200 |
|
|
4572
|
+
|
|
4573
|
+
`add` of a different local definition remains `alias-exists` (409); `replace` is explicit where a family serves it.
|
|
4574
|
+
Model invocation settlement follows {§functionality-model-mutation} independently.
|
|
4575
|
+
|
|
4352
4576
|
§functionality-discover-advertisement **A family's `discover` advertises exactly the inputs it
|
|
4353
4577
|
serves.** The coordinator builds the family's discover input schema from its declared discovery
|
|
4354
4578
|
({§functionality-discovery-inputs}): the declared inputs with their shared
|
|
@@ -4542,8 +4766,11 @@ set any name it lists or none of them — it answers which names have a **consum
|
|
|
4542
4766
|
a Worker learns the name of a value only the operator can supply. The catalog projects
|
|
4543
4767
|
declarations, never the host environment, so a credential the operator has filled in appears by
|
|
4544
4768
|
name with its documentation and an empty value ({§exec-env-scoped}: referred to by name, never
|
|
4545
|
-
read). `source` selects one declaring package
|
|
4546
|
-
catalog. A
|
|
4769
|
+
read). `source` selects one declaring package; an unknown source is `source-unknown`
|
|
4770
|
+
(400), not an empty catalog. A known source with no matching settable declarations
|
|
4771
|
+
returns an empty candidate list. A request naming neither input is the whole
|
|
4772
|
+
catalog. Files are read with READ; variables are set with `add` or `EDIT (env:///NAME)`.
|
|
4773
|
+
A client's own environment is no input: contributing candidates, it would be a second
|
|
4547
4774
|
door past the ceiling.
|
|
4548
4775
|
|
|
4549
4776
|
The family publishes no process runtimes. Its values are read at the spawn that uses them,
|
|
@@ -4557,7 +4784,7 @@ reserved or masked name is no resource. The family's manager exposes it as the f
|
|
|
4557
4784
|
the value its commands receive now, FIND lists the names in effect and a pattern on it matches
|
|
4558
4785
|
values, COPY carries a value out. The manager's own output streams, eight hexadecimal characters
|
|
4559
4786
|
({§execution-output-identity}), stay the executor's. A write is the Worker's own layer, never the
|
|
4560
|
-
workspace's or the operator's: EDIT sets the whole value through the family's `
|
|
4787
|
+
workspace's or the operator's: EDIT sets the whole value through the family's `replace` for the
|
|
4561
4788
|
Worker, and KILL retires the name from the Worker's commands — `remove` for an entry the Worker
|
|
4562
4789
|
owns, which restores an inherited value, `disable` for an inherited one, which keeps its
|
|
4563
4790
|
definition. Admission is the family's ({§env-functionality}) and its refusal is the operation's
|
|
@@ -4594,7 +4821,7 @@ reach the other, and depth is transitive with no further rule. Each copied entry
|
|
|
4594
4821
|
`inherited`, the Worker that set it, preserved across generations until the child changes that
|
|
4595
4822
|
entry, so `list` never claims the child set what it inherited; a parent's masking of an
|
|
4596
4823
|
ambient name travels the same way. WORK and FORK may hand the child more: the heading's `env`
|
|
4597
|
-
option
|
|
4824
|
+
option replaces and enables the child's own entries after the copy ({§env-option}).
|
|
4598
4825
|
|
|
4599
4826
|
§functionality-state **One durable value per workspace and family.**
|
|
4600
4827
|
`{ version: 1, definitions: { [alias]: { origin, enabled, definition? } } }`
|
|
@@ -4664,7 +4891,7 @@ It then reports `active`, `unavailable`, or `authorization-required`, or the exa
|
|
|
4664
4891
|
publication failure. Resource readiness is not execution liveness: a mutation's
|
|
4665
4892
|
`202 authorization-required` body remains exact, while the finished manager
|
|
4666
4893
|
execution closes with `200`. It does not wait for sign-in. A preparation failure may publish enabled-but-unavailable
|
|
4667
|
-
state; a publication failure never reports a successful mutation. Stream polling,
|
|
4894
|
+
state for other mutations, but `replace` rejects it ({§functionality-replacement}); a publication failure never reports a successful mutation. Stream polling,
|
|
4668
4895
|
waiting, and result observation use the ordinary execution lifecycle, without a
|
|
4669
4896
|
separate deferred-commit queue. An explicit client action publishes now, rejects
|
|
4670
4897
|
a failed preparation, and fails 409 while the workspace is held
|
|
@@ -4703,6 +4930,7 @@ Core's behavior behind them.
|
|
|
4703
4930
|
| Runtime actor | `ensureRuntimeWorker(workspaceId)` | Returns the workspace's `_plurnk` actor, creating it if absent; it always retains runtime ownership. |
|
|
4704
4931
|
| Workspace lifecycle | `forkWorker({ workspaceId, workerId, name? })` | Creates a child worker that branches the source worker's history while sharing workspace state. |
|
|
4705
4932
|
| §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
|
|
4933
|
+
| §methods-workspace-rollback Workspace files | `rollback({ workspaceId, workerId, clientWorkerId, to })` | Reverses `workerId`'s settled file mutations after its coordinate `to` as the client's own operations in `clientWorkerId` ({§rollback}); answers a `RollbackReport`. |
|
|
4706
4934
|
| §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?, workerId?)` | Returns nonempty loop-seed prompts a client addressed to the workspace's model workers, newest-first; `workerId` narrows to one worker. Authorship is the seed message's address ({§message-arrival}): a worker-issued seed (WORK, FORK, SEND to a worker) has none and is never history, whichever worker it seeded; a client prompt at a forked conversation worker is. An omitted limit is `PLURNK_SERVICE_PROMPTS_PAGE`. |
|
|
4707
4935
|
| Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
|
|
4708
4936
|
| §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. |
|
|
@@ -4972,7 +5200,7 @@ adding a loop to it. LOOK text anchors resolve through the same
|
|
|
4972
5200
|
|
|
4973
5201
|
| Event | Payload | When fired |
|
|
4974
5202
|
|--------------------------------------------------------------|---------|------------|
|
|
4975
|
-
| §notifications-operation-event `operation/event` | `ApplicationOperationEvent`: `{ workerId, loopId, turnId, sequence, origin, projectRoot, statement, phase, result? }` | One admitted dispatch starts before capability/proposal admission and settles after its durable receipt(s). Only the settled phase has `result`, the exact returned operation result.
|
|
5203
|
+
| §notifications-operation-event `operation/event` | `ApplicationOperationEvent`: `{ workerId, loopId, turnId, sequence, origin, projectRoot, statement, phase, result? }` | One admitted dispatch starts before capability/proposal admission and settles after its durable receipt(s). Only the settled phase has `result`, the exact returned operation result. Resource fan-out is one dispatch ({§bulk-resource-targeting}); BARE starts before prompt preparation and settles after ordered receipt persistence. Automatic stream observations and log writes are not dispatches. An asynchronous executor's successful dispatch does not assert process exit. An internal exception that prevents settlement has no invented result event. |
|
|
4976
5204
|
| §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. |
|
|
4977
5205
|
| §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. |
|
|
4978
5206
|
| §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. |
|
|
@@ -5162,11 +5390,10 @@ flowchart TD
|
|
|
5162
5390
|
```
|
|
5163
5391
|
|
|
5164
5392
|
- §context-budget **One room.** The budget is the provider's input capacity through the loop's calibration, `floor(inputCapacity / factor)` ({§tokenomics-calibrated-readout}), and it bounds the whole packet — teaching, catalog, log and gauge together. Nothing on the service panel sizes a part of it: no projection share or preview page. When the loop's first response fixes its factor, the budget follows it either way; a room that shrinks under the model is announced by the over-budget row ({§context-over-budget-row}), never hidden by keeping a larger figure.
|
|
5165
|
-
- §context-gauge **One gauge.** Every packet carries one `## Context` section holding one JSON object: `tokens`, the packet's weight as rendered,
|
|
5166
|
-
- §context-pressure-notice **Pressure is one notice.** When the gauge names its inventory ({§context-gauge}) and the packet, with the notice in it, stays within its budget, the packet's notices section carries one `engine:context` notice `budget_pressure`, `level: warn`, whose directive is "YOU MUST NOT exceed budget." and whose message is "Context is at *N*% of budget." *N* is `floor(100 × tokens / budget)` over the gauge's final figures, so the share never disagrees with the gauge, and the notice carries no count of its own. It is decided and rendered with the packet it describes, recurs on every such packet, and is never buffered or sent to clients, which read their own pair ({§tokenomics-client-gauge}). An over-budget packet carries the row instead ({§context-over-budget-row}).
|
|
5393
|
+
- §context-gauge **One gauge.** Every packet carries one `## Context` section holding one JSON object: `tokens`, the packet's weight as rendered, `budget`, the known room, and `percent`, `floor(100 × tokens / budget)` over the gauge's own final figures, so the share never disagrees with the counts beside it; a zero budget states no share. Only when the packet without an inventory strictly exceeds `PLURNK_SERVICE_BUDGET_PRESSURE` of its budget does `largest` name the `PLURNK_SERVICE_BUDGET_LARGEST_ITEMS` heaviest retained log rows as `{path, tokens}`, ranked by weight then path. Unknown budget omits `budget`, `percent` and `largest`. The final `tokens` includes the inventory; over budget, its full configured count remains available for curation ({§context-over-budget-row}). Each log row heading carries its own `tokens`. The gauge is state: it never presents `budget − tokens` as response allowance and carries no mandate.
|
|
5167
5394
|
- §context-fit **One rule: whole if it fits, otherwise as much as fits, then its size and address.** A result the model asked for — a READ without a scope, a FIND, an exec result delivered on close — arrives complete when its weight fits within `budget − tokens` as of that turn, less the room the turn still owes — one receipt's measured weight for each result still to land in it and the emission record that answers it, so that the receipts of a batch and the answer always fit. Otherwise the complete result stays where it was read from and the row is a `413` receipt naming the result's size, its weight, the remaining budget, and the two verbs: `READ` a range, or `KILL` first. A READ of lines carries, above its receipt, the longest prefix of those lines whose row fits that room — the lines with their anchors, the returned range closed on the last line delivered, and the receipt naming the lines delivered; a result whose first line does not fit, a FIND, a stream page and a byte view are bodiless receipts. An arrival the model did not ask for — an inbound `SEND`, a child's conclusion — takes the same bodiless receipt as a fact, not an error: its size and its address. Explicit scopes (`<a,b>`, a pattern, `<1,-1>`) are exact and take the same test. Result cuts are named where they happen: the first page of what came back unasked in size ({§markerless-first-page}) and the cut at the room in the receipt. The optional emission history is whole or absent ({§emission-history}), never a cut.
|
|
5168
5395
|
- §context-verbs **The verbs are the curation.** `READ` with a range takes a piece of what did not fit ({§read-selection-projection}); `NOTE` keeps what the model learned; `KILL` retires rows, ranges and bodies ({§log-kill-scope}) and may carry what it keeps of them as its own NOTE ({§log-kill-distillation}). The daemon adds no other mechanism.
|
|
5169
|
-
- §context-over-budget-row **Over budget is a row and a request, not an ending.** A packet whose weight exceeds `budget` is still submitted when it fits the window ({§context-wall}), and it carries one `_plurnk` error row at the head of its turn, `engine/context/packet-exceeds-budget` 413: "Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn." The row is the mandate and carries no figure: the gauge is the one home for `tokens` and `budget` ({§context-gauge}), and it shows the packet over with the row in it. The row
|
|
5396
|
+
- §context-over-budget-row **Over budget is a row and a request, not an ending.** A packet whose weight exceeds `budget` is still submitted when it fits the window ({§context-wall}), and it carries one `_plurnk` error row at the head of its turn, `engine/context/packet-exceeds-budget` 413: "Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn." The row is the mandate and carries no figure: the gauge is the one home for `tokens` and `budget` ({§context-gauge}), and it shows the packet over with the row in it. The row is shown once, in the packet it describes, then retired from the projection as a no-match KILL receipt is ({§log-kill-meta-operation}): it stays durable and readable at its coordinate, and a later packet that is over carries its own row. Nothing is hidden to make the packet smaller; the response grant is the window's remainder above the provider's output floor ({§provider-output-floor}). The limit protects a loop; it never ends one.
|
|
5170
5397
|
- §context-wall **Only the window ends a loop.** The wall is the provider's physical input limit: `maxInputTokens`, and the context window less the output floor ({§provider-output-floor}). A request over the wall sheds ({§context-own-rows-fit}) and is measured again ({§context-wall-measure}); a packet that cannot fit even as receipts ends its loop with the exact `engine/context/window-overflow` 413 Problem, and no inference request is made. An unknown window has no wall ({§tokenomics-window-unpollable-deliberate}).
|
|
5171
5398
|
- §context-wall-measure **The wall measures the request that will be sent.** The estimate is the packet's weight through its calibration factor ({§tokenomics-calibrated-readout}) and is never assumed to overestimate. A packet that fits by the estimate is assessed by the provider as the exact wire request ({§provider-capacity-admission}): an admission sends it; an exact refusal is the wall's verdict, and the request sheds by the refusal's excess and is assessed again. A provider that can only estimate defers, and the upstream provider is then the capacity oracle: its refusal ends the loop with the provider's own 413.
|
|
5172
5399
|
- §context-own-rows-fit **The model's own rows take the same receipt.** When a request is over the wall by either measure ({§context-wall-measure}), its newest rows that still carry a body or a native part — NOTEs, receipts, delivered results, pictures — render bodiless in the fit rule's receipt shape, newest first and only as many as it takes for the request to fit: the heading, the facts, and `size`, the lines and tokens of what the row stood for. The optional emission history has already been omitted whole ({§emission-history}); an emission record has no body to take. A row whose receipt would weigh no less than its body stays whole. Every body stays stored and readable at its address, the verbs restore the room ({§context-verbs}), and each packet decides afresh from its own newest rows. The daemon chooses nothing to summarize and hides nothing silently.
|
|
@@ -5520,8 +5747,7 @@ retain distinct contracts and lifetimes.
|
|
|
5520
5747
|
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | YOU SHOULD write the canonical form. | content-offset into the model's emission |
|
|
5521
5748
|
| `search_progress` | repository materialization/indexing lifecycle ({§persistent-search-index}); structured phase, count, and percent; `level: info`, `warn` when a completed pass carries failed members ({§derivation-member-failure}), `error` on terminal failure | none | none |
|
|
5522
5749
|
| `git_inspection_refused` | engine membership — automatic Git inspection refused a supplied repository whose config declares a `filter.*` program ({§membership-git-hermetic}); names the key; `level: warn`, once per workspace until the key changes or clears | none | none |
|
|
5523
|
-
| `continued_without_note` | engine turn — a continuing or parked model turn that admitted no NOTE ({§continued-without-note}); `level: warn` | YOU MUST
|
|
5524
|
-
| `budget_pressure` | engine context — a packet within its budget whose gauge is under pressure ({§context-pressure-notice}); `level: warn`; rendered with that packet, never buffered | YOU MUST NOT exceed budget. | none |
|
|
5750
|
+
| `continued_without_note` | engine turn — a continuing or parked model turn that admitted no NOTE ({§continued-without-note}); `level: warn` | YOU MUST record at least one NOTE along with other operations. | none |
|
|
5525
5751
|
| `outside_text` | engine turn — text the emission carried outside its operations, discarded ({§outside-text}); `level: warn` | YOU MUST NOT emit anything except whitespace between fenced operations. | none |
|
|
5526
5752
|
| `invalid_emission` | engine grammar — a response rejected before dispatch; `level: error` | YOU MUST ONLY emit fenced operations; with the parameters, pattern, and terse aside on the fenced Operation line. | content-offset of the parser diagnostic, when it has one |
|
|
5527
5753
|
| `output_truncated` | engine capacity or turn — an emission cut at the output allowance ({§output-allowance-notice}); `level: error` when the cut response was rejected, otherwise `warn` | YOU SHOULD emit fewer or shorter operations per turn. | none |
|
|
@@ -5529,19 +5755,19 @@ retain distinct contracts and lifetimes.
|
|
|
5529
5755
|
| `provider_retry` | a provider stream that failed after output began and was answered by a complete retry; `level: warn` | none | none |
|
|
5530
5756
|
| `provider_unavailable` | engine provider — a provider failure retried within its recovery budget | none | none |
|
|
5531
5757
|
| `path_normalized` | file scheme — a path resolved to its canonical spelling; `level: warn` | YOU SHOULD address the resolved path. | none |
|
|
5532
|
-
| `read_fanout_bounded` | engine dispatcher — a READ whose glob matched more paths than
|
|
5758
|
+
| `read_fanout_bounded` | engine dispatcher — a READ whose glob matched more paths than its resource page selected; `level: warn` | YOU SHOULD narrow the glob, or FIND first. | none |
|
|
5533
5759
|
| `parse_issues_unavailable` | engine mimetype — parser recovery evidence unavailable for a mimetype; `level: warn` | none | none |
|
|
5534
5760
|
| `metadata_ignored` | engine dispatcher — `[metadata]` on an operation whose scheme takes none, run without it; `level: warn` | YOU SHOULD NOT write [metadata] on an operation that takes none. | none |
|
|
5535
5761
|
| `scope_normalized` | engine slicer — a scope normalized to its canonical form; `level: warn` | YOU SHOULD write the normalized scope. | none |
|
|
5536
5762
|
| `edit_merged` | engine slicer — an EDIT resolution rule applied to a batch ({§edit-batch-merges}); `level: warn` | YOU SHOULD verify the merged EDIT before building on it. | none |
|
|
5537
5763
|
|
|
5538
|
-
§continued-without-note **A continuing turn that lapsed from the per-turn rule is told so.** The card's rule is one line, `YOU MUST
|
|
5764
|
+
§continued-without-note **A continuing turn that lapsed from the per-turn rule is told so.** The card's rule is one line, `YOU MUST record at least one NOTE along with other operations.`, and the daemon's directive quotes it. When a model turn settles at 102 or 202, so the loop continues past it or parks on it, and it admitted no NOTE in its program or from its reasoning ({§reasoning-operations}), the next packet carries one `engine:turn` notice, `continued_without_note`, `level: warn`, with that directive and the message `The turn continued without a NOTE.`; when its program was NOTEs and nothing else, the next packet carries `noted_without_operation`, the same directive and the message `The turn carried NOTEs and no other operation.` Each is a notice, never a failure: it mints no row, never counts toward the strike rail, and never ends or alters a loop. A turn that concludes its loop, an empty turn, which carries its own no-operation row, and every non-model turn take none.
|
|
5539
5765
|
|
|
5540
5766
|
§notice-callout **A notice speaks in the card's callout form.** Each renders as one alert callout, its level choosing the callout: `> [!CAUTION]` for `error`, `> [!WARNING]` for `warn`, and `> [!NOTE]` for `info`, which no model packet carries. Inside it stand the directive ({§notice-directive}), then the message, any typed position as `@ line:column`, and the kind in brackets; a blank line separates consecutive callouts:
|
|
5541
5767
|
|
|
5542
5768
|
```text
|
|
5543
5769
|
> [!WARNING]
|
|
5544
|
-
> YOU MUST
|
|
5770
|
+
> YOU MUST record at least one NOTE along with other operations. The turn continued without a NOTE. [continued_without_note]
|
|
5545
5771
|
```
|
|
5546
5772
|
|
|
5547
5773
|
§notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `output_unaccounted` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
|
|
@@ -5664,12 +5890,15 @@ Core registers the `members` family with the coordinator ({§functionality-coord
|
|
|
5664
5890
|
the model, the client, and the operator learn one surface — `list | discover | add |
|
|
5665
5891
|
enable | disable | remove`, `workspace.members.<verb>` for the client,
|
|
5666
5892
|
```` ```members (<verb>) ```` for the model — for what the model may see, exactly as they do for skills and
|
|
5667
|
-
MCP servers. A definition is one
|
|
5668
|
-
root; a leading `!` excludes matching members, and an exclusion wins over every inclusion.
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5893
|
+
MCP servers. A definition is one shell-path glob ({§path-glob-matching}) relative to the project
|
|
5894
|
+
root; a leading `!` excludes matching members, and an exclusion wins over every inclusion. The glob
|
|
5895
|
+
is the definition's identity ({§functionality-addressing}): `add` takes `{"files": ["<glob>", …]}`
|
|
5896
|
+
and admits each glob, trimmed, as one definition, a glob named twice being one; `enable`, `disable`
|
|
5897
|
+
and `remove` take `{"file": "<glob>"}`, the glob as `list` shows it. A bare `!` is 400
|
|
5898
|
+
`definition-invalid`. Admission provenance (`service-configuration`, `client-action`,
|
|
5899
|
+
`model-proposal`) rides the persisted definition, `{ glob, provenance }`, to enforce
|
|
5900
|
+
{§members-model-scope}; configuration-source provenance belongs to the shared inspection projection
|
|
5901
|
+
({§configuration-provenance}). `list` shows each
|
|
5673
5902
|
definition with what it resolved to — `include` or `exclude`, the pattern, the members it
|
|
5674
5903
|
admits or removes (count and a bounded sample), and for a model's inclusion the matches the
|
|
5675
5904
|
repository's ignore rules refused — so the model sees what its glob did and adapts.
|
|
@@ -5680,7 +5909,9 @@ or exclude. A query that names neither, blank or a bare `!`, is 400 `query-inval
|
|
|
5680
5909
|
never content; nothing is added.
|
|
5681
5910
|
|
|
5682
5911
|
§members-configuration *Available definitions.* `PLURNK_MEMBERS_<alias>=<glob>`
|
|
5683
|
-
declares one service-origin rule (`!glob` excludes)
|
|
5912
|
+
declares one service-origin rule (`!glob` excludes), named by its glob like every definition; the
|
|
5913
|
+
key is its configuration provenance, which `list` shows, and two keys declaring one glob fail by
|
|
5914
|
+
name. The shared naming and
|
|
5684
5915
|
enabledness dialect is {§resource-environment}; `PLURNK_MEMBERS_ENABLED` supplies
|
|
5685
5916
|
the panel default and `PLURNK_MEMBERS_<alias>_ENABLED` overrides one rule.
|
|
5686
5917
|
An empty glob or a bare `!` fails validation. Controls may precede their rule;
|
|
@@ -5707,7 +5938,8 @@ the repository ignores ({§membership-model-universe}). The engine's creation re
|
|
|
5707
5938
|
overwrites or retires them. Projection happens at the family's publication commit and
|
|
5708
5939
|
re-resolves membership; workspace cooling changes nothing, because desired state is
|
|
5709
5940
|
durable. Each enabled definition is one generated document at
|
|
5710
|
-
`worker:///_plurnk/members/<
|
|
5941
|
+
`worker:///_plurnk/members/<glob>.md` ({§functionality-documents}), the glob percent-encoded as
|
|
5942
|
+
one path segment (RFC 3986 unreserved characters and parentheses stay literal) — its glob, origin,
|
|
5711
5943
|
provenance, and what it resolved to — surveyed at turn 0 like every family's enabled
|
|
5712
5944
|
definitions ({§actor-boundary-catalog-preview}), so the model sees why a file is or is
|
|
5713
5945
|
not a member before it asks. There is no other membership path: the client's `/members`
|
|
@@ -5998,12 +6230,12 @@ repair neighboring punctuation. Readable projections have their own coordinates.
|
|
|
5998
6230
|
|
|
5999
6231
|
### §ext-mimetype Path-extension declares mimetype
|
|
6000
6232
|
|
|
6001
|
-
`
|
|
6233
|
+
`PathMimetype.resolve` (exported from `@plurnk/plurnk-schemes`): pathname extension → `Mimetypes.detect({ ext })` (with `text/plain` normalized to `text/markdown` per {§markdown-primitive}); an unrecognized or absent extension uses the caller's supplied type. Text EDIT creation supplies the scheme's declared channel type or the Markdown primitive for a dynamically typed channel. Transfers follow {§copy-destination-mimetype}.
|
|
6002
6234
|
|
|
6003
6235
|
- `worker:///users.json` → `application/json` (extension wins)
|
|
6004
6236
|
- `worker:///notes.md` → `text/markdown` (extension; matches default)
|
|
6005
6237
|
- `worker:///config.yaml` → `application/yaml`
|
|
6006
|
-
- `worker:///users` (no suffix) → `text/markdown` (
|
|
6238
|
+
- Text EDIT of `worker:///users` (no suffix) → `text/markdown` (text primitive)
|
|
6007
6239
|
|
|
6008
6240
|
§ext-mimetype-extension-mimetype The same rule applies to every entry-bearing scheme when
|
|
6009
6241
|
creating a channel without a per-call type declaration. EDIT and COPY/MOVE into
|
|
@@ -6139,6 +6371,24 @@ lane's run directory and the lane's reclaim takes all of it; an unnamed run is C
|
|
|
6139
6371
|
that passes is reclaimed when it exits; a failed suite's evidence is never touched and stays exactly where the run reported it. A cross-package test may reuse Core's migration fixture only by passing a path inside the
|
|
6140
6372
|
caller's own run directory.
|
|
6141
6373
|
|
|
6374
|
+
§tier-census **A real-model tier run is one directory with its census.** The live and demo drivers
|
|
6375
|
+
stamp `PLURNK_TIER_RUN` as `<kind>-<UTC stamp>`; every worker the run claims lands inside
|
|
6376
|
+
`PLURNK_BENCHMARKS/tier-<kind>-<stamp>/`, each in its own `<label>-XXXXXX/` with its database, its own
|
|
6377
|
+
host, its digest and a `census.json` naming the specimen that drove it, its loops, turns, requests,
|
|
6378
|
+
tokens and cost. The run's `census.md` and `census.json`, written by the tier's node:test reporter
|
|
6379
|
+
when the run ends, carry one row per specimen: verdict, skip reason or first failure line, the
|
|
6380
|
+
workers it claimed, turns, requests and cost; a run never deletes or moves any of it. A specimen
|
|
6381
|
+
declares what it requires of the route and the host (`input:<image|pdf|audio|video>`, `reasoning`,
|
|
6382
|
+
`output-budget`, `env:<NAME>`, `url:<http(s) URL>`, `bin:<name>` on PATH, `checkout:<client|a2a-tck>`
|
|
6383
|
+
at `PLURNK_CLIENT_CHECKOUT` or `PLURNK_A2A_TCK_CHECKOUT`, else beside the repository); an unmet
|
|
6384
|
+
requirement is a skip, before anything boots or is spent, whose reason names the requirement and what
|
|
6385
|
+
was observed, and the census answers each unmet route-bound requirement with the declared aliases
|
|
6386
|
+
whose catalog entry satisfies it. A route the harness cannot resolve is a failure, never a skip. No
|
|
6387
|
+
test surface is an opt-in flag or a script of its own: the third-party MCP composition, the
|
|
6388
|
+
llama-server rails, the upstream A2A TCK and the client's real-model TUI tier are live specimens that
|
|
6389
|
+
run wherever their requirements hold. `tier:history` ledgers every census under the home: per
|
|
6390
|
+
specimen, its verdicts over runs and its last reason.
|
|
6391
|
+
|
|
6142
6392
|
§fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (every file row's origin is Git or constraint), and sig-coherence. Generated-pick incorporation and lifecycle require filesystem/Git evidence and are covered by the composed creation matrix rather than a false pure-database proxy. The harness runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
|
|
6143
6393
|
|
|
6144
6394
|
## Problem codes and pinned wording
|
|
@@ -6150,6 +6400,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
6150
6400
|
| code | status | contract |
|
|
6151
6401
|
|---|---:|---|
|
|
6152
6402
|
| `target-required` | 400 | *OP* requires a target path. Recovery: Write the target in parentheses on the opening fence line: `OP (path)`. |
|
|
6403
|
+
| `target-cardinality` | 400 | *OP* *operand* matched *n* resources; expected one. Recovery: Name one source and one destination per pair. |
|
|
6153
6404
|
| `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery}) `Registered schemes: *names*.` |
|
|
6154
6405
|
| `scheme-metadata-unsupported` | 400 | *OP* on '*scheme*' does not accept the [metadata] modifier. |
|
|
6155
6406
|
| `operation-not-implemented` | 501 | Scheme '*name*' does not implement *OP* (or exec). |
|
|
@@ -6170,13 +6421,36 @@ Every Problem code core mints is named here under its family ({§problem-error-c
|
|
|
6170
6421
|
| `kill-target-scheme-required` | 400 | KILL target requires a scheme. |
|
|
6171
6422
|
| `worker-not-found` | 404 | Worker '*name*' does not exist in this workspace. |
|
|
6172
6423
|
| `entry-operation-unsupported` | 400 | KILL requires an entry-bearing target; '*scheme*' does not provide one. |
|
|
6424
|
+
| `coordinate-invalid` | 400 | '*to*' is not a log coordinate ({§rollback}). Recovery: Name the coordinate as `<loop>/<turn>/<item>`, as the log shows it. |
|
|
6425
|
+
| `coordinate-not-found` | 404 | No log entry exists at log:///*coordinate* ({§rollback}). |
|
|
6426
|
+
| `project-root-required` | 400 | Rollback restores files, and this workspace has no project root ({§rollback}). |
|
|
6173
6427
|
| `resource-scheme-required` | 400 | Resource selection requires an address. |
|
|
6174
6428
|
| `channel-required` | 400 | The '*scheme*' scheme has no default channel. Recovery: Address a named channel with a URI fragment. |
|
|
6175
6429
|
| `binary-source-unsupported` | 415 | Channel #*name* is binary and its scheme keeps no bytes to transfer. |
|
|
6176
|
-
| `metadata-unsupported` | 400 | *OP* takes only the env option; '*key*' is not one. |
|
|
6177
|
-
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace. |
|
|
6430
|
+
| `metadata-unsupported` | 400 | *OP* takes only the env option; '*key*' is not one. A WORK to a held name with env: WORK to the existing worker '*name*' carries env; a message takes none. |
|
|
6431
|
+
| `worker-name-conflict` | 409 | Worker '*name*' already exists in this workspace. Recovery: WORK or SEND (worker://*name*) delivers a message to the live worker; FORK with a name no worker holds. ({§worker-scheme-spawn}) |
|
|
6178
6432
|
| `no-operation` | 422 | The turn performed no operation ({§empty-turn}). |
|
|
6179
6433
|
| `send-target-not-a-recipient` | 400 | The addressed scheme is not a SEND recipient. Recovery: Name a message address or a recipient that implements SEND. |
|
|
6434
|
+
| `invalid-operation-syntax` | 400 | The parser's diagnostic for an invalid operation in an admitted turn. |
|
|
6435
|
+
| `unreadable-pattern` | 400 | The pattern reader's diagnostic for an unreadable matcher. |
|
|
6436
|
+
| `completion-invalid` | 400 | A reply accepts one completion code: 200 or 499. |
|
|
6437
|
+
| `attachment-address-invalid` | 400 | An attachment selects one exact resource address. |
|
|
6438
|
+
|
|
6439
|
+
§problems-loop **Loop and context Problems.** These codes identify the failed boundary; lifecycle and recovery remain governed by their owning contracts.
|
|
6440
|
+
|
|
6441
|
+
| code | status | condition |
|
|
6442
|
+
|---|---:|---|
|
|
6443
|
+
| `result-exceeds-budget` | 413 | A result exceeds the remaining log budget; detail names its size, delivered portion, and a smaller selection or curation ({§context-fit}). |
|
|
6444
|
+
| `window-overflow` | 413 | The packet cannot fit the model's window even as receipts ({§context-wall}). |
|
|
6445
|
+
| `packet-exceeds-budget` | 413 | Context exceeds budget; the curation mandate is the pinned sentence below ({§context-over-budget-row}). |
|
|
6446
|
+
| `loop-timeout` | 504 | The loop exhausted its active execution allowance. |
|
|
6447
|
+
| `strike-threshold` | 508 / 500 | Repetition crossed the strike threshold (508), or another strike source crossed it (500), under {§engine-rails}. |
|
|
6448
|
+
| `loop-running` | 425 | The addressed execution has not concluded. |
|
|
6449
|
+
| `loop-cancelled` | 499 | The loop was cancelled; detail preserves the cancellation reason. |
|
|
6450
|
+
| `loop-threw` | 500 | The loop failed outside its operation result contract. |
|
|
6451
|
+
| `narration-failed` | 500 | Filesystem divergence narration failed before its operation turn settled. |
|
|
6452
|
+
| `provider-contract-violation` | 502 | The provider failed without returning its required Problem Details. |
|
|
6453
|
+
| `active-worker-limit-reached` | 508 | The workspace's active workers reach its configured limit. |
|
|
6180
6454
|
|
|
6181
6455
|
§unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.** Its recovery
|
|
6182
6456
|
lists the schemes the workspace registers, and rebuilds the address into nothing else
|
|
@@ -6203,6 +6477,7 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6203
6477
|
|
|
6204
6478
|
| code | status | contract |
|
|
6205
6479
|
|---|---:|---|
|
|
6480
|
+
| `invalid-file-url` | 400 | The native file-URL diagnostic, or `File URL path must not include NUL characters.` ({§file-url}). |
|
|
6206
6481
|
| `edit-empty` | 400 | EDIT requires at least one statement. Recovery: Provide an EDIT statement. |
|
|
6207
6482
|
| `edit-batch-mismatch` | 400 | The EDIT batch spans multiple resources. Recovery: Submit a separate EDIT batch for each resource. |
|
|
6208
6483
|
| `line-marker-required` | 400 | EDIT of an existing file requires a line marker ({§edit-marker-required-on-existing}). Recovery: Name the lines to replace with `<@hash>` or `<@start,@end>` from a READ of the file; `<L,1,L,1>` inserts before line L, and `<1,-1>` replaces the whole file. |
|
|
@@ -6216,16 +6491,35 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6216
6491
|
| `file-create-excluded` | 403 | A members exclusion (`!_glob_`) covers '*path*'. Recovery: Remove or disable the excluding members definition, or choose another path. |
|
|
6217
6492
|
| `file-create-gitignored` | 403 | Active Git policy ignores '*path*', and no members definition includes it. Recovery: Choose a Git-admitted path or add a members definition that includes it. |
|
|
6218
6493
|
| `file-materialization-limit` | 413 | The file exceeds the materialization byte limit and is not read into the workspace. |
|
|
6219
|
-
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. A path beyond the root recovers instead to: '*path*' is outside the project root: only a members definition under the operator's namespace scope admits it. |
|
|
6494
|
+
| `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: FIND lists paths. EDIT creates files; `members (add)` admits existing files with a `{"alias": "<name>", "definition": {"glob": "<path>"}}` body. A path beyond the root recovers instead to: '*path*' is outside the project root: only a members definition under the operator's namespace scope admits it. |
|
|
6495
|
+
| `body-channel-required` | 400 | A file write requires a body channel. |
|
|
6496
|
+
| `write-failed` | 500 | Publication or its settlement failed; the result distinguishes an unpublished write from an already-published one. |
|
|
6497
|
+
| `creation-rollback-failed` | 500 | Incorporating a newly created file failed, and rollback was incomplete. |
|
|
6498
|
+
| `creation-incorporation-failed` | 500 | Incorporating a newly created file failed; its exclusive creation was rolled back. |
|
|
6499
|
+
| `materialization-failed` | 500 | The file was written to disk but could not be registered. |
|
|
6500
|
+
| `delete-failed` | 500 | Deletion or projection settlement failed; the result distinguishes an undeleted file from an already-deleted one. |
|
|
6220
6501
|
|
|
6221
6502
|
§problems-exec **Execution Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6222
6503
|
|
|
6223
6504
|
| code | status | contract |
|
|
6224
6505
|
|---|---:|---|
|
|
6225
6506
|
| `invalid-input-target` | 400 | SEND input addresses an execution, without a channel or scope. |
|
|
6226
|
-
| `input-unavailable` | 409 | This execution's input receiver is no longer enabled. |
|
|
6507
|
+
| `input-unavailable` | 409 | This execution was launched without input. Recovery: Launch it with `[{"stdin": "open"}]` when its runtime takes input, then SEND to that execution. — This execution is queued for an execution slot; its input opens when it starts. Recovery: SEND again once the execution has started. — This execution's input receiver is no longer enabled. |
|
|
6227
6508
|
| `stream-not-found` | 404 | No execution exists at the requested address. Recovery, when the id holds an execution under another runtime ({§exec-near-miss}): The execution at /*id* is `*runtime*:///*id*`. |
|
|
6228
6509
|
| `input-closed` | 410 | Execution input is closed. |
|
|
6510
|
+
| `executor-not-registered` | 400 | No executor or MCP service named '*runtime*' is registered for this worker. |
|
|
6511
|
+
| `runtime-unavailable` | 501 | Executable tool '*runtime*' is unavailable; detail includes the availability diagnostic. |
|
|
6512
|
+
| `lifetime-invalid` | 400 | The execution lifetime directive is invalid; detail identifies the invalid form. |
|
|
6513
|
+
| `target-classification-failed` | 500 | The execution target could not be inspected; detail includes a bounded cause. |
|
|
6514
|
+
| `source-content-unavailable` | 422 | The source scheme did not supply execution content. |
|
|
6515
|
+
| `stream-entry-write-failed` | 500 | The execution's stream entry could not be created. |
|
|
6516
|
+
| `program-is-a-tool` | 404 | The command exited 127 and names a registered tool of another runtime ({§exec-tool-fall-through}). |
|
|
6517
|
+
| `executor-did-not-conclude` | 500 | The executor did not produce a terminal result. |
|
|
6518
|
+
| `execution-cancelled` | 499 | Execution was cancelled by the service. |
|
|
6519
|
+
| `executor-invalid-result` | 500 | The executor returned an invalid operation result. |
|
|
6520
|
+
| `executor-threw` | 500 | The executor failed outside its operation result contract. |
|
|
6521
|
+
| `entry-narration-failed` | 500 | An executor entry could not be materialized or narrated. |
|
|
6522
|
+
| `input-receiver-failed` | 500 | The input receiver failed outside its result contract; delivery may be partial. |
|
|
6229
6523
|
|
|
6230
6524
|
§problems-entries **Entry scheme Problems (log, worker, entries).** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6231
6525
|
|
|
@@ -6233,12 +6527,36 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6233
6527
|
|---|---:|---|
|
|
6234
6528
|
| `read-target-required` | 400 | READ requires a log coordinate. Recovery: Provide one exact log coordinate. |
|
|
6235
6529
|
| `coordinate-malformed` | 400 | The log coordinate '*path*' is malformed. Recovery: Use one exact loop/turn/sequence coordinate. |
|
|
6530
|
+
| `kill-failed` | 400 | The log target '*path*' is malformed. (A glob the matcher cannot read: The log glob '*glob*' is malformed.) Recovery: the {§log-target-shape} sentence. |
|
|
6531
|
+
| `curation-failed` | 400 | A scoped KILL's selection could not be read: the same sentences and recovery as `kill-failed`. |
|
|
6236
6532
|
| `worker-target-required` | 400 | EDIT requires a worker:// target. Recovery: Provide the worker target. |
|
|
6237
6533
|
| `binary-edit-unsupported` | 415 | The #*channel* channel is binary and cannot be edited. |
|
|
6238
6534
|
| `message-not-implemented` | 501 | SEND does not deliver messages to *scheme* entries. Recovery: To reply, SEND to an Open Message address or omit the target. `SEND (worker://<name>)` sends a new message. |
|
|
6239
6535
|
| `worker-entity-not-editable` | 400 | A worker entity is not an editable entry. Recovery: EDIT requires an entry path, such as worker:///example.md. |
|
|
6240
6536
|
| `message-empty` | 400 | SEND has no message text or attachments. |
|
|
6241
6537
|
| `scope-unsupported` | 400 | A worker SEND takes no scope. |
|
|
6538
|
+
| `control-address-invalid` | 400 | The operation requires an authority-only worker control address. |
|
|
6539
|
+
| `named-worker-required` | 400 | A worker deliverable READ requires a named worker. |
|
|
6540
|
+
| `emission-curated-whole` | 422 | An emission has no legend lines, so a line scope selects nothing on it. |
|
|
6541
|
+
| `entry-exists` | 409 | An entry already exists at the addressed resource. |
|
|
6542
|
+
| `invalid-expression` | 400 | The full-text or graph matcher expression is invalid. |
|
|
6543
|
+
| `delete-target-required` | 400 | KILL requires a target path. |
|
|
6544
|
+
|
|
6545
|
+
§problems-client **Client interactions and message admission Problems.** Refused admission creates no replacement message or interaction.
|
|
6546
|
+
|
|
6547
|
+
| code | status | condition |
|
|
6548
|
+
|---|---:|---|
|
|
6549
|
+
| `interaction-not-pending` | 409 | The requested client interaction is not pending. |
|
|
6550
|
+
| `interaction-unsupported` | 501 | No recipient implements the requested tool for this conversation. |
|
|
6551
|
+
| `recipient-mismatch` | 403 | Only the interaction's recipient may answer it. |
|
|
6552
|
+
| `interaction-response-invalid` | 400 | The response does not satisfy the pending interaction's schema. |
|
|
6553
|
+
| `invalid-body` | 400 | A question body is not JSON, or lacks its nonempty message or requested schema. |
|
|
6554
|
+
| `offset-invalid` | 400 | An entry offset is not a nonnegative safe integer. |
|
|
6555
|
+
| `userinfo-not-allowed` | 400 | An entry target URL contains userinfo. |
|
|
6556
|
+
| `action-threw` | 500 | The client action failed outside its operation result contract. |
|
|
6557
|
+
| `message-already-accepted` | 409 | The message address was already accepted in this workspace. |
|
|
6558
|
+
| `source-not-running` | 409 | The originating task is not running; no message was admitted. |
|
|
6559
|
+
| `loop-not-open` | 409 | The named loop is not an unfinished recipient of the worker; no message was admitted. |
|
|
6242
6560
|
|
|
6243
6561
|
§problems-functionality **Server and Functionality Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
|
|
6244
6562
|
|
|
@@ -6247,12 +6565,13 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6247
6565
|
| `service-starting` | 503 | The PLURNK service owns this listener but has not admitted its client interface yet. |
|
|
6248
6566
|
| `route-not-found` | 404 | The requested HTTP route does not exist. |
|
|
6249
6567
|
| `configuration-invalid` | 503 | The owning configuration reader's diagnostic, naming the invalid key. Recovery: Correct the named configuration input. Other capabilities remain available. |
|
|
6250
|
-
| `name-reserved` | 400 | '*alias*' is
|
|
6568
|
+
| `name-reserved` | 400 | '*alias*' is reserved in env entries and invocation overrides. Recovery: READ worker:///_plurnk/plurnk/env.md for supported configuration paths. |
|
|
6251
6569
|
| `value-invalid` | 400 | '*alias*' needs a string value. |
|
|
6252
6570
|
| `env-invalid` | 400 | `env` must be an object of string values; '*name*' is not a name a shell can export. |
|
|
6571
|
+
| `source-unknown` | 400 | '*source*' is not a package in the configuration catalog. Recovery: Omit source to list the catalog. READ files; set variables with add or EDIT (env:///NAME). |
|
|
6253
6572
|
| `query-invalid` | 400 | '*query*' names no path or pattern. Recovery: Supply a path such as `docs/guide.md` or a pattern such as `docs/**`. |
|
|
6254
6573
|
| `headless` | 409 | The workspace has no project root, so there are no file members. Recovery: Open the workspace on a project root. |
|
|
6255
|
-
| `definition-invalid` | 400 | A members definition is { glob }: a
|
|
6574
|
+
| `definition-invalid` | 400 | A members definition is { glob }: a shell-path pattern, `!glob` to exclude. |
|
|
6256
6575
|
| `model-scope` | 403 | The model may not change membership here: the members scope is none. Recovery: `git add` the file so git tracks it, or ask the operator to add it (/members add) or raise PLURNK_SERVICE_MEMBERS_MODEL_SCOPE. |
|
|
6257
6576
|
| `workspace-not-found` | 404 | Workspace *id* does not exist. |
|
|
6258
6577
|
| `state-not-json` | 400 | Worker module state is not JSON-serializable. |
|
|
@@ -6263,8 +6582,17 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6263
6582
|
| `offset-channel-required` | 400 | Recovery: Select the channel to read from the offset. |
|
|
6264
6583
|
| `target-invalid` | 400 | Recovery: Use a scheme://path target. |
|
|
6265
6584
|
| `proposal-not-pending` | 409 | Recovery: Refresh pending proposals before resolving one. |
|
|
6585
|
+
| `proposal-decision-unrecorded` | 500 | The approval decision could not be saved; the operation was not applied. |
|
|
6266
6586
|
| `scope-cancelled` | 499 | The worker scope was cancelled: *reason*. |
|
|
6267
6587
|
| `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery: Trim one line with `<L>` or lines L through M with `<L,M>`; `KILL (log:///…/READ)` with no scope retires the whole row. |
|
|
6588
|
+
| `runtime-owner-reserved` | 409 | The runtime owner cannot be registered by a client. |
|
|
6589
|
+
| `owner-not-found` | 404 | The owner address is not registered in the workspace. |
|
|
6590
|
+
| `proposal-policy-failed` | 500 | Core could not establish the proposal's settlement policy. |
|
|
6591
|
+
| `handler-unavailable` | 410 | The proposed scheme handler is no longer available. |
|
|
6592
|
+
| `proposal-apply-threw` | 500 | The scheme failed outside its proposal application contract. |
|
|
6593
|
+
| `verb-unknown` | 400 | The requested verb is not a lifecycle verb of the addressed family. |
|
|
6594
|
+
| `arguments-not-json` | 400 | The lifecycle verb's body must be a JSON object. |
|
|
6595
|
+
| `dispatch-threw` | 500 | The Plurnk actor failed outside its operation result contract. |
|
|
6268
6596
|
|
|
6269
6597
|
§pinned-wording-core **Pinned wording.** Verbatim sentences tests pin: each is contract, and a change here is a change of contract.
|
|
6270
6598
|
|
|
@@ -6273,8 +6601,7 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6273
6601
|
| Nothing is in flight. Continuing. | a WAIT (or a premature terminal) with no live work ({§wait-obligation-matrix}) |
|
|
6274
6602
|
| All Open Messages resolved. Review new results; emit no OPs if finished. | resolved messages with unobserved results ({§loop-completion}) |
|
|
6275
6603
|
| Context exceeds budget. YOU MUST ONLY KILL, MOVE or NOTE this turn. | the over-budget row ({§context-over-budget-row}) |
|
|
6276
|
-
| YOU MUST
|
|
6277
|
-
| YOU MUST use at least one NOTE per continuing turn. The turn continued without a NOTE. | a continuing or parked model turn without a NOTE ({§continued-without-note}) |
|
|
6604
|
+
| YOU MUST record at least one NOTE along with other operations. The turn continued without a NOTE. | a continuing or parked model turn without a NOTE ({§continued-without-note}) |
|
|
6278
6605
|
| Each directive in the notice table | a notice of the model's own output ({§notice-directive}) |
|
|
6279
6606
|
| Context window overflow: the packet cannot fit the model's window even as receipts. | the wall ({§context-wall}) |
|
|
6280
6607
|
| No recipient implements the requested interaction. | The worker's owner is not interactive or does not declare the required client tool ({§client-interaction-routing}). |
|
|
@@ -6286,5 +6613,5 @@ lists the schemes the workspace registers, and rebuilds the address into nothing
|
|
|
6286
6613
|
| '*path*' is a directory, not a file; READ reads one file. Recovery: `FIND (_path_/)` lists its files. | READ of a directory |
|
|
6287
6614
|
| The execution at ops://*worker*/*loop* has not concluded. | a bare READ of a running worker's result (425) |
|
|
6288
6615
|
| The child provider failed. | a child's provider failure read back by its parent |
|
|
6289
|
-
| '*path*' exists on disk but is not a member of this workspace. Recovery: Admit it with `members (add)` and a `{"glob": "<path>"}` body. | a non-member on disk at the addressed path |
|
|
6616
|
+
| '*path*' exists on disk but is not a member of this workspace. Recovery: Admit it with `members (add)` and a `{"alias": "<name>", "definition": {"glob": "<path>"}}` body. | a non-member on disk at the addressed path |
|
|
6290
6617
|
| '*path*' exists on disk but is not a member of this workspace. Recovery: The repository ignores it: a client or operator members definition can include it, a model definition cannot. | a non-member the repository ignores ({§membership-read-refusal}) |
|