Skip to main content

Causal Assumptions and Abstention Boundary

Date: 2026-04-07 Scope: AR-first causal / intervention layer Related doctrine: architecture-doctrine-2026-04-08.md This note is the repo-grounded boundary for what the current system can honestly claim today. It is not a mathematical proof of causality. It is the operational contract that the code currently approximates.

What The System Assumes

The current intervention stack assumes:
  1. Temporal order matters. Predictions and interventions should be evaluated on point-in-time object state, not future outcomes leaked back into the past.
  2. Tenant scope is real. Every causal artifact must be interpreted inside one tenant boundary.
  3. The object graph is the source of state. The ledger and object graph define what the model saw at decision time.
  4. Learned intervention effects are only trustworthy inside observed support. If the action/object combination is thinly supported, the system should soften or abstain rather than pretend certainty.
  5. Drift and out-of-distribution signals matter. A learned result that looks off-distribution should not be treated as a clean counterfactual.

Where The Code Enforces This Today

  • services/ml-sidecar/src/training.py
    • Probability-model training now requires resolved decision_epochs rows with frozen feature_snapshot data. Legacy rows without point-in-time snapshots are rejected instead of being rebuilt from current object state.
  • services/ml-sidecar/src/server.py
    • The cached probability-model path, release replay scoring, and drift/distribution baselines now consume normalized decision-epoch examples instead of current world_objects snapshots.
    • The live uplift shadow path now calls the DR-first /uplift/predict/v2 endpoint, and weekly retraining now calls /uplift/train/v2 instead of the legacy T-learner endpoints.
  • services/ml-sidecar/src/db.py
    • Intervention training rows now hydrate object state from world_object_versions as of action_at, and fail closed when no point-in-time version exists.
  • services/ml-sidecar/src/training.py
    • Intervention-effect models now build features with action_at as the reference time instead of observed_at, which avoids encoding post-action time drift into training features.
  • src/world-model/ensemble.ts
    • predict() now rejects invalid V2 responses, falls back when the sidecar reports drift or out-of-distribution input, and requires an approved world_model_releases row plus an approved promotion-quality report before it accepts a learned V2 prediction.
    • estimateIntervention() prefers explicit sidecar intervention models only when causal-quality evidence is approved; otherwise it falls back to learned priors or heuristic effects.
    • estimateIntervention() now downgrades to proceed_with_caution when the approved causal support is thin.
  • src/eval/autonomy-enforcer.ts
    • Elevated-autonomy promotion now treats observational-only treatment-quality evidence as insufficient authority, even when a legacy treatment report still says approved / eligible.
  • src/api/world-runtime-routes.ts
    • Learned-model release gating now treats observational-only treatment-quality evidence as insufficient for release approval during /v1/world/reestimate.
  • src/eval/rollout-gates.ts
    • Rollout-gate evidence snapshots now record whether treatment-quality evidence was observational-only or causal-grade so the audit trail does not hide that distinction.
  • src/core/uncertainty.ts
    • The uncertainty profile already marks drift and OOD as abstention-relevant signals.
  • src/eval/shadow-scorecard.ts
    • Calibration and shadow-scoring are tracked as evaluation signals, not as a proof of causal identification.
  • src/eval/evaluation-reports.ts
    • treatment_quality now prefers propensity-aware comparisons from action_decision_log linked to resolved decision_epochs, and stamps decision_epoch_ope_v1 only when that evidence is actually available.
    • When those logged propensities/outcomes are missing or too weak, the report falls back to observational comparisons but remains candidate / insufficient_evidence instead of granting causal-grade eligibility.

Where The Code Does Not Fully Enforce It

  • There is no formal written ignorability, positivity, SUTVA, or consistency proof in the codebase.
  • There is no general unmeasured-confounder check such as an E-value or sensitivity analysis gate on the live inference path.
  • Support / overlap is not a hard abstention gate everywhere. The current boundary is conservative, but it is still a policy approximation.
  • The treatment-quality report path is now OPE-backed when decision-log coverage exists, but it is still weaker than a full DR / refutation-backed evaluation stack.
  • Many tenants may still have sparse or missing linked decision-log outcomes, which means the report will stay observational-only and ineligible until that logging surface matures.
  • Confidence intervals are only as good as the upstream model and the promotion gates behind it. A valid interval is not the same thing as a valid causal identification strategy.

Current Abstention Boundary

The system currently fails closed or softens when:
  • the sidecar returns a malformed V2 payload;
  • the V2 payload is marked drifted or out-of-distribution;
  • the learned model lacks an approved world_model_releases row;
  • the learned release lacks an approved promotion-quality artifact;
  • intervention support is thin enough that the system should only recommend proceed_with_caution.
  • the treatment-quality report is observational-only, in which case it cannot promote autonomy or approve learned-model release.
  • the treatment-quality report lacks enough linked propensity-weighted evidence, in which case it stays candidate even if observational deltas look good.
The system does not yet fully abstain on every weak-support case. That is the next causal hardening step if the goal is a stronger identification claim.

Practical Reading

The honest public claim today is:
Nooterra uses a governed, tenant-scoped world model to rank actions and estimate intervention effects under uncertainty, with fail-closed fallbacks when the learned path is not sufficiently supported.
The stronger claim, that the system has fully validated causal identification under all deployment conditions, is not yet warranted by the code.