KB-8CB7

R2-D2 Channel Decision Packet — B2 Inspect Producer (LEGO, design-only, 2026-06-18)

37 min read Revision 1
laws-newR2-D2channel-decisionB2inspect-producerlegodesign-onlyread-onlynon-authorizinghost-cronagent-api-executorpg_cronjob_queueowner-gated2026-06-18

R2-D2 Channel Decision Packet — B2 Inspect Producer

Date: 2026-06-18 · Workstream: LEGO-PILOT-SLICE-0-R2-B2-PLANNING-BUNDLE-2026-06-18 (Deliverable A of five) · Editorial revision: rev1 Class: design-only / channel-comparison / decision-support · READ-ONLY · NON-ENACTING · NON-AUTHORIZING · NOT remediation · NOT technical design · NOT implementation · NO channel selected · NO blocker resolved · NO runtime touched.

Metadata convention. This body uses editorial revision (rev1) only. AgentData storage revision and content_length are authoritative in AgentData metadata at read time; they are deliberately not pinned in this body.

Channel-decision lock. This packet compares the candidate invocation channels for the B2 inspect producer and classifies them for a later Owner decision. It selects no channel as authority, specifies no scheduler/runner, installs nothing, enables nothing, and builds nothing. The channel is an internal of B2 (B2-AC-7); whichever is later chosen must stay inside the block so the contract is unaffected.


0. Status and non-authorization

STATUS: PASS — engineering / design-only. This is a complete design-only channel comparison for the B2 inspect producer: a comparison matrix across five candidate channels, a per-channel analysis, a LEGO-replaceability comparison, an evidence/observability comparison, a rollback/delete comparison, the Owner-gated future-work list, and a recommendation-only summary. It builds nothing, mutates nothing, authorizes nothing, and chooses nothing.

Engineering PASS ≠ authority PASS. A PASS here means the channel options are completely and fairly compared on paper. It is not an Owner authorization to select a channel, to design-in-detail, to write technical design, to install an extension, to promote a contract, to enable a worker, or to build a producer. Default disposition: HOLD.

Pipeline position (downstream-only).

Accepted R1a/R2a root-cause baseline (Codex PASS_WITH_CAVEATS) → Owner Decision Packet (Option D, accepted) → R1/R2 Modular LEGO Architecture Scoping (accepted) → R1-K ∥ R2-B block-contract packets (accepted) → Registries/Pivot LEGO Interface TD-prep (accepted) → R2-B2 Inspect Producer TD-prep (accepted, Codex PASS_WITH_CAVEATS)this R2-D2 standalone channel decision packet (Deliverable A of the Pilot-Slice-0 planning bundle) → (only if separately authorized) actual B2 technical design with a chosen channel → (only if separately authorized again) producer build / write-enabled remediation.

This packet deepens §11 of the accepted R2-B2 TD-prep packet (its conceptual channel matrix) into a standalone decision packet. It opens no next package and selects no channel.

Non-authorization (explicit). This document does not, and cannot: run any DB write / DDL / DML; restart or reload any container or service; run any worker / cron / job; trigger DOT / KG / birth / certify / promote / repair execution; set inspect_pen / inspect_stamp / inspect_gate; set certified=true; flip app.birth_gate_mode or any dot_config gate; assign a governance owner; install pg_cron or any extension; promote any agent-api contract DRY_RUN→REAL_RUN; enable any queue worker / master switch; write env / config files; patch source code; patch any source law / draft / note / prior report; create a current corpus or staging corpus; write technical design; implement; resolve any blocker; select or wire a channel; overwrite the v0.1-stable / FIX7 V3 baseline; promote or use Tool-Kiem-Thu v0.2-hardening as authority.

Evidence basis — INHERITED_EVIDENCE. No runtime was queried in this run. Every runtime fact cited is inherited from the accepted read-only reports (R2a root-cause, R2 readiness scope, Phase-1, Phase-1B) and accepted design packets. AgentData metadata is authoritative at read time. CAV-3 / CAV-4 / CAV-5 bound what is provable about each channel.

Reading discipline (Codex operational caveat, honored). All sources were read directly from AgentData KB, in bounded, sequential, single-document batch_read (full) calls, by the main processno parallel reader-agents, no background reader-agents, no sub-agent outsourcing, no inference from local prose. One oversized source was decoded locally by the main process only to render its already-fetched bytes readable; no reading was outsourced.


1. Purpose

Compare host cron, agent-api executor, pg_cron, job_queue worker, and manual one-shot as B2 invocation channels, and classify them for a later Owner decision without selecting one as authority. The packet answers:

  1. Which channels are candidate / risky / rejected? — §5–§10, §15.
  2. What evidence is needed for each before a build? — §6–§10, §12.
  3. What Owner gate is needed for each? — §6–§10, §14.
  4. What rollback unit would apply to each? — §6–§10, §13.
  5. Which channel best preserves LEGO replaceability? — §11.
  6. What must be proven before actual B2 TD? — §15, §16.

The one rule, above all detail. The channel is a replaceable internal of B2, not the block boundary. B2's contract — read uncertified birth_registry rows → write inspect_* only, genuine per-stage, fail-closed — is channel-independent (B2-AC-7). This packet may compare channels; it may not let any channel leak into the contract, and it may not promote any channel to authority.


2. Sources read

All sources read first-hand, directly from AgentData KB, via batch_read (single path, full: true), one document per call, sequentially, by the main process — no parallel reader-agents, no background agents, no sub-agents, no local-prose inference. None SOURCE_NOT_READ. AgentData storage revision / content_length authoritative in metadata at read time.

# Source (prefix knowledge/dev/ omitted) Status Used for
1 laws-new/newlaws/consolidation/r2-b2-inspect-producer-td-prep-lego-2026-06-18.md READ (full) the accepted B2 contract; §11 channel matrix this packet deepens; B2-AC-7 (channel internal)
2 laws-new/newlaws/reports/r2-b2-inspect-producer-td-prep-lego-execution-report-2026-06-18.md READ (full) B2 completion criteria; channel-conceptual-only posture
3 laws-new/reports/codex/codex-review-r2-b2-inspect-producer-td-prep-lego-2026-06-18.md READ (full) B2 PASS_WITH_CAVEATS; "channel matrix conceptual only; no channel selected as authority"
4 laws-new/newlaws/consolidation/registries-pivot-lego-interface-td-prep-2026-06-18.md READ (full) S3/S4/S7/S8 surfaces; B2's interface access line; channel-is-internal
5 laws-new/reports/codex/codex-review-registries-pivot-lego-interface-td-prep-2026-06-18.md READ (full) the no-parallel-reader-agents process caveat
6 laws-new/newlaws/consolidation/r2-b-block-contract-packet-lego-2026-06-18.md READ (full) B2/B3/B4/B5/B7 contracts; channel-is-internal; B5/B7 kept separate
7 laws-new/reports/codex/codex-review-r1-k-r2-b-block-contract-packets-lego-2026-06-18.md READ (full) B2 = "channel remains later TD-prep decision, correctly kept inside block"
8 laws-new/newlaws/consolidation/r1-r2-modular-lego-architecture-scoping-2026-06-18.md READ (full) block map; R2-D2 channel as internal; anti-coupling AC-1…12
9 laws-new/reports/codex/codex-review-r1-r2-modular-lego-architecture-scoping-2026-06-18.md READ (full) design-only altitude; channel deferred as future TD-prep
10 laws-new/newlaws/reports/r2a-birth-inspection-runner-cron-log-root-cause-2026-06-18.md READ (full) the channel evidence (containers; pg_cron absent; host cron map; master switches; queue idle; agent-api :8090; tool-boundary)
11 laws-new/reports/codex/codex-review-r1a-r2a-runner-cron-log-root-cause-2026-06-18.md READ (full) 6 caveats; 3 wording constraints; "net-new governed build, not restart"
12 laws-new/newlaws/reports/r2-birth-certify-canonical-stamp-readiness-scope-2026-06-17.md READ (full) birth_registry schema; no live inspect_* setter; consumer starved
13 laws-new/newlaws/consolidation/phase1b-runtime-truth-blocker-decision-packet-2026-06-17.md READ (full) all OPEN blockers; HOLD-2 PARTIAL; R2 macro framing
14 architecture/birth-registry-law.md (Điều 0-G v1.0) READ (full) the PEN/STAMP/GATE rule-set the chosen channel must run; one-column-per-inspector
15 laws-new/newlaws/notes/dieu4-birth-process-compatibility-note.md (rev1) READ (full) birth ≠ canonical; certify is not the channel's job
16 laws-new/newlaws/notes/dieu32-approval-owner-gate-compatibility-note.md (rev1) READ (full) Owner gate; no-Stamp-bypass
17 laws/dieu32-approval-law.md (v1.1) READ (full) §2.1 DOT-100% / no manual SQL / no curl bypass; §2.4 new/fix DOT in scope
18 laws-new/newlaws/notes/dieu35-dot-governance-compatibility-note.md (rev1) READ (full) scanner=list-only; warn-vs-block §10; reuse-pattern-not-turnkey
19 ssot/operating-rules.md (v7.58) READ (full) Assembly First; fail-closed default; AP-CLOSE evidence; out-of-scope-blocker STOP

3. Tool/packet lock

Carried exactly, no change:

Item Status
Tool/packet currently built by T1 = v0.1-stable / FIX7 V3 baseline Carried. May continue to be used for FIX7 Recheck-9 / current Codex packet. Must not be overwritten. Use only as reproducibility / comparison / regression fixture.
Tool-Kiem-Thu v0.2-hardening Carried. Separate development track on a separate dev surface. May inherit lessons from V3 (black-box oracle, fail-open regression, manifest-laundering prevention). Not authority for FIX7 until it passes regression and Owner/User promotes it.

This packet builds, runs, promotes, overwrites, and relies on neither tool. A v0.2-hardening result offered as authority for FIX7 is rejected (mirrored in Deliverable D, bad-input case BAD-10).


4. Accepted channel baseline (carried, not re-derived)

Carried in substance from §11 of the accepted R2-B2 Inspect Producer TD-prep packet (Codex PASS_WITH_CAVEATS) and from the R2a root-cause study (Codex PASS_WITH_CAVEATS). This packet deepens that matrix; it does not change it.

The channel is internal (B2-AC-7). Per the accepted B2 contract: "Producer channel is internal & swappable; contract = write inspect_* only." Codex's acceptance of B2 reads: "Producer not built; channel remains later TD-prep decision, correctly kept inside block." The five channels named across the accepted chain are: host cron · agent-api executor · pg_cron · job_queue worker · manual one-shot.

Runtime substrate the channels must live in (INHERITED_EVIDENCE, R2a §3–§9):

  • Containers: postgres (Up 2 months, healthy — hosts birth_registry, trg_birth_auto_certify, 192 birth triggers), incomex-directus (Up 5 weeks, healthy — births fire on its INSERTs), incomex-agent-api-executor (agent-api-executor-local:v1, Up 13 days, healthy, :8090/dispatch — a generic DOT dispatch runner, not bound to any birth DOT). There is no dedicated birth-inspection service/container.
  • Master switches OFF: process_dot_runtime.execute_enabled=false, real_run_enabled=false, dry_run_only=true; queue.worker.enabled=false; queue.job_substrate.enabled=false.
  • pg_cron NOT installed: pg_extension = btree_gist, pgcrypto, plpgsql, postgres_fdw only.
  • Queue idle: queue_heartbeat last tick 2026-05-22→26 (3 executors, none birth-related); event_outbox grows live to 215,588 rows (≈215,227 system/issue_opened) but is undrained and carries no birth/certify events.
  • Host cron (wf_host_crontab_snapshot, observed 2026-06-17 02:10:04, 54 entries, all status=OBSERVED): the 0 6 * * * slot belongs to dot-nrm-lifecycle, not birth-verify. Sibling scanner/maintenance DOTs run here — dot-hc-executor (0 */3), dot-orphan-scanner, dot-misclass-scanner, dot-nrm-verify/sync/lifecycle/discover, dot-sync-orphan-scan, dot-trigger-guard, dot-matrix-health, dot-gov-verify, dot-vector-audit, dot-pivot-health, dot-accuracy-verify, fn_expire_stale_approvals (0 5), auto_apply_approval (30 4), matview-refresh, backups, certbot. No host cron entry references birth / inspect / certify.
  • agent-api contract today: the only dot_agent_api_contract bindings are the KG EXPLAIN pair (DOT_KG_EXPLAIN, DRY_RUN pilot, 2026-06-04 → :8090/dispatch). The inspector DOTs DOT-TAC-BIRTH-VERIFY (cron 0 6 metadata) / -GATE (event) are unwired stubs (engine_unclassified/requires_runner, no file_path, no contract, last_executed=NULL).
  • Tool-boundary (CAV-3/CAV-4): no crontab -l / systemctl / docker exec / docker inspect tool exists in the available surface; read_file is allowlisted to /opt/incomex/docs, /opt/incomex/dot/specs, /var/log/nginx only; /opt/incomex/dot/bin and env files are not readable on the VPS; container logs are tail-only (≤500 lines), so deep liveness of any channel is provable only via DB-captured snapshots.

The job the chosen channel invokes (Điều 0-G, carried). Whatever the channel, it must invoke a producer that runs the three Điều 0-G inspections in strict PEN → STAMP → GATE order, each writing only its own inspect_* column on a genuine per-stage pass, fail→audit-queue, idempotent. The channel never changes that rule-set.


5. Channel comparison matrix

Conceptual comparison only. No channel is selected, specified, scheduled, installed, enabled, or built. Each row is FUTURE_TECHNICAL_DESIGN_REQUIRED for any build. Dispositions match the accepted §11 matrix.

Channel Possible role LEGO boundary risk Evidence requirement (before TD) Observability Rollback unit Owner gate needed TD required later Disposition
host cron Scheduled trigger that invokes the inspector pass (the proven channel for the sibling scanner DOTs) Low — a cron entry is outside the block and swappable; not transactional with PG; opaque except via the DB-captured snapshot Cron entry visible in wf_host_crontab_snapshot; per-run S7 append Indirect (snapshot table); not in-txn Remove the one cron entry; one producer run Điều 32 + S2 owner Yes — the wiring spec candidate (lowest blast radius; proven for siblings)
agent-api executor (:8090) Dispatch the inspector via an agent-api contract, as the KG EXPLAIN pilot does Low–Medium — contract-bound and observable (governance-aligned); but shared infra (also serves the KG lane) and master-switch-gated agent-api contract bound + dispatch records + master-switch state + S7 append Strong (contract + dispatch records) Unbind / disable the contract (return to DRY_RUN); one producer run Điều 32 + S2 + contract promotion DRY_RUN→REAL_RUN Yes — the contract + wiring candidate (existing healthy runner; contract pattern proven) — gated by master switch + promotion
pg_cron In-database scheduler running the inspector pass Medium–High — in-DB and transactional with the inspect_* writes (clean for atomicity) but requires installing a new extension (not installed today) → infra dependency / higher blast radius pg_cron installed + job catalog + S7 append Strong (in-DB job catalog) Unschedule the job; (extension removal = infra) Điều 32 + infra/extension-install approval Yes risky / future-gated (net-new extension install)
job_queue worker Enqueue inspection jobs drained by a worker High — substrate exists but disabled/idle; the "queue that nobody drains" failure mode (event_outbox 215k undrained) is already observed here job_queue rows + worker heartbeat + master-switch state + S7 append Medium (heartbeat + queue rows), currently dead Disable the worker; drain/purge the queue; one producer run Điều 32 + enable worker / master-switch flip Yes risky / future-gated (substrate idle/disabled; undrained-queue failure mode present)
manual one-shot Operator-run bring-up (the 2026-03-21 SSH + docker exec pattern) Disqualifying as a standing channel — not testable/replaceable/rollbackable as a block; violates Điều 32 §2.1 (no manual SQL / no curl bypass); is the vehicle of the fused INSERT Ad hoc only None (no standing artifact) None clean Would still need Điều 32, but is structurally unfit as a standing channel n/a (anti-pattern) reject as a standing channel

Convergent reading of the matrix. Two channels are standing-fit candidates (host cron, agent-api executor); two are standing but currently-blocked/heavier (pg_cron needs an extension install; job_queue worker sits on an idle/undrained substrate); one is structurally unfit as a standing channel (manual one-shot). No row is promoted to authority here.


6. Host cron analysis

Possible role. A host-crontab entry that periodically invokes the B2 inspector pass — the same channel the sibling scanner DOTs already use (dot-orphan-scanner, dot-misclass-scanner, dot-nrm-*, dot-hc-executor, etc., per wf_host_crontab_snapshot). The inspector's nature — a periodic scan over uncertified rows — matches a cron cadence.

LEGO boundary fit (strong). A cron entry lives outside the block; it merely invokes the producer. Swapping host cron for another channel changes nothing in the B3 inspect_* contract. This is exactly the replaceable-internal that B2-AC-7 requires. The 0 6 * * * slot is already taken by dot-nrm-lifecycle, so a birth-inspector would need its own slot — a wiring detail, not written here.

LEGO boundary risk (low, with one caveat). Cron is not transactional with the inspect_* writes (the producer must own its own per-stage atomicity and idempotency), and it is opaque to in-DB observability — visible only via the DB-captured wf_host_crontab_snapshot, never via a live crontab -l (no such tool; CAV-3/CAV-4). So "is the cron actually installed and firing?" is provable only through the snapshot + the S7 run-evidence, not directly.

Evidence needed before TD. (a) A cron entry present in wf_host_crontab_snapshot bound to the inspector; (b) per-run S7 evidence (counts/ids/timestamps/rule-set hash) confirming the producer ran; (c) confirmation that the producer is genuinely idempotent (re-firing the cron must not double-stamp).

Owner gate. Điều 32 (the producer build is a new/fix DOT, §2.4) + an assigned S2 producer owner. The cron wiring itself is part of the producer's governed build, never a manual crontab -e.

Rollback unit. Remove the single cron entry; one producer run is the rollback unit (S8). Clean and bounded.

Residual. FUTURE_TECHNICAL_DESIGN_REQUIRED for the exact slot, command, and idempotency guard — not written here (no cron spec, no command sequence).


7. Agent-api executor analysis

Possible role. Dispatch the B2 inspector via a dot_agent_api_contract binding to incomex-agent-api-executor (:8090/dispatch), the same mechanism the KG EXPLAIN pilot uses (DOT_KG_EXPLAIN). The executor exists, is healthy, and has been Up 13 days, but is not bound to any birth DOT today.

LEGO boundary fit (strong, governance-aligned). A contract-bound dispatch is the most observable and Điều-32-promotable channel: the binding, the mode (DRY_RUN/REAL_RUN), and the dispatch records are all in-DB and governed. It aligns with Điều 35's "DOT is the gate" and Điều 32 §2.1's "no manual SQL / no curl bypass." The channel still stays inside B2 (the contract is unchanged whether dispatch is cron or agent-api).

LEGO boundary risk (low–medium). Two caveats: (a) the executor is shared infra — it also serves the KG lane — so a birth binding must not couple the birth lane to the KG lane (AC-7 stays intact because the contract is per-DOT, not a shared body); (b) it is currently fail-closed: master switches are OFF (execute_enabled/real_run_enabled=false, dry_run_only=true), and a contract promotion DRY_RUN→REAL_RUN is itself Owner-gated. CAV-5 applies to any GUC/switch claim.

Evidence needed before TD. (a) A dot_agent_api_contract row binding the inspector DOT to :8090; (b) the master-switch state (must be intentionally flipped, Owner-gated, before REAL_RUN); (c) dispatch records + per-run S7 evidence; (d) proof the binding does not entangle the KG-lane contract.

Owner gate. Điều 32 + S2 owner + a contract promotion DRY_RUN→REAL_RUN (a distinct Owner gate of its own).

Rollback unit. Unbind or disable the contract (return to DRY_RUN); one producer run is the rollback unit (S8). The executor itself is untouched.

Residual. FUTURE_TECHNICAL_DESIGN_REQUIRED for the contract shape, dispatch payload, and master-switch sequence — not written here.


8. pg_cron analysis

Possible role. An in-database scheduler (pg_cron) that runs the inspector pass on a schedule, transactional with the inspect_* writes.

LEGO boundary fit (clean for atomicity, heavy for infra). Because pg_cron runs in-DB, the inspector pass and its inspect_* writes can share a transaction — attractive for per-stage atomicity. But pg_cron is NOT installed (pg_extension shows only btree_gist, pgcrypto, plpgsql, postgres_fdw), so choosing it means a net-new extension install — an infrastructure change with a larger blast radius than a cron entry or a contract row.

LEGO boundary risk (medium–high). The extension install is a privileged infra action outside the block, with its own failure and rollback surface. It is heavier than the two candidate channels precisely because it adds a dependency that does not exist today (Assembly First disfavors standing up new infra when an existing channel suffices).

Evidence needed before TD. (a) An infra decision + approval to install pg_cron; (b) the cron.job catalog entry bound to the inspector; (c) per-run S7 evidence; (d) a tested extension-removal/rollback path.

Owner gate. Điều 32 + a separate infra / extension-install approval.

Rollback unit. Unschedule the job (bounded); extension removal is an infra-level rollback (heavier, separate).

Disposition. risky / future-gated — not rejected, but deprioritized relative to host cron / agent-api because of the net-new extension dependency. FUTURE_TECHNICAL_DESIGN_REQUIRED; no install authorized or planned here.


9. job_queue worker analysis

Possible role. Enqueue inspection jobs into job_queue, drained by a worker that runs the inspector pass.

LEGO boundary fit (decoupled, but on a dead substrate). A queue+worker decouples scheduling from execution cleanly. But the queue substrate is disabled/idle: queue.worker.enabled=false, queue.job_substrate.enabled=false, no queue_heartbeat tick since 2026-05-26.

LEGO boundary risk (high — a failure mode already observed here). The "queue that nobody drains" failure mode is not hypothetical in this substrate: event_outbox already grows to ~215,588 rows undrained. Choosing a queue channel for B2 risks reproducing exactly that pattern — inspection jobs piling up with no live drainer — which would leave the producer silently starved (the very condition R2 is trying to fix).

Evidence needed before TD. (a) The worker + job substrate enabled and proven to drain (a live heartbeat, not a config flag); (b) job_queue rows consumed end-to-end on a sample; (c) per-run S7 evidence; (d) an explicit guard against the undrained-queue failure mode.

Owner gate. Điều 32 + enabling the worker / flipping the master switch (queue.worker.enabled / queue.job_substrate.enabled).

Rollback unit. Disable the worker; drain/purge the queue; one producer run (S8).

Disposition. risky / future-gated — not rejected, but the idle/undrained substrate makes it the least-ready standing channel today. FUTURE_TECHNICAL_DESIGN_REQUIRED; no worker enabled here.


10. Manual one-shot analysis

What it was (carried, R2a §7). The 2026-03-21 06:00–08:00 certification was an operator-run S157-A bootstrap: dot-birth-backfill (+ an s157b seed) executed via SSH + docker exec → psql, stamping all three inspect_* and certified=true directly in the INSERT (… 'backfill:dot-birth-backfill', true, now(), now(), now(), now() … ON CONFLICT (entity_code) DO NOTHING).

Why it is rejected as a standing channel.

  1. Not a standing producer — it cannot be scheduled, tested in isolation, replaced, or rolled back as a block; it ran once and never recurred by construction.
  2. Violates Điều 32 §2.1 — manual SQL via SSH + docker exec is exactly "insert SQL tay / curl bypass," explicitly forbidden ("mọi approval request phải được tạo qua DOT hợp pháp").
  3. It is the vehicle of the fused INSERT — the anti-pattern B2-AC-5/AC-6 reject (faked inspect_*=now() + fused B1+B2+B3+B4).

The single legitimate residual one-shot. A bounded, Owner-approved one-time historical backlog pass is B5, a separate block — it runs once over the 1.21M historical uncertified rows through the same fail-closed B3 contract and Điều 0-G rules (never the fused shortcut). B5 is a dependency boundary, not part of B2's channel decision — this packet does not open B5 (see §16). Reading the residual one-shot as "manual one-shot is fine after all" is the SCOPE_CREEP error and is rejected.

Disposition. reject as a standing channel for B2.


11. LEGO replaceability comparison

The LEGO test for a channel: can B2 be deleted and rebuilt on a different channel without touching B1, B3, B4, or any shared surface, with the B3 inspect_* contract invariant across the swap?

Channel Swappable without touching the contract? Blast radius of choosing it Blast radius of replacing it later Replaceability verdict
host cron Yes — a cron entry is external and removable Lowest (one crontab line) Lowest (remove the line, wire another channel) Best replaceability
agent-api executor Yes — a contract row is external and unbindable Low (one contract row; shared executor untouched) Low (unbind, return to DRY_RUN, wire another channel) Strong replaceability (most observable)
pg_cron Yes for the job; the extension is sticky Medium–high (net-new extension) Medium (unschedule job easy; extension removal heavier) Good for the job, heavier for the dependency
job_queue worker Yes — worker/queue are external High (idle substrate to revive) Medium (disable worker; purge queue) Decoupled but substrate-fragile
manual one-shot No — not a standing artifact to swap n/a (anti-pattern) n/a Not replaceable (disqualified)

Conclusion (replaceability lens only, not a selection). host cron preserves LEGO replaceability best (smallest external artifact, lowest swap cost), with agent-api executor close behind and more observable. Both keep the channel a true replaceable internal. pg_cron and job_queue worker are swappable in principle but add a heavier or fragile dependency; manual one-shot is not a replaceable block at all. This is a replaceability comparison, not a channel choice.


12. Evidence and observability comparison

What each channel can prove about itself, bounded by the tool-boundary caveats (CAV-3/CAV-4: no crontab -l/systemctl/docker exec; logs tail-only; /opt/incomex/dot/bin + env unreadable).

Channel "Is it installed?" provable via "Did it run?" provable via In-transaction with inspect_*? Observability strength
host cron wf_host_crontab_snapshot (DB-captured; not live crontab -l) per-run S7 evidence + snapshot No Medium (indirect)
agent-api executor dot_agent_api_contract row + master-switch state dispatch records + S7 evidence No (dispatch is out-of-band) Strong (governed, in-DB contract)
pg_cron pg_extension + cron.job catalog cron.job_run_details + S7 Yes (in-DB) Strong (in-DB)
job_queue worker dot_config switches + worker heartbeat job_queue rows + heartbeat + S7 No Medium (and currently dead)
manual one-shot nothing standing ad hoc only (was in-INSERT — the anti-pattern) None

Shared evidence floor (all channels). Regardless of channel, B2 must append the same S7 run-evidence — rows scanned/passed/failed per stage, runner id, channel id, rule-set version/hash, run start/end, and per-failure audit records. S7 records; it does not decide (no channel's evidence may act as an approval or certify signal). The channel id in S7 is what makes a later channel swap auditable.


13. Rollback / delete comparison

The rollback unit for every channel is one producer run (S8 discipline); the channels differ only in how the invocation is undone. No rollback script, DELETE/UPDATE sequence, or command list is written here (B2-AC-9 / RP-AC-8).

Channel Undo the invocation by Undo one producer run by Downstream-certify caveat
host cron Remove the cron entry (S8 per-run rollback unit; mechanism is FUTURE_TECHNICAL_DESIGN_REQUIRED) If a run completes all three inspect_* on a row, B4 independently auto-certifies — outside B2
agent-api executor Unbind / disable the contract (→ DRY_RUN) (same S8 unit) same
pg_cron Unschedule the job (extension removal = infra) (same S8 unit) same
job_queue worker Disable the worker; drain/purge the queue (same S8 unit) same
manual one-shot (no clean undo — disqualifying) (no clean per-run boundary) the fused INSERT certified directly — unrollbackable block-by-block

The downstream-certify subtlety (carried, not resolved). Because completing all three inspect_* on a row legitimately triggers B4's independent auto-certify, the rollback of "one producer run" has a downstream effect (a triggered certified=true) that lies outside B2 — identical across all channels. Whether/how to unwind a triggered certify is FUTURE_TECHNICAL_DESIGN_REQUIRED and Owner-gated. HOLD-2 is OPEN: there is no atomic end-to-end birth-certify promote transaction today. No channel choice resolves HOLD-2.


14. Owner-gated future work

Every action below is forbidden now (OWNER_GATE_REQUIRED). Listing is scoping, not authorization.

Future write Gate required Forbidden now?
Select the B2 invocation channel Owner decision (after this comparison) Yes
Wire host cron for the inspector Điều 32 + S2 owner Yes
Bind/promote the agent-api contract (DRY_RUN→REAL_RUN) Điều 32 + S2 + contract promotion Yes
Install pg_cron (extension) Điều 32 + infra/extension approval Yes
Enable the job_queue worker / master switch Điều 32 + master-switch flip Yes
Run any chosen channel against live rows Điều 32 + standing B2 producer Yes
Assign the birth-producer governance owner (S2) Điều 37 → Điều 32 Yes
Confirm transient app.birth_gate_mode/app.bypass_birth_gate (CAV-5) Owner out-of-band — read-only, not a runtime write Yes (not done here)

15. Recommendation-only summary

RECOMMENDATION_ONLY — NOT AUTHORITY — OWNER_GATE_REQUIRED — FUTURE_TECHNICAL_DESIGN_REQUIRED.

Channel Disposition Authority status
host cron candidate — lowest blast radius; the proven channel for the sibling scanner DOTs; matches the inspector's periodic-scan nature; best LEGO replaceability Not selected
agent-api executor (:8090) candidate — existing healthy runner; contract-bound and most observable / Điều-32-promotable; gated by master switch + DRY_RUN→REAL_RUN promotion Not selected
pg_cron risky / future-gated — clean in-DB atomicity but a net-new extension install (not installed today) → higher infra blast radius Not selected
job_queue worker risky / future-gated — decoupled, but the substrate is disabled/idle and the undrained-queue failure mode is already present in this system Not selected
manual one-shot reject as a standing channel — not testable/replaceable/rollbackable; violates Điều 32 §2.1; is the fused-INSERT vehicle (the only legitimate residual one-shot is B5, a separate Owner-gated backlog pass) Rejected as standing channel

If the Owner later opens B2's technical design, the two viable standing candidates are host cron (lowest blast radius / Assembly First) and the agent-api executor (most governance-aligned and observable). This is a comparison for a later Owner decision; no channel is selected here, and whichever is chosen must remain inside B2 so the contract is unaffected (B2-AC-7). Selecting a channel here would be CHANNEL_AUTHORITY_DRIFT and is refused.


16. What remains unresolved

  • CHANNEL not selected (by design). The Owner decision among the candidates is deliberately not made here; this packet only classifies. FUTURE_TECHNICAL_DESIGN_REQUIRED for any chosen channel's build.
  • Substrate currently fail-closed. Master switches OFF, queue idle, no birth cron, pg_cron absent — every standing channel that uses the runner/queue substrate is presently disabled and would require an Owner-gated enable.
  • SOURCE_RECOVERY_REQUIRED — Điều 0-G rule-set. The PEN/STAMP/GATE check definitions the chosen channel must invoke live in architecture/birth-registry-law.md (a temporary working source; the Constitution reference law-00g-birth.md is broken). Authoritative re-establishment is Owner-controlled and out-of-band (external S6).
  • CAV-3 / CAV-4 / CAV-5 carried. Channel liveness is provable only via DB-captured snapshots (no crontab -l/systemctl/docker exec tool; /opt/incomex/dot/bin + env unreadable); the transient GUC layer is unreadable. No overclaim is made about any channel's live state.
  • B5 / B7 remain dependencies only, not opened. The one-time backlog pass (B5) and the warn→block GUC policy (B7) are referenced as dependency boundaries; their designs are not opened here (SCOPE_CREEP guarded).
  • HOLD-2 OPEN — no atomic end-to-end birth-certify promote transaction today; no channel resolves it.
  • Blockers — all OPEN, none resolved: CONS-002, CONS-003, CELL-003/004/007, HOLD-1, HOLD-2, RISK-BYPASS, GOV-016/017, GOV-REUSE-001, Điều 39 runtime-EMPTY (2199 edges / 0 provenance), Điều 35 production-readiness FAIL.
  • FUTURE_TECHNICAL_DESIGN_REQUIRED (explicitly NOT written here): any scheduler/runner/cron implementation, contract shape, dispatch payload, command sequence, extension-install plan, worker-enable plan, or rollback script.

17. Ready for GPT/Codex review

Yes.

Core rule, kept above all detail: the B2 invocation channel is a replaceable internal, not the block boundary; B2's contract (read uncertified → write inspect_* only, fail-closed) is channel-independent. This packet compares host cron, agent-api executor, pg_cron, job_queue worker, and manual one-shot, and classifies them — host cron / agent-api = candidates, pg_cron / job_queue = risky-future-gated, manual one-shot = rejected-as-standing — without selecting any as authority.

Default disposition: HOLD. Engineering PASS = a complete, fair channel comparison; it is not an Owner authorization to select a channel, install, promote, enable, or build. No PASS authorizes writes. All blockers remain OPEN.

Back to Knowledge Hub knowledge/dev/laws-new/newlaws/consolidation/r2-d2-b2-channel-decision-packet-lego-2026-06-18.md