ARCLUX Progress — Design Decisions
Why things were built the way they were. See PROGRES.md for the index.2026-08-03 — Update — GitHub infra + features/graph decision
Repo infrastructure added: branch ruleset onmain (PR required, no
direct push — verified by testing it against ourselves), PR + issue
templates (.github/), 10 GitHub Issues created from open items in this
file, release tag v0.1.0-alpha published, CONTRIBUTING.md rewritten
(was stale: said pnpm/turbo, said detectors don’t exist — now says npm,
18/18 detectors, references playground/ testing pattern).
Also removed turbo.json (0 bytes, unused leftover — project uses npm
directly, turbo command never actually run against this repo).
apps/web/features/graph/ decision*: useGraph.ts implemented as a
thin re-export of GraphProvider.tsx’s useGraphContext(). The other 4
files (graphStore.ts, graphEvents.ts, useGraphLayout.ts,
useGraphSelection.ts) are DELIBERATELY left as documentation-only stubs
— GraphProvider.tsx already owns all graph state (transform, positions,
dimensions, selection) via React Context. Do NOT implement a separate
store/hooks layer here; it would create two sources of truth for the same
state. Same class of risk as the packages/ui/graphColor.ts /
theme/graphColors.ts naming collision noted earlier.
2026-08-03 — Update — parseTsx.ts and parseTsConfig.ts confirmed intentionally empty
Verified, not just assumed:packages/parser/typescript/parseTsx.ts and
parseTsConfig.ts will stay empty stubs permanently, not because they’re
“not done yet” but because their functionality already lives elsewhere:
.tsxparsing: handled insideparseTs.tsitself viats.ScriptKind.TSX(checked itsextensionsfield and ScriptKind selection logic directly).- tsconfig.json parsing: handled inside
packages/graph/resolveAliases.ts(moved from packages/indexer/ on 2026-08-13, fix for issue #2 circular dependency indexer<->graph), which reads tsconfig.json / jsconfig.json directly (with comment/trailing-comma stripping) for path-alias resolution.
packages/ui/graphColor.ts vs
theme/graphColors.ts (that one is still an open risk; these two are now
resolved/documented).
2026-08-04 — Update — PLANNED (not yet built): graph node visual impact indicator
[STATUS UPDATE, 2026-08-07]: this plan is now implemented. See the “UPDATE: Graph impact halo — implemented” entry near the bottom of this file for what actually got built and what’s still open (tier thresholds not yet tuned, not yet visually verified). The plan below is kept as-is for historical context — don’t re-implement it.Goal: in the dependency graph view, high-impact nodes (files with many consumers, e.g. logService.ts in a VS Code-scale repo with 430 importers) should be visually distinguishable WITHOUT clicking each node first. Motivated by dogfooding: currently every file node is the same blue regardless of impact, so finding “the important files” requires clicking through hundreds of nodes one at a time. Explicit non-goal, confirmed with user: do NOT change node color by type. graphNodeColors (theme/graphColors.ts) currently colors nodes by GraphNodeType (file=blue, external-package=amber, route=purple, component=teal, hook=red) — that must stay as-is, it’s how users tell node kinds apart. Impact must be a SEPARATE visual signal layered on top (halo ring and/or radius size), not a replacement for type color. Data availability, already confirmed:
- packages/shared/types.ts’s GraphNode interface has NO importedBy/fan-in field built in.
- BUT DependencyGraph.edges (GraphEdge[], with source/target as GraphNode ids) is already sent to the browser in full via GET /api/graph (packages/graph/serializeGraph.ts passes graph.edges through unmodified, no changes needed there).
- Therefore: fan-in count per node can be computed CLIENT-SIDE by
counting how many times each node id appears as an edge’s
targetacross graph.edges. No backend/API changes needed at all — this is a frontend-only feature.
-
In
apps/web/components/graph/GraphProvider.tsx: add auseMemothat, whenevergraphchanges, buildsMap<nodeId, number>by iteratinggraph.edgesand counting occurrences of eachedge.target. Expose this as a newimportCounts: Map<string, number>field onGraphContextValue(add to both the interface and thevalueobject near the bottom of the file, same pattern as the existingpositionsfield). -
In
apps/web/components/graph/GraphCanvas.tsx: at the<GraphNode>render call around line 308-315 (confirmed exact location — inside{graph.nodes.map((node) => { ... return <GraphNode ... /> })}, sibling props toisSelected/isHovered), pullimportCountsfromuseGraphContext()(already imported/used elsewhere in this file presumably — verify) and passimportCount={importCounts.get(node.id) ?? 0}as a new prop. -
In
apps/web/components/graph/GraphNode.tsx: addimportCount: numbertoGraphNodeProps. Define tier thresholds (user’s suggested starting point: High >100, Medium 20-100, Low/normal <20 — these are arbitrary and should be tuned after seeing it rendered against a few real repos of different sizes, e.g. python-demo vs vscode vs next.js, since “100 importers” means very different things in a 50-file repo vs a 15,000-file repo). For High/Medium tiers, render an additional<circle>halo BEHIND the existing node circle (larger radius, no fill, a neutral stroke color like white or amber at low opacity — NOT reusing graphNodeColors, since that would collide with the type-color meaning). Consider also scaling BASE_RADIUS slightly for High-tier nodes. Existing isSelected halo logic ({isSelected && <circle r={radius + 5} ... />}) is a useful reference for the halo-circle pattern already used in this file — don’t duplicate logic, structure the new halo consistently with it. -
Test with
enableMouseInteraction-style verification: run against playground/python-demo first (small, fast iteration) to confirm no crash/visual regression, THEN test against a large real repo (the user has already tested vscode, react, vercel/next.js, microsoft/vscode via the /new flow against localhost — reuse one of those) to confirm the tiering actually looks meaningful at scale, not just correct in theory. Screenshot verification in-browser required before considering this done — typecheck alone is not sufficient evidence per this project’s established verification standard. -
Consider whether label text position (
x={radius + 6}in GraphNode.tsx) needs to account for the halo radius too, or if it’s fine referencing only the inner circle’s radius — check visually. - Consider whether d3-force’s collision detection (GraphCanvas.tsx, look for wherever simulation nodes get a radius/collision force) needs updating so bigger high-impact nodes don’t visually overlap neighboring nodes now that some nodes are bigger than others — this wasn’t investigated yet, flagged as a real risk worth checking, not confirmed either way.
2026-08-05 — Decision — same-package/same-namespace resolution: ONE generic pass, not per-language fixes
Context: Go graph (Kubernetes test) and Java graph (java-demo fixture) both showed near-zero edges despite files clearly being related. Root cause confirmed identical in bothparseGo.ts and parseJava.ts’s own
comments (already documented by whoever wrote them, not discovered fresh
here): both Go and Java let files in the same package/directory reference
each other with ZERO import statements. playground/go-demo’s
cyclic_a.go/cyclic_b.go and playground/java-demo’s Main.java calling
Service/Models/Utils are both confirmed real examples of this. The parser
only extracts what’s literally written, so these relationships never
reach resolvePath.ts as anything to resolve — there’s no import
statement token to feed it in the first place.
Decision: do NOT write a Java-specific fix and a separate Go-specific
fix. This is one general problem — “files that share an implicit scope
need a same-scope dependency pass independent of import statements” —
that will likely also apply to C# (namespace) and Rust (mod) once
those parsers go further than manifest-only (parseCsproj.ts,
parseCargoToml.ts exist; parseCSharp.ts/parseRust.ts are still
empty). Build ONE resolution pass parameterized by “what counts as a
shared scope” per language (directory for Go, package declaration for
Java), not four copies of similar logic.
Not yet built — this is a design decision recorded for whoever picks
this up next, not an implementation. Same class of gap as
resolveRoutes.ts being empty (noted in parseGo.ts’s own comment as a
parallel case).
Referenced but not portable: cloned javaparser/javaparser to
~/research/javaparser for its SymbolSolver/TypeSolver concepts —
it’s a JVM library, not directly adaptable to TypeScript, but worth
reading for how a mature tool structures scope resolution before
designing ARCLUX’s own pass.
2026-08-06 — Decision — issues assigned to a collaborator must also be marked in-file
Context: packages/parser/php/parsePhp.ts and packages/parser/php/parsePhpRoutes.ts sit right next to each other. parsePhpRoutes.ts is assigned to Alitindrawan24 via issue #53. Someone Browse-ing packages/parser/php/ without first checking the GitHub issues list has no way to know parsePhpRoutes.ts is spoken for- it just looks like another empty file waiting to be filled in, identical in appearance to a genuinely unclaimed stub.
Still empty, priority order for next session
packages/indexer/resolveRoutes.ts— unblocks entry-file-awareness for detectUnusedExports/detectOrphanFiles false positivespackages/indexer/resolveExports.ts,resolveComponents.ts,resolveHooks.ts,resolveProviders.ts— same family as resolveRoutesapps/web/components/explorer/Explorer.tsx,DependencyList.tsx— FileDetails.tsx already exists but isn’t wired to anything, this is whyapps/web/lib/api.ts,graph.ts— client fetch helpers, currently pages call fetch() inlinepackages/db/*— persistence layer, 0%, needed before any “history over time” featurepackages/indexer/updateIndex.ts,watchIndex.ts,indexSchema.ts— incremental indexing, depends on packages/incremental being wired in first (not yet done)
2026-08-07 — DependencyList.tsx type confirmed against real API
DependencyList.tsx previously had a local GraphResponse/GraphNodeResponse/GraphEdgeResponse type, written before app/api/graph/route.ts’s actual response shape was checked (its own comment admitted this). Verified: DependencyGraph.nodes/edges from packages/shared/types match exactly. Replaced the local guessed type with the real shared type. Going forward: don’t guess API response shapes in component files — check the actual route.ts handler first, even if it means a short delay before writing the component.2026-08-07 — Next steps priority for future sessions
[STATUS UPDATE, 2026-08-07 later same day]: item (1) below is now implemented — see “UPDATE: Graph impact halo — implemented” near the end of this file. Item (2) is still open.Two concrete next steps identified this session, in suggested order: (1) Graph node visual impact indicator (halo ring for high-fan-in nodes) — full implementation plan already documented in an earlier entry in this file (client-side importCounts via useMemo in GraphProvider.tsx, passed as importCount prop through GraphCanvas.tsx to GraphNode.tsx, rendered as an extra halo circle). Zero code written yet, ready to start from step 1. (2) Remaining inline fetch() calls that duplicate the pattern lib/api.ts’s fetchJson() now centralizes — ImpactSummary.tsx and GlobalSearch.tsx were the two examples that motivated building fetchJson() in the first place but were NOT themselves refactored to use it. Worth a follow-up pass to actually consume the helper there, plus check FileDetails.tsx and app/api/file/route.ts for the same duplicated pattern.
2026-08-07 — Graph impact halo: zoom-gated to avoid clutter
Resolved an open question from the original halo-ring plan: halos only render when zoom level is past a threshold (not always-on), avoiding visual clutter/overlap when zoomed out on dense graphs. Rejected alternatives: always-on halo (overlaps neighboring nodes in dense graphs), thicker border/stroke instead of halo (loses the ‘grows with importance’ visual cue that a halo radius gives). Implementation-wise this means GraphNode.tsx’s halo render needs access to the current transform.scale (already available via useGraphContext()) and a MIN_ZOOM_FOR_HALO constant to gate on.2026-08-07 — UPDATE: Graph impact halo — implemented
The halo-ring plan described in the 2026-08-0X entry above (and listed as a next step in ‘Next steps priority for future sessions’) is now implemented: GraphNode.tsx renders an impact halo circle gated by zoomScale >= MIN_ZOOM_FOR_HALO, importCount computed via useMemo in GraphProvider.tsx from graph.edges, passed through GraphCanvas.tsx. Tier thresholds (High >100, Medium 20-100) are still unverified against real repos — that part of the original plan remains open. Not yet visually verified in-browser as of this entry. If you’re reading the older halo entries above, they’re outdated — this is the current status.2026-08-07 — Simulated stage progress instead of real backend streaming
apps/web/components/graph/AnalyzingProgress.tsx (new) replaces the
static “Analyzing repository…” text in GraphCanvas.tsx’s isLoading
branch. Cycles through 5 stage labels (Cloning/Scanning/Parsing/
Resolving/Building) on a fixed timer + shows an indeterminate progress
bar, with a “taking longer than usual” message after ~17s.
Chose client-only simulated progress over backend SSE streaming:
the correct fix (backend emits real stage events, e.g. via
Server-Sent Events on /api/graph) would need analyzeRepository()‘s
pipeline to become event-emitting instead of a single synchronous
return — a much larger change. This is a stopgap: the labels/timing are
tuned by feel, NOT derived from real pipeline telemetry. Large repos will
sit on the last stage indefinitely since there’s no real signal to
advance further. Documented as such in the component’s own comment so
nobody later mistakes this for actual progress reporting.
Addresses the UX gap noted in status-backlog.md’s large-repo dogfooding
entry (microsoft/TypeScript’s “Indexing failed” was indistinguishable
from vercel/next.js’s “just slow” until it errored, because there was no
feedback at all).
Verified: tsc --noEmit -p apps/web/tsconfig.json clean. NOT yet
visually verified in-browser — pushed near a chat context limit.
Coordination note: git pull before this session started fast-forwarded
in unrelated changes to GraphCanvas.tsx/GraphNode.tsx/GraphProvider.tsx
from another session (fan-in halo indicator feature, matches an earlier
decisions.md plan) — merged cleanly, no conflict with this change since
they touch different parts of the same files.
2026-08-07 — QUICKSTART.md language kept English
QUICKSTART.md initially drafted in Indonesian during a mobile terminal session, per user preference for chat interaction. Decided to keep it English-only to match PROGRES.md and TOOLING.md conventions (all repo docs are English, Indonesian is only used in Claude chat sessions). No translation needed yet since the file is still short (3 sections: workflow, progress logging, pre-check for empty files).2026-08-07 — README Contributors section intentionally removed
The Contributors section (contrib.rocks avatar grid) was intentionally removed from README.md by the user via a direct GitHub browser edit. A later session mistook this for accidental damage (based on the generic ‘Update README.md’ commit message, which matched the pattern of other stray browser-edit branches like GSF-001-patch-1/-2) and restored it — this was wrong and got reverted. If README.md is missing a Contributors section in the future, that’s the current intended state, not a bug to fix.2026-08-07 — Next up: graph LOD (level-of-detail) rendering
[STATUS UPDATE, 2026-08-08]: this plan is now implemented. See “UPDATE: Graph LOD rendering — implemented” below.Status: In Progress Discussed but not yet started: extend the zoomScale-gating pattern already used for the impact halo (GraphNode.tsx, MIN_ZOOM_FOR_HALO) to also gate label/icon visibility at low zoom, reducing DOM/render load when zoomed out on large graphs. Rough plan discussed: very low zoom (<0.5) hides icon+label entirely (node becomes a plain dot), mid zoom (0.5-1) keeps current behavior (label only on select/hover), high zoom (>=1) optionally always shows labels for high-importance nodes. Checked reactflow-ref’s Stress example for a reference pattern first — it’s a performance benchmarking harness, not an LOD implementation (React Flow handles this internally, not via example code), so no direct pattern to borrow. This is a natural extension of existing code (GraphNode.tsx’s opacity={isSelected || isHovered ? …} pattern at the label render, ~line 104), not a new subsystem. Prioritized as step 1 of 3 general performance directions discussed (graph viewer LOD/canvas rendering, pipeline parallelization+caching, new analysis features) — graph viewer was picked first since it’s the most immediately felt by users and doesn’t overlap with collaborator-assigned work (call graph is assigned to xcontcom via issue #50).
2026-08-07 — Cache package design research (packages/cache)
Status: Not Started Not Started2026-08-07 — Cache package design research (packages/cache)
Status: In Progress Researched before implementing packages/cache (CacheProvider.ts, fileCache.ts, graphCache.ts, memoryCache.ts, repositoryCache.ts — all still 8-line stubs, zero consumers currently call any of them, no prior plan existed in progres/ for this). Checked packages/README.md and pipeline.ts/indexer — confirmed nothing references cache yet, this is greenfield design work. Studied ~/dependency-cruiser/src/cache/ as reference (NOT for copying, for architecture ideas — user explicitly wants ARCLUX’s cache to be MORE capable than this reference, not simplified). Key findings:- Two invalidation strategies: MetadataStrategy (git-diff based via watskeburt/getSHA — fast, no file reads, just asks git what changed since last SHA) vs ContentStrategy (per-file checksum comparison — works without git but has to hash every file). MetadataStrategy is the better fit for ARCLUX since packages/git and packages/watcher already do git-diff based watching — reuse that instead of hashing.
- Cache format has an explicit CACHE_FORMAT_VERSION constant (numeric, bumped on breaking changes) so an old cache from a previous ARCLUX version gets safely invalidated instead of returning corrupt/incompatible results.
- Cache dirtiness is scoped precisely: they maintain an explicit list of which CLI options/config changes should 100% invalidate cache vs which only invalidate a subset. ARCLUX equivalent: analyzeRepository({repoUrl, branch, …}) options that affect output (branch, exclude patterns, etc) should be part of the cache key/invalidation check.
- brotli compression at min quality (faster than gzip, still better ratio) used for on-disk cache storage, sync not async (sync is faster in this context and avoids promisifying zlib).
- Design CacheProvider.ts as the orchestrator/interface (equivalent to their Cache class), with a pluggable invalidation strategy (metadata/git-diff-based as primary, matching packages/git’s existing capabilities).
- fileCache.ts, graphCache.ts, repositoryCache.ts likely map to caching ParsedFile results, DependencyGraph results, and Repository (indexed) results respectively at different pipeline stages — needs confirming against packages/engine/pipeline.ts’s actual stage boundaries before finalizing shapes.
- memoryCache.ts — in-memory layer (fast, non-persistent), likely sits in front of an optional on-disk persisted cache, need to decide if disk persistence is in scope for v1 or a later phase.
- Add a CACHE_FORMAT_VERSION-style constant so future cache shape changes don’t silently return corrupt results to old cache format.
- Zero code written yet — this entry is the research/design summary only.
2026-08-08 — UPDATE: Graph LOD rendering — implemented
Status: Done Both steps of the LOD plan are done and visually verified in-browser by the user: step 1 (icon gating below zoomScale 0.5) and step 2 (label gating, same threshold, plus always-show labels for high-importance nodes above zoomScale 1.5). Node radius scaling at low zoom (the optional 3rd idea mentioned in the original plan) was not implemented — current LOD (icon+label gating) was sufficient. Considered done for now; revisit radius scaling later only if a real repo shows it’s still needed.2026-08-08 — Cache design: git-diff strategy needs getCommitHistory.ts first
Status: In Progress Follow-up to the earlier cache research entry: confirmed packages/git/getCommitHistory.ts is still an 8-line stub, and there’s no existing function anywhere that gets the current commit SHA or lists changed files via git diff. simple-git (the library cloneRepository.ts already uses) can do this easily, but the capability itself doesn’t exist yet in ARCLUX. This means the MetadataStrategy-style (git-diff based) cache invalidation approach isn’t a ‘just plug into packages/git’ thing as initially assumed — getCommitHistory.ts (or a new small function) needs to expose at least: current HEAD SHA, and a way to list files changed since a given SHA. Revised plan: implement that git capability first (or as part of the same PR), before or alongside CacheProvider.ts, rather than assuming it’s ready to consume.2026-08-08 — Cache design: shallow clone conflicts with git-diff strategy
Status: In Progress Critical finding: cloneRepository.ts defaults to depth=1 (shallow clone, only the latest commit, no history). This directly conflicts with a MetadataStrategy-style (git-diff based) cache invalidation approach, which needs to diff against a PREVIOUS commit — with only 1 commit present locally, there’s nothing to diff against on a fresh clone. This doesn’t kill the git-diff approach, but changes what it can be used for: it would only work for INCREMENTAL re-analysis of a repo ARCLUX already has a deeper local copy of (e.g. via packages/watcher’s ongoing filesystem watch, which presumably keeps a persistent local clone across multiple analysis runs) — not for a fresh one-shot analyzeRepository() call, which is the common case today (dependency-cruiser assumes it’s running against the user’s own full local repo, a different situation from ARCLUX cloning someone else’s repo fresh each time). Revised understanding: ARCLUX’s cache is more likely to help in two different ways than dependency-cruiser’s single git-diff-driven design:- Content-hash based caching of PARSE results (ContentStrategy-style, not MetadataStrategy) for repeat analysis of the same repo/branch within a short window — doesn’t need git history at all, just file content hashes, works fine with shallow clones.
- A git-diff strategy only makes sense later, once packages/watcher is doing persistent incremental watching (a repo checked out once, kept around, re-diffed on change) — not for the current one-shot clone-analyze-cleanup flow.
2026-08-08 — packages/cache: 3 of 5 files done
Status: In Progress fileCache.ts (content-hash based, per-ParsedFile), repositoryCache.ts (fingerprint-based, per-Repository), graphCache.ts (same fingerprint, per-DependencyGraph) all implemented and typechecked. Both repositoryCache.ts and graphCache.ts share the same fingerprint scheme (computeRepositoryFingerprint in repositoryCache.ts, derived from sorted FileInfo.hash) so they invalidate together. None wired into engine/pipeline.ts yet — that’s a separate step. Remaining: CacheProvider.ts (orchestrator) and memoryCache.ts (unclear if it’s a distinct generic layer or redundant with the three content-hash caches already built — needs more thought).2026-08-09 — ARCHITECTURE_MAP.md added: explicit core/extension boundaries
Status: Done Added ARCHITECTURE_MAP.md defining which packages are CORE (engine, repository, shared — changes need a decisions.md entry first) vs EXTENSION POINTS (parser, detectors, rules, cache — safe to add to without discussion) vs FOUNDATION-NOT-WIRED (watcher, incremental). Also defines where AI/intelligence-layer work (semantic search, RAG, embeddings, agent tooling) should live: a new top-level package consuming ARCLUX’s structural outputs, not woven into core packages. Motivated by onboarding ManSio (5th collaborator), whose own project (mscodebase-intelligence) is a much more elaborate codebase-intelligence system — graph RAG, agentic search, embeddings, LSP bridge, 1000+ tests. Real risk identified: a skilled collaborator coming from an overengineered project has a natural tendency to keep adding intelligence layers to whatever codebase they touch, which could slowly pull ARCLUX away from its current strength (disciplined scope, verified against real repos) toward matching that complexity. This isn’t a judgment on ManSio — his first PR (detectAmbiguousSymbolResolution.ts) was excellent, well-scoped, and followed existing patterns exactly. The boundary is proactive, not reactive to any actual problem yet.2026-08-10 — Vision: TUI (terminal UI) as a third consumer of engine/
Status: Not Started Idea discussed, not started: ARCLUX’s engine/ (analyzeRepository()) already returns pure data (DependencyGraph, Repository) decoupled from any UI — CLI and web dashboard are both just consumers of that same output. A TUI (terminal UI, think lazygit/htop-style keyboard-driven interface) would be a natural third consumer: same engine/, same data, different rendering layer. Candidate library: ink (React for terminal) or blessed, not researched yet. This is long-term vision, not scoped work — no research done, no library chosen, no timeline. Revisit once core detector/parser coverage feels solid enough to justify a new surface.2026-08-10 — External review from ManSio (MSCodeBase) — 4 findings to verify
Status: Not Started Collaborator ManSio reviewed parsePython.ts + scanFiles.ts, found 4 potential issues, NONE verified yet by us: (1) relative imports with leading dots ‘from ..utils import X’ may not resolve correctly if tree-sitter strips the dots before resolvePath.ts sees it — highest priority, likely to produce wrong edges on real repos. (2) parsePython.ts has zero test files, unlike Go/Rust parsers. (3) scanFiles.ts has catch{} blocks that silently drop unreadable files with no warning — same class as the wasm silent-failure gotcha. (4) wasmPath in parsePython.ts is hardcoded to a pnpm-specific node_modules path (.pnpm/tree-sitter-wasms@version/…) — will silently fail under npm/yarn installs. Next session: verify each against parsePython.ts/scanFiles.ts directly before fixing anything, per usual verification standard (cat/grep the actual code, don’t just trust the review).2026-08-11 — Cytoscape.js researched as UI/UX reference for graph rendering
Status: Done Cloned cytoscape.js (open source, unlike Obsidian which was considered but is closed-source) to research graph visualization patterns. Found src/extensions/renderer/canvas/layered-texture-cache.mjs — a sophisticated multi-layer texture caching system with zoom-tier caching, per-frame render budgets (deqCost/deqAvgCost), and priority-queue-based texture refresh. Too complex/different (Canvas-based) to adopt wholesale into ARCLUX’s SVG renderer, but extracted one directly-applicable principle: don’t re-render elements whose own state hasn’t changed. Applied as GraphNode.tsx’s React.memo wrap. Full layered-caching-style system remains a possible future direction if SVG proves insufficient at larger scale (see the earlier canvas-vs-SVG discussion in this file’s history), not pursued now.2026-08-11 — ARCLUX stays structural-truth engine; MSCodeBase-style intelligence becomes an optional consumer layer, not a merge
Status: Not Started Source: GPT roadmap discussion after reviewing ARCLUX architecture map + file sizes, refined further after ManSio suggested keeping the two projects separate. Core decision: do not try to turn ARCLUX into MSCodeBase. ARCLUX stays parse -> index -> graph -> impact -> detect, verifiable and AI-free. Any semantic/RAG/embedding layer becomes packages/intelligence/, sitting ON TOP of Repository + DependencyGraph as a consumer, never inside core. Flow: Repository and DependencyGraph feed packages/intelligence, which then branches into semantic search, context builder, and optional RAG — core stays the single source of truth underneath all three. Phased roadmap agreed: Phase 0 reliability (python edges — already fixed this session, wasmPath pnpm-only portability — still open, silent scan failures in scanFiles.ts — still open, parser test coverage), Phase 1 structural search (graph-aware search: fuzzyScore.ts + buildImportGraph/ExportGraph/CallGraph already exist, extend GlobalSearch to return structural context — imports/exports/consumers/routes — not just filename matches), Phase 2 architecture intelligence (turn the 18 existing detectors into a scored health view — structural integrity / dependency hygiene / layer consistency percentages derived from real detector output, not AI-generated), Phase 3 optional intelligence (packages/intelligence/ — embeddings, semantic search, RAG, agent-facing tools — explicitly deprioritized, not started until Phase 0-2 are solid), Phase 4 external integrations (LSP bridge, MCP/agent interface — deferred, risk of blurring “who is the source of truth” if added too early).2026-08-11 — LAB 1/2/3 — diff, verify, and analyzeLocal/pipeline merge (all on feat/diff-lab1-mvp, NOT pushed yet)
Context: after the ARIES→ARCLUX rename, the temptation was to treat the original ARIES blueprint (11 parsers, 9-layer event engine, full web UI) as a from-scratch spec — a “1 year project” framing. Decision made instead: ARCLUX already has ~80% of the needed machinery built. Cut scope into 3 small LABs that prove the existing pipeline works, rather than building new abstractions speculatively. See roadmap.md’s “Core Principle” — this is that principle applied to process, not just architecture.LAB 1 — arclux diff <refA> <refB> [repoPath]
New files: packages/diff/types.ts, gitDiff.ts, architecturalDiff.ts,
apps/cli/diff.ts. Registered in apps/cli/index.ts.
Honest scope limit, documented in architecturalDiff.ts’s own header:
this does NOT build two separate dependency graphs (one at refA, one at
refB) and diff them — that would require checking out each ref into a
clean state and running the full pipeline twice, not built. What it
DOES do: get changed-files list from git diff --name-status (cheap),
then run existing traceConsumers against the CURRENT working tree for
each changed file that still exists. Answers “what’s affected by files
that changed” using today’s graph, not “did the graph itself differ.”
Upgrading to true dual-graph comparison is a separate, larger task.
Verified working: tested against ARCLUX’s own repo, HEAD~5 HEAD
correctly traced GraphFocusView.tsx/GraphProvider.tsx changes to 9
consumer files (GraphCanvas, GraphViewport, etc).
LAB 2 — arclux verify [path]
New file: apps/cli/verify.ts. Registered in apps/cli/index.ts.
Combines the same 10 detectors doctor.ts runs with packages/rules/ RuleEngine.ts’s runRules(), into one PASS/FAIL verdict (exit code 0/1).
Important finding, confirmed by direct inspection (not assumed): of
13 rule files across nextjs/react/nestjs/express/vite/electron, only
packages/rules/nextjs/requirePage.ts (60 lines) is actually
implemented. The other 12 are copyright-header-only stubs — 8 lines,
zero export statement. verify.ts’s header comment documents this
explicitly so a future session doesn’t assume they’re wired in.
Rule/detectedFrameworks string matching confirmed working correctly
(tested: frameworks checked: nextjs, react matched
appliesToFramework: "nextjs" on requirePage without any mismatch).
Still not built: severity policy is minimal — any detector finding
OR any rule error fails the build; rule warnings are shown but
don’t fail it. Not yet tuned against real usage.
LAB 3 — merge analyzeLocal.ts into pipeline.ts
This one wasn’t a new feature — it closed a duplication gap that
analyzeLocal.ts’s own header comment had already flagged (“once
[pipeline.ts] refactor lands, THIS FILE should be deleted”). Confirmed
via direct read that no parallel-session refactor had actually landed
before doing this (git log showed no such merge to main).
Real bug found and fixed as a side effect of the merge:
analyzeLocal.ts’s ensureParsersRegistered() only registered
parseTs and parsePython — 2 of pipeline.ts’s 7 language parsers.
Every CLI command (diff, verify, doctor, impact, graph,
analyze, config) was silently never parsing JS/JSX/CommonJS/Go/Java
files, only TS and Python, since analyzeLocal.ts was CLI’s only entry
point. Post-merge, all CLI commands go through the same
ensureParsersRegistered() as the web/API remote flow (all 7 parsers +
9 manifest parsers).
Also removed: packages/engine/analyzeRepository.ts — was a
copyright-header-only empty stub, confusingly named almost identically
to the real analyzeRepository() function that lives in pipeline.ts.
API change: analyzeRepository() in pipeline.ts now takes
{ repoUrl } OR { localPath } (throws if both or neither given).
Remote-URL code path (analyzeRemoteRepository) is a direct extraction
of the pre-existing clone→index→graph→cache→cleanup logic — unchanged
behavior, just moved into its own function so the public
analyzeRepository() can route to it or to the new
analyzeLocalPath(). Web app / /api/analyze callers unaffected
(still call with { repoUrl, branch }, same shape as before).
No caching for local-path analysis — deliberate, not an oversight.
repositoryCache.ts/graphCache.ts are keyed by repoUrl+branch, which
doesn’t map to a bare local directory a developer is actively editing.
Documented as a possible future gap if arclux commands feel slow on
large local repos — not ruled out, just not built.
Verified: tsc --noEmit clean (zero errors) after the merge touched 9
files (pipeline.ts + 7 CLI commands + 2 deletions). verify/diff/
doctor all re-tested working post-merge; detector counts shifted
slightly (428→430 in apps/web) as expected from the additional files
now in scope, not a regression.
Current state
All 3 LABs committed tofeat/diff-lab1-mvp, 3 commits
(43013a75, ccd1d5b8, 3926d61f). Not pushed to origin. Branch
is local-only, awaiting review before any push/PR.
Open follow-ups, not done yet (don’t assume these are handled)
- True dual-graph diff (LAB 1’s documented scope limit)
12/13 empty rule stubs (LAB 2) — only requirePage is real— DONE 2026-08-13: all 10 stubs implemented, 13 rules wired into verify.ts/contract.ts; only react/requirePropsTyping remains a documented deferral- Verify’s severity policy is untuned (LAB 2)
- No cache for local-path analysis (LAB 3) — fine for now, revisit if slow on large repos
2026-08-11 — PLANNED (not yet built) — LAB 4/5/6: Stable Core Contract, Engine/API boundary, External consumers
Status: planning only, ZERO code written. This session (that built LAB 1/2/3 — see the entry above) ran near its context limit right as this was being scoped out, so it’s recorded here as a plan for the next session to execute with full context, rather than started and left half-finished. Same discipline as the earlier “graph node visual impact indicator” plan in this file — plan fully, execute in a dedicated pass. Do not skip straight to writing code from this plan. The instruction that came with it, verbatim in spirit: map the current system before adding anything new.LAB 4 — Stable Core Contract
Goal: a single stable shape forAnalysisResult, Graph, Impact,
Issue, Rule that CLI/API/future consumers all depend on, instead of
each command reaching into packages/* internals directly (current
state: e.g. verify.ts imports 10 individual detector functions +
RuleEngine directly — works, but every consumer re-does this
wiring).
LAB 5 — Engine/API boundary
packages/parser, packages/graph,
packages/detectors etc directly. pipeline.ts’s analyzeRepository()
is already close to this for the analyze step (post-LAB-3 merge) — LAB
5 is likely about extending that same pattern to diff/verify/detect,
not introducing a new mechanism.
LAB 6 — External consumers
CLI, IDE, CI, SDK — multiple consumers of the same Engine boundary from LAB 5. Not started, no design yet beyond the name.Ground rule carried over from LAB 1-3, still applies
- Experiment on a branch (
feat/*or similar), never touchmaindirectly. mainstays exactly atorigin/mainuntil a reviewed PR merges — confirmed true as of this entry: LAB 1/2/3 sat onfeat/diff-lab1-mvp, local-only, for the entire time they were being built, and were only pushed (as a branch, not to main) once the user explicitly decided to.- The workflow that worked for LAB 1-3 and should repeat for LAB 4-6: code → test → (optionally) benchmark → if it breaks, reset the branch and try again. Cheap to experiment because main is never at risk.
- Confirm real file state before writing code (grep/cat, not memory of old docs) — this caught the rule-stub gap (LAB 2) and the 2-vs-7 parser bug (LAB 3). Assume more gaps like that exist elsewhere.
2026-08-12 — LAB 4 MVP built: runAllChecks() stable contract
Status: In Progress packages/engine/contract.ts added on feat/diff-lab1-mvp (still local/branch-only, not merged to main). Wraps the 10 detectors + requirePage rule verify.ts already runs into one runAllChecks(repository) call returning normalized Issue[] (source/checkId/severity/message) instead of consumers importing 10 detector functions individually. Hit one signature mismatch during build: runRules() needs a 3rd detectedFrameworks arg, pulled from repository.meta.detectedFrameworks. tsc clean after fix. Not yet wired into verify.ts itself (that’s LAB 5’s job, formalizing CLI -> Engine -> Core boundary) — this session only built the contract, not the migration.2026-08-12 — LAB 4 — External repository validation + Python parser WASM fix
Status: Verified — pushed tofeat/diff-lab1-mvp
LAB 4 Stable Core Contract was validated against an external repository rather
than only ARCLUX itself. The test target was Django, cloned locally at
~/django.
External repository test
Initial ARCLUX analysis of Django:- 3,039 modules indexed
- 3,039 graph nodes
- Initial graph contained only 3 edges
Root cause investigation
Direct inspection confirmed:parsePythonexists and is registered byengine/pipeline.ts.LanguageParsercorrectly exposes Python through.py.resolvePath.tsalready contains Python-specific resolution for:__init__.py- sibling imports
- explicit relative imports
- dotted Python module paths
- Direct invocation of
parsePythoninitially returned zero imports with:
ENOENT: ... tree-sitter-wasms/.../tree-sitter-python.wasm
The WASM file itself was confirmed to exist inside the pnpm store.
require.resolve("tree-sitter-wasms/out/tree-sitter-python.wasm")
also confirmed the correct runtime path.
Fix
packages/parser/python/parsePython.ts contained an incorrect WASM
path calculation.
The path was corrected to resolve the pnpm-installed
tree-sitter-wasms@0.1.13 Python grammar from the actual ARCLUX working
directory.
No parser architecture was redesigned. The fix was isolated to the runtime
WASM path.
Parser verification
Direct Python parser execution against:django/db/models/base.py
successfully returned Python imports with no warnings.
Examples observed included:
collectionsfunctoolsitertoolsasgiref.syncdjangodjango.appsdjango.confdjango.coredjango.core.exceptionsdjango.dbdjango.db.modelsdjango.db.models.constantsdjango.db.models.deletiondjango.db.models.expressionsdjango.db.models.fetch_modesdjango.db.models.fields.compositedjango.db.models.fields.related
Full Django graph verification
After the fix:- 3,039 modules indexed
- 3,039 graph nodes
- 7,734 dependency edges
LAB 4 contract verification
runAllChecks(repository) was also executed against Django.
Observed result:
- modules: 3,039
- issues: 11,452
- errors: 11,452
- warnings: 0
- passed: false
- unusedExports: 7,788
- orphanFiles: 2,453
- ambiguousSymbolResolution: 522
- largeModules: 327
- sharedModules: 225
- circularDependency: 104
- deadCode: 24
- duplicateModules: 9
Important engineering finding
The first failed Django analysis was not treated as a successful test. The unusually low graph edge count triggered investigation. The workflow was:- Analyze external repository.
- Detect suspicious result.
- Inspect parser registration.
- Inspect Python parser.
- Test parser directly on a real Django file.
- Trace failure to missing WASM path.
- Confirm WASM package actually exists.
- Fix only the path resolution.
- Re-run the full repository analysis.
- Confirm graph increased from 3 edges to 7,734 edges.
- Run the stable check contract against the external repository.
Commit
5e3748a7 fix: resolve Python tree-sitter wasm path
Branch:
feat/diff-lab1-mvp
Remote branch was confirmed synchronized with the local HEAD after push.
Current conclusion
LAB 4 is not merely a type/interface exercise. The stable Engine contract was exercised against a real, large, external Python repository and the test uncovered and fixed an actual runtime integration bug in the existing Python parser.2026-08-13 — Platform layer scaffold added
docs/log-today-progress-v2[STATUS UPDATE, 2026-08-13]: this plan is now implemented. See “UPDATE: Platform layer scaffold added — implemented — implemented” below.
[STATUS UPDATE, 2026-08-13]: this plan is now implemented. See “UPDATE: Platform layer scaffold added — implemented — implemented” below.
[STATUS UPDATE, 2026-08-13]: this plan is now implemented. See “UPDATE: Platform layer scaffold added — implemented” below.ARCLUX.main Status: Not Started Added scaffold-only folder structure for a new additive platform layer (runtime, services, scheduler, environment, workspace, terminal, storage, networking, security, system, diagnostics, editor, language, orchestration) plus matching apps/cli commands and apps/web API routes. Files are Apache-header-only stubs, no logic yet. Per ARCHITECTURE_MAP.md, this consumes existing core (engine/graph/impact/parser) rather than duplicating it — implementation to follow incrementally. docs/log-today-progress-v2
2026-08-13 — UPDATE: Platform layer scaffold added — implemented — implemented
Status: Done Rencana awal baru sebagian ke-scaffold: package runtime, services, scheduler, environment, workspace, terminal, storage, networking, security, system, diagnostics, editor, language, orchestration sudah ada, tapi ketinggalan packages/kernel, packages/semantic-diff, packages/notifications, packages/package-manager, dan CLI command health.ts + package.ts. Semua sudah ditambahkan (stub-only). Juga ditambahkan docs-site/map/map-packages-platform.mdx section Blueprint Integration yang memetakan alur editor dan semantic-diff pipeline ke file platform layer beserta dependency ke engine yang sudah ada. Masih open: belum ada logic diisi, murni struktur file + dokumentasi peta dependency.2026-08-13 — UPDATE: Platform layer scaffold added — implemented — implemented
Status: Done Rencana awal baru sebagian ke-scaffold: package runtime, services, scheduler, environment, workspace, terminal, storage, networking, security, system, diagnostics, editor, language, orchestration sudah ada, tapi ketinggalan packages/kernel, packages/semantic-diff, packages/notifications, packages/package-manager, dan CLI command health.ts + package.ts. Semua sudah ditambahkan (stub-only). Juga ditambahkan docs-site/map/map-packages-platform.mdx section Blueprint Integration yang memetakan alur editor dan semantic-diff pipeline ke file platform layer beserta dependency ke engine yang sudah ada. Masih open: belum ada logic diisi, murni struktur file + dokumentasi peta dependency.2026-08-13 — UPDATE: Platform layer scaffold added — implemented
Rencana awal (lihat entry “Platform layer scaffold added” di atas) baru sebagian ke-scaffold saat pertama kali dibuat: packageruntime,
services, scheduler, environment, workspace, terminal,
storage, networking, security, system, diagnostics,
editor, language, orchestration sudah ada, tapi ketinggalan:
packages/kernel/ (Kernel, ProcessTable, SignalBus, ServiceRegistry,
introspection), packages/semantic-diff/ (SemanticDiff, SymbolDiff,
AstDiff, DependencyDiff, DiffRenderer), packages/notifications/
(NotificationManager, Notification, NotificationChannel),
packages/package-manager/ (PackageManager, PackageManifest,
PackageResolver, PackageState), dan CLI command health.ts +
package.ts.
Semua sudah ditambahkan (stub-only, sama seperti scaffold awal — Apache
header + comment placeholder, belum ada logic). Juga ditambahkan
docs-site/map/map-packages-platform.mdx section “Blueprint
Integration” yang memetakan setiap tahap alur editor (developer ketik →
incremental analysis → diagnostics → impact → notification) dan
semantic-diff pipeline (text→symbol→AST→dependency→impact→
architectural) ke file platform layer yang sesuai, plus dependency-nya
ke packages/engine/, packages/parser/, packages/diff/,
packages/impact/ yang sudah ada. Masih open: belum ada satupun logic
diisi, ini murni struktur file + dokumentasi peta dependency.
ARCLUX.main