Skip to content

Commit 99ffa96

Browse files
mpstatonclaude
andcommitted
issue(org-relations): relation kinds are inverse pairs — logged, not fixed, per operator
One edge, one truth, two seats: NextLadder is funded_by Ballmer Group while Ballmer Group is funder_of NextLadder. Today only that one pair is special-cased in a hardcoded read-time map; every other directional kind (initiative_of and the hierarchy family, any future member_of / fiscal_sponsor_of) still reads wrong from one side. Issue records the current partial mechanism, three design options (extend the map / store both directions on the edge / a kind-vocabulary pairs table), and the live subgraphs to test any fix against. Files changed: - context-v/issues/Relation-Kinds-Are-Inverse-Pairs.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RW28dw3kQAKXr2ZNefCukE
1 parent 84675e5 commit 99ffa96

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
title: "Relation kinds are inverse pairs — one stored string can't speak from both seats"
3+
lede: "NextLadder is funded_by Ballmer Group; Ballmer Group is funder_of NextLadder — the same edge needs a different kind string per perspective, and today only one pair is special-cased in a read-time map."
4+
date_created: 2026-07-28
5+
date_modified: 2026-07-28
6+
authors:
7+
- Michael Staton
8+
augmented_with:
9+
- Claude Code on Claude Fable 5
10+
semantic_version: 0.0.0.1
11+
tags:
12+
- Issue
13+
- Augment-It
14+
- Org-Relations
15+
- Data-Modeling
16+
status: Active
17+
---
18+
19+
# Relation kinds are inverse pairs
20+
21+
## The observation (operator, 2026-07-28)
22+
23+
> relationships have the kind/type string. They are often inverse, so need
24+
> to be written both ways inverted. So NextLadder is funded_by Ballmer
25+
> Group, Ballmer Group is funder_of NextLadder.
26+
27+
One org↔org edge, one truth — but the **kind string reads differently
28+
depending on which card you're standing on.** `rel` (parent/child/peer)
29+
already gets this right via read-time projection; `kind` mostly doesn't.
30+
31+
## Current state (shipped same day, deliberately partial)
32+
33+
- Kinds are authored ONCE, from the edge's `in` side
34+
(`ballmer-group —funder_of→ nextladder`). Storage is a single string.
35+
- `listOrgRelations` inverts at read time via a **hardcoded map** in
36+
`org-relations.ts` (`KIND_INVERSE`): `funder_of ↔ funded_by`,
37+
`funds → funded_by`. That fixed the NextLadder card — and nothing else.
38+
- Every other directional kind still reads wrong from one seat:
39+
- Hierarchical kinds on the CHILDREN listing: the parent's card shows
40+
`cfat (initiative_of)` — reading as if CFAT were initiative_of the
41+
viewer's child, when the honest label from the parent's seat is
42+
something like `has_initiative`.
43+
- Any future directional kind (`member_of`, `spun_out_of`,
44+
`fiscal_sponsor_of`…) silently inherits the defect until someone adds
45+
a map entry.
46+
- Symmetric kinds (`partners_with`) are fine — they're their own inverse.
47+
48+
## Design space (log, don't decide)
49+
50+
1. **Extend the read-time map** — cheapest; the vocabulary lives in code:
51+
`initiative_of → has_initiative`, `fund_of → has_fund`,
52+
`program_of → has_program`, `agency_of → has_agency`,
53+
`chapter_of → has_chapter`, symmetric kinds mapping to themselves.
54+
Con: open-vocabulary kinds (the operator can type anything) get no
55+
inverse until code changes.
56+
2. **Store both directions on the edge** (`kind` as authored +
57+
`kind_inverse`, both writable at relate/update time) — redundancy-over-
58+
normalization house ethos; the operator can author asymmetric wording;
59+
reads pick by seat. Con: two fields to keep coherent on update.
60+
3. **A kind-vocabulary table** (pairs as data, per client like `tag_vocab`)
61+
— inverse pairs become operator-curated data, the datalist can offer
62+
both forms, exports/didi read the same source. Most machinery.
63+
64+
Whatever the choice, the UI datalist and didi's slab should present kinds
65+
in the operator's seat-relative form ("is funded_by…" when relating from
66+
the recipient's side), and the export's `related_orgs` column has the
67+
same seat problem.
68+
69+
## See also
70+
71+
- `services/record-surrealdb-resolver/src/org-relations.ts` — the
72+
`KIND_INVERSE` map (the partial fix) + the shapeRelated projection.
73+
- [[../plans/Org-Relations-Parent-Child-Peer-Plus-Org-Tags]] — the shipped
74+
model this refines.
75+
- Live examples to test any fix against: NextLadder's four funders, the
76+
National Academy for AI Instruction's three, CFAT ⊂ carnegie-foundation,
77+
FIPSE ⊂ us-department-of-education.

0 commit comments

Comments
 (0)