gabriel / musehub public
feat patch feat/211-identity-genealogy-api #1 / 1
AI Agent gabriel · 2 days ago · Oct 22, 2026 · Diff

feat: expose IdentityGraphService/RootDistanceIndex via a genealogy query endpoint (musehub#211)

IdentityGraphService/RootDistanceIndex/QuorumEngine (musehub/graph/) are a real, correct, well-tested in-memory engine for identity-DAG invariants -- I1 (no cycles), I2 (root-distance to a human), I3 (org quorum soundness). Backed by 66 references across 5 dedicated test files. None of it was ever wired into the live application: register_agent_identity() writes spawned_by as a plain string column and commits, with no production code path anywhere that builds the DAG from persisted data or exposes a genealogy query.

Scoped to the minimal slice that closes the ticket's core gap, per the ticket's own revised framing after its author's live-tested correction: spawned_by can only ever be set to the authenticated caller's own handle and is never mutable afterward, so classic cycles (I1) are structurally impossible via the real API regardless of whether the engine is wired in -- this is 'a correct query engine exists and is never exposed,' not 'cycles are currently possible.'

Added GET /api/identities/{handle}/genealogy: builds the full spawn graph from musehub_identities (every non-deleted identity as a node, every spawned_by as a GraphEdge), runs RootDistanceIndex.build() fresh per request (correctness over caching for this first cut), and returns root_distance + human_ancestors. Same visibility as GET /api/identities/{handle} itself -- optional auth, no special permission.

As a side effect, this also makes the ticket's flagged-but-unverified orphan scenario queryable: an agent whose spawn chain passes through a revoked (soft-deleted) operator now correctly reports root_distance=null, human_ancestors=[] -- detectable, even though automatic cascading/flagging on revocation itself stays out of scope for this fix (noted as follow-up).

Explicitly out of scope, per agreed MVP cut: QuorumEngine/org-quorum query surface (I3) is a separate concern; left for a future ticket.

sha256:1a3ef15ee7610ff3777347c20b1f89ac9988b93b0eccc32f2e365a927b46ed68 sha
+15 symbols
2 changed · 1109 in snapshot files
sha256:249abe5f2e561c87e5e5846c714120d888ae0718a44591e1d460b5f2407caf72 snapshot
+15
symbols added
2
files changed
1109
files in snapshot
0
dead code introduced
Semantic Changes 15 symbols
~ tests/test_identity_genealogy_api.py .py 14 symbols added
+ TestGenealogyEndpoint class class TestGenealogyEndpoint L50–137
+ test_direct_agent_spawn_distance_is_one method async_method test_direct_agent_spawn_distance_is_one L63–76
+ test_human_root_distance_is_zero method async_method test_human_root_distance_is_zero L51–61
+ test_no_auth_required method async_method test_no_auth_required L128–137
+ test_orphaned_agent_has_null_distance method async_method test_orphaned_agent_has_null_distance L98–122
+ test_two_hop_spawn_chain_distance_is_two method async_method test_two_hop_spawn_chain_distance_is_two L78–96
+ test_unknown_handle_404s method async_method test_unknown_handle_404s L124–126
+ _create_identity function async_function _create_identity L30–46
+ AsyncClient import import AsyncClient L23–23
+ AsyncSession import import AsyncSession L24–24
+ MusehubIdentity import import MusehubIdentity L26–26
+ annotations import import annotations L20–20
+ compute_identity_id import import compute_identity_id L27–27
+ pytest import import pytest L22–22
+ get_identity_genealogy function async_function get_identity_genealogy L259–314
Files Changed
+1 ~1
1109 in snapshot
← Older Oldest on feat/211-identity-genealogy-api
All commits
Newer → Latest on feat/211-identity-genealogy-api

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:1a3ef15ee7610ff3777347c20b1f89ac9988b93b0eccc32f2e365a927b46ed68 --body "your comment"