Zašto dva artefakta — services.json vs ci-state.json¶
TL;DR
services.json je statički registar (commit-permanent, šta
servis JESTE). ci-state.json je dinamički state (per-run,
šta servis RADI upravo). Miješanje ove dvije uloge je najčešći
drift pattern — drži ih odvojene.
Uloge¶
| Artifact | Kad se mijenja | Ko čita | Ko piše |
|---|---|---|---|
services.json |
Nikad za vrijeme pipeline-a (commit-only) | ci/service_manifest.py |
developer (commit) |
ci-state.json |
Svaki verb (bump/seed/build/scan/deploy/notify) | ci/pipeline_state.py |
business verbs |
service_manifest.py je read-only za services.json — nijedan
verb ne smije da piše u njega za vrijeme pipeline-a.
pipeline_state.py je read+write za ci-state.json — jedini
dozvoljeni writer. Raw file writes iz verb-ova su zabranjeni.
Šta živi gdje¶
services.json (komitovan)¶
{
"schema": "https://schemas.infopuls.app/services/v31.json",
"environments": {
"production": { "infisical_env": "prod" }
},
"services": {
"api": {
"path": "apps/api",
"build": { "enabled": true, "kind": "docker", ... },
"release": { "enabled": true, "scheme": "semver", ... },
"deploy": { "enabled": true, "mode": "coolify", ... },
"observability": { "sentry": { ... } }
}
}
}
Owner: developer. Lifecycle: commit, tag, release.
Schema: ci/json/services.schema.json (hard-cut to v31).
ci-state.json (per-run, gitignored)¶
{
"pipeline": {
"deployment_type": "production",
"release_commit": "abc123...",
"release_mode": true,
"head_commit": "def456..."
},
"services": {
"api": {
"version": "1.2.3",
"image_tag": "1.2.3",
"image": "infopuls/api:1.2.3",
"build": { "status": "deployed", "duration_seconds": 245 },
"deploy": { "status": "deployed", "task_definition_arn": "..." }
}
}
}
Owner: CI. Lifecycle: per-run, atomic write.
Schema: ci/json/ci-state.schema.json (v10).
Tri invarianta (ne smije se kršiti)¶
services.jsonje statički input;ci-state.jsonje dinamički output. Ne miješaj uloge.- Tri selection liste znače različite stvari i ostaju odvojene:
versioned_services— ko ima verzijubuild_services— ko se gradi ovaj rundeploy_services— ko se deploy-uje ovaj run- Schema i kod se mijenjaju zajedno. Promjena shape-a bez loader-a/recorder-a je drift.
Kada šta čitati¶
# services.json (kroz jedini loader)
from ci.service_manifest import load_manifest
manifest = load_manifest("services.json")
build_kind = manifest.services["api"].build.kind # "docker"
# ci-state.json (kroz jedini reader)
from ci.pipeline_state import load_state
state = load_state("ci-state.json")
image_tag = state.services["api"].image_tag # "1.2.3"
Nikad raw json.load(open("services.json")) u verb kodu.
Vidi i¶
02-services-json-map.md— field catalog03-ci-state-map.md— state field catalog12-state-write-protocol.md— dual-writeci/CLAUDE.md(root) — "Core Artifacts" sekcijaci/service_manifest.pyci/pipeline_state.py