mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-10-25 21:20:25 +00:00
61b25f48d2
* feat(gitops): show per-target image digests and document the drift model The observed per-service digests already reached the projection, but the approved side did not, so a reader could see that two identities differed without ever seeing which digest each side held. The frozen artifact set's per-service evidence now rides along with the expected identity, and each target's card compares them per service: the approved digest beside the running one, the approved child for the platform that node actually runs, and matched, drifted, unverified, or not compared as the honest answer. The comparison follows the model's own rules, so the view cannot claim a match the projection does not, a stale or unqualified identity stays unverified, a built service is labelled not compared rather than matched, and a value that is not a content digest is ignored instead of compared. Adds the drift model reference the model was missing: the seven classes and what each is measured against, how to read an item, where each surface shows it, the states that are progress rather than drift, what Sencho cannot prove, and the four policy domains. The Blueprint page gains the digest-drift section it never had, trimmed to the Enforce mechanics. The end-to-end spec pins an approved digest, replaces the running workload with different content under the same project, and asserts the deployment reports the drift, the projection carries both digests, and the Drift tab renders the comparison without adopting what the tag now points at. * test(gitops): pin the digest drift spec to a resolvable repository The spec pinned a locally invented repository, e2e-digest-probe:<stamp>@sha256:..., which is not a reference any registry knows. That works or fails depending on what the local Docker version decides to do with a tag-and-digest reference that has no matching repo digest, and the observation filters the running image's repo digests by the authored repository, so an invented repository can never produce an observed digest at all. On a runner whose Docker resolves it differently, the deploy never lands and the spec waits out its poll. Both sides are now real upstream tags of one repository, so the approved reference resolves from the local content store without a registry call and the moved side is a real digest difference. The digests are read from the daemon per repository rather than trusting Docker's ordering, and the two sets are asserted disjoint before anything runs, so two tags that resolve to one manifest fail by name instead of by timeout. The spec also stopped assuming things it never checked. The baseline is proven from the daemon, because the container that was actually created from the approved reference is the ground truth for what is running, and reading it costs one call where waiting for the projection's observation costs a reconciler tick. Every poll now asserts its status, so an API error reports itself instead of surfacing as a timeout, the apply retry is limited to the stale-preview case the UI asks the operator to confirm again, Docker calls are bounded, teardown clears its handle only after a confirmed delete and then checks the containers are actually gone, and a Docker that is installed but broken fails instead of skipping. Verified against local dev servers across four runs at 16 to 55 seconds each, with no leftover images, containers, or override files, and type-clean under a strict invocation. * test(gitops): prove Enforce repairs to the approved digest, not the moved tag The digest drift spec proves detection. It does not prove repair, because it runs the Blueprint in observe mode, and the Inline path is not the one that repairs. The Git-managed loop re-observes a drifted target and applies the configured drift mode, so that is where the repair mechanic lives, and it now has a test of its own. The test starts from a genuinely drifted target rather than an assumed one. The fixture seeds a newer candidate artifact set carrying a moved digest, points the latest pointer at it while the approved and last-known-good pointers stay on the original, and records a runtime observation carrying the moved digest. That starting state is asserted before repair runs, so a fixture that quietly stopped seeding it fails instead of passing on a correct-looking end state. Repair then has to do the one thing that matters: hand the deploy the approved platform child digest, take it from the accepted artifact set rather than the most recent resolution or the running image, and leave every pointer that says what was approved exactly where it was. The observation still reads as drifted afterwards, because repair changes what runs, not what was agreed. The test is mutation-checked. Pointing repair at the latest artifact set instead of the expected one makes it fail with the moved digest, which is the bug this exists to catch. The taxonomy page also records the settings-only reconcile decision properly: source drift compares commits, so a change of compose path, env path, or context directory creates no expected-versus-observed pair and no drift item. It surfaces as reconcile required, and for a Direct application that is where you fetch again. The page says plainly that this is a choice about what the word drift means, not proof that the materialized content was unchanged, because changing where Compose is read from can change the content. The portfolio page no longer keeps its own copy of the class list. It names the classes by reference to the drift model page, so the two cannot disagree. Verified: backend typecheck and lint clean, 9515 backend tests passing, frontend typecheck clean with zero lint errors and 3457 tests across 347 files, docs config parses. * test(gitops): pin a settings-only reconcile as attention, not drift The decision is recorded on the taxonomy page: a change to the compose path, env path, or context directory, with the accepted commit still matching the ref, creates no source drift item. Source drift compares commits, and that shape has no expected-versus-observed pair of commits. That decision needed a test to hold it, and the coverage that existed asserted the facet status and the offered action without ever asserting that no source item is emitted. The behavior was therefore unpinned in both directions: nothing would have failed if the producer started reporting it, and nothing would have failed if it stopped. This adds the missing half. The fixture is the decided case exactly: same commit, different materialization fingerprint. No source drift item, the facet reads reconcile required, and fetch is offered. It is mutation-checked, and dropping the commit comparison from the producer makes it fail, so it holds the line rather than merely restating it.