feat(causal-engine): umbrella proposal + Phase-0 (state-change feed, Gap B, Gap G handoff) #3519

Open
mfreeman451 wants to merge 30 commits from feat/causal-engine-v1 into staging
Owner

Summary

Introduces the add-causal-engine OpenSpec umbrella proposal for ServiceRadar's DeepCausality causal engine and lands Phase 0 of it.

The engine's value is automation — events → alerts → state enrichment → prediction — with the God-View topology renderer as one optional consumer. Today DeepCausality backs a misplaced 244-line reactive stub in god_view_nif; the proposal ships a real single-pod fused rust/causal-engine on the existing CNPG/SRQL/AGE substrate and closes the loop by publishing predictions that re-enter StatefulAlertEngine.

Proposal (openspec/changes/add-causal-engine/)

  • Validates openspec validate --strict (49 requirements / 131 scenarios).
  • 11 capability deltas — 6 ADDED (causal-engine, causal-reasoning, causal-prediction-signals, inventory-risk-feed, service-flow-bridge, device-components), 5 MODIFIED (observability-signals, age-graph, health-events, topology-causal-overlays, topology-god-view).
  • Phased V1 + Gaps A–G; design.md records the four key decisions and the reversible god_view_nif cutover. The three authoritative design docs are vendored under docs/docs/.

Phase-0 implementation (ServiceRadar-owned slice)

  • Gap B — capacity eligibility: network_discovery/topology_graph.ex now marks edges without a populated capacity_bps (min-of-both-ends speed_bps/if_speed) ineligible, so the saturation causaloid (C6) skips them rather than treating absent capacity as zero/infinite. Refines the existing telemetry_eligible field; no new schema column. Coverage audit SQL in runbooks/gap-b-capacity-audit.sql.
  • Decision-1 state-change feed: new ServiceRadar.EventWriter.StateChangePublisher emits app-level state transitions to cdc.platform.<table> over NATS — default-disabled (STATE_CHANGE_EVENTS_ENABLED / :state_change_events_enabled), fire-and-forget, never hypertables, and not pgoutput CDC / logical replication. Hooked health_events (HealthTracker), service_state (ServiceStateRegistry, gated pre-fetch + transition diff), and ocsf_devices (sync_ingestor bulk path, COALESCE-aware diff). Pure unit test for the envelope + gating.
  • Gap G: routed to the DeepCausality author — runbooks/gap-g-ultragraph-handoff.md specs the StructuralGraphAlgorithms trait (articulation points / bridges / reachability / pathway centrality / unfreeze) and the six causaloids that gate on it. ServiceRadar does not fork ultragraph.

Deferred (tracked in tasks.md)

Virtualization + AGE-projection transition hooks, the cdc.platform.> JetStream stream + Phase-1 consumer (held back so app startup isn't coupled to a not-yet-existing processor), and an optional risk_score rollup hook.

Testing

All touched Elixir was syntax-parsed locally (Code.string_to_quoted); full compile + credo + the publisher unit test run in CI (no local deps fetched). openspec validate --strict passes. No Bazel BUILD change needed (serviceradar_core globs sources).

Per the OpenSpec gate this proposal is not yet approved — opening for CI (a real compile/credo gate on the Phase-0 Elixir) and review; implementation continues on the branch.

🤖 Generated with Claude Code

## Summary Introduces the **`add-causal-engine`** OpenSpec umbrella proposal for ServiceRadar's DeepCausality causal engine and lands **Phase 0** of it. The engine's value is **automation** — events → alerts → state enrichment → prediction — with the God-View topology renderer as one optional consumer. Today DeepCausality backs a misplaced 244-line reactive stub in `god_view_nif`; the proposal ships a real single-pod fused `rust/causal-engine` on the existing CNPG/SRQL/AGE substrate and closes the loop by publishing predictions that re-enter `StatefulAlertEngine`. ## Proposal (`openspec/changes/add-causal-engine/`) - Validates `openspec validate --strict` (49 requirements / 131 scenarios). - 11 capability deltas — **6 ADDED** (`causal-engine`, `causal-reasoning`, `causal-prediction-signals`, `inventory-risk-feed`, `service-flow-bridge`, `device-components`), **5 MODIFIED** (`observability-signals`, `age-graph`, `health-events`, `topology-causal-overlays`, `topology-god-view`). - Phased V1 + Gaps A–G; `design.md` records the four key decisions and the reversible `god_view_nif` cutover. The three authoritative design docs are vendored under `docs/docs/`. ## Phase-0 implementation (ServiceRadar-owned slice) - **Gap B — capacity eligibility:** `network_discovery/topology_graph.ex` now marks edges without a populated `capacity_bps` (min-of-both-ends `speed_bps`/`if_speed`) ineligible, so the saturation causaloid (C6) skips them rather than treating absent capacity as zero/infinite. Refines the existing `telemetry_eligible` field; no new schema column. Coverage audit SQL in `runbooks/gap-b-capacity-audit.sql`. - **Decision-1 state-change feed:** new `ServiceRadar.EventWriter.StateChangePublisher` emits app-level state transitions to `cdc.platform.<table>` over NATS — **default-disabled** (`STATE_CHANGE_EVENTS_ENABLED` / `:state_change_events_enabled`), fire-and-forget, never hypertables, and **not** pgoutput CDC / logical replication. Hooked `health_events` (HealthTracker), `service_state` (ServiceStateRegistry, gated pre-fetch + transition diff), and `ocsf_devices` (sync_ingestor bulk path, COALESCE-aware diff). Pure unit test for the envelope + gating. - **Gap G:** routed to the DeepCausality author — `runbooks/gap-g-ultragraph-handoff.md` specs the `StructuralGraphAlgorithms` trait (articulation points / bridges / reachability / pathway centrality / unfreeze) and the six causaloids that gate on it. ServiceRadar does not fork `ultragraph`. ## Deferred (tracked in `tasks.md`) Virtualization + AGE-projection transition hooks, the `cdc.platform.>` JetStream stream + Phase-1 consumer (held back so app startup isn't coupled to a not-yet-existing processor), and an optional `risk_score` rollup hook. ## Testing All touched Elixir was syntax-parsed locally (`Code.string_to_quoted`); full compile + credo + the publisher unit test run in CI (no local deps fetched). `openspec validate --strict` passes. No Bazel BUILD change needed (`serviceradar_core` globs sources). > Per the OpenSpec gate this proposal is **not yet approved** — opening for CI (a real compile/credo gate on the Phase-0 Elixir) and review; implementation continues on the branch. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author the OpenSpec umbrella change `add-causal-engine` for the
DeepCausality causal engine: a single-pod fused `rust/causal-engine`
service consuming EmbeddedSrql + JetStream + app-level NATS state-change
events, reasoning over ultragraph CSR, and emitting verdicts on
`signals.causal.predictions` that re-enter StatefulAlertEngine (the
automation loop) and the existing God-View renderer.

Covers the full roadmap as 11 capability spec deltas (6 ADDED, 5
MODIFIED) plus proposal/design/tasks, phased V1 + Gaps A-G:
- ADDED: causal-engine, causal-reasoning, causal-prediction-signals,
  inventory-risk-feed, service-flow-bridge, device-components
- MODIFIED: observability-signals, age-graph, health-events,
  topology-causal-overlays, topology-god-view

Decisions: app-level NATS state-change events (NOT pgoutput CDC);
Gap G as a committed upstream ultragraph dependency; package<->CVE
matching delegated to add-cti-signal-coverage; the inventory->engine
risk seam authored here. Composes with the in-flight attributed-flow
correlation (a partial Gap A down-payment). Validates
`openspec validate --strict` (49 requirements / 131 scenarios).

Also vendors the three design docs (Integration-assessment,
unblock-capabilities, causal-engine-integration-points) onto this branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implements the ServiceRadar-owned slice of add-causal-engine Phase 0.

Gap B (task 0.2): network_discovery/topology_graph.ex telemetry_status_fields/4
now requires a populated capacity_bps (min-of-both-ends from speed_bps/if_speed)
in addition to observed flow before an edge is telemetry_eligible, so the
saturation causaloid (C6) skips capacity-less edges rather than treating absent
capacity as zero/infinite. Refines the existing telemetry_eligible field; no new
schema column. Coverage audit SQL added at
openspec/changes/add-causal-engine/runbooks/gap-b-capacity-audit.sql.

Decision-1 state-change feed (task 0.3, partial): new
ServiceRadar.EventWriter.StateChangePublisher publishes app-level state
TRANSITIONS to cdc.platform.<table> over NATS (default-disabled via
STATE_CHANGE_EVENTS_ENABLED / :state_change_events_enabled; fire-and-forget;
NOT pgoutput CDC, NOT logical replication, never hypertables). Hooked:
- health_events via HealthTracker.record_state_change/3 (old/new in hand)
- service_state via ServiceStateRegistry.upsert_from_status/1 (gated pre-fetch
  + transition diff; composite service identity per Decision 2)
Per-table canonical identity, before/after, partition_id, monotonic seq,
event_time, and event_identity (engine dedupes on event_identity). Pure unit
test for envelope + gating.

Deferred (tasks 0.3.1d/0.3.1e/0.3.5, new follow-up): the ocsf_devices
bulk-path hook in sync_ingestor.ex, virtualization/AGE-projection hooks, and
the cdc.platform.> JetStream stream + Phase-1 consumer. Gap G (task 0.1) is an
upstream ultragraph PR (deepcausality-rs) left for author coordination.

Elixir syntax-parsed locally (Code.string_to_quoted); full compile/credo gated
in CI (no local deps). openspec validate --strict passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): ocsf_devices state-change hook + Gap G handoff
Some checks failed
lint / lint (push) Successful in 1m12s
Helm Lint / Helm Lint (pull_request) Successful in 20s
Secret Scan / gitleaks (pull_request) Successful in 28s
Golang Tests / test-go (push) Successful in 1m38s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m7s
lint / lint (pull_request) Successful in 1m10s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
961918369e
Completes the device-availability slice of the add-causal-engine Decision-1
state-change feed (task 0.3.1d):

- inventory/sync_ingestor.ex: before the bulk upsert_devices, gated pre-fetch
  of prior is_available/is_managed by uid (StateChangePublisher.enabled?/0
  guards the extra read); after {:ok, remap}, diff against the records and
  publish a cdc.platform.ocsf_devices transition per changed device, keyed by
  the remapped final sr: uid. COALESCE-aware: only a non-nil incoming value
  that differs from the stored one is treated as a transition (matches the
  device upsert's COALESCE(EXCLUDED.x, stored)). risk_score transitions
  deferred (separate DeviceRiskReducer rollup hook). Best-effort + rescued;
  never affects ingestion.

- Gap G (task 0.1) routed to the DeepCausality author: handoff spec at
  runbooks/gap-g-ultragraph-handoff.md (StructuralGraphAlgorithms trait —
  articulation_points/bridges/biconnected_components/is_reachable/
  pathway_betweenness_centrality + unfreeze, ~200 LOC Tarjan; tests; the six
  causaloids that gate on it). ServiceRadar does not fork ultragraph.

Remaining Phase-0/1 deferred: virtualization + AGE-projection hooks, the
cdc.platform.> JetStream stream + Phase-1 consumer. Elixir syntax-parsed
locally; full compile/credo + the publisher unit test gated in CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(causal-engine): Gap G resolved upstream — ultragraph 0.9.0 already ships it
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 19s
Secret Scan / gitleaks (pull_request) Successful in 33s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m6s
lint / lint (pull_request) Successful in 1m26s
Golang Tests / test-go (push) Successful in 1m41s
lint / lint (push) Successful in 1m49s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
ca6d75df98
On inspecting deepcausality-rs/deep_causality, ultragraph 0.9.0 (published
2025-08-27, on crates.io) already implements the full Gap G surface with real
code — StructuralGraphAlgorithms (strongly_connected_components /
articulation_points / bridges / biconnected_components),
pathway_betweenness_centrality(pathways, directed, normalized), is_reachable,
and unfreeze. The docs' "implement upstream" framing was an artifact of being
written against the 0.8 the NIF pins.

No DeepCausality PR is needed: ServiceRadar just depends on `ultragraph = "0.9"`
in rust/causal-engine, unblocking the six graph causaloids (C4/C5/C5b/C7/C8/C9)
immediately with no upstream wait.

- proposal.md, design.md (Decision 2 + risk + goals), tasks.md (0.1, 1.1.3,
  1.4.2/1.4.3) reframed from "upstream PR" to "ultragraph 0.9 version bump".
- Replaced runbooks/gap-g-ultragraph-handoff.md with gap-g-resolution.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(causal-engine): land Gap G resolution edits (ultragraph 0.9 bump)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 20s
Secret Scan / gitleaks (pull_request) Successful in 32s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m0s
lint / lint (push) Successful in 1m15s
Golang Tests / test-go (push) Successful in 1m44s
lint / lint (pull_request) Successful in 1m53s
CI / build (pull_request) Failing after 11m43s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
3e4c8fac98
Follow-up to ca6d75df9 (which removed the now-moot handoff runbook). Carries the
actual reframing from "implement Gap G upstream" to "depend on ultragraph 0.9":
- proposal.md Gap G bullet, design.md Decision 2 + risk + goals, tasks.md 0.1 /
  1.1.3 / 1.4.2 / 1.4.3
- new runbooks/gap-g-resolution.md documenting that ultragraph 0.9.0 already
  ships StructuralGraphAlgorithms + pathway_betweenness_centrality + is_reachable
  + unfreeze (no DeepCausality PR needed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): scaffold rust/causal-engine crate (Phase 1.1)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 27s
lint / lint (push) Has been cancelled
Golang Tests / test-go (push) Has been cancelled
lint / lint (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Has been cancelled
Secret Scan / gitleaks (pull_request) Has been cancelled
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 52s
Rust Add-on Interop Test / interop (push) Successful in 2m16s
39f93ace50
New top-level workspace crate for the DeepCausality engine — single binary,
single pod, fused (hydrator + reasoner in-process). Modules:
- context_hydrator: ContextStore trait (hydrator<->reasoner seam, preserves a
  future split) + ContextHydrator stub
- domain_model: V1 entity types (Context/Device/Service) keyed by canonical sr: ids
- reasoner: Verdict/Classification + Reasoner stub (CausaloidGraph TODO 1.3)
- emitter: signals.causal.predictions publisher stub (TODO 1.6)
- snapshot: restart-snapshot stub (TODO 1.7)
- config (CAUSAL_ENGINE_* via envy) + error (thiserror)
main.rs wires a fused reasoning tick loop (hydrate -> reason -> emit).

Heavy integration deps are deferred to the increment that first uses them
(srql + async-nats in 1.2; ultragraph 0.9 + deep_causality in 1.3) to keep each
crate_universe change scoped. Added to workspace members + Cargo.lock;
BUILD.bazel mirrors rust/srql (all_crate_deps).

Verified: cargo check, cargo clippy --all-targets -D warnings, cargo fmt
--check, and bazel build //rust/causal-engine:{causal_engine_lib,causal_engine_bin}
--config=ci (RBE) all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
build(causal-engine): update MODULE.bazel.lock for the new workspace crate
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 22s
Secret Scan / gitleaks (pull_request) Successful in 41s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m13s
lint / lint (pull_request) Successful in 2m5s
lint / lint (push) Successful in 2m22s
Golang Tests / test-go (push) Successful in 2m36s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
e8323e87ba
The crate_universe from_cargo lock records the rust/causal-engine/Cargo.toml
entry plus refreshed Cargo.lock/Cargo.toml hashes — committed so RBE/CI builds
reproducibly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): emitter publishes signals.causal.predictions (Phase 1.6)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 20s
Secret Scan / gitleaks (pull_request) Successful in 46s
lint / lint (pull_request) Successful in 1m22s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 1m28s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m13s
Golang Tests / test-go (push) Successful in 1m41s
lint / lint (push) Successful in 1m55s
Rust Add-on Interop Test / interop (push) Successful in 2m11s
CI / build (pull_request) Failing after 12m42s
Elixir Quality / Elixir Quality (pull_request) Failing after 15m10s
142d4e8ec2
rust/causal-engine/src/emitter.rs: Emitter connects NATS JetStream (async_nats
0.48) and publishes one message per verdict on signals.causal.predictions.<entity>
with a DETERMINISTIC event_identity (pred:<entity>:<classification>) so
re-emission is idempotent (CausalSignals dedupes on it). The OCSF-compatible
envelope (signal_type "causal"; event_type mapped to the God-View 4 buckets;
source_identity / routing_correlation) mirrors what the existing CausalSignals
processor normalizes into ocsf_events — the signals.causal.* prefix already
routes, so no new inbound plumbing. main.rs connects the emitter at startup.

Deps async-nats 0.48 + chrono added (both already in the workspace lock).
Verified: cargo clippy --all-targets -D warnings, cargo test (3 pass), cargo
fmt --check, and bazel build //rust/causal-engine:{causal_engine_lib,
causal_engine_bin,causal_engine_test} --config=ci (RBE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): hydrator current-state snapshot via EmbeddedSrql (1.2 feed 1)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 35s
Secret Scan / gitleaks (pull_request) Successful in 36s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 45s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 53s
lint / lint (pull_request) Successful in 1m24s
lint / lint (push) Successful in 1m32s
Golang Tests / test-go (push) Successful in 1m41s
Rust Add-on Interop Test / interop (push) Successful in 1m48s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
a753e8d1b7
ContextHydrator::connect() opens a CNPG pool through EmbeddedSrql (srql path
dep, srql AppConfig::from_env), and current_context() hydrates the Context from
SRQL (in:devices, in:services) via QueryEngine::execute_query, mapping result
rows to domain_model Device/Service. Single-point identity validation: device
rows without a canonical sr: uid are skipped (the engine never forks the ID
space). Service identity is the composite agent_id:service_type:service_name
(Decision 2). Unit-tested row mappers; main.rs connects the hydrator at startup.

Feeds 2/3 (JetStream signals.causal.> + cdc.platform.<table> live deltas),
broader entity coverage, and endpoint-cluster-summary handling land in 1.2b.

Dep: srql = { path = "../srql" }; BUILD.bazel deps //rust/srql:srql_lib.
Verified: cargo check, cargo clippy --all-targets -D warnings, cargo test
(6 pass), cargo fmt --check, bazel build //rust/causal-engine:{causal_engine_lib,
causal_engine_bin,causal_engine_test} --config=ci (RBE, 1097 actions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): cdc.platform delta parse/apply core (Phase 1.2 feed 3 core)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 20s
Secret Scan / gitleaks (pull_request) Successful in 31s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 46s
lint / lint (pull_request) Successful in 1m32s
lint / lint (push) Successful in 1m36s
Golang Tests / test-go (push) Successful in 1m49s
CI / build (pull_request) Failing after 7m29s
Elixir Quality / Elixir Quality (pull_request) Failing after 11m10s
27426970dc
New `delta` module: parse_state_change parses the cdc.platform.<table> envelope
(the Phase-0 StateChangePublisher format) into a typed StateChangeDelta, and
apply_delta mutates the in-memory Context for ocsf_devices (is_available/
is_managed) and service_state (available). Pure + unit-tested (11 crate tests
total). The async JetStream subscriber that maintains a shared Context and
applies these deltas between EmbeddedSrql snapshots is the next sub-step (1.2b).

No new deps. Verified: cargo clippy --all-targets -D warnings, cargo test
(11 pass), cargo fmt --check, bazel build //rust/causal-engine:{lib,test}
--config=ci (RBE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
refactor(causal-engine): rename cdc.platform.* -> signals.state.* (it's NATS, not CDC)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 23s
Secret Scan / gitleaks (pull_request) Successful in 33s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 47s
lint / lint (pull_request) Successful in 1m25s
lint / lint (push) Successful in 1m33s
Golang Tests / test-go (push) Successful in 2m0s
CI / build (pull_request) Failing after 9m23s
Elixir Quality / Elixir Quality (pull_request) Failing after 10m44s
8d5f5c2153
The app-level state-change feed (Decision 1) publishes to NATS JetStream — it was
never pgoutput CDC / logical replication. The cdc.platform.<table> subject name
(carried from the design doc) implied otherwise and caused confusion. Renamed the
subject to signals.state.<table>, the telemetry event to
[:serviceradar, :state_change, :published], and the envelope signal_type to
"state_change", across StateChangePublisher + the core-elx hooks, the engine's
delta module/docs, the proposal/design/tasks, and the observability-signals /
causal-engine spec deltas (+ the publisher unit test). The "NOT pgoutput CDC"
clarifications are kept (they now read correctly against signals.state).

No behavior change. Verified: cargo clippy --all-targets -D warnings + test (11)
+ fmt, elixir syntax-parse, openspec validate --strict.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): live signals.state.> subscriber + shared Context (1.2 feed 3)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 26s
Secret Scan / gitleaks (pull_request) Successful in 34s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 44s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 55s
lint / lint (pull_request) Successful in 1m28s
Golang Tests / test-go (push) Successful in 1m33s
Rust Add-on Interop Test / interop (push) Successful in 1m54s
lint / lint (push) Successful in 2m9s
CI / build (pull_request) Failing after 9m52s
Elixir Quality / Elixir Quality (pull_request) Failing after 11m13s
2bc9bcd86c
Push-input wired for V1 (per the input-strategy decision):
- nats.rs: TLS-aware NATS connect helper (mTLS via CAUSAL_ENGINE_NATS_* cert
  paths) returning the core Client + a JetStream context; used by both the
  subscriber and the emitter.
- context_hydrator: now holds a shared Arc<RwLock<Context>> — seeded by an
  initial EmbeddedSrql snapshot on connect, refreshed periodically (refresh()),
  and read via current_context() (clone under read lock). shared_context() hands
  the Arc to the subscriber.
- subscriber.rs: best-effort core-NATS subscription to signals.state.> that
  parses StateChangePublisher envelopes (delta.rs) and applies deltas to the
  shared Context between refreshes. Durability/correctness comes from the
  periodic refresh, so no JetStream stream/consumer/ack is needed for V1
  (Phase-2 reactivity/scale concern).
- emitter: refactored to Emitter::new(jetstream) over the shared connection.
- main: connect NATS once, spawn the subscriber, run dual cadences (reason tick
  + slower refresh tick) via tokio::select!.

Config gains nats_ca_file/nats_cert_file/nats_key_file + refresh_interval_ms.
Dep: futures 0.3 (StreamExt; already in the workspace lock). Verified: cargo
check, cargo clippy --all-targets -D warnings, cargo test (11), cargo fmt
--check, bazel build //rust/causal-engine:{causal_engine_lib,causal_engine_bin,
causal_engine_test} --config=ci (RBE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(sr-testing): restricted-PodSecurity securityContext on the NATS deployment
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 22s
Secret Scan / gitleaks (pull_request) Successful in 31s
lint / lint (push) Successful in 1m12s
lint / lint (pull_request) Successful in 1m13s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m16s
Golang Tests / test-go (push) Successful in 1m54s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
0b274da26c
The sr-testing namespace enforces PodSecurity "restricted:latest", which had
been forbidding the sr-testing-nats pod (FailedCreate: no securityContext) —
leaving the Services + TLS secret orphaned with 0 pods. Add a restricted-
compliant securityContext: runAsNonRoot + runAsUser/Group 1000 + fsGroup
(JetStream writes its store dir on an fsGroup-owned emptyDir), seccompProfile
RuntimeDefault, allowPrivilegeEscalation=false, drop ALL capabilities.

Pod now Running 1/1; JetStream + TLS up; reachable at the external LB
23.138.124.18:4222. This restores the test NATS used to runtime-test the
causal-engine subscriber/emitter (signals.state.> / signals.causal.predictions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(causal-engine): drop residual CDC verbiage from tasks.md
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 15s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 42s
Secret Scan / gitleaks (pull_request) Successful in 52s
lint / lint (push) Successful in 1m13s
lint / lint (pull_request) Successful in 1m26s
Golang Tests / test-go (push) Successful in 2m3s
CI / build (pull_request) Failing after 9m13s
Elixir Quality / Elixir Quality (pull_request) Failing after 14m38s
62c9ae72cb
The state-change feed is an app-level NATS publish, not CDC; remove the
lingering 'NOT pgoutput CDC / NOT logical replication' clarifier now that the
cdc.platform -> signals.state rename has landed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge feat/endpoint-sbom-ingestion into feat/causal-engine-v1
Some checks failed
lint / lint (push) Successful in 1m27s
Helm Lint / Helm Lint (pull_request) Successful in 23s
Golang Tests / test-go (push) Successful in 2m9s
Rust Tests / test-rust (//rust/rperf-server:rperf, rust/rperf-server, bazel) (push) Successful in 2m21s
Secret Scan / gitleaks (pull_request) Successful in 38s
Rust Tests / test-rust (rust/rdp-adapter, cargo) (push) Successful in 2m32s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Successful in 2m49s
Rust Tests / test-rust (//rust/netprobe:netprobe, //build/platforms:linux_x86_64_musl, rust/netprobe, bazel-static) (push) Successful in 2m49s
Rust Add-on Interop Test / interop (push) Successful in 2m51s
Rust Tests / test-rust (//rust/netprobe:netprobe, //build/platforms:linux_aarch64_musl, rust/netprobe, bazel-static) (push) Successful in 2m53s
Rust Tests / test-rust (rust/rperf-client, cargo) (push) Successful in 3m20s
lint / lint (pull_request) Successful in 1m59s
Rust Tests / test-rust (rust/trapd, cargo) (push) Successful in 3m34s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m50s
Rust Tests / test-rust (rust/consumers/zen, cargo) (push) Successful in 3m44s
Rust Tests / test-rust (rust/log-collector, cargo) (push) Successful in 4m1s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
Rust Tests / test-rust (//rust/netprobe:netprobe_test, rust/netprobe, bazel-test) (push) Successful in 4m24s
Rust Tests / test-rust (rust/rdp-connector-probe, cargo) (push) Successful in 4m43s
Rust Tests / test-rust (rust/srql, cargo) (push) Successful in 6m8s
80097d807b
Bring the endpoint-SBOM inventory feature (endpoint_inventory_ingestor +
endpoint_inventory_* resources/tables) onto the causal-engine branch so the
inventory-risk-feed (task 1.8) can wire the engine's DeviceRiskReducer
contribution + signals.causal.inventory emission against the REAL ingestor —
which is not yet on staging (staging still has the older pre-scale design).

The causal-engine work builds on top of the inventory (intended dependency
order); these SBOM commits drop out on rebase once that feature lands on
staging. Clean auto-merge — topology_graph.ex reconciled the Gap B
telemetry-eligibility edit with the inventory changes; cargo check green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(causal-engine): mark 1.8/1.9 delivered by the merged endpoint-SBOM feature
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 19s
Secret Scan / gitleaks (pull_request) Successful in 30s
lint / lint (pull_request) Successful in 1m30s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m19s
lint / lint (push) Successful in 1m46s
Golang Tests / test-go (push) Successful in 2m10s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
1bdbc82508
After merging feat/endpoint-sbom-ingestion, the inventory-risk-feed (1.8) and
automation-loop (1.9) are already implemented in the inventory feature:
- EndpointInventoryVulnerabilityRisk -> DeviceRiskReducer (source "endpoint_inventory", CVSS-scored)
- EndpointInventoryHistory -> signals.causal.inventory.<event_type>
- topology_graph.ex pkg_* Device scalars (project_vulnerability_risk_summary)
- causal_signals.ex OCSF class_uid 2004 vuln findings + inventory alert evaluation

The engine consumes per-device risk via ocsf_devices.risk_score (hydrator
map_device already reads it); composing risk into causaloids C5/C7/C10 is the
reasoner (1.5, Marvin's DeepCausality domain). Resolves the cti boundary (D1):
inventory scores vulnerability-match payloads itself.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): Context snapshot persistence + restore (Phase 1.7)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 26s
Secret Scan / gitleaks (pull_request) Successful in 37s
lint / lint (push) Successful in 1m23s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m26s
lint / lint (pull_request) Successful in 1m30s
Golang Tests / test-go (push) Successful in 1m53s
CI / build (pull_request) Failing after 8m58s
Elixir Quality / Elixir Quality (pull_request) Failing after 11m24s
6e60832470
snapshot.rs SnapshotStore: atomic JSON persistence of the Context (temp+rename).
ContextHydrator::connect(snapshot_path) restores the snapshot to seed the shared
Context instantly, then runs a best-effort initial refresh (serves the restored
state if CNPG is momentarily down at boot; the refresh tick retries). refresh()
persists the Context after each SRQL re-snapshot. Context/Device/Service gain
serde derives. main passes config.snapshot_path; the standalone SnapshotStore in
main is removed (the hydrator owns it).

CausaloidGraph frozen-state persistence is deferred to the reasoner (Marvin).
Verified: cargo clippy --all-targets -D warnings, cargo test (12, incl. snapshot
round-trip), cargo fmt --check, bazel build //rust/causal-engine:{causal_engine_lib,
causal_engine_bin,causal_engine_test} --config=ci (RBE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(causal-engine): reasoner hand-off note; mark V1 plumbing complete
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 18s
Secret Scan / gitleaks (pull_request) Successful in 32s
lint / lint (pull_request) Successful in 1m11s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m39s
Golang Tests / test-go (push) Successful in 1m50s
lint / lint (push) Successful in 2m4s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
20ddd3d2c0
The ServiceRadar-owned V1 engine plumbing is complete and green: scaffold,
hydrator (SRQL snapshot + live signals.state.> subscriber + shared Context +
snapshot persistence), emitter, the Phase-0 state-change feed + Gap B, Gap G
(ultragraph 0.9), and 1.8/1.9 via the merged endpoint-SBOM feature. The
remaining tasks — reasoner + causaloids C1-C13 + risk composition (1.3/1.4/1.5),
the causality.rs extraction (1.10.1), and the reasoner-gated NIF cutover (1.10)
+ feed-2 (1.2.2) — are the DeepCausality author's domain.

runbooks/reasoner-handoff.md documents the seams: ContextStore (input),
Reasoner::evaluate, Verdict + emitter (output), ultragraph 0.9 (Gap G already
upstream), risk inputs (ocsf_devices.risk_score + AGE pkg_* scalars), and the
1.10 / feed-2 follow-ups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): reasoner C3 gateway shared-fate root cause (Phase 1.4)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 22s
Secret Scan / gitleaks (pull_request) Successful in 30s
lint / lint (pull_request) Successful in 1m30s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m37s
lint / lint (push) Successful in 2m15s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
c3c3ebc557
First real causaloid: c3_gateway_shared_fate groups unavailable devices by
gateway_id and, when >= threshold share a gateway, emits a RootCause verdict for
the gateway + Affected verdicts for the devices (the shared gateway is the
likelier root cause than each device independently). Plain Rust over the
Context; maps cleanly onto the God-View 4 buckets. domain_model.Device gains
gateway_id (hydrator map_device reads it). Unit-tested (shared-gateway,
below-threshold, gatewayless, evaluate-runs-c3).

Remaining causaloids (C1/C2/C4/C5/C5b/C6/C7-C13) + risk composition build on
this + the ultragraph 0.9 graph layer (next).

Verified: cargo clippy --all-targets -D warnings, cargo test (15), cargo fmt
--check, bazel build //rust/causal-engine:{lib,test} --config=ci (RBE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): add C4 management-unobservable causaloid (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 18s
Secret Scan / gitleaks (pull_request) Successful in 42s
lint / lint (push) Successful in 1m18s
lint / lint (pull_request) Successful in 1m36s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 2m0s
CI / build (pull_request) Failing after 7m32s
Elixir Quality / Elixir Quality (pull_request) Failing after 14m3s
5987dc8b77
A device whose MANAGED_BY manager is unavailable is unobservable through
that manager, so its availability is Unknown rather than failed. Suppresses
false "down" classifications for devices behind a dead manager.

- c4_management_unobservable() over Context.edges (ManagedBy)
- wired into Reasoner::evaluate after C3
- 2 unit tests (dead-manager -> Unknown; live-manager -> no verdict)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Substrate for causaloids C1-C13 and risk composition (tasks 1.3/1.5):

- EdgeKind gains Contains/BackedBy/DependsOn (C1/C2/C7); GatewayClass enum
  (Gap E, C3 OOB); InterfaceLink (C6); AttributedFlow (C10); BgpRoute (C8);
  OperatorRule (C12).
- Context gains links/flows/bgp_routes/operator_rules collections; Device
  gains gateway_class/flap_count/observation_expected/pkg_severity; all new
  fields serde(default) so snapshots stay backward compatible.
- Verdict gains a 0..=100 predicted `severity` (Verdict::new seeds it from
  the classification; raise_severity_to amplifies for risk composition).
- Emitter envelope surfaces severity_score + derives OCSF severity_id.
- map_device reads pkg_worst_severity; construction sites updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- C1: a CONTAINS host going unavailable cascades Affected to its guests.
- C2: a BACKED_BY datastore degrading cascades Affected to backed guest disks.
- Factor availability_map() helper shared by C1/C2/C4.
- 4 unit tests (cascade fires / suppressed when source healthy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Projects link saturation from Context.links by comparing observed flow_bps
against engineered capacity_bps (>=80% utilization). Capacity-ineligible
links (no denominator, Gap B contract) are skipped — no projection without
a capacity denominator. Severity scales with utilization. 3 unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- C7: a failed DEPENDS_ON dependency (service/host/resource) predicts collapse
  of the dependent stack. entity_availability_map() spans devices + services.
- C3 Gap E: a gateway whose gateway_class is OutOfBand/Management is no longer
  blamed as a data-plane root cause (shared-fate inference suppressed).
- 4 unit tests (C7 fires/suppressed; C3 OOB suppressed / in-band still blamed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): add C11/C12/C13 temporal & operator causaloids (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 17s
Secret Scan / gitleaks (pull_request) Successful in 37s
lint / lint (push) Successful in 1m13s
lint / lint (pull_request) Successful in 1m17s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Successful in 1m58s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
e53cdc7eb5
- C11: elevated flap_count (>=3 recent transitions) emits an instability
  precursor, severity scaling with flap rate.
- C12: an operator-authored stateful rule whose condition is met is promoted
  into causal reasoning as an observation over its target entity.
- C13: a node expected to be observed but with no availability reading is a
  discovery/observation gap (Unknown), not a confirmed outage (pairs with C4).
- Refresh module/evaluate docs: the 9 non-graph causaloids are wired; C5/C5b/
  C8/C9/C10 land with the ultragraph graph module next.
- 4 unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): add graph causaloids C5/C5b/C8/C9/C10 on ultragraph 0.9 (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 23s
Secret Scan / gitleaks (pull_request) Successful in 37s
Fingerprint Licensing / netprobe-fingerprint-licenses (push) Failing after 49s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 56s
lint / lint (push) Successful in 1m23s
lint / lint (pull_request) Successful in 1m58s
Golang Tests / test-go (push) Successful in 2m2s
Rust Add-on Interop Test / interop (push) Successful in 2m5s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
261aff1051
New `graph` module projects Context CONNECTS_TO edges into a frozen ultragraph
0.9 CsmGraph (Gap G algorithms already upstream) keyed back to canonical ids:

- C5 single-point-of-failure via articulation_points (StructuralGraphAlgorithms)
- C5b bridge redundancy-gap via bridges (both endpoints flagged, de-duped)
- C9 shared-hop bottleneck via betweenness_centrality (CentralityGraphAlgorithms)
- C10 traffic-source blast radius via is_reachable (PathfindingGraphAlgorithms),
  severity weighted by source risk (low-risk source => lower severity)
- C8 BGP withdrawal: downstream destinations of a withdrawn route degraded

All 13 causaloids (C1-C13) now wired into Reasoner::evaluate. ultragraph = "0.9"
added; crate_universe repinned (Cargo.lock + MODULE.bazel.lock). 44 unit tests;
cargo clippy/fmt + bazel lib/bin/test --config=ci green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): compose per-device risk into C5/C7/C10 severity (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 16s
Secret Scan / gitleaks (pull_request) Successful in 32s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 40s
lint / lint (push) Successful in 1m26s
lint / lint (pull_request) Successful in 1m27s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
1b9ebfdc72
Task 1.5: device_risk() folds the MAX-wins ocsf_devices.risk_score and the
bounded pkg_severity (CVSS, scaled x10) into a 0..=100 per-device risk that
RAISES — never lowers — the predicted severity of C5 (SPOF), C7 (stack
collapse), and C10 (blast radius) for the affected node. The structural
classification is unchanged (raise_severity_to is monotonic). 2 unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): project AGE topology edges into the hydrated Context (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 17s
Secret Scan / gitleaks (pull_request) Successful in 31s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 44s
lint / lint (pull_request) Successful in 1m15s
lint / lint (push) Successful in 1m27s
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
791eb39cd0
refresh() now runs a read-only graph_cypher MATCH over the AGE platform graph
and projects CONNECTS_TO/MANAGED_BY/CONTAINS/BACKED_BY/DEPENDS_ON relationships
into Context.edges (canonical sr: ids via the Device `id` property), unlocking
C1/C2/C4/C5/C5b/C7/C9/C10 against live topology. Best-effort: a projection
failure logs and reasons-without-edges that tick rather than aborting refresh.

parse_topology_edges + edge_kind_from_label are pure and unit-tested against the
documented graph_cypher {nodes,edges} wrapper shape (dedup + canonical-id +
unknown-label filtering). Live cypher still needs a CNPG smoke test; links/
flows/bgp_routes/operator_rules feeds remain TODO(1.2b) (causaloids no-op empty).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): extract god_view reasoning into the engine (#3425, task 1.10.1)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 20s
Secret Scan / gitleaks (pull_request) Successful in 34s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 59s
Golang Tests / test-go (push) Failing after 1m34s
lint / lint (push) Successful in 1m39s
lint / lint (pull_request) Successful in 1m39s
CI / build (pull_request) Has been cancelled
Elixir Quality / Elixir Quality (pull_request) Has been cancelled
d06a767f7c
Port god_view_nif/core/causality.rs (betweenness root-cause selection + 3-hop
affected BFS) into rust/causal-engine/src/god_view.rs, dropping the dead
DeepCausality CausaloidGraph the NIF built-then-froze-but-never-queried. State
codes (0=root/1=affected/2=healthy/3=unknown) and reason strings are preserved
verbatim so shadow-mode diffing against the legacy NIF is exact. 5 unit tests.

The remaining 1.10 steps (NIF demotion 1.10.2, drop deep_causality/ultragraph
1.10.3, workspace rejoin 1.10.4, shadow 1.10.5, cutover 1.10.6) are deploy-gated
and documented in runbooks/god-view-nif-cutover.md — demoting the live NIF
before the engine serves verdicts would blank the God-View overlay, so they
follow engine deployment + parity, not this PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(causal-engine): Gap D reverse MANAGES edge + V1 task closeout (#3425)
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 21s
Secret Scan / gitleaks (pull_request) Successful in 42s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m8s
lint / lint (pull_request) Successful in 1m23s
Golang Tests / test-go (push) Successful in 1m24s
lint / lint (push) Successful in 1m51s
CI / build (pull_request) Failing after 9m25s
Elixir Quality / Elixir Quality (pull_request) Failing after 10m40s
a41724c6d4
- Gap D (5.2.1): upsert_managed_by/2 now also MERGEs the reverse
  (mgmt)-[:MANAGES]->(child) AGE edge so the engine traverses manager->managed
  directly (additive; mirrors the MANAGED_BY MERGE).
- tasks.md: mark Phase 0-1 V1 engine COMPLETE — 1.1.3 (ultragraph dep),
  1.3 (reasoner shape), 1.4 (C1-C13), 1.5 (risk composition), 1.9.4, 1.10.1
  (god_view extraction), 5.2.1 (Gap D), and validation 6.1-6.5 all done.
- Phases 2-4 (Gaps A/C/F) and Gap E data-source remain spec-captured +
  dependency/deploy-gated by design; 1.10.2-1.10.6 deploy-gated (cutover runbook).
- openspec validate --strict: valid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Some checks failed
Helm Lint / Helm Lint (pull_request) Successful in 21s
Secret Scan / gitleaks (pull_request) Successful in 42s
Fingerprint Licensing / netprobe-fingerprint-licenses (pull_request) Failing after 1m8s
lint / lint (pull_request) Successful in 1m23s
Golang Tests / test-go (push) Successful in 1m24s
lint / lint (push) Successful in 1m51s
CI / build (pull_request) Failing after 9m25s
Elixir Quality / Elixir Quality (pull_request) Failing after 10m40s
This pull request has changes conflicting with the target branch.
  • Cargo.lock
  • MODULE.bazel.lock
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/causal-engine-v1:feat/causal-engine-v1
git switch feat/causal-engine-v1

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch staging
git merge --no-ff feat/causal-engine-v1
git switch feat/causal-engine-v1
git rebase staging
git switch staging
git merge --ff-only feat/causal-engine-v1
git switch feat/causal-engine-v1
git rebase staging
git switch staging
git merge --no-ff feat/causal-engine-v1
git switch staging
git merge --squash feat/causal-engine-v1
git switch staging
git merge --ff-only feat/causal-engine-v1
git switch staging
git merge feat/causal-engine-v1
git push origin staging
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
carverauto/serviceradar!3519
No description provided.