Skip to content

MeshWeaver.Plugins runs NO secret preflight and neither it nor Manufacturing calls node-repo-validate — a hand-rolled lane opts out of every guard the lane grows later #3504

Closed

Description

@rbuergi

Measured: two repos do not call node-repo-validate, and one of them runs NO secret preflight at all

Found while applying the rule that #3454's work produced, rather than by looking for it:

The guards live INSIDE the shared lane. A hand-rolled copy therefore opts out of every guard that
lane grows LATER — silently, retroactively, and invisibly from the repo that made the copy.

check-workflow-timeouts.py and check-pr-secret-preflight.py are both invoked inside
node-repo-validate.yml. Neither existed when the older copies were made, so nobody chose to skip
them — the copy chose, months of commits later. A repo that forked a lane before a guard was written
looks identical to one that passes it.

The adoption matrix, measured 2026-09-07 against each repo's main

Read from each repo's actual workflow files, not from AGENTS.md — which named Education a caller
while Education called none (that is the precedent, #258).

repo validate compile-check gate module-pack publish-bake tag-modules platform-ref-bump
MeshWeaver.SocialMedia ✅ ✅ ✅ ✅ ✅ ✅ ✅
MeshWeaver.Reinsurance ✅ ✅ ✅ — ✅ ✅ —
MeshWeaver.Crm ✅ ✅ ✅ — ✅ ✅ —
MeshWeaver.Education ✅ — — — ✅ ✅ —
MeshWeaver.Manufacturing ❌ ✅ ✅ — ✅ — —
MeshWeaver.Plugins ❌ — ✅ ✅ ✅ — ✅

A missing lane is not automatically wrong — a repo that packs no modules has no use for
module-pack. validate is different, because it is where the fleet-wide guards run.

What each of the two actually has

repo check-workflow-timeouts.py check-pr-secret-preflight.py
MeshWeaver.Manufacturing ✅ inline in ci.yml (+ auto-arm.yml) ✅ inline in ci.yml
MeshWeaver.Plugins ⚠️ only in auto-arm.yml 🚨 not invoked in any workflow

Manufacturing is covered today and fragile tomorrow — its coverage came from #3454's PR adding
the two calls by hand, which is exactly the copy that will not carry guard number three.

🚨 Plugins has NO secret-preflight coverage, and it is the worst repo for that to be true of. It
is the largest satellite, carries the most lanes and the most secrets, and the guard exists for the
failure mode Plugins is most exposed to: a secret consumed by a PR-reachable job that no preflight
asserts surfaces late, wearing a message that names no secret. AGENTS.md cites Reinsurance#128 —
compose-sealed-modules.sh: --registry-url needs --registry-key was an absent MW_REGISTRY_KEY
with preflight GREEN. Nothing today would stop the same thing in Plugins.

Its check-workflow-timeouts.py coverage is also thinner than it looks: auto-arm.yml is a
different workflow with a different trigger from the one validate would run on.

What to do, and the two traps that make it not a one-liner

Adopt node-repo-validate.yml in both repos.

  • 🚨 Adopting a shared lane RENAMES that repo's required status-check contexts to
    <caller job> / <name>. That must land in the SAME change as the branch-protection or ruleset
    update, or the repo ends up requiring a context nothing posts — and an absent required context
    counts as SATISFIED, so the failure is a silently unguarded repo, not a stuck PR.
  • 🚨 Branch protection is per-repo and lives in one of two places. Measured: core and Memex use
    rulesets (the classic endpoint 404s, which read as "unprotected" is simply wrong);
    MeshWeaver.Plugins uses classic protection with 5 contexts; the three satellites Three satellites verify nothing about the digest they pin — SocialMedia, Manufacturing and Crm have no pin-consistency gate at all, so a half-moved set merges green #3454 touched
    are classic with strict: false. Check both endpoints, per repo, at the time of the change.
  • A new required input on the lane would be a silent startup failure for existing callers, so
    the adoption must not need one.

Plugins first — it is the one with an actual hole rather than a fragile patch.

Why this is filed rather than fixed

Plugins is mid-release: its platform pin is moving (Plugins#1429), its staleness bound is being
managed, and renaming its required contexts while a tag is being cut off a sealed set is the wrong
hour for it. This is deliberately queued behind the 3.0.0 wave.

Related: #3454 (where the rule came from), #258 / the Education adoption, Reinsurance#128
(the incident the secret preflight exists for), and Doc/Architecture/ModuleBuildArchitecture
("never hand-roll a repo's build; a deviating repo is behind, not different").

Activity

  1. rbuergi commented on Sep 7, 2026

    @rbuergi
    ContributorAuthor

    STAYING OPEN — Manufacturing adopted, Plugins has not, and the contexts prove it

    Verified 2026-09-07T12:25Z. This issue names both repos, so it closes only when both adopt the
    lane. One has.

    Manufacturing — done, contexts renamed in the same change

    • Systemorph/MeshWeaver.Manufacturing#63 — merged = true, merged_at = 2026-09-07T09:05:20Z.
    • Required contexts, read from both endpoints as this issue itself demands:
      • repos/Systemorph/MeshWeaver.Manufacturing/rulesets → one ruleset, 20625978
        "Copilot review for default branch", active — no required-status-checks rule.
      • repos/Systemorph/MeshWeaver.Manufacturing/branches/main/protection → classic, strict: false,
        6 contexts, and the two that matter now carry the caller-job prefix:
        validate / Validate node repos and compile-check / Compile every NodeType (vs core).

    So Manufacturing did not end up requiring a context nothing posts. ✅

    MeshWeaver.Plugins — NOT adopted

    • Systemorph/MeshWeaver.Plugins#1453 ("fix(ci): call the shared validate lane instead of copying
      it"
      ) — state = open, merged = false, mergeable_state = dirty. It needs a merge from main
      before it can even run CI.
    • Protection, both endpoints:
      • rulesets → one ruleset, 19008635 "Copilot review for default branch", active — no
        required-status-checks rule.
      • branches/main/protection → classic, strict: false, 5 contexts, all un-prefixed:
        Validate node repos, Compile every NodeType (vs core), Build + test the portal hosts,
        Module bundles / All selected bundles built, Module bundles (floor) / All selected bundles built.

    The un-prefixed names are the direct evidence that the adoption has not landed. Plugins — the repo
    this issue calls "the one with an actual hole rather than a fragile patch", with no
    check-pr-secret-preflight.py invocation in any workflow — is still unguarded.

    🚨 One correction to #3575's own table, which lists Plugins as "0 (adopted, #1453)": that row
    anticipates a merge that has not happened. #3575 is the durable write-up and merged correctly
    (ce09ad62a); the adoption it describes is half-real.

    Also spun out of this work, already tracked

    #3576 — Crm, SocialMedia and Education call node-repo-validate at a pin that predates the
    secret guard (4 unasserted PR secrets each, MW_REGISTRY_KEY among them). That is the "calling the
    lane is necessary and not sufficient" half and is not this issue.

    This issue closes when Plugins#1453 merges and Plugins' required contexts are renamed to
    <caller job> / <name> in the same change.

    Measured 2026-09-07T12:25Z over REST: pulls/63, pulls/1453, and for each repo BOTH
    rulesets and branches/main/protection — neither classic endpoint 404'd, so rulesets were checked
    for a required-status-checks rule and carry none.

  2. rbuergi commented on Sep 7, 2026

    @rbuergi
    ContributorAuthor

    Plugins#1453 is now UP TO DATE and its own gate is GREEN — blocked only on the platform pin

    Measured 2026-09-07T15:05Z. Two of the three things this issue waits on are done; the third is not mine.

    1. The conflict is resolved and main is in

    fix/3504-plugins-adopts-node-repo-validate was dirty (one conflict: Hosting/manifest.lock,
    both sides having bumped moduleVersion/version off their own trees). Resolved the sanctioned
    way — scripts/gen-manifests.py --resolve, which regenerates over the merged tree, rather than
    by picking a side (scripts/merge-manifest-lock.py's header explains why a merge driver cannot:
    it runs before git has written the other paths). Result 1.13.1 = main's 1.13.0 (index.json
    moved to "1.13") plus the patch the branch's own PlatformBuilds.md edit earns.

    The resolution was diffed against both parents, because a careless one here has silently
    reverted merged fixes in this fleet before:

    direction expectation observed
    origin/main..HEAD only the branch's 8 files exactly the 8, byte-identical hunks (ci.yml, check-shared-lanes.py, the allow file, the two skills, PlatformBuilds.md, the lock, the What's New note)
    3ed781a7..HEAD only main's 18 files exactly main's 18, and ci.yml's 63 changed lines are identical to ef3ffcb7..origin/main's

    Head is now 03cec7ae.

    2. 🚨 The adoption WORKS — validate / Validate node repos is green on the first run that had it

    Run 34135660815:

    success  validate / Validate node repos      ← the shared lane, called not copied
    success  Required CI inputs
    success  Resolve the platform commit
    failure  Repo policy gates
    failure  Compile every NodeType (vs core)    ← "a needed job did not succeed"
    failure  The Tests-area gate's inputs are present
    skipped  Module bundles / Module bundles (floor)
    

    Repo policy gates has exactly one failing step, and it is not this diff:

    26 failure  Neither frozen platform input is stale (image set, source ref)
    

    Reproduced locally against the same inputs: MW_PLATFORM_SET 3.0.0-ci.7938 / MW_PLATFORM_REF aa4075832 are 227 commits and 18.0 h behind core main (5453be493) — bounds 120 and 24 h.
    The pin move is Plugins#1463, whose own CI failed at 11:12Z on Portal hosts (shard 3) → Test the platform projects that moved here. That PR is owned elsewhere and untouched here.

    So the required contexts cannot go green until the pin lands. Everything else on the branch is
    green locally too: check-shared-lanes.py (self-test 11/11, 7 lane calls, 0 violations),
    check-platform-pins.py, check-pr-secret-preflight.py at the pinned core (5 reachable,
    2 asserted, 0 violations
    — the three exemptions hold), check-workflow-timeouts.py
    (18 jobs, 7 reusable-call exemptions, 0 violations), gen-manifests.py --check,
    validate-repos.py (260 nodes / 61 repos), check-modules-published.py, check-skip-sets.py,
    check-test-projects.py, check-build-invocations.py, check-test-references.py,
    check-main-runs-not-cancelled.py.

    3. The context rename is staged, deliberately NOT applied yet

    Measured again from both endpoints (a 404 on the classic one would have meant "look in
    rulesets", never "unprotected" — neither 404'd):

    • rulesets → 19008635 Copilot review for default branch, active, no required-status-checks rule.
    • branches/main/protection → classic, strict: false, enforce_admins: true, 5 contexts, all un-prefixed.

    The target set is validate / Validate node repos + Repo policy gates +
    Compile every NodeType (vs core) + Build + test the portal hosts + the two
    Module bundles… / All selected bundles built.

    🚨 Applying it before the merge would make the deadlock worse, not better. The bare
    Validate node repos is never published again once #1453 lands, and the two new contexts are not
    published by any branch that predates it — so flipping protection now would leave every open
    Plugins PR unable to satisfy the required set, including Plugins#1463, which is the one PR that
    unblocks #1453. The rename therefore goes on immediately after the merge, in the same operation
    window, as this issue asks.

    What is left

    One thing: Plugins#1463 lands → merge main into #1453 again → green → merge → rename the
    contexts → close this.
    Nothing else about the adoption is outstanding.

    Read over REST only. pulls/1453, pulls/1463, actions/runs/34135660815(/jobs),
    actions/runs?head_sha=c5fd9d004…, and both protection endpoints for MeshWeaver.Plugins.

  3. rbuergi commented on Sep 8, 2026

    @rbuergi
    ContributorAuthor

    Backlog audit, 2026-09-08: leaving this open for a concrete remaining step.

    Systemorph/MeshWeaver.Plugins#1453 has now merged (2026-09-08T11:45:46Z, 10768c9f015ffc314f7f73fc7c4feaf0d1d1b0ad), so the earlier discussion's merge blocker is stale. However, the required-context rename has NOT happened.

    Fresh REST reading of Plugins branches/main/protection still requires the old Validate node repos context, plus Compile every NodeType (vs core), Build + test the portal hosts, and the two module-bundle aggregate contexts. It requires neither validate / Validate node repos nor Repo policy gates. Also checked rulesets: the sole active ruleset 19008635 has deletion, non_fast_forward and copilot_code_review rules, with no required-status-checks rule supplying the missing contexts.

    Therefore the issue's explicit closure condition (adoption AND matching branch protection) is still unmet. The remaining action is to replace the stale validation context with the shared lane's emitted context and require Repo policy gates, preserving the other required checks. No protection settings were changed by this audit.

  4. rbuergi commented on Sep 9, 2026

    @rbuergi
    ContributorAuthor

    Completed the remaining protection update for #3504. Plugins main now explicitly requires validate / Validate node repos and Repo policy gates, both bound to GitHub Actions app 15368. Read the saved settings back successfully; strict: false and all five existing required checks are preserved.

    Correction to the previous audit note: current ci.yml has a validate-name-shim which republishes the shared lane result as Validate node repos and fails unless that lane succeeds. The old context therefore was not an unenforced check. I retained it alongside the new names, avoiding a transition with weakened protection. Four currently open PR heads already emit both new names; #1529 has no such reported checks and must update/run the current workflow before merging.

    Both adoption PRs are merged (Manufacturing#63 and Plugins#1453). Manufacturing protection also still requires its shared validation and repository-policy checks. With the explicit Plugins protection requirements now saved, closing as completed. No workflow or application source was changed for this repair.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions