KB-7753
90000x · 03 — MARK Integration writer surface (Migration 038)
8 min read Revision 1
iu-core90000xmark-integrationfn_iu_mark_create_manifestdot_iu_mark_articlemigration-038authored-ready2026-05-25
90000x · 03 — MARK Integration writer surface
Phase: C
Status: AUTHORED-READY
Migration: 038
D9 delta after apply: +1 fn (fn_iu_mark_create_manifest), +1 DOT (dot_iu_mark_article).
Why this surface exists
The mission requires Agent MARK to write into No-Vector Staging Zone, not into KB and not into IU. The existing dot_iu_staging_create is a generic creator — it does not know about cut_manifest M1-M16 fields, doesn't compose the 3-part payload (cut_manifest + mark_report + coverage_proof), and doesn't enforce the mark_manifest kind. fn_iu_mark_create_manifest is the purpose-built MARK writer.
Contract
| Property | Value |
|---|---|
| Inputs | manifest jsonb, mark_report_md text, coverage_proof jsonb, determinism_digest text, source_kind, source_ref, idempotency_key, actor |
| Side effects | 1 row iu_core.iu_staging_record (kind=mark_manifest, status=pending_review, expires_at=now+15d, vector_excluded=true) + 3 rows iu_core.iu_staging_payload (cut_manifest, mark_report, coverage_proof) + 1 audit row in dot_iu_command_run |
| Idempotency | idempotency_key unique per staging_kind='mark_manifest'. Replay returns same staging_record_id, ok=true, idempotent_replay=true. |
| Refusals | Returns {ok:false, reason:'manifest missing M1/M2/M3/M4 or pieces'} if manifest is missing manifest_version, source_id, manifest_digest, source_bytes, or pieces. |
| Never does | Create IU pieces. Insert into knowledge_documents. Insert into production_documents. Set vector_excluded=false. Upload anything to Qdrant. Skip the staging tier. |
| Lifecycle out | pending_review (NOT pending) — MARK is intentionally pending_review because the manifest is already proposal-ready and Phase D is what gates approval. pending is reserved for partial drafts not yet ready for review. |
Migration 038 — authored
-- IU Core 90000x · Migration 038 · MARK Writer Surface
BEGIN;
CREATE OR REPLACE FUNCTION fn_iu_mark_create_manifest(
p_manifest jsonb,
p_mark_report_md text,
p_coverage_proof jsonb,
p_determinism_digest text,
p_source_kind text,
p_source_ref text,
p_idempotency_key text,
p_actor text DEFAULT 'agent_mark'
) RETURNS jsonb LANGUAGE plpgsql AS $$
DECLARE v_staging_id uuid; v_content_hash text; v_now timestamptz := now();
BEGIN
SELECT staging_record_id INTO v_staging_id
FROM iu_core.iu_staging_record
WHERE idempotency_key = p_idempotency_key AND staging_kind = 'mark_manifest';
IF v_staging_id IS NOT NULL THEN
RETURN jsonb_build_object('ok',true,'idempotent_replay',true,'staging_record_id',v_staging_id);
END IF;
IF NOT (p_manifest ? 'manifest_version' AND p_manifest ? 'source_id'
AND p_manifest ? 'manifest_digest' AND p_manifest ? 'source_bytes'
AND p_manifest ? 'pieces') THEN
RETURN jsonb_build_object('ok',false,'reason','manifest missing M1/M2/M3/M4 or pieces');
END IF;
v_content_hash := md5(p_manifest::text || '|' || p_mark_report_md || '|' || p_coverage_proof::text);
v_staging_id := gen_random_uuid();
INSERT INTO iu_core.iu_staging_record (
staging_record_id, staging_kind, payload_type, purpose,
lifecycle_status, owner_actor, source_kind, source_ref, idempotency_key,
content_hash, byte_len, part_count, metadata, referenced_iu_ids,
created_at, expires_at, vector_excluded
) VALUES (
v_staging_id, 'mark_manifest', 'application/json', 'cut_manifest_for_review',
'pending_review', p_actor, p_source_kind, p_source_ref, p_idempotency_key,
v_content_hash, octet_length(p_manifest::text), 3,
p_manifest || jsonb_build_object('determinism_digest', p_determinism_digest), NULL,
v_now, v_now + INTERVAL '15 days', true
);
INSERT INTO iu_core.iu_staging_payload (staging_payload_id, staging_record_id, part_index, part_name, payload_kind, payload_json, content_hash, created_at)
VALUES
(gen_random_uuid(), v_staging_id, 1, 'cut_manifest', 'json', p_manifest, md5(p_manifest::text), v_now),
(gen_random_uuid(), v_staging_id, 2, 'mark_report', 'markdown', jsonb_build_object('md', p_mark_report_md), md5(p_mark_report_md), v_now),
(gen_random_uuid(), v_staging_id, 3, 'coverage_proof', 'json', p_coverage_proof, md5(p_coverage_proof::text), v_now);
INSERT INTO dot_iu_command_run (command_name, payload_json, actor, status)
VALUES ('dot_iu_mark_article',
jsonb_build_object('staging_record_id', v_staging_id,
'manifest_digest', p_manifest->>'manifest_digest',
'source_ref', p_source_ref),
p_actor, 'ok');
RETURN jsonb_build_object(
'ok', true,
'staging_record_id', v_staging_id,
'lifecycle_status', 'pending_review',
'expires_at', v_now + INTERVAL '15 days',
'manifest_digest', p_manifest->>'manifest_digest'
);
END; $$;
INSERT INTO dot_iu_command_catalog (command_name, category, mutating, reversible, target_functions, registered_at)
VALUES ('dot_iu_mark_article', 'mark', true, false, ARRAY['fn_iu_mark_create_manifest']::text[], now());
COMMIT;
Rollback 038
BEGIN;
DELETE FROM dot_iu_command_catalog WHERE command_name = 'dot_iu_mark_article';
DROP FUNCTION IF EXISTS fn_iu_mark_create_manifest(jsonb,text,jsonb,text,text,text,text,text);
COMMIT;
Why pending_review not pending
pending= partial intake; the agent may still be building the manifest.pending_review= the manifest exists, hasmanifest_digest, and is awaitingfn_iu_verify_mark.- The expiry clock starts the same instant in both. Cleanup treats them identically.
Refusals exercised at write time
| Caller mistake | Returns |
|---|---|
manifest_version missing |
{ok:false, reason:'manifest missing M1/M2/M3/M4 or pieces'} |
pieces=[] |
(passes 038 surface — Phase D rejects on empty pieces) |
same idempotency_key twice |
{ok:true, idempotent_replay:true, staging_record_id: <existing>} |
expires_at > created_at + 30d (caller tries to bypass via metadata) |
impossible — fn sets expires_at = now + 15d ignoring caller input |
What MARK NEVER writes to
| Target | Why blocked |
|---|---|
knowledge_documents (KB table) |
fn signature has no path; Agent MARK has no upload_document permission for mark_manifest paths. |
iu.information_unit |
fn body does not insert; pieces are born only by fn_iu_create called from fn_iu_cut_from_manifest after approval. |
iu_vector_sync_point |
vector_excluded=true CHECK + structural absence of path. |
production_documents (Directus) |
no write surface here at all. |
| Qdrant | fn cannot call extension; no pg_qdrant extension installed. |
Cross-links
- [[project_dot_iu_cutter_v0_6_iu_core_80000x_operational_cut_workflow_mark_review_cut_verify_mark_review_cut_verify]] —
02-agent-mark-instructions.mdis the 12-step Agent procedure that produces the inputs for this function. - [[project_dot_iu_cutter_v0_6_iu_core_80000x_operational_cut_workflow_mark_review_cut_verify_mark_review_cut_verify]] —
03-cut-manifest-schema.mdis the M1-M16 schema this fn validates against (minimally). - [[feedback-idempotency-key-for-event-driven-compose]] — idempotency_key pattern (md5(event_id||':'||template_id||':'||suffix)) applies analogously to MARK (md5(source_ref||':'||manifest_digest||':'||agent_run_id)).