Found during review of #41. Follow-up to a merged feature.
Problem
The fork agent name doubles as the Chronicle namespace (conversations/{name}), but forkAgentName's sanitizer is not injective.
src/mcpl/conversation-router.ts:281:
const safe = channelId.replace(/[^A-Za-z0-9_-]+/g, '-');
return `${prefix}-${safe}-g${generation}`;
slack:C1, slack/C1, and slack C1 all collapse to conversation-slack-C1-g1.
Impact
Two distinct channels → one fork name → one shared Chronicle namespace → the isolation guarantee inverts into a context merge. Unlikely with a single well-behaved adapter; reachable once channel IDs are server-qualified or federated.
Suggested fix
Make the mapping injective — hash the raw channel id, or percent-encode the unsafe bytes rather than collapsing runs to -.
Found during review of #41. Follow-up to a merged feature.
Problem
The fork agent name doubles as the Chronicle namespace (
conversations/{name}), butforkAgentName's sanitizer is not injective.src/mcpl/conversation-router.ts:281:slack:C1,slack/C1, andslack C1all collapse toconversation-slack-C1-g1.Impact
Two distinct channels → one fork name → one shared Chronicle namespace → the isolation guarantee inverts into a context merge. Unlikely with a single well-behaved adapter; reachable once channel IDs are server-qualified or federated.
Suggested fix
Make the mapping injective — hash the raw channel id, or percent-encode the unsafe bytes rather than collapsing runs to
-.