KB-4780
04 — Function fixes (mig 054)
5 min read Revision 1
dieu44dieu39mig-054function-fix
04 — Function fixes (mig 054)
Single TX, COMMITTED 2026-05-27 02:51 UTC. File: /tmp/mig_054_dieu39_verify_mark_root_cause_fix.sql.
Fix 1 — fn_iu_verify_mark
| before | after | |
|---|---|---|
| md5 | 923263c84d5b37070eaa0fc8f9017bb7 |
04e5191c430a142712bfe63089863d44 |
Patch summary
- Bug:
v_problems := v_problems || 'literal'— PG resolved this astext[] || 'literal'::text[], requiring{...}array-literal syntax, raisedmalformed array literaland aborted. - Fix: every bare string literal on the right of
||is wrapped asARRAY['…'](5 sites:manifest.pieces missing or empty, Axis A/B/C messages,coverage_proof…,manifest_digest is not 32-hex). - Hardening: Axis A now pre-checks
source_positionis a non-negative-integer string before casting; if any piece has a missing or malformedsource_position, it emits"Axis A: source_position missing or non-integer on at least one piece"instead of raising in(p->>'source_position')::int. - Hardening: Axis B now also rejects empty/whitespace
piece_roleandsection_type(previously onlyIS NULL). - Preserved: lifecycle/approval guards,
dot_iu_command_runaudit insert,manifest_digest32-hex check,coverage_proof.covered_bytes = manifest.source_bytescheck, signature and return shape.
Fix 2 + 3 — fn_cut_mark_staged_file
| before | after | |
|---|---|---|
| md5 | 0a6feadddc8f70efe5c35d6b252167d2 |
67721b42a55315858e3c377654c2a5b1 |
Patch summary
- Schema gate (Fix 2): per-piece validation block now enforces
cut_manifest_piece_schema_v1BEFORE any state transition. New checks:local_piece_idnon-empty + unique-within-manifest,source_positioninteger-like and >= 1,piece_rolenon-empty,section_typenon-empty AND present inpublic.dot_configasvocab.section_type.<value>. Existing mig 053 checks (content_text,canonical_address) preserved. - Re-mark path (Fix 3): status precondition relaxed from
= 'copied'toIN ('copied','mark_rejected'). Both transitions remain→ mark_in_progress → marked, both legal underfn_cut_request_transitionstate machine. - Idempotency:
p_idempotency_keynow includesmd5(p_pieces::text)so a re-mark with different pieces yields a fresh manifest record (no idempotent reuse of stale manifest). - Forensics: result JSON now returns
piece_schema_validated: 'cut_manifest_piece_schema_v1'; transition metadata stampspiece_schema='cut_manifest_piece_schema_v1'andfrom_status_was=<prior status>. - Unchanged: source_copy read path, alias call (
fn_iu_op_mark_filebody md5ffaa47fff7a906d93060141661080cd4untouched),cut_request_signal('cut.mark', …), signature, return-shape additive only.
Refusal messages (operator-readable)
fn_cut_mark_staged_file: piece[%].local_piece_id is required (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].local_piece_id % is duplicated (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].content_text is required (would cause "body required" at CUT)
fn_cut_mark_staged_file: piece[%].canonical_address is required (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].source_position must be a non-negative integer (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].source_position must be >= 1 (got %) (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].piece_role is required (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].section_type is required (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: piece[%].section_type % not in dot_config vocab.section_type.* (cut_manifest_piece_schema_v1)
fn_cut_mark_staged_file: cannot mark from status % — must be 'copied' or 'mark_rejected' (re-mark path)
Rollback
-- Restores prior bodies; preserved in /tmp/mig_054_*.sql diff against pg_proc bodies
-- captured pre-apply with md5 923263c8… (verify) and 0a6feadd… (mark).
-- Single TX: BEGIN; CREATE OR REPLACE … (paste prior bodies) … ; COMMIT;
The prior bodies are reproducible from the pre-fix pg_dump (/tmp/pre_dieu39_verify_mark_fix_20260527_094407.dump) via pg_restore --schema-only and selection of the two function definitions.