Commit Graph
114 Commits
Author SHA1 Message Date
Bernhard Jackiewicz 62257fd418 fix(ui): retire a cached explanation when its scope's evidence changed
The explanation cache is keyed by selection and scope shape only, so that
a scope that is still loading finds its explanation. After a re-index of
the same project in the same session, returning to a selection still
showed the explanation of the old graph. Every cached explanation now
keeps the id of the complete evidence it was written from. When the same
selection completes with other evidence, the entry is dropped and the
selection is explained again; while it loads, the cached text stays.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:38:56 +02:00
Bernhard Jackiewicz fdb8142473 fix(ui): let the input limit decide how much evidence a question carries
The input limit only capped token counting. Manual chat always started
from 3,200 characters of evidence, so raising the limit never showed more
of a scope while the capacity note still blamed the model. The first
evidence budget now follows the configured limit (2,048 tokens still give
3,200 characters) and shrinks from there as before.

The output field used step 64 with a minimum of 32, which made the
default 512 and values like 128 or 256 step mismatches and kept the
arrows from reaching 512. It now steps by 32; the input field keeps 64.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:38:27 +02:00
Bernhard Jackiewicz 0f202d781f fix(ui): release the local agent when another tab picks another model
The model choice is stored in the browser and follows storage events, but
only this tab's select released the worker. A model chosen in another tab
changed this tab's model while the old worker stayed loaded: the dialog
called the new model "Loaded", turns recorded the wrong model and the new
model's limits ran on the old worker. The dock now remembers which model
its worker was created for and releases it, and clears the explanation
cache, whenever the chosen model differs.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:37:58 +02:00
Bernhard Jackiewicz ee5d4e8fdb fix(ui): list callers only for the selected symbol and only on list questions
Without a detected subject every caller question counted as one about the
selection, and subjects were found only for camelCase names. "Who calls
get_queryset?" or "Wer ruft as_sql auf?" therefore listed the callers of
the selected JSONBAgg. The question is now read around its verb, so
snake_case and single-capital names are subjects too, and only a subject
that names the selection, one of its roots or "it"/"this" gets the graph
list.

The direction patterns also missed common phrasings and read "Welche
Funktion ruft X auf?" as a callee question. Singular "welche <Nomen> ruft
X auf", "rufen ... auf", "wo wird X aufgerufen", "which/what <noun> call
X" and "where is X called" now ask for callers; a plural noun with "ruft",
"was ruft" and "wird von X aufgerufen" ask for callees. Why, how, what-if
and explain questions go to the model even when they mention callers.

A listed answer now offers "Ask the model", which sends the same question
with the same evidence as a fresh request and replaces the list.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:37:27 +02:00
Bernhard Jackiewicz d53b008db8 fix(ui): keep large Galaxy scopes whole for the local agent
The selection snapshot has a 16,000 character budget. Roots came first
with up to 1,200 characters of documentation each, so in a large scope
the copy cut whole relationship groups, the symbol totals and names. The
answer then said "to 0 symbols", dropped edge types and still called the
list complete. When a side was dropped entirely the reader fell back to
the old path dump, caller questions went to the model and the explanation
key lost its waiting gate.

GalaxyPanel now builds its evidence through galaxyScopeEvidence. Root
documentation stops at the 300 characters the readers use. Counts come
before names, and the names of all groups share an explicit budget, so a
scope fits the snapshot. The reader recognises a Galaxy scope by its
identity and depth, accepts a missing or cut side and reads the snapshot
omissions. The prompt and the listed answer then say that relationships
were left out instead of claiming a complete list.

The capacity note now appears only when the prompt could not name every
symbol the snapshot carried. The snapshot's own bound of 24 names per
group is no longer reported as too large for the model.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:36:48 +02:00
Bernhard Jackiewicz d74fc714d4 fix(ui): count an answer that ends on its last allowed token as finished
The worker inferred "length" whenever the answer used every allowed token.
Transformers.js also hands the end-of-sequence token to the streamer, so an
answer that ended exactly on the limit was reported as cut and the chat
showed "Shortened (token limit)". The worker now remembers the last token
and reports "length" only when it is not an end-of-sequence id of the
model or tokenizer.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 19:36:13 +02:00
Bernhard Jackiewicz db4c441cc9 style(ui): replace long dashes in the browser agent code
The style gate forbids U+2013 and found nine in the reader context notes,
the chat source ranges and their tests. Ranges now use a hyphen.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:59:26 +02:00
Bernhard Jackiewicz 369e9993b5 feat(ui): show the local agent as a robot with a status lamp
The header read "Agent active · Qwen2.5 Coder 0.5B" next to the chat
toggle. It is now a robot icon drawn on the same grid as the chat toggle,
with the status lamp at its corner; a click still opens the agent
configuration. The state and the model name move into the tooltip and
the accessible name, and the model is chosen in the configuration.

The header's agent and chat labels now come from the workspace strings,
which removes the seven hardcoded chrome strings the style gate found in
AtlasChrome.tsx.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:59:03 +02:00
Bernhard Jackiewicz 9e27ae3048 feat(ui): set and keep local agent token limits per model
The agent configuration offered model, automatic explanations and
history only, and the model choice and the automatic flag reset on every
reload.

It now has an input (context) and an output limit for the selected
model, bounded by the model policy: the answer stays within the model's
output ceiling and question plus answer within its browser context.
Limits, the chosen model and "Explain selections automatically" are
stored in this browser under a versioned key and validated on read, as
the view preferences are. Manual chat uses the limits for its prompt
budget and asks the worker for that many output tokens; automatic
explanations keep their short budget but never exceed the limits.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:57:24 +02:00
Bernhard Jackiewicz 0fb9504085 fix(ui): reuse selection explanations and wait for complete scopes
Every return to a selection showed "Explaining selection..." and ran the
model again: there was one explanation slot, and the selection key held
the whole evidence text, so counts and the loading state changed it
while the scope loaded. An explanation could also start on the preview
and describe the state before the expansion.

A Galaxy selection is now identified by project, workspace, the selected
scope, direction, edge types and depth. Finished explanations are kept
per selection (at most 32) and shown again on return without a new
generation; "Explain again" replaces the entry. An explanation starts
only once the scope is complete; until then the card says it is waiting.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:53:20 +02:00
Bernhard Jackiewicz b38ba0827b fix(ui): answer caller and callee questions from the loaded graph
"Who calls JSONBAgg?" got no caller: the model saw one relationship,
decoded greedily without repetition controls and repeated one line until
the 512 token budget ran out.

Caller and callee questions about the current Galaxy selection, in
English or German, are now answered without the model from the loaded
scope: every edge type with its complete count, the related names by
file and an explicit "+N more" beyond the evidence bound, CALLS first.
The answer says when the scope does not follow that direction or is
still loading, instead of reporting no callers.

For everything else:
- manual chat gets a repetition penalty and an n-gram block as well;
  the n-gram block now checks the answer against itself only, because
  counting the prompt forces quoted names and paths off course
- the worker reports why generation ended and the dock marks answers
  cut at the output limit as "Shortened (token limit)"
- a scope larger than the prompt can name shows "<nodes> nodes /
  <edges> edges: too large for the local <model> model; showing <n>"
- history is trimmed oldest first to the input limit, with a note,
  before the request is refused

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:51:01 +02:00
Bernhard Jackiewicz c3fe308763 fix(ui): describe Galaxy selections to the local agent as readable facts
The prompt for a Galaxy selection was a dump of JSON paths: snapshot,
view, generation, rendered sizes and omission paths. Relationship items
were cut to 24 before anyone looked at their direction and then to three
before the budget applied, so "who calls JSONBAgg" reached the model with
one outgoing INHERITS edge and no caller.

GalaxyPanel now classifies every scope edge against the roots first and
publishes incoming and outgoing groups per edge type with complete
counts and the related names by file. The agent prompt states the
selection with kind and file:lines, both sides in words, the scope
(depth, direction, filters) and its completeness. Names are listed until
the budget ends and followed by an explicit "+N more"; the packet
reports how many it could name. Other evidence kinds keep the generic
formatter.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:43:44 +02:00
Bernhard Jackiewicz 2bc10e1616 fix(ui): keep Selection details inside the galaxy stage
The Galaxy workspace gave .atlas-galaxy no position, so the absolutely
positioned Selection details box was placed against the workspace grid
that also holds the chat column. With chat open it covered the chat
input and swallowed clicks on Send. The galaxy stage is now the
containing block; fullscreen keeps its own fixed box.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:35:58 +02:00
Bernhard Jackiewicz 92224c4463 docs(ui): reproduce the review call feedback and plan the fixes
Reproduce every point from the 2 October review call in a real browser
against a Django 5.2.7 index and this repository as control, and record
the plan with measured causes, priorities and open decisions.

The capture script splits each interaction into numbered screenshots
with a visible cursor ring and records canvas identity, camera and the
prompt sent to the browser model, so resets, zoom direction and chat
evidence are measurable rather than described. Only 17 downscaled
images are committed; the full series stays local.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-10-02 18:19:23 +02:00
Martin Vogel 50a6a67b89 Streamline local agent controls and preserve proactive chat
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>
2026-10-01 20:24:06 +02:00
Martin Vogel ea931e7647 feat(ui): refine graph exploration and add local agent configuration
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>
2026-09-28 18:39:48 +02:00
Martin Vogel 4ff6feeab6 feat(ui): add project indexing and editable architecture decisions
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>
2026-09-14 01:39:17 +02:00
Martin Vogel 31cb564981 fix(ui): hide inactive Explorer explanation tray
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>
2026-09-14 00:19:30 +02:00
Martin Vogel d0f148bb5a feat(ui): expand architecture exploration and streamline workspaces
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>
2026-09-13 22:10:10 +02:00
Martin Vogel 79c37032cc feat(ui): add 3D architecture and route exploration
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>
2026-09-10 10:21:35 +02:00
Bernhard Jackiewicz 0b47b7f5ec docs(ui): hand off PR 2068 repairs with browser evidence and known limits
Record the failed first pass, integrated repairs, actual Playwright flows,
source and research decisions, same-port daemon behavior and maintainer entry
points. Include before/after screenshots and the final map recheck after login.
Archive original test logs losslessly with SHA-256 records; retain failed runs
separately instead of presenting them as successful checks.

Disclose unresolved global C lint, parser callsite coordinates, heuristic
architecture roles, manual diff narrowing and outstanding platform validation.

Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
2026-09-10 00:09:12 +02:00
Bernhard Jackiewicz 4372d9fada feat(ui): integrate repository evidence and change analysis on one daemon
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>
2026-09-10 00:08:19 +02:00
Martin Vogel 80f4f41f9b Merge CodeAtlas logging with the exploration frontend
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>
2026-09-09 19:59:56 +02:00
Martin Vogel f9ba36e5c0 feat(ui): replace semantic twin with selected code inspector
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>
2026-09-09 19:48:47 +02:00
Martin Vogel 0cc163eedb fix(ui): restore project switching and expand explorer graph
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-09 07:09:00 +02:00
Martin Vogel a47e0dadb3 feat(ui): graph exploration workspaces with local browser chat
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>
2026-09-09 00:37:21 +02:00
Martin Vogel 0fe968a343 fix(ui): the reader announces a file it cannot show, where it is tested
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>
2026-09-08 01:30:38 +02:00
Martin Vogel 9dc882a82f feat(ui): frontend log file, written by the page and served by the server
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>
2026-09-08 01:26:33 +02:00
Martin Vogel a338c1cae1 fix(ui): the reader asks for full source and pages through long files
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>
2026-09-06 18:10:49 +02:00
Martin Vogel 6928c8a177 fix(ui): read the lean-contract footer lines in CodeAtlasWeb's compact parser
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>
2026-09-06 15:56:53 +02:00
Martin Vogel 453d6cc9bc ci(ui): the CodeAtlasWeb leg is one canonical script, here and in CI
tests/test_venue_parity_contract.sh holds every venue to one harness: a
workflow step may provision, move artifacts, or call a canonical leg
entry, and the product-exercising commands live inside scripts/. The
test-ui job ran npm inline and tripped it on the local ladder.

scripts/ci/test-ui.sh is now the whole leg (install without a browser
download, vitest, the style and promise scans, the portable frozen
acceptance checks, the production build); the job calls it, and running
the same script locally is the same leg. Contract green again
(22 workflows marker-checked, 10 walked).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-05 20:43:13 +02:00
Martin Vogel f490238120 ci(ui): test-ui lane gates CodeAtlasWeb; docs describe the new Atlas
- .github/workflows/_test.yml: a `test-ui` job (ubuntu, node 22) runs
  the frontend's vitest suite, its hardcoded-string and promise scans,
  the portable frozen acceptance checks and a production build, with
  the same browser-download skip the product build uses. The browser
  proofs (tools/smoke-*.mjs) need a running server and Playwright
  browsers and stay a local, manually dispatched venue.
- graph-ui/package.json: `test:acceptance` runs every frozen check except
  the two release-binding files, which tie the recorded release report
  to the commits of the frontend's original repository and cannot pass
  anywhere else (203 checks pass here; the full `npm test` fails exactly
  those four assertions).
- README.md: the Atlas section describes CodeAtlasWeb, credits
  Bernhard Jackiewicz and points at #1964.
- graph-ui/README.md: a maintainers' preface on how this repository
  builds, embeds, proxies and gates the frontend, and what it added;
  his README follows unchanged.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-05 20:41:18 +02:00
Martin VogelandBernhard Jackiewicz 722a2424db docs(ui): CodeAtlasWeb proof artifacts, verbatim
The recorded proof runs of CodeAtlasWeb at 1825f9c850ac794066e02606012508b9d393c6aa:
screenshots, contact sheets, two screen recordings and the JSON reports
of every cycle's smoke run, gate run and audit (227 files, 65 MB).
Bernhard Jackiewicz's work, imported unchanged.

They sit in their own commit on purpose: his frozen acceptance checks
read them (tests/scaffold), his help page points readers at them, and
the maintainer may still decide to keep this history out of the public
tree. Dropping this commit removes exactly the artifacts and nothing
else; the four acceptance checks that bind the report to his
repository's own commits are not part of the CI gate either way.

Co-authored-by: Bernhard Jackiewicz <bj@techport.io>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-05 20:38:59 +02:00
Martin Vogel c8661d7fb1 feat(ui): projects panel keeps indexing, ADR editing and server views in the browser
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>
2026-09-05 20:36:10 +02:00
Martin Vogel 62af5b87ee feat(ui): wire CodeAtlasWeb into the build, the dev-proxy contract and the CSP
Maintainer glue for the imported frontend; no product behaviour of the
UI itself changes.

- Makefile.cbm: `npm ci` runs with PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1.
  The UI's dev dependencies include playwright for its local browser
  proofs, and a plain install would download browsers that no build or
  gate launches.
- graph-ui/vite.config.ts: the dev server listens on 5173 with the two
  literal loopback origins, which is what
  tests/test_ui_dev_proxy_security.sh pins.
- graph-ui/index.html: lang="en"; the catalog is English.
- CSP: the directive string moves to http_server.h as CBM_UI_CSP_VALUE
  so a test can pin it, and connect-src now admits the two loopback
  services the UI may talk to when the reader starts them, the
  local-model sidecar on 127.0.0.1:4141 and the agent-event bridge on
  127.0.0.1:4142. Under connect-src 'self' both fetches were silently
  blocked in the embedded build. Every other host stays forbidden; a
  new httpd test asserts that the only hosts in the policy are those
  two loopback ports.
- scripts/security-ui.sh: two false positives that bit on the imported
  source. The analytics pattern matched the English word "plausible"
  (now plausible.io), and `\s` inside an ERE bracket is a literal
  backslash and 's', which cut every localhost URL at its first 's' and
  then failed the allowlist (now [:space:]).

Verified: httpd suite 64 passed; dev-proxy contract and UI security
audit pass; graph-ui builds and its 2024 vitest tests pass.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-05 20:15:13 +02:00
Martin VogelandBernhard Jackiewicz 67e39d16c0 feat(ui): replace graph-ui with CodeAtlasWeb by Bernhard Jackiewicz
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>
2026-09-05 20:05:43 +02:00
Martin Vogel bda4608651 feat(ui): computed sentences compose natively per locale
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>
2026-08-28 09:17:02 +02:00
Martin Vogel 675b955f23 feat(ui): chrome-string i18n sweep — Symbol, Flows, Overview, WikiPanel
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>
2026-08-28 02:15:11 +02:00
Martin Vogel 762fbe2d55 feat(ui): the Who-can-help card — contacts with evidence on every symbol
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>
2026-08-28 00:56:01 +02:00
Martin Vogel 007a46baf8 feat(ui): content-i18n — the wiki, questions, and Atlas cards speak Chinese
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>
2026-08-28 00:49:57 +02:00
Martin Vogel ce2e406839 feat(ui): observed vs possible — runtime markers in flows and traces
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>
2026-08-27 21:46:24 +02:00
Martin Vogel 11bdc08147 feat(ui): why is this here — per-symbol git history with linked evidence
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>
2026-08-27 18:51:39 +02:00
Martin Vogel 617a4b1495 feat(ui): change impact — who can reach this symbol, and what to retest
/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>
2026-08-27 14:29:51 +02:00
Martin Vogel ed8a45c9d9 feat(ui): the question index — what Atlas answers, honestly
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>
2026-08-27 13:38:20 +02:00
Martin Vogel 9c9e353795 feat(ui): wiki hover previews, tooltip delay setting, tooltip breakdowns
- 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>
2026-08-27 13:30:50 +02:00
Martin Vogel b7f227617a fix(ui): chart-standard compliance sweep — honest axes, real knee, bound bins
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>
2026-08-27 13:14:36 +02:00
Martin Vogel cfebb1b2f9 feat(ui): #wiki=<slug> deep link — wiki entries addressable by URL
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>
2026-08-27 12:26:56 +02:00
Martin Vogel 3f3f1ac486 feat(ui): the metric wiki — single-source entries, WikiPanel, term chips
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>
2026-08-27 12:23:50 +02:00
Martin Vogel e14624d681 feat(ui): semantic zoom, flow-hop confidence, honest caps, tri-state filter
- 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>
2026-08-26 23:01:11 +02:00
Martin Vogel c36a9b81ff feat(ui): galaxy orientation triad — halos, view marker, framed camera
- 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>
2026-08-26 22:34:51 +02:00