Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
765e385
chore: sync main into develop after v0.1.6 release
explosivebit May 5, 2026
e07304f
chore: sync main into develop after v0.1.6 (#21)
explosivebit May 5, 2026
487cc84
feat(a11y): add +error.svelte SvelteKit error boundary (FR-001)
explosivebit May 5, 2026
51edb7a
fix(a11y): role=img on graph SVGs replaces role=application (FR-002)
explosivebit May 5, 2026
bc7c4f5
fix(a11y): prefers-reduced-motion shared helper + ForceView guard (FR…
explosivebit May 5, 2026
b52b020
fix(a11y): nested button replaces li role=button in InsightsRail (FR-…
explosivebit May 5, 2026
ec3405a
fix(layout): narrow-viewport .has-panel grid alignment (FR-005)
explosivebit May 5, 2026
202803c
docs(changelog): F1 frontend recovery + a11y entries under [Unreleased]
explosivebit May 5, 2026
b0c8f1d
docs(forgeplan): PRD-003 F1 artifact
explosivebit May 5, 2026
d939f88
feat(a11y): PRD-003 F1 — frontend recovery + a11y (5 HIGH audit fixes…
explosivebit May 5, 2026
94d724d
docs(forgeplan): EVID-010 closes PRD-003, activate both
explosivebit May 5, 2026
7aaa04d
docs(forgeplan): EVID-010 closes PRD-003 + activate (#23)
explosivebit May 5, 2026
bd33416
feat(graph): shared highlight state + edgeClass helper
explosivebit May 5, 2026
d135c82
fix(graph): ForceView selection ring excludes status dot + hover-edge…
explosivebit May 5, 2026
91e40ce
fix(graph): hover-edge pattern across Tree/Radial/Matrix/Lanes (FR-005)
explosivebit May 5, 2026
b0d5e7b
docs(changelog): F2-graph entries + ignore L4 test screenshots
explosivebit May 5, 2026
ac2289f
docs(forgeplan): PRD-004 F2-graph artifact
explosivebit May 5, 2026
de0ba61
feat(graph): PRD-004 F2 — selection sans status-dot + hover-edge high…
explosivebit May 5, 2026
36203df
docs(forgeplan): EVID-011 closes PRD-004 (F2-graph), activate both
explosivebit May 5, 2026
7e311a7
docs(forgeplan): EVID-011 closes PRD-004 + activate (#25)
explosivebit May 5, 2026
391deca
feat(graph): cluster lib + adaptive ring radius
explosivebit May 5, 2026
14cb457
feat(graph): forceClusterRepel custom d3 force
explosivebit May 5, 2026
df497b1
fix(graph): RadialView adaptive ring radius + collision sweep
explosivebit May 5, 2026
847b493
feat(graph): ForceView hierarchy clustering
explosivebit May 5, 2026
8772856
docs(changelog): F4-clustering entries under [Unreleased]
explosivebit May 5, 2026
fd656a6
docs(forgeplan): PRD-005 + RFC-004 artifacts (F4-clustering)
explosivebit May 5, 2026
54f666a
refactor(graph): RadialView geometry-first layout
explosivebit May 5, 2026
e3e0602
docs(forgeplan): RFC-004 + CHANGELOG match geometry-first layout
explosivebit May 5, 2026
8407f49
chore(graph): drop dead MIN_NODE_SPACING export
explosivebit May 5, 2026
9f52bb8
docs(forgeplan): EVID-012 closes PRD-005 (F4 RadialView geometry)
explosivebit May 5, 2026
dbdc76b
docs(forgeplan): activate PRD-005 + RFC-004 (R_eff=1.00)
explosivebit May 5, 2026
319fa27
chore(dev): add dev:playground mode pointing at playground/
fedorovvvv May 5, 2026
d2e9f25
chore: untrack .forgeplan/session.yaml (auto-touched by forgeplan)
fedorovvvv May 5, 2026
2b8083e
feat(cli): show Forgeplan/Web ASCII banner on `start`
fedorovvvv May 5, 2026
2796fdf
feat(graph): fade unrelated nodes on hover by graph distance
fedorovvvv May 5, 2026
bf842a7
feat(graph): PRD-005 F4 — hierarchy clustering + RadialView overlap f…
explosivebit May 5, 2026
3478fa4
docs(playground): seed Forgeplan workspace with 123 Helios artifacts
fedorovvvv May 5, 2026
216a8d9
feat(graph): extend hover-fade to selected node with softer dim
fedorovvvv May 5, 2026
74f44df
chore: pnpm
fedorovvvv May 5, 2026
75b8f3b
docs(readme): document dev:playground mode and seeded workspace
fedorovvvv May 5, 2026
2e6300a
fix(health): render blind_spots as objects, not [object Object]
fedorovvvv May 5, 2026
cf049df
feat(graph): sync hover highlight with artifact-id mentions in side p…
fedorovvvv May 5, 2026
16ab811
docs(changelog): playground mode, banner, NodeRef, hover-fade extensions
fedorovvvv May 5, 2026
8fd3f53
fix(graph): F5 audit cleanup — CRITICAL+HIGH+MEDIUM fixes
explosivebit May 5, 2026
06574d3
fix(deps): F5 LOW — bump cookie ≥ 0.7.0 (CVE-2024-47764)
explosivebit May 5, 2026
f062b38
test(graph): F5 — vitest unit-tests for cluster geometry + radii regr…
explosivebit May 5, 2026
b9bb6b6
Merge remote-tracking branch 'origin/develop' into feature/playground
fedorovvvv May 5, 2026
6dac7b4
fix(graph): F5 audit cleanup — CRITICAL+HIGH+MEDIUM fixes + tests (#28)
explosivebit May 5, 2026
7adf4c2
Merge remote-tracking branch 'origin/develop' into feature/playground
fedorovvvv May 5, 2026
a3f19e3
Feature/playground (#27)
fedorovvvv May 5, 2026
3d364ba
feat(graph): F6 — collapse/drill-down for large RadialView clusters
explosivebit May 5, 2026
1efd7e1
feat(graph): F6 — ArrowKey navigation between nodes (RadialView + For…
explosivebit May 5, 2026
955d69a
docs(forgeplan): EVID-013 closes F5 audit-cleanup acceptance
explosivebit May 5, 2026
3af3fba
Merge remote-tracking branch 'origin/develop' into feature/ux-followu…
explosivebit May 5, 2026
1f5cdad
feat(graph): F6 UX follow-ups — cluster collapse + ArrowKey nav + EVI…
explosivebit May 5, 2026
b323f75
chore(release): bump version to 0.1.7
explosivebit May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions .claude/rules/23-bin-zero-deps.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import.

- `node:*` modules (`node:fs`, `node:child_process`, `node:path`,
`node:url`, `node:os`, `node:crypto`, `node:util`).
- Relative imports of sibling `.mjs` files **inside `bin/`** (e.g.
`import { … } from "./banner.mjs"`). These are first-party code that
ships in the `bin/` folder of the published tarball; they introduce
no third-party resolution at `npx` time. Each such sibling file is
itself bound by this rule (zero `node_modules/` imports, `node:*`-only).
- Synchronous I/O (`mkdirSync`, `cpSync`, …) — the script is short and
CLI-bound; readability beats event-loop nicety.

Expand Down Expand Up @@ -52,9 +57,23 @@ shipping a pre-built artifact.
## Verification

```bash
# bin must not reference anything outside node:* in its imports
grep -E "^import |^const .*= require\\(" bin/forgeplan-web.mjs | \
grep -v "from 'node:" | grep -v "require('node:" || echo "OK: no third-party deps"
# bin/* must only import node:* modules or relative sibling .mjs files.
# Allowed: from 'node:fs', from "./banner.mjs", from "../bin/x.mjs"
# Forbidden: from 'chalk', from 'figlet', from any bare specifier.
# Also handles multi-line `import { … } from "node:fs";` because we match
# the `from "…"` line itself, regardless of where the `import` keyword sits.
for f in bin/*.mjs; do
hits=$(grep -E "(from|require\()\s*['\"]" "$f" \
| grep -vE "(from|require\()\s*['\"]node:" \
| grep -vE "(from|require\()\s*['\"]\\.{1,2}/" || true)
if [ -z "$hits" ]; then
echo "OK ($f): no third-party deps"
else
echo "FAIL ($f): third-party imports found:"
echo "$hits"
exit 1
fi
done

# root package must not declare runtime deps
node -e "const p=require('./package.json'); if (p.dependencies && Object.keys(p.dependencies).length) { console.error('FAIL: runtime deps present', p.dependencies); process.exit(1)} else { console.log('OK: no runtime deps') }"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
created: 2026-05-05
depth: tactical
id: EVID-010
kind: evidence
links:
- target: PRD-003
relation: informs
status: active
title: 'PRD-003 F1 acceptance: 5 FR live-verified via Playwright DOM eval + visual screenshots'
updated: 2026-05-05
---

# EVID-010: PRD-003 F1 acceptance — live browser verification

| Field | Value |
| ----------- | --------------------------------------------------------------- |
| Status | Draft |
| Created | 2026-05-05 |
| Valid Until | 2026-08-05 (3 months — re-verify if any view component changes) |
| Target | PRD-003 |

## Structured Fields

verdict: supports
congruence_level: 3
evidence_type: test

## Measurement

PR #22 (`feature/frontend-recovery-a11y-f1 -> develop`, merge commit `d939f88`)
shipped 5 HIGH a11y/recovery fixes. This evidence pack verifies each FR
against the **live dev server** (`npm run dev` in `template/`) via the
MCP Playwright integration: DOM-property assertions on the rendered
output plus visual screenshots saved to repo root for review.

Layers:

- **Code review** — already done by frontend-developer sub-agents during
T-1..T-5 implementation; svelte-check passed 0/0.
- **CI smoke matrix** — PR #22 ubuntu/macos/windows × Node 22 all green.
- **Live DOM verification** — this layer; goes beyond compile-time and
catches integration issues invisible to type-checking.

### Layer A — DOM assertions (live, http://localhost:5174)

| FR | Assertion | Result |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| FR-001 | `navigate /nonexistent` renders `.error-shell` with `404` status, `Not Found` message, link `/` | ✅ all 4 properties present |
| FR-002 | All 5 graph views (Force/Tree/Radial/Matrix/Lanes) expose `role="img"` + descriptive aria-label | ✅ 5/5 verified by switching views and re-querying SVG |
| FR-003 | `aside.rail .row.clickable` uses nested `<button class="row-trigger">`; 0 `<li role="button">`, 0 `tabindex="0"` | ✅ 20 row-triggers, 0 of either old pattern |
| FR-004 | `motionDuration(300)` returns 0 when `matchMedia('(prefers-reduced-motion: reduce)').matches` | ✅ logic verified (MCP doesn't expose CDP setEmulatedMedia, override-based) |
| FR-005 | At viewport 1024×900 with `.has-panel`: grid is 3-col (`200px Xpx 380px`), `aside.rail` is `display:none`, panel left == filters+canvas widths | ✅ measured `200px 444px 380px`, rail hidden, panel left=640px |

### Layer B — visual screenshots (repo root, for PR review)

| File | What it shows |
| ------------------------- | ---------------------------------------------------------------- |
| `f1-main-1600.png` | Lanes view at 1600×900 with InsightsRail (Recent, 20 entries) |
| `f1-narrow-grid-1024.png` | `.has-panel` at 1024×900 — 3 cols filter/canvas/panel, no orphan |
| `f1-error-svelte-404.png` | `+error.svelte` rendered — large 404, message, "GO HOME" link |

## Result

| ID | Target | Measured | Verdict |
| ---- | ------------------------------------------------------------ | -------------------------------------------------------- | ------- |
| SC-1 | `template/src/routes/+error.svelte` exists + custom UI | file present, screenshot shows custom layout | ✅ pass |
| SC-2 | All 5 graph views use `role="img"`, not `role="application"` | 5/5 confirmed in DOM after view-switch | ✅ pass |
| SC-3 | `InsightsRail.svelte` has no `svelte-ignore` directive | 0 `[role="button"]`, 0 `tabindex="0"`, 0 svelte-ignore | ✅ pass |
| SC-4 | `prefers-reduced-motion` guards present in graph views | `motionDuration` evaluates to 0 under emulated reduce | ✅ pass |
| SC-5 | `.has-panel` layout aligned at viewport < 1100 px | 1024px viewport shows 3-col grid, panel correctly placed | ✅ pass |
| SC-6 | Smoke matrix 3/3 OS × Node 22 green | PR #22 ubuntu/macos/windows all green | ✅ pass |
| SC-7 | `svelte-check` 0 errors / 0 warnings | repeated 0/0 after each FR commit | ✅ pass |

## Interpretation

PRD-003 acceptance fully met across all 7 SC and 4 NFR. Seven commits
landed on `develop` via PR #22. None of the 5 fixes broke build, smoke,
or type-check. Live DOM verification confirms the changes are not just
present in source but actually rendered with the expected attributes —
the gap that source-only review would miss (e.g. a SvelteKit hydration
glitch could strip an attribute and ts-check would never know).

The `+error.svelte` boundary is now the user-visible failure mode for
any future load/render error in `/api/*` polling — replacing the generic
SvelteKit fallback. Together with PRD-002's security cap, this PR
hardens the _resilience_ surface: errors don't crash, hostile env
doesn't inject, narrow viewports don't break.

## Congruence Level Justification

**CL3 (same-context, penalty 0.0)**:

- DOM assertions ran against the **same** SvelteKit dev server users
point their browser at (`http://localhost:5174`). No proxy, no
emulator. `npm run dev` uses identical source files as `npm run build`
produces — only HMR differs.
- Visual screenshots are at the actual viewport sizes the audit flagged
(1024×900 for the narrow-grid bug, 1600×900 for the desktop hero
layout). Pixel-level evidence of correct layout.
- `evidence_type: test` because every assertion is binary pass/fail
with deterministic queries (CSS selector + getAttribute / classList /
getComputedStyle), not a numeric measurement.

## Related Artifacts

| Artifact | Relation | Notes |
| -------- | --------- | --------------------------------------------------------- |
| PRD-003 | informs | Closes all 7 SC and 4 NFR. Activates PRD-003 (R_eff > 0). |
| EVID-009 | builds-on | PRD-002 acceptance pattern (3-layer source/compiled/CI). |
| PRD-001 | informs | Methodology baseline (audit→PRD→evidence→activate flow). |


Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
created: 2026-05-05
depth: tactical
id: EVID-011
kind: evidence
links:
- target: PRD-004
relation: informs
status: active
title: 'PRD-004 F2-graph acceptance: 5 FRs across 5 views via shared highlight lib, smoke + svelte-check 0/0'
updated: 2026-05-05
---

# EVID-011: PRD-004 F2-graph acceptance

| Field | Value |
|-------------|----------------------------------------------------------------------|
| Status | Draft |
| Created | 2026-05-05 |
| Valid Until | 2026-08-05 |
| Target | PRD-004 |

## Structured Fields

verdict: supports
congruence_level: 3
evidence_type: test

## Measurement

PR #24 (`feature/frontend-graph-ux-f2 -> develop`) shipped UX
improvements requested by the user during F1 live walkthrough. This
evidence pack verifies the changes via three layers: source code review,
type/svelte-check, and CI smoke matrix.

### Layer A — source verification

| FR | Surface | Verification |
|--------|----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
| FR-001 | `ForceView`/`Tree`/`Radial`/`Lanes` `<rect class="selection-ring">` | Each view has a dedicated ring sized to card content (`node.w × node.h`). Status dot stays outside the selection bbox. Matrix is N/A (no encircled card). |
| FR-002 | All 5 views | `onmouseenter={() => setHovered(node.id)}` + `onmouseleave={clearHovered}` on each node `<g>` (also `onfocus`/`onblur` for keyboard a11y). |
| FR-003 | All 5 views | Edge primitives carry `class={edgeClass(from, to, highlight.hoveredId)}` returning `'edge-active'` when hovered matches an endpoint. |
| FR-004 | All 5 views | Same `edgeClass` returns `'edge-dim'` when `hoveredId != null` and unrelated. |
| FR-005 | Tree/Radial/Matrix/Lanes | Same pattern as ForceView; per-view edge primitive (`<path>` for Tree/Radial/Lanes, cell `<rect>` for Matrix). |
| FR-006 | All 5 views | `clearHovered()` on `mouseleave`/`blur` resets `highlight.hoveredId = null`; `edgeClass` then returns `''`. |
| FR-007 | `CHANGELOG.md` `[Unreleased]` `### Changed` | Two bullets covering FR-001 + FR-002..FR-006. References PRD-004. |

### Layer B — shared lib

`template/src/widgets/dependency-graph/lib/highlight.svelte.ts`:

- `export const highlight = $state<{ hoveredId: string | null }>({ hoveredId: null })` — runed shared state.
- `setHovered(id)` / `clearHovered()` — mutator helpers.
- `edgeClass(from, to, hovered)` — pure classifier returning `''` / `'edge-active'` / `'edge-dim'`.

Single source of truth for the hover state means hovering a node in any
view re-renders only the link class strings, not the whole graph
(R-2 mitigation per PRD).

### Layer C — type/build/CI

- `cd template && npx svelte-check` → **0 errors / 0 warnings**.
- `npm run clean && npm run smoke` (locally) → **PASS**.
- PR #24 CI matrix → **3/3 OS green** (ubuntu/macos/windows × Node 22).

## Result

| ID | Target | Verdict |
|-------|-------------------------------------------------------------------|---------|
| SC-1 | Selected node `<rect>` does NOT overlap status dot | ✅ pass |
| SC-2 | Hover on node adds `edge-active` to connected edges | ✅ pass |
| SC-3 | Hover dims unrelated edges to opacity 0.25 | ✅ pass |
| SC-4 | Hover affordance present on all 5 graph views | ✅ pass |
| SC-5 | Smoke matrix 3/3 OS × Node 22 green | ✅ pass |
| SC-6 | `svelte-check` 0/0 | ✅ pass |
| SC-7 | No new runtime deps | ✅ pass |

## Interpretation

PRD-004 acceptance fully met across all 7 SC and 4 NFR. Five commits
landed via PR #24, each independently revertable. The hover affordance
makes the graph «readable at a glance» on workspaces with many edges —
a deliberate response to user feedback during F1 testing.

The F2-graph PR sets a pattern that PRD-005 (F4-clustering) will build
on: shared `lib/*.svelte.ts` modules with runed state are the right home
for cross-view interaction state.

## Congruence Level Justification

**CL3 (same-context, penalty 0.0)**:

- Code review against the actual files merged into `develop` (no proxy).
- Compile + type verification via `svelte-check` against the same
tsconfig the production build uses.
- CI smoke against the actual matrix the release workflow gates on.
- `evidence_type: test` because every assertion is binary pass/fail
with deterministic queries (file existence, regex match, exit code).

## Related Artifacts

| Artifact | Relation | Notes |
|----------|-----------|------------------------------------------------------------------|
| PRD-004 | informs | Closes all 7 SC and 4 NFR. |
| PRD-003 | builds-on | F1 a11y + recovery; same pattern of shared `.svelte.ts` lib. |
| EVID-010 | builds-on | Live-verification template (deferred to a separate post-merge run for F2). |


Loading
Loading