State write protocol — dual-write contract¶
TL;DR
Business verbs (bump, seed, build, scan, deploy,
pipeline notify) pišu u oba: canonical ci-state.json +
per-service shard ci-state.<svc>.<env>[.<platform>].json. Preko
pipeline_state.write_state_with_mirrors. Razlog: shard-glob
fan-in (merge-state) hvata i raw canonical writes.
Problem bez dual-write¶
Pipeline A (parallel shard): piše ci-state.api.staging.json
Pipeline B (canonical flow): piše ci-state.json
Poslije: merge-state hvata ci-state.api.staging.json ALI NE
ci-state.json (jedna tačka u imenu, glob ne matchuje).
Rezultat: A-ov contribution propao.
Rješenje¶
from ci.pipeline_state import write_state_with_mirrors
# Svaki verb radi:
write_state_with_mirrors(
state=state,
canonical_path="ci-state.json",
services=("api", "worker"),
env="staging",
)
# → piše ci-state.json (canonical) + ci-state.api.staging.json + ci-state.worker.staging.json
Atomic write za oba:
- Temp file u istom dir-u (
ci-state.json.tmp,ci-state.<svc>.<env>.json.tmp). os.replace(tmp, target)— POSIX atomic rename.
Tri ograničenja¶
merge-stateNE koristi business-verb write path. Fan-in verb ima svoj read+merge; ne pozivawrite_state_with_mirrors.- Dual-write je compatibility bridge, ne zamjena za shard-based
fan-in. Paralelni step-ovi se i dalje oslanjaju na shard-ove +
merge-state. - Canonical
ci-state.jsonNIJE parallel-safe coordination surface. Za paralelne koriste se shard-ovi.
Shard path format¶
ci-state.json # canonical
ci-state.<svc>.<env>.json # per-service, per-env
ci-state.<svc>.<env>.<platform>.json # EAS deploy (per-platform)
Primjeri:
ci-state.json # canonical
ci-state.api.staging.json # api @ staging
ci-state.mobile.production.ios.json # mobile @ production, iOS only
ci-state.mobile.production.android.json # mobile @ production, Android
Discovery: pipeline_state.is_shard_path(path) —
ci-state.X.Y.json (sa najmanje 2 tačke) je shard; ci-state.json
(sa 1 tačkom) je canonical.
Šta NE piše u state¶
make ci-state-merge— čita, ne piše (samo merge-uje shard-ove u canonical).ci/state.pyCLI read — samo čita.bin/design,bin/check_arch_reminder.py— ne diraju state.
Failure modes¶
- Temp file write fail (disk full) → state write fail-uje; verb aborta, retry.
- Rename fail (permission) → verb aborta, ne partial-write.
- Shard dir ne postoji →
os.makedirs(parent, exist_ok=True).
Vidi i¶
03-ci-state-map.md— state field katalog01-two-schemas.md— zašto dva artifactaci/pipeline_state.py—write_state_with_mirrorssourceci/CLAUDE.md(root) — "Dual-write contract" sekcija