Feature design: ClickHouse external-replication full-refresh publication¶
- Status: APPROVED
- Owner: maintainers
- Issue: independent open-source enhancement
- Target release: next minor release
- Last verified: 2026-09-18
- Approval basis: explicit maintainer implementation request on 2026-09-18; independent explorer, architecture, certification, and documentation reviews incorporated before approval
Executive summary¶
ClickHouse clusters whose shard reports internal_replication=false send a
Distributed-table insert to every replica. The existing dpone cluster
publication protocol intentionally supports only internal_replication=true
with Replicated*MergeTree: it stages through one connection and relies on
ClickHouse replication to produce one shared generation. Removing that guard
would either leave nodes unstaged or duplicate data.
This design adds an explicit external replication mode for one-shard clusters
of independent, non-replicated *MergeTree tables. Dpone acquires Keeper
authority before candidate mutation, consumes one immutable replayable artifact,
and stages that artifact directly to every required member exactly once. A
logical generation binds the artifact and schema digests to an ordered map of
opaque member IDs and physical table UUIDs. Publication remains a single
fenced, correlated ON CLUSTER operation and is successful only after every
member exposes the complete desired generation. Interrupted staging is repaired
by dropping and rebuilding only the exact unpublished owned candidate; dpone
never appends blindly after an ambiguous response.
The measurable safety outcome is zero duplicate rows after retry and zero false
success when any required member is missing, divergent, or on another
generation. Existing local publication and internal_replication=true behavior
remain unchanged, including their V1 authority and receipt codecs.
Personas and customer journey¶
| Persona | Goal | Current pain | Success signal |
|---|---|---|---|
| Analytics author | Run bounded full refresh without topology-specific scripts | External replication is rejected and local fallback would be unsafe | One manifest selects external mode and produces a complete receipt |
| Platform engineer | Operate independent replicas with deterministic recovery | A broadcast insert hides per-node delivery and retry state | Every member has an explicit stage and publication state |
| Operator | Resume an interrupted generation without guessing | A timeout cannot distinguish committed, partial, or absent work | Read-only evidence identifies the exact safe recovery action |
| Auditor | Prove no node was skipped or double-loaded | Counts and one coordinator response are insufficient | Commit-bound inventory, artifact, generation, and per-member digests |
Journey:
- Discover the external-mode constraints and confirm a one-shard, two-or-more
member cluster of direct non-replicated
*MergeTreetables. - Configure
replication_mode: external, cluster-scoped DDL, same-database staging, and a positive source-byte bound. - Run
dpone checkanddpone plan; static output states that live runtime admission, Keeper authority, and replayable-artifact capability are required. - Run the workload. Before source I/O, dpone inventories every member and fences the target operation in Keeper.
- Dpone seals the extracted artifact, stages it directly to every member, and reports member readiness without exposing endpoints or row data.
- Dpone publishes one correlated cluster DDL and returns success only after all members expose the desired logical generation.
- A same-operation retry observes authority, candidates, queue, and targets; it resumes the incomplete phase without duplicate insert or blind exchange.
- Cleanup removes only exact predecessor objects after global commit. Operators retain unresolved candidates and authority records for diagnosis.
- Existing manifests without
replication_modecontinue to use internal mode.
Scope¶
In scope¶
- Bounded ClickHouse
full_refreshon exactly one shard with at least two required members and uniforminternal_replication=false. - Explicit manifest mode
external; omission meansinternal. - Direct non-replicated
*MergeTreetarget and candidate tables in Atomic databases.Distributedaccess facades are not publication targets. - One immutable, replayable, byte-receipted extraction artifact whose schema, SHA-256, byte size, and row count are known before member mutation.
- Target fencing before staging, deterministic operation and generation IDs, direct per-member staging, one-shot mutations, exact observation, retry, replay, interruption recovery, and separately fenced cleanup.
- Existing-target adoption after exact all-member schema and logical-content equality is recorded in authority; absent targets are supported.
- Versioned external authority and receipt schemas coexisting with V1 internal records on the same target-key namespace.
- A two-member synthetic fixture and fault matrix at the lowest practical layer.
Non-goals¶
- Multiple shards, mixed replication flags, one-member clusters, Shared or
Replicated database engines, or
Distributedpublication targets. Replicated*MergeTreeunder external mode; that combination is rejected because fan-out plus table replication can duplicate delivery.- Transparent materialization of a one-shot stream. Unsupported artifacts fail before member candidate mutation.
- Global read atomicity during a multi-host DDL. Dpone proves convergence and never reports success for a partial generation; applications requiring an instantaneous cluster-wide read cutover need a separate indirection layer.
- Automatic repair of a terminal mixed publication without exact queue and physical-generation evidence.
- Lease expiry, authority stealing, or coordination with writers that bypass dpone.
- Production certification from local synthetic evidence.
Assumptions and constraints¶
- Every member is reachable for admission, staging, observation, publication, and cleanup. Partial inventory is never sufficient.
- Dpone can create one direct member connection from the already-resolved sink credential without logging or persisting secrets.
- KeeperMap is configured and available to every member.
- The replayable artifact is atomically retained in a content-addressed durable
store, is reopenable by a fresh process from its authority-bound identity,
and stays immutable until external staging reaches
STAGEDor the operation is safely aborted. Authority/evidence contains no local path. - Logical-content verification uses a deterministic SHA-256 stream over typed rows in a canonical all-column order. Unsupported types or an unbounded sort fail admission; equal row counts alone never prove equality.
- Candidate names and member identities are opaque, deterministic, and bounded.
Public contract¶
CLI¶
No command is added. Existing check, plan, and run entrypoints gain an
additive replication decision:
{
"requested": "cluster",
"selected": "cluster_external",
"replication_mode": "external",
"runtime_admission_required": true,
"no_fallback": true
}
Static blockers use stable error codes and a non-zero validation exit. Runtime errors are emitted on stderr; structured output excludes endpoints, credentials, raw SQL values, file paths, and row data. Normal stdout and file atomicity remain unchanged. No option enables fallback or force-replay.
Python API¶
No new public import is required. Existing manifest and runtime APIs accept the
additive manifest field. Internal V2 models remain under canonical
dpone.contracts, dpone.ports, and dpone.runtime packages. Stable exceptions
retain the DPONE_CLICKHOUSE_CLUSTER_* family.
Manifest/schema¶
physical_design:
storage:
clickhouse:
engine: MergeTree
cluster:
name: analytics_cluster
ddl_scope: cluster
replication_mode: external
replication_mode is internal | external and defaults to internal.
internalpreserves the currentReplicated*MergeTreecontract and requires every runtime inventory row to reportinternal_replication=true.externalrequires a non-replicated*MergeTreeengine and every runtime row to reportinternal_replication=false.- Mixed flags, missing members, a mode/flag mismatch, or an engine/mode mismatch fail before source extraction and never route to the local publisher.
- The existing positive
max_source_bytes, same target/staging database, cluster DDL scope, and no-access-table rules remain mandatory.
Artifacts and evidence¶
External authority schema version:
dpone.clickhouse.cluster-external-full-refresh.v1.
External receipt schema version:
dpone.clickhouse.cluster-external-full-refresh-receipt.v1.
The retained target slot uses the same target-key digest namespace as V1 and stores:
- replication mode, scheduler-stable operation ID, random fence token, phase, dispatch epoch, and Keeper version;
- inventory and normalized-plan digests;
- artifact SHA-256, byte size, row count, schema digest, and logical
generation_id; - ordered opaque
member_id -> stage/publication/cleanuprecords; - per-member target and candidate physical UUIDs plus canonical content digest;
- bound publication and cleanup queue entry, token, and query digest;
- timestamps and stable redacted error classification.
Evidence uses opaque member IDs derived from (shard_num, replica_num) and does
not expose hostnames or addresses. The synthetic evidence producer binds exact
commit and fixture-configuration digests and labels scope local_synthetic.
Compatibility and migration¶
- Local bounded, local legacy, and internal cluster publication are unchanged.
- Existing manifests default to internal mode. False topology remains blocked unless the author explicitly selects external mode.
- V1 authority/receipt decoding and cleanup remain supported. An unresolved V1 record blocks external mode. A completed V1 record may transition only through a version-checked mode-migration CAS after current physical truth is adopted.
- A pre-existing external target is adopted only when every member is reachable and the canonical schema and content digests match. The resulting baseline receipt is stored before candidate mutation.
- Rollback disables external admission; it does not delete unresolved authority, candidates, or predecessors. Internal mode remains available for compatible topologies.
Detailed algorithm¶
1. Static normalization and runtime admission¶
- Parse the explicit mode, defaulting to internal.
- Preserve all current cluster full-refresh static requirements.
- Require
Replicated*MergeTreefor internal mode and direct non-replicated*MergeTreefor external mode. - Read the complete sorted
system.clustersinventory. - Require one shard, at least two unique
(shard_num, replica_num)members, uniform flags, and an exact match between the declared and observed mode. - Map each endpoint to one opaque member ID. Missing, extra, duplicate, or ambiguous mapping blocks.
- Require Atomic databases, KeeperMap facade consistency, direct connection capability, and canonical-digest support on every member.
- Never use
skip_unavailable_shards=1as admission evidence.
2. Deterministic identity and pre-source fencing¶
Derive:
target_key = H(cluster, database, target)
operation_id = H(protocol_version, scheduler_invocation, target_key,
normalized_plan_digest)
member_id = H(shard_num, replica_num)
candidate_name = bounded(target + "__dpone_ext_" + operation_id_prefix)
Worker try number, host ordering, endpoint text, and random values are excluded
from deterministic IDs. Inventory drift changes inventory_digest and fences
the operation; it does not create a second operation ID.
Before source I/O, create or resume one Keeper authority row in phase LOCKED.
A different unresolved operation is rejected. A completed record may begin a
new operation only through acknowledged one-shot CAS plus exact version+1
post-read. If a prior V1 record is unresolved, external mode is blocked.
3. Seal the replayable artifact and baseline¶
- Require a replayable artifact receipt with SHA-256, byte size, row count,
wire/schema identity, and a byte bound not exceeding
max_source_bytes. - Revalidate the receipt immediately before every member load.
- Derive
schema_digestandgeneration_id = H(operation_id, artifact_sha256, schema_digest, row_count). - Observe every current target. For an existing target, stream canonical typed rows in deterministic all-column order and compute a SHA-256 content digest.
- Require equal target schema/content across members, while allowing distinct
physical UUIDs. CAS the ordered predecessor map and artifact identity into
phase
STAGINGbefore candidate creation. - Empty input is valid: the artifact and canonical empty-content digests still identify one complete generation.
4. Per-member staging¶
For each member in stable member-ID order:
- Read authority and confirm operation, fence, inventory, artifact, phase, and
the member is not already
READY. - Open a direct local connection through the injected member-connection port. Generic connector retry, redirect, reconnect replay, and async insert are disabled for create/load/drop mutations.
- If an owned candidate exists, observe its physical UUID, schema, row count, and canonical content digest.
- If it exactly matches the desired generation, CAS that member to
READYwithout inserting. - If it is absent, generate and CAS a candidate UUID intent before physical
mutation, execute
CREATE TABLE ... UUIDwith that exact value, observe it, and CAS the complete candidate identity before load. A retry after process death reuses the same intent and never adopts a foreign UUID. - If it is incomplete after an ambiguous prior load, require that no member has entered publication and the candidate UUID is the exact owned UUID. Drop that candidate locally, prove absence, recreate it, bind the new UUID, and replay the same immutable artifact. Never append to an ambiguous candidate.
- Execute the load once with deterministic
query_idandinsert_deduplication_token; these are defense in depth, not the recovery decision. - Re-observe schema, count, and canonical content digest. Only an exact match
may CAS the member to
READY. - A missing, foreign, duplicated, or divergent candidate stops the operation without mutating targets.
After every required member is READY, CAS phase to STAGED. Source terminal
success is not emitted yet; the artifact remains retained until the durable
stage receipt exists.
5. Fenced publication¶
- Re-observe inventory, targets, and candidates and require the exact bound
member maps and
STAGEDphase. - CAS to
PUBLICATION_DISPATCHING, increment epoch, and bind one randomddl_correlation_tokenplus normalized query digest. Only an acknowledged CAS with exact version+1 post-read returns an in-memory dispatch permit. - Dispatch exactly one
EXCHANGE TABLES ... ON CLUSTERfor an existing target orRENAME TABLE ... ON CLUSTERfor an absent target. Use the existing one-shot transport,skip_unavailable_shards=0,distributed_ddl_output_mode=throw, and boundlog_comment. - Never redispatch that DDL. Resolve the one exact queue entry and reconcile every expected member's physical target/candidate UUID pair.
- Active partial state reports in-progress. Terminal mixed, missing queue evidence, foreign UUID, divergent generation, or inventory drift fails closed and retains all objects.
- Only when every target is the desired member generation may dpone CAS
COMMITTEDand emit the commit receipt. Downstream source state may advance only after that receipt is durable.
6. Cleanup, retry, and recovery¶
- Cleanup re-reads exact authority and receipt identity.
- When a predecessor exists, require all members committed and every candidate to equal the bound per-member predecessor UUID.
- CAS
CLEANUP_DISPATCHING, bind a separate token/query digest, and dispatch one correlatedDROP TABLE ... ON CLUSTER. - Reconcile the exact cleanup queue entry and prove predecessor absence on all
members before CAS
COMPLETED. - A lost response resumes by observation; no cleanup mutation is blindly repeated. Unknown evidence retains the objects.
- A same-operation retry resumes
LOCKED,STAGING,STAGED, publication, commit, cleanup, or completion. A different operation remains fenced. - Before publication only, an unsupported sealed artifact may CAS
ABORTEDafter exact owned candidate cleanup.ABORTEDis terminal and reusable by a new operation; it never represents success. - Cancellation follows the same phase rules. There is no lease stealing.
Pseudocode¶
plan = admit_static(manifest)
inventory = admit_runtime(plan)
authority = lock_target(operation_id(plan), inventory)
artifact = extract_and_seal()
desired = logical_generation(artifact, schema, inventory)
authority = bind_baseline_and_stage(authority, desired, observe_targets())
for member in inventory.members:
current = observe_owned_candidate(member, authority)
if current == desired.member(member):
mark_ready(member)
continue
if current is ambiguous_owned_partial:
require_no_publication_started()
drop_exact_owned_candidate(member)
persist_candidate_uuid_intent(member)
create_candidate_with_exact_uuid(member)
bind_observed_candidate(member)
load_artifact_once(member, artifact)
require_exact_content(member, desired)
mark_ready(member)
require_all_ready()
mark_staged()
permit = cas_publication_dispatching_once()
dispatch_cluster_ddl_once(permit)
reconcile_bound_queue_and_every_member()
mark_committed_and_emit_receipt()
cleanup_per_exact_receipt()
mark_completed()
State machine¶
stateDiagram-v2
[*] --> LOCKED
LOCKED --> STAGING: artifact and baseline bound
LOCKED --> ABORTED: unsupported before mutation
STAGING --> STAGING: reconcile or exact drop/rebuild
STAGING --> STAGED: every member READY
STAGED --> PUBLICATION_DISPATCHING: acknowledged fenced CAS
PUBLICATION_DISPATCHING --> PUBLICATION_DISPATCHING: observe active partial
PUBLICATION_DISPATCHING --> COMMITTED: every member desired
COMMITTED --> CLEANUP_DISPATCHING: acknowledged cleanup CAS
CLEANUP_DISPATCHING --> CLEANUP_DISPATCHING: observe unresolved cleanup
CLEANUP_DISPATCHING --> COMPLETED: predecessor absent everywhere
COMPLETED --> LOCKED: versioned next operation
ABORTED --> LOCKED: versioned next operation
Edge cases¶
- Empty input publishes a verified empty generation on every member.
- Nulls and temporal/decimal values use the canonical typed-row encoder; an unsupported type blocks before member mutation.
- A lost load response never causes an append retry. Exact content completes the member; partial content triggers exact candidate replacement before replay.
- Process crash after member load but before Keeper CAS is reconciled from the candidate UUID and canonical content digest.
- Duplicate delivery is rejected by exact content, deterministic tokens, and replacement-not-append recovery.
- Schema or topology drift fences the operation.
- Partial DDL remains bound to the original queue entry; no second exchange is issued.
- Deep/nested types outside the canonical encoder profile are unsupported in this version and fail explicitly.
Architecture¶
Components and responsibilities¶
| Component | Existing/new | Responsibility | Dependencies |
|---|---|---|---|
| Cluster admission policy | extended | Static mode/engine rules and no-fallback decision | Pure manifest values |
| Inventory contract | extended | Uniform mode and opaque member identity | system.clusters facts |
| External authority contracts/codecs | new | V2 state, identities, per-member receipts | Pure values |
| External stage coordinator | new | Fence-before-stage, direct fan-out, replay/rebuild | Authority, member stage port |
| Member connection provider | new | Clone resolved connection for one admitted member | Composition root, connector |
| Member stage/catalog adapter | new | Local create/load/observe/drop and canonical digest | Direct member connector |
| External publication service | new | Barrier, one-shot DDL, reconcile, cleanup | Authority, catalog, DDL |
| Existing internal service | unchanged | V1 internal publication | Existing V1 ports |
| Cluster mode router | extended | Select internal/external only after exact admission | Both services |
| Receipt/evidence producer | extended | Versioned redacted evidence | V1/V2 codecs |
Ports, adapters, and composition root¶
Add narrow ReplicaConnectionProvider and ExternalReplicaStagingPort ports.
Topology discovery remains in the catalog adapter; it does not construct
clients. The composition root copies already-resolved credentials into a
member-local connector without exposing them to contracts or evidence. The
stage coordinator depends only on ports. Vendor SDK imports remain lazy.
The generic connector is not turned into a cluster service and no generic plugin registry is added. V1 internal code remains a separate strategy behind the cluster mode router.
Data and control flow¶
flowchart LR
M[Manifest external mode] --> I[Complete inventory]
I --> K[Keeper target fence]
K --> A[Immutable artifact receipt]
A --> S1[Stage member 1]
A --> S2[Stage member 2..N]
S1 --> B[All-member READY barrier]
S2 --> B
B --> C[Fenced one-shot cluster DDL]
C --> Q[Queue plus per-member reconciliation]
Q --> E[COMMITTED receipt]
E --> X[Exact predecessor cleanup]
Alternatives and tradeoffs¶
| Alternative | Advantages | Disadvantages | Decision |
|---|---|---|---|
| Direct per-member staging from one immutable artifact | Observable, exact recovery, no hidden fan-out | More connections, storage, and verification cost | Adopt |
Insert once through Distributed with false mode |
Small implementation | Hidden delivery retries and partial fan-out cannot prove exactly-once | Reject |
| Treat false as internal replicated topology | Reuses V1 | Official semantics send to every replica and can duplicate | Reject |
| Require operators to change to true | No code | Does not satisfy external topology | Reject |
| Generic cross-connector distributed transaction framework | Broad reuse | Speculative and disproportionate | Reject |
ADR requirement¶
Required. ADR 0069 records that external mode uses Keeper authority plus direct per-member staging while ADR 0067 remains authoritative for internal mode.
Quality-budget impact¶
New pure contracts, staging policy, adapters, and service modules remain split
by responsibility under the repository max_sloc: 400 limit. Shared admission,
router, schemas, and evidence codecs are integrator-owned. Import direction is
contracts -> ports -> runtime/adapters -> composition; no adapter imports enter
contracts.
Market comparison¶
Checked 2026-09-18 against current official primary sources.
| System/version | Relevant capability | Observed design | Strength | Limitation | Adopt/reject | Source/date |
|---|---|---|---|---|---|---|
| ClickHouse current docs | Distributed writes and replication flag | True sends to one healthy replica; false sends to every replica and does not check replica consistency | Defines the exact platform semantics | Does not provide dpone operation fencing or complete-generation publication | Adopt explicit mode matching; reject hidden Distributed fan-out | clickhouse.com/docs/reference/engines/table-engines/special/distributed, 2026-09-18 |
| ClickHouse current docs | KeeperMap | Linearizable writes, sequential reads, strict insert mode, shared ON CLUSTER facade |
Suitable target fence | Caller must handle ambiguous transport outcomes | Retain one-shot CAS and exact post-read | clickhouse.com/docs/reference/engines/table-engines/special/keepermap, 2026-09-18 |
| dlt current docs | Staging dataset for merge/replace | Loads into staging before destination mutation | Clear staging boundary | Does not document this ClickHouse per-member failure model | Adopt staging-first; add member evidence | dlthub.com/docs/dlt-ecosystem/staging, 2026-09-18 |
| Fivetran current docs | Full/table re-sync | Re-sync overwrites selected data and pauses incremental updates | Understandable operator workflow | Intermediate destination state may be unsuitable for readers; physical generation fencing is not exposed | Adopt explicit run status; reject unqualified read consistency claim | fivetran.com/docs/core-concepts/features, 2026-09-18 |
| Informatica | N/A | Managed integration product; no current public primary contract for ClickHouse internal_replication=false publication was identified |
N/A | Irrelevant to the physical member protocol | N/A | 2026-09-18 |
| Airbyte | N/A | Connector sync modes do not specify this physical ClickHouse member protocol | N/A | Different abstraction layer | N/A | 2026-09-18 |
| Pentaho | N/A | ETL orchestration does not define this ClickHouse publication primitive | N/A | Different abstraction layer | N/A | 2026-09-18 |
| Microsoft SSIS | N/A | Package execution does not define this ClickHouse publication primitive | N/A | Different abstraction layer | N/A | 2026-09-18 |
| gusty | N/A | DAG generation, not sink publication | N/A | Different layer | N/A | 2026-09-18 |
| Astronomer Cosmos | N/A | dbt orchestration, not sink publication | N/A | Different layer | N/A | 2026-09-18 |
| Apache Beam | N/A | Distributed processing/checkpointing, not ClickHouse physical table publication | N/A | Different ownership boundary | N/A | 2026-09-18 |
Measurable differentiation¶
axis: duplicate-free same-operation replay across externally replicated members
scenario: response loss after one member accepted a complete candidate load
baseline: naive retry of the same insert into every member
metric: duplicate logical rows per member and false-success count
target: 0 duplicate rows; 0 false successes; all members converge to one generation
procedure: run the two-member synthetic fault profile, lose the first load response,
retry the same scheduler operation, compare canonical content digests, and replay again
artifact: test_artifacts/clickhouse-external-publication/synthetic-receipt.json
limitations: local synthetic proof does not certify external networks, grants,
queue retention, server patches, or production workload performance
Security, privacy, and operations¶
- Reuse resolved credentials in memory only. Never place passwords, endpoints, source SQL, local paths, or row values in Keeper, evidence, logs, or errors.
- Evidence exposes opaque member IDs and digests only.
- Required grants cover local candidate create/insert/drop, target exchange or rename, cluster DDL observation, system catalogs, and KeeperMap CAS.
- Enforce source-byte, member-count, verification-time, and canonical-sort budgets. No silent partial inventory or async fire-and-forget insert.
- Alert on fenced foreign operation, staging divergence, terminal mixed publication, queue-evidence expiry, cleanup unknown, and topology drift.
- The recovery runbook forbids local fallback, blind exchange replay, manual candidate deletion without UUID evidence, and authority-row deletion.
Test and certification plan¶
| Layer | Scenario | Environment | Expected artifact |
|---|---|---|---|
| Unit | Mode/flag/engine matrix, identities, codec, redaction | Offline | Test report |
| Contract | One-shot member mutation, exact observation, V1/V2 compatibility | Offline fakes | Test report |
| Mocked integration | Stage -> validate -> publish -> cleanup; loss, replay, divergence | In-process synthetic ports | Machine-readable scenario receipt |
| Synthetic integration | Two members, false mode, direct local tables, exact multiset | Opt-in pinned Docker | local_synthetic receipt bound to commit/config |
| Fault integration | First-member interruption, lost load response, partial DDL, cleanup loss | Opt-in pinned Docker | Fault-matrix receipt |
| Live certification | Actual external topology, grants, retention, failure injection | Explicitly approved environment | UNVERIFIED until available |
| Performance | Canonical digest and N-member fan-out within declared budget | Synthetic bounded data | Benchmark JSON |
| Compatibility | All current internal/local tests and V1 receipt replay | Offline + existing Docker | Test report |
Skipped or unavailable live checks remain SKIP/UNVERIFIED, never PASS.
Documentation plan¶
- Add a tested generic manifest example using
analytics_cluster,source_table, andtarget_table. - Add a ClickHouse cluster-publication overview/how-to, exact reference, and operator recovery runbook.
- Document
check, plan JSON, runtime receipt, exit/error behavior, redaction, no-fallback semantics, limitations, and Python API parity. - Update ClickHouse, load-strategy, physical-design, configuration, source-sink, compatibility/migration, certification, matrix, navigation, and changelog pages.
- Reconcile stale V1 design/roadmap status without rewriting generated output.
Rollout and rollback¶
External mode is opt-in through the manifest; internal remains the default. Start with synthetic evidence, then an explicitly approved live environment. Disable external admission if duplicate, divergence, false success, evidence expiry, or performance budgets fail. Rollback preserves unresolved authority and tables for recovery. Post-release verification reruns V1 compatibility and the external fault profile at the exact release commit.
Agent execution plan¶
| Agent/role | Owned paths | Read-only paths | Forbidden paths | Dependency |
|---|---|---|---|---|
| Implementer: contracts | external contract/port modules and focused tests | approved spec, existing V1 | shared schemas, router, changelog, nav | Approved spec |
| Implementer: runtime | external staging/publication modules and focused tests | contracts, V1 services | shared schemas, changelog, nav | Contract commit |
| Test certifier | synthetic fixture/evidence and fault tests | implementation/spec | production modules, shared release indexes | Integrated runtime |
| Docs reviewer | user docs audit and proposed corrections | spec/diff | production code | Integrated behavior |
| Integrator | shared admission, router, composition, schemas, docs nav, changelog | all | none inside task scope | All owned results |
The primary agent is integrator and sole shared-file owner. Parallel writers use separate worktrees and validated task contracts.
Approval checklist¶
- User problem and CJM are clear.
- Algorithm and failure semantics are implementable without guessing.
- Public contracts and compatibility are explicit.
- Architecture and alternatives are justified.
- Relevant market research uses current official sources.
- Claimed differentiation is measurable.
- Tests, evidence, docs, rollout, and rollback are complete.
- Path ownership and integration plan are conflict-safe.
- Maintainer implementation authorization is recorded and status is
APPROVED.