fix(registry): allow ancestor↔descendant A2A so audit_summary can reach PM - #102
Merged
Merged
Conversation
…ch PM Found via deep workspace inspection during a maintenance cycle: Security Auditor's hourly cron correctly tries to delegate_task its audit_summary to PM, the platform proxy rejects with "access denied: workspaces cannot communicate per hierarchy", the agent falls back to delegating to its direct parent (Dev Lead), and PM's category_routing dispatcher (#75) is never reached. This breaks the audit-routing contract end-to-end. Every audit cycle was landing on Dev Lead instead of being fanned out via PM's category_routing to the right dev role (security → BE+DevOps, ui/ux → FE, etc). ## Root cause `registry.CanCommunicate()` only allowed: - self → self - siblings (same parent) - root-level siblings - direct parent → child - direct child → parent A grandchild → grandparent (Security Auditor → PM, where parent is Dev Lead and grandparent is PM) was DENIED. The original design wanted strict hierarchy to prevent rogue horizontal A2A — but it also broke the fundamental "child can talk to its leadership chain" pattern that any audit/escalation flow needs. ## Fix Generalise to ancestor ↔ descendant. Any workspace can talk to any ancestor (any depth) and any descendant (any depth). Direct parent/child remains a fast path that avoids the walk. Sibling rules unchanged. Cousins still cannot directly communicate (would need to go through their shared ancestor). Cross-subtree A2A is still rejected. Implementation: `isAncestorOf(ancestorID, childID)` walks the parent chain in Go with a maxAncestorWalk=32 safety cap so a malformed cycle in the workspaces table cannot loop forever. One DB lookup per step. For a typical 3-deep tree, this adds 1-2 extra lookups vs the old direct-parent fast path. Could be optimized to a single recursive CTE if profiling shows it matters; not now. ## Tests - TestCanCommunicate_Denied_Grandchild → REPLACED with two new tests: - TestCanCommunicate_Allowed_GrandparentToGrandchild - TestCanCommunicate_Allowed_GrandchildToGrandparent (the actual bug) - TestCanCommunicate_Allowed_DeepAncestor — 4-level chain - TestCanCommunicate_Denied_UnrelatedAncestors — ensures cross-subtree walks still terminate denied - TestCanCommunicate_Denied_DifferentParents — extended with the walk lookup mocks so sqlmock doesn't log warnings - TestCanCommunicate_Denied_CousinToRoot — same All 13 tests pass clean. The previous direct parent/child / siblings / self tests are unchanged (fast paths preserved). ## Why platform-level Per the "platform-wide fixes are mine to ship" rule. Every org template hits the same broken audit-routing chain — fixing it at the platform benefits all users, not just molecule-dev. This unblocks #50 (PM dispatcher prompt) and #75 (category_routing).
molecule-ai Bot
pushed a commit
that referenced
this pull request
Apr 21, 2026
…-chain fix(registry): allow ancestor↔descendant A2A so audit_summary can reach PM
This was referenced Apr 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Discovered via deep workspace inspection during a maintenance cycle: every audit cron in molecule-dev was structurally broken. Security Auditor / UIUX Designer / QA Engineer would correctly try to deliver their hourly `audit_summary` to PM (per #50 + #75), the platform A2A proxy would reject it with 'access denied: workspaces cannot communicate per hierarchy', and the agent would silently fall back to delegating to its direct parent (Dev Lead). PM's category_routing dispatcher was never reached.
Live evidence (just now)
From Security Auditor's memory:
```
Conversation: Delegation results are ready. Review them and take appropriate action:
Error: access denied: workspaces cannot communicate per hierarchy
```
(`f3531ba4...` is PM's workspace ID. Security Auditor's parent is Dev Lead.)
From Security Auditor's recent activity log:
```
2026-04-15T05:13:07 a2a_send ok Delegating to Backend Engineer
2026-04-15T05:12:25 a2a_send ok Delegating to Dev Lead
2026-04-15T03:51:15 a2a_send ok Delegating to Dev Lead
```
Every fall-back delegation went to Dev Lead instead of PM. PM's inbox shows zero `audit_summary` deliveries this entire session.
Root cause
`registry.CanCommunicate()` only allowed: self → self, siblings, root-level siblings, direct parent ↔ child. A grandchild → grandparent (Security Auditor → Dev Lead → PM) was rejected. The original design wanted strict hierarchy to prevent rogue horizontal A2A — but it also broke the leadership-chain pattern that any audit/escalation flow needs.
Fix
Generalise to ancestor ↔ descendant. Any workspace can talk to any ancestor (any depth) and any descendant (any depth). Direct parent/child remains a fast path that avoids the walk; sibling rules unchanged; cross-subtree A2A still rejected.
Implementation: `isAncestorOf(ancestorID, childID)` walks the parent chain in Go with a `maxAncestorWalk=32` safety cap so a malformed cycle in the workspaces table cannot loop forever. One DB lookup per step. For a typical 3-deep tree this adds 1-2 extra lookups beyond the direct-parent fast path. Could be optimised to a single recursive CTE later if profiling shows it matters.
Tests (13 total, all passing)
The previous `Denied_Grandchild` test (which asserted the wrong behaviour) was REPLACED.
Local verification
```
ok github.com/Molecule-AI/molecule-monorepo/platform/internal/registry 0.005s (13 tests)
```
Why platform-level
Per the 'platform-wide fixes are mine to ship' rule. Every org template hits the same broken audit-routing chain — fixing it at the platform benefits all users, not just molecule-dev. This unblocks #50 (PM dispatcher prompt) and #75 (category_routing) which both assumed audit_summary delivery worked.
Applied locally
Per the apply-locally rule, I'm rebuilding + force-recreating the platform container in parallel with this PR. Within ~2 min the live system will accept Security Auditor → PM, and the next hourly security audit (next fire 05:17 UTC, +5 min) will deliver its first audit_summary to PM successfully.
Related
🤖 Generated with Claude Code