Skip to content

fix(gitsync): accept build signals only from content CI - #3981

Merged
meshweaver-cloud[bot] merged 3 commits into
mainfrom
codex/fix-3978-content-ci-signal
Sep 11, 2026
Merged

meshweaver-cloud[bot] merged 3 commits into
mainfrom
codex/fix-3978-content-ci-signal

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #3978

Root cause

GitSync treated how a workflow started plus its branch as proof that the workflow compiled repository content. A green scheduled PR updater or a push-triggered chart check could therefore overwrite BuildCompletion for a commit whose real content CI was red.

Fix

  • Require the stable workflow file path as a third independent admission guard.
  • Use .github/workflows/ci.yml by convention for node/content repositories and .github/workflows/dotnet-test.yml only for the exact Systemorph/MeshWeaver identity.
  • Allow repositories with a nonstandard content workflow to declare an explicit repository-level path override under GitHub:ContentWorkflows:Repositories.
  • Match repository identities case-insensitively and workflow paths case-sensitively; missing or different paths fail closed.
  • Add a shared node-repo gate, with a self-test, so renaming content CI fails red instead of silently freezing imports.
  • Reconcile with GitSync: a source that never converges re-clones its WHOLE repository on every green build — lastSyncCommitSha is both the cheapness gate and the convergence guard #3945 so accepted content-CI repeats still use its final-verdict skip, while unrelated workflows never create a build fact.
  • Document the publish-signal contract and user-visible fix.

Evidence

Red-before discriminator stub: 6 failures and 24 passes, covering unrelated chart, probe, updater, deployment, missing-path, and processor-composition cases.

Green after merging current main and addressing review:

Required rollout

After this core change merges, each shared-workflow caller must pin the resulting core revision so the new validation gate becomes live: MeshWeaver.Plugins, MeshWeaver.Education, MeshWeaver.Reinsurance, MeshWeaver.SocialMedia, MeshWeaver.Manufacturing, and MeshWeaver.Crm. This issue is not considered delivered until those six pin updates pass their required checks and merge.

The pull request remains draft while the delivery lane is serialized.

Copilot AI lite review requested due to automatic review settings September 10, 2026 20:53

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.

🟡 Changes recommended

Unresolved critical and moderate findings remain around workflow scope, repository identity, rollout enforcement, and case-sensitive path validation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Tightens GitSync so only successful content-CI workflows can publish build completions.

Changes:

  • Adds exact workflow-path admission checks.
  • Adds CI enforcement and regression coverage.
  • Documents the publish-signal contract and user-facing fix.
File summaries
File Summary Review status
test/MeshWeaver.Hosting.Test/BuildTriggeredSyncPinsTheBuiltCommitTest.cs Tests build-triggered synchronization behavior. Reviewed
test/MeshWeaver.Documentation.Test/GreenBuildPublishSignalTest.cs Tests workflow admission rules. Moderate: Case-sensitive path validation is not fully covered on macOS.
src/MeshWeaver.GitSync/GitHubWebhookProcessor.cs Applies content-CI workflow filtering. Critical: Arbitrary repositories need workflow-path configuration, and the core exception must use the full repository identity.
src/MeshWeaver.Documentation/Data/WhatsNew/2026-09-10-only-content-ci-can-publish-a-repository.md Adds the user-facing fix entry. Reviewed
src/MeshWeaver.Documentation/Data/Architecture/SyncRefContract.md Documents the publish contract. Reviewed
src/MeshWeaver.Documentation/Data/Architecture/PluginUpdateOnGreenBuild.md Updates build-signal guidance. Reviewed
src/MeshWeaver.Documentation/Data/Architecture/GitSyncTriggerCost.md Records corrected trigger behavior. Reviewed
.github/workflows/node-repo-validate.yml Runs the shared content-CI path guard. Moderate: Existing callers must adopt the updated reusable workflow revision.
.github/scripts/check-content-ci-path.py Validates the exact node CI path. Reviewed
Review details

Suppressed comments (2)

.github/workflows/node-repo-validate.yml:111

  • This guard is inert for every satellite that still references the reusable workflow at its existing pinned SHA; the caller contract above requires uses and platform-ref to move together, and this PR changes no callers. Until each node repo adopts this revision, a renamed ci.yml still passes its old validation lane and can silently freeze GitSync. Please land the coordinated caller pin bumps (or explicitly track them as a required rollout) before relying on this protection.
      - name: Fetch the content-CI publish-path guard at the lane's scripts ref
        env:
          GH_TOKEN: ${{ github.token }}
          SCRIPTS_REF: ${{ inputs.scripts-ref || inputs.platform-ref }}
        run: |
          set -euo pipefail
          [ -n "${SCRIPTS_REF:-}" ] || { echo "::error::scripts-ref / platform-ref are both empty — the content-CI path guard has no ref to be fetched at"; exit 1; }
          gh api "repos/Systemorph/MeshWeaver/contents/.github/scripts/check-content-ci-path.py?ref=${SCRIPTS_REF}" --jq .content | base64 -d > "$RUNNER_TEMP/check-content-ci-path.py" \
            || { echo "::error::could not fetch .github/scripts/check-content-ci-path.py at ${SCRIPTS_REF} from Systemorph/MeshWeaver — a pin older than the guard needs the older lane"; exit 1; }
          head -c 400 "$RUNNER_TEMP/check-content-ci-path.py" | grep -q "check-content-ci-path" || { echo "::error::the fetched check-content-ci-path.py at ${SCRIPTS_REF} does not look like the guard"; exit 1; }
      - name: "The content-CI publish path is enforced — the gate can fail (self-test)"
        run: python3 "$RUNNER_TEMP/check-content-ci-path.py" --self-test
      - name: "Content CI remains at GitSync's publish-signal path"
        run: python3 "$RUNNER_TEMP/check-content-ci-path.py" --root . --expected .github/workflows/ci.yml

test/MeshWeaver.Documentation.Test/GreenBuildPublishSignalTest.cs:204

  • This guard uses File.Exists, which is case-insensitive on the default macOS checkout. Renaming the workflow to Dotnet-Test.yml therefore passes this test locally even though IsRepositoryContentWorkflow compares Git paths case-sensitively and would reject every core build signal, silently freezing imports. Check the directory entry name with an ordinal comparison, as the node-repo Python guard does.
        var root = SourceScan.FindRepoRoot();
        Assert.True(File.Exists(Path.Combine(
                root, ".github", "workflows", "dotnet-test.yml")),
            "moving core content CI would make every workflow_run fail the path discriminator; "
            + "the renamed workflow must fail red instead of silently freezing GitSync");
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

…t-ci-signal

# Conflicts:
#	src/MeshWeaver.Documentation/Data/Architecture/GitSyncTriggerCost.md
#	src/MeshWeaver.GitSync/GitHubWebhookProcessor.cs
@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

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

Results for commit b7d011d. ± Comparison against base commit f1a945d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

500 tests  ±0   500 ✅ ±0   45s ⏱️ +10s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

390 tests  ±0   390 ✅ ±0   59s ⏱️ +13s
  2 suites ±0     0 💤 ±0 
  2 files   ±0     0 ❌ ±0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

1 923 tests  +15   1 923 ✅ +15   3m 26s ⏱️ -7s
    4 suites ± 0       0 💤 ± 0 
    4 files   ± 0       0 ❌ ± 0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

1 273 tests  ±0   1 271 ✅ ±0   3m 53s ⏱️ -1s
    3 suites ±0       2 💤 ±0 
    3 files   ±0       0 ❌ ±0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

♻️ This comment has been updated with latest results.

@rbuergi

rbuergi commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Review follow-up b7d011d addresses all four findings: arbitrary repositories have a repository-level workflow-path override with real configuration-binding coverage; the core exception matches the full Systemorph/MeshWeaver identity; the core filename guard enumerates directory entries with ordinal comparison so macOS cannot hide a case-only rename; and satellite adoption is an explicit required rollout after the core merge, because callers must pin the resulting core commit. I will open and land those six MeshWeaver.* pin bumps before calling production delivery complete. Revalidated on the combined #3945 tree: policy 37/37, Hosting 593/593, Documentation 389/389, path-guard self-test 6/6, workflow YAML 34/34, and all strict builds at zero warnings/errors.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    6 files  ±0      6 suites  ±0   6m 23s ⏱️ +48s
2 662 tests +1  2 470 ✅ +1  192 💤 ±0  0 ❌ ±0 
2 666 runs  +1  2 474 ✅ +1  192 💤 ±0  0 ❌ ±0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   17 files  ± 0     17 suites  ±0   17m 32s ⏱️ + 1m 2s
7 002 tests +16  6 808 ✅ +16  194 💤 ±0  0 ❌ ±0 
7 006 runs  +16  6 812 ✅ +16  194 💤 ±0  0 ❌ ±0 

Results for commit b7d011d. ± Comparison against base commit f1a945d.

@rbuergi

rbuergi commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Related source-convergence finding from the SAV production rollout, kept isolated from this PR's workflow-admission work: Store imported new tree B (8ee8a/Store1621) at18:55, then the old sealed generation restored A and pruned B-only nodes at19:10. On the ci8304 roll, normal B imports at21:07 trusted the old successful full-import marker and returned Skipped, advancing lastSyncCommitSha without rereading the current A tree.

There are now 3 deterministic real-mesh RED cases on current main f1a945d in isolated /Users/roland/code/MeshWeaver-store-import-convergence: B→A→B remains stale; same-SHA Reconcile creates the missing B node but leaves the existing stale source because changedNodePaths is empty; the same failure reproduces with two-way protection enabled. Receipts: /tmp/store-convergence-red-test.log and /tmp/store-convergence-results/store-convergence-red.trx.

A bounded candidate is being tested locally: require the current existing import-manifest tokens (including root) to agree before trusting the old marker, and let Reconcile evaluate the full source without Force or conflict bypass. No edits to your checkout, no new PR, push, merge or production mutation. This is distinct from the content-CI workflow-path admission defect. I will supply the exact red/green patch once ready.

The live deployment also has a verified old/new generation overlap: two ci8238 pods continue mesh work during their declared1800-second drain, with deletion deadlines21:31:33 and21:32:36 UTC; newci8304pods correctly use sealed identity s01d65c. Final live source acceptance waits for that retirement as well.

@rbuergi

rbuergi commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

The isolated source-convergence correction is ready as local commit 7aac375b710fd0cb526503f0e40093e08362bf23 in /Users/roland/code/MeshWeaver-store-import-convergence, branch codex/store-import-convergence (clean, based on f1a945d). No push, PR, merge or deployment occurred under the hold.

Production diff: StaticRepoImporter requires current import-manifest tokens, now including the root, before trusting a historical successful marker; explicit reconciliation evaluates the full source instead of trusting the Git diff or per-node import tokens. GitHubSyncService supplies an unscoped diff for Reconcile, without Force. Claims and two-way edit protection are preserved. Six actual-mesh regressions fail on baseline and pass with the patch; 19 targeted Hosting/GitSync, 51 surrounding Graph importer and20 documentation/reactive guards pass. Release builds are warning/error-free. The committed StaticRepoImport architecture page and release note conserve the evidence and full-reconcile cost.

Current production correction: after both oldci8238pods retired at their declared deadlines, the remaining3ci8304pods are on the correct seal. Store1.10 nowhas matching adopted/current fingerprintbf501962b9ea4c2a, module1fb8490d29406f6a, and the new nodes; textarea schema exposesariaLabel. Thus the21:07false-skip was real historical evidence, not a claim that Store is still old now. The importer patch prevents that recurrence and is ready for coordinated ownership/release when the lane permits.

A separate replica-local content-registration warning remains in /health forStore/Catalog,Store/Plugin,Store/Tier despite correct source/framework and successful freshviews; no runtime mutation has been attempted to hide it.

@rbuergi

rbuergi commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor Author

The independent returning-source importer fix is now complete locally at ac3de620a6fc5550dafd59dd0a577e662abc2ef4, atop 7aac375b710fd0cb526503f0e40093e08362bf23, in /Users/roland/code/MeshWeaver-store-import-convergence. Please retain BOTH commits when this is integrated after the hold.

Follow-up review found and fixed one scoped-root gap in the first commit: B→A with only index.json changed wrote root A but retained B's manifest token, so returning to B skipped and left root A. The actual content regression is red on 7aac and green after the one-condition correction to always record the root token EnsureRoot evaluated. Final Release validation: 20 Hosting/GitSync cases (all 7 returning-source regressions), 51 Graph importer cases and 20 documentation/reactive guards, zero build warnings/errors. Claims, prune guards and human-edit protection remain intact.

The full two-commit patch applies cleanly to inspected main 89c914b6, this PR's b7d011d and their combined tree. After the hold, transplant both in order onto then-current main and rerun the three validation selections; patch application alone is not an integration pass. This PR governs which content-CI completion can request an import; the importer fix governs whether the requested content is actually still present. No overlapping source change was found.

Durable core documentation: src/MeshWeaver.Documentation/Data/Architecture/StaticRepoImport.md in the two commits. It also records a separate pre-existing last-child removal observation explicitly as source-review-only and outside this correction. All work remains local/unreleased, with no force import or production mutation. The SAV feature still waits on coordinated release clearance.

Integration follow-up: the isolated combined source abf7074509a60c77117f933f4084b18bddd1a203 (main 89c914b6 + this PR's b7d011dd + both importer changes) now passes 129 selected tests: 21 Hosting/GitSync, 51 Graph importer, 20 documentation/reactive and 37 workflow-admission, with zero failures/skips and all three Release builds at zero warnings/errors. The receipt is committed locally as be1c9a809135f0cb8ebc51b71bf61cbdc4de31b6 in /Users/roland/code/MeshWeaver-store-import-integration; original importer branch remains preserved. This is stronger combined-tree readiness evidence, but final main/#3985 changes and supported release acceptance remain pending. A concise proposed PR title/body is ready in /tmp/store-importer-pr-{title.txt,body.md}; no core push was made.

Final-main readiness at 22:43 UTC: #3985 has merged as 3e731d947244b51b19f4c78b1114fc4273a9a840. Both importer changes apply cleanly in /Users/roland/code/MeshWeaver-store-import-final-main, branch codex/store-import-final-main; source 2b1b41d80d5a60fccc8fba8a50d31b50441f829a, durable receipt 08e919d9cfe2cf995d4d471997a9965025dd225c. The replay Data files and importer/service/seven-case regression are byte-identical to owner-replay integration 0687a719, which also passed all 129 selections. Final main differs from that snapshot only by this PR still being absent and the restored bilingual ui.gitSync.settled key. JSON/key parity and three documentation integrity tests pass with a clean Release build; no redundant full-suite run is claimed. Exact comparisons are in /tmp/store-import-final-main-readiness.json and the prepared PR body is updated. No core push, new PR, merge or deployment has been made. Keep the hold until your clearance; review final main/#3981 before release.

Additional SAV release dependency (23:28 UTC): a narrow existing-policy precedence correction is committed locally as 56260054ab20bf179bd3f3e0e947b5dfea75e60a in /private/tmp/roadmap-entitlement-read-cap-review. It has executed red/green evidence plus 23 core, 33 existing security and 6 documentation checks. A paired Store correction is being finalized with an additional background-reconcile recovery regression. The redacted local finding is /Users/roland/code/MeshWeaver.Plugins-entitlement-privacy/Store/EntitlementPrivacy.md; no learner identifiers are included here. This adds an access-boundary prerequisite to the SAV launch, separate from this PR's workflow-admission scope. No core push or release was made, and the hold is preserved. Please coordinate the narrow corrective publication with this task after the current CD/permission-repair sequence clears; importer and policy integration readiness is being prepared against final main.

Reply to the release-task delegation about the user-home OperationRequest copy: SAV has no intended dependency on it and did not deliberately create or repair that production copy. LearningRoadmap installation is still local-only under isolated test learner homes; deliberate production SAV edits were the non-GitSynced post/talk/demo links. An automatic preinstall caused by ordinary browsing/MCP use has not been ruled out. I will leave the copy untouched while you trace the installer. Direct task replies still fail with “Cannot steer conversation ... without an active turn id”, hence this update to the existing handoff. The importer/privacy integration readiness and separate PR drafts are now conserved in /tmp/roadmap-core-integration-handoff/, with clean receipt commit e2de2fc971cfa0fa1d7edf90cb49862d7ae561c8; no combined-PR decision or release action.

Coordination reply at 23:46 UTC: neither the SAV task nor its three agents is editing core #3983 or #3984 (pod-hub startup/delivery placement). Both are free for the release task to own. Our core scope is the two returning-source importer corrections plus the read-cap privacy correction; the active watcher recovery work is in Plugins. Direct app task replies still fail, so this existing handoff and the SAV task's latest commentary carry the answer.

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

Labels

None yet

Projects

None yet

2 participants