The AtmosphereConf talks your skyline missed
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #7 from musicjunkieg/chore/sync-decision-graph

chore: sync decision graph (crawler nodes 19-23)

authored by

chaos gremlin and committed by
GitHub
1fb66b91 25674201

+566 -1
+58
docs/git-history.json
··· 1 + [ 2 + { 3 + "hash": "549dff02906291887b63f2aa79e6a637e89b44c7", 4 + "short_hash": "549dff0", 5 + "author": "Bryan Guffey", 6 + "date": "2026-04-09T20:04:07-07:00", 7 + "message": "docs: add social graph crawler spec and implementation plan\n\nHistorical reference for the work that landed in PR #5 (closes #16, #17).", 8 + "files_changed": 2 9 + }, 10 + { 11 + "hash": "3cbb4ee4b490ef307ca645568644738c2d093302", 12 + "short_hash": "3cbb4ee", 13 + "author": "Bryan Guffey", 14 + "date": "2026-04-09T16:04:32-07:00", 15 + "message": "fix(crawl): review round 2 - 504, unhandled rejection, perf, search window\n\n- route.ts: return 504 Gateway Timeout for timeout errors instead of a generic\n 500. Detects both AbortSignal.timeout's DOMException (name === \"TimeoutError\")\n and the withTimeout() helper's Error(\"Crawl timeout\").\n\n- cache.ts: fix a latent unhandled rejection. promise.finally() returns a new\n derived promise whose rejection would be orphaned (since nothing awaited it).\n Now we store the derived \"settled\" promise in the inFlight map and return it,\n so the caller's await observes the rejection. Identity check compares against\n the derived promise for the same reason.\n\n- crawler.ts: replace O(n²) includes/push aggregation with per-talk Set-backed\n tracking (followSets, rsvpSets, postLists). Projected to TalkMention arrays\n via buildResult() at the end, so the exported shape is unchanged.\n\n- search.ts: extend SEARCH_UNTIL to 2026-04-27T00:00:00.000Z (exclusive upper\n bound = through end of April 26, 2026). Intentionally beyond the spec's\n conference window so Understory keeps surfacing post-conference aftermath\n discussion after the event ends.", 16 + "files_changed": 4 17 + }, 18 + { 19 + "hash": "282fcc9ecdae5a21a68944ad35d3da6044243533", 20 + "short_hash": "282fcc9", 21 + "author": "Bryan Guffey", 22 + "date": "2026-04-09T15:49:35-07:00", 23 + "message": "fix(crawl): review fixes - abort signal, atomic in-flight, nested embeds\n\n- route.ts: atomically register/join crawls via registerCrawl so concurrent\n requests can't overwrite each other's in-flight promise. New crawls own an\n AbortSignal.timeout(30s) so a timeout actually cancels outbound fetches\n rather than just detaching the handler. Joined requests wrap their wait in a\n separate Promise.race timeout (can't cancel another caller's work).\n withTimeout helper clears the timer on settlement so it doesn't leak.\n\n- cache.ts: replace getInFlightCrawl/setInFlightCrawl with atomic\n registerCrawl(did, factory) -> { promise, isNew }. Cleanup only deletes the\n entry when the map still references this exact promise (identity check), so\n a stale finally from an overwritten promise can't erase a newer one.\n\n- crawler.ts / constellation.ts / search.ts: thread an optional AbortSignal\n through fetchFollows, fetchRsvps, searchConferencePosts and into every\n fetch() / agent.* call via CallOptions. Check signal.aborted at loop\n boundaries and rethrow abort errors from search.ts catch so a timeout\n actually unwinds the crawl instead of being swallowed.\n\n- matcher.ts: extract collectRecordUris() and handle the nested\n app.bsky.embed.recordWithMedia shape where embed.record is itself a\n record#view with its own .record.uri. Applied to both view-level (post.embed)\n and record-level (post.record.embed) containers.\n\nSEARCH_UNTIL intentionally not changed: spec §3 and CLAUDE.md both pin the\nwindow at since:2026-03-26 / until:2026-04-06, and searchPosts treats until\nas exclusive, so the current value correctly covers all of April 5 (the last\nconference day).", 24 + "files_changed": 6 25 + }, 26 + { 27 + "hash": "535526ba59da9f08a6992989d323a54ed6052782", 28 + "short_hash": "535526b", 29 + "author": "chaos gremlin", 30 + "date": "2026-04-07T21:42:02-07:00", 31 + "message": "Merge pull request #4 from musicjunkieg/feat/oauth\n\nfeat: AT Protocol OAuth with login form and auth-aware Nav", 32 + "files_changed": 0 33 + }, 34 + { 35 + "hash": "56073eac69fe911e93ab79ccef20efe73cc465a6", 36 + "short_hash": "56073ea", 37 + "author": "chaos gremlin", 38 + "date": "2026-04-06T17:28:12-07:00", 39 + "message": "Merge pull request #3 from musicjunkieg/feat/landing-page\n\nfeat: landing page and talks index", 40 + "files_changed": 0 41 + }, 42 + { 43 + "hash": "511a6e00533c71b409a5325ca57c060a9b2a5069", 44 + "short_hash": "511a6e0", 45 + "author": "chaos gremlin", 46 + "date": "2026-04-06T16:52:49-07:00", 47 + "message": "Merge pull request #2 from musicjunkieg/feat/talk-page\n\nfeat: talk page with HLS video, transcript, and search", 48 + "files_changed": 0 49 + }, 50 + { 51 + "hash": "79f70643a2241be699072d19291ccce244779fee", 52 + "short_hash": "79f7064", 53 + "author": "chaos gremlin", 54 + "date": "2026-04-06T16:06:07-07:00", 55 + "message": "Merge pull request #1 from musicjunkieg/feat/design-system\n\nfeat: bioluminescent design system + project foundation", 56 + "files_changed": 0 57 + } 58 + ]
+508 -1
docs/graph-data.json
··· 1 - {"nodes":[],"edges":[]} 1 + { 2 + "nodes": [ 3 + { 4 + "id": 1, 5 + "change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 6 + "node_type": "goal", 7 + "title": "Build Understory for Streamplace VOD JAM", 8 + "description": null, 9 + "status": "pending", 10 + "created_at": "2026-04-05T06:20:00.757206-07:00", 11 + "updated_at": "2026-04-05T06:20:00.757206-07:00", 12 + "metadata_json": "{\"branch\":\"main\",\"confidence\":90,\"prompt\":\"Read the attached design doc (docs/understory-design.md). This is the full system design for Understory, a social anti-algorithm for ATmosphereConf VODs. We're building this for the Streamplace VOD JAM, deadline April 12.\"}" 13 + }, 14 + { 15 + "id": 2, 16 + "change_id": "e6e07ab7-4a17-4803-862b-4feadd3f6092", 17 + "node_type": "option", 18 + "title": "Use Next.js with App Router, TypeScript, Tailwind", 19 + "description": null, 20 + "status": "pending", 21 + "created_at": "2026-04-05T06:20:17.379763-07:00", 22 + "updated_at": "2026-04-05T06:20:17.379763-07:00", 23 + "metadata_json": "{\"branch\":\"main\",\"confidence\":85,\"files\":[\"package.json\",\"tsconfig.json\"]}" 24 + }, 25 + { 26 + "id": 3, 27 + "change_id": "1c0cb222-6785-4d35-9f86-674e2aacf373", 28 + "node_type": "option", 29 + "title": "Use AssemblyAI for transcription instead of local Whisper", 30 + "description": null, 31 + "status": "pending", 32 + "created_at": "2026-04-05T06:20:17.389728-07:00", 33 + "updated_at": "2026-04-05T06:20:17.389728-07:00", 34 + "metadata_json": "{\"branch\":\"main\",\"confidence\":80,\"files\":[\"scripts/transcribe.ts\"]}" 35 + }, 36 + { 37 + "id": 4, 38 + "change_id": "c095ccd1-be73-449d-9eb6-e675c9d7f090", 39 + "node_type": "decision", 40 + "title": "Chose Next.js + AssemblyAI stack", 41 + "description": "Next.js for frontend (design doc suggested React/Next.js), AssemblyAI for transcription (faster than local Whisper, speaker labels built in)", 42 + "status": "pending", 43 + "created_at": "2026-04-05T06:20:17.398567-07:00", 44 + "updated_at": "2026-04-05T06:20:17.398567-07:00", 45 + "metadata_json": "{\"branch\":\"main\",\"confidence\":90}" 46 + }, 47 + { 48 + "id": 5, 49 + "change_id": "db57b64e-d3d3-4e9e-b955-a50c2ac65fee", 50 + "node_type": "action", 51 + "title": "Scaffolded Next.js app and built transcription pipeline", 52 + "description": null, 53 + "status": "pending", 54 + "created_at": "2026-04-05T06:20:24.645025-07:00", 55 + "updated_at": "2026-04-05T06:20:24.645025-07:00", 56 + "metadata_json": "{\"branch\":\"main\",\"confidence\":95,\"files\":[\"scripts/transcribe.ts\",\"scripts/build-talk-index.ts\",\"data/talks.json\"]}" 57 + }, 58 + { 59 + "id": 6, 60 + "change_id": "3fe5e92d-afab-4d5a-9460-1d01ec3e89a7", 61 + "node_type": "outcome", 62 + "title": "129 talks transcribed via AssemblyAI, 115 transcript files, 94 matched to schedule", 63 + "description": null, 64 + "status": "pending", 65 + "created_at": "2026-04-05T06:20:24.661811-07:00", 66 + "updated_at": "2026-04-05T06:20:24.661811-07:00", 67 + "metadata_json": "{\"branch\":\"main\",\"confidence\":95,\"files\":[\"data/talks.json\"]}" 68 + }, 69 + { 70 + "id": 7, 71 + "change_id": "a2e3e3e6-ca6a-4adf-9c16-50683f4e69ab", 72 + "node_type": "observation", 73 + "title": "Full-day room streams identified by creator === REPO_DID; ATScience talks lack vodAtUri links in schedule data", 74 + "description": "Filtering heuristic: 7 full-room recordings all created by did:plc:rbvrr34edl5ddpuwcubjiost. 35 unmatched VODs include non-talk content (lunch, starting soon, remarks) and ATScience day talks missing schedule links.", 75 + "status": "pending", 76 + "created_at": "2026-04-05T06:20:35.351244-07:00", 77 + "updated_at": "2026-04-05T06:20:35.351244-07:00", 78 + "metadata_json": "{\"branch\":\"main\",\"confidence\":90}" 79 + }, 80 + { 81 + "id": 8, 82 + "change_id": "cb33f803-5dc7-4939-bcd4-948145224943", 83 + "node_type": "action", 84 + "title": "Created project tracking with 6 milestones and 33 issues", 85 + "description": "Milestones: Foundation (done), Talk Pages & UI, Scoring Engine, Embeddings, Coverage Map & Polish, Ship. Blocking relationships set up for dependencies.", 86 + "status": "pending", 87 + "created_at": "2026-04-05T06:22:16.940388-07:00", 88 + "updated_at": "2026-04-05T06:22:16.940388-07:00", 89 + "metadata_json": "{\"branch\":\"main\",\"confidence\":90}" 90 + }, 91 + { 92 + "id": 9, 93 + "change_id": "320c518d-10b7-4c3a-8c2a-26280260307c", 94 + "node_type": "action", 95 + "title": "Implemented bioluminescent design system", 96 + "description": null, 97 + "status": "pending", 98 + "created_at": "2026-04-06T16:07:44.754998-07:00", 99 + "updated_at": "2026-04-06T16:07:44.754998-07:00", 100 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"79f7064\",\"confidence\":95,\"files\":[\"src/app/globals.css\",\"src/app/layout.tsx\",\"src/components/ui/button.tsx\",\"src/components/ui/chip.tsx\",\"src/components/ui/lume-card.tsx\",\"src/components/ui/nav.tsx\"]}" 101 + }, 102 + { 103 + "id": 10, 104 + "change_id": "849be730-00e0-4479-a14a-5b9f9a3f8bd7", 105 + "node_type": "outcome", 106 + "title": "Design system complete: 50+ color tokens, 3-font type scale, 4 UI components, atmospheric effects", 107 + "description": null, 108 + "status": "pending", 109 + "created_at": "2026-04-06T16:07:52.249334-07:00", 110 + "updated_at": "2026-04-06T16:07:52.249334-07:00", 111 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"79f7064\",\"confidence\":95}" 112 + }, 113 + { 114 + "id": 11, 115 + "change_id": "cf7e27f6-790c-4b76-b362-b5b39f344899", 116 + "node_type": "action", 117 + "title": "Fixed ATScience talk-to-schedule matching with fallback title/timestamp matcher", 118 + "description": null, 119 + "status": "pending", 120 + "created_at": "2026-04-06T16:08:02.457818-07:00", 121 + "updated_at": "2026-04-06T16:08:02.457818-07:00", 122 + "metadata_json": "{\"branch\":\"main\",\"confidence\":95,\"files\":[\"scripts/build-talk-index.ts\"]}" 123 + }, 124 + { 125 + "id": 12, 126 + "change_id": "032b7fe7-7966-4e06-b7b2-c98c33017645", 127 + "node_type": "outcome", 128 + "title": "102 talks matched to schedule (up from 94), 100 complete with transcripts", 129 + "description": null, 130 + "status": "pending", 131 + "created_at": "2026-04-06T16:08:08.305525-07:00", 132 + "updated_at": "2026-04-06T16:08:08.305525-07:00", 133 + "metadata_json": "{\"branch\":\"main\",\"confidence\":95}" 134 + }, 135 + { 136 + "id": 13, 137 + "change_id": "6f73230b-15b5-4930-9267-f886c9ae09c5", 138 + "node_type": "action", 139 + "title": "Built talk page with HLS video, transcript, and search", 140 + "description": null, 141 + "status": "pending", 142 + "created_at": "2026-04-06T16:57:37.698726-07:00", 143 + "updated_at": "2026-04-06T16:57:37.698726-07:00", 144 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"511a6e0\",\"confidence\":95,\"files\":[\"src/app/talk/[rkey]/page.tsx\",\"src/components/video-player.tsx\",\"src/components/transcript-panel.tsx\",\"src/components/talk-page-client.tsx\",\"src/lib/transcript.ts\",\"src/lib/format.ts\",\"src/lib/types.ts\"]}" 145 + }, 146 + { 147 + "id": 14, 148 + "change_id": "fc101e72-add6-44cc-b5c4-611e3b3075bb", 149 + "node_type": "outcome", 150 + "title": "Talk page live: 115 static pages, HLS video, sentence-level transcript with click-to-seek and search", 151 + "description": null, 152 + "status": "pending", 153 + "created_at": "2026-04-06T16:57:42.766260-07:00", 154 + "updated_at": "2026-04-06T16:57:42.766260-07:00", 155 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"511a6e0\",\"confidence\":95}" 156 + }, 157 + { 158 + "id": 15, 159 + "change_id": "409656c7-fcb6-4c0f-a147-1f342a16b2f4", 160 + "node_type": "action", 161 + "title": "Built landing page and talks index", 162 + "description": null, 163 + "status": "pending", 164 + "created_at": "2026-04-06T17:28:39.517725-07:00", 165 + "updated_at": "2026-04-06T17:28:39.517725-07:00", 166 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"56073ea\",\"confidence\":95,\"files\":[\"src/app/page.tsx\",\"src/app/talks/page.tsx\",\"src/components/ui/nav.tsx\"]}" 167 + }, 168 + { 169 + "id": 16, 170 + "change_id": "a4e6001c-f14c-40d2-9453-7a736424f715", 171 + "node_type": "outcome", 172 + "title": "Landing page and talks index live: hero, 3 feature sections, 115-talk browse grid", 173 + "description": null, 174 + "status": "pending", 175 + "created_at": "2026-04-06T17:28:39.538622-07:00", 176 + "updated_at": "2026-04-06T17:28:39.538622-07:00", 177 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"56073ea\",\"confidence\":95}" 178 + }, 179 + { 180 + "id": 17, 181 + "change_id": "4f052c12-6057-4ac0-bb5a-fe713468abf8", 182 + "node_type": "action", 183 + "title": "Implemented AT Protocol OAuth flow", 184 + "description": null, 185 + "status": "pending", 186 + "created_at": "2026-04-07T21:43:18.380198-07:00", 187 + "updated_at": "2026-04-07T21:43:18.380198-07:00", 188 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"535526b\",\"confidence\":95,\"files\":[\"src/lib/auth/client.ts\",\"src/lib/auth/session.ts\",\"src/app/oauth/login/route.ts\",\"src/app/oauth/callback/route.ts\",\"src/components/login-form.tsx\"]}" 189 + }, 190 + { 191 + "id": 18, 192 + "change_id": "c60fe61e-b37d-4cb4-8c0d-216a866c6198", 193 + "node_type": "outcome", 194 + "title": "AT Protocol OAuth working: login, session cookie, avatar in Nav, cimd-service + Tailscale Funnel dev setup", 195 + "description": null, 196 + "status": "pending", 197 + "created_at": "2026-04-07T21:43:18.398872-07:00", 198 + "updated_at": "2026-04-07T21:43:18.398872-07:00", 199 + "metadata_json": "{\"branch\":\"main\",\"commit\":\"535526b\",\"confidence\":95}" 200 + }, 201 + { 202 + "id": 19, 203 + "change_id": "50d9542b-7dcc-4e2e-a5bf-75fed865ed99", 204 + "node_type": "action", 205 + "title": "Built social graph crawler + post-to-talk matcher", 206 + "description": null, 207 + "status": "pending", 208 + "created_at": "2026-04-09T15:49:46.145149-07:00", 209 + "updated_at": "2026-04-09T15:49:46.145149-07:00", 210 + "metadata_json": "{\"branch\":\"feat/social-graph-crawler\",\"commit\":\"282fcc9\",\"confidence\":90,\"files\":[\"src/lib/crawl/types.ts\",\"src/lib/crawl/cache.ts\",\"src/lib/crawl/constellation.ts\",\"src/lib/crawl/matcher.ts\",\"src/lib/crawl/search.ts\",\"src/lib/crawl/crawler.ts\",\"src/app/api/crawl/route.ts\"]}" 211 + }, 212 + { 213 + "id": 20, 214 + "change_id": "9dbc20bb-3cd6-48d3-85dc-98276812d82c", 215 + "node_type": "outcome", 216 + "title": "GET /api/crawl live: dual-strategy (Constellation RSVPs + Bluesky text search) with AbortSignal timeout, atomic in-flight coalescing, nested recordWithMedia embed matching", 217 + "description": null, 218 + "status": "pending", 219 + "created_at": "2026-04-09T15:49:49.977986-07:00", 220 + "updated_at": "2026-04-09T15:49:49.977986-07:00", 221 + "metadata_json": "{\"branch\":\"feat/social-graph-crawler\",\"commit\":\"282fcc9\",\"confidence\":90}" 222 + }, 223 + { 224 + "id": 21, 225 + "change_id": "8dfc00b5-0444-4258-aa05-1aa59b45f5bb", 226 + "node_type": "action", 227 + "title": "Review round 2 fixes: 504 status, cache unhandled rejection, O(n^2) aggregation, extended search window", 228 + "description": null, 229 + "status": "pending", 230 + "created_at": "2026-04-09T16:04:37.482252-07:00", 231 + "updated_at": "2026-04-09T16:04:37.482252-07:00", 232 + "metadata_json": "{\"branch\":\"feat/social-graph-crawler\",\"commit\":\"3cbb4ee\",\"confidence\":90,\"files\":[\"src/lib/crawl/cache.ts\",\"src/lib/crawl/crawler.ts\",\"src/lib/crawl/search.ts\",\"src/app/api/crawl/route.ts\"]}" 233 + }, 234 + { 235 + "id": 22, 236 + "change_id": "f53b3b51-76aa-4b33-b58f-f88825991593", 237 + "node_type": "outcome", 238 + "title": "Crawler spec + plan archived in repo", 239 + "description": null, 240 + "status": "pending", 241 + "created_at": "2026-04-09T20:04:11.504657-07:00", 242 + "updated_at": "2026-04-09T20:04:11.504657-07:00", 243 + "metadata_json": "{\"branch\":\"docs/social-graph-crawler-spec\",\"commit\":\"549dff0\",\"confidence\":95,\"files\":[\"docs/superpowers/specs/2026-04-07-social-graph-crawler.md\",\"docs/superpowers/plans/2026-04-07-social-graph-crawler.md\"]}" 244 + } 245 + ], 246 + "edges": [ 247 + { 248 + "id": 1, 249 + "from_node_id": 1, 250 + "to_node_id": 2, 251 + "from_change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 252 + "to_change_id": "e6e07ab7-4a17-4803-862b-4feadd3f6092", 253 + "edge_type": "leads_to", 254 + "weight": 1.0, 255 + "rationale": "Approach option for framework", 256 + "created_at": "2026-04-05T06:20:17.403795-07:00" 257 + }, 258 + { 259 + "id": 2, 260 + "from_node_id": 1, 261 + "to_node_id": 3, 262 + "from_change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 263 + "to_change_id": "1c0cb222-6785-4d35-9f86-674e2aacf373", 264 + "edge_type": "leads_to", 265 + "weight": 1.0, 266 + "rationale": "Approach option for transcription", 267 + "created_at": "2026-04-05T06:20:17.409001-07:00" 268 + }, 269 + { 270 + "id": 3, 271 + "from_node_id": 2, 272 + "to_node_id": 4, 273 + "from_change_id": "e6e07ab7-4a17-4803-862b-4feadd3f6092", 274 + "to_change_id": "c095ccd1-be73-449d-9eb6-e675c9d7f090", 275 + "edge_type": "leads_to", 276 + "weight": 1.0, 277 + "rationale": "Chose this approach", 278 + "created_at": "2026-04-05T06:20:17.414591-07:00" 279 + }, 280 + { 281 + "id": 4, 282 + "from_node_id": 3, 283 + "to_node_id": 4, 284 + "from_change_id": "1c0cb222-6785-4d35-9f86-674e2aacf373", 285 + "to_change_id": "c095ccd1-be73-449d-9eb6-e675c9d7f090", 286 + "edge_type": "leads_to", 287 + "weight": 1.0, 288 + "rationale": "Chose this approach", 289 + "created_at": "2026-04-05T06:20:17.419889-07:00" 290 + }, 291 + { 292 + "id": 5, 293 + "from_node_id": 4, 294 + "to_node_id": 5, 295 + "from_change_id": "c095ccd1-be73-449d-9eb6-e675c9d7f090", 296 + "to_change_id": "db57b64e-d3d3-4e9e-b955-a50c2ac65fee", 297 + "edge_type": "leads_to", 298 + "weight": 1.0, 299 + "rationale": "Implementation of chosen stack", 300 + "created_at": "2026-04-05T06:20:24.651998-07:00" 301 + }, 302 + { 303 + "id": 6, 304 + "from_node_id": 5, 305 + "to_node_id": 6, 306 + "from_change_id": "db57b64e-d3d3-4e9e-b955-a50c2ac65fee", 307 + "to_change_id": "3fe5e92d-afab-4d5a-9460-1d01ec3e89a7", 308 + "edge_type": "leads_to", 309 + "weight": 1.0, 310 + "rationale": "Result of transcription pipeline run", 311 + "created_at": "2026-04-05T06:20:24.667597-07:00" 312 + }, 313 + { 314 + "id": 7, 315 + "from_node_id": 6, 316 + "to_node_id": 7, 317 + "from_change_id": "3fe5e92d-afab-4d5a-9460-1d01ec3e89a7", 318 + "to_change_id": "a2e3e3e6-ca6a-4adf-9c16-50683f4e69ab", 319 + "edge_type": "leads_to", 320 + "weight": 1.0, 321 + "rationale": "Discovery during pipeline run", 322 + "created_at": "2026-04-05T06:20:35.357640-07:00" 323 + }, 324 + { 325 + "id": 8, 326 + "from_node_id": 1, 327 + "to_node_id": 8, 328 + "from_change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 329 + "to_change_id": "cb33f803-5dc7-4939-bcd4-948145224943", 330 + "edge_type": "leads_to", 331 + "weight": 1.0, 332 + "rationale": "Project planning action", 333 + "created_at": "2026-04-05T06:22:16.948366-07:00" 334 + }, 335 + { 336 + "id": 9, 337 + "from_node_id": 4, 338 + "to_node_id": 9, 339 + "from_change_id": "c095ccd1-be73-449d-9eb6-e675c9d7f090", 340 + "to_change_id": "320c518d-10b7-4c3a-8c2a-26280260307c", 341 + "edge_type": "leads_to", 342 + "weight": 1.0, 343 + "rationale": "Design system implements the visual foundation for the chosen Next.js stack", 344 + "created_at": "2026-04-06T16:07:48.236867-07:00" 345 + }, 346 + { 347 + "id": 10, 348 + "from_node_id": 9, 349 + "to_node_id": 10, 350 + "from_change_id": "320c518d-10b7-4c3a-8c2a-26280260307c", 351 + "to_change_id": "849be730-00e0-4479-a14a-5b9f9a3f8bd7", 352 + "edge_type": "leads_to", 353 + "weight": 1.0, 354 + "rationale": "Design system implementation complete, merged to main", 355 + "created_at": "2026-04-06T16:07:58.765476-07:00" 356 + }, 357 + { 358 + "id": 11, 359 + "from_node_id": 7, 360 + "to_node_id": 11, 361 + "from_change_id": "a2e3e3e6-ca6a-4adf-9c16-50683f4e69ab", 362 + "to_change_id": "cf7e27f6-790c-4b76-b362-b5b39f344899", 363 + "edge_type": "leads_to", 364 + "weight": 1.0, 365 + "rationale": "Fixing the gap identified in observation about ATScience vodAtUri links", 366 + "created_at": "2026-04-06T16:08:08.295208-07:00" 367 + }, 368 + { 369 + "id": 12, 370 + "from_node_id": 11, 371 + "to_node_id": 12, 372 + "from_change_id": "cf7e27f6-790c-4b76-b362-b5b39f344899", 373 + "to_change_id": "032b7fe7-7966-4e06-b7b2-c98c33017645", 374 + "edge_type": "leads_to", 375 + "weight": 1.0, 376 + "rationale": "Fallback matching resolved ATScience schedule gaps", 377 + "created_at": "2026-04-06T16:08:08.311572-07:00" 378 + }, 379 + { 380 + "id": 13, 381 + "from_node_id": 10, 382 + "to_node_id": 13, 383 + "from_change_id": "849be730-00e0-4479-a14a-5b9f9a3f8bd7", 384 + "to_change_id": "6f73230b-15b5-4930-9267-f886c9ae09c5", 385 + "edge_type": "leads_to", 386 + "weight": 1.0, 387 + "rationale": "Talk page builds on the completed design system", 388 + "created_at": "2026-04-06T16:57:42.751320-07:00" 389 + }, 390 + { 391 + "id": 14, 392 + "from_node_id": 13, 393 + "to_node_id": 14, 394 + "from_change_id": "6f73230b-15b5-4930-9267-f886c9ae09c5", 395 + "to_change_id": "fc101e72-add6-44cc-b5c4-611e3b3075bb", 396 + "edge_type": "leads_to", 397 + "weight": 1.0, 398 + "rationale": "Talk page implementation complete", 399 + "created_at": "2026-04-06T16:57:42.773836-07:00" 400 + }, 401 + { 402 + "id": 15, 403 + "from_node_id": 14, 404 + "to_node_id": 15, 405 + "from_change_id": "fc101e72-add6-44cc-b5c4-611e3b3075bb", 406 + "to_change_id": "409656c7-fcb6-4c0f-a147-1f342a16b2f4", 407 + "edge_type": "leads_to", 408 + "weight": 1.0, 409 + "rationale": "Landing page builds on completed talk pages", 410 + "created_at": "2026-04-06T17:28:39.525341-07:00" 411 + }, 412 + { 413 + "id": 16, 414 + "from_node_id": 15, 415 + "to_node_id": 16, 416 + "from_change_id": "409656c7-fcb6-4c0f-a147-1f342a16b2f4", 417 + "to_change_id": "a4e6001c-f14c-40d2-9453-7a736424f715", 418 + "edge_type": "leads_to", 419 + "weight": 1.0, 420 + "rationale": "Landing page complete", 421 + "created_at": "2026-04-06T17:28:39.544503-07:00" 422 + }, 423 + { 424 + "id": 17, 425 + "from_node_id": 16, 426 + "to_node_id": 17, 427 + "from_change_id": "a4e6001c-f14c-40d2-9453-7a736424f715", 428 + "to_change_id": "4f052c12-6057-4ac0-bb5a-fe713468abf8", 429 + "edge_type": "leads_to", 430 + "weight": 1.0, 431 + "rationale": "OAuth enables personalized features on top of static pages", 432 + "created_at": "2026-04-07T21:43:18.386897-07:00" 433 + }, 434 + { 435 + "id": 18, 436 + "from_node_id": 17, 437 + "to_node_id": 18, 438 + "from_change_id": "4f052c12-6057-4ac0-bb5a-fe713468abf8", 439 + "to_change_id": "c60fe61e-b37d-4cb4-8c0d-216a866c6198", 440 + "edge_type": "leads_to", 441 + "weight": 1.0, 442 + "rationale": "OAuth flow complete and tested", 443 + "created_at": "2026-04-07T21:43:18.404085-07:00" 444 + }, 445 + { 446 + "id": 19, 447 + "from_node_id": 1, 448 + "to_node_id": 19, 449 + "from_change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 450 + "to_change_id": "50d9542b-7dcc-4e2e-a5bf-75fed865ed99", 451 + "edge_type": "leads_to", 452 + "weight": 1.0, 453 + "rationale": "Crawler is core feature of Understory per spec", 454 + "created_at": "2026-04-09T15:49:53.815507-07:00" 455 + }, 456 + { 457 + "id": 20, 458 + "from_node_id": 19, 459 + "to_node_id": 20, 460 + "from_change_id": "50d9542b-7dcc-4e2e-a5bf-75fed865ed99", 461 + "to_change_id": "9dbc20bb-3cd6-48d3-85dc-98276812d82c", 462 + "edge_type": "leads_to", 463 + "weight": 1.0, 464 + "rationale": "Implementation result", 465 + "created_at": "2026-04-09T15:49:53.821825-07:00" 466 + }, 467 + { 468 + "id": 21, 469 + "from_node_id": 19, 470 + "to_node_id": 21, 471 + "from_change_id": "50d9542b-7dcc-4e2e-a5bf-75fed865ed99", 472 + "to_change_id": "8dfc00b5-0444-4258-aa05-1aa59b45f5bb", 473 + "edge_type": "leads_to", 474 + "weight": 1.0, 475 + "rationale": "Follow-up fixes from code review", 476 + "created_at": "2026-04-09T16:04:37.489914-07:00" 477 + }, 478 + { 479 + "id": 22, 480 + "from_node_id": 21, 481 + "to_node_id": 22, 482 + "from_change_id": "8dfc00b5-0444-4258-aa05-1aa59b45f5bb", 483 + "to_change_id": "f53b3b51-76aa-4b33-b58f-f88825991593", 484 + "edge_type": "leads_to", 485 + "weight": 1.0, 486 + "rationale": "Documentation archived after PR #5 merged", 487 + "created_at": "2026-04-09T20:04:11.511166-07:00" 488 + } 489 + ], 490 + "documents": [ 491 + { 492 + "id": 1, 493 + "change_id": "8ba8f873-e5d1-43d1-8e0f-b8e2f44d9338", 494 + "node_id": 1, 495 + "node_change_id": "64a3beb0-3fe9-44bd-9b4a-cfa8f5470cf2", 496 + "content_hash": "5453fbe3a98c2d2b41df57faca270c39fb945f9217ea3258337fb602efb5b7d3", 497 + "original_filename": "understory-design.md", 498 + "storage_filename": "understory-design.md.5453fbe3", 499 + "mime_type": "text/markdown", 500 + "file_size": 36512, 501 + "description": "Full system design spec for Understory", 502 + "description_source": "manual", 503 + "attached_at": "2026-04-05T06:20:07.564957-07:00", 504 + "attached_by": null, 505 + "detached_at": null 506 + } 507 + ] 508 + }