@unson/brainbase-mcp 0.7.0 → 0.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/contracts/foundation/graph-history.sql +634 -0
- package/contracts/judgment-value-proof/schema.json +43 -1
- package/dist/canonical-task-service.js +16 -5
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +107 -0
- package/dist/company-os-objectives.d.ts +11 -0
- package/dist/company-os-objectives.js +84 -47
- package/dist/foundation-authenticated-tools.d.ts +56 -0
- package/dist/foundation-authenticated-tools.js +347 -0
- package/dist/foundation-graph-http.d.ts +43 -0
- package/dist/foundation-graph-http.js +243 -0
- package/dist/foundation-graph-write.d.ts +90 -0
- package/dist/foundation-graph-write.js +447 -0
- package/dist/foundation-public-provider.d.ts +140 -0
- package/dist/foundation-public-provider.js +192 -0
- package/dist/graph-corrections.d.ts +157 -0
- package/dist/graph-corrections.js +620 -0
- package/dist/graph-foundation-reader.d.ts +60 -0
- package/dist/graph-foundation-reader.js +494 -0
- package/dist/graph-retrieval.d.ts +6 -1
- package/dist/graph-revision-reader.d.ts +80 -0
- package/dist/graph-revision-reader.js +246 -0
- package/dist/graph-web-http.d.ts +26 -0
- package/dist/graph-web-http.js +215 -0
- package/dist/graph-web.d.ts +364 -0
- package/dist/graph-web.js +639 -0
- package/dist/judgment-problem-snapshot.d.ts +30 -2
- package/dist/judgment-problem-snapshot.js +302 -6
- package/dist/judgment-value-proof-review.d.ts +166 -0
- package/dist/judgment-value-proof-review.js +437 -0
- package/dist/judgment-value-proof.d.ts +28 -1
- package/dist/judgment-value-proof.js +53 -8
- package/dist/knowledge-continuation.d.ts +127 -0
- package/dist/knowledge-continuation.js +446 -0
- package/dist/knowledge-lookup.d.ts +178 -0
- package/dist/knowledge-lookup.js +758 -0
- package/dist/local-web-fetch-bridge.d.ts +5 -0
- package/dist/local-web-fetch-bridge.js +37 -0
- package/dist/local-web-host.d.ts +109 -0
- package/dist/local-web-host.js +688 -0
- package/dist/local-web-security.d.ts +25 -0
- package/dist/local-web-security.js +95 -0
- package/dist/organization-graph.d.ts +15 -0
- package/dist/organization-graph.js +24 -4
- package/dist/personal-knowledge.d.ts +12 -0
- package/dist/personal-knowledge.js +29 -0
- package/dist/personal-memory-handover.d.ts +108 -0
- package/dist/personal-memory-handover.js +369 -0
- package/dist/philosophy-revision-reader.d.ts +85 -0
- package/dist/philosophy-revision-reader.js +241 -0
- package/dist/portable-graph.d.ts +24 -0
- package/dist/portable-graph.js +77 -0
- package/dist/server.d.ts +7 -2
- package/dist/server.js +9 -6
- package/dist/value-proof-review-http.d.ts +25 -0
- package/dist/value-proof-review-http.js +185 -0
- package/dist/world-model.d.ts +21 -3
- package/dist/world-model.js +94 -12
- package/package.json +94 -3
- package/ui/brainbase-tokens.css +56 -0
- package/ui/graph-own-share.js +367 -0
- package/ui/graph-projects-view.css +23 -0
- package/ui/graph-projects-view.js +730 -0
- package/ui/graph-registry-view.css +101 -0
- package/ui/graph-registry-view.js +804 -0
- package/ui/graph-view-shared.css +522 -0
- package/ui/graph-view-shared.js +1227 -0
- package/ui/judgment-view.css +119 -45
- package/ui/local-web-shell.css +396 -0
- package/ui/local-web-shell.js +378 -0
- package/ui/objective-editor-http-port.js +154 -0
- package/ui/objective-editor.css +180 -74
- package/ui/objective-editor.js +490 -43
- package/ui/outcome-knowledge.css +50 -14
- package/ui/outcome-knowledge.js +15 -1
- package/ui/outcome-mana.css +91 -14
- package/ui/outcome-mana.js +958 -61
- package/ui/value-proof-review.css +504 -0
- package/ui/value-proof-review.js +1104 -0
- package/ui/workspace-kit.css +485 -0
- package/ui/workspace-kit.js +229 -0
- package/ui/world-model-view.css +188 -0
- package/ui/world-model-view.js +486 -0
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Canonical Graph Foundation history
|
|
3
|
+
*
|
|
4
|
+
* This migration is deliberately limited to public.graph_entities and the
|
|
5
|
+
* history objects created below. The application role must not receive
|
|
6
|
+
* INSERT/UPDATE/DELETE on graph_foundation_revisions. The host migration
|
|
7
|
+
* should grant SELECT on that table to the same runtime roles that can read
|
|
8
|
+
* graph_entities; the policy below still requires the current row to be
|
|
9
|
+
* visible through graph_entities RLS.
|
|
10
|
+
*
|
|
11
|
+
* The host applies this file inside its existing single transaction. Do not
|
|
12
|
+
* add BEGIN/COMMIT here: the host applies schema, RLS, this migration, and
|
|
13
|
+
* its readback checks atomically.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
LOCK TABLE public.graph_entities IN SHARE ROW EXCLUSIVE MODE;
|
|
17
|
+
|
|
18
|
+
DO $graph_history_required_columns$
|
|
19
|
+
DECLARE
|
|
20
|
+
missing_columns text[];
|
|
21
|
+
BEGIN
|
|
22
|
+
IF to_regclass('public.graph_entities') IS NULL THEN
|
|
23
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_MISSING_GRAPH_ENTITIES'
|
|
24
|
+
USING ERRCODE = 'undefined_table';
|
|
25
|
+
END IF;
|
|
26
|
+
|
|
27
|
+
SELECT array_agg(required_column ORDER BY required_column)
|
|
28
|
+
INTO missing_columns
|
|
29
|
+
FROM (VALUES
|
|
30
|
+
('id'),
|
|
31
|
+
('entity_type'),
|
|
32
|
+
('project_id'),
|
|
33
|
+
('payload'),
|
|
34
|
+
('role_min'),
|
|
35
|
+
('sensitivity'),
|
|
36
|
+
('lifecycle_status'),
|
|
37
|
+
('version')
|
|
38
|
+
) AS required(required_column)
|
|
39
|
+
WHERE NOT EXISTS (
|
|
40
|
+
SELECT 1
|
|
41
|
+
FROM information_schema.columns AS c
|
|
42
|
+
WHERE c.table_schema = 'public'
|
|
43
|
+
AND c.table_name = 'graph_entities'
|
|
44
|
+
AND c.column_name = required.required_column
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
IF missing_columns IS NOT NULL THEN
|
|
48
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_GRAPH_ENTITIES_COLUMNS_MISSING: %', missing_columns
|
|
49
|
+
USING ERRCODE = 'undefined_column';
|
|
50
|
+
END IF;
|
|
51
|
+
END;
|
|
52
|
+
$graph_history_required_columns$;
|
|
53
|
+
|
|
54
|
+
/* PostgreSQL 18/PGlite exposes sha256(bytea) in the core catalog. */
|
|
55
|
+
CREATE OR REPLACE FUNCTION public.graph_foundation_storage_digest(p_payload jsonb)
|
|
56
|
+
RETURNS text
|
|
57
|
+
LANGUAGE sql
|
|
58
|
+
IMMUTABLE
|
|
59
|
+
STRICT
|
|
60
|
+
SET search_path = pg_catalog, public
|
|
61
|
+
AS $graph_foundation_storage_digest$
|
|
62
|
+
SELECT 'sha256:' || encode(sha256(convert_to(p_payload::text, 'UTF8')), 'hex');
|
|
63
|
+
$graph_foundation_storage_digest$;
|
|
64
|
+
|
|
65
|
+
CREATE TABLE IF NOT EXISTS public.graph_foundation_revisions (
|
|
66
|
+
entity_id text NOT NULL,
|
|
67
|
+
entity_type text NOT NULL
|
|
68
|
+
CONSTRAINT graph_foundation_revisions_entity_type_check
|
|
69
|
+
CHECK (entity_type IN ('objective', 'variable', 'model', 'constraint', 'philosophy')),
|
|
70
|
+
revision text NOT NULL
|
|
71
|
+
CONSTRAINT graph_foundation_revisions_revision_check
|
|
72
|
+
CHECK (revision ~ '^[1-9][0-9]*$'),
|
|
73
|
+
payload jsonb NOT NULL,
|
|
74
|
+
project_id text,
|
|
75
|
+
role_min text,
|
|
76
|
+
sensitivity text,
|
|
77
|
+
lifecycle_status text,
|
|
78
|
+
storage_digest text NOT NULL
|
|
79
|
+
CONSTRAINT graph_foundation_revisions_storage_digest_format_check
|
|
80
|
+
CHECK (storage_digest ~ '^sha256:[0-9a-f]{64}$'),
|
|
81
|
+
captured_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
82
|
+
CONSTRAINT graph_foundation_revisions_storage_digest_check
|
|
83
|
+
CHECK (storage_digest = public.graph_foundation_storage_digest(payload)),
|
|
84
|
+
CONSTRAINT graph_foundation_revisions_pkey
|
|
85
|
+
PRIMARY KEY (entity_id, entity_type, revision)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
/* Make a pre-existing table from an interrupted/older attempt converge. */
|
|
89
|
+
DO $graph_history_constraints$
|
|
90
|
+
BEGIN
|
|
91
|
+
IF NOT EXISTS (
|
|
92
|
+
SELECT 1 FROM pg_constraint
|
|
93
|
+
WHERE conrelid = 'public.graph_foundation_revisions'::regclass
|
|
94
|
+
AND conname = 'graph_foundation_revisions_entity_type_check'
|
|
95
|
+
) THEN
|
|
96
|
+
ALTER TABLE public.graph_foundation_revisions
|
|
97
|
+
ADD CONSTRAINT graph_foundation_revisions_entity_type_check
|
|
98
|
+
CHECK (entity_type IN ('objective', 'variable', 'model', 'constraint', 'philosophy'));
|
|
99
|
+
END IF;
|
|
100
|
+
|
|
101
|
+
IF NOT EXISTS (
|
|
102
|
+
SELECT 1 FROM pg_constraint
|
|
103
|
+
WHERE conrelid = 'public.graph_foundation_revisions'::regclass
|
|
104
|
+
AND conname = 'graph_foundation_revisions_revision_check'
|
|
105
|
+
) THEN
|
|
106
|
+
ALTER TABLE public.graph_foundation_revisions
|
|
107
|
+
ADD CONSTRAINT graph_foundation_revisions_revision_check
|
|
108
|
+
CHECK (revision ~ '^[1-9][0-9]*$');
|
|
109
|
+
END IF;
|
|
110
|
+
|
|
111
|
+
IF NOT EXISTS (
|
|
112
|
+
SELECT 1 FROM pg_constraint
|
|
113
|
+
WHERE conrelid = 'public.graph_foundation_revisions'::regclass
|
|
114
|
+
AND conname = 'graph_foundation_revisions_storage_digest_format_check'
|
|
115
|
+
) THEN
|
|
116
|
+
ALTER TABLE public.graph_foundation_revisions
|
|
117
|
+
ADD CONSTRAINT graph_foundation_revisions_storage_digest_format_check
|
|
118
|
+
CHECK (storage_digest ~ '^sha256:[0-9a-f]{64}$');
|
|
119
|
+
END IF;
|
|
120
|
+
|
|
121
|
+
IF NOT EXISTS (
|
|
122
|
+
SELECT 1 FROM pg_constraint
|
|
123
|
+
WHERE conrelid = 'public.graph_foundation_revisions'::regclass
|
|
124
|
+
AND conname = 'graph_foundation_revisions_storage_digest_check'
|
|
125
|
+
) THEN
|
|
126
|
+
ALTER TABLE public.graph_foundation_revisions
|
|
127
|
+
ADD CONSTRAINT graph_foundation_revisions_storage_digest_check
|
|
128
|
+
CHECK (storage_digest = public.graph_foundation_storage_digest(payload));
|
|
129
|
+
END IF;
|
|
130
|
+
|
|
131
|
+
IF NOT EXISTS (
|
|
132
|
+
SELECT 1 FROM pg_constraint
|
|
133
|
+
WHERE conrelid = 'public.graph_foundation_revisions'::regclass
|
|
134
|
+
AND conname = 'graph_foundation_revisions_pkey'
|
|
135
|
+
) THEN
|
|
136
|
+
ALTER TABLE public.graph_foundation_revisions
|
|
137
|
+
ADD CONSTRAINT graph_foundation_revisions_pkey
|
|
138
|
+
PRIMARY KEY (entity_id, entity_type, revision);
|
|
139
|
+
END IF;
|
|
140
|
+
END;
|
|
141
|
+
$graph_history_constraints$;
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* This private table supplies a per-trigger nonce. A caller cannot make a
|
|
145
|
+
* direct history INSERT look like the SECURITY DEFINER append helper merely
|
|
146
|
+
* by setting a custom GUC: the nonce must have been created by that helper in
|
|
147
|
+
* the same transaction and backend.
|
|
148
|
+
*/
|
|
149
|
+
CREATE TABLE IF NOT EXISTS public.graph_foundation_capture_nonces (
|
|
150
|
+
nonce text PRIMARY KEY,
|
|
151
|
+
transaction_id bigint NOT NULL,
|
|
152
|
+
backend_pid integer NOT NULL,
|
|
153
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp()
|
|
154
|
+
);
|
|
155
|
+
REVOKE ALL ON TABLE public.graph_foundation_capture_nonces FROM PUBLIC;
|
|
156
|
+
REVOKE ALL ON TABLE public.graph_foundation_revisions FROM PUBLIC;
|
|
157
|
+
|
|
158
|
+
CREATE OR REPLACE FUNCTION public.assert_graph_foundation_payload(
|
|
159
|
+
p_entity_id text,
|
|
160
|
+
p_entity_type text,
|
|
161
|
+
p_payload jsonb
|
|
162
|
+
)
|
|
163
|
+
RETURNS void
|
|
164
|
+
LANGUAGE plpgsql
|
|
165
|
+
IMMUTABLE
|
|
166
|
+
SET search_path = pg_catalog, public
|
|
167
|
+
AS $assert_graph_foundation_payload$
|
|
168
|
+
DECLARE
|
|
169
|
+
foundation jsonb;
|
|
170
|
+
draft_candidate boolean;
|
|
171
|
+
required_key text;
|
|
172
|
+
required_keys text[];
|
|
173
|
+
BEGIN
|
|
174
|
+
IF p_entity_type NOT IN ('objective', 'variable', 'model', 'constraint') THEN
|
|
175
|
+
IF p_entity_type = 'philosophy' AND jsonb_typeof(p_payload) = 'object' THEN
|
|
176
|
+
RETURN;
|
|
177
|
+
END IF;
|
|
178
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_INVALID_ENTITY_TYPE: %', p_entity_type
|
|
179
|
+
USING ERRCODE = 'check_violation';
|
|
180
|
+
END IF;
|
|
181
|
+
|
|
182
|
+
IF p_payload IS NULL OR jsonb_typeof(p_payload) <> 'object' THEN
|
|
183
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_PAYLOAD_MUST_BE_OBJECT: %', p_entity_id
|
|
184
|
+
USING ERRCODE = 'check_violation';
|
|
185
|
+
END IF;
|
|
186
|
+
|
|
187
|
+
foundation := p_payload -> 'foundation';
|
|
188
|
+
IF foundation IS NULL OR jsonb_typeof(foundation) <> 'object' THEN
|
|
189
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_DEFINITION_REQUIRED: %/%', p_entity_type, p_entity_id
|
|
190
|
+
USING ERRCODE = 'check_violation';
|
|
191
|
+
END IF;
|
|
192
|
+
|
|
193
|
+
IF foundation ->> 'id' IS DISTINCT FROM p_entity_id THEN
|
|
194
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_ID_MISMATCH: %/%', p_entity_type, p_entity_id
|
|
195
|
+
USING ERRCODE = 'check_violation';
|
|
196
|
+
END IF;
|
|
197
|
+
IF foundation ->> 'type' IS DISTINCT FROM p_entity_type THEN
|
|
198
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_TYPE_MISMATCH: %/%', p_entity_type, p_entity_id
|
|
199
|
+
USING ERRCODE = 'check_violation';
|
|
200
|
+
END IF;
|
|
201
|
+
IF foundation ->> 'revision' IS NULL
|
|
202
|
+
OR foundation ->> 'revision' !~ '^[1-9][0-9]*$' THEN
|
|
203
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_REVISION_INVALID: %/%', p_entity_type, p_entity_id
|
|
204
|
+
USING ERRCODE = 'check_violation';
|
|
205
|
+
END IF;
|
|
206
|
+
|
|
207
|
+
required_keys := ARRAY[
|
|
208
|
+
'id', 'type', 'revision', 'meaning', 'adoptionState', 'authorizedUses',
|
|
209
|
+
'acl', 'storage', 'provenance', 'scope'
|
|
210
|
+
];
|
|
211
|
+
FOREACH required_key IN ARRAY required_keys LOOP
|
|
212
|
+
IF NOT (foundation ? required_key)
|
|
213
|
+
OR jsonb_typeof(foundation -> required_key) = 'null' THEN
|
|
214
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_FIELD_REQUIRED: %/% %',
|
|
215
|
+
p_entity_type, p_entity_id, required_key
|
|
216
|
+
USING ERRCODE = 'check_violation';
|
|
217
|
+
END IF;
|
|
218
|
+
END LOOP;
|
|
219
|
+
|
|
220
|
+
IF jsonb_typeof(foundation -> 'meaning') <> 'string'
|
|
221
|
+
OR jsonb_typeof(foundation -> 'adoptionState') <> 'string'
|
|
222
|
+
OR jsonb_typeof(foundation -> 'authorizedUses') <> 'array'
|
|
223
|
+
OR jsonb_typeof(foundation -> 'provenance') <> 'array'
|
|
224
|
+
OR jsonb_typeof(foundation -> 'acl') <> 'object'
|
|
225
|
+
OR jsonb_typeof(foundation -> 'scope') <> 'object' THEN
|
|
226
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_BASE_INVALID: %/%', p_entity_type, p_entity_id
|
|
227
|
+
USING ERRCODE = 'check_violation';
|
|
228
|
+
END IF;
|
|
229
|
+
|
|
230
|
+
IF NOT (foundation -> 'acl' ? 'ownerId')
|
|
231
|
+
OR NOT (foundation -> 'acl' ? 'visibility')
|
|
232
|
+
OR NOT (foundation -> 'acl' ? 'readerIds')
|
|
233
|
+
OR NOT (foundation -> 'acl' ? 'writerIds')
|
|
234
|
+
OR jsonb_typeof(foundation -> 'acl' -> 'ownerId') <> 'string'
|
|
235
|
+
OR jsonb_typeof(foundation -> 'acl' -> 'visibility') <> 'string'
|
|
236
|
+
OR jsonb_typeof(foundation -> 'acl' -> 'readerIds') <> 'array'
|
|
237
|
+
OR jsonb_typeof(foundation -> 'acl' -> 'writerIds') <> 'array' THEN
|
|
238
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_ACL_INVALID: %/%', p_entity_type, p_entity_id
|
|
239
|
+
USING ERRCODE = 'check_violation';
|
|
240
|
+
END IF;
|
|
241
|
+
|
|
242
|
+
IF NOT (foundation -> 'scope' ? 'subjectIds')
|
|
243
|
+
OR NOT (foundation -> 'scope' ? 'validFrom')
|
|
244
|
+
OR jsonb_typeof(foundation -> 'scope' -> 'subjectIds') <> 'array'
|
|
245
|
+
OR jsonb_typeof(foundation -> 'scope' -> 'validFrom') <> 'string'
|
|
246
|
+
OR ((foundation -> 'scope') ? 'validUntil'
|
|
247
|
+
AND jsonb_typeof(foundation -> 'scope' -> 'validUntil') <> 'string') THEN
|
|
248
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_SCOPE_INVALID: %/%', p_entity_type, p_entity_id
|
|
249
|
+
USING ERRCODE = 'check_violation';
|
|
250
|
+
END IF;
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* Keep history capture aligned with the canonical draft writer. A draft
|
|
254
|
+
* is relaxed only for the exact candidate contract; an approved/proposed
|
|
255
|
+
* row must continue through the strict type-specific checks below.
|
|
256
|
+
*/
|
|
257
|
+
draft_candidate := foundation ->> 'adoptionState' = 'draft'
|
|
258
|
+
AND foundation ->> 'storage' = 'candidate'
|
|
259
|
+
AND (foundation -> 'authorizedUses') = '["draft"]'::jsonb;
|
|
260
|
+
|
|
261
|
+
IF p_entity_type = 'objective' THEN
|
|
262
|
+
IF draft_candidate THEN
|
|
263
|
+
IF ((foundation ? 'beneficiaryIds') AND jsonb_typeof(foundation -> 'beneficiaryIds') IS DISTINCT FROM 'array')
|
|
264
|
+
OR ((foundation ? 'desiredState') AND jsonb_typeof(foundation -> 'desiredState') IS DISTINCT FROM 'string')
|
|
265
|
+
OR ((foundation ? 'criteria') AND jsonb_typeof(foundation -> 'criteria') IS DISTINCT FROM 'array')
|
|
266
|
+
OR ((foundation ? 'evaluationPeriod') AND jsonb_typeof(foundation -> 'evaluationPeriod') IS DISTINCT FROM 'object')
|
|
267
|
+
OR ((foundation ? 'accountableId') AND jsonb_typeof(foundation -> 'accountableId') IS DISTINCT FROM 'string') THEN
|
|
268
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_OBJECTIVE_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
269
|
+
USING ERRCODE = 'check_violation';
|
|
270
|
+
END IF;
|
|
271
|
+
ELSIF NOT (foundation ? 'beneficiaryIds')
|
|
272
|
+
OR NOT (foundation ? 'desiredState')
|
|
273
|
+
OR NOT (foundation ? 'criteria')
|
|
274
|
+
OR NOT (foundation ? 'evaluationPeriod')
|
|
275
|
+
OR jsonb_typeof(foundation -> 'beneficiaryIds') <> 'array'
|
|
276
|
+
OR jsonb_typeof(foundation -> 'desiredState') <> 'string'
|
|
277
|
+
OR jsonb_typeof(foundation -> 'criteria') <> 'array'
|
|
278
|
+
OR jsonb_typeof(foundation -> 'evaluationPeriod') <> 'object' THEN
|
|
279
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_OBJECTIVE_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
280
|
+
USING ERRCODE = 'check_violation';
|
|
281
|
+
END IF;
|
|
282
|
+
ELSIF p_entity_type = 'variable' THEN
|
|
283
|
+
IF draft_candidate THEN
|
|
284
|
+
IF ((foundation ? 'subject') AND jsonb_typeof(foundation -> 'subject') IS DISTINCT FROM 'string')
|
|
285
|
+
OR ((foundation ? 'valueKind') AND jsonb_typeof(foundation -> 'valueKind') IS DISTINCT FROM 'string')
|
|
286
|
+
OR ((foundation ? 'unit') AND jsonb_typeof(foundation -> 'unit') IS DISTINCT FROM 'string')
|
|
287
|
+
OR ((foundation ? 'aggregation') AND jsonb_typeof(foundation -> 'aggregation') IS DISTINCT FROM 'string')
|
|
288
|
+
OR ((foundation ? 'granularity') AND jsonb_typeof(foundation -> 'granularity') IS DISTINCT FROM 'string')
|
|
289
|
+
OR ((foundation ? 'measurementMethod') AND jsonb_typeof(foundation -> 'measurementMethod') IS DISTINCT FROM 'string') THEN
|
|
290
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_VARIABLE_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
291
|
+
USING ERRCODE = 'check_violation';
|
|
292
|
+
END IF;
|
|
293
|
+
ELSIF NOT (foundation ? 'subject')
|
|
294
|
+
OR NOT (foundation ? 'valueKind')
|
|
295
|
+
OR NOT (foundation ? 'aggregation')
|
|
296
|
+
OR NOT (foundation ? 'granularity')
|
|
297
|
+
OR NOT (foundation ? 'measurementMethod')
|
|
298
|
+
OR jsonb_typeof(foundation -> 'subject') <> 'string'
|
|
299
|
+
OR jsonb_typeof(foundation -> 'valueKind') <> 'string'
|
|
300
|
+
OR jsonb_typeof(foundation -> 'aggregation') <> 'string'
|
|
301
|
+
OR jsonb_typeof(foundation -> 'granularity') <> 'string'
|
|
302
|
+
OR jsonb_typeof(foundation -> 'measurementMethod') <> 'string' THEN
|
|
303
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_VARIABLE_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
304
|
+
USING ERRCODE = 'check_violation';
|
|
305
|
+
END IF;
|
|
306
|
+
ELSIF p_entity_type = 'model' THEN
|
|
307
|
+
IF draft_candidate THEN
|
|
308
|
+
IF NOT (foundation ? 'epistemicState')
|
|
309
|
+
OR jsonb_typeof(foundation -> 'epistemicState') IS DISTINCT FROM 'string'
|
|
310
|
+
OR ((foundation ? 'inputVariableRefs') AND jsonb_typeof(foundation -> 'inputVariableRefs') IS DISTINCT FROM 'array')
|
|
311
|
+
OR ((foundation ? 'outputVariableRefs') AND jsonb_typeof(foundation -> 'outputVariableRefs') IS DISTINCT FROM 'array')
|
|
312
|
+
OR ((foundation ? 'applicability') AND jsonb_typeof(foundation -> 'applicability') IS DISTINCT FROM 'object')
|
|
313
|
+
OR ((foundation ? 'relationship') AND jsonb_typeof(foundation -> 'relationship') IS DISTINCT FROM 'string')
|
|
314
|
+
OR ((foundation ? 'uncertainty') AND jsonb_typeof(foundation -> 'uncertainty') IS DISTINCT FROM 'string')
|
|
315
|
+
OR ((foundation ? 'validationState') AND jsonb_typeof(foundation -> 'validationState') IS DISTINCT FROM 'string') THEN
|
|
316
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_MODEL_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
317
|
+
USING ERRCODE = 'check_violation';
|
|
318
|
+
END IF;
|
|
319
|
+
ELSIF NOT (foundation ? 'epistemicState')
|
|
320
|
+
OR NOT (foundation ? 'inputVariableRefs')
|
|
321
|
+
OR NOT (foundation ? 'outputVariableRefs')
|
|
322
|
+
OR NOT (foundation ? 'applicability')
|
|
323
|
+
OR NOT (foundation ? 'relationship')
|
|
324
|
+
OR NOT (foundation ? 'uncertainty')
|
|
325
|
+
OR NOT (foundation ? 'validationState')
|
|
326
|
+
OR jsonb_typeof(foundation -> 'epistemicState') <> 'string'
|
|
327
|
+
OR jsonb_typeof(foundation -> 'inputVariableRefs') <> 'array'
|
|
328
|
+
OR jsonb_typeof(foundation -> 'outputVariableRefs') <> 'array'
|
|
329
|
+
OR jsonb_typeof(foundation -> 'applicability') <> 'object'
|
|
330
|
+
OR jsonb_typeof(foundation -> 'relationship') <> 'string'
|
|
331
|
+
OR jsonb_typeof(foundation -> 'uncertainty') <> 'string'
|
|
332
|
+
OR jsonb_typeof(foundation -> 'validationState') <> 'string' THEN
|
|
333
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_MODEL_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
334
|
+
USING ERRCODE = 'check_violation';
|
|
335
|
+
END IF;
|
|
336
|
+
ELSIF p_entity_type = 'constraint' THEN
|
|
337
|
+
IF draft_candidate THEN
|
|
338
|
+
IF ((foundation ? 'condition') AND jsonb_typeof(foundation -> 'condition') IS DISTINCT FROM 'string')
|
|
339
|
+
OR ((foundation ? 'appliesTo') AND jsonb_typeof(foundation -> 'appliesTo') IS DISTINCT FROM 'array')
|
|
340
|
+
OR ((foundation ? 'exceptions') AND jsonb_typeof(foundation -> 'exceptions') IS DISTINCT FROM 'array')
|
|
341
|
+
OR ((foundation ? 'adoptionBasis') AND jsonb_typeof(foundation -> 'adoptionBasis') IS DISTINCT FROM 'array') THEN
|
|
342
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_CONSTRAINT_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
343
|
+
USING ERRCODE = 'check_violation';
|
|
344
|
+
END IF;
|
|
345
|
+
ELSIF NOT (foundation ? 'condition')
|
|
346
|
+
OR NOT (foundation ? 'appliesTo')
|
|
347
|
+
OR NOT (foundation ? 'exceptions')
|
|
348
|
+
OR NOT (foundation ? 'adoptionBasis')
|
|
349
|
+
OR jsonb_typeof(foundation -> 'condition') <> 'string'
|
|
350
|
+
OR jsonb_typeof(foundation -> 'appliesTo') <> 'array'
|
|
351
|
+
OR jsonb_typeof(foundation -> 'exceptions') <> 'array'
|
|
352
|
+
OR jsonb_typeof(foundation -> 'adoptionBasis') <> 'array' THEN
|
|
353
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_CONSTRAINT_FIELDS_INVALID: %/%', p_entity_type, p_entity_id
|
|
354
|
+
USING ERRCODE = 'check_violation';
|
|
355
|
+
END IF;
|
|
356
|
+
END IF;
|
|
357
|
+
END;
|
|
358
|
+
$assert_graph_foundation_payload$;
|
|
359
|
+
|
|
360
|
+
CREATE OR REPLACE FUNCTION public.guard_graph_foundation_revision_mutation()
|
|
361
|
+
RETURNS trigger
|
|
362
|
+
LANGUAGE plpgsql
|
|
363
|
+
SECURITY DEFINER
|
|
364
|
+
SET search_path = pg_catalog, public
|
|
365
|
+
AS $guard_graph_foundation_revision_mutation$
|
|
366
|
+
DECLARE
|
|
367
|
+
nonce_value text;
|
|
368
|
+
BEGIN
|
|
369
|
+
IF TG_OP <> 'INSERT' THEN
|
|
370
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_APPEND_ONLY: % is forbidden', TG_OP
|
|
371
|
+
USING ERRCODE = 'insufficient_privilege';
|
|
372
|
+
END IF;
|
|
373
|
+
|
|
374
|
+
nonce_value := current_setting('graph.foundation_capture_nonce', true);
|
|
375
|
+
IF nonce_value IS NULL OR nonce_value = ''
|
|
376
|
+
OR NOT EXISTS (
|
|
377
|
+
SELECT 1
|
|
378
|
+
FROM public.graph_foundation_capture_nonces AS nonce
|
|
379
|
+
WHERE nonce.nonce = nonce_value
|
|
380
|
+
AND nonce.transaction_id = txid_current()
|
|
381
|
+
AND nonce.backend_pid = pg_backend_pid()
|
|
382
|
+
) THEN
|
|
383
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_DIRECT_INSERT_FORBIDDEN'
|
|
384
|
+
USING ERRCODE = 'insufficient_privilege';
|
|
385
|
+
END IF;
|
|
386
|
+
|
|
387
|
+
RETURN NEW;
|
|
388
|
+
END;
|
|
389
|
+
$guard_graph_foundation_revision_mutation$;
|
|
390
|
+
|
|
391
|
+
CREATE OR REPLACE FUNCTION public.append_graph_foundation_revision(
|
|
392
|
+
p_entity_id text,
|
|
393
|
+
p_entity_type text,
|
|
394
|
+
p_revision text,
|
|
395
|
+
p_payload jsonb,
|
|
396
|
+
p_project_id text,
|
|
397
|
+
p_role_min text,
|
|
398
|
+
p_sensitivity text,
|
|
399
|
+
p_lifecycle_status text,
|
|
400
|
+
p_allow_migration_initial boolean DEFAULT false
|
|
401
|
+
)
|
|
402
|
+
RETURNS void
|
|
403
|
+
LANGUAGE plpgsql
|
|
404
|
+
SECURITY DEFINER
|
|
405
|
+
SET search_path = pg_catalog, public
|
|
406
|
+
AS $append_graph_foundation_revision$
|
|
407
|
+
DECLARE
|
|
408
|
+
nonce_value text;
|
|
409
|
+
previous_revision numeric;
|
|
410
|
+
expected_revision numeric;
|
|
411
|
+
saved_digest text;
|
|
412
|
+
BEGIN
|
|
413
|
+
IF p_entity_type NOT IN ('objective', 'variable', 'model', 'constraint', 'philosophy') THEN
|
|
414
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_INVALID_ENTITY_TYPE: %', p_entity_type
|
|
415
|
+
USING ERRCODE = 'check_violation';
|
|
416
|
+
END IF;
|
|
417
|
+
|
|
418
|
+
IF p_entity_type = 'philosophy' THEN
|
|
419
|
+
PERFORM public.assert_graph_foundation_payload(p_entity_id, p_entity_type, p_payload);
|
|
420
|
+
ELSE
|
|
421
|
+
PERFORM public.assert_graph_foundation_payload(p_entity_id, p_entity_type, p_payload);
|
|
422
|
+
IF p_revision IS NULL OR p_revision !~ '^[1-9][0-9]*$' THEN
|
|
423
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_FOUNDATION_REVISION_INVALID: %/%', p_entity_type, p_entity_id
|
|
424
|
+
USING ERRCODE = 'check_violation';
|
|
425
|
+
END IF;
|
|
426
|
+
END IF;
|
|
427
|
+
|
|
428
|
+
saved_digest := public.graph_foundation_storage_digest(p_payload);
|
|
429
|
+
|
|
430
|
+
SELECT max(history.revision::numeric)
|
|
431
|
+
INTO previous_revision
|
|
432
|
+
FROM public.graph_foundation_revisions AS history
|
|
433
|
+
WHERE history.entity_id = p_entity_id
|
|
434
|
+
AND history.entity_type = p_entity_type;
|
|
435
|
+
|
|
436
|
+
IF p_entity_type = 'philosophy' THEN
|
|
437
|
+
expected_revision := coalesce(previous_revision, 0) + 1;
|
|
438
|
+
p_revision := expected_revision::text;
|
|
439
|
+
ELSE
|
|
440
|
+
expected_revision := coalesce(previous_revision, 0) + 1;
|
|
441
|
+
IF previous_revision IS NULL AND p_allow_migration_initial THEN
|
|
442
|
+
expected_revision := p_revision::numeric;
|
|
443
|
+
ELSIF p_revision::numeric <> expected_revision THEN
|
|
444
|
+
RAISE EXCEPTION
|
|
445
|
+
'GRAPH_FOUNDATION_HISTORY_REVISION_SEQUENCE: %/% expected %, got %',
|
|
446
|
+
p_entity_type, p_entity_id, expected_revision::text, p_revision
|
|
447
|
+
USING ERRCODE = 'check_violation';
|
|
448
|
+
END IF;
|
|
449
|
+
END IF;
|
|
450
|
+
|
|
451
|
+
nonce_value := md5(
|
|
452
|
+
clock_timestamp()::text || ':' || txid_current()::text || ':' ||
|
|
453
|
+
pg_backend_pid()::text || ':' || random()::text
|
|
454
|
+
);
|
|
455
|
+
INSERT INTO public.graph_foundation_capture_nonces (nonce, transaction_id, backend_pid)
|
|
456
|
+
VALUES (nonce_value, txid_current(), pg_backend_pid());
|
|
457
|
+
PERFORM set_config('graph.foundation_capture_nonce', nonce_value, true);
|
|
458
|
+
|
|
459
|
+
BEGIN
|
|
460
|
+
INSERT INTO public.graph_foundation_revisions (
|
|
461
|
+
entity_id,
|
|
462
|
+
entity_type,
|
|
463
|
+
revision,
|
|
464
|
+
payload,
|
|
465
|
+
project_id,
|
|
466
|
+
role_min,
|
|
467
|
+
sensitivity,
|
|
468
|
+
lifecycle_status,
|
|
469
|
+
storage_digest
|
|
470
|
+
) VALUES (
|
|
471
|
+
p_entity_id,
|
|
472
|
+
p_entity_type,
|
|
473
|
+
p_revision,
|
|
474
|
+
p_payload,
|
|
475
|
+
p_project_id,
|
|
476
|
+
p_role_min,
|
|
477
|
+
p_sensitivity,
|
|
478
|
+
p_lifecycle_status,
|
|
479
|
+
saved_digest
|
|
480
|
+
);
|
|
481
|
+
EXCEPTION WHEN OTHERS THEN
|
|
482
|
+
PERFORM set_config('graph.foundation_capture_nonce', '', true);
|
|
483
|
+
DELETE FROM public.graph_foundation_capture_nonces WHERE nonce = nonce_value;
|
|
484
|
+
RAISE;
|
|
485
|
+
END;
|
|
486
|
+
|
|
487
|
+
PERFORM set_config('graph.foundation_capture_nonce', '', true);
|
|
488
|
+
DELETE FROM public.graph_foundation_capture_nonces WHERE nonce = nonce_value;
|
|
489
|
+
END;
|
|
490
|
+
$append_graph_foundation_revision$;
|
|
491
|
+
|
|
492
|
+
REVOKE ALL ON FUNCTION public.append_graph_foundation_revision(
|
|
493
|
+
text, text, text, jsonb, text, text, text, text, boolean
|
|
494
|
+
) FROM PUBLIC;
|
|
495
|
+
|
|
496
|
+
CREATE OR REPLACE FUNCTION public.capture_graph_foundation_revision()
|
|
497
|
+
RETURNS trigger
|
|
498
|
+
LANGUAGE plpgsql
|
|
499
|
+
SECURITY DEFINER
|
|
500
|
+
SET search_path = pg_catalog, public
|
|
501
|
+
AS $capture_graph_foundation_revision$
|
|
502
|
+
BEGIN
|
|
503
|
+
IF TG_TABLE_SCHEMA <> 'public' OR TG_TABLE_NAME <> 'graph_entities'
|
|
504
|
+
OR TG_OP NOT IN ('INSERT', 'UPDATE') THEN
|
|
505
|
+
RAISE EXCEPTION 'GRAPH_FOUNDATION_HISTORY_TRIGGER_ONLY'
|
|
506
|
+
USING ERRCODE = 'insufficient_privilege';
|
|
507
|
+
END IF;
|
|
508
|
+
|
|
509
|
+
IF NEW.entity_type IN ('objective', 'variable', 'model', 'constraint', 'philosophy')
|
|
510
|
+
AND (
|
|
511
|
+
TG_OP = 'INSERT'
|
|
512
|
+
OR OLD.id IS DISTINCT FROM NEW.id
|
|
513
|
+
OR OLD.entity_type IS DISTINCT FROM NEW.entity_type
|
|
514
|
+
OR OLD.payload IS DISTINCT FROM NEW.payload
|
|
515
|
+
OR OLD.project_id IS DISTINCT FROM NEW.project_id
|
|
516
|
+
OR OLD.role_min IS DISTINCT FROM NEW.role_min
|
|
517
|
+
OR OLD.sensitivity IS DISTINCT FROM NEW.sensitivity
|
|
518
|
+
OR OLD.lifecycle_status IS DISTINCT FROM NEW.lifecycle_status
|
|
519
|
+
) THEN
|
|
520
|
+
IF NEW.entity_type = 'philosophy' THEN
|
|
521
|
+
PERFORM public.append_graph_foundation_revision(
|
|
522
|
+
NEW.id, NEW.entity_type, NULL, NEW.payload, NEW.project_id,
|
|
523
|
+
NEW.role_min, NEW.sensitivity, NEW.lifecycle_status, false
|
|
524
|
+
);
|
|
525
|
+
ELSE
|
|
526
|
+
PERFORM public.append_graph_foundation_revision(
|
|
527
|
+
NEW.id, NEW.entity_type, NEW.payload -> 'foundation' ->> 'revision', NEW.payload,
|
|
528
|
+
NEW.project_id, NEW.role_min, NEW.sensitivity, NEW.lifecycle_status, false
|
|
529
|
+
);
|
|
530
|
+
END IF;
|
|
531
|
+
END IF;
|
|
532
|
+
|
|
533
|
+
RETURN NEW;
|
|
534
|
+
END;
|
|
535
|
+
$capture_graph_foundation_revision$;
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
* The SECURITY DEFINER append helper must see every prior revision while it
|
|
539
|
+
* calculates max+1, including rows whose current Graph entity is inactive or
|
|
540
|
+
* deleted. Normalize this before the migration backfill below.
|
|
541
|
+
*/
|
|
542
|
+
ALTER TABLE public.graph_foundation_revisions ENABLE ROW LEVEL SECURITY;
|
|
543
|
+
ALTER TABLE public.graph_foundation_revisions NO FORCE ROW LEVEL SECURITY;
|
|
544
|
+
|
|
545
|
+
/* Recreate both guards so a partially applied prior migration cannot leave a gap. */
|
|
546
|
+
DROP TRIGGER IF EXISTS graph_foundation_revisions_guard
|
|
547
|
+
ON public.graph_foundation_revisions;
|
|
548
|
+
DROP TRIGGER IF EXISTS graph_foundation_revisions_truncate_guard
|
|
549
|
+
ON public.graph_foundation_revisions;
|
|
550
|
+
CREATE TRIGGER graph_foundation_revisions_guard
|
|
551
|
+
BEFORE INSERT OR UPDATE OR DELETE ON public.graph_foundation_revisions
|
|
552
|
+
FOR EACH ROW EXECUTE FUNCTION public.guard_graph_foundation_revision_mutation();
|
|
553
|
+
CREATE TRIGGER graph_foundation_revisions_truncate_guard
|
|
554
|
+
BEFORE TRUNCATE ON public.graph_foundation_revisions
|
|
555
|
+
FOR EACH STATEMENT EXECUTE FUNCTION public.guard_graph_foundation_revision_mutation();
|
|
556
|
+
|
|
557
|
+
/* Existing graph rows are captured once. No pre-migration history is inferred. */
|
|
558
|
+
SELECT public.append_graph_foundation_revision(
|
|
559
|
+
graph.id,
|
|
560
|
+
graph.entity_type,
|
|
561
|
+
CASE WHEN graph.entity_type = 'philosophy'
|
|
562
|
+
THEN NULL
|
|
563
|
+
ELSE graph.payload -> 'foundation' ->> 'revision'
|
|
564
|
+
END,
|
|
565
|
+
graph.payload,
|
|
566
|
+
graph.project_id,
|
|
567
|
+
graph.role_min,
|
|
568
|
+
graph.sensitivity,
|
|
569
|
+
graph.lifecycle_status,
|
|
570
|
+
true
|
|
571
|
+
)
|
|
572
|
+
FROM public.graph_entities AS graph
|
|
573
|
+
WHERE graph.entity_type IN ('objective', 'variable', 'model', 'constraint', 'philosophy')
|
|
574
|
+
AND NOT EXISTS (
|
|
575
|
+
SELECT 1
|
|
576
|
+
FROM public.graph_foundation_revisions AS history
|
|
577
|
+
WHERE history.entity_id = graph.id
|
|
578
|
+
AND history.entity_type = graph.entity_type
|
|
579
|
+
AND history.payload IS NOT DISTINCT FROM graph.payload
|
|
580
|
+
AND history.project_id IS NOT DISTINCT FROM graph.project_id
|
|
581
|
+
AND history.role_min IS NOT DISTINCT FROM graph.role_min
|
|
582
|
+
AND history.sensitivity IS NOT DISTINCT FROM graph.sensitivity
|
|
583
|
+
AND history.lifecycle_status IS NOT DISTINCT FROM graph.lifecycle_status
|
|
584
|
+
AND history.storage_digest = public.graph_foundation_storage_digest(graph.payload)
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
DROP TRIGGER IF EXISTS graph_entities_foundation_history_capture
|
|
588
|
+
ON public.graph_entities;
|
|
589
|
+
CREATE TRIGGER graph_entities_foundation_history_capture
|
|
590
|
+
AFTER INSERT OR UPDATE ON public.graph_entities
|
|
591
|
+
FOR EACH ROW EXECUTE FUNCTION public.capture_graph_foundation_revision();
|
|
592
|
+
|
|
593
|
+
DROP POLICY IF EXISTS graph_foundation_revisions_current_graph_read
|
|
594
|
+
ON public.graph_foundation_revisions;
|
|
595
|
+
CREATE POLICY graph_foundation_revisions_current_graph_read
|
|
596
|
+
ON public.graph_foundation_revisions
|
|
597
|
+
FOR SELECT
|
|
598
|
+
USING (
|
|
599
|
+
storage_digest = public.graph_foundation_storage_digest(payload)
|
|
600
|
+
AND EXISTS (
|
|
601
|
+
SELECT 1
|
|
602
|
+
FROM public.graph_entities AS current_graph
|
|
603
|
+
WHERE current_graph.id = graph_foundation_revisions.entity_id
|
|
604
|
+
AND current_graph.entity_type = graph_foundation_revisions.entity_type
|
|
605
|
+
AND current_graph.lifecycle_status = 'active'
|
|
606
|
+
)
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
/*
|
|
610
|
+
* brainbase_app is the canonical host runtime role. Keep this conditional so
|
|
611
|
+
* local/OSS installs that use another role do not fail during migration; those
|
|
612
|
+
* deployments must grant SELECT explicitly alongside their graph_entities
|
|
613
|
+
* reader grant. This is intentionally SELECT-only: capture runs through the
|
|
614
|
+
* SECURITY DEFINER trigger and runtime roles never receive history writes.
|
|
615
|
+
*/
|
|
616
|
+
DO $graph_history_runtime_grant$
|
|
617
|
+
BEGIN
|
|
618
|
+
IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'brainbase_app') THEN
|
|
619
|
+
REVOKE ALL ON TABLE public.graph_foundation_revisions FROM brainbase_app;
|
|
620
|
+
GRANT SELECT ON TABLE public.graph_foundation_revisions TO brainbase_app;
|
|
621
|
+
REVOKE ALL ON FUNCTION public.append_graph_foundation_revision(
|
|
622
|
+
text, text, text, jsonb, text, text, text, text, boolean
|
|
623
|
+
) FROM brainbase_app;
|
|
624
|
+
END IF;
|
|
625
|
+
END;
|
|
626
|
+
$graph_history_runtime_grant$;
|
|
627
|
+
|
|
628
|
+
/*
|
|
629
|
+
* Stable host readback bindings:
|
|
630
|
+
* graph_entities_foundation_history_capture (AFTER INSERT OR UPDATE)
|
|
631
|
+
* graph_foundation_revisions_guard (BEFORE INSERT OR UPDATE OR DELETE)
|
|
632
|
+
* graph_foundation_revisions_truncate_guard (BEFORE TRUNCATE)
|
|
633
|
+
* graph_foundation_storage_digest(jsonb)
|
|
634
|
+
*/
|