Skip to content

fix(runtime): refuse backend snapshot entries whose runtime domain is an untyped string - #1441

Open
doublewhy wants to merge 3 commits into
devfrom
1434-typed-runtime-domain
Open

doublewhy wants to merge 3 commits into
devfrom
1434-typed-runtime-domain

Conversation

@doublewhy

@doublewhy doublewhy commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

SnapshotEntry.domain is typed RuntimeDomain, a str enum, but backend snapshot admission never checked it, and _identity_violation compares by value ("provisioning" == RuntimeDomain.PROVISIONING). On dev, a provisioner result with plain-string domains was committed by both RuntimeManager.apply and the control plane; identity checks on submission and credential paths then refused the planner-authorized teardown of provision.node.web (runtime.plan-resource-incoherent).

Admission now refuses an entry whose domain is not a RuntimeDomain member. This source is evidence-bound, so both research families get new captures (docs/develop/research-captures.md). Retained outcomes, classifications and claim limits are unchanged.

Requirement UIDs

  • ASR-532 (Runtime Backend Result Integrity): backend-result-admission.md: a backend "MUST NOT rewrite" the plan-owned runtime domain; ASR-532/requirement.md already lists backend_snapshot_contracts.py as IMPLEMENTS. No scope file; no requirement record changes.

Related Issues

Closes #1434

ADR Impact

  • None; follows ADR-105's normative backend-result-admission.md.

Changes

  • New _domain_violation, checked first in _entry_violation, requires type(entry.domain) is RuntimeDomain, else "Backend snapshot contains an untyped runtime domain.", which the shape gate turns into runtime.backend-contract-invalid, keeping the predecessor.
  • Helpers _returned (test_issue_1200) and _snapshot_from_plan (test_issue_1067) now build RuntimeDomain.PROVISIONING, so the closed-excess test still fails for closed excess, and asserts that message.
  • Captures (python -m tools.research_capture record): specification-coverage capture-0be8c669… and formal-validation capture-86296e4c…, with receipts. Bound to implementation digest 719a546cff12 at source commit 0d85e547, checkout_state clean; no numbered file, index or pin changes.

Issue verification-plan bullets, verbatim; "fails without" = backend_snapshot_contracts.py from dev:

Plan bullet Change Fails without it CI lane, evidence
A string-domain result through RuntimeManager.apply is refused with runtime.backend-contract-invalid and leaves the snapshot unchanged. backend_snapshot_contracts.py:_domain_violation test_issue_1434_typed_runtime_domain.py manager case: committed (assert True is False) canonical / test-shard, run 38503323059
On the control plane, a one-shot string-domain result is refused, and the next planner-authorized plan is accepted. An unperturbed control commits and then tears down provision.node.web. same control-plane case: second receipt refused, runtime.plan-resource-incoherent canonical / test-shard, run 38503323059
It fails on dev before the fix. - 2 of 3 fail (above) Test Plan
Run test_issue_1200_mixed_runtime_constraints.py, test_issue_1067_resolved_realization_authority.py, test_issue_158_runtime_result_integrity.py and the test_issue_1204_result_* modules as targeted modules, with and without -m integration. the two helpers reverted _returned: 13 of 46 test_issue_1200 cases fail; reverted _snapshot_from_plan: closed-excess message assertion fails canonical / test-shard: 175 passed (178 with the #1434 module); -m integration selects none
Run repository fast feedback against origin/dev. - - fast-feedback: passed (Test Plan)

Test Plan

  • Unit tests pass
  • Integration tests pass if applicable
  • Full completion suite required in CI before merge
  • No coverage regression

uv run --project implementations/python --frozen --all-extras python -m pytest implementations/python/tests/test_issue_1434_typed_runtime_domain.py -q -p no:cacheprovider: 3 passed (2 fail without the fix).

Evidence: a shared collector (collect_research_evidence.py, kept outside this repository) ran on the clean, rebased tree. It ran the 6 pinned specification artifacts through _execute_artifact (0 rejections; 38 of 42 stages passed, 4 preregistered non-execution), then recompute_analysis (10 of 10 load-bearing checks pass). It replayed the 10 retained formal cases with replay_case, ran the 4 production cases with their raes processor argv and the 14 participant test functions (18 passed), then recompute_claim_results. All 20 observations match their expected outcomes. The only drift from dev's templates is in the formal snapshot: replay command retained-case-replay with its real argv, and Python 3.12.3. Both checkers passed at the head and on a scratch worktree of git merge-tree --write-tree origin/dev HEAD. nox -s contracts -- --base-rev origin/dev passed.

nox -s verify-fast-feedback -- --base-rev origin/dev passed and ran the three changed test modules (79 passed). nox -s lint passed.

CI at head ef84ce34 (dev base 348c490): run 38503323059, 28 checks pass, deploy skipped, SonarCloud passed.

Ground Control Checks

  • Repository policy command passes (make policy; requirement governance skipped)
  • Pre-push gates: policy, fast feedback, lint and contracts (above); no Codex review.

Traceability

  • IMPLEMENTS: ASR-532 ← implementations/python/packages/raes_runtime/backend_snapshot_contracts.py
  • TESTS: ASR-532 ← implementations/python/tests/test_issue_1434_typed_runtime_domain.py, implementations/python/tests/test_issue_1200_mixed_runtime_constraints.py, implementations/python/tests/test_issue_1067_resolved_realization_authority.py

Checklist

  • Code follows the project coding standards
  • FM level classified if semantic change: FM0, local type check in snapshot admission; no executable or runtime adoption is claimed.
  • Published contract schemas regenerated if models changed: none changed.
  • PR title is a Conventional Commit
  • Architectural docs updated if applicable: not applicable.

@doublewhy
doublewhy force-pushed the 1434-typed-runtime-domain branch from 6e425be to 9a80447 Compare October 9, 2026 13:25
@doublewhy
doublewhy marked this pull request as ready for review October 9, 2026 15:28
@doublewhy
doublewhy force-pushed the 1434-typed-runtime-domain branch from 9a80447 to 5672244 Compare October 13, 2026 06:34
@doublewhy
doublewhy marked this pull request as draft October 13, 2026 19:39
… an untyped string

RuntimeDomain is a str enum, so a backend entry whose domain was the plain string "provisioning" passed the value comparison in the plan-ownership check and was committed. The control-plane submission and credential paths compare the domain by identity, so every later planner-authorized plan for that resource was refused as incoherent, and the resource could not be torn down.

Backend snapshot admission now requires a RuntimeDomain member, next to the typed profile-binding check. Two test helpers that built backend results with string domains now use RuntimeDomain.PROVISIONING, so the closed-excess test keeps failing for closed excess.
The issue #1434 regression module now asserts the exact backend diagnostic
on the manager and control-plane paths, and its SDL fixtures are literal
documents. The issue #1067 closed-excess test also asserts its refusal
message, so an untyped-domain refusal can no longer satisfy it.
Collected by running the pinned specification artifacts through the production pipeline, replaying the 10 retained formal cases with replay_case, the 4 production cases with their raes processor argv, and the 14 participant test functions against this branch's source, then recorded with python -m tools.research_capture record.
@doublewhy
doublewhy force-pushed the 1434-typed-runtime-domain branch from 5672244 to ef84ce3 Compare October 14, 2026 02:52
@doublewhy
doublewhy marked this pull request as ready for review October 14, 2026 03:56

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant