identity-profiles.md markdown
310 lines 9.5 KB
Raw
sha256:5472be4fece32b606c308fad9d57295ce327955fb2b87b8beec6ea1626050473 Add published YouTube URL to Episode 00 Sonnet 5 10 hours ago

Episode 19 --- Identity Profiles

Working YouTube title:
I Almost Reported A Fake Bug (A Lesson In Checking Your Assumptions)

Thumbnail thought:
human -> agent -> agent. distance: 2.

Target runtime: ~8:30


[0:00--0:20] COLD OPEN

[CAMERA --- Episode 18's closing line, on screen: "another organization, or another agent, with its own identity to prove."]

GABRIEL:

Every agent registered this season has had one operator behind it. What happens when an agent spawns another agent? Who's actually accountable three levels down? Muse has a real answer to that question. I almost got the story wrong finding it.

[TITLE CARD --- fast]

IDENTITY PROFILES

[Music enters.]


[0:20--1:20] SPAWNING AN AGENT, FOR REAL

[TERMINAL]

$ curl -X POST .../api/identities/agent -H "Authorization: MSign handle=\"gabriel\"..." \
    --data '{"handle":"ep19-agent-a","public_key_b64":"ed25519:...", ...}'
{ "handle": "ep19-agent-a", "spawned_by": "gabriel", "is_new_identity": true }

GABRIEL VO:

A real agent identity, a real Ed25519 key, spawned_by set automatically to whoever's signature is on the request --- not something the caller gets to claim. Now the interesting part: sign the next registration with agent A's own key instead of mine.

$ # signed with agent A's private key, not gabriel's
$ curl -X POST .../api/identities/agent --data '{"handle":"ep19-agent-b", ...}'
{ "handle": "ep19-agent-b", "spawned_by": "ep19-agent-a" }

GABRIEL:

An agent, spawning an agent, entirely on its own authority. Real chain: gabriel → agent A → agent B. Two hops from a human.


[1:20--2:40] THE BUG I ALMOST REPORTED

[CAMERA]

While building this, my very first attempt at step two crashed. Hard.

TypeError: __init__() got an unexpected keyword argument 'committed_at_raw'

GABRIEL VO:

Every instinct says: file it, it's a real crash, I have a traceback. I almost did. Then I checked something first.

$ docker inspect musehub --format '{{.Image}}' | xargs docker image inspect --format '{{.Created}}'
2026-07-08T01:34:52Z

GABRIEL:

The container serving my requests was built in July. It's September. committed_at_raw is a real, valid field on the model --- I checked the source on disk, right there, current. The running process just didn't have it yet. This is the exact incident this workspace has a standing rule about, and I nearly became its next example.

[beat]

$ docker restart musehub musehub_worker

Same exact call, freshly restarted container: works. Clean. No bug. I'd have filed a false report on infrastructure staleness and called it a code defect.


[2:40--3:40] THE REAL FINDING, CORRECTED

[CAMERA]

That near-miss made me slow down on my next claim too. I initially assumed I could make spawned_by point backward and create a cycle --- register B, then somehow re-point A at B. I wrote that into a ticket. Then I actually tried it.

$ curl -X PATCH .../api/identities/ep19-agent-a --data '{"spawned_by": "ep19-agent-b"}'

GABRIEL VO:

spawned_by isn't even in the list of fields PATCH accepts. It's set once, at creation, to whoever authenticated the call --- never attacker-controlled, never mutable after. A cycle is structurally impossible through this API, by construction. I corrected the ticket before writing this script. Getting the finding right matters more than getting to keep the first, scarier version of it.


[3:40--5:00] WHAT'S ACTUALLY MISSING

[TERMINAL]

$ curl .../api/openapi.json | jq '.paths | keys[] | select(contains("ancestor") or contains("genealog"))'
(nothing)

GABRIEL:

Real gap, precisely stated: there is no endpoint, anywhere, to ask "what's this agent's distance to a human root" or "list its human ancestors" --- for the exact two-hop chain I just built with real API calls.

$ python3 -c "
from musehub.graph.service import IdentityGraphService
svc = IdentityGraphService()
svc.add_identity('gabriel', HUMAN); svc.add_identity('agent-a', AGENT); svc.add_identity('agent-b', AGENT)
svc.add_spawn('gabriel','agent-a'); svc.add_spawn('agent-a','agent-b')
print(svc.root_distance('agent-b'), svc.human_ancestors('agent-b'))
"
2 {'gabriel'}

GABRIEL VO:

The engine that answers this --- correctly, instantly --- has existed the whole time. RootDistanceIndex, multi-source BFS from every human node. It's just never connected to anything a real request can reach.


[5:00--6:00] THE ENGINE DEFENDS ITSELF TOO

[TERMINAL]

$ python3 -c "svc.add_spawn('agent-b', 'agent-a')"  # try to close the loop
Correctly rejected: CycleError: Cycle detected: adding 'agent-b' → 'agent-a' would close a cycle

GABRIEL:

Even though the real API already prevents this structurally, the purpose-built engine independently agrees --- tested, correct, unreachable. Filed as staging#211, retitled after I got the framing right: not "cycles are possible," but "a correct genealogy engine has no door into it."


[6:00--6:40] ATTESTATIONS: REAL, JUST EMPTY HERE

[TERMINAL]

$ curl .../api/profiles/attestation-types
{ "claimTypes": [], "total": 0 }

GABRIEL VO:

The attestation system --- issue, list, revoke cryptographic claims about an identity --- is real infrastructure with its own migration and its own signed-canonical-message format. This particular dev database just has no seeded claim types to attest with yet. Not a finding, just an honest note on what this episode could and couldn't show live.


[6:40--7:20] WHY THE CORRECTION MATTERED MORE THAN THE BUG

[CAMERA]

Two near-misses, same episode: a false crash from a stale container, an overstated cycle claim from not testing before writing. Neither made it into what you just watched as a real finding. That's not padding --- that's the actual discipline this season depends on. Every bug reported across eighteen episodes had to survive being wrong first.


[7:20--8:00] OUT

[TERMINAL --- fading to black]

GABRIEL VO:

Every identity this season has lived inside one repo, one hub. Next: how something content-addressed becomes a shareable, standalone object --- a Mist --- independent of any single repository at all.

[beat]

That's next.

[CUT TO BLACK]

musehub.ai


Production Notes

Episode 19's real subject is genealogy, but its real lesson is verification discipline — say both out loud, don't let the meta-lesson overshadow the actual identity-graph content. Structure: real spawn chain first (0:20), then the two near-misses in sequence (1:20 stale container, 2:40 corrected cycle claim), then the real remaining gap (3:40) delivered with full confidence because it survived scrutiny.

The Stale-Container Beat Must Show The Timestamp

"2026-07-08" next to today's date is the entire proof — don't summarize it, put the actual docker image inspect output on screen. This is the single most concrete demonstration all season of why the container-freshness discipline in .museagent.md exists, not just a rule to recite.

Don't Soften The Self-Correction

Explicitly say the first version of the ticket was wrong and that it got corrected before this episode was written — audiences trust a correction shown in the open far more than a clean narrative that never admits the false start existed. This is the same posture as episode 14's reconcile near-miss, but higher stakes because a ticket was actually filed with the wrong claim, not just a private hypothesis.

Attestations Get One Honest Beat, Not An Apology

6:00's attestation segment should feel like a factual aside, not a letdown after two real findings — the infrastructure is real and described accurately; there's simply no seed data in this dev database to demonstrate issuance live. Keep it brief.

Everything Here Is Real

Every registration, the stale-container crash (genuinely encountered, not staged), the corrected cycle claim, and the direct IdentityGraphService calls were run against the actual current build. Re-run make-identity-episode19-demo.sh at record time — it generates unique handles per run via a timestamp suffix, so it's safely re-runnable against the same dev database.

The Seed

The viewer arrives thinking:

Agents having identities is neat. Genealogy sounds like a nice compliance feature.

They should leave thinking:

The genealogy engine is real and correct, and simultaneously unreachable — and I just watched the person building this season almost report two things that weren't true, catch both, and correct the record before moving on. That's a harder standard than most bug reports get held to.

That's the standard the rest of the season needs to keep meeting.

File History 1 commit
sha256:5472be4fece32b606c308fad9d57295ce327955fb2b87b8beec6ea1626050473 Add published YouTube URL to Episode 00 Sonnet 5 10 hours ago