KB-90A8

07 · Next batch cut test plan

7 min read Revision 1
dieu44iu_cutnext_packbatch_cutroadmap

07 · Next batch cut test plan

With Phase B (no jsonb_set workaround), Phase C (cut_pipeline_operator heartbeat), and Phase D (cut_request TTL dry-run) in place, the operational pipeline is ready for a controlled second-document cut to verify that batch behavior matches the Điều 38 pilot without manual recovery.

IU_CUT_BATCH_PILOT_2ND_DOCUMENT_DRY_RUN_FIRST — pick one Điều 37, 44, or 45-related document NOT yet cut, run the full REQUEST→COPY→MARK→VERIFY→CUT→VERIFY→COMPLETE pipeline, and verify:

  1. No body required raise. The Agent's piece array must include content_text and canonical_address per piece. If the Agent omits either, fn_cut_mark_staged_file refuses upstream with a per-index error — operators must NOT jsonb_set-patch; instead, they must regenerate pieces from the Agent.
  2. Heartbeat tick coverage. The operator process calls fn_cut_heartbeat_ping('cut_pipeline_operator', 'external_worker', 'ok', …) at the start of MARK, before VERIFY_MARK, before CUT, before VERIFY_CUT, and at COMPLETE — at least once per stage. The wrapper's audit-pin metadata becomes the trace.
  3. No false-heal. The iu_outbound_default row stays at last_tick_at = 2026-05-22 11:31:41, last_tick_status=warn. Phase 3C closure remains a separate carry-forward.
  4. TTL behavior is unchanged. After COMPLETE, the new cut_request gets cleanup_scheduled_at = completed_at + 15 days. fn_cut_cleanup_dry_run(15) continues to report 0 eligible until the first row passes its 15d post-schedule mark (Điều 38 row → 2026-06-25).

Pre-flight checklist (operator)

step command expected
Confirm baseline gates SELECT key,value FROM dot_config WHERE key LIKE 'queue.%' OR key='iu_core.composer_enabled' OR key='runtime.phase' substrate=false, heartbeat=true, dlq.replay=false, lease.reaper=false, composer=false, runtime.phase=phase2_governance
Confirm 6-alias md5 SELECT md5(string_agg(prosrc,E'\n' ORDER BY proname)) FROM pg_proc WHERE proname IN (6 alias names) 750b06b610f50065f1117961813d9df4
Confirm 3 new fns present \df fn_cut_heartbeat_ping fn_cut_cleanup_dry_run fn_cut_mark_staged_file all 3 exist
pg_dump pre-pilot pg_dump -Fc -f /tmp/pre_<pack>.dump succeeds

Pilot loop (per document)

step function invariant
1. Request fn_cut_request_add(source_ref, source_kind, requested_by) status=requested
2. Copy fn_cut_copy_to_staging(cut_request_id, source_path, actor) status=copied; source_copy payload present
3. Heartbeat fn_cut_heartbeat_ping('cut_pipeline_operator', 'external_worker', 'ok', {stage:'pre_mark', cut_request_id}) row ticks
4. Mark fn_cut_mark_staged_file(cut_request_id, p_pieces, actor) status=marked; piece_schema_validated=true
5. Heartbeat fn_cut_heartbeat_ping(…, {stage:'pre_verify_mark', …}) row ticks
6. Verify mark fn_cut_verify_mark(cut_request_id, true, approval_doc_id, approver, actor) status=mark_verified
7. Heartbeat fn_cut_heartbeat_ping(…, {stage:'pre_cut', …}) row ticks
8. Cut fn_cut_apply(cut_request_id, true, actor) status=cut_done; cut_run_id assigned; no body required raise
9. Heartbeat fn_cut_heartbeat_ping(…, {stage:'pre_verify_cut', …}) row ticks
10. Verify cut fn_cut_verify_cut(cut_request_id, actor) status=cut_verified; axes a/b/c=t; no_vector_ok=t
11. Heartbeat fn_cut_heartbeat_ping(…, {stage:'pre_complete', …}) row ticks
12. Complete fn_cut_complete(cut_request_id, actor) status=cleanup_scheduled; cleanup_scheduled_at=now()+15d

Failure mode rehearsal (must verify before batch)

scenario expected refusal recovery path
Agent piece missing content_text RAISE: piece[N].content_text is required Operator REGENERATES pieces from Agent; does NOT jsonb_set
Agent piece missing canonical_address RAISE: piece[N].canonical_address is required same
Operator calls fn_cut_apply before VERIFY_MARK RAISE: cannot cut from status … must be 'mark_verified' run VERIFY_MARK first
Operator pings fn_cut_heartbeat_ping('iu_outbound_default',…) {refused:true, reason:'protected_legacy_silent_passive'} use cut_pipeline_operator or a cut_pipeline_operator_<scope> variant
Operator runs fn_cut_cleanup_dry_run(0) RAISE: must be >= 1 use ≥ 1
Gate queue.heartbeat.enabled=false and operator pings {skipped:true, reason:'queue.heartbeat.enabled=false'} flip gate on; do not silently no-op

D30/D31 closeout per pilot

Each pilot pack must include the D30 8-check and D31 7-check matrices from this pack (06-d30-d31-protection-refresh.md) — repeat them at the post-COMMIT moment and at end-of-pilot. The 6-alias md5 must equal 750b06b610f50065f1117961813d9df4 at end-of-pilot.

Stop conditions

Halt and route to operator/GPT if any of the following occur:

  • fn_cut_apply raises anything other than expected status-machine refusals
  • body required ever surfaces (means Phase B validation was bypassed)
  • iu_outbound_default last_tick_at advances (means false-heal happened)
  • production_documents touched
  • pg_cron installed
  • event_outbox schema mutated
  • 6-alias md5 changes
  • DLQ row count grows
  • runtime.phase changes from phase2_governance

Single document, single operator, dry-run pg_dump pre + post, 2 BEGIN/ROLLBACK proofs at the start (PB validation refuses bad pieces; PC heartbeat refuses iu_outbound_default), then real apply, then D30/D31, then KB report bundle.

After that single-document pilot PASSes, the third pack can extend to 3–5 documents in sequence and explore CF-1 (cleanup APPLY executor design).

Forbidden in this next pack

  • batch parallelism (one cut_request at a time)
  • enabling queue.job_substrate.enabled (still false)
  • enabling iu_core.composer_enabled permanently
  • automated cron-driven cut
  • pg_cron install
  • Qdrant write
  • jsonb_set on payload to recover a bad piece (forbidden by Phase B rule)
  • false-heal of iu_outbound_default
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-cut-operational-pipeline-runtime-hardening/07-next-batch-test-plan.md