Separate agent configuration from chat visibility, keep chat compact, and
resume selection explanations after manual questions. Restore project
conversations locally for 24 hours with bounded storage and clear history.
Move daemon configuration into System and report persisted index metadata
and live watcher registration alongside its configuration control.
Validated with 303 focused frontend tests, TypeScript/Vite production build,
160 native watcher/HTTP tests, regression checks, and local browser checks.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add focused galaxy tracing, edge filters, organic cluster layouts and cached
graph exploration with compact architecture and impact summaries.
Make the browser-local agent explain the current selection proactively,
and add a Config panel with persisted daemon overrides, shared browser
preferences and a reference for external configuration inputs.
Validation: 182 focused frontend tests and TypeScript passed. Reused the
recorded production build and 485 passing native checks on unchanged
source. The pre-existing capped-layout loading-note test failure remains
documented separately; the full local CI ladder was waived.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add a local folder picker with indexing progress and editable per-project ADRs. Keep the current file or literal code selection in browser chat context, and make Explorer graph and hierarchy focus follow that scope.
Simplify workspace navigation and keep experimental agent observability behind its feature flag.
Validation: focused frontend tests, TypeScript, production build, and browser checks including indexing and opening a new project. Full local CI omitted as requested.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Remove the folded tool strip and splitter from the default Explorer layout. Keep contextual tools available when explicitly opened and preserve the reader when folding them.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add source-backed system structure and behavior analysis, container service maps, and graph navigation with directional edge styling. Refine repository metadata, graph focus resets, and local browser chat with a resizable Explorer graph.
Move index coverage into its own workspace and diagnostic history into System; simplify Explorer actions and header controls.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add spatial overview, dependency, entry-point and route views with source drilldown, directed relationship evidence, bounded graph expansion, and a plan view. Keep existing architecture details available and expose coverage and display limits.
Validation: frontend build, 2503 unit tests, 203 acceptance tests, and browser workflows on indexed dependency-cruiser, LikeC4 and CBM passed. Broader Linux and Windows native checks still have recorded failures.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add source-backed repository navigation, selection context and a shared change
analysis workspace for symbols, working-tree changes and Git comparisons.
Persist agent events and project logs through the existing daemon with SQLite
schema 4, bounded polling, retention and restart-safe deduplication.
Repair compact RPC decoding, path-search races, source pagination and identity,
large map responses, live error propagation and explicit local diagnosis flows.
Include the real-repository browser runners and focused regression coverage.
Validation: 2473 frontend tests, 203 acceptance checks, production build,
style/promise gates, 5 reference-boundary checks and 7 local hook tests pass.
The complete repository-map browser flow also passes after daemon restart.
Global C lint and cross-platform release validation remain open and are
recorded in the accompanying handoff report.
Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
Retain the existing frontend diagnostics and unreadable-file reporting
alongside the selected-code inspector, graph navigation, and local chat.
Keep both process telemetry and log-tail models, and preserve the HTTP
logging tests alongside the browser model download policy checks.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Show indexed file symbols and source-linked facts in a compact inspector.
Pin context while exploring, attach literal selections to browser-local chat,
and navigate directly between code and the graph.
Preserve flow roots during source navigation, keep the inspector above chat,
and replace legacy sidecar controls with browser model settings.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Add Explore, Galaxy, Architecture, Agents, and System workspaces with a
persistent, resizable local chat dock. Attach exact source selections and
graph context, render Markdown, and offer pinned opt-in browser models.
Keep the galaxy visible below chat and focused on the active file or code
selection. Restore hierarchy root selection, resolve projection identities
by symbol, and retain loaded search matches after an empty index reply.
Expose process measurement units, embed browser runtime MJS/WASM assets,
and constrain binary-audit exceptions to reviewed dependency strings.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The previous commit announced the reader's failure from App.tsx's catch,
with no test on that wiring, and its message claimed the case had been
seen live. It had not: the live run covered console lines, the start
line, the failures of an unknown project through the seam (/rpc tool
errors and a /api 404), the ring mirror and the panel. This commit puts
the announcement where the failure is decided, in loadFileDocument, for
both of its shapes (no module node in the index; the server's
"(source not available)" placeholder for a file gone from disk), and
pins it with two reader tests: both shapes reach the observer as
source "reader", level warn, and a file that loads announces nothing.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The browser console was the only place Atlas wrote to, and it dies with
the tab: a reader who saw "get_code_snippet returned no source" had
nothing to hand over, and an agent looking into it had nothing to read.
The page now keeps a second copy of everything it logs, on the server,
next to the daemon's own records.
Server (src/ui/http_server.c):
- POST /api/ui-log takes {page, session, entries[]} and appends one JSON
line per entry to <cache_dir>/logs/ui.log (received, page, session,
seq, ts, level, source, message, detail, stack, url, line, col).
Bounds: 64 KiB per post, 100 entries per post, 4096 characters per
text field cut on a UTF-8 boundary and marked, the level normalised to
a known word, every string escaped again on the way out. The file
rotates once to ui.log.1 at CBM_UI_LOG_ROTATE_BYTES (default 5 MiB).
Warnings and errors are mirrored into the ring GET /api/logs serves,
so both sides of one failure sit in one list; the chatter stays in
the file. The reply names the file and says whether it could be
written.
- GET /api/ui-log?lines=N tails the file (default 200, at most 1000,
from the last 256 KiB) and names the file and its rotated
predecessor; `partial` says when the lines do not start at the top.
- cbm_ui_log_file_path() is the one place the path is built.
Frontend (graph-ui):
- app/ui-log.ts: a bounded buffer (200 entries, oldest dropped first
and the loss named at the head of the next batch), batched posts
(25 entries or 1.5 s), backoff on a refused post, never writes to the
console itself. app/ui-log-transport.ts posts with fetch, and with a
beacon when the page is going away.
- app/ui-log-install.ts wraps the five console methods (they still
print; the copy is taken after), listens to window error and
unhandledrejection, and flushes on pagehide. Installed first in
main.tsx, so nothing can fail before the copy exists.
- provider/error-observer.ts is the seam for failures the panels catch
and show as a sentence: the /rpc transport and the /api client
announce every failed call there before throwing, with a level that
tells a tool the server does not offer (info) from a tool that said
no (warn) from a broken or unreachable server (error). The reader
announces a file the index does not know.
- The projects panel shows the tail under "This server" as sentences,
names the file to attach to a report, and reloads it with the rest.
- README (both) and INVENTAR.md name the file and the routes.
Tests: three httpd cases (JSON lines and tail, refused bodies and
dropped entries, rotation); vitest for the buffer, the wiring in jsdom,
the transport, the seam through both clients, the API method, the model
and the panel. Verified live against a real project: the reader's
failure appears in the file and in the panel within two seconds.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Second drift of the lean output contract (#1597), found on a real
project: get_code_snippet now outlines any container of 200 lines or
more unless source_mode is "full", and full source arrives in pages of
at most 500 lines with next_start_line and original_end_line. The
reader loaded a file through its module node with the old request, so
on main every file longer than 200 lines came back as an outline with
no source ("get_code_snippet returned no source for ..."), and even with
"full" only the first 500 lines would have shown.
- rpc-client: getCodeSnippet sends source_mode "full" and takes an
optional page window (start_line, max_lines); the provider's symbol
snippets benefit the same way.
- rpc-schemas: the page fields are read (source_mode, source_truncated,
next_start_line, original_end_line), optional so recorded answers from
before the contract keep parsing.
- file-source: pages are fetched one after the other and joined; a page
that does not arrive ends the loading and the note under the source
names the missing lines. The single-window behaviour of servers
before the contract is unchanged. The server's "(source not
available)" placeholder, sent when the indexed file is no longer on
disk where the index expects it, is refused as source and reported as
what it is.
Tests: two pages joined with the calls the server needs, a missing page
named, the placeholder refused; the client's request pinned. Reader and
provider suites 149 passed; full suite green with both gates.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
On current main the compact text form of query_graph and search_graph
carries footer lines the frontend's parser did not know (returned,
total_relation, truncated; search_mode now follows the head):
rows: 2 (cols: n.name n.file_path)
loadConfig src/config.ts
isProduction src/config.ts
returned: 2
total: 2
total_relation: eq
has_more: false
truncated: false
The parser refused the first unknown line, and since the reader resolves
a file's module symbol through query_graph before it asks for the
source, no file could be opened on main ("query_graph: Antwort war nicht
lesbar: unbekannte Fusszeile einer kompakten Antwort: returned: 1").
Both parsers now read the new keys as fields (returned, totalRelation,
hasMore, truncated) rather than skipping them, so a capped answer stays
nameable, and refuse anything else as before. Two tests carry main's
exact output for the fixture. The recorded fixtures from before the
contract keep passing, as the fields are optional.
Verified against the embedded build on the re-stacked branch: files
open, the twin answers, search returns hits; provider tests 126 passed.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The previous graph-ui let a reader index a repository from the browser,
delete an index, edit the project's decision record and look at the
server's log and processes. CodeAtlasWeb is read-only by design and sent
all of that to the command line, which for a fresh install means a page
that says "nothing indexed" with no way forward. This adds a [p]rojects
panel (alt+p) in Bernhard's idiom so nothing users have today is cut.
What it does, and how it says so:
- Projects on this server: the list from list_projects over /rpc, with
root path and counts when the server sends them ("counts not sent"
when it does not), open (reloads with ?project=), check
(GET /api/project-health as a sentence), reindex (POST /api/index with
the root the server reported; no root, no button, a sentence instead)
and delete (DELETE /api/project) as a two-step question in place.
- Index a repository: path and name (suggested from the last segment),
a folder browser over GET /api/browse, the index button only once
both fields are there, the acknowledgement of POST /api/index, and
the job table from GET /api/index-status polled every 1.5 s while a
job runs; the list reloads exactly when a job finishes.
- Decision record: GET/POST /api/adr for the open project, with
"busy" told apart from "refused" by the 423 status.
- This server: GET /api/processes and the GET /api/logs tail.
Every block names its source route, a number the server did not send is
shown as not sent, and no control is on the screen that cannot act
(his promise-scan and style gates stay green; the panel is in the
hardcoded-string scan's file list).
Wiring: AtlasApi grows the routes above with a method-aware request;
the catalog gets a projects section, the menu entry, the help panel
entry and the help wording about what this window can ask the server
to do; WIRED_MENU_SHORTCUTS gains 'p' and the help table picks it up
structurally; the no-project status line points at alt+p.
index.html gets an inline SVG favicon so a fresh page stops logging a
404 for /favicon.ico.
Verified: 2073 vitest tests pass (49 new: model readers, the API
routes with a recording fetch, the panel in jsdom); in the embedded
build against a live server, POST /api/index returned 202, the job
table was polled to "done" and the list refreshed with the new project.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Imports the CodeAtlasWeb companion frontend verbatim from
BernhardJackiewicz/CodeAtlasWeb at commit
1825f9c850ac794066e02606012508b9d393c6aa as the new graph-ui and removes
the previous React frontend.
This is Bernhard Jackiewicz's work, contributed with his agreement and
squashed here from his development history (41 commits, cycles W0
through W15). The maintainer only relocates it: every product decision,
line of code and test below graph-ui/ is his. The seven galaxy files
that originate in this repository's previous graph-ui, and the pinned
3D libraries, are listed in graph-ui/THIRD_PARTY.md.
What it is: a local reading IDE on the CBM read surface. A read-only
Monaco source reader, a semantic twin that follows the caret, entry,
bug-hunt, change-scope and flow reading modes, deterministic
source-cited explanations with an optional local-model wording pass
(llama-server sidecar, off unless the reader starts one; no model or
binary ships), a persistent galaxy with focus following in both
directions, a live-agent overlay fed by a loopback bridge, explicit
air-gap, provenance and index-limit messaging, and an offline
acceptance and browser verification harness.
It consumes POST /rpc (the read-only tool allowlist), GET /api/layout,
and the atlas routes /api/tree, /api/trace, /api/flows and /api/flow,
plus the real ingest_traces store for observed calls; all of these are
on feat/atlas-r1 (#1860), which this change stacks on.
Not imported: CLAUDE.md (an agent-instruction file, which stays
local-only in this repository), and the recorded proof artifacts under
graph-ui/verification/, which follow in a separate commit so they can
be reviewed and dropped on their own.
Build wiring, the dev-proxy port contract, the CSP allowance for the
sidecar and bridge ports, and the control surfaces the previous
frontend had (project indexing, ADR editor, logs) follow in separate
maintainer commits.
Design and tracking: #1964.
Co-authored-by: Bernhard Jackiewicz <bj@techport.io>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The takeaway/cost sentences, the trigger tree's guard grammar, and the
first-read content each build their own full sentence in the viewer's
language from shared parameters — never word substitution into an
English frame (zh restructures where zh reads better: 只要 X 运行,它就
一定运行——调用点上没有任何条件). The load-bearing discipline holds
bilingually: the complexity takeaway's simple/exceed claims are parsed
back out of BOTH languages and asserted against the same CPLX_BINS
metadata, so a bin edit moves every locale or fails loudly. The
server's region-why templates get parsed and recomposed client-side
with byte-identical English reproduction and verbatim pass-through for
unknown shapes. English output is byte-identical everywhere, guarded
by the untouched en expectations.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The remaining hardcoded chrome moves into the catalog (en byte-
preserved, zh added with identical interpolation shapes): symbol
section titles and states, the flows trace bar and journey chrome, the
overview slots/findings/regions/reference blocks, and the wiki
fallback. Metric vocabulary stays English-canonical; computed sentences
(Dashboard takeaways, TriggerTree guard assembly, firstread content)
are flagged for their own pass rather than half-translated.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Names as plain text with their evidence line (commits to this file this
year, repo-wide breadth, last touched when the retained commits prove
it), honest empty and no-history states, en+zh from birth. The
question index stops claiming the view is planned: F13's remaining gap
is the region-level rollup — and, as ever, never a leaderboard.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Wiki entries and question families carry co-located zh content
(sentence, why, caps, not-covered, hints, gaps — 24 entries, 18
questions) with per-field English fallback; metric terms stay
English-canonical with a zh gloss in the panel header, so the zh UI
keeps teaching the tokens users meet in code and issues. The impact,
history, and observed surfaces move their remaining hardcoded strings
into the message catalog (en+zh, same interpolation shapes). zh
sentences are budget-tested at ≤45 characters like their English
counterparts at ≤30 words; the refusal rationale of the four
refused-metric pages is translated at full bluntness.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Trace hops and flow steps that actually fired render '▶ observed ×N'
with the run label and date; a fully-observed trace says so in one
line, and the footer states the honesty rule: unmarked hops are
possible, not dead — runs only cover what they exercised. The wiki
gains the observed entry (first-class, with its caps), and F5's gap
narrows to what is still missing (automatic capture).
Live-smoke fix on the C side: resolve_store hands handlers a
query-only connection, so ingest writes silently no-op'd against real
project stores — ingest_traces now takes the dedicated read-write
connection (open_store_for_write, né open_adr_store_for_write), whose
open also creates the observed tables in pre-existing databases.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The most-deferred developer question in the literature gets its evidence
surface: /api/symbol-history runs a bounded git log -L over the symbol's
line range (follows renames, 12 commits, on demand — one subprocess,
never automatic), and file history now carries the forge base URL
(git@/ssh remotes normalized to https). The symbol page grows a 'Why is
this here?' card: trace button, commit list with hashes and #123 refs
linked to the forge, honest empty/capped states, and a footnote that
titles are not fetched. The existing recent-commits list linkifies
through the same component. F7's gap narrows accordingly.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
/api/impact answers the strongest-demand developer question in the
information-needs literature: if I change this, what breaks and what
must I retest. A reverse CALLS adjacency joins the flow cache (built in
the same edge pass); a distance-labelled BFS from any symbol reports
reachers per hop, a region rollup, and — separately — the test
functions that reach the symbol, nearest first: the tests to run.
Honest caps (depth 10, 50k visits, both flagged) and a stated basis:
static CALLS only, so every count is a floor.
The symbol page grows an 'If you change this' card: headline sentence,
cumulative hop tiers, region chips, run-these-first test list with an
explicit warning when no test reaches the symbol, and the floor
footnote. Question family F3 flips to answered (7/8/3); the
blast-radius wiki entry now names its caps.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Twenty years of developer-information-needs research reduces to 18
question families; the Overview now opens with Atlas's scorecard against
them: 6 answered, 9 partial, 3 not yet — counts derived, never
hard-coded. Each row names the question, where to look, and for partial
and missing families exactly what's missing; rows with a home navigate
there. Status is glyph + word, color redundant. Chrome en+zh; the
question text itself awaits the content-i18n pass.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- every metric chip previews its wiki entry on dwell: term, tier, the
single-source sentence, click-for-more; pointer can enter the card,
Esc dismisses just the card, no auto-timeout; portaled + clamped
- tooltip delay is a display setting (150-800ms, persisted), read at
hover-start so changes apply to the next hover
- galaxy tooltips show the arithmetic already in the scene payload:
fan-in/out and lines per node; symbols, files, cohesion per region
- test setup restores jsdom's localStorage under Node's experimental
global, so storage persistence tests assert for real instead of
silently no-opping
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Evidence-audit fixes across the dashboard and friends:
- sparklines plot real time (indexed_at), break across gaps, and carry a
printed first→last delta; no line under 4 snapshots (a 2-point line is
a trend claim)
- the hero head cut is a Kneedle-style knee (unit square, smoothed, max
distance below the chord, clamped 3..15) — largest-relative-drop
collapsed to 'top 1' on power-law data
- hero rows show both axes (commits and complexity), caption carries the
denominator; 'Complexity mix' (né distribution) prints per-bin counts,
N, and its flag threshold
- Modules bars state their reference; Overview regions get a cohesion
strip with median tick; the Control gauge prints its cut-points with
non-color glyphs
- complexity bins live in one module (lib/complexity.ts); a test binds
the takeaway sentence's claims to the bin labels so they cannot drift
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The doc_url target: the hash opens the entry's panel over whatever view
the rest of the URL names, and hashchange keeps it live.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Every number Atlas shows gets a wiki entry: one tooltip-sized sentence,
why it matters, how it is computed with named caps, what it deliberately
does not cover, where it appears, and its paired counter-metric. Four
'refused' entries document metrics Atlas will not show (Maintainability
Index, Halstead, coverage gates, quality grades) and why.
Entries live in one typed module (word-budget-enforced by test) and are
rendered by a docked WikiPanel with a navigation stack — terms inside the
panel are chips too, so concepts link without nested tooltips. Dotted-
underline MetricChips wire the Dashboard and Symbol surfaces in; section
headings ship en+zh.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- Semantic zoom on the region scene: zooming INTO a region blob
opens it, guarded by the anti-annoyance set from the research
round - user wheel input within 600 ms only (programmatic fly-tos
never trigger), approach direction only, 1.5 s grace so backing
out doesn't bounce back in. The HUD hint says so.
- Flow steps carry the resolver confidence of their parent edge;
hops under 75% show a small warm approx marker with the number -
a misresolved hop now looks different from a certain one.
- Dashboard lists declare their caps honestly: 'top N of M' where
the payload names the population (callables, churned files),
plain 'top N' where it doesn't - never an invented M.
- FilterPanel All|None buttons became one tri-state master checkbox
(checked / unchecked / mixed dash, aria-checked, keyboard-native).
vitest 71/71, tsc clean, C suites 96/0, lint green.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- Landmark halos: the top-12 hubs carry a soft additive corona
(single Points layer, one sprite) so panning always has stable
anchors - the CodeCity landmark idea, kept sparse on purpose.
- Minimap gains a view marker: a ring at the camera's orbit target,
reported throttled (200 ms, movement-gated) from inside the
canvas, projected with the same bounds as the region dots.
- Constrained camera: orbit min/max distance follow the scene's
actual radius instead of fixed constants; scenes auto-frame on
load (the fixed default camera landed inside larger clouds) while
deep-linked nodes keep their focus fly-to.
- Minimap moved above the Prompt button (they overlapped).
vitest 71/71 incl. minimapProject bounds tests.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The Atlas program added seven tabs of hardcoded English on top of an
en/zh UI. This translates the shell (tab labels, switcher strings)
so zh users get a coherent frame; panel-content i18n is a dedicated
follow-up pass, recorded.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- The Why view now sits directly under the symbol header, before the
flat caller/callee columns: the condition question is the primary
answer, the lists are reference (question-first IA per the
research synthesis).
- Cross-seam dots on connection rows invert into noise on utilities
called from everywhere; past half the rows the list now says it
once in the header ('79 of 83 cross regions') instead of dotting
nearly every row.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- /api/why entries carry candidates from the CALLS edge; the tree
shows a '1 of N targets' diamond chip on dynamic dispatch -
genuine resolver uncertainty made visible.
- Decision-table pivot on the trigger tree (>=3 guarded callers):
rows = callers, columns = distinct conditions, cells = when /
unless / none. The experimentally-winning format for
condition-combination lookup (Huysmans 2011).
- /api/flow&guards=1: flow-detail steps gain per-step guard chips,
computed from each step's parent call site - journeys read as
'then X, when ok && *cursor' instead of bare arrows.
- Number formatting unified to en-US (mixed browser locales
rendered 1.053 next to 1,053).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The condition→action abstraction (Pennington 1987: the mental model
with the highest error rates, and the one code text serves worst),
served on demand. Design per the research synthesis: thin caller-only
spine (thin slicing), closed question menu, guard text ON the edge
in words (information scent), glyphs always paired with text
(Reacher's 22% missed-icon failures), complexity-gated (Scanlan),
declared elision, both directions (Green), honest footer.
- /api/why?id|qn&dir=up|down: callers (or callees) with the
SYNTACTIC guard chain around each call site — enclosing
if/else/switch-case/loop/ternary/catch conditions, outermost
first, else-arm negation detected — extracted by parsing the few
caller files live with the embedded tree-sitter grammars from the
call-site line the CALLS edges already carry. Zero indexing cost;
works on every existing index. Per-request parse cache; 2 MB file
cap; unparseable sources reported as guards_unavailable, never
guessed.
- /api/trace&guards=1: A-to-B paths gain per-hop guard chips -
'reachable in 5 hops' becomes 'reachable when ...' (the exact gap
Reacher's users hit: they hand-derived conditionals).
- Symbol page: 'When does this run?' tree - guard chips (amber
unless / blue when), loop marker, unguarded honestly labeled,
per-caller upward expansion, direction toggle, single-line answer
when every call site is unguarded, footer stating guards are
syntactic and dispatch/events are invisible.
- Trace results in Flows render the same chips per hop.
Tests: nested-if chain outermost-first + else-arm negation + loop
flag + downward direction + callsite helper on a real temp-dir C
file (C); /api/why route wiring; formatGuard/chain + the
complexity gate (vitest). Trap fixed en route: the extension table
keys WITH the dot ('.c'), not 'c'.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The header's backdrop-filter creates a CSS stacking context, which
paints its entire subtree as ONE atomic layer. A child's z-index
cannot escape it: the body-level dim overlay (z-20) therefore sat
above the dropdown panel (z-30-inside-the-header) and dimmed the
panel together with the page - uniform darkening, zero separation.
Both the backdrop and the panel now portal to <body>, where the
paint order is explicit: backdrop z-20 dims everything, panel z-30
floats above it, anchored to the trigger button's rect (closes on
resize; Esc and backdrop-click close; click-away listener dropped -
the backdrop IS the click-away surface).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Review feedback: the dropdown blended into the page and offered no
way to search among many projects.
- Type-to-filter input at the top, autofocused on open; Enter picks
the first match, Esc closes.
- The panel is now a real layer: solid surface, stronger border,
deep shadow, and a viewport backdrop that dims the page. The
backdrop is portaled to <body> because the header's
backdrop-filter makes it the containing block for fixed children,
which silently clamped the first version to the header bar.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Review feedback: the top bar mixed project-scoped tabs with
app-level ones and left the project tabs visible-but-dead until a
project was chosen elsewhere.
- The project is now a first-class switcher directly after the
wordmark (dropdown: all indexed projects + a manage-and-index
row); picking one lands on its Overview.
- Project tabs (Overview...Dashboard) render only when a project is
selected - a control that cannot work does not render, same trust
rule as everywhere else. A divider separates context from views.
- App-level destinations sit quietly on the right: search (only
with a project) and Control. The redundant right-side project
chip is gone; the Projects tab is reachable through the switcher
and remains the no-project landing page.
UI-only change; vitest 66/66, tsc clean.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
GET /api/handout renders a self-contained, print-friendly HTML
document that explains the project to a newcomer: the region map
(cohesion as words, hubs), boundary spanners with a why-you-care
line, the main entry-to-effect journeys, and the churn x complexity
table. Linked from the Overview header ('Handout').
Honesty properties, tested: every graph-derived string is
HTML-escaped; no host paths leak into the artifact; caps are
declared inline ('20 of 33 regions shown', '10 of 60 journeys');
a project with no readable git history says so instead of skipping
silently; every fact is deterministic - the header states that no
model wrote any of it.
Exposing the same document as an MCP resource is recorded as a
follow-up (touches the MCP protocol surface; wants its own review).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
/api/blast buckets a file list by region (names included, 200-file
cap declared as truncated, every file accounted for: bucketed +
unmapped == files). The Changes tab feeds it the impacted symbols'
files (falling back to raw changed files) and renders the review
signal git cannot compute: 'your change reaches N files across K
regions' with per-region chips - disambiguated with the same
hub-suffix rule the galaxy uses, so two 'tests' communities don't
render as twins - and a seam warning at K>=3 suggesting a split or
citing the region names in the prompt.
Tests: blast bucketing + accounting + empty-input refusal (C),
/api/blast route wiring.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The D6 trust sweep: every capped or scoped surface says what it hid
and what it means.
- Symbol connections: when the page cuts the list, the hidden
remainder is grouped BY FILE ('src/auth/session.c x 12') next to
the Show-more button - a bare '+N more' hides the answer to 'who
calls this' on exactly the nodes where it matters.
- Connection rows carry the neighbor's region; a row whose edge
crosses an architectural seam gets a quiet accent dot.
- The Data-flows panel no longer renders on projects with no
DATA_FLOWS edges at all: a section that can only ever say 'none'
is noise, not honesty.
- /api/bridges: boundary spanners ranked by DISTINCT foreign regions
a node calls into (cross-call count as tiebreak), test files
excluded and inbound direction ignored - orchestrators like main
and cbm_daemon_host_run surface; utility sinks and test harnesses
(which the naive both-directions metric ranked first) do not.
Overview shows the top 5 with a why-you-care line.
- Staleness banner was built and then REMOVED: no server signal
means 'files changed since indexing' today, and detect_changes
(a git-base diff) would have shown the wrong number. Recorded as
a follow-up instead of shipped with wrong semantics.
Tests: bridges need >=2 foreign regions (a dense gamma community
mirrors the beta fixture pattern), overflow tail accounts for
exactly what the page cut, per-row regions + data-flow presence
flag, /api/bridges route wiring.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- The galaxy stays mounted once visited: hidden with invisible (never
display:none, which zeroes a canvas), WebGL context and layout kept,
frameloop paused via the scene's active prop - switching tabs no
longer drops and refetches the whole 3D scene.
- Flows list merges journeys by entry point: one row per entry
(richest first) with an 'x N journeys from <entry> - show all'
expander, so ten main() walks stop drowning the list.
- Modules gains a map|bars toggle (persisted): the same children as a
sorted horizontal-bar list - region-colored, symbol counts - for
when proportion matters less than ranking.
- Filter chips strike through when disabled (excluded, not missing).
- One-time in-place hint on the region scene; dismissing persists,
leaving without dismissing does not.
Tests: groupFlowsByEntry ordering/merge (vitest); suite green with
the keep-mounted change.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The D4 orientation package, mechanics adapted from the two reference
UIs studied in the screened snapshots:
- Search scent propagates up the hierarchy: a 'find a symbol' input on
the region sidebar lights matching regions in the 3D scene, pins hit
counts on the region rows and the minimap, and reports the total
with an outside-regions remainder. Served by /api/scent - a
case-insensitive name match bucketed per region via the cached
file->region map (File/Folder nodes excluded so a file never
double-counts its own symbols; sub-2-char queries refused).
- 2D minimap panel (bottom right, collapsible): every region as a dot
on a fixed top-down projection, sized by sqrt(members), colored by
region, open region ringed, scent counts above the dots, click to
open, and a Home button that fits the current scene.
- Region hover card: members/files, cohesion as a word (tightly /
moderately / loosely connected) with the score, and the hub.
- Node tooltip on graphite tokens (last pre-D1 hardcoded surface) and
in/out call degree - layout nodes now carry out_calls, which the
degree pass already computed and discarded.
- Honest scope note in the region detail panel: '+N callers outside
this region' whenever the full-graph in-degree exceeds the loaded
window.
Tests: scent bucketing + LIKE-escape refusal (C), /api/scent route
wiring, minimap projection + cohesion words (vitest), region-list
queries disambiguated from minimap titles.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The two questions the research says developers ask most and tooling
answers worst: why is this code the way it is (rationale via change
history and ownership), and does A reach B (LaToza reachability,
asked ~9x/day). Plus the user-requested data-flow lens.
- /api/trace: shortest A-to-B path over CALLS or DATA_FLOWS (BFS,
depth-capped at 12), endpoints by id or qualified name; the flow
cache gains a DATA_FLOWS CSR beside the CALLS one.
- Symbol bundle: file_history (recent commits, commits/year, top
author share from a bounded git log at metrics time, cached and
honest - available:false when no history was parsed) and
data_in/data_out with the stored edge detail.
- Flows tab: trace bar with symbol pickers and a control/data
toggle; the result path is clickable hop by hop.
- Symbol tab: 'Recent changes to this file' and 'Data flows'
panels with honest empty states.
- Tests: trace reachability both modes + endpoint errors, symbol
bundle data-flow/history shape, /api/trace route wiring, and a
fetchTrace client test.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The metrics screens now answer questions instead of displaying data
(dashboard canon: Few, Grafana, CodeScene — the Field Guide carries the
citations):
Overview
- Four opinionated slots on top: Needs attention (knee-point count over
churn×complexity), Direction (deltas vs the previous index), Riskiest
area (named, with its why), and an untoned Trust strip (index stamp,
missed files, unmapped symbols).
- Surprising couplings become finding sentences with evidence, an
'inspect' next click, and an 'intended' dismissal whose key buckets by
order of magnitude — a dismissed finding resurfaces only when it grows
10x (regression re-alert, CodeScene's goals idea in one line of code).
- Hubs, entry points and boundaries demote to a collapsed Reference
disclosure; inventory facts move to an untoned footer.
Dashboard
- Hero: the churn×complexity list with the knee-point head highlighted, a
cost sentence ('N files — X% of the codebase, Y% of all commits this
year'), raw commits shown per row, mute-as-intended dispositions, and
rows opening the file's folder in Modules.
- Quality signals (resolution, dead, tested, documented) keep tones and
trends; the complexity histogram now states its takeaway and names the
tail; averages and equal-weight inventory cards are gone — facts live
in the footer.
- Metrics payload gains raw commits per risky entry, churn totals and the
distinct-file count to make the cost sentence computable.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Visual language, rebuilt on the researched rules (Primer/Carbon/Material/
Radix/Linear; details in the Atlas Field Guide):
- Graphite surfaces with fixed step jobs (#0D0F12 canvas → #293038
selected) replace the saturated navy; elevation is a lighter surface
step, not a shadow; hover/selection are surface washes.
- One accent (sky #4FA8E0) reserved for interactivity; semantic
good/warn/crit separate; the type floor is 12px (labels), body 13-14px,
system font stacks (sans UI, mono identifiers only — zero vendored
bytes), tabular numerals, radius 6px.
- Region colors move to the Okabe-Ito color-blind-safe palette, assigned
server-side to the ten largest regions with a neutral tail — the code
graph is the only colorful thing on screen.
Trust repairs, because every wrong-looking item costs belief in every
right one:
- builtins filtered out of hub lists (a 'len' hub reads as a bug);
- a product-code lens hides test regions by default everywhere regions
appear, one honest toggle away ('18 test regions hidden — show');
- flow labels carry file context when the bare name is ambiguous
('datastructures.__init__ → …' instead of '__init__ → …').
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The lazy-schema fix was ineffective: the UI never sent include_details,
so list_projects returned names only, every card lacked totals, and the
>1M-node skip compared against undefined — each Projects visit still ran
a ~30 s kernel schema scan, and revisits stacked uncancelled sweeps that
kept the store busy (the felt slowness).
Now: list_projects(include_details:true) carries totals and indexed_at;
the enrichment loop is generation-guarded (unmount or refresh abandons
it), schemas are cached for the session, auto-fetch is capped at 20
projects of ≤200k nodes, and larger stores keep a card with totals and
no chips. After a Projects visit the daemon log shows only sub-second
requests.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Opening the /rpc allowlist revealed a pre-existing cost: the Projects tab
awaited get_graph_schema for EVERY project before rendering anything, and
a schema scan walks every node and edge — ~30 s on a 13 GB kernel index.
(Before #1663's fix those calls failed instantly, which is why the page
ever felt fast.)
list_projects already reports per-project node/edge totals, so the page
now renders from those immediately; per-label chips arrive lazily, one
schema at a time, patching each card as it lands — and projects above a
million nodes skip the schema scan entirely, keeping a card with totals
and no chips rather than burning half a minute of server time per load.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The numbers view of a project, with the code behind every number one
click away and no composite health score — the cards are the score:
- /api/metrics (cached per project+indexed_at): complexity and function-
length histograms and top lists straight from pass_complexity's stored
cyclomatic/cognitive/lines numbers, edge certainty (CALLS vs
CALL_REFERENCE vs USAGE), dead-code candidates (same exclusions as the
galaxy classifier), TESTS linkage, SIMILAR_TO duplication, missed
files, documented-exports coverage.
- Per-file churn from one bounded git log pass (1 year, 10k commits, the
pass_githistory bounds) computed at metrics time — ZERO cost added to
indexing — plus churn × complexity, the classic where-the-bugs-live
list.
- A per-index history sidecar (JSONL in the cache dir, one snapshot per
indexed_at) feeds trend sparklines across reindexes.
- Dashboard tab: stat cards with warn tones, histograms, top lists
linking to symbol pages; churn honestly marked unavailable when the
project has no readable git history.
The wired-routes test covers /api/metrics; the ui suite pins totals,
certainty, histogram completeness and history presence on a fixture.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The human side of the Atlas program:
- Overview: the first read of a project — header numbers, region cards
with provenance and cohesion, hubs by fan-in, entry points, surprising
couplings with enumerated reasons, suggested questions with a why, and
the cross-package boundary table. Assembled client-side from the
read-only /rpc surface (get_architecture format:json) + the regions
payload; no new server code.
- Modules: a squarified treemap (in-house, no new dependency) of any
folder via /api/tree — sized by symbols, colored by dominant region,
hatched where the indexer missed files, breadcrumbed drill-down, file
panel listing symbols via search_graph.
- Symbol: one page per node via /api/symbol — docstring, flags, region,
editor/GitHub links, code on demand, callers/callees with true totals
and per-type confidence badges (resolved / reference / unproven),
tests, co-change partners, near-clones.
- Flows: the /api/flows journeys grouped across/within regions, each a
clickable indented call tree with truncation stated, mermaid export.
- Changes: detect_changes on the working tree grouped by risk, blast
radius citable into the prompt in one click.
- ⌘K: symbols (search_graph) + code text (search_code) in one box.
- Prompt composer: a basket of cited symbols/regions/flows/questions that
renders a prompt naming exact qualified names, file:line ranges and the
MCP calls that reproduce the context — the bridge back to the agent.
Routing carries every screen in the URL (tab, project, path, sym, flow,
node, region) so all of it deep-links. Fixed en route: the /api/flow
route pattern '/api/flow?*' never matched (req->path has no query
string) — now exact, pinned by a wired-routes test that distinguishes a
matched route's 400 from the static handler's 404.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>