@plurnk/plurnk-service 1.7.0 → 1.8.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 +29 -42
- package/INSTALL.md +49 -10
- package/README.md +11 -1
- package/SPEC.md +631 -279
- package/digest-sql/channel-dispositions/dispositions.sql +15 -0
- package/digest-sql/channel-state/state.sql +6 -0
- package/digest-sql/curation/curation.sql +5 -0
- package/digest-sql/derivations/derivations.sql +4 -0
- package/digest-sql/embeddings/embeddings.sql +4 -0
- package/digest-sql/entry-dispositions/dispositions.sql +15 -0
- package/digest-sql/entry-state/state.sql +6 -0
- package/digest-sql/token-counts/token-counts.sql +2 -0
- package/dist/Paths.d.ts +2 -5
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +9 -21
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +4 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +12 -22
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +2 -1
- package/dist/core/Dispatcher.d.ts +7 -6
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +34 -88
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +11 -8
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +45 -27
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +112 -107
- package/dist/core/ExecutorRegistry.d.ts +8 -2
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +6 -3
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/HostPaths.d.ts +29 -0
- package/dist/core/HostPaths.d.ts.map +1 -0
- package/dist/core/HostPaths.js +74 -0
- package/dist/core/HostPaths.js.map +1 -0
- package/dist/core/LegacyHome.d.ts +10 -0
- package/dist/core/LegacyHome.d.ts.map +1 -0
- package/dist/core/LegacyHome.js +170 -0
- package/dist/core/LegacyHome.js.map +1 -0
- package/dist/core/LogBody.d.ts +1 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +2 -2
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.js +1 -1
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LogVisibility.d.ts +28 -0
- package/dist/core/LogVisibility.d.ts.map +1 -0
- package/dist/core/LogVisibility.js +215 -0
- package/dist/core/LogVisibility.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +1 -0
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +8 -0
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +10 -0
- package/dist/core/OperatorConfig.d.ts +6 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -0
- package/dist/core/OperatorConfig.js +92 -0
- package/dist/core/OperatorConfig.js.map +1 -0
- package/dist/core/OverflowTurn.d.ts +11 -0
- package/dist/core/OverflowTurn.d.ts.map +1 -0
- package/dist/core/OverflowTurn.js +77 -0
- package/dist/core/OverflowTurn.js.map +1 -0
- package/dist/core/Owner.js +2 -2
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +3 -15
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +48 -121
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.js +1 -1
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +3 -23
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts +9 -5
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +99 -104
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +5 -3
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +0 -1
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +7 -11
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ToolResources.d.ts +19 -0
- package/dist/core/ToolResources.d.ts.map +1 -0
- package/dist/core/ToolResources.js +122 -0
- package/dist/core/ToolResources.js.map +1 -0
- package/dist/core/Turn.d.ts +27 -0
- package/dist/core/Turn.d.ts.map +1 -0
- package/dist/core/Turn.js +43 -0
- package/dist/core/Turn.js.map +1 -0
- package/dist/core/Turn.sql +72 -0
- package/dist/core/TurnOps.d.ts +7 -0
- package/dist/core/TurnOps.d.ts.map +1 -0
- package/dist/core/TurnOps.js +63 -0
- package/dist/core/TurnOps.js.map +1 -0
- package/dist/core/TurnRunner.d.ts +12 -4
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +1045 -898
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerName.d.ts +1 -1
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js +7 -5
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +15 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +57 -27
- package/dist/core/git-env.d.ts +0 -1
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +0 -3
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +10 -26
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +13 -14
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/operation-target-groups.d.ts +3 -0
- package/dist/core/operation-target-groups.d.ts.map +1 -0
- package/dist/core/operation-target-groups.js +53 -0
- package/dist/core/operation-target-groups.js.map +1 -0
- package/dist/core/packet-inject.d.ts +0 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +6 -13
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +4 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +208 -44
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +3 -3
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +4 -5
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/worker-settings.d.ts +9 -0
- package/dist/core/worker-settings.d.ts.map +1 -0
- package/dist/core/worker-settings.js +25 -0
- package/dist/core/worker-settings.js.map +1 -0
- package/dist/core/workspace-settings.d.ts +0 -11
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +3 -47
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +164 -92
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +8 -2
- package/dist/observe/genai.d.ts +9 -0
- package/dist/observe/genai.d.ts.map +1 -0
- package/dist/observe/genai.js +31 -0
- package/dist/observe/genai.js.map +1 -0
- package/dist/observe/spans.d.ts +3 -3
- package/dist/observe/spans.d.ts.map +1 -1
- package/dist/observe/spans.js +20 -5
- package/dist/observe/spans.js.map +1 -1
- package/dist/schemes/EffectPolicy.d.ts +3 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +38 -6
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +55 -13
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/Log.d.ts +6 -2
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +73 -22
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +25 -7
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +1 -2
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts +10 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -0
- package/dist/schemes/QuestionTool.js +81 -0
- package/dist/schemes/QuestionTool.js.map +1 -0
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +4 -1
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +20 -3
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +19 -1
- package/dist/schemes/_entry-find.d.ts +5 -3
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +102 -22
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +8 -6
- package/dist/schemes/_entry-graph.sql +2 -6
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +12 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +37 -25
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/server/Daemon.d.ts +58 -7
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +551 -113
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +12 -9
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +59 -10
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/client-input.d.ts +5 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +53 -34
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +28 -6
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +26 -11
- package/dist/server/envelope.d.ts +1 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +4 -4
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +25 -1
- package/dist/server/lifecycle-recovery.sql +11 -1
- package/dist/server/logEntry.d.ts +2 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +3 -2
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +7 -0
- package/dist/server/loop-model.d.ts +2 -2
- package/dist/server/loop-model.d.ts.map +1 -1
- package/dist/server/loop-model.js +23 -33
- package/dist/server/loop-model.js.map +1 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +61 -10
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/loopDocs.sql +4 -2
- package/dist/server/model-catalog.d.ts +3 -0
- package/dist/server/model-catalog.d.ts.map +1 -0
- package/dist/server/model-catalog.js +83 -0
- package/dist/server/model-catalog.js.map +1 -0
- package/dist/server/model-route.d.ts +7 -0
- package/dist/server/model-route.d.ts.map +1 -0
- package/dist/server/model-route.js +47 -0
- package/dist/server/model-route.js.map +1 -0
- package/dist/server/module-discovery.d.ts +13 -0
- package/dist/server/module-discovery.d.ts.map +1 -0
- package/dist/server/module-discovery.js +78 -0
- package/dist/server/module-discovery.js.map +1 -0
- package/dist/server/skillDocs.d.ts +9 -0
- package/dist/server/skillDocs.d.ts.map +1 -0
- package/dist/server/skillDocs.js +212 -0
- package/dist/server/skillDocs.js.map +1 -0
- package/dist/server/skillDocs.sql +14 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +182 -123
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +424 -65
- package/package.json +37 -37
- package/dist/core/ExecutableTools.d.ts +0 -11
- package/dist/core/ExecutableTools.d.ts.map +0 -1
- package/dist/core/ExecutableTools.js +0 -49
- package/dist/core/ExecutableTools.js.map +0 -1
- package/dist/core/JournalTurn.d.ts +0 -9
- package/dist/core/JournalTurn.d.ts.map +0 -1
- package/dist/core/JournalTurn.js +0 -14
- package/dist/core/JournalTurn.js.map +0 -1
- package/dist/core/JournalTurn.sql +0 -10
- package/dist/core/git-iso.d.ts +0 -13
- package/dist/core/git-iso.d.ts.map +0 -1
- package/dist/core/git-iso.js +0 -267
- package/dist/core/git-iso.js.map +0 -1
- package/dist/core/search-gate.d.ts +0 -17
- package/dist/core/search-gate.d.ts.map +0 -1
- package/dist/core/search-gate.js +0 -77
- package/dist/core/search-gate.js.map +0 -1
- package/dist/digest/Digest.sql +0 -1
|
@@ -30,6 +30,21 @@ CREATE TABLE IF NOT EXISTS workspace_module_state (
|
|
|
30
30
|
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
|
|
31
31
|
) STRICT;
|
|
32
32
|
|
|
33
|
+
-- model_routes — the immutable resolved model route ({§worker-model-selection}). One row per
|
|
34
|
+
-- complete resolved tuple; append-only. Alias is provenance plus a tuning scope,
|
|
35
|
+
-- not route identity, and is absent on a direct provider/model selection.
|
|
36
|
+
CREATE TABLE IF NOT EXISTS model_routes (
|
|
37
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
|
38
|
+
alias TEXT CHECK (alias IS NULL OR length(alias) > 0),
|
|
39
|
+
provider TEXT NOT NULL CHECK (length(provider) > 0),
|
|
40
|
+
model TEXT NOT NULL CHECK (length(model) > 0),
|
|
41
|
+
base_url TEXT CHECK (base_url IS NULL OR length(base_url) > 0),
|
|
42
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
43
|
+
) STRICT;
|
|
44
|
+
|
|
45
|
+
CREATE UNIQUE INDEX IF NOT EXISTS model_routes_identity
|
|
46
|
+
ON model_routes (coalesce(alias, ''), provider, model, coalesce(base_url, ''));
|
|
47
|
+
|
|
33
48
|
-- workers
|
|
34
49
|
CREATE TABLE IF NOT EXISTS workers (
|
|
35
50
|
id INTEGER NOT NULL PRIMARY KEY,
|
|
@@ -41,16 +56,31 @@ CREATE TABLE IF NOT EXISTS workers (
|
|
|
41
56
|
-- independent databases reuse local integer ids.
|
|
42
57
|
provider_identity TEXT NOT NULL DEFAULT (lower(hex(randomblob(16))))
|
|
43
58
|
CHECK (length(provider_identity) = 32 AND provider_identity NOT GLOB '*[^0-9a-f]*'),
|
|
59
|
+
-- {§worker-model-selection}: the worker's durable resolved model, NULL for non-model
|
|
60
|
+
-- workers or a deliberately modelless unresolved worker. spawn_model_route_id is the
|
|
61
|
+
-- persistent spawn override; NULL means "use my model."
|
|
62
|
+
model_route_id INTEGER REFERENCES model_routes(id),
|
|
63
|
+
spawn_model_route_id INTEGER REFERENCES model_routes(id),
|
|
64
|
+
-- {§worker-reasoning-policy}: nullable only while the worker has no model;
|
|
65
|
+
-- once selected, model and reasoning policy form one durable generation policy.
|
|
66
|
+
reasoning_policy TEXT CHECK (reasoning_policy IS NULL OR reasoning_policy IN ('off', 'adaptive', 'low', 'medium', 'high')),
|
|
44
67
|
-- workers fork via parent_worker_id; workspaces carry no parent — {§machine-processes-no-fork-workspace}
|
|
45
68
|
parent_worker_id INTEGER CHECK (parent_worker_id IS NULL OR parent_worker_id != id),
|
|
46
|
-
origin TEXT NOT NULL DEFAULT 'client' CHECK (origin IN ('model', 'client', '
|
|
69
|
+
origin TEXT NOT NULL DEFAULT 'client' CHECK (origin IN ('model', 'client', '_plurnk')),
|
|
47
70
|
-- {§methods-model-worker}: durable identity for the workspace's stable
|
|
48
71
|
-- default conversation; unrelated to its human-facing, reclaimable name.
|
|
49
72
|
default_conversation INTEGER NOT NULL DEFAULT 0 CHECK (default_conversation IN (0, 1)),
|
|
73
|
+
-- {§worker-settings}: the worker's own behavioral rules inside the workspace's
|
|
74
|
+
-- world — the workspace is how things are; each worker carries the rules its
|
|
75
|
+
-- loops obey. Client-declared at worker creation, mutable between loops,
|
|
76
|
+
-- validated at the client-input boundary (closed known-key set; unknown keys
|
|
77
|
+
-- never persist).
|
|
78
|
+
settings TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(settings)),
|
|
50
79
|
-- {§env-delta-log-pull}: monotonic observation progress, not a private world snapshot.
|
|
51
80
|
-- NULL means the worker has not established its first-turn baseline yet.
|
|
52
81
|
ambient_event_cursor INTEGER CHECK (ambient_event_cursor IS NULL OR ambient_event_cursor >= 0),
|
|
53
82
|
CHECK (default_conversation = 0 OR (origin = 'model' AND parent_worker_id IS NULL)),
|
|
83
|
+
CHECK ((model_route_id IS NULL) = (reasoning_policy IS NULL)),
|
|
54
84
|
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
55
85
|
FOREIGN KEY (parent_worker_id) REFERENCES workers(id) ON DELETE CASCADE
|
|
56
86
|
) STRICT;
|
|
@@ -129,8 +159,11 @@ CREATE TABLE IF NOT EXISTS loops (
|
|
|
129
159
|
status INTEGER NOT NULL DEFAULT 102 CHECK (status IN (100, 102, 200, 202, 413, 429, 499, 500, 504, 508)),
|
|
130
160
|
prompt TEXT NOT NULL,
|
|
131
161
|
flags TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(flags)),
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
-- {§worker-model-selection}: immutable loop snapshots of the resolved model route and the
|
|
163
|
+
-- effective spawn route (was provider_spec/child_provider_spec JSON).
|
|
164
|
+
model_route_id INTEGER REFERENCES model_routes(id),
|
|
165
|
+
spawn_model_route_id INTEGER REFERENCES model_routes(id),
|
|
166
|
+
reasoning_policy TEXT CHECK (reasoning_policy IS NULL OR reasoning_policy IN ('off', 'adaptive', 'low', 'medium', 'high')),
|
|
134
167
|
max_turns INTEGER NOT NULL DEFAULT 50 CHECK (max_turns >= -1),
|
|
135
168
|
-- {§methods-loop-run-open-paths}: the initial prompt frame's selected paths,
|
|
136
169
|
-- held here until turn 1 materializes that frame (string[] JSON).
|
|
@@ -145,6 +178,9 @@ CREATE TABLE IF NOT EXISTS loops (
|
|
|
145
178
|
-- {§loop-terminal-authorship}: 'cancel' names an external loop.cancel;
|
|
146
179
|
-- NULL covers model terminals and engine verdicts whose result carries the story.
|
|
147
180
|
terminated_by TEXT CHECK (terminated_by IS NULL OR terminated_by = 'cancel'),
|
|
181
|
+
CONSTRAINT loops_generation_policy_contract CHECK (
|
|
182
|
+
(model_route_id IS NULL) = (reasoning_policy IS NULL)
|
|
183
|
+
),
|
|
148
184
|
CONSTRAINT loops_terminal_result_contract CHECK (
|
|
149
185
|
CASE
|
|
150
186
|
WHEN status IN (100, 102, 202) THEN terminal_result IS NULL
|
|
@@ -191,7 +227,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS loops_worker_id_sequence ON loops (worker_id,
|
|
|
191
227
|
CREATE UNIQUE INDEX IF NOT EXISTS loops_orphan_source_loop_id ON loops (orphan_source_loop_id);
|
|
192
228
|
-- {§worker-scheme}: a loop crossing into a terminal status stamps terminated_at, so sibling
|
|
193
229
|
-- workers pull the termination as a folded ambient delta — caught uniformly across every
|
|
194
|
-
-- death-path (SEND,
|
|
230
|
+
-- death-path (SEND, overflow recovery, max-turns, strike, KILL). The stamp updates terminated_at,
|
|
195
231
|
-- never status, so it cannot re-fire this trigger. Terminals: 200 done · 413 budget ·
|
|
196
232
|
-- 429 turn-ceiling · 499 cancel · 500 fail · 504 wall-clock timeout · 508 runaway. (202 = parked/sleeping, NOT terminal.)
|
|
197
233
|
CREATE TRIGGER IF NOT EXISTS loops_stamp_terminated_at
|
|
@@ -229,7 +265,15 @@ CREATE TABLE IF NOT EXISTS turns (
|
|
|
229
265
|
loop_id INTEGER NOT NULL,
|
|
230
266
|
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
231
267
|
timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
268
|
+
-- {§turn-record}: producer and purpose define the turn. Packet/provider
|
|
269
|
+
-- evidence below is an optional inference specialization.
|
|
270
|
+
producer TEXT NOT NULL CHECK (producer IN ('model', 'client', '_plurnk', 'plugin')),
|
|
271
|
+
kind TEXT NOT NULL CHECK (kind IN ('inference', 'initialization', 'overflow', 'operation')),
|
|
232
272
|
status INTEGER NOT NULL CHECK (status BETWEEN 100 AND 599),
|
|
273
|
+
-- NULL while the producer still owns this turn. Status 102 is both the
|
|
274
|
+
-- provisional running value and the exact completed continue disposition;
|
|
275
|
+
-- completed_at distinguishes those states without inventing another status.
|
|
276
|
+
completed_at TEXT DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
233
277
|
-- Provider-derived curation calibration for this turn; NULL when input
|
|
234
278
|
-- capacity is unknown. {§tokenomics-client-gauge}
|
|
235
279
|
usage_curation_budget INTEGER CHECK (usage_curation_budget IS NULL OR usage_curation_budget >= 1),
|
|
@@ -264,16 +308,59 @@ CREATE TABLE IF NOT EXISTS turns (
|
|
|
264
308
|
END
|
|
265
309
|
),
|
|
266
310
|
finish_reason TEXT,
|
|
267
|
-
model TEXT
|
|
268
|
-
-- Opaque provider→client metadata plus engine rail keys;
|
|
269
|
-
--
|
|
270
|
-
meta TEXT
|
|
311
|
+
model TEXT CHECK (model IS NULL OR length(model) >= 1),
|
|
312
|
+
-- Opaque provider→client metadata plus engine rail keys; absent outside
|
|
313
|
+
-- recorded inference evidence. {§meta-passthrough}, {§rail-truth-engine-verdict}
|
|
314
|
+
meta TEXT CHECK (meta IS NULL OR json_valid(meta)),
|
|
315
|
+
CHECK (completed_at IS NOT NULL OR status = 102),
|
|
316
|
+
CHECK ((producer = 'model') = (kind = 'inference')),
|
|
317
|
+
CHECK (kind NOT IN ('initialization', 'overflow') OR producer = '_plurnk'),
|
|
318
|
+
CHECK (
|
|
319
|
+
kind = 'inference'
|
|
320
|
+
OR (
|
|
321
|
+
usage_curation_budget IS NULL
|
|
322
|
+
AND packet IS NULL
|
|
323
|
+
AND finish_reason IS NULL
|
|
324
|
+
AND model IS NULL
|
|
325
|
+
AND meta IS NULL
|
|
326
|
+
)
|
|
327
|
+
),
|
|
271
328
|
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE
|
|
272
329
|
) STRICT;
|
|
273
330
|
|
|
274
331
|
CREATE UNIQUE INDEX IF NOT EXISTS turns_loop_id_sequence ON turns (loop_id, sequence);
|
|
275
332
|
CREATE INDEX IF NOT EXISTS turns_timestamp ON turns (timestamp);
|
|
276
333
|
|
|
334
|
+
-- Producer and purpose are immutable except for the single pre-inference
|
|
335
|
+
-- diversion into overflow recovery. The transition is allowed only before any
|
|
336
|
+
-- model or non-kernel evidence exists.
|
|
337
|
+
CREATE TRIGGER IF NOT EXISTS turns_identity_forward_only
|
|
338
|
+
BEFORE UPDATE OF producer, kind ON turns
|
|
339
|
+
WHEN NOT (
|
|
340
|
+
OLD.producer = NEW.producer
|
|
341
|
+
AND OLD.kind = NEW.kind
|
|
342
|
+
)
|
|
343
|
+
AND NOT (
|
|
344
|
+
OLD.producer = 'model'
|
|
345
|
+
AND OLD.kind = 'inference'
|
|
346
|
+
AND NEW.producer = '_plurnk'
|
|
347
|
+
AND NEW.kind = 'overflow'
|
|
348
|
+
AND OLD.completed_at IS NULL
|
|
349
|
+
AND OLD.packet IS NULL
|
|
350
|
+
AND OLD.usage_curation_budget IS NULL
|
|
351
|
+
AND OLD.finish_reason IS NULL
|
|
352
|
+
AND OLD.model IS NULL
|
|
353
|
+
AND OLD.meta IS NULL
|
|
354
|
+
AND NOT EXISTS (SELECT 1 FROM model_calls WHERE turn_id = OLD.id)
|
|
355
|
+
AND NOT EXISTS (
|
|
356
|
+
SELECT 1 FROM log_entries
|
|
357
|
+
WHERE turn_id = OLD.id AND origin != '_plurnk'
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
BEGIN
|
|
361
|
+
SELECT RAISE(ABORT, 'turn producer and kind are immutable outside pre-inference overflow diversion');
|
|
362
|
+
END;
|
|
363
|
+
|
|
277
364
|
-- One logical provider.generate call. Emission attempts and BARE inferences
|
|
278
365
|
-- share response/failure evidence and cardinal physical request accounting;
|
|
279
366
|
-- operation-specific semantics live in their specializing relations.
|
|
@@ -321,6 +408,17 @@ CREATE TABLE IF NOT EXISTS model_calls (
|
|
|
321
408
|
|
|
322
409
|
CREATE INDEX IF NOT EXISTS model_calls_turn_id ON model_calls (turn_id, sequence);
|
|
323
410
|
|
|
411
|
+
CREATE TRIGGER IF NOT EXISTS model_calls_inference_turn_only
|
|
412
|
+
BEFORE INSERT ON model_calls
|
|
413
|
+
WHEN COALESCE((
|
|
414
|
+
SELECT producer = 'model' AND kind = 'inference'
|
|
415
|
+
FROM turns
|
|
416
|
+
WHERE id = NEW.turn_id
|
|
417
|
+
), 0) != 1
|
|
418
|
+
BEGIN
|
|
419
|
+
SELECT RAISE(ABORT, 'model call requires a model inference turn');
|
|
420
|
+
END;
|
|
421
|
+
|
|
324
422
|
CREATE TRIGGER IF NOT EXISTS model_calls_request_identity_immutable
|
|
325
423
|
BEFORE UPDATE OF turn_id, sequence, kind, attributions, timestamp ON model_calls
|
|
326
424
|
BEGIN
|
|
@@ -532,9 +630,9 @@ BEGIN
|
|
|
532
630
|
END;
|
|
533
631
|
|
|
534
632
|
-- derivations
|
|
535
|
-
-- Content-addressed deep projections.
|
|
536
|
-
-- deep_hash; graph, FTS, and vectors are stored once
|
|
537
|
-
--
|
|
633
|
+
-- Content-addressed deep projections. Entry channels and log projections point
|
|
634
|
+
-- at a COMPLETE artifact by deep_hash; graph, FTS, and vectors are stored once
|
|
635
|
+
-- regardless of how many addresses carry identical content under the same reader/config.
|
|
538
636
|
-- A building row is unattached and safely replaceable after interruption.
|
|
539
637
|
CREATE TABLE IF NOT EXISTS derivations (
|
|
540
638
|
id INTEGER NOT NULL PRIMARY KEY,
|
|
@@ -543,6 +641,14 @@ CREATE TABLE IF NOT EXISTS derivations (
|
|
|
543
641
|
disposition TEXT CHECK (disposition IN ('vector', 'lexical', 'excluded', 'nonsemantic', 'failed')),
|
|
544
642
|
reason TEXT,
|
|
545
643
|
parse_issues INTEGER CHECK (parse_issues IS NULL OR parse_issues > 0),
|
|
644
|
+
summary TEXT CHECK (
|
|
645
|
+
summary IS NULL OR (
|
|
646
|
+
length(summary) > 0
|
|
647
|
+
AND summary = trim(summary)
|
|
648
|
+
AND instr(summary, char(10)) = 0
|
|
649
|
+
AND instr(summary, char(13)) = 0
|
|
650
|
+
)
|
|
651
|
+
),
|
|
546
652
|
CHECK ((state = 'building' AND disposition IS NULL) OR (state = 'complete' AND disposition IS NOT NULL))
|
|
547
653
|
) STRICT;
|
|
548
654
|
|
|
@@ -572,11 +678,6 @@ CREATE TABLE IF NOT EXISTS entries (
|
|
|
572
678
|
-- == members; 'client'/'constraint' (model-created, add-glob) are not git's to reclaim.
|
|
573
679
|
-- NULL = not a file member (other schemes don't carry origin).
|
|
574
680
|
membership_origin TEXT CHECK (membership_origin IS NULL OR membership_origin IN ('git', 'client', 'constraint')),
|
|
575
|
-
-- {§membership-change-gated-sync}: hash of the body content at the last
|
|
576
|
-
-- deep-channel derivation. The manifest-add pass re-derives symbols/refs (and
|
|
577
|
-
-- embeddings, later) ONLY when this differs from the current body hash — an
|
|
578
|
-
-- unchanged entry is skipped, never re-metadatafied every turn.
|
|
579
|
-
deep_hash TEXT,
|
|
580
681
|
-- SPEC {§membership-change-gated-sync} — the per-member sync stat-detect:
|
|
581
682
|
-- "<mtimeMs>:<size>" of the disk file at its last materialization, or `absent`
|
|
582
683
|
-- after an observed deletion. The pre-turn
|
|
@@ -584,13 +685,13 @@ CREATE TABLE IF NOT EXISTS entries (
|
|
|
584
685
|
-- signature changed; an unchanged member is a no-op. NULL = never synced.
|
|
585
686
|
synced_sig TEXT,
|
|
586
687
|
-- User Note 5 — manifest cache-friendliness. Last-modified stamp, bumped on every
|
|
587
|
-
--
|
|
588
|
-
--
|
|
688
|
+
-- addressable representation change; engine_list_workspace_entries orders the catalog
|
|
689
|
+
-- by it ASC so dormant entries hold the stable prompt-cache prefix. Private derivation
|
|
690
|
+
-- attachment does not make an entry recently touched.
|
|
589
691
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
590
692
|
CHECK (workspace_id IS NOT NULL),
|
|
591
693
|
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
592
|
-
FOREIGN KEY (owner_id) REFERENCES workers(id) ON DELETE CASCADE
|
|
593
|
-
FOREIGN KEY (deep_hash) REFERENCES derivations(deep_hash)
|
|
694
|
+
FOREIGN KEY (owner_id) REFERENCES workers(id) ON DELETE CASCADE
|
|
594
695
|
) STRICT;
|
|
595
696
|
|
|
596
697
|
-- {§entry-owner} / {§stream-owner-scoped} — owner is the sole visibility and identity axis.
|
|
@@ -610,6 +711,9 @@ CREATE TABLE IF NOT EXISTS entry_channels (
|
|
|
610
711
|
-- Content identity: sha256 of content, stamped at static writes; streamed
|
|
611
712
|
-- appends leave it NULL. Curation weight remains model-independent.
|
|
612
713
|
content_hash TEXT,
|
|
714
|
+
-- Search derivation for this exact addressable channel representation.
|
|
715
|
+
-- Content or mimetype changes invalidate it at the owning channel row.
|
|
716
|
+
deep_hash TEXT,
|
|
613
717
|
state TEXT NOT NULL DEFAULT 'static' CHECK (state IN ('static', 'active', 'closed', 'errored')),
|
|
614
718
|
-- Exact terminal producer evidence for this representation channel. NULL is
|
|
615
719
|
-- the ordinary implicit {status:200}; selection/projection metadata belongs
|
|
@@ -642,12 +746,26 @@ CREATE TABLE IF NOT EXISTS entry_channels (
|
|
|
642
746
|
END
|
|
643
747
|
),
|
|
644
748
|
PRIMARY KEY (entry_id, name),
|
|
645
|
-
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE
|
|
749
|
+
FOREIGN KEY (entry_id) REFERENCES entries(id) ON DELETE CASCADE,
|
|
750
|
+
FOREIGN KEY (deep_hash) REFERENCES derivations(deep_hash)
|
|
646
751
|
) STRICT, WITHOUT ROWID;
|
|
647
752
|
|
|
648
|
-
--
|
|
649
|
-
--
|
|
650
|
-
--
|
|
753
|
+
-- A changed channel representation cannot retain search evidence derived from
|
|
754
|
+
-- its predecessor. This trigger is the one invalidation owner for every write
|
|
755
|
+
-- path, including model EDIT, plugin channel capabilities, and streams.
|
|
756
|
+
CREATE TRIGGER IF NOT EXISTS entry_channels_invalidate_derivation
|
|
757
|
+
AFTER UPDATE OF content, mimetype ON entry_channels
|
|
758
|
+
WHEN OLD.content IS NOT NEW.content OR OLD.mimetype IS NOT NEW.mimetype
|
|
759
|
+
BEGIN
|
|
760
|
+
UPDATE entry_channels
|
|
761
|
+
SET deep_hash = NULL
|
|
762
|
+
WHERE entry_id = NEW.entry_id AND name = NEW.name AND deep_hash IS NOT NULL;
|
|
763
|
+
END;
|
|
764
|
+
|
|
765
|
+
-- User Note 5 — bump the entry's updated_at on addressable representation or
|
|
766
|
+
-- lifecycle writes so the catalog (ordered by updated_at ASC) keeps recently-
|
|
767
|
+
-- touched entries at the tail and holds the prompt-cache prefix stable across
|
|
768
|
+
-- turns. Content hashes and search attachments are private metadata, not touches.
|
|
651
769
|
CREATE TRIGGER IF NOT EXISTS entries_touch_on_channel_write
|
|
652
770
|
AFTER INSERT ON entry_channels
|
|
653
771
|
BEGIN
|
|
@@ -655,7 +773,7 @@ BEGIN
|
|
|
655
773
|
END;
|
|
656
774
|
|
|
657
775
|
CREATE TRIGGER IF NOT EXISTS entries_touch_on_channel_update
|
|
658
|
-
AFTER UPDATE ON entry_channels
|
|
776
|
+
AFTER UPDATE OF content, mimetype, weight, state, producer_result ON entry_channels
|
|
659
777
|
BEGIN
|
|
660
778
|
UPDATE entries SET updated_at = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = NEW.entry_id;
|
|
661
779
|
END;
|
|
@@ -731,7 +849,8 @@ CREATE TABLE IF NOT EXISTS derivation_embeddings (
|
|
|
731
849
|
-- status⊥state: status is the HTTP outcome, state is where in the
|
|
732
850
|
-- lifecycle the entry sits. Most rows write 'resolved' directly;
|
|
733
851
|
-- proposing schemes transition 'proposed' → resolved/failed/cancelled.
|
|
734
|
-
--
|
|
852
|
+
-- folded: canonical hidden log-body line intervals for OPEN/FOLD. [] is
|
|
853
|
+
-- wholly open and [[1,-1]] is wholly folded.
|
|
735
854
|
CREATE TABLE IF NOT EXISTS log_entries (
|
|
736
855
|
id INTEGER NOT NULL PRIMARY KEY,
|
|
737
856
|
version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
|
|
@@ -741,7 +860,7 @@ CREATE TABLE IF NOT EXISTS log_entries (
|
|
|
741
860
|
turn_id INTEGER NOT NULL,
|
|
742
861
|
sequence INTEGER NOT NULL CHECK (sequence >= 1),
|
|
743
862
|
at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
744
|
-
origin TEXT NOT NULL CHECK (origin IN ('model', 'client', '
|
|
863
|
+
origin TEXT NOT NULL CHECK (origin IN ('model', 'client', '_plurnk', 'plugin')),
|
|
745
864
|
-- {§env-delta-attribution}: a worker:// name or stable subsystem token ('file');
|
|
746
865
|
-- NULL = the owning worker itself, rendered without causal attribution.
|
|
747
866
|
source TEXT,
|
|
@@ -750,21 +869,22 @@ CREATE TABLE IF NOT EXISTS log_entries (
|
|
|
750
869
|
ambient_event_id INTEGER REFERENCES ambient_events(id),
|
|
751
870
|
-- Search derivation attached to this durable log result, when available.
|
|
752
871
|
deep_hash TEXT REFERENCES derivations(deep_hash),
|
|
753
|
-
-- Exact logical provider call represented by a BARE result
|
|
754
|
-
--
|
|
872
|
+
-- Exact logical provider call represented by a BARE result, admitted
|
|
873
|
+
-- model turnOps, or rejected emissionAttempt. Other operation and ambient
|
|
874
|
+
-- rows carry no model-call identity.
|
|
755
875
|
model_call_id INTEGER REFERENCES model_calls(id),
|
|
756
876
|
|
|
757
877
|
-- 'error' is an ACTIONLESS row ({§operation-results} — errors are log items): a parse failure that
|
|
758
878
|
-- produced no op still records a log entry (op='error', status_rx≥400, no target) so the model
|
|
759
879
|
-- can fold/kill/recall its own mistakes like any other log row — one budget surface, the log.
|
|
760
|
-
--
|
|
761
|
-
-- ({§
|
|
880
|
+
-- Exact producer source and rejected-attempt artifacts carry NULL here
|
|
881
|
+
-- ({§turn-ops-entry}, {§rejected-emission-entry}).
|
|
762
882
|
-- No op enum here: the grammar op set is grammar's contract (PlurnkOp), and this column is written
|
|
763
883
|
-- only by the PlurnkOp-typed engine (grammar ops), service row selectors, or NULL for no op.
|
|
764
884
|
-- A SQL enum would be a hand-copy of grammar's op list that silently goes stale on every new verb
|
|
765
885
|
-- (it did — FORK/WORK). Validity lives at the parse + type layer, not duplicated in DDL.
|
|
766
886
|
op TEXT,
|
|
767
|
-
|
|
887
|
+
delimiter TEXT NOT NULL DEFAULT '',
|
|
768
888
|
signal TEXT CHECK (signal IS NULL OR json_valid(signal)),
|
|
769
889
|
|
|
770
890
|
scheme TEXT CHECK (scheme IS NULL OR length(scheme) > 0),
|
|
@@ -795,11 +915,16 @@ CREATE TABLE IF NOT EXISTS log_entries (
|
|
|
795
915
|
outcome TEXT,
|
|
796
916
|
attrs TEXT NOT NULL DEFAULT '{}' CHECK (json_valid(attrs)),
|
|
797
917
|
|
|
798
|
-
|
|
918
|
+
folded TEXT NOT NULL DEFAULT '[]'
|
|
919
|
+
CHECK (json_valid(folded) AND json_type(folded) = 'array'),
|
|
799
920
|
|
|
800
|
-
CHECK (
|
|
801
|
-
|
|
802
|
-
|
|
921
|
+
CHECK (
|
|
922
|
+
(op IS NULL) = COALESCE(
|
|
923
|
+
json_extract(attrs, '$.kind') IN ('turnOps', 'emissionAttempt'),
|
|
924
|
+
0
|
|
925
|
+
)
|
|
926
|
+
),
|
|
927
|
+
CHECK (json_extract(attrs, '$.kind') != 'emissionAttempt' OR origin = 'model'),
|
|
803
928
|
|
|
804
929
|
FOREIGN KEY (worker_id) REFERENCES workers(id) ON DELETE CASCADE,
|
|
805
930
|
FOREIGN KEY (loop_id) REFERENCES loops(id) ON DELETE CASCADE,
|
|
@@ -817,6 +942,108 @@ CREATE UNIQUE INDEX IF NOT EXISTS log_entries_worker_ambient_event
|
|
|
817
942
|
ON log_entries (worker_id, ambient_event_id)
|
|
818
943
|
WHERE ambient_event_id IS NOT NULL;
|
|
819
944
|
|
|
945
|
+
-- A log row belongs to one exact worker/loop/turn chain. Its writer is either
|
|
946
|
+
-- that turn's producer or `_plurnk` observing the turn. Primitive absence,
|
|
947
|
+
-- enum, and foreign-key failures remain owned by their column constraints.
|
|
948
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_turn_ownership
|
|
949
|
+
BEFORE INSERT ON log_entries
|
|
950
|
+
WHEN NEW.worker_id IS NOT NULL
|
|
951
|
+
AND NEW.loop_id IS NOT NULL
|
|
952
|
+
AND NEW.turn_id IS NOT NULL
|
|
953
|
+
AND NEW.origin IN ('model', 'client', '_plurnk', 'plugin')
|
|
954
|
+
AND EXISTS (SELECT 1 FROM workers WHERE id = NEW.worker_id)
|
|
955
|
+
AND EXISTS (SELECT 1 FROM loops WHERE id = NEW.loop_id)
|
|
956
|
+
AND EXISTS (SELECT 1 FROM turns WHERE id = NEW.turn_id)
|
|
957
|
+
AND NOT EXISTS (
|
|
958
|
+
SELECT 1
|
|
959
|
+
FROM turns
|
|
960
|
+
JOIN loops ON loops.id = turns.loop_id
|
|
961
|
+
WHERE turns.id = NEW.turn_id
|
|
962
|
+
AND loops.id = NEW.loop_id
|
|
963
|
+
AND loops.worker_id = NEW.worker_id
|
|
964
|
+
AND (NEW.origin = turns.producer OR NEW.origin = '_plurnk')
|
|
965
|
+
)
|
|
966
|
+
BEGIN
|
|
967
|
+
SELECT RAISE(ABORT, 'log entry must match its turn ownership and producer');
|
|
968
|
+
END;
|
|
969
|
+
|
|
970
|
+
-- {§turn-ops-entry} — exact admitted source is authored by the turn producer.
|
|
971
|
+
-- `_plurnk` may observe another producer's turn through ordinary operation
|
|
972
|
+
-- rows, but it cannot impersonate that producer's source program.
|
|
973
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_turn_ops_producer
|
|
974
|
+
BEFORE INSERT ON log_entries
|
|
975
|
+
WHEN NEW.op IS NULL
|
|
976
|
+
AND json_extract(NEW.attrs, '$.kind') = 'turnOps'
|
|
977
|
+
AND EXISTS (SELECT 1 FROM turns WHERE id = NEW.turn_id)
|
|
978
|
+
AND NOT EXISTS (
|
|
979
|
+
SELECT 1
|
|
980
|
+
FROM turns
|
|
981
|
+
WHERE turns.id = NEW.turn_id
|
|
982
|
+
AND turns.producer = NEW.origin
|
|
983
|
+
)
|
|
984
|
+
BEGIN
|
|
985
|
+
SELECT RAISE(ABORT, 'actionless log entry does not match its turn producer');
|
|
986
|
+
END;
|
|
987
|
+
|
|
988
|
+
-- A folded interval is an inclusive [start,end] pair. Ranges are positive,
|
|
989
|
+
-- sorted, disjoint, and non-adjacent; -1 is the final open-ended endpoint.
|
|
990
|
+
-- Canonical intervals make visibility equality and curation effects exact.
|
|
991
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_folded_valid_insert
|
|
992
|
+
BEFORE INSERT ON log_entries
|
|
993
|
+
WHEN EXISTS (
|
|
994
|
+
SELECT 1
|
|
995
|
+
FROM json_each(NEW.folded) range
|
|
996
|
+
WHERE range.type != 'array'
|
|
997
|
+
OR json_array_length(range.value) != 2
|
|
998
|
+
OR COALESCE(json_type(range.value, '$[0]'), '') != 'integer'
|
|
999
|
+
OR COALESCE(json_type(range.value, '$[1]'), '') != 'integer'
|
|
1000
|
+
OR json_extract(range.value, '$[0]') < 1
|
|
1001
|
+
OR (
|
|
1002
|
+
json_extract(range.value, '$[1]') != -1
|
|
1003
|
+
AND json_extract(range.value, '$[1]') < json_extract(range.value, '$[0]')
|
|
1004
|
+
)
|
|
1005
|
+
OR EXISTS (
|
|
1006
|
+
SELECT 1
|
|
1007
|
+
FROM json_each(NEW.folded) previous
|
|
1008
|
+
WHERE previous.key = range.key - 1
|
|
1009
|
+
AND (
|
|
1010
|
+
json_extract(previous.value, '$[1]') = -1
|
|
1011
|
+
OR json_extract(range.value, '$[0]') <= json_extract(previous.value, '$[1]') + 1
|
|
1012
|
+
)
|
|
1013
|
+
)
|
|
1014
|
+
)
|
|
1015
|
+
BEGIN
|
|
1016
|
+
SELECT RAISE(ABORT, 'log entry folded ranges are invalid');
|
|
1017
|
+
END;
|
|
1018
|
+
|
|
1019
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_folded_valid_update
|
|
1020
|
+
BEFORE UPDATE OF folded ON log_entries
|
|
1021
|
+
WHEN EXISTS (
|
|
1022
|
+
SELECT 1
|
|
1023
|
+
FROM json_each(NEW.folded) range
|
|
1024
|
+
WHERE range.type != 'array'
|
|
1025
|
+
OR json_array_length(range.value) != 2
|
|
1026
|
+
OR COALESCE(json_type(range.value, '$[0]'), '') != 'integer'
|
|
1027
|
+
OR COALESCE(json_type(range.value, '$[1]'), '') != 'integer'
|
|
1028
|
+
OR json_extract(range.value, '$[0]') < 1
|
|
1029
|
+
OR (
|
|
1030
|
+
json_extract(range.value, '$[1]') != -1
|
|
1031
|
+
AND json_extract(range.value, '$[1]') < json_extract(range.value, '$[0]')
|
|
1032
|
+
)
|
|
1033
|
+
OR EXISTS (
|
|
1034
|
+
SELECT 1
|
|
1035
|
+
FROM json_each(NEW.folded) previous
|
|
1036
|
+
WHERE previous.key = range.key - 1
|
|
1037
|
+
AND (
|
|
1038
|
+
json_extract(previous.value, '$[1]') = -1
|
|
1039
|
+
OR json_extract(range.value, '$[0]') <= json_extract(previous.value, '$[1]') + 1
|
|
1040
|
+
)
|
|
1041
|
+
)
|
|
1042
|
+
)
|
|
1043
|
+
BEGIN
|
|
1044
|
+
SELECT RAISE(ABORT, 'log entry folded ranges are invalid');
|
|
1045
|
+
END;
|
|
1046
|
+
|
|
820
1047
|
CREATE TRIGGER IF NOT EXISTS log_entries_model_call_valid
|
|
821
1048
|
BEFORE INSERT ON log_entries
|
|
822
1049
|
WHEN NEW.model_call_id IS NOT NULL
|
|
@@ -831,7 +1058,7 @@ WHEN NEW.model_call_id IS NOT NULL
|
|
|
831
1058
|
OR (
|
|
832
1059
|
call.kind = 'emission'
|
|
833
1060
|
AND NEW.op IS NULL
|
|
834
|
-
AND json_extract(NEW.attrs, '$.kind')
|
|
1061
|
+
AND json_extract(NEW.attrs, '$.kind') IN ('turnOps', 'emissionAttempt')
|
|
835
1062
|
)
|
|
836
1063
|
)
|
|
837
1064
|
)
|
|
@@ -935,14 +1162,61 @@ BEGIN
|
|
|
935
1162
|
AND source_record_id = NEW.id;
|
|
936
1163
|
END;
|
|
937
1164
|
|
|
1165
|
+
-- {§worker-initialization-entry} {§overflow-turn-script} — the turn identity
|
|
1166
|
+
-- classifies every row in a kernel-authored recovery/orientation turn. No
|
|
1167
|
+
-- caller can omit provenance from either its exact turnOps or its operation
|
|
1168
|
+
-- outcomes.
|
|
1169
|
+
CREATE TRIGGER IF NOT EXISTS log_entries_classify_plurnk_turn
|
|
1170
|
+
AFTER INSERT ON log_entries
|
|
1171
|
+
WHEN EXISTS (
|
|
1172
|
+
SELECT 1
|
|
1173
|
+
FROM turns
|
|
1174
|
+
WHERE turns.id = NEW.turn_id
|
|
1175
|
+
AND turns.producer = '_plurnk'
|
|
1176
|
+
AND turns.kind IN ('initialization', 'overflow')
|
|
1177
|
+
)
|
|
1178
|
+
BEGIN
|
|
1179
|
+
INSERT OR IGNORE INTO log_tags (log_entry_id, tag)
|
|
1180
|
+
VALUES (NEW.id, '_plurnk');
|
|
1181
|
+
INSERT OR IGNORE INTO log_tags (log_entry_id, tag)
|
|
1182
|
+
SELECT NEW.id, CASE turns.kind
|
|
1183
|
+
WHEN 'initialization' THEN 'init'
|
|
1184
|
+
ELSE 'overflow'
|
|
1185
|
+
END
|
|
1186
|
+
FROM turns
|
|
1187
|
+
WHERE turns.id = NEW.turn_id;
|
|
1188
|
+
END;
|
|
1189
|
+
|
|
1190
|
+
-- Overflow admission reclassifies a would-be inference turn only after its
|
|
1191
|
+
-- pre-model rows exist. Apply the same turn-owned classification to those
|
|
1192
|
+
-- rows; later rows are covered by log_entries_classify_plurnk_turn above.
|
|
1193
|
+
CREATE TRIGGER IF NOT EXISTS turns_classify_existing_plurnk_rows
|
|
1194
|
+
AFTER UPDATE OF producer, kind ON turns
|
|
1195
|
+
WHEN NEW.producer = '_plurnk'
|
|
1196
|
+
AND NEW.kind IN ('initialization', 'overflow')
|
|
1197
|
+
BEGIN
|
|
1198
|
+
INSERT OR IGNORE INTO log_tags (log_entry_id, tag)
|
|
1199
|
+
SELECT id, '_plurnk' FROM log_entries WHERE turn_id = NEW.id;
|
|
1200
|
+
INSERT OR IGNORE INTO log_tags (log_entry_id, tag)
|
|
1201
|
+
SELECT id, CASE NEW.kind
|
|
1202
|
+
WHEN 'initialization' THEN 'init'
|
|
1203
|
+
ELSE 'overflow'
|
|
1204
|
+
END
|
|
1205
|
+
FROM log_entries
|
|
1206
|
+
WHERE turn_id = NEW.id;
|
|
1207
|
+
END;
|
|
1208
|
+
|
|
938
1209
|
-- Successful OPEN/FOLD rows are durable curation events even though their
|
|
939
1210
|
-- ordinary packet projection is suppressed ({§fold-open-meta-operations}).
|
|
940
|
-
-- Preserve the exact selected set and each target's
|
|
1211
|
+
-- Preserve the exact selected set and each target's before/after visibility so a
|
|
941
1212
|
-- broad selector never collapses into the lossy fact `matched: N`.
|
|
942
1213
|
CREATE TABLE IF NOT EXISTS log_curation_effects (
|
|
943
1214
|
operation_log_entry_id INTEGER NOT NULL,
|
|
944
1215
|
target_log_entry_id INTEGER NOT NULL,
|
|
945
|
-
|
|
1216
|
+
folded_before TEXT NOT NULL
|
|
1217
|
+
CHECK (json_valid(folded_before) AND json_type(folded_before) = 'array'),
|
|
1218
|
+
folded_after TEXT NOT NULL
|
|
1219
|
+
CHECK (json_valid(folded_after) AND json_type(folded_after) = 'array'),
|
|
946
1220
|
tags_added TEXT NOT NULL DEFAULT '[]'
|
|
947
1221
|
CHECK (json_valid(tags_added) AND json_type(tags_added) = 'array'),
|
|
948
1222
|
tags_removed TEXT NOT NULL DEFAULT '[]'
|
|
@@ -972,6 +1246,39 @@ BEGIN
|
|
|
972
1246
|
AND operation.status_rx < 400
|
|
973
1247
|
AND operation.worker_id = target.worker_id
|
|
974
1248
|
)
|
|
1249
|
+
OR EXISTS (
|
|
1250
|
+
SELECT 1
|
|
1251
|
+
FROM (
|
|
1252
|
+
SELECT 'before' AS side, key, value, type FROM json_each(NEW.folded_before)
|
|
1253
|
+
UNION ALL
|
|
1254
|
+
SELECT 'after' AS side, key, value, type FROM json_each(NEW.folded_after)
|
|
1255
|
+
) range
|
|
1256
|
+
WHERE range.type != 'array'
|
|
1257
|
+
OR json_array_length(range.value) != 2
|
|
1258
|
+
OR COALESCE(json_type(range.value, '$[0]'), '') != 'integer'
|
|
1259
|
+
OR COALESCE(json_type(range.value, '$[1]'), '') != 'integer'
|
|
1260
|
+
OR json_extract(range.value, '$[0]') < 1
|
|
1261
|
+
OR (
|
|
1262
|
+
json_extract(range.value, '$[1]') != -1
|
|
1263
|
+
AND json_extract(range.value, '$[1]') < json_extract(range.value, '$[0]')
|
|
1264
|
+
)
|
|
1265
|
+
OR EXISTS (
|
|
1266
|
+
SELECT 1
|
|
1267
|
+
FROM (
|
|
1268
|
+
SELECT key, value FROM json_each(
|
|
1269
|
+
CASE range.side
|
|
1270
|
+
WHEN 'before' THEN NEW.folded_before
|
|
1271
|
+
ELSE NEW.folded_after
|
|
1272
|
+
END
|
|
1273
|
+
)
|
|
1274
|
+
) previous
|
|
1275
|
+
WHERE previous.key = range.key - 1
|
|
1276
|
+
AND (
|
|
1277
|
+
json_extract(previous.value, '$[1]') = -1
|
|
1278
|
+
OR json_extract(range.value, '$[0]') <= json_extract(previous.value, '$[1]') + 1
|
|
1279
|
+
)
|
|
1280
|
+
)
|
|
1281
|
+
)
|
|
975
1282
|
OR EXISTS (
|
|
976
1283
|
SELECT 1
|
|
977
1284
|
FROM (
|
|
@@ -1027,7 +1334,7 @@ BEGIN
|
|
|
1027
1334
|
END;
|
|
1028
1335
|
|
|
1029
1336
|
-- One outer INSERT owns the whole landed curation event: exact selected rows,
|
|
1030
|
-
-- their
|
|
1337
|
+
-- their before/after visibility and tag deltas, and the
|
|
1031
1338
|
-- resulting classifications. Trigger failure rolls the operation row and all
|
|
1032
1339
|
-- effects back together. The private plan is erased before INSERT returns.
|
|
1033
1340
|
CREATE TRIGGER IF NOT EXISTS log_entries_apply_curation
|
|
@@ -1037,26 +1344,70 @@ WHEN NEW.op IN ('OPEN', 'FOLD')
|
|
|
1037
1344
|
AND json_type(NEW.attrs, '$.__plurnk_curation') = 'object'
|
|
1038
1345
|
BEGIN
|
|
1039
1346
|
SELECT CASE WHEN
|
|
1040
|
-
COALESCE(json_type(NEW.attrs, '$.__plurnk_curation.
|
|
1347
|
+
COALESCE(json_type(NEW.attrs, '$.__plurnk_curation.targets'), '') != 'array'
|
|
1041
1348
|
OR COALESCE(json_type(NEW.attrs, '$.__plurnk_curation.add'), '') != 'array'
|
|
1042
1349
|
OR COALESCE(json_type(NEW.attrs, '$.__plurnk_curation.remove'), '') != 'array'
|
|
1043
|
-
OR
|
|
1044
|
-
OR json_extract(NEW.attrs, '$.__plurnk_curation.expanded') NOT IN (0, 1)
|
|
1045
|
-
OR json_array_length(NEW.attrs, '$.__plurnk_curation.ids') = 0
|
|
1350
|
+
OR json_array_length(NEW.attrs, '$.__plurnk_curation.targets') = 0
|
|
1046
1351
|
OR EXISTS (
|
|
1047
|
-
SELECT 1
|
|
1048
|
-
|
|
1352
|
+
SELECT 1
|
|
1353
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets') selected
|
|
1354
|
+
WHERE selected.type != 'object'
|
|
1355
|
+
OR COALESCE(json_type(selected.value, '$.id'), '') != 'integer'
|
|
1356
|
+
OR json_extract(selected.value, '$.id') <= 0
|
|
1357
|
+
OR COALESCE(json_type(selected.value, '$.before'), '') != 'array'
|
|
1358
|
+
OR COALESCE(json_type(selected.value, '$.after'), '') != 'array'
|
|
1359
|
+
OR EXISTS (
|
|
1360
|
+
SELECT 1 FROM json_each(selected.value) field
|
|
1361
|
+
WHERE field.key NOT IN ('id', 'before', 'after')
|
|
1362
|
+
)
|
|
1363
|
+
OR EXISTS (
|
|
1364
|
+
SELECT 1
|
|
1365
|
+
FROM (
|
|
1366
|
+
SELECT 'before' AS side, range.key, range.value, range.type
|
|
1367
|
+
FROM json_each(json_extract(selected.value, '$.before')) range
|
|
1368
|
+
UNION ALL
|
|
1369
|
+
SELECT 'after' AS side, range.key, range.value, range.type
|
|
1370
|
+
FROM json_each(json_extract(selected.value, '$.after')) range
|
|
1371
|
+
) range
|
|
1372
|
+
WHERE range.type != 'array'
|
|
1373
|
+
OR json_array_length(range.value) != 2
|
|
1374
|
+
OR COALESCE(json_type(range.value, '$[0]'), '') != 'integer'
|
|
1375
|
+
OR COALESCE(json_type(range.value, '$[1]'), '') != 'integer'
|
|
1376
|
+
OR json_extract(range.value, '$[0]') < 1
|
|
1377
|
+
OR (
|
|
1378
|
+
json_extract(range.value, '$[1]') != -1
|
|
1379
|
+
AND json_extract(range.value, '$[1]') < json_extract(range.value, '$[0]')
|
|
1380
|
+
)
|
|
1381
|
+
OR EXISTS (
|
|
1382
|
+
SELECT 1
|
|
1383
|
+
FROM json_each(
|
|
1384
|
+
CASE range.side
|
|
1385
|
+
WHEN 'before' THEN json_extract(selected.value, '$.before')
|
|
1386
|
+
ELSE json_extract(selected.value, '$.after')
|
|
1387
|
+
END
|
|
1388
|
+
) previous
|
|
1389
|
+
WHERE previous.key = range.key - 1
|
|
1390
|
+
AND (
|
|
1391
|
+
json_extract(previous.value, '$[1]') = -1
|
|
1392
|
+
OR json_extract(range.value, '$[0]') <= json_extract(previous.value, '$[1]') + 1
|
|
1393
|
+
)
|
|
1394
|
+
)
|
|
1395
|
+
)
|
|
1049
1396
|
)
|
|
1050
1397
|
OR (
|
|
1051
|
-
SELECT COUNT(*) FROM json_each(NEW.attrs, '$.__plurnk_curation.
|
|
1398
|
+
SELECT COUNT(*) FROM json_each(NEW.attrs, '$.__plurnk_curation.targets')
|
|
1052
1399
|
) != (
|
|
1053
|
-
SELECT COUNT(DISTINCT value
|
|
1400
|
+
SELECT COUNT(DISTINCT json_extract(value, '$.id'))
|
|
1401
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets')
|
|
1054
1402
|
)
|
|
1055
1403
|
OR EXISTS (
|
|
1056
1404
|
SELECT 1
|
|
1057
|
-
FROM json_each(NEW.attrs, '$.__plurnk_curation.
|
|
1058
|
-
LEFT JOIN log_entries target ON target.id = selected.value
|
|
1059
|
-
WHERE target.id IS NULL
|
|
1405
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets') selected
|
|
1406
|
+
LEFT JOIN log_entries target ON target.id = json_extract(selected.value, '$.id')
|
|
1407
|
+
WHERE target.id IS NULL
|
|
1408
|
+
OR target.worker_id != NEW.worker_id
|
|
1409
|
+
OR target.id = NEW.id
|
|
1410
|
+
OR json(target.folded) != json(json_extract(selected.value, '$.before'))
|
|
1060
1411
|
)
|
|
1061
1412
|
OR EXISTS (
|
|
1062
1413
|
SELECT 1
|
|
@@ -1107,14 +1458,16 @@ BEGIN
|
|
|
1107
1458
|
INSERT INTO log_curation_effects (
|
|
1108
1459
|
operation_log_entry_id,
|
|
1109
1460
|
target_log_entry_id,
|
|
1110
|
-
|
|
1461
|
+
folded_before,
|
|
1462
|
+
folded_after,
|
|
1111
1463
|
tags_added,
|
|
1112
1464
|
tags_removed
|
|
1113
1465
|
)
|
|
1114
1466
|
SELECT
|
|
1115
1467
|
NEW.id,
|
|
1116
1468
|
target.id,
|
|
1117
|
-
|
|
1469
|
+
json_extract(selected.value, '$.before'),
|
|
1470
|
+
json_extract(selected.value, '$.after'),
|
|
1118
1471
|
COALESCE((
|
|
1119
1472
|
SELECT json_group_array(ordered.tag)
|
|
1120
1473
|
FROM (
|
|
@@ -1139,26 +1492,32 @@ BEGIN
|
|
|
1139
1492
|
ORDER BY removal.value
|
|
1140
1493
|
) ordered
|
|
1141
1494
|
), '[]')
|
|
1142
|
-
FROM json_each(NEW.attrs, '$.__plurnk_curation.
|
|
1143
|
-
JOIN log_entries target ON target.id = selected.value;
|
|
1495
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets') selected
|
|
1496
|
+
JOIN log_entries target ON target.id = json_extract(selected.value, '$.id');
|
|
1144
1497
|
|
|
1145
1498
|
UPDATE log_entries
|
|
1146
|
-
SET
|
|
1499
|
+
SET folded = (
|
|
1500
|
+
SELECT json_extract(selected.value, '$.after')
|
|
1501
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets') selected
|
|
1502
|
+
WHERE json_extract(selected.value, '$.id') = log_entries.id
|
|
1503
|
+
)
|
|
1147
1504
|
WHERE id IN (
|
|
1148
|
-
SELECT value
|
|
1505
|
+
SELECT json_extract(value, '$.id')
|
|
1506
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets')
|
|
1149
1507
|
);
|
|
1150
1508
|
|
|
1151
1509
|
DELETE FROM log_tags
|
|
1152
1510
|
WHERE log_entry_id IN (
|
|
1153
|
-
SELECT value
|
|
1511
|
+
SELECT json_extract(value, '$.id')
|
|
1512
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets')
|
|
1154
1513
|
)
|
|
1155
1514
|
AND tag IN (
|
|
1156
1515
|
SELECT value FROM json_each(NEW.attrs, '$.__plurnk_curation.remove')
|
|
1157
1516
|
);
|
|
1158
1517
|
|
|
1159
1518
|
INSERT OR IGNORE INTO log_tags (log_entry_id, tag)
|
|
1160
|
-
SELECT selected.value, addition.value
|
|
1161
|
-
FROM json_each(NEW.attrs, '$.__plurnk_curation.
|
|
1519
|
+
SELECT json_extract(selected.value, '$.id'), addition.value
|
|
1520
|
+
FROM json_each(NEW.attrs, '$.__plurnk_curation.targets') selected
|
|
1162
1521
|
CROSS JOIN json_each(NEW.attrs, '$.__plurnk_curation.add') addition;
|
|
1163
1522
|
|
|
1164
1523
|
UPDATE log_entries
|
|
@@ -1168,18 +1527,18 @@ END;
|
|
|
1168
1527
|
|
|
1169
1528
|
-- Column-scoped immutability: the original action's identity and target never
|
|
1170
1529
|
-- change; the proposal lifecycle is allowed to mutate state, outcome,
|
|
1171
|
-
-- status_rx, rx,
|
|
1530
|
+
-- status_rx, rx, folded. Keep attrs separate so the curation trigger's one
|
|
1172
1531
|
-- private-payload removal cannot exempt changes to any other core column.
|
|
1173
1532
|
CREATE TRIGGER IF NOT EXISTS log_entries_immutable_core
|
|
1174
1533
|
BEFORE UPDATE OF
|
|
1175
1534
|
worker_id, loop_id, turn_id, sequence, at, origin, source, model_call_id,
|
|
1176
|
-
op,
|
|
1535
|
+
op, delimiter, signal,
|
|
1177
1536
|
scheme, username, password, hostname,
|
|
1178
1537
|
port, pathname, query, fragment,
|
|
1179
1538
|
lineMarker, tx, mimetype_tx, mimetype_rx
|
|
1180
1539
|
ON log_entries
|
|
1181
1540
|
BEGIN
|
|
1182
|
-
SELECT RAISE(ABORT, 'log_entries core fields are immutable; only state/outcome/status_rx/rx/
|
|
1541
|
+
SELECT RAISE(ABORT, 'log_entries core fields are immutable; only state/outcome/status_rx/rx/folded may change');
|
|
1183
1542
|
END;
|
|
1184
1543
|
|
|
1185
1544
|
CREATE TRIGGER IF NOT EXISTS log_entries_immutable_attrs
|
|
@@ -1213,7 +1572,7 @@ WHEN NEW.ambient_event_id IS NULL
|
|
|
1213
1572
|
AND (NEW.scheme IS NULL OR NEW.scheme != 'plurnk')
|
|
1214
1573
|
AND (NEW.scheme IS NULL OR NEW.scheme != 'worker' OR NEW.hostname IS NULL OR NEW.hostname = 'plurnk')
|
|
1215
1574
|
AND (
|
|
1216
|
-
NEW.origin != '
|
|
1575
|
+
NEW.origin != '_plurnk'
|
|
1217
1576
|
OR EXISTS (SELECT 1 FROM workers w WHERE w.id = NEW.worker_id AND w.name = 'plurnk')
|
|
1218
1577
|
)
|
|
1219
1578
|
BEGIN
|
|
@@ -1247,7 +1606,7 @@ WHEN OLD.state = 'proposed'
|
|
|
1247
1606
|
AND (NEW.scheme IS NULL OR NEW.scheme != 'plurnk')
|
|
1248
1607
|
AND (NEW.scheme IS NULL OR NEW.scheme != 'worker' OR NEW.hostname IS NULL OR NEW.hostname = 'plurnk')
|
|
1249
1608
|
AND (
|
|
1250
|
-
NEW.origin != '
|
|
1609
|
+
NEW.origin != '_plurnk'
|
|
1251
1610
|
OR EXISTS (SELECT 1 FROM workers w WHERE w.id = NEW.worker_id AND w.name = 'plurnk')
|
|
1252
1611
|
)
|
|
1253
1612
|
BEGIN
|