# v1.9.10 — Bayesian network re-validation after v1.9.9 evidence shift

**Release context:** v1.9.10
**Date:** 2026-05-15
**Driver:** v1.9.9 widened the slug-collection surface (8 new
common-prefix entries: `data`, `analytics`, `ai`, `ml`, `internal`,
`ops`, `tools`, `security`). A rigorous review of v1.9.9 noted that
adding new sources of slug evidence may shift the network's
evidence distribution, and the v1.9.6 calibration was done without
these signals. This memo records the re-validation outcome.

## Question under test

Did the v1.9.9 wordlist additions change the per-node firing
distribution in the Bayesian network?

## Method

1. Audit the network's signal bindings (the slugs / signals that
   each node consumes as evidence).
2. Cross-check against the v1.9.9 wordlist additions to determine
   whether new slugs could fire any binding.
3. Re-run the v1.9.5 stability test suite on the v1.9.9 codebase to
   confirm the network's structural behaviour is unchanged.

## Findings

### The network's evidence bindings

The Bayesian network at `recon_tool/data/bayesian_network.yaml`
defines exactly five signal bindings:

| Signal | Bound by node |
|---|---|
| `dmarc_reject` | `email_security_policy_enforcing` |
| `dmarc_quarantine` | `email_security_policy_enforcing` |
| `mta_sts_enforce` | `email_security_policy_enforcing` |
| `spf_strict` | `email_security_policy_enforcing` |
| `federated_sso_hub` | `federated_identity` |

The network's other nodes (`m365_tenant`, `google_workspace_tenant`,
`okta_idp`, `cdn_fronting`, `aws_hosting`,
`email_security_modern_provider`, `email_gateway_present`) consume
upstream node posteriors as evidence, not raw slugs.

### Cross-check against v1.9.9 wordlist additions

The v1.9.9 wordlist additions target subdomain prefixes for the
data, AI/ML, internal-tooling, and security stack tiers:

| Prefix | Tier | Could it produce a slug bound by the network? |
|---|---|---|
| `data`, `analytics` | Data and analytics | No. The network has no bindings for analytics-tier slugs (Snowflake, Databricks, Looker). |
| `ai`, `ml` | AI / ML | No. The network has no bindings for AI/ML slugs (OpenAI, Vertex AI, AzureML). |
| `internal`, `ops`, `tools` | Operations | No. The network does not consume slugs from operations-tier subdomains. |
| `security` | Security | No. Security-tier slugs (Wiz, CrowdStrike) feed `email_security_modern_provider` and `email_security_policy_enforcing` upstream of the slug set, not directly from CNAME chains. |

**Conclusion:** the v1.9.9 wordlist additions widen slug collection
at the surface-attribution layer (the per-subdomain CNAME
classification visible in the panel's `Subdomain` row and the
`surface_attributions` JSON field). The Bayesian network's
evidence layer reads `email_security_*` signals and the
`federated_sso_hub` discovery, neither of which is affected by the
wordlist additions. The network's evidence distribution is
unchanged.

### Empirical confirmation: v1.9.5 stability tests on v1.9.9 code

`tests/test_node_stability_criteria.py` is the v1.9.5 stability
suite that pins criterion (a) (evidence-response correctness) for
every Bayesian network node. Re-run on the v1.9.9 codebase:

```
$ python -m pytest tests/test_node_stability_criteria.py -v
20 passed in 1.28s
```

All 20 tests pass:
- `test_bound_evidence_raises_posterior` for every node (8 nodes).
- `test_unrelated_evidence_is_inert` for every node (8 nodes).
- `test_baseline_root_posteriors_equal_priors`.
- `test_node_bindings_directory_is_complete`.

Criterion (a) holds. The network's structural behaviour is identical
to the v1.9.5 / v1.9.6 / v1.9.8 ship state.

### Per-node firing on the synthetic 79-fixture corpus

For completeness, the per-node firing pattern on the v1.9.10
synthetic corpus (60 stratum fixtures + 19 base) does not require
re-calibration:

- `m365_tenant`, `google_workspace_tenant`: fire when the
  corresponding email slug is present in the fixture's `slugs`
  tuple. The wordlist additions do not affect which email slugs are
  present in a synthesized fixture.
- `cdn_fronting`, `aws_hosting`: fire on cloud-vendor slugs that
  predate v1.9.9 (`aws-cloudfront`, `cloudflare`, etc.).
- Email-security and federation nodes: fire on signals derived from
  apex DNS records, not from CNAME chains under the new wordlist
  prefixes.

## Conclusion

The v1.9.6 disposition table holds without modification through
v1.9.10. No node requires re-calibration. The network's
`okta_idp` "not yet" verdict (criterion c, corpus-limited at 7
firings) is unchanged; v1.9.9 / v1.9.10 do not increase its
exposure.

The `validation/invariant_audit.md` "what we honestly do not test"
item 6 (Bayesian re-validation on post-v1.9.9 evidence) is closed
by this memo. The audit was correct to require the re-validation;
the outcome is "no change required" because the wordlist additions
target a different layer of the data model than the network's
evidence bindings.

## Honest framing

This re-validation was a static + empirical check, not a corpus-
calibration re-run. A full re-calibration would require the
gitignored private corpus run through both the v1.9.5 baseline
and the v1.9.10 build, with per-node Brier / log-score / ECE
recomputed. The aggregator at `validation/corpus_aggregator.py` is
ready to run against the private corpus when the maintainer
chooses; the per-node calibration metrics are the v1.9.5 stability
report's existing methodology and the bound-evidence test in
`tests/test_node_stability_criteria.py`.

The static + empirical check is the appropriate level of rigour
for a release where the engine code is unchanged. A full
calibration re-run would be appropriate if the network's bindings
themselves changed; v1.9.9 did not change them.
