fix(canvas): canonicalise Job.DependsOn entries with install- prefix — fix invisible edges (#1500)

PR #1499 plumbed spec.dependsOn end-to-end and verified deps populate
on first event (no /refresh-watch needed). But the openova-flow snapshot
composer (flow_snapshot_local.go) emits finish-to-start relationships
where fromId = jobs.JobID(deploymentID, dep). Without the "install-"
prefix on each dep entry, fromId came out as:

  <dep>:hel1-2:seaweedfs                 (secondary, missing "install-")
  <dep>:gitea                            (primary, missing "install-")

But the FlowNode ids in the snapshot are:

  <dep>:install-hel1-2:seaweedfs
  <dep>:install-gitea

The FE canvas adapter matches by exact id → every finish-to-start rel
points at a non-existent node → 224 rels emitted, 0 edges rendered.

Caught on prov t103.omani.works (005080699326a7ac, 2026-05-15):

  curl /v1/flows/.../snapshot → 376 rels total: 152 contains, 224 finish-to-start
  every finish-to-start fromId malformed
  canvas: sibling edges invisible across all 135 install Jobs

Fix in two places:

  internal/handler/phase1_watch.go (spawnSecondaryRegionWatchers emit):
    Region-prefix each dep AND inject the "install-" prefix so
    ev.DependsOn = ["install-<region>:<chart>"] before the bridge
    receives the event. Symmetric with how ev.Component is constructed.

  internal/jobs/helmwatch_bridge.go (OnHelmReleaseEvent):
    Canonicalise every dep entry: if it doesn't already start with
    JobNamePrefix ("install-"), prepend it. Idempotent on entries
    that already are canonical (set by the phase1_watch.go path).
    Covers the primary-region path (bare chart names like "gitea")
    too — Job.DependsOn now stores "install-gitea", which matches
    the composer's emitted FromId exactly.

Tests: go build ./... + go test on internal/jobs + helmwatch + provisioner
all green. (Pre-existing TestHandleWhoami_* flake in handler is unrelated.)

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
This commit is contained in:
e3mrah 2026-05-15 17:18:40 +04:00 committed by GitHub
parent 5b2c8b79a8
commit 80fdbcd8e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 3 deletions

View File

@ -477,12 +477,27 @@ func (h *Handler) spawnSecondaryRegionWatchers(dep *Deployment) func() {
// pointing at the PRIMARY region's bare-named jobs,
// and the canvas fan-out collapses cross-region edges
// that aren't real. helmwatch.processEvent populated
// ev.DependsOn from the live spec.dependsOn; we just
// rescope here.
// ev.DependsOn from the live spec.dependsOn (bare chart
// names like "gitea"); we both region-prefix AND inject
// the canonical "install-" prefix so the stored Job
// row's DependsOn matches the JobName scheme exactly.
//
// Why "install-<region>:<chart>" not "<region>:<chart>":
// the FE canvas adapter looks up node ids by exact match;
// node ids are `<dep>:install-<region>:<chart>` for
// install Jobs. Storing "<region>:<chart>" as a dep
// produces a `<dep>:<region>:<chart>` fromId in the
// finish-to-start relationship, which matches no node →
// edge invisible. Caught on prov t103.omani.works
// (005080699326a7ac, 2026-05-15): openova-flow snapshot
// had 224 finish-to-start rels emitted but their fromIds
// were `<dep>:hel1-2:seaweedfs` etc., missing "install-"
// → canvas rendered every secondary HR with no sibling
// edges despite the rel count being non-zero.
if len(ev.DependsOn) > 0 {
rescoped := make([]string, 0, len(ev.DependsOn))
for _, d := range ev.DependsOn {
rescoped = append(rescoped, region+":"+d)
rescoped = append(rescoped, "install-"+region+":"+d)
}
ev.DependsOn = rescoped
}

View File

@ -489,6 +489,33 @@ func (b *Bridge) OnHelmReleaseEvent(componentID, state, level, message string, t
dependsOn = []string{}
}
// Prepend the canonical JobNamePrefix ("install-") to every dep so
// the stored Job.DependsOn matches the format other Jobs use as
// their JobName. Without this, the openova-flow snapshot composer
// emits finish-to-start relationships with fromIds like
// "<dep>:hel1-2:seaweedfs" (missing "install-"), which match no
// FlowNode and the canvas renders every sibling-edge invisible.
// Caught on prov t103.omani.works (005080699326a7ac, 2026-05-15):
// 224 finish-to-start rels emitted, every fromId malformed.
//
// Three input shapes the watcher may emit:
// "cilium" (primary, bare chart) → "install-cilium"
// "hel1-2:cilium" (secondary, region-prefixed) → "install-hel1-2:cilium"
// "install-hel1-2:cilium"(already canonical, idempotent) → same
if len(dependsOn) > 0 {
canon := make([]string, 0, len(dependsOn))
for _, d := range dependsOn {
if d == "" {
continue
}
if !strings.HasPrefix(d, JobNamePrefix) {
d = JobNamePrefix + d
}
canon = append(canon, d)
}
dependsOn = canon
}
// Ensure the bootstrap-kit parent group exists before any leaf is
// written underneath it (idempotent — UpsertJob's merge preserves
// any prior row).