Skip to content

fix(ci): the validate lane compares what the two package enumerators RETURN, not what they declare (#4774) - #5455

Merged
meshweaver-cloud[bot] merged 2 commits into
mainfrom
chore/4774-4777-satellite-enumeration
Sep 23, 2026
Merged

meshweaver-cloud[bot] merged 2 commits into
mainfrom
chore/4774-4777-satellite-enumeration

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

What

node-repo-validate.yml now fetches and runs .github/scripts/check-package-enumeration.py beside the canonical gen-manifests.py. It calls the caller's scripts/validate-repos.py → package_dirs(root) and the canonical's plugin_dirs(root) and compares what they return:

  1. on the checkout, name for name;
  2. on a fixture holding every name either side declares, every top-level dir of the checkout, a probe dot-directory and a probe package — so a disagreement that needs a directory the tree does not contain today (the dot rule, a skip name one side forgot) is red now.

Why (Refs #4774)

Each satellite's own check-skip-sets.py compared the two declared skip sets; plugin_dirs also drops every top-level dot-directory, a rule in no declaration — so equal declarations over different enumerations were green. The guard's first run against MeshWeaver.Plugins found a live one the old guard could not see: dist in both of Plugins' SKIP sets and NOT in the gen-manifests.config.json the canonical actually reads (the verdict enumerator reads neither SKIP).

Ordering (no fleet-wide red)

A caller whose validate-repos.py has no package_dirs yet is named (::warning::package enumeration NOT compared), not failed. Everything else is red: missing/unloadable validate-repos.py, a package_dirs that raises or returns a non-list, an unloadable canonical, a missing config, any disagreement. The satellite adoptions are ready (all seven callers: Plugins, Education, Reinsurance, SocialMedia, Manufacturing, Crm, FundReporting) and are opened after this lands so their CI exercises the guard; the flip of the absent case to red is a follow-up change to this guard once all seven have merged — never a date.

Measured locally against each satellite with the adoption applied: guard green on checkout + fixture in all seven; canonical --check/--check-versions green on every committed tree (no lock or version moves).

Also

  • dotnet-test.yml runs the guard's --self-test (14 cases: both directions on tree and fixture, main() must walk THROUGH package_dirs, every unreadable input red) so a core PR that breaks it is red here.
  • The canonical's two docstrings that named check-skip-sets.py as the contract now name the platform guard (docstring-only; the copy guard reports code-identical).
  • ModuleVersioning.md → "The declared skip is NOT the whole rule" describes the guard, the contract and the ordering.

Local: check-package-enumeration.py --self-test 14/14; gen-manifests.py --self-test green; check-guard-step-masking (107 steps, 0 violations), check-workflow-timeouts, check-workflow-yaml-keys, check-workflow-shell, check-reusable-workflow-runners, check-workflow-permission-pairing green; MeshWeaver.Documentation Release -warnaserror build clean.

Refs #4774 · Refs #4777

Pairs-with: none — removes no public type or member (Python and workflow only).

🤖 Generated with Claude Code

…RETURN, not what they declare (#4774)

A node repo enumerates its top-level packages twice: the platform's canonical gen-manifests.py
(`plugin_dirs`, the verdict) and its own scripts/validate-repos.py. Each satellite's
check-skip-sets.py compared the two DECLARED skip sets, and plugin_dirs applies a rule in no
declaration — a top-level dot-directory is never a package — so equal declarations over different
enumerations were green.

check-package-enumeration.py, fetched and run by node-repo-validate.yml beside the canonical, calls
validate-repos.py's `package_dirs(root)` and the canonical's `plugin_dirs` on the checkout AND on a
fixture holding every declared name, every top-level dir of the checkout, a probe dot-directory and a
probe package — so a disagreement that needs a directory the tree does not contain today is red now.
First run against MeshWeaver.Plugins found a live one: `dist` in both of its SKIP sets and not in the
gen-manifests.config.json the canonical actually reads.

A caller with no package_dirs yet is NAMED (`NOT compared`), not failed: adoption is one PR per
satellite, and reddening first would red every satellite's required validate context at once. The
flip is a change to the guard once all seven callers have adopted. Everything else is red. Self-test
(11 cases, both directions, on tree and fixture) runs in the lane and in core's CI.

Refs #4774, refs #4777.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 23, 2026 04:48

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Moderate correctness and contract-enforcement issues remain in the enumeration guard, with documentation updates also outstanding.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity · 2 Low severity

Open (4)
What changed in this PR

This PR adds a centralized CI guard comparing satellite and canonical package enumeration, with workflow and documentation updates.

Changes:

  • Adds checkout and fixture-based enumeration checks.
  • Integrates the guard and self-tests into CI workflows.
  • Updates the enumeration contract and adoption documentation.
File Review findings
src/​MeshWeaver.Documentation/​Data/​Architecture/​ModuleVersioning.md Two nit findings remain (2 votes; 1 vote): update the outdated config table and correct adoption instructions.
.github/​workflows/​node-repo-validate.yml No final findings.
.github/​workflows/​dotnet-test.yml No final findings.
.github/​scripts/​gen-manifests.py One nit finding remains (2 votes): update the obsolete missing-config diagnostic.
.github/​scripts/​check-package-enumeration.py Five moderate findings remain (3, 1, 2, 1, and 1 votes): enforce list results, handle duplicates, verify main() delegation, avoid probe-name collisions, and register dynamically loaded modules.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/scripts/check-package-enumeration.py Outdated
Comment on lines +125 to +130
package_dirs = getattr(validator, "package_dirs", None)
if not callable(package_dirs):
say("::warning::package enumeration NOT compared: scripts/validate-repos.py exposes no "
"package_dirs(root), so this repo's second enumerator cannot be called "
"(MeshWeaver#4774). Adopt: define package_dirs(root) — SKIP plus the dot-directory rule "
"— and enumerate through it in main().")

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.

Fixed in 3bdbb9d: new main_delegates() parses validate-repos.py statically and reds unless there is exactly one top-level main() that calls package_dirs(...) and contains no iterdir() call of its own. Two self-test cases cover it (main never calls it; main calls it AND walks the tree itself). Measured on all seven satellite adoptions: each main() makes 1 package_dirs call and 0 iterdir calls.

Comment on lines +64 to +66
package in another — and `validate-repos.py`'s `package_dirs(root)` must
return what `plugin_dirs` returns, which the lane's
`check-package-enumeration.py` asserts on the checkout and on a fixture.

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.

Fixed in 3bdbb9d: the missing-config refusal now says validate-repos.py's package_dirs(root) must return what plugin_dirs does and names check-package-enumeration.py. The canonical self-test stays green.

Comment on lines +327 to +332
**The guard is the platform's, and it calls both enumerators.** `node-repo-validate.yml` fetches
`.github/scripts/check-package-enumeration.py` beside the canonical and runs it on every caller. The
contract is one function: the caller's `scripts/validate-repos.py` exposes
`package_dirs(root) -> list[Path]` — its skip set **and** the dot-directory rule, a pure function of
the top-level names — and its own `main()` enumerates through it. The guard then compares what the two
enumerators *return*, twice:

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.

Fixed in 3bdbb9d: the skip row of the config table now states the package_dirs / effective-enumeration contract and points to the guard section below; no remaining check-skip-sets.py contract text in that page except the historical paragraph explaining why it was blind.

… a list; the config refusal and the doc table name the new contract

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

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

  1 files  ±0    1 suites  ±0   2m 40s ⏱️ -12s
326 tests ±0  326 ✅ ±0  0 💤 ±0  0 ❌ ±0 
330 runs  ±0  330 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

443 tests  ±0   443 ✅ ±0   59s ⏱️ +5s
  3 suites ±0     0 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

♻️ This comment has been updated with latest results.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 623 tests  ±0   1 623 ✅ ±0   3m 28s ⏱️ -1s
    2 suites ±0       0 💤 ±0 
    2 files   ±0       0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

    3 files  ±0      3 suites  ±0   6m 3s ⏱️ -15s
1 988 tests ±0  1 988 ✅ ±0  0 💤 ±0  0 ❌ ±0 
1 989 runs  ±0  1 989 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

731 tests  ±0   539 ✅ ±0   7m 5s ⏱️ ±0s
  3 suites ±0   192 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    5 files  ±0      5 suites  ±0   15m 51s ⏱️ +59s
3 992 tests ±0  3 990 ✅ ±0  2 💤 ±0  0 ❌ ±0 
3 996 runs  ±0  3 994 ✅ ±0  2 💤 ±0  0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   17 files  ±0     17 suites  ±0   36m 8s ⏱️ +36s
9 103 tests ±0  8 909 ✅ ±0  194 💤 ±0  0 ❌ ±0 
9 112 runs  ±0  8 918 ✅ ±0  194 💤 ±0  0 ❌ ±0 

Results for commit 3bdbb9d. ± Comparison against base commit 39f4949.

@meshweaver-cloud
meshweaver-cloud Bot added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 9efc808 Sep 23, 2026
41 checks passed
@rbuergi
rbuergi deleted the chore/4774-4777-satellite-enumeration branch October 10, 2026 13:09
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.

2 participants