···100100101101### Union Array Elements ($type)
102102103103-**IMPORTANT**: When an array element is a union type (has `$type` field), constellation includes the type in the path:
103103+**IMPORTANT**: When an **array element** is a union type (has `$type` field), constellation includes the type in the path:
104104105105```
106106.items[com.deckbelcher.collection.list#cardItem].ref.scryfallUri
···108108109109NOT:
110110```
111111-.items[].ref.scryfallUri # WRONG for union types
111111+.items[].ref.scryfallUri # WRONG for union types in arrays
112112```
113113114114-This is because constellation's link extractor (`links/src/record.rs`) uses the `$type` value when present:
114114+This is because constellation's link extractor (`links/src/record.rs`) uses the `$type` value when present in array elements:
115115116116```rust
117117if let Some(JsonValue::String(t)) = o.get("$type") {
···119119} else {
120120 format!("{path}[]") // Plain array notation
121121}
122122+```
123123+124124+### Standalone Union Fields (NOT arrays)
125125+126126+For union fields that are NOT in arrays, just use the normal path without `[$type]`:
127127+128128+```
129129+.subject.ref.oracleUri # Correct for non-array union field
130130+```
131131+132132+NOT:
133133+```
134134+.subject[some.type#variant].ref.oracleUri # WRONG - [$type] is for arrays only
122135```
123136124137## DeckBelcher-Specific Paths
···433433 * Hash an object to a deterministic rkey using SHA-256 + base64url.
434434 * Full hash (43 chars) for maximum collision resistance.
435435 * Valid rkey chars: A-Za-z0-9.-_:~ (base64url uses A-Za-z0-9-_)
436436+ * Sorts keys to ensure hash is independent of object key insertion order.
436437 */
437438export async function hashToRkey(obj: unknown): Promise<Rkey> {
438438- const json = JSON.stringify(obj);
439439+ const json = JSON.stringify(obj, Object.keys(obj as object).sort());
439440 const encoder = new TextEncoder();
440441 const data = encoder.encode(json);
441442 const hashBuffer = await crypto.subtle.digest("SHA-256", data);
+3-5
src/lib/constellation-client.ts
···1818// Future: cards in decks (also uses oracleUri for aggregation)
1919export const DECK_LIST_CARD_PATH = ".cards[].ref.oracleUri";
20202121-// Like paths (subject is a union, so includes $type in path)
2222-export const LIKE_CARD_PATH =
2323- ".subject[com.deckbelcher.social.like#cardSubject].ref.oracleUri";
2424-export const LIKE_RECORD_PATH =
2525- ".subject[com.deckbelcher.social.like#recordSubject].ref.uri";
2121+// Like paths (subject is a union but NOT an array, so no [$type] notation)
2222+export const LIKE_CARD_PATH = ".subject.ref.oracleUri";
2323+export const LIKE_RECORD_PATH = ".subject.ref.uri";
26242725export const COLLECTION_LIST_NSID = "com.deckbelcher.collection.list";
2826export const DECK_LIST_NSID = "com.deckbelcher.deck.list";