Repository navigation
The combo assembler: materialise an instance's recorded module set for the gate - #1097
Conversation
…r the gate Step 2 of the Candidate Release Protocol's instance gate (step 1, the InstanceComboReader, merged as #1091). InstanceComboAssembler turns an InstanceCombo into the repo-root layout mw-plugin-test verifies — every module's files at its RECORDED ref under <workRoot>/<ModuleId>/ — plus a manifest (combo-assembly.json) naming module → resolved ref → content hash, so the gate's verdict can name its exact input. Semantics: GitSync coordinates fetch repositoryUrl at lastSyncCommitSha (one shallow pack via the existing IGitHubRepoClient.Fetch seam, never a history clone); package coordinates go through NodeRepoPackageSource.FetchPackageFiles against a snapshot fetched once per (repo, ref). Moving/unrecorded refs are REFUSED by default — a gate run on a moving ref is not evidence — with --allow-moving as the explicit opt-in, stamped as Moving in the manifest; a recorded ModuleVersion with only a movable fetch ref must PROVE itself against the tree's manifest.lock. A known-incomplete combo refuses the whole run. Fetches are bounded and a failure is NAMED for exactly the modules riding it — breadth-complete, never stop-at-first. mw-combo-assemble (tools/MeshWeaver.ComboAssembler) is the console boundary, one Task bridge in Program.cs, everything below reactive. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPQKMhQDpitUzsW1MqTVhH
There was a problem hiding this comment.
Pull request overview
Implements step 2 (“combo assembler”) of the Candidate Release Protocol instance gate by materializing an InstanceCombo into a repo-root directory suitable for mw-plugin-test, and producing a manifest (combo-assembly.json) that records the exact assembled inputs.
Changes:
- Added
InstanceComboAssembler+ manifest/report model to fetch modules at recorded refs, materialize their file trees, and record resolved commits + deterministic content hashes. - Added
mw-combo-assembleconsole tool as the CLI boundary for assembling combos. - Added an integration-style unit test suite for the assembler behavior and a What’s New entry.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/MeshWeaver.ComboAssembler/Program.cs | New CLI entrypoint + argument parsing; wires Git fetch client + InstanceComboAssembler. |
| tools/MeshWeaver.ComboAssembler/MeshWeaver.ComboAssembler.csproj | New console project definition (multi-arch RIDs) referencing PluginCatalog + GitSync. |
| src/MeshWeaver.PluginCatalog/InstanceComboAssembler.cs | Core implementation: planning/refusal policy, grouped fetch/materialize pipeline, hashing, and manifest writing. |
| src/MeshWeaver.PluginCatalog/ComboAssembly.cs | New public DTOs/options/enums for assembly policy and manifest/report shape. |
| test/MeshWeaver.PluginCatalog.Test/InstanceComboAssemblerTest.cs | New tests covering refusal semantics, layout, manifest contents, proof rules, and breadth-complete failure reporting. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-10-your-exact-plugin-set-can-be-rebuilt-for-verification.md | What’s New entry describing the new capability and evidence semantics. |
| MeshWeaver.slnx | Adds the new combo assembler tool project to the solution. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| case "--fetch-timeout" when i + 1 < args.Length: | ||
| fetchTimeout = TimeSpan.FromSeconds( | ||
| double.Parse(args[++i], CultureInfo.InvariantCulture)); | ||
| break; |
| var moduleRoot = Path.Combine(Path.GetFullPath(workRoot), moduleId); | ||
| Directory.CreateDirectory(moduleRoot); | ||
| var manifest = new StringBuilder(); |
Test Results (shard 5)1 773 tests 1 581 ✅ 6m 19s ⏱️ Results for commit 0451c83. ♻️ This comment has been updated with latest results. |
Test Results 65 files 65 suites 50m 55s ⏱️ Results for commit 0451c83. ♻️ This comment has been updated with latest results. |
Step 2 of the Candidate Release Protocol's instance gate (
Doc/Architecture/CandidateReleaseProtocol→ "What is missing is only the combo assembler"). Step 1, the reader, merged as #1091.What this adds
InstanceComboAssembler(src/MeshWeaver.PluginCatalog) turns anInstanceCombo— what an instance actually runs, asInstanceComboReaderstates it — into a materialised repo-root directory thatmw-plugin-testverifies: every module's files at its recorded ref under<workRoot>/<ModuleId>/, plus a manifest (combo-assembly.json) naming module → resolved ref → content hash, so the gate's verdict can name its exact input (this later lands onAdmin/UpdatePolicy).mw-combo-assemble(tools/MeshWeaver.ComboAssembler) is the console boundary, mirroringmw-plugin-test's shape — the one Task bridge lives inProgram.cs; everything below is reactive:Semantics — a gate run on a moving ref must never silently become evidence
repositoryUrlatlastSyncCommitShawith the recordedsubdirectory— one shallow pack over the existingIGitHubRepoClient.Fetchseam (git protocol; no whole-history clone, no hand-rolled git).NodeRepoPackageSource.FetchPackageFilesagainst a snapshot fetched once per (repo, ref) — the same in-memory-snapshot patternmw-plugin-testuses, inheriting its binary-preservation semantics (Registry does not publish binary content — course/plugin videos drift between git and portal storage #848). The install record names a source, not a URL, so the tool takes--source <name>=<url>mappings.RefFidelity.Moving/Unrecordedare REFUSED by default, with an error naming the module and the way out;--allow-movingis the explicit opt-in, and the manifest then stamps the pin asMovingso it can never read as reproducible evidence.ModuleVersionwith only a movable fetch ref must PROVE itself: the fetched tree'smanifest.lockmodule version has to match, or the module is a named failure ("the ref moved past the recorded install") —VerifiedModuleVersionpin on success.IsComplete == falserefuses the whole run (--allow-incompleteoverrides): a known-short combo assembled silently would verify a subset while reading as though it verified the instance.--fetch-timeout), a fetch failure is a NAMED failure for exactly the modules riding it, and the run continues to collect ALL failures. The manifest is written even on refusal, documenting why nothing was materialised.Verified
dotnet build -c Release -warnaserrorclean onMeshWeaver.PluginCatalog,MeshWeaver.ComboAssembler,MeshWeaver.PluginCatalog.Test(re-run after merging current main, which movedDirectory.Build.props).InstanceComboAssemblerTest(synthetic combos against in-memory fixture repos — no network, no mesh): refusal on moving/unrecorded refs before any fetch, the tester layout (<ModuleId>/index.jsontop-level, foreign folders excluded), manifest shape + deterministic content hashes, module-version proof (match + mismatch), named fetch failures with breadth-completeness, incomplete-combo refusal. All green, plusWhatsNewEntryIntegrityTest/DocumentationLinkIntegrityTest.MeshWeaver.SocialMediaat an exact sha materialised 24 files into<work>/SocialMedia/(index.json at the tester's expected place) and exited 0.What step 3 still needs
Wiring the gate: run
mw-combo-assemble+mw-plugin-testinside the candidate image over an instance's combo (reader → combo.json → assembled root → tester), and report the verdict toAdmin/UpdatePolicyas "cannot update to X — these installed modules do not compile/pass against it".🤖 Generated with Claude Code
https://claude.ai/code/session_01CPQKMhQDpitUzsW1MqTVhH