mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-10-26 13:40:26 +00:00
3623ce2d89
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.