Files
sencho/docs
Anso 3623ce2d89 feat(gitops): persist the observed apply invocation and classify invocation drift (#2032)
The invocation drift class had no producer because the observed compose
invocation was never persisted anywhere the deriver could read it. Emitting
the authored invocation against a permanent unknown would have been constant
fabricated drift, so the class was absent rather than wrong. This records the
observation and adds the producer that compares it.

What Compose was invoked with is read back off the running project's
container labels at apply time, not off the argv Sencho built, because
reading the argv back would only ever confirm what Sencho already believes.
It lands on a new nullable per-target column, and the column stays null when
the node cannot be reached, which is the same absence as never having
looked. A new producer compares that record against the invocation the
accepted generation was authored with, and reports nothing while either side
is missing, unreadable, or not comparable, naming each case in a caveat
rather than reporting agreement.

The single-file case is what the design turns on. Compose omits every flag
for a single-file selection, so a generation's argv is empty while the
observed label always names at least one file. The authored file order
therefore falls back to the application's configured compose selection, which
is what makes a true negative reachable on the majority of stacks instead of
a standing false positive. The comparison is Direct-only: a Blueprint target
is deployed under its own stack name from a generation whose argv was
authored for the source stack, so there is no correct expected side to
compare against and the class stays silent for it.

The read requires the project's containers to agree. An ordinary up recreates
only the services whose configuration changed, so a half-recreated project
carries labels from two invocations; a disagreement records nothing rather
than sampling whichever container the daemon listed first, which would flap
across applies and could report agreement while a sibling container
disagrees.

The history column for this observation already existed in the schema
without a writer, so the audit row now records the evidence rather than only
the fact that a column moved. A new target column is added additively for
existing installs, and a migrated target stays unobserved rather than being
backfilled with a value no apply recorded.

Validated over the live route: a differing invocation produces one item with
both identities real, a matching one produces nothing, and a missing
observation produces nothing plus a caveat. Unit coverage spans the
canonicalization, the label read, the three acceptance states, the additive
migration, and the drift row rendering.
2026-09-29 08:50:51 -04:00
..