This repository has no description
6.0 kB
213 lines
1import type { ContrailConfig, PipelineQueryHandler } from "@atmo-dev/contrail";
2
3// ── Pipeline queries: the Yoneda probes ─────────────────────────────────
4//
5// The Yoneda lemma: an object is determined by its relationships.
6// Hom(C(a, -), F) ≅ F(a)
7//
8// Two fundamental queries:
9// getIncoming -- all morphisms TO a resource (covariant probe: C(-, a))
10// getOutgoing -- all morphisms FROM a resource (contravariant probe: C(a, -))
11//
12// A resource "emerges" from the sum of its connections.
13
14const getIncoming: PipelineQueryHandler = async (db, params, config) => {
15 const uri = params.get("uri");
16 if (!uri) throw new Error("uri is required");
17
18 const limit = Math.min(parseInt(params.get("limit") || "50"), 100);
19 const cursor = params.get("cursor");
20 const types = params.get("types"); // comma-separated connection types
21
22 const conditions = ["json_extract(record, '$.target') = ?"];
23 const sqlParams: (string | number)[] = [uri];
24
25 if (types) {
26 const typeList = types.split(",").map((t) => t.trim());
27 const placeholders = typeList.map(() => "?").join(",");
28 conditions.push(`json_extract(record, '$.connectionType') IN (${placeholders})`);
29 sqlParams.push(...typeList);
30 }
31
32 if (cursor) {
33 conditions.push("time_us < ?");
34 sqlParams.push(parseInt(cursor));
35 }
36
37 const where = conditions.join(" AND ");
38
39 return {
40 joins: undefined,
41 conditions: [where],
42 params: sqlParams,
43 };
44};
45
46const getOutgoing: PipelineQueryHandler = async (db, params, config) => {
47 const uri = params.get("uri");
48 if (!uri) throw new Error("uri is required");
49
50 const limit = Math.min(parseInt(params.get("limit") || "50"), 100);
51 const cursor = params.get("cursor");
52 const types = params.get("types");
53
54 const conditions = ["json_extract(record, '$.source') = ?"];
55 const sqlParams: (string | number)[] = [uri];
56
57 if (types) {
58 const typeList = types.split(",").map((t) => t.trim());
59 const placeholders = typeList.map(() => "?").join(",");
60 conditions.push(`json_extract(record, '$.connectionType') IN (${placeholders})`);
61 sqlParams.push(...typeList);
62 }
63
64 if (cursor) {
65 conditions.push("time_us < ?");
66 sqlParams.push(parseInt(cursor));
67 }
68
69 const where = conditions.join(" AND ");
70
71 return {
72 joins: undefined,
73 conditions: [where],
74 params: sqlParams,
75 };
76};
77
78export const config: ContrailConfig = {
79 namespace: "org.latha.strata",
80 collections: {
81 // ── Semble records (indexed from the network) ──────────────────
82
83 card: {
84 collection: "network.cosmik.card",
85 queryable: {
86 type: {},
87 "content.url": {},
88 },
89 searchable: ["content.url", "content.text", "content.metadata.title", "content.metadata.description"],
90 references: {
91 parentCard: {
92 collection: "card",
93 field: "parentCard.uri",
94 },
95 },
96 },
97
98 collection: {
99 collection: "network.cosmik.collection",
100 queryable: {
101 name: {},
102 accessType: {},
103 },
104 searchable: ["name", "description"],
105 relations: {
106 cards: {
107 collection: "card",
108 count: true,
109 },
110 },
111 },
112
113 // ── Connection: the fundamental primitive (Yoneda) ──────────────
114 //
115 // Connections are morphisms in the knowledge graph.
116 // Objects (cards, collections, URLs) emerge from their connections.
117 // This is the Yoneda embedding: every object is determined by
118 // the set of morphisms pointing at it and originating from it.
119
120 connection: {
121 collection: "network.cosmik.connection",
122 queryable: {
123 source: {},
124 target: {},
125 connectionType: {},
126 },
127 searchable: ["note"],
128 pipelineQueries: {
129 getIncoming,
130 getOutgoing,
131 },
132 },
133
134 // ── Follow: social graph for feed construction ─────────────────
135
136 follow: {
137 collection: "network.cosmik.follow",
138 queryable: {
139 subject: {},
140 },
141 discover: false, // only index follows from known users
142 },
143
144 // ── Strata analysis records (generated by this appview) ────────
145
146 citation: {
147 collection: "org.latha.strata.citation",
148 queryable: {
149 url: {},
150 confidence: {},
151 domain: {},
152 },
153 searchable: ["title", "takeaway"],
154 relations: {
155 reasoning: {
156 collection: "reasoning",
157 groupBy: "method",
158 count: true,
159 },
160 },
161 },
162
163 entity: {
164 collection: "org.latha.strata.entity",
165 queryable: {
166 entityType: {},
167 name: {},
168 },
169 searchable: ["name", "description"],
170 },
171
172 reasoning: {
173 collection: "org.latha.strata.reasoning",
174 queryable: {
175 method: {},
176 confidence: {},
177 },
178 searchable: ["question", "evidence"],
179 references: {
180 citation: {
181 collection: "citation",
182 field: "justifies",
183 },
184 },
185 },
186
187 // ── Strata synthesis: the stigmergic signal ────────────────────
188 //
189 // When a user runs Strata analysis on a Semble card, the output
190 // is an org.latha.strata record on their PDS. It's a pheromone
191 // trail — others discover it, build on it, the network effect
192 // compounds. Carry stays local-first; only summaries go into
193 // the record unless explicitly published as companion records.
194
195 strata: {
196 collection: "org.latha.strata",
197 queryable: {
198 "source.uri": {},
199 "source.collection": {},
200 updatedAt: { type: "range" },
201 },
202 searchable: ["analysis.synthesis", "analysis.themes"],
203 references: {
204 sourceCard: {
205 collection: "card",
206 field: "source.uri",
207 },
208 },
209 },
210 },
211 profiles: ["app.bsky.actor.profile"],
212 notify: true,
213};