KB-2DF6

02 — Root Cause Classification

4 min read Revision 1
dieu44dieu39root-causecontract-gapverify-mark-bug

02 — Root Cause Classification

root_cause:
  primary:
    class: contract_gap_between_MARK_VERIFY_CUT
    detail: |
      fn_cut_mark_staged_file (operational wrapper) validated only
      content_text and canonical_address per piece (added in mig 053).
      It did NOT validate source_position, piece_role, section_type,
      or local_piece_id — fields that fn_iu_verify_mark Axis A
      (dense source_position) and Axis B (piece_role/section_type
      non-null) require, and that fn_iu_op_cut downstream needs to
      build addressable IUs.
      Result: a manifest with only {content_text, canonical_address,
      section_type, piece_index} fields was accepted and reached
      status='marked'. VERIFY_MARK was then guaranteed to reject —
      but the rejection was masked by a secondary bug (below).

  secondary:
    class: verify_error_handling_bug
    detail: |
      fn_iu_verify_mark used `v_problems := v_problems || 'literal'`
      where v_problems is text[]. PostgreSQL operator resolution
      picked array_concat(text[], text[]) over array_append(text[], text),
      casting the bare string literal to text[]. That cast requires the
      string to be in PG array-literal form `{...}`, so it raised
      `malformed array literal: "Axis B: piece_role or section_type
      missing on at least one piece"` from inside the verify function,
      surfacing as a PL/pgSQL hard error instead of a structured
      `{ok:false, verdict:rejected, problems:[...]}` JSON response.
      The Axis A line escaped this bug because its expression
      `'literal' || v_min || 'literal' || ...` resolves to text, not unknown.

  tertiary:
    class: wrapper_validation_incomplete
    detail: |
      fn_iu_op_mark_file (alias) is a pure pass-through — it embeds
      whatever pieces the caller hands it into the manifest. The contract
      gate therefore has to live in fn_cut_mark_staged_file (the
      operational wrapper above the alias) or earlier in the caller.
      Since the alias contract is governance-locked (alias body md5 is
      pinned across packs), the right place is the operational wrapper.

  not_root:
    DOT_copy:
      verdict: not_root
      evidence: |
        COPY_TO_CUT_ZONE produced source_hash a732962665691c620a050265de246050
        and source_bytes 23394 deterministically. The fix re-marked from
        the same source_copy payload (no new copy) and produced a valid
        manifest. The copy was always correct.
    document_complexity:
      verdict: not_root
      evidence: |
        Điều 39 is 23 KB / 16 sections — well within the size envelope
        already passing for Điều 37 (17 pieces) and Điều 38 (8 pieces).
        The same source body produced a valid v1 manifest once the
        caller emitted the required fields.
    Codex_execution:
      verdict: contributing_but_not_root
      evidence: |
        The Codex caller emitted incomplete pieces. But Codex cannot be
        expected to enforce a contract that the boundary does not
        publish or check. With the boundary now enforced, future Codex
        invocations are guided by structured RAISE messages naming
        cut_manifest_piece_schema_v1 — the system is self-correcting.

Why the two-bug interaction matters

Either bug alone would have been noisier and easier to catch:

  • If MARK had validated full schema, the caller would have failed at MARK with a clear piece[N].source_position is required message and the operator would have re-issued.
  • If verify had returned a structured verdict on the missing fields, the operator would have seen Axis A/B failed and known the manifest needed regeneration.

Together, MARK silently accepted the bad manifest, advanced the cut_request to marked, and verify_mark blew up with a cryptic malformed array literal — which reads like a verify bug, not a contract gap. This pack closes both ends.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-cut-dieu39-verify-mark-root-cause-and-contract-fix/02-root-cause-classification.md