Skip to content

Commit 03b3ba2

Browse files
authored
Merge pull request #292 from Blazity/fix/aiw-245-carry-schema-drift
fix(worker): detect and resync drifted embedded carry schemas in stored definitions (AIW-245)
2 parents 60154ec + b2a7e8b commit 03b3ba2

10 files changed

Lines changed: 8833 additions & 12 deletions
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
CREATE TABLE "carry_schema_resync_audit" (
2+
"definition_id" integer NOT NULL,
3+
"version" integer NOT NULL,
4+
"node_index" integer NOT NULL,
5+
"node_id" text,
6+
"carry_index" integer NOT NULL,
7+
"source_key" text NOT NULL,
8+
"before_schema" jsonb NOT NULL,
9+
"applied_at" timestamp with time zone DEFAULT now() NOT NULL,
10+
CONSTRAINT "carry_schema_resync_audit_definition_id_version_node_index_carry_index_pk" PRIMARY KEY("definition_id","version","node_index","carry_index")
11+
);
12+
--> statement-breakpoint
13+
-- >>> AIW-245 carry schema resync data migration (generated below; do not hand-edit) <<<
14+
-- Re-syncs code-owned JSON schemas embedded BY VALUE in a stored definition's
15+
-- loop carry (configuration.carry; loops are schema-version 2) with the current
16+
-- constants in apps/shared/contracts. A run never reads the constant: the
17+
-- definition froze a copy when it was saved, and when the constant changed shape
18+
-- ("critical"|"suggestion" -> "Blocker"|"High"|"Medium"|"Nit") every stored copy
19+
-- went stale and its definition began failing validation with no migration
20+
-- having touched it. That is AIW-245.
21+
--
22+
-- Guard: there is NO authorship marker inside a definition JSON. So a carry
23+
-- schema is rewritten ONLY when it byte-matches (jsonb =) a KNOWN PRIOR platform
24+
-- shape. Value alone still cannot prove the copy was the platform's rather than a
25+
-- customer step output of the same shape, so BEFORE rewriting, each matched carry
26+
-- is recorded in carry_schema_resync_audit (coordinate + before-value) -- the
27+
-- INSERT is ON CONFLICT DO NOTHING and the UPDATE is a strict no-op once the copy
28+
-- is current, so a re-run captures and changes nothing. An operator can read the
29+
-- audit for the exact rows changed and revert from before_schema.
30+
--
31+
-- Every reachable version snapshot is corrected, not just the deployed one: the
32+
-- statements have no version filter. Each is standalone (no explicit
33+
-- transaction: neon-http has none) and guards every jsonb_array_elements against
34+
-- a non-array so one malformed row cannot abort the whole migration.
35+
--
36+
-- Generated; do not hand-edit the shapes. Regenerate with
37+
-- scripts/generate-carry-schema-resync-migration.ts (see its header).
38+
INSERT INTO "carry_schema_resync_audit"
39+
("definition_id", "version", "node_index", "node_id", "carry_index", "source_key", "before_schema")
40+
SELECT
41+
"v"."definition_id",
42+
"v"."version",
43+
("node_ord" - 1)::int,
44+
"node"->>'id',
45+
("carry_ord" - 1)::int,
46+
'review_result',
47+
"carry"->'schema'
48+
FROM "workflow_definition_versions" AS "v"
49+
CROSS JOIN LATERAL jsonb_array_elements(
50+
CASE WHEN jsonb_typeof("v"."definition"->'nodes') = 'array' THEN "v"."definition"->'nodes' ELSE '[]'::jsonb END
51+
) WITH ORDINALITY AS "n"("node", "node_ord")
52+
CROSS JOIN LATERAL jsonb_array_elements(
53+
CASE WHEN jsonb_typeof("node"->'configuration'->'carry') = 'array' THEN "node"->'configuration'->'carry' ELSE '[]'::jsonb END
54+
) WITH ORDINALITY AS "c"("carry", "carry_ord")
55+
WHERE "carry"->'schema' IN ($aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["critical","suggestion"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb, $aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["Blocker","High","Medium","Nit"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb)
56+
ON CONFLICT ("definition_id", "version", "node_index", "carry_index") DO NOTHING;
57+
--> statement-breakpoint
58+
UPDATE "workflow_definition_versions" AS "v"
59+
SET "definition" = jsonb_set(
60+
"v"."definition",
61+
'{nodes}',
62+
COALESCE((
63+
SELECT jsonb_agg("rewritten_node" ORDER BY "node_ord")
64+
FROM (
65+
SELECT
66+
CASE
67+
WHEN jsonb_typeof("node"->'configuration'->'carry') = 'array'
68+
THEN jsonb_set(
69+
"node",
70+
'{configuration,carry}',
71+
COALESCE((
72+
SELECT jsonb_agg("rewritten_carry" ORDER BY "carry_ord")
73+
FROM (
74+
SELECT
75+
CASE
76+
WHEN "carry"->'schema' IN ($aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["critical","suggestion"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb, $aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["Blocker","High","Medium","Nit"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb)
77+
THEN jsonb_set("carry", '{schema}', $aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"repo":{"type":"string"},"severity":{"enum":["Blocker","High","Medium","Nit"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb)
78+
ELSE "carry"
79+
END AS "rewritten_carry",
80+
"carry_ord"
81+
FROM jsonb_array_elements("node"->'configuration'->'carry')
82+
WITH ORDINALITY AS "c"("carry", "carry_ord")
83+
) AS "carries"
84+
), '[]'::jsonb)
85+
)
86+
ELSE "node"
87+
END AS "rewritten_node",
88+
"node_ord"
89+
FROM jsonb_array_elements(
90+
CASE WHEN jsonb_typeof("v"."definition"->'nodes') = 'array' THEN "v"."definition"->'nodes' ELSE '[]'::jsonb END
91+
) WITH ORDINALITY AS "n"("node", "node_ord")
92+
) AS "nodes"
93+
), "v"."definition"->'nodes')
94+
)
95+
WHERE EXISTS (
96+
SELECT 1
97+
FROM jsonb_array_elements(
98+
CASE WHEN jsonb_typeof("v"."definition"->'nodes') = 'array' THEN "v"."definition"->'nodes' ELSE '[]'::jsonb END
99+
) AS "node"
100+
CROSS JOIN LATERAL jsonb_array_elements(
101+
CASE WHEN jsonb_typeof("node"->'configuration'->'carry') = 'array' THEN "node"->'configuration'->'carry' ELSE '[]'::jsonb END
102+
) AS "carry"
103+
WHERE "carry"->'schema' IN ($aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["critical","suggestion"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb, $aiw_carry_resync${"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":true,"properties":{"decision":{"enum":["approve","request_changes"],"type":"string"},"feedback":{"type":"string"},"findings":{"items":{"additionalProperties":true,"properties":{"description":{"type":"string"},"endLine":{"type":"number"},"file":{"type":"string"},"severity":{"enum":["Blocker","High","Medium","Nit"],"type":"string"},"startLine":{"type":"number"}},"required":["file","description","severity"],"type":"object"},"type":"array"}},"required":["decision","findings"],"type":"object"}$aiw_carry_resync$::jsonb)
104+
);

0 commit comments

Comments
 (0)