07 · Next batch cut test plan
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.
Recommended next pack
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:
- No
body requiredraise. The Agent's piece array must includecontent_textandcanonical_addressper piece. If the Agent omits either,fn_cut_mark_staged_filerefuses upstream with a per-index error — operators must NOTjsonb_set-patch; instead, they must regenerate pieces from the Agent. - 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. - No false-heal. The
iu_outbound_defaultrow stays atlast_tick_at = 2026-05-22 11:31:41, last_tick_status=warn. Phase 3C closure remains a separate carry-forward. - 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_applyraises anything other than expected status-machine refusalsbody requiredever 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
Recommended scope for the next pack
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_enabledpermanently - automated cron-driven cut
- pg_cron install
- Qdrant write
jsonb_seton payload to recover a bad piece (forbidden by Phase B rule)- false-heal of iu_outbound_default