Skip to content

fix(gen-manifests): hermetic self-test — fixtures never inherit the caller's PR event - #5847

Merged
meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/selftest-hermetic-env
Sep 28, 2026
Merged

meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/selftest-hermetic-env

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

The first settlement PR the Plugins settle-locks job opened (Systemorph/MeshWeaver.Plugins#2487, App-authored, lock-only) went red in validate / Validate node repos — not on its lock diff, but in the canonical self-test step:

✗ gen-manifests self-test:
  - main-owned: a source-only pull request must pass the untouched check
  - main-owned: a committed lock change must be named, got ['the generated settlement PR must change only existing package manifest.lock files; found Mod/src.cs']

Root cause: _lock_base and is_manifest_lock_settlement_pr read GITHUB_EVENT_NAME / GITHUB_EVENT_PATH from the real run, so on the settlement PR every fixture took the settlement branch. Fix: --self-test runs with GITHUB_EVENT_NAME, GITHUB_EVENT_PATH, GITHUB_BASE_REF, MW_LOCK_BASE removed (restored afterwards).

Verified: with the settle PR's event payload exported, main's copy fails exactly those two cases; this copy passes the full self-test. On any ordinary PR the predicate is false, which is why no other run saw it.

Pairs-with: none — self-test harness only.

🤖 Generated with Claude Code

…t the caller's PR event

On the first settlement PR (MeshWeaver.Plugins#2487) the validate lane's canonical self-test went red:
_lock_base / is_manifest_lock_settlement_pr read GITHUB_EVENT_NAME / GITHUB_EVENT_PATH from the REAL
run, so every main-owned fixture took the settlement branch. --self-test now runs with those (and
GITHUB_BASE_REF, MW_LOCK_BASE) removed, restoring them after. Reproduced locally with the settle PR's
event payload: main's copy fails the two main-owned cases, this copy passes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@systemorph systemorph Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change makes the canonical gen-manifests.py --self-test hermetic: main() pops the four run-context variables its fixtures must not inherit (GITHUB_EVENT_NAME, GITHUB_EVENT_PATH, GITHUB_BASE_REF, MW_LOCK_BASE) around the self_test() call and restores them in a finally. The whole diff is present (+13/-1, no cuts).

What I checked: the pop/restore mechanics (the k in os.environ guard keeps the comprehension KeyError-free; try/finally restores on both the return and an exception path; a variable that was absent stays absent); the scope (isolation applies only to the --self-test arm, so --check's env-driven behavior — including the settlement-PR acceptance path is_manifest_lock_settlement_pr -> check_generated_lock_settlement — is unchanged); that the four names cover every environment read of the two functions the comment names, cross-checked against the identical machinery landed in MeshWeaver.Plugins#2481; and the causality — on the settle PR's run (Plugins#2487) the predicate was true for every fixture, so check_untouched delegated to check_generated_lock_settlement, which is exactly the two observed 'main-owned' fixture failures quoting the settlement message. No security surface: no injection, no secrets, no access-control change; the settlement predicate itself is not altered, only shielded during the self-test; nothing in the diff or PR text addresses the reviewer.

What I could not verify: the fixtures' own expectations — the diff shows only these two hunks and the mesh does not carry the full file, so 'this copy passes the full self-test' rests on the author's verification and this PR's CI; and which copy of the script the failing step executes (one question below).

Findings: 0 blocking · 0 should-fix · 1 question · 0 nit


Internal review of e2959ae2f8dd6c2e0c6c22731f00f0e29c1924a2 — GLM-5.3, posted by the control plane. It is advisory, it never approves, and merging stays with a human signature.

# `is_manifest_lock_settlement_pr` read GITHUB_EVENT_NAME / GITHUB_EVENT_PATH / MW_LOCK_BASE,
# so on the settlement PR's own run (MeshWeaver.Plugins#2487) every fixture took the
# settlement branch and the self-test went red over the environment, not the code.
saved = {k: os.environ.pop(k) for k in _SELF_TEST_ENV_ISOLATED if k in os.environ}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question — The failing job ran in MeshWeaver.Plugins (validate / Validate node repos on the settle PR #2487), and that repo carries a vendored scripts/gen-manifests.py with the identical --self-test arm and the same env-reading functions (landed in Plugins#2481; its KNOWN_ARGS includes --self-test) — so the vendored copy has this same leak. The body calls the failing step 'the canonical self-test' and says 'Pairs-with: none', but the stated verification — running main's copy with the settle PR's exported event payload — cannot distinguish the two copies, because they are the same code: it reproduces the failure either way. Can you confirm the validate step fetches and runs this core copy (e.g. through scripts/platform-script.py, which the script's own usage block names) rather than the vendored one? If any Plugins job can reach the vendored --self-test inside a pull-request environment, this isolation needs porting there too, or the settle PR stays red.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — the failing step runs THIS core copy, not the vendored one. The job was validate / Validate node repos (job 108829103360), failing step "The manifest checker can fail — --resolve, the trunk baseline and the config contract (self-test)", which is node-repo-validate.yml:554: python3 "$RUNNER_TEMP/gen-manifests.py" --self-test — the canonical fetched from Systemorph/MeshWeaver at the lane's scripts ref (main for Plugins), not scripts/gen-manifests.py.

And no Plugins job runs the vendored --self-test: git grep "gen-manifests.py --self-test" over Plugins main's .github/ finds nothing (its repo-gates job, which calls the vendored copy's check_manifests through validate-repos.py, went green on #2487).

The vendored copy still carries the same leak as dead code in CI, so I'll re-sync it to this canonical in the Plugins follow-up anyway: it is kept code-identical to the canonical, and check-resolver-copy.py reports any drift.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

  1 files  ±0    1 suites  ±0   3m 6s ⏱️ -8s
348 tests ±0  348 ✅ ±0  0 💤 ±0  0 ❌ ±0 
352 runs  ±0  352 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

461 tests  ±0   461 ✅ ±0   1m 3s ⏱️ +6s
  3 suites ±0     0 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 701 tests  ±0   1 701 ✅ ±0   4m 50s ⏱️ ±0s
    2 suites ±0       0 💤 ±0 
    2 files   ±0       0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

    3 files  ±0      3 suites  ±0   5m 42s ⏱️ -42s
2 232 tests ±0  2 232 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 233 runs  ±0  2 233 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

770 tests  ±0   579 ✅ ±0   7m 8s ⏱️ -1s
  3 suites ±0   191 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

This pull request removes 25 and adds 9 tests. Note that renamed tests count towards both.

   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
…
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a MIXED aggregate — one transient branch, one genu"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (source B is misconfigured)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate with one genuine leaf", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---

   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate, all leaves transient", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a reflective wrapper around a transient cause", exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Net.Sockets.SocketException (110): Connection timed out
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a transient cause UNDER an aggregate branch's wrap"···, exception: System.AggregateException: One or more errors occurred. (wrapped)
 ---> System.InvalidOperationException: wrapped
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an 'initialization failed' wrapper around a transi"···, exception: System.InvalidOperationException: Hub 'x' initialization failed
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an aggregate whose branches are ALL transient (two"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (Name or service not known)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "the #4067 shape: transient provider fault wrapping"···, exception: MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.TimeoutException: Timeout during connection attempt, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "the #4068 shape: transient provider fault wrapping"···, exception: MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known, expected: True)

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    5 files  ±0      5 suites  ±0   14m 15s ⏱️ -4s
4 288 tests ±0  4 286 ✅ ±0  2 💤 ±0  0 ❌ ±0 
4 292 runs  ±0  4 290 ✅ ±0  2 💤 ±0  0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

This pull request removes 4 and adds 2 tests. Note that renamed tests count towards both.
   --- End of inner exception stack trace ---, isDenial: True)
 ---> System.UnauthorizedAccessException: Access denied
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "e067801a-15c0-4079-aee5-6c7e3e800578")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "c9cc2168-5dbb-4066-940e-fbf3ffb2aa6a")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
 ---> System.UnauthorizedAccessException: Access denied
   --- End of inner exception stack trace ---, isDenial: True)

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   17 files  ±0     17 suites  ±0   36m 6s ⏱️ -47s
9 800 tests ±0  9 607 ✅ ±0  193 💤 ±0  0 ❌ ±0 
9 809 runs  ±0  9 616 ✅ ±0  193 💤 ±0  0 ❌ ±0 

Results for commit e2959ae. ± Comparison against base commit 003b70d.

This pull request removes 29 and adds 11 tests. Note that renamed tests count towards both.

   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
   --- End of inner exception stack trace ---, isDenial: True)
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
…
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "c9cc2168-5dbb-4066-940e-fbf3ffb2aa6a")
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
 ---> System.UnauthorizedAccessException: Access denied
   --- End of inner exception stack trace ---, isDenial: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a MIXED aggregate — one transient branch, one genu"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (source B is misconfigured)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate with one genuine leaf", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (boom)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---

   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: False)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a nested aggregate, all leaves transient", exception: System.AggregateException: One or more errors occurred. (One or more errors occurred. (Failed to connect to 10.42.18.4:5432)) (Failed to connect to 10.42.18.4:5432)
 ---> System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a reflective wrapper around a transient cause", exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.Net.Sockets.SocketException (110): Connection timed out
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "a transient cause UNDER an aggregate branch's wrap"···, exception: System.AggregateException: One or more errors occurred. (wrapped)
 ---> System.InvalidOperationException: wrapped
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an 'initialization failed' wrapper around a transi"···, exception: System.InvalidOperationException: Hub 'x' initialization failed
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "an aggregate whose branches are ALL transient (two"···, exception: System.AggregateException: One or more errors occurred. (Failed to connect to 10.42.18.4:5432) (Name or service not known)
 ---> MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
   --- End of inner exception stack trace ---
 ---> (Inner Exception #1) System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known<---
, expected: True)
MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest ‑ Classifies(shape: "the #4067 shape: transient provider fault wrapping"···, exception: MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432
 ---> System.TimeoutException: Timeout during connection attempt, expected: True)
…

@meshweaver-cloud
meshweaver-cloud Bot merged commit 6c24eb7 into main Sep 28, 2026
48 of 54 checks passed
@rbuergi
rbuergi deleted the fix/selftest-hermetic-env branch October 10, 2026 13:11
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