Skip to content

feat(control-lane): a plan never contains a listing — targets (query + count), action-plan/v2 - #5792

Merged
rbuergi merged 3 commits into
mainfrom
feat/control-lane-plan-targets
Sep 27, 2026
Merged

rbuergi merged 3 commits into
mainfrom
feat/control-lane-plan-targets

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

What

This is a follow-up to #5785. It aligns the control lane's plans with MeshWeaver.Plugins#2426, per the rule that a plan never contains a listing.

  • ControlLanePlanTarget (label, query, count) and ControlLanePlanStep.Targets: the same shape as Plugins' PlanTarget / ActionPlanStep.Targets.
  • ControlLanePlan.Digest(): a plan whose steps carry targets digests as action-plan/v2. This is the exact encoding of ActionPlanSnapshot.Digest: per step, the target count, then each target's query and count, never the label. A plan without targets stays v1 byte for byte.
  • SpaceDeletion.PlanSteps replaces StepsOf. It emits the plan RoutingGrain no-live-subscriber storm: 20,718 errors/3h on memex-cloud (~2/s) — dead portal/circuit and cache/ addresses churned as errors #2426's DeleteSpaceRunner.PlanOf shows:
    • The space root is path:X with count 1.
    • NodeTypes, grants, GitSync nodes and content roots are each a query with a count.
    • The subtree is path:X scope:subtree with no count.
    • Outside dependents appear as a count in the command only.
  • Recycle states its address as path:X with count 1. Its network is a count plus the digest of the exact address set, and the notes no longer list any addresses.
  • Doc: the Doc/Architecture/ControlLane digest section is updated. The "Owner commands" section is untouched, and Secrets: write-only entry, split identities — operator verbs, design doc, CI guard #5790 owns that wording.

Verification

  • dotnet build -c Release -warnaserror, 0 warnings: MeshWeaver.Graph, MeshWeaver.Graph.Test, Memex.Portal.Shared, MeshWeaver.Documentation.Test.
  • ControlLaneTest 14/14. The new APlanWithTargets_IsTheActionPlanV2Encoding pins the v2 preimage and shows that a label is not bound. The DeleteSpace end-to-end test now asserts that no step command names a member (Doomed/Page) and that the subtree target is uncounted.
  • MeshWeaver.Documentation.Test 649/649.

Cross-repo

Pairs-with: none — SpaceDeletion.StepsOf is removed, but it merged hours ago in #5785 and nothing outside core references it. Its only consumer is the unmerged Plugins branch feat/control-instance-lane (Systemorph/MeshWeaver.Plugins#2433), which moves to PlanSteps in the same wave. The NamedDependents constant goes with it for the same reason.
Implementers: none — no member is added to an existing interface.
Mirror-sync: none — no i18n key is added or changed.

🤖 Generated with Claude Code

…gets (query + count), action-plan/v2

SpaceDeletion.PlanSteps replaces StepsOf: every set a step acts on is a ControlLanePlanTarget (an
anchored, scoped query with its count) — the subtree uncounted, outside dependents and a network as
counts only — the same plan MeshWeaver.Plugins#2426's DeleteSpaceRunner.PlanOf shows. A plan with
targets digests as action-plan/v2 exactly as ActionPlanSnapshot.Digest; target-less stays v1.
Recycle states its address as path:X (count 1) and no longer lists its network in the notes.

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

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 issues remain in malformed-target handling and deletion target/count alignment.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
What changed in this PR

This PR updates control-lane plans to use structured query/count targets and action-plan/v2 digests while preserving v1 compatibility.

Changes:

  • Reworks deletion and recycle plans to avoid member listings.
  • Adds target-aware digest encoding and validation.
  • Updates tests and architecture documentation.
File Summary
test/​MeshWeaver.Graph.Test/​ControlLaneTest.cs Tests v1/v2 digests and target behavior.
src/​MeshWeaver.Graph/​ControlLane/​SpaceDeletion.cs Generates structured deletion targets.
src/​MeshWeaver.Graph/​ControlLane/​ControlLaneOperations.cs Uses structured plans for deletion and recycle.
src/​MeshWeaver.Graph/​ControlLane/​ControlLaneEnvelopes.cs Adds targets and digest versioning.
src/​MeshWeaver.Documentation/​Data/​Architecture/​ControlLane.md Documents target-based digest semantics.

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

public static string RootQuery(string space) => $"path:{space}";

/// <summary>The space's direct children — a rootless space's content roots. Pure.</summary>
public static string ChildrenQuery(string space) => $"namespace:{space} scope:children";

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.

Acknowledged, and not changed in this PR on purpose. These queries and labels are byte-for-byte the plan MeshWeaver.Plugins#2426 introduced (DeleteSpaceRunner.PlanOf), and after this PR the in-process runner delegates to this function. Changing the predicate here would therefore change both paths at once. It should be a deliberate design change, not a side effect of the lane alignment. Two things narrow the gap. First, the GitSync step runs before content deletion, so a rootless space's direct _GitSync row is gone before the content roots are deleted. Second, the count comes from the inventory, and the inventory is what executes. Filed to bug triage as a follow-up for the shared plan (rbuergi/Feedback/plan-target-queries-vs-inventory-predicates-20260927).

$"namespace:{space} scope:descendants nodeType:{AccessAssignmentGuard.AccessAssignmentNodeType}";

/// <summary>Every GitSync configuration node in the space. Pure.</summary>
public static string GitSyncQuery(string space) => $"namespace:{space} scope:descendants nodeType:{GitSyncNodeType}";

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.

Same as the sibling thread. The query is #2426's shared plan shape, and the bound count comes from the inventory predicate that executes (IsGitSync is path-or-type). A path-only _GitSync row counted but not matched by nodeType:GitHubSyncConfig is a real display/test mismatch. Aligning it means giving both targets non-overlapping queries (the exact _GitSync path plus typed entries). That belongs in the shared plan for both paths, and it is filed in the same triage item (rbuergi/Feedback/plan-target-queries-vs-inventory-predicates-20260927).

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

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

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

410 tests   410 ✅  1m 2s ⏱️
  1 suites    0 💤
  1 files      0 ❌

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

1 678 tests   1 678 ✅  4m 1s ⏱️
    2 suites      0 💤
    2 files        0 ❌

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

1 006 tests  +545   1 006 ✅ +545   6m 6s ⏱️ + 5m 9s
    1 suites  -   2       0 💤 ±  0 
    1 files    -   2       0 ❌ ±  0 

Results for commit 18b93f4. ± Comparison against base commit f7dd509.

This pull request removes 461 and adds 1006 tests. Note that renamed tests count towards both.
MeshWeaver.Deployment.Contract.Test.ConfigurationBindingTest ‑ ARecordInjectedAsConfigurationBindsBackIdentically
MeshWeaver.Deployment.Contract.Test.ConfigurationBindingTest ‑ AnAbsentSectionBindsToNoRecord
MeshWeaver.Deployment.Contract.Test.ConfigurationBindingTest ‑ TheEnvironmentKeyIsTheConfigurationKeyInEnvironmentForm
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ ABareRecordStatesItsStorageAndPort
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ AnExplicitIssuerStandsAndNoneIsKept
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ AnInstanceWithATlsSecretAsksForItsCertificateByDefault
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ EveryTransformLeavesItsInputUntouched
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ TheActionsExecutorReachesTheConfigWithTheOperatorJobOff
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ TheEuAiKeysRenderUnderThePortalsNames
MeshWeaver.Deployment.Contract.Test.FluentBuilderTest ‑ TheSameRecordRendersTheSameKeysForHelmAndForAspire
…
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ ADefinitionThatDidNotMove_CompilesFromTheBatchSet
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ ADefinitionThatMovedDuringTheSweep_IsJudgedAsItNowStands(newCode: "public static class ConsumerApi { public static in"···, expected: CompileError)
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ ADefinitionThatMovedDuringTheSweep_IsJudgedAsItNowStands(newCode: "public static class ConsumerApi { public static in"···, expected: Compiled)
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ AGenuineCompileError_StillGates
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ AMovedDefinitionWhoseSourcesCannotBeEstablished_IsNotEvaluated
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ ASourceEditedUnderUnchangedQueries_IsCompiledAsItNowStands
MeshWeaver.Hosting.Test.ABakeCompilesTheDefinitionItResolvedTest ‑ ATypePrunedDuringTheSweep_IsRemoved_AndNotRecreated
MeshWeaver.Hosting.Test.ABakedTypeRegistersWithoutAnInstanceTest ‑ ABakedTypeNobodyActivated_IsRegisteredByThePass_WithoutARecompile
MeshWeaver.Hosting.Test.ABakedTypeRegistersWithoutAnInstanceTest ‑ ATypeWithNoBuild_IsSkipped_NotCompiled
MeshWeaver.Hosting.Test.ACloseCarriesItsReasonTest ‑ AnAbsentOrUnknownReasonIsUnknown_NotCompleted(wireValue: "   ")
…

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

    1 files      1 suites   5m 56s ⏱️
2 184 tests 2 184 ✅ 0 💤 0 ❌
2 185 runs  2 185 ✅ 0 💤 0 ❌

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    2 files      2 suites   8m 6s ⏱️
2 711 tests 2 711 ✅ 0 💤 0 ❌
2 715 runs  2 715 ✅ 0 💤 0 ❌

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    8 files      8 suites   28m 22s ⏱️
8 337 tests 8 337 ✅ 0 💤 0 ❌
8 346 runs  8 346 ✅ 0 💤 0 ❌

Results for commit 18b93f4.

♻️ This comment has been updated with latest results.

@meshweaver-cloud
meshweaver-cloud Bot added this pull request to the merge queue Sep 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 27, 2026
@meshweaver-cloud

Copy link
Copy Markdown
Contributor

⛔ Merge-queue steward: left dequeued — a job other than a test shard failed — a build or gate failure is never a flake.
Group build: https://github.com/Systemorph/MeshWeaver/actions/runs/36307979031

  • failed job: Dependent suites (MeshWeaver.Plugins)

Not a catalogued flake. Fix the failure, or — with run URLs, an issue and an assertion-message pattern — add it to .github/known-flakes.json (see Doc/Architecture/MergeQueue). Re-queue with gh pr merge <n> --auto once the head is green; label queue-rejected marks this PR as needing a person.

@meshweaver-cloud meshweaver-cloud Bot added the queue-rejected The merge queue rejected this PR on an uncatalogued failure; a person owns it now label Sep 27, 2026
@rbuergi

rbuergi commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Re-queueing on evidence: the queue build's only red was Dependent suites (MeshWeaver.Plugins) reporting SILENCE after 42 min ("did not answer within 42 min"). This was the Plugins runner pool being saturated, with four core-candidate runs queued at the same time. The dependent run dispatched for this candidate, https://github.com/Systemorph/MeshWeaver.Plugins/actions/runs/36308382966 (created 09:07:46Z, when this queue build started), has since completed success. So the suites pass against this candidate. The verdict arrived after the waiting job's deadline.

@rbuergi rbuergi removed the queue-rejected The merge queue rejected this PR on an uncatalogued failure; a person owns it now label Sep 27, 2026
@rbuergi
rbuergi added this pull request to the merge queue Sep 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 27, 2026
@meshweaver-cloud

Copy link
Copy Markdown
Contributor

⛔ Merge-queue steward: left dequeued — a job other than a test shard failed — a build or gate failure is never a flake.
Group build: https://github.com/Systemorph/MeshWeaver/actions/runs/36320379707

  • failed job: Dependent suites (MeshWeaver.Plugins)

Not a catalogued flake. Fix the failure, or — with run URLs, an issue and an assertion-message pattern — add it to .github/known-flakes.json (see Doc/Architecture/MergeQueue). Re-queue with gh pr merge <n> --auto once the head is green; label queue-rejected marks this PR as needing a person.

@meshweaver-cloud meshweaver-cloud Bot added the queue-rejected The merge queue rejected this PR on an uncatalogued failure; a person owns it now label Sep 27, 2026
rbuergi added a commit that referenced this pull request Sep 27, 2026
…ward re-queues it, capped

Five core PRs (#5789 #5791 #5792 #5793 #5795) sat queue-rejected on 2026-09-27 for one reason:
'MeshWeaver.Plugins did not answer within 42 min (no verdict yet)' — the dependent's legs never got
a runner, while every candidate that did run was green. The steward classed that as a gate/build
failure ('never a flake') and left them out.

- await-dependent-verdict.py: silence exits EXIT_NO_VERDICT=3 (still red, never a pass); every
  verdict-shaped red stays exit 1.
- dotnet-test.yml: the wait step hands exit 3 to its own failing step, 'No verdict in time: the
  dependent's suites did not report (infrastructure)'.
- merge-queue-steward.py: a Dependent-suites job that failed ONLY on that step is starved, not
  failed — re-queue kind=infra, capped 2 per head sha with the marker comment; beside a build
  failure or an uncatalogued assertion it still rejects; a verdict red still rejects. Nine new
  self-test rows (66 ok).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi added this pull request to the merge queue Sep 27, 2026
@rbuergi
rbuergi enabled auto-merge September 27, 2026 16:46
# Conflicts:
#	src/MeshWeaver.Documentation/Data/Architecture/ControlLane.md
#	test/MeshWeaver.Graph.Test/ControlLaneTest.cs
rbuergi added a commit that referenced this pull request Sep 27, 2026
…letion: targets for GitSync / teardown (grants, subtree, NodeTypes), counts not listings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rbuergi
rbuergi merged commit 18b4dd7 into main Sep 27, 2026
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

queue-rejected The merge queue rejected this PR on an uncatalogued failure; a person owns it now

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants