Repository navigation
Add comprehensive research documentation for git worldmap architecture - #7
Draft
yarikoptic wants to merge 37 commits into
Draft
yarikoptic wants to merge 37 commits into
yarikoptic wants to merge 37 commits into
Conversation
…zers Interim landing of two of five parallel research tracks for the git walker/drawer issues (#1, #4, #5, #6): - tech-graph-visualization-stack.md: survey of browser graph rendering libraries, layout engines, exploration apps, view-state persistence formats and their licenses. - tools-git-native-visualizers.md: survey of existing open source tools that draw/navigate git repo, branch and remote relationships. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Third of five parallel research tracks for the git walker/drawer issues (#1, #4, #5, #6): survey of incrementally-expanded persistent knowledge map tools (Maltego model, AWS graph-explorer, Juggl, OpenCTI, Litmaps), application architecture options, worldmap persistence and merge design, plus naming, scope and a phased roadmap proposal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Final two pieces of the five-track research for the git walker/drawer issues (#1, #4, #5, #6): - ecosystem-and-walker-data-sources.md: git-annex/DataLad prior art, forge and discovery APIs, measured costs for cheap remote-state acquisition, RIA layout, security of ssh spidering, crawl algorithm. - README.md: synthesis across all five tracks with editorial judgement, ranked data sources, scope and MVP proposal, open questions. Verified independently while synthesizing: - 'git annex map --json' exists as of git-annex 10.20250605; the todo referenced from issue #1 is done. - Command/Map.hs is AGPL-3-or-later (not GPL-3 as two tracks reported), so its --json output should be consumed rather than its code reused. - The --json schema carries no host/cluster grouping and no trust level, and silently drops dead remotes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Reviews concepts.datalad.org (read from the psychoinformatics-de/datalad-concepts source, as the site is egress-blocked here) and the orinoco explore view of the CON test site, in light of the reframing towards a generic graph exploration system with typed expansion, refresh, and per-model view tuning. Findings: - The 'things' module is already a generic reifiable property-graph model (Thing/Property/Statement/AttributeSpecification, relations-mixin), and Statement.characterized_by provides data-carrying edges. - No version-control vocabulary exists at all (Repository/Clone/Remote/Branch all grep to zero); git commits and annex keys appear only in examples, though an annex-key namespace is already reserved. - No observation/vantage layer for staleness of the description itself. - The orinoco explore view emits untyped edges, discarding relation semantics the source records carry; it is static, with no expansion or saved view. - Per-model presentation tuning already exists as LinkML sh:/dash: annotations driving shacl-vue forms; the proposal is a parallel graph: annotation set. Also amends the synthesis README: the earlier claim that data-carrying edges rule out RDF is superseded by dlthings:Statement reification. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
- Replace the inferred 'project has clearly anticipated VCS' claim with the actual evidence and its limits: three identifier namespaces (gitsha, dataset-uuid, annex-key) are already minted under concepts.datalad.org in demo-research-assets' XYZDistribution example, while the type still points at example.org; and extra-docs/usage-considerations.md lines 179-186 name the 'network of dataset clones' in prose. No stated roadmap exists. - Note the shaclvue: namespace precedent for tool-specific presentation terms. - New section 5a: plain git repos have no annex branch, so their remotes can only be read by running git where the repo lives. This makes ssh a primary walker path and fixes the backend as a real local program: shell out to the system ssh, inherit ssh-agent/ssh_config/ProxyJump, support interactive auth via BatchMode detection and retry, keep probes as POSIX sh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
…ment Assesses dump-things-service (read from the christian-monch GitHub mirror) as the record store: LinkML collections over datalad Thing, record_dir/sqlite backends, incoming-vs-curated areas, token/Forgejo authz, JSON+Turtle output. Its retrieval API has no traversal and no backward query, so a derived adjacency index is needed in front of it. Assesses BrainKB (sensein/BrainKB, sensein/brainkb-ui) against the three axes asked about: no plugin/adapter interface; its d3 graph view operates on an uploaded triples file with click-to-select rather than expanding the live store; but contribution, RBAC and LLM-assisted extraction are strong, and evidence/assertion semantics are its premise. Sibling with opposite emphasis; align at the model level, not the code level. Surveys pluggable-expansion prior art (NCATS Translator KP/ARA/TRAPI/Biolink, Knowledge Beacons, Comunica, MCP as a possible transport), evidence modelling (nanopublication assertion/provenance/publication-info split, which refines the earlier observation record), and model-driven UI platforms (metaphactory, LinkedDataHub, shacl-vue, Reactodia), noting none does model-driven graph exploration. Proposes the two collections in one store, one UI, two perspectives test as the cheapest proof of the pluggability claim. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Reads con/query-things (now cloneable) and dandi/dandi-bib from source. - Corrects the previous document: query-things already implements forward (filter-linked-pid), backward and recursive (filter-links-pid) traversal, normalises association-class edges, anticipates time-windowed matching, and resolves pids across collections. What is missing is an index, not the semantics. - Tests git propagation directly: contents of .git/ do not survive a clone, and neither do refs outside refs/heads/*; only a real branch travels. This gives a two-tier split matching dump-things' incoming/curated areas -- .git/orinoco/ for transactions and caches, an orinoco branch for curated records in record_dir layout, fetchable with one cheap command. - Repo-as-seed browsing, with file:/// before ssh, remote exploration by running the same tool remotely with a POSIX sh fallback, and aggregation as a vantage-point-preserving merge. - Collections split by provenance rather than entity type, with a four-step identity strategy for common nodes (People, repos, papers); dandi-bib is both a node and a collection provider. - Sharpened first milestone that exercises all four architectural claims with no ssh, no forge API and no new vocabulary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Answers whether an ontology or controlled vocabulary already covers the git graph, whether to extend datalad-concepts and map outward, and whether any W3C group is producing a schema.org extension. Verified from source rather than search summaries: - schema.org release 18.0 has no repository/clone/remote/branch/fork/commit class at all, and codeRepository has rangeIncludes schema:URL -- a link, not an entity. - ForgeFed (head 2026-05-03) is active with 41 terms; its mirroredFrom/ mirrors family is the closest existing analogue to clone-of, and cloneUri and forkedFrom are directly usable. - SEON is abandoned since 2013 and its Clone class means *code clone* (duplicated fragments), not repository clone -- a false friend. - SWHID is now ISO/IEC 18670:2025; its snp object identifies the full set of branches of a repo at a moment, which is a usable clone-state primitive. Concludes that existing vocabularies model the project, the content, or the forge social layer, but never the deployment topology -- because a named remote is local, asymmetric, mutable and private, which is exactly what standards bodies do not mint terms for. Recommends authoring a things-vcs module and linking by LinkML mappings rather than owl:imports, with enum values taken verbatim from git-annex, and defers standards engagement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Resolves open question 4 of the vocabulary document. - LinkML does support mixins (50 uses in datalad-concepts), so the premise about multiple inheritance is half right; slots are still correct here, because the variation is per-instance, not per-schema. Rule adopted: mixin when the variation changes which slots exist, slot when it changes a value. - Recommends orthogonal enum slots (vcs, layout, annex_mode, packaging) over a flat feature bag, so layout is validatable and groupable. A RIA store is a Distribution containing Distributions via parts, which also gives bundles and submodule nesting; vcs: none covers special remotes with no git. - Clone disappears as a class and becomes a perspective over Distribution. - Measured the template-sibling case: a template, two independent descendants and one true clone all share the same root commit, so root commit cannot discriminate. Merge-base position plus containment does (0.19 vs 1.00). Recommends containment over Jaccard. - Argues no content-based immutable repository id can exist, since false merge (shared template prefix) and false split (history rewriting) impose contradictory requirements; identity must be extrinsic or asserted. - Verified the DataLad dataset id is tracked in the default branch (dandi-bib), notes the template-copy trap, and ranks identity evidence by cost and strength. Identity becomes a claim with provenance over objective computed relations, never a silent merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
- Reweight the DataLad dataset id: it settles ~99% of cases and the design should lean on it rather than hedge. The in-tree template-copy trap becomes a lint (loud error when two demonstrably different datasets declare the same id), not a general suspicion; matching ids otherwise merge silently. - Add the remote-graph signal (shared common clone among remotes for the same tracked default branch) and test it against the same fixture. Taken alone it gets the case backwards in both directions: the two template siblings share an upstream and a tracked branch while not being the same repository, and the true clone has a different upstream from both. It measures lineage, not identity, for the same reason history overlap does. It becomes strong in two forms: mutual remote references, which templates never produce and which the spacetop map in issue #1 exhibits; and as a free candidate generator, where connected components over canonicalised remote URLs bound the set of pairs that the expensive checks are run on. Adopts the resulting two-stage identity algorithm: remote topology bounds the problem, declared ids resolve it, history overlap breaks ties for the plain-git remainder. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Adds reproducible worldmap.json fixtures (fixed epoch, seeded RNG) for
comparing prototype graph explorers:
- s1-spacetop 24 nodes host clustering, disagreeing remote names, special
remotes, duplicate annex UUID error, dead remote
- s2-babs-ria 51 nodes superdataset/subdataset and RIA-store nesting, 40
per-subject result branches, worktrees, aheadness
- s3-forks 68 nodes plain git with no UUIDs, 52 inactive forks to grey
out, preview-before-add, and the measured template
sibling trap at containment 0.19
Node/edge shape follows the Distribution model, with parent for containment
and kind naming the relation to expand along.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
The three bake-off teams are writing into issue-1/prototypes/team-{a,b,c}/.
Keep source, screenshots, exports and findings; drop node_modules and build
artifacts. Team output itself is committed once the runs finish.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Third bake-off approach: sigma 3.0.3 + graphology, deliberately without compound nodes, testing whether perspectives and filtering can substitute for nesting. - stdlib http.server backend, seed-only reveal, POST /expand with a real 300-900ms probe delay, GET /synthetic up to 30k nodes - five perspectives (remotes, storage, lineage, topology, health) switching in 2.5-15.4ms without moving any node - containment without compound nodes via four layers: nested annulus packing, a hull canvas behind sigma, collapse-to-meta-node, semantic zoom - 38 Playwright screenshots, all verified non-blank, zero console errors Their own negative findings: ~600 of 1862 client lines exist only to replace one library feature; canvas edge labels crowd from ~150 nodes and are already tight on s1 at 24; collapse stops paying above ~500 nodes for sparse groups because cross-group edges grow; and the 10k hairball is edge aggregation, which compound nodes would not have fixed either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
First bake-off approach: Cytoscape 3.34 + fcose with fixedNodeConstraint pinning, layout-utilities for placing new nodes, node-html-label badges. - stdlib http.server backend, seed-only reveal, POST /api/expand with a 300-900ms probe delay; stateless, client sends known ids and the server returns a recomputed frontier that drives the +N hidden badges - compound hosts and RIA stores nested 3 levels deep in s2, per-edge remote names, aheadness chips, hand-rolled collapse with meta-edge bundling, s3 grey-out / preview / add-as-remote, live layout-stability HUD - 16 Playwright screenshots, all verified non-blank; raw metrics committed Central claim verified from the raw metrics rather than the summary: with pinning, displacement of already-placed leaf nodes is 0.00px mean AND max across all 19 pinned probes, against 434-756px for the unpinned control and 455px for a naive full re-layout. Their own negative findings: fCoSE cannot pin a compound, so a node that becomes a container jumps 980px when it gains 40 children -- and in a compound-first design the containers are exactly what grows; edge labels render at 4.3-5.1px at the default fit zoom, below legibility, so s1's remote-name story is carried by the inspector rather than the picture; revealing all 68 nodes at once drops to 6.2fps with a 417ms blocked frame; and s3's identity trap is a disconnected component that pure traversal never reaches, which is a finding about the model, not the renderer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Second bake-off approach: @hpcc-js/wasm Graphviz computing real cluster geometry in-browser, fed to Cytoscape as a preset layout, plus an ELK layered lineage view. - stdlib http.server backend with GET /api/dot emitting cluster_<host> subgraphs, so the worldmap.json -> DOT -> browser Graphviz -> cytoscape preset round trip is demonstrated end to end - save/load/continue with server-side canonicalisation; three genuinely self-contained HTML exports (464-496kB, zero external refs, verified loading over file:// with non-file requests aborted) - 25 Playwright screenshots, all verified non-blank Correction they found to the brief: dot_json in @hpcc-js/wasm 2.35.0 returns the parsed DOT AST with no coordinates; the format carrying layout results is plain 'json' (xdot). Their own negative findings, verified here: persistence is excellent (0px drift over 14 nodes on reload) but the generator is unstable -- one expansion adding a single node moved 62 of 62 already-placed nodes by a median 1588px, and about half of measured expansions had zero churn while the rest were catastrophic. I confirmed the consequence independently: two consecutive saved views differ by 88 of 155 lines, with coordinates churning outright. Diff-friendly formatting cannot rescue an unstable generator. Graphviz needed three hacks for fans (rank=same gridding, server-emitted gridpos with client snapping, and an ELK fan pre-pass). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Cross-team comparison of the three prototypes, with every claim re-verified against the committed artefacts rather than the teams' summaries. The main result is that two failures appeared in all three prototypes independently, across different renderers and layout engines, which makes them properties of the problem and our model rather than of any stack: - per-clone remote names do not survive the default view (measured at 4.3-5.1px by one team, colliding at 51 nodes for another, avoided only by abandoning free layout for a grid), so the naming relation issue #1 is about needs label-on-demand rather than a static edge label - expansion from a seed silently omits whole disconnected components; s3's template trap was unreachable, one team's first run reported 67/68 nodes with the finding never firing. A seed is not a root set, and containment must be a walkable relation. Judgement: keep Cytoscape as the base, but give compounds their geometry from a whole-graph pass and let the incremental layout place only leaves, since fCoSE pins leaves at 0.00px yet cannot pin a container that grew by 980px. Adopt Team B's persistence and self-contained export, and Team C's aggregate tier treated as edge aggregation rather than node hiding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Implements the judgement from BAKE-OFF-RESULTS.md: container geometry from a whole-graph pass that reruns only when the container set changes, leaves placed inside fixed container bounds, both tiers in a Web Worker, edge aggregation on collapse, a real root set, and label-on-demand. Verified here against the raw metrics and saved views rather than the team's prose: containers other than the expanded one move 0px on 16/17 expansions (vs 980px for Team A); one expansion changes 16 of 199 view lines (vs 88 of 155 for Team B) and an identical state diffs to 0; collapse cuts edges 86->7 and 66->3 (vs Team C's 773->1205 increase); longest frame at 68 nodes falls to 100-117ms from 416.6ms; edge labels render at 13px at fit zoom instead of 4.3-5.1px; and s3 reachability is measured and displayed as 62/68 rather than silently reported as 67/68. It loses to Team B on reload drift (0.462px vs 0) and to Team A on first paint (324-354ms vs 311ms). A control arm makes this falsifiable: every scenario was run twice, sticky and full, and the full arm reproduces the failure at 10/17 zero with displacements to 607px. The team's own verdict corrects the judgement's reasoning and is recorded as such: the win came not from composing Graphviz with fCoSE but from taking container geometry away from the layout engine and storing leaf positions in container-local coordinates anchored to a corner that never moves. They used no Cytoscape compound nodes at all, and fcose output survived in only 2 of 20 tier-2 runs, so tier 2 wants a packing algorithm rather than a force layout. The durable finding is a data-model one, portable to any renderer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
The reports referenced 28 screenshots as verbatim backticked paths, so none of them rendered. Now: - 20 inline mentions across team-a, team-c and team-d converted to figures placed after the paragraph that discusses them, with the filename kept in the prose so the reference still reads - team-b's screenshot index table converted from 18 filename rows into captioned figures, including the six file:// export shots that were referenced by a glob - a screenshot gallery appended to each team README, grouped by scenario: 16 (A), 25 (B), 38 (C), 28 (D) images - BAKE-OFF-RESULTS.md gains a side-by-side section showing the same moment rendered four ways for the two shared benchmarks (the s1 duplicate annex UUID and s3's 52 inactive forks), plus the two things only Team D managed: remote-name disagreement legible at fit zoom, and the unreachable-component affordance All 162 image links verified to resolve; zero broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Adds issue-1/tools/worldmap-crawl.py: emits the scenario worldmap.json schema from real git/git-annex repositories using plain git only -- git-annex and datalad need not be installed. Reads remotes with their per-clone names, branch tracking, ahead/behind from local refs without network, worktrees, submodules as containment, the DataLad dataset id out of the tree, and uuid.log / remote.log / trust.log straight from the git-annex branch via git cat-file. --depth follows local remotes; --ls-remote allows one round trip per unresolved remote. Wires Team D to accept it: server discovers any directory under WORLDMAP_DIR holding a worldmap.json and re-scans per request, and the client populates its dropdown from GET /api/scenarios instead of a hardcoded list. Verified end to end on real repositories. On a shallow clone of dandi-bib the crawl yields 4 nodes; after one 1.27s fetch of just the git-annex branch it yields 28, discovering 23 clones with no ssh and no credentials, and expanding the seed in the prototype returns 27 nodes and 49 edges in a single probe. That reproduces finding 2 of the synthesis on real data rather than on a fixture. Browser session had zero console errors. Documents plainly what it does not do: no ssh, no forge APIs, no identity resolution, no .git/orinoco persistence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Testing worldmap-crawl.py against a real collection of spacetop datasets surfaced three defects that made a 108-node crawl render as 6 nodes: - The server's WALKABLE relation list was hardcoded, so annex_knows edges emitted by the crawler were not expandable and 92 of 108 nodes were silently unreachable. WALKABLE is now derived per worldmap from the relations actually present, with the original vocabulary as the ordering baseline. Same class of bug as the hardcoded scenario list. - There was no way to show an already-crawled graph. 'expand all' only un-collapses containers and never probes, so the only path was clicking each seed and each relation in turn. Adds a 'reveal all' button and ids:'*' support in /api/materialize: for a crawl the data is already on disk, so probing one relation at a time is theatre. - Clones discovered through uuid.log all landed under a single 'unknown' host. git-annex descriptions are conventionally user@host:/path, so the host is now parsed out and clones cluster by real machine, which is what makes the issue #1 style host grouping work. Verified end to end: a six-repo crawl now reveals 36 nodes across github.com, localhost and the real annex-known hosts, then 41 nodes across 8 hosts once descriptions are parsed, with zero console errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Adds issue-1/exploration-history-and-undo.md and implements it in the Team D prototype. Two rules make undo correct rather than merely plausible: - Undo operates on the view, never on the store. A step is undone by hiding what it revealed, not by forgetting what it taught, because crawled facts are append-only knowledge exactly as observations are in the store design. Redo therefore needs no network and never re-runs a 300-900ms probe, and undo can never lose data. The first implementation violated this by truncating the edge array, which both destroyed knowledge and made redo impossible; the fix touches only visible, collapsed and the layout snapshot, since edges are already filtered by visibility at render time. - A step snapshots container geometry so undo restores positions rather than recomputing them. Re-running layout on undo would move everything and throw away the 0px stability that is Team D's whole result. This is cheap because leaf positions are container-local: a snapshot is two small maps, not one entry per node. Full history to 100 steps with redo, jump-to-any-point, Ctrl+Z / Ctrl+Shift+Z, a history panel, and no entry recorded for probes that return nothing or fail. Verified by driving the real app: 5 steps 2->51->11->51->11->3, undo walks back the exact mirror 11->51->11->51->2, undo disables at the start, redo replays all 5, undo/redo cycle drift 0.00px, zero console errors. Scope explicitly excludes persistence across reloads, collaborative undo, and undoing writes -- a view-history control silently reverting a git remote add would be a serious surprise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Written as a TODO spec, not implemented. Badges on repository rectangles, so the map answers questions without being clicked: unwalked relation counts, humanised annex size held, annex-ignore, form, trust, and health. Shaped by a measurement rather than taste -- node text renders at 6.8px at fit zoom, so badges are glyph-and-colour first with text only at reading zoom, capped at four plus overflow, toggled per group. Two design points worth the spec: - Annex sizes need neither git-annex nor the network. Keys encode their own size in the -s<bytes> field, so summing over the location logs in an already-fetched git-annex branch gives believed bytes held per UUID for every clone on the map. Recorded as an observation with its timestamp, since it is what the last sync claimed, not verified truth, and keys without a size field are reported separately rather than undercounted. - annex-ignore is per-clone config, so it is an edge property; 'ignored by every clone that knows it' is a derived graph finding worth a node badge, because it means the map contains no route to content there at all. The fact stays on edges and the conclusion appears on a node with nothing denormalised. Also specifies the relation details panel, fixing that clicking a remote leaves the panel showing the repository. Content is ordered by cost: free crawled facts immediately (per-clone names and the disagreement, annex-ignore, recorded-vs-observed uuid, trust, ahead/behind with its staleness), a branch correspondence table behind one ls-remote, and content comparison shown log-derived and labelled believed with verification offered separately. Every computed row is stored as an observation, so laziness keeps the panel honest about known versus assumed rather than merely being a performance tactic. Lists what worldmap-crawl.py must collect for each, with costs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Two corrections from review, both verified against the git-annex source. - Do not hand-sum key sizes. The earlier draft proposed parsing -s<bytes> out of key names in the location log; that reimplements badly what git-annex already does. 'git annex info' reports the annex sizes of each repository in one command, with --json, --bytes, --show= to skip unnecessary work, and --fast; and the CHANGELOG for 10.20240831 records 'info: Improved speed by using new repository size tracking', so it is maintained rather than recomputed. Where git-annex is absent the size is reported unknown rather than estimated, since an estimate that disagrees with git annex info is worse than a blank. - For pairwise comparison use a matching expression rather than set arithmetic: git annex find --in=X --not --in=Y with --format exposing bytesize and key. Both directions are shown as two figures, never one signed number, because they answer different questions. - annex-ignore: a short, explicit, overridable list of forges that cannot carry annexed content over plain git is allowed, but marked as an assumption visually distinct from an observed setting -- a wrong prior that looks like a measurement is a bug nobody will find. The sharper point is the git-lfs special remote (Remote/GitLFS.hs), which stores annexed content on exactly such a host: annex-capability is a property of the route, not the host, so the same host can carry both an annex-incapable git remote and an annex-capable git-lfs special remote. They are two distributions sharing a host, which the instance-slot model already expresses and a host-level flag could not. Host nodes are therefore never coloured annex-incapable, and a git-lfs remote to such a host is the interesting configuration rather than a contradiction to warn about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Implements the badge half of the badges spec plus two requested features. - Node badges (web/src/badges.js): glyph-and-colour indicators grouped as health / annex policy / storage / topology / form, ordered by priority, capped at four plus overflow, toggled per group from the toolbar and persisted in localStorage. Rendered above the node label because at fit zoom the label text itself is ~7px. 'ignored by all known' is computed as the derived graph finding the spec calls for -- unanimous annex-ignore over at least two inbound edges -- rather than stored on the node. - Hide node / hide container, from the details panel. Hidden nodes leave the view but stay in the store, appear in a Hidden panel with show / show all, and are un-hidden automatically when a later expansion from another clone reaches them. Hiding is a history step, so Ctrl+Z brings them back. - Version stamping: the server reports ba97756-dirty of its checkout, the crawler stamps tool_version, git_version, git_annex_version and crawled_at into every map it produces, and the footer shows both, so a screenshot names the exact code that made it. - Crawler now collects remote.<n>.annex-ignore and pushurl, and marks known annex-incapable forges with annex_incapable_assumed -- flagged as an assumption distinct from an observed setting, and never applied to a host node or to a special remote, since a git-lfs remote to the same host can carry content. Bug found and fixed by testing: the history snapshot did not include the hidden set, so undoing a hide restored the node count but not the hidden nodes. Verified: hide node 37->36, hide container 37->33 including its four children, undo restores 37, zero console errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
There were 13 research documents and an index, but nothing tracking features from requested through specified, implemented and verified -- status was buried inside individual documents and the answer to 'is X built?' required reading several of them. DESIGN.md is that missing document: settled architecture with links to where each decision was argued, a feature ledger across exploration, rendering, data and provenance with an explicit status per feature, the rules that constrain future work, the known gaps and untested claims, and the ordered next steps. README now points at it first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Two requested features, both cheap because of the container-local coordinate model, and DESIGN.md updated in the same commit per the new working rule. - Drag to reposition. A container owns a world centre, so dragging it carries its children for free; a repository owns an offset from its parent's top-left, so dragging it cannot take it out of the box. Dragged nodes are pinned so later expansion and layout runs work around them, the move is a history step, and placement is already part of the saved view. Measured: container drag moved its 3 children 494px each and everything else 0.00px; leaf drag moved only itself, stayed inside its container box, and survived save+load with 0.01px drift; undo of a move restored 0.00px. - Bundle cross-container edges into one summary arrow per container pair, toggled from the toolbar. Implemented by reusing the collapse roll-up with a different notion of who represents a node, rather than adding a second aggregation mechanism. Edges inside a single container are deliberately left alone. Measured on a real crawl: 26 drawn edges -> 7. Adds two rules to DESIGN.md: new roll-ups reuse effectiveId rather than adding a mechanism, and user placement outranks the layout engine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Clicking a remote arrow showed the repository, so a remote's own configuration was unreachable. A relation is a first-class thing in this model -- RemoteLink is a reified statement carrying its own data -- so it is now selectable and inspectable in its own right. Content is ordered by cost, which is the design rather than an implementation detail. Free and shown immediately: the name this clone uses, every other name the same peer is called by across the map, URL and pushurl, resolution, annex-ignore, the annex-incapable forge assumption rendered as an assumption, recorded annex UUID, trust, and ahead/behind labelled as of the last fetch with its observation age. One round trip (ls-remote branch table) and expensive (content each side lacks) are present as explicit disabled actions pointing at their spec, rather than being silently absent. Bundled and collapsed arrows list their member relations and drill down into each; a member that is not drawn on its own is still inspectable. Both endpoints are navigable, which swaps the panel back to a repository. Fixed while testing: aggregate() wraps every edge, so a lone edge arrived with members:[oneId] and rendered as a summary; only treat it as one when it actually summarises more than one. Verified on s1-spacetop: the panel reports the peer is called 2 different names with the clones using each, a bundled arrow of count 2 lists both members and drills into them, and navigating to an endpoint returns to the distribution panel. Zero console errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Isolated agent runs create a git worktree inside the repository, which shows up as untracked and must never be committed. Ignored narrowly rather than ignoring all of .claude/, so project-level settings there could still be tracked if ever wanted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
An isolated UX pass drove the app with a real mouse (never by poking state) across 18 probes on all three fixtures, and found that drag and bundling were verified only on happy paths. Merged its fixes and its findings. Bugs found and fixed, each measured: 1. A dragged repository escaped its container entirely -- there was no bound at all, and clampTo/innerBounds existed but were never called. A leaf sat 551.9px right and 255.2px below its box; a 40x45px drag already pushed one 42.9px through the bottom. This contradicted both the README and DESIGN.md. 2. Save->load silently lost every nested container size: viewPayload wrote sizes, loadView never read them, so the RIA store reloaded at 210x76 with its 40 children outside the box, and re-saving wrote the loss to disk. 3. S.moved was dead code -- written, snapshotted, never read -- so rule 9 was unimplemented and collapsing a container shoved a hand-placed neighbour and its 40 children 513.31px. 4. A drag during an in-flight probe had its history entry eaten by abandon(), making a 297.53px move un-undoable and then silently reverted by an undo labelled 'expand'. 5. Hide then show of a dragged leaf lost its placement (236.52px). 6. The bundle button stayed lit after an undo that turned bundling off. 7. loadView restored the wrong zoom, found by asserting save->load->save is a fixpoint. Bundling itself is sound: conservation holds in all five collapse/bundle states on all three fixtures, unbundle restores the exact edge id set, and toggling moves nothing. But its benefit is scenario-dependent -- 47.1% on s2 against 1.5% on s3 -- so the ledger's 26->7 was not the general case and is now stated as such. DESIGN.md gains 21 testable requirements covering placement, nothing-else- moves, undo, hide, save/load and aggregation, each with its measured number; the claim that the offset model prevents escape is corrected; and the drag, bundling, hide and hand-arranged-position rows are rewritten with evidence. Merge verified rather than trusted: their main.js was confirmed to contain the relation-details panel added meanwhile, and after merging both were re-tested -- relation panel intact with zero errors, leaf clamped with 0.0px overflow, save->load 0.01px position and 0.00px size, collapse round trip 0.00px over 51 nodes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
…tree floods Items 1 and 2 of the ledger, plus two crawl-shape bugs reported from a real worktree-heavy checkout. Item 1 -- the three known-wrong interactions: - A container was sized to fit its slot grid exactly, so whenever the child count landed on a tier boundary a repository had 0px of room and dragging it did nothing (4 of 9 s1 containers). Added SLACK to container sizing; measured per-container drag room is now 130-334px with zero containers at 0px. - Hiding a container left its children drawn but detached from the box their coordinates were relative to. Hiding a container now always takes its descendants: 37 -> 33 nodes for a container with 3 children, 0 orphans. - A container dropped overlapping another now says so, in the toast and as a dashed warning border. Rule 9 says user placement wins, so the overlap is allowed -- but silently allowing it looked like a rendering fault. Item 2 -- git-annex wiring: - Crawler runs git annex info --json --bytes --fast --show='annex sizes of repositories' and attaches annex_bytes per node, matching by uuid or description. Parser unit-tested against real-shaped output, against git-annex being absent, and against malformed lines. - New POST /api/relation backs the relation panel's two buttons: a real git ls-remote branch correspondence table (same/only-here/only-there/ differs), and git annex find --in=X --not --in=Y as two figures never one signed number. Every result names the command that produced it. - These are marked as the only unverified rows in the ledger: git-annex is not installed here, so no end-to-end run exists. Crawl-shape fixes: - git worktree list reports every worktree whichever one you run it in, so N worktrees emitted N*N worktree_of edges -- the green hairball. Anchored on the main worktree and globally deduped: 5 worktrees now yield 4 arrows, not 25, each pointing at the original location. - Linked worktrees share .git/config, so each re-emitted every remote: 20 worktrees x 59 remotes drew 1180 identical arrows and implied the remotes belonged to each checkout. Emitted once from the main worktree: 5 worktrees x 2 remotes now yield 2 edges, not 10. DESIGN.md gains three crawl-shape requirements, including that a crawl-shape bug is invisible in the viewer and belongs in the crawler's own output. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
- The details-panel button now flips to 'show' on a hidden node and restores it. A hidden node keeps its selection so the panel stays open where the hide happened, and its kind line marks it hidden; showing a container brings its descendants back. Verified: leaf 51->50->51, container 51->48->51, zero console errors. Also fixes the hide path not repainting the inspector, which is why the button appeared not to change. - Remotes are classified by what tracks them: each remote edge carries tracked_by (the branches whose branch.<b>.remote is this remote) and tracking = current | branch | none. Verified against git config ground truth on this repository: origin is tracking=current with tracked_by ['claude/git-graph-viz-research-85imhc', 'main']. The viewer gains a current / tracked / all filter over remote edges, and styles current thicker and untracked dotted, so 'which remotes am I actually working with' is answerable without reading config. Measured on a mixed map: 8 drawn edges -> 6 under 'current', dropping exactly the two untracked remotes. The relation panel names the tracking state and the branches. tracked_by is a list rather than a flag because each worktree has its own HEAD, so 'current' is a question about a node, not about the edge -- recorded as requirement 25. Confirms for the record that hiding a container no longer leaves its children on screen; that was fixed in 4db4f76, after the b21233b build the report came from. Re-verified here on a real github.com container: 41 -> 35 nodes for a container with 5 children, 0 orphans, and show restores 41. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
… all The tracking data landed last commit but only reached edge styling and a filter -- the two places actually read, the arrow-count badge and the expand list, still lumped every remote into one bucket, so an untracked remote looked exactly as worth expanding as the one you work with. - rel_counts now carries remote@current:out, remote@tracked:out and remote@untracked:out beside the total, computed per node because current depends on that node's HEAD. - expand accepts them as relations, so you can walk only the remotes the checked-out branch tracks. - the details panel lists them as separate labelled entries with hints, and a new badge names the count of remotes the current branch tracks. Verified per node within one map: a checkout on claude/git-graph-viz-research shows remote:out 1 / remote@tracked:out 1 / remote@current:out 1 and badges 'current 1', while a worktree on master with two untracked remotes shows remote:out 2 / remote@untracked:out 2 and no tracked badge. Also renames 'expand all' to 'uncollapse all'. It only ever unfolded collapsed containers and never probed, and was reported as doing nothing twice; 'reveal all' remains the control that shows everything crawled. Added as rule 10: a control that silently does less than its name is a bug report generator. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Every interaction defect found so far was found by a human clicking, so add the suite that would have caught them. tools/e2e/setup-fixture.sh builds eight real repositories: a clone of datalad/testrepo_gh with a live github remote, a submodule, two clones (one carrying remotes no branch tracks), two linked worktrees, and the same subdataset a second time with origin removed so that only shared history and the dataset id relate the two copies. tools/e2e/e2e.mjs crawls that fixture, serves it, and drives Playwright through 25 invariants -- relations, not golden numbers, so the fixture can grow. --worldmap/--scenario replays the viewer half against the pre-generated s1/s2/s3 maps (24, 51 and 68 nodes), which is where a regression that only shows on a wider map gets caught. The suite immediately earned its keep: "collapse all" folded only containers with no *visible* parent, so a container drawn without its own parent on screen was skipped and its repositories stayed drawn -- reported twice as "collapse all still leaves individual repos". Fold every container with visible children instead; an inner fold is harmless when the outer one hides it. The stray check passed throughout, because "no orphan drawn" and "only containers drawn" are different claims -- hence the new assertion, which states what the label promises. DESIGN.md gains section 5 (testing): what the suite is, the five rules it follows, and what it still does not cover -- git-annex, ssh, scale above 68 nodes, save/load/export, layout quality. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Three related asks: mark which remote connections are automated, deduce
and visualise the movement of data, and fold in the standard git-annex
groups as extracted metadata.
Verified the ground truth against a real git-annex branch rather than
recalling it. The location log is `<unixtime>s <1|0> <uuid>`, not the
+/- form; size is carried in the key name (MD5E-s359--...), so flow can
be byte-weighted with plain git and no `git annex info`; per-key
metadata sits alongside in <key>.log.met, which is where a
`metadata=` preferred-content expression gets its answers.
That probe also found something worth recording as a defect rather than
a feature. dandi-bib, the repository the annex path was demonstrated on
("23 clones, 1.27s"), has 25 UUIDs in uuid.log of which 24 are ephemeral
`runner@runnervm...` CI VMs and exactly one holds any content, with the
branch authored by github-actions[bot]. The crawler is right and the map
is wrong: it draws 25 clones where there is one repository and one
automated process. Downgraded that ledger row to "mechanism correct,
misleading result" and recorded the numbers in Known gaps.
The spec keeps policy (git-annex branch, global, free), automation
(config/hooks/cron/CI, per-clone, inferred) and flow (location-log
replay, O(keys), direction unrecorded) as three separate claims with
separate confidences, and six new rules in section 4 hold that line --
notably that direction of transfer is always inference, that a
location-log entry is a claim rather than an observation, that
preferred-content expressions must never be reimplemented, and that
world time must not be merged into the undo history.
Work is ordered cheapest first, and the cheapest item -- deciding
whether a clone is a person or a bot -- is promoted to the top of
section 7 because it needs no git-annex binary and fixes the map above.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
…ld gap Reviewed the harness by making it fail on purpose. A mutation drill -- sabotage collapseAll into a no-op, expect red -- ran GREEN, because the server serves web/dist, a Vite build, and the build predated the sabotage. The same gap means the collapse-all fix in 1209bad was first "verified" by a build from before the fix (dist 13:43, fix 14:07); it passed because the old code also passes on those maps. The suite now rebuilds the viewer whenever web/src is newer than web/dist, the drill cycle is proven both ways (sabotage -> 2 named FAILs, exit 1, artifacts kept; restore -> auto-rebuild -> green), and that green is the first genuine verification of the fix. The drill is documented in the README and rules 37-41 in DESIGN.md hold the lessons. The rest of the hardening, each item against a failure mode that actually happened: * free ports by default (probed in-process) plus a double scenario guard: the served list must name the requested scenario and the page must agree it loaded it -- the zombie-server / silent-fallback trap that once invalidated three runs is now a named failure. Two suites verified running concurrently. * the server is polled until it answers, with its own output captured, instead of a blind 2.5 s sleep. * quiescence waits (two identical position samples, floor + ceiling) replace ~25 s of guessed sleeps: the walk is ~10 s, was ~50 s, and two consecutive runs plus a concurrent pair showed no flake. * try/finally around the whole walk: an unexpected throw is a named FAIL with a summary; browser and server always close; temp dirs are removed on success and kept on failure (the old --keep deleted nothing and had leaked 17 directories). * repositories are discovered from the fixture and scenarios from scenarios/, so growth in either gains coverage by existing. * setup-fixture.sh sets git identity via environment variables; the per-repo config covered only init'ed repos while clones commit too, which fails on any machine without a global identity. * chrome resolution falls back from CHROME_PATH to the sandbox symlink to playwright's own browser, instead of pinning chromium-1194. * offline mode verified end to end: 26/26 with the synthesised upstream. * package.json pins playwright and gives npm test; a GitHub Actions workflow runs the whole suite on every push touching the prototype and uploads failure artifacts. Full matrix at HEAD: 26/26 fixture (online and offline), 21/21 on each of s1/s2/s3 serial and concurrent, bogus scenario exits 2 with a message, mutation drill red then green -- 89 checks per full run-all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
A subdataset node is now the CHECKOUT at <super>/<path>, contained in its own super -- so a worktree's initialized submodule sits inside the worktree box -- and the edge label is the path, never the URL. The old model made the .gitmodules URL target the node, which labelled subdatasets by URL, claimed the upstream lives inside the super, and let the last worktree crawled win the containment. Fixing that surfaced three more crawl bugs, each now pinned by an e2e invariant (30 on the fixture, 93 across the suite): * `git worktree list` inside a submodule reports the absorbed git dir (.git/modules/...) as the main worktree; taken literally this invented phantom repositories and marked every submodule checkout a linked worktree, suppressing its remotes. * submodule names containing spaces (testrepo_gh's "sub _1") were split at the first space and produced garbage nodes; .gitmodules is now read with `git config -z`. * relative submodule URLs resolve against the superproject's ORIGIN (git's own rule), not its local path. Declared-but-uninitialized subdatasets keep a URL-target node, uncontained, marked state=not-initialized, emitted once per repository. Initialized checkouts are queued for crawling, so their remotes and dataset ids are picked up. The fixture initializes the submodule in wt-x only, keeping the declared-but-absent case on wt-y; the fixture is stamped with its script's hash so run-all --reuse rebuilds when setup changes (same trap as a stale web/dist, caught live). lenses-and-joined-graphs.md answers the generalization question: the worldmap and the psychoinformatics /explore graph are two LENSES over graphs of the same kind. A lens is a declarative bundle (which relation becomes geometry, edge classes structural/route/affinity, type filters, badges, primary action, layout); joins across collections are explicit bridge records on confident keys (dataset id, canonical URL, host, DOI, person) -- never merges -- navigated by portal badges that pivot panes, not by cross-lens arrows. Staged plan puts the lens descriptor extraction and toolbar type filters before the two-collections test. Rules 42-44 and three ledger rows added to DESIGN.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
Replace the lenses doc's cheapest-first staged plan with a six-phase implementation plan, reordered schema-first on the load-bearing argument: a lens classifies relations by name, and only formalizing the deployment model (LinkML, concepts.datalad.org framework) gives those names stable URIs a lens document, a linter, or another tool can reference. Phases: (1) things-deployment schema + worldmap-export converter + round-trip validation in e2e; (2) LensDefinition as a LinkML class, two hand-written lens documents, lens linter; (3) viewer consumes the lens, gated on the unchanged e2e suite staying green; (4) CON group graph as second collection under the portfolio lens, absorbing the two-collections test, dump-things-service decision made here; (5) Bridge records and portal pivots with their own fixture invariants; (6) panes, co-highlighting, person bridges, perspectives as things. DESIGN.md TODO item 4 rewritten to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds extensive research documentation for the "git walker/drawer" project, covering architecture decisions, prior art analysis, and technology recommendations for building an interactive, expandable knowledge map of git and git-annex repositories.
Key additions
architecture-persistence-and-prior-art.md: Comprehensive analysis of expandable knowledge map systems (Maltego, AWS graph-explorer, OpenCTI, Juggl, SpiderFoot, etc.), persistence strategies, and architectural recommendations. Recommends a local daemon + browser SPA model with append-only JSONL observation logs.
ecosystem-and-walker-data-sources.md: Detailed survey of data acquisition sources for git/git-annex discovery, ranking
git-annexbranch inspection,git annex map --json,git ls-remote, datalad-registry, and forge APIs by leverage.semantic-layer-quay-ontosphere-ontologies.md: Evaluation of QUAY ontology and Ontosphere editor for semantic modeling. Concludes QUAY is unsuitable as the primary language but useful as a controlled vocabulary; recommends LinkML for the core model with RDF as a generated export.
generic-graph-explorer-and-datalad-concepts.md: Analysis of datalad-concepts as a generic property-graph model, identifying
Thing,Property,Statement, and reification patterns already present in the schema.pluggable-kg-exploration-and-brainkb.md: Assessment of dump-things-service as the persistence layer and BrainKB's pluggable architecture. Identifies TRAPI/Translator as prior art for pluggable expansion.
tech-graph-visualization-stack.md: Technology recommendations for the rendering layer, recommending Cytoscape.js + fCoSE for compound-node support, incremental layout, and multi-edge handling.
tools-git-native-visualizers.md: Survey of existing git visualization tools, identifying
git annex mapas the only existing tool with repository-level nodes and remote edges.repo-embedded-things-and-collections.md: Design for storing things inside
.git/directories and managing multiple enrichment collections over shared nodes.vocabulary-for-clones-and-remotes.md: Verification that no existing vocabulary covers clone/remote/submodule topology; recommends extending datalad-concepts with LinkML and mapping to ForgeFed.
distribution-modeling-and-repo-identity.md: Analysis of
Distributionas the superclass for repository forms and the identity problem for pure git repositories.README.md: Index and synthesis of all research tracks with provenance notes and caveats about egress-blocked sources.
Notable findings
git annex mapextended with interactivity, persistence, and incremental expansion is achievable in weeks<timestamp>--<agent>--<runid>.jsonl), not CRDTshttps://claude.ai/code/session_01GWoTt2cAfzT6rLU2edwQk9