KB-4876

00 — IU CUT Điều 39 VERIFY_MARK Root Cause + Contract Fix — Summary

6 min read Revision 1
dieu44iu-cutdieu39verify-markcontract-fixv0.6pass

00 — IU CUT Điều 39 VERIFY_MARK Root Cause + Contract Fix

Pack: IU_CUT_DIEU39_VERIFY_MARK_ROOT_CAUSE_AND_CONTRACT_FIX_PASS Date: 2026-05-27 Channel: local CC → ssh contabo → docker exec postgres → psql -U workflow_admin -d directus Result: PASS

Headline

The Điều 39 VERIFY_MARK failure had two compounding root causes, both now fixed at the contract level:

  1. MARK contract gap (primary)fn_cut_mark_staged_file validated only content_text and canonical_address, allowing manifests missing source_position, piece_role, local_piece_id to reach status='marked'. The Codex caller for Điều 39 produced pieces with only piece_index, section_type, content_text, canonical_address — and MARK accepted them silently.
  2. VERIFY_MARK error handling bug (secondary)fn_iu_verify_mark appended bare string literals to a text[] (v_problems := v_problems || 'literal'). PostgreSQL resolved this as text[] || 'literal'::text[], requiring {...} array-literal syntax, so the function raised malformed array literal: "Axis B: ..." instead of returning a structured failed verdict.

Both fixes shipped together in mig 054 (single TX, COMMITTED). Re-mark of Điều 39 against the corrected contract passed all 3 axes with verdict approved.

Live state at exit

key value
cut_request_id 146f1520-aaa2-4bda-af2c-06a8f76cd36a
cut_request.status marked (re-marked under v1 schema)
manifest_staging_record_id 9fa4685e-d35a-45d4-aee7-aa2836785ca5 (new)
manifest_digest aded6af91fb9643fb2ea99ff024a1ede (new)
pieces_count 16
cut_manifest_piece_schema_v1 fields 16/16 each (local_piece_id, content_text, canonical_address, source_position, piece_role, section_type)
verify_mark preview verdict=approved, axis_a_ok=true, axis_b_ok=true, axis_c_ok=true
Prior bad staging record 3d9d0388-…lifecycle_status=rejected (orphaned, kept for audit)
cut_run_id NULL (no CUT was run — strict non-goal honored)
Backups pre 84,084,948 B / post 84,104,933 B (Δ +19,985 B)
5/5 MARK/CUT alias body md5 UNCHANGED
Gates at exit job_substrate=false, composer=false, heartbeat=true (untouched)

What changed (durable)

  • public.fn_iu_verify_marktext[] || ARRAY['...'] everywhere; added Axis A pre-check that surfaces non-integer source_position as a structured problem rather than raising in the int cast. New md5 04e5191c430a142712bfe63089863d44.
  • public.fn_cut_mark_staged_file — added cut_manifest_piece_schema_v1 validation block before status transitions; relaxed status precondition to accept {copied, mark_rejected} for the re-mark path; idempotency key now includes md5(p_pieces::text) so a re-mark with different pieces yields a new manifest record. New md5 67721b42a55315858e3c377654c2a5b1.

Strict non-goals honored

  • No CUT, no VERIFY_CUT, no COMPLETE.
  • No Qdrant touch, no production_documents touch (table absent).
  • No pg_cron.
  • No worker started.
  • No manual jsonb_set patch on iu_staging_payload.payload_json.pieces (the prior recovery pattern from [[feedback-mark-pieces-live-in-iu-staging-payload-cut-manifest-not-in-iu-staging-record-metadata]] was explicitly avoided — root cause fixed instead).
  • No MARK/CUT alias contract rewrite (5/5 alias body md5 unchanged).
  • Điều 45 untouched.

Report index

# File
00 00-summary.md (this file)
01 01-hard-gate-baseline-backup.md
02 02-root-cause-classification.md
03 03-cut-manifest-piece-schema-v1.md
04 04-function-fixes.md
05 05-dieu39-rerun-mark-result.md
06 06-dieu39-rerun-verify-mark-result.md
07 07-regression-safety.md
08 08-next-step-cut-approval.md

Carry-forward

  • CF-1 — Approval gate: operator should call fn_cut_verify_mark(cut_request_id, p_approve:=true, p_approval_doc_id:='<doc>', p_approver:='<user>') to transition marked → mark_verified. Until then, the manifest stays at preview level.
  • CF-2fn_cut_verify_mark quirk: when p_approve=false is passed, the operator wrapper transitions the cut_request without first reading the structured verdict from fn_iu_op_verify_mark. Consider tying transition to actual verdict (or document the manual-override semantics).
  • CF-3 — Orphaned staging records: the rejected staging record 3d9d0388-… remains at lifecycle_status=rejected. Cleanup executor (already CF in [[project-iu-cut-operational-pipeline-runtime-hardening-pass-2026-05-27]]) should sweep these.
  • CF-4piece_role vocab: no vocab.piece_role.* entries exist in dot_config. Today only non-empty is enforced; consider defining the vocabulary (e.g., section_body, definition, clause).
  • CF-5 — Caller convergence: operational MARK callers (Codex/Agent) should adopt cut_manifest_piece_schema_v1 documented in 03-cut-manifest-piece-schema-v1.md to avoid silent rejects.
  • [[project-iu-cut-operational-pipeline-runtime-hardening-pass-2026-05-27]] — direct parent (added content_text/canonical_address validation in mig 053; this pack extends to full schema v1).
  • [[project-iu-cut-operational-pipeline-copy-mark-verify-cut-pass-2026-05-26]] — operational pipeline parent.
  • [[feedback-fn-cut-mark-staged-file-must-validate-piece-schema-upstream]] — now fully generalized from content_text to all schema-v1 fields.
  • [[feedback-mark-pieces-live-in-iu-staging-payload-cut-manifest-not-in-iu-staging-record-metadata]] — recovery pattern explicitly avoided; root cause fixed at MARK boundary instead.
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-cut-dieu39-verify-mark-root-cause-and-contract-fix/00-summary.md