feat(web): F11 — body preview + decision impact drill-down (PRD-006/RFC-005)#36
Merged
Conversation
Implements PRD-006 / RFC-005. Two coupled UX improvements that turn @forgeplan/web from a "table of contents" into a "decision viewer". Body preview: - ArtifactPanel adds "+ Show body / − Hide body" toggle revealing the full markdown body of the selected artifact inline. - New `widgets/artifact-panel/lib/markdown-renderer.ts` uses marked (GFM tables / code / checkboxes) + DOMPurify (allow-listed tags, no scripts, no javascript: URLs). - 6 unit tests cover basic markdown, XSS strip, GFM tables, task checkboxes, empty-string fallback. - bodyExpanded state persisted per session in localStorage. Decision impact drill-down: - "Show downstream" / "Show upstream" buttons in ArtifactPanel. - New `widgets/dependency-graph/lib/impact-graph.ts` exports computeDownstream / computeUpstream pure functions, BFS bounded by MAX_IMPACT_DEPTH=8, direction normalised via type-tier.ts#normaliseHierarchyEdge so all hierarchy relations (informs / refines / belongs-to / contains / supersedes) flow abstract → concrete consistently. - 7 unit tests cover linear chain, diamond, cycle, depth cap, non-hierarchy filter, upstream chain, downstream/upstream symmetry. - highlight.svelte.ts extended with impactRoot / impactDirection $state fields; setImpactRoot() and impactedClass() exported. Dual-exposed via entities/graph and widgets/dependency-graph/lib for FSD layering. - 5 views (Force / Tree / Radial / Lanes / Matrix) wire impact map via $derived.by; outer SVG gets `impact-mode` class; nodes get `node-impact-root` / `node-impacted-near` / `node-impacted-far` applied alongside existing `nodeClass(...)`. Sankey + Sunburst do NOT participate — their hierarchy semantics already cover the impact view. - Matrix applies impact class to row + col headers (artifacts); cells (which represent edges) are skipped. Visual treatment in app.css: - node-impact-root: stroke var(--accent), stroke-width 2, drop-shadow(0 0 8px var(--accent)). - node-impacted-near: opacity 1. - node-impacted-far: opacity 0.7. - impact-mode unaffected nodes: opacity 0.18. Dependencies: - runtime: marked@^18, dompurify@^3. - dev: @types/dompurify, happy-dom (vitest DOM env for renderer test). Verify: - svelte-check 0 errors / 0 warnings / 432 files. - npm test 53/53 (40 baseline + 13 new — 6 renderer, 7 impact-graph). - npm run smoke PASS. Refs: PRD-006 RFC-005
PRD-006 (Standard) — Web body preview + decision impact drill-down. 9 SC, 8 FR, 5 NFR, 5 risks. Targets code reviewer / stakeholder / new team member personas. Bundle ≤ 80 KB tracked via NFR-001. DOMPurify + CSP layered for XSS (NFR-003). RFC-005 (Standard) — Markdown rendering + decision impact algorithm. Pins marked + DOMPurify config, BFS depth cap (MAX_IMPACT_DEPTH=8), direction normalisation via type-tier.ts#normaliseHierarchyEdge. Sankey + Sunburst explicitly excluded from impact mode. PRD-007 (Standard) — Web stale + blind-spot push notifications. 9 SC, 9 FR, 5 NFR, 5 risks. Browser Notification API only (no SW). Privacy: only id + title in payload (NFR-002). Throttle 1 per 60s per category. F12 implementation. RFC-006 (Standard) — Notification permission UX + breach detection. State machine for default / requested / granted / denied. Breach categories: new blind_spot / stale_count delta / orphan_count delta. notifyBus pattern for cross-scope click-handler routing. All 4 validated: PRD-006/007 PASS (with non-blocking warnings), RFC-005/006 PASS clean. Refs: PRD-006 RFC-005 PRD-007 RFC-006
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements PRD-006 + RFC-005. Two coupled UX improvements that turn
@forgeplan/webfrom a "table of contents" into a "decision viewer":Body preview
widgets/artifact-panel/lib/markdown-renderer.tsusesmarked(GFM) + DOMPurify (allow-listed tags). XSS-safe by construction.<script>strip,javascript:href strip, GFM table preserved, task checkbox<input type="checkbox">, empty fallback).localStorage.Decision impact drill-down
widgets/dependency-graph/lib/impact-graph.ts— pure BFS bounded byMAX_IMPACT_DEPTH=8, direction normalised viatype-tier.ts#normaliseHierarchyEdgesoinforms/refines/belongs-to/contains/supersedesall flow abstract → concrete consistently.highlight.svelte.tsextended withimpactRoot/impactDirection$state +setImpactRoot/impactedClassexports. Dual-exposed viaentities/graphandwidgets/dependency-graph/lib.$derived.by; outer SVG getsclass:impact-mode; nodes getnode-impact-root/node-impacted-near/node-impacted-far.Visual treatment
node-impact-root: accent stroke 2px + drop-shadow.node-impacted-near: opacity 1.node-impacted-far: opacity 0.7.impact-modeunaffected nodes: opacity 0.18.Dependencies
marked@^18,dompurify@^3.@types/dompurify,happy-dom(vitest DOM env).Verify
Test plan
Refs:
PRD-006RFC-005🤖 Generated with Claude Code