Skip to content

docs: a handover for whoever picks this up - #33

Merged
guan4tou2 merged 2 commits into
mainfrom
docs/handover
Sep 4, 2026
Merged

guan4tou2 merged 2 commits into
mainfrom
docs/handover

Conversation

@guan4tou2

Copy link
Copy Markdown
Owner

Eight PRs (#25–#32) landed in this stretch. This adds docs/HANDOVER-2026-09.md — the part a diff cannot carry.

Where main stands, with the exact verification sequence including the native-module ABI swap that has to bracket the e2e run.

What the last eight PRs decided and why — the three core ones expanded: why a marker amendment is a new chained event rather than an UPDATE, why scope withdrawals are computed from the violation records rather than by rescanning (the logged tier is pruned, so a rescan leaves them standing forever), and why every looser unlock predicate in progressive disclosure makes some page lie.

What is still open, ordered by value ÷ risk, each with the reason it was deferred: the bookmark rename (blocked on aliasing three external contracts), bookmarks having no retention sweep at all, the bundle verifier never re-hashing manifest["files"], the unimplemented scope-aware-lifecycle spec, and env.d.ts still being a hand-written mirror.

The traps — the section I would most want handed to me. The ABI swap whose failure mode is unit tests skipping rather than failing. The temporal-dead-zone crash that only appears in the bundled build, which has bitten this tree three times and which vitest structurally cannot see. The two-tier tables. The source-scanning guards. And two mistakes of my own from this stretch, written down so the next person does not repeat them.

And the closed direction: PR #8 is archived as a tag, with the recovery commands and the reason it was closed on direction rather than staleness.

ROADMAP.md gets a staleness banner rather than a rewrite — it predates this work by five releases, and rewriting someone's planning document from the outside is worse than pointing at what is current. The docs index had been claiming v0.11.7.

Every relative link and code path in the new page resolves (checked).

🤖 Generated with Claude Code

Eight PRs landed in this stretch and the reasoning behind most of it lives in
commit messages nobody reads twice. This is the part a diff cannot carry: why
each decision went the way it did, what is still open and why it was deferred,
and the traps in this tree that cost real time.

The open items are written as work, not as a wish list — each says what it is,
why it is not done, where to start, and what needs a human decision. The
bookmark rename is blocked on aliasing three external contracts; the SQL table
rename is blocked on whether anyone runs mixed versions against one project.

The traps section is the part I would most want handed to me. The native-module
ABI swap, whose failure mode is unit tests SKIPPING rather than failing. The
temporal-dead-zone crash that only appears in the bundled build, which has bitten
this codebase three times and which vitest structurally cannot see. The two-tier
tables, where most of the corpus lives in the half that gets pruned. The
source-scanning guard tests. And two of my own mistakes from this stretch: a
scripted edit whose anchor silently missed and stopped capture for three commits,
and a `git checkout --` that ate an hour of uncommitted work in the file I was
editing.

ROADMAP.md gets a staleness banner rather than a rewrite — it was written
against v0.9.3, five releases back, and rewriting someone's planning document
from the outside is worse than pointing at what is current. The docs index has
been claiming v0.11.7; it now says v0.14.3 and leads with the handover.

Every relative link and code path in the new page is checked to resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 4, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 3612cf94-3f33-4530-b716-bf0691971101


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…is not them

The written standard has been in the repo since #29, but two things it names
were not: the app-icon masters, and the design canvas itself.

The masters are now at design/assets/. The canvas is deliberately not — it is
authored in the design project, and a copy in the repo would just be a second
truth that drifts.

Pulling the masters in surfaced a contradiction worth writing down: §16 says
the old logo "was replaced", while resources/icon.svg, resources/logo.svg,
resources/tray-icon.svg and the renderer's logo.svg are all still the old one,
gradients and glow included, and every .icns/.ico/PNG derives from them. So §16
now carries a ▲ 分歧 saying it describes the design ruling, not what you get
when you install the app, and the handover carries the swap as item 7 with the
part that makes it more than a file replacement: the macOS tray set is a
Template image with two states, and 16px is exactly where the old mark failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@guan4tou2
guan4tou2 merged commit 368ece6 into main Sep 4, 2026
5 checks passed
@guan4tou2
guan4tou2 deleted the docs/handover branch September 4, 2026 05:28
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Seven P1 findings from the UI/UX audit, batched:

  • #15 HUD auto-collapse now pauses while the pointer is on the overlay
    (audit was: hard 8s timer, no way to keep it open while reading the
    topology chain / Reveal button).
  • #16 Terminal tab labels ("Shell 1", "Shell 2" …) used tabs.length + 1
    → duplicated after any close. Now uses a monotonic counter.
  • #17 Closing a terminal tab kills the PTY silently. Now confirms via
    ConfirmDialog when the tab is still alive (matches ProjectPicker
    delete pattern).
  • #21 Settings CDP test callback had a `const tab = ...` shadowing the
    outer `tab` state (settings tab name). Renamed to `cdpTab`.
  • #28-29 EventMarker showed raw enum strings ("info" / "initial_access")
    for severity + category — now i18n'd (marker.severity.*, marker.
    category.*). Also added an opt-out "Capture screenshot too" checkbox
    (default on) so a mark taken over sensitive UI doesn't force a capture.
  • #30 EventMarker gained role="dialog", aria-modal, aria-label, and an
    Escape-to-close handler on the backdrop. Autofocus lands on the dialog
    body so keyboard users have a hook.
  • #32 App title-bar Mark button title="Ctrl+Shift+M" was hardcoded —
    Mac users saw the wrong hint. Uses isMac to pick ⌘⇧M vs Ctrl+Shift+M.

Deferred (need bigger refactors): #9-14/#49-50 shared IPC store to stop
per-event refetches across StatusBar/Sidebar/Dashboard/LootPanel/TargetView/
ScopeStatus; #22-24 sidebar keyboard drag; #25-27 FindingsView/SearchPanel/
LootPanel interactive; #33 uptime should be engagement-scoped not window-
scoped; #34 StatusBar record toggle button styling; #37-38 timeline layout
constraints. All queued for the next batch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
…ocus

  • #25 FindingsView CDP poll now backs off from 3s → 10s while the browser
    isn't running. Was hitting IPC every 3s regardless.
  • #26 Mark URLs (both the primary and the auto-captured browserUrl) now
    open in the operator's real browser via app.openExternal — was inert
    plain text before. New http/https-only openExternal IPC (rejects file:
    and other schemes so untrusted content can't dispatch side effects).
  • #27 SearchPanel results are clickable — click jumps to the event on
    the Timeline via the existing focusEvent flow. Also dropped the q<2
    gate to q<1 so single-char IPs/octets work.
  • #37 Cluster popover now flips ABOVE the cluster when the natural
    position would drop it off the bottom of the timeline (last-lane
    clusters).
  • #39 Recent-project delete ✕ now shows on focus, not only hover —
    keyboard users can reach it. Also gained a focus ring.
  • #47 Timeline zoom-reset button gained a ↺ glyph so the click-to-reset
    behaviour is discoverable (was just the percentage number), plus is
    disabled at 100% and has aria-label + focus ring.

New i18n keys: marks.openUrl, search.openInTimeline (en + zh-TW).

Deferred (still queued): #24 already fixed by v0.6.29's shortcut order
change; #33 uptime → engagement start; #38 timeline layout with detail
panel; #48 MCP UI stdio vs http. Bigger P1s (#9-14, #49-50 shared IPC
store) and P2 shared-component extractions still need dedicated design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
  • #33 StatusBar uptime is now engagement-scoped: reads project.active()
    createdAt instead of window-open Date.now(). Closing the app mid-op
    and reopening no longer resets the counter — the timeline matches
    what "uptime" says. Also extended the project.active IPC to include
    createdAt (with a matching env.d.ts type bump).
  • #41 (partial) Screenshots + Loot cards gained role="button",
    tabIndex, aria-label, Enter/Space key handlers, and a focus-visible
    ring. Grid views are keyboard-navigable now.
  • #30/#40 (screenshot expanded overlay) got role="dialog", aria-modal,
    aria-label, autofocus, Escape-to-close — was click-only before.

TargetView cards still need the same keyboard-nav pass; queued for the
next batch alongside StatusBar sep buttons and Overlay ▲/▼/✕.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Second-pass audit (81 findings) shortlisted three P0 bugs. All fixed:

  • #33 TargetView in-scope / out-of-scope filter always returned empty.
    Every entry's `inScope` was set to null and never populated; both filter
    chips compared === true/false, so they always yielded zero results while
    "All" worked. Compute inScope client-side by matching each target against
    the current scope config (wildcard subdomains + CIDR + exact). Reclassify
    when the scope config changes. Also extended the source query from
    shell-only to all events (audit finding #34) — screenshot / http_navigation
    / loot events with a detectedTarget now surface here too.

  • #1 Timeline reveal state was sticky across the session. `revealedEvents`
    Set only shrank when the user clicked Hide — leaving and coming back kept
    everything unmasked. Now the set clears on every selectedEvent.id change,
    so mask-by-default holds.

  • #2 Copy JSON always dumped raw bytes regardless of what the panel was
    showing. Now respects the reveal state: masked panel → masked clipboard,
    revealed panel → raw clipboard. New toast tells the user which they got.

  • #43 CDP port had TWO controls: a separate FieldGroup with local `cdpPort`
    state (bypassed auto-save entirely) plus BrowserPanel's `config.browser.
    cdpPort` field that did save. Users editing one thought they'd changed
    both. Removed the standalone Field + local state; the Test Connection
    button now reads from config.browser.cdpPort like everything else.

Second-pass audit produced 81 findings across 14 feature areas; these are
the three called out as P0. Batches of P1/friction items to follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
docs: a handover for whoever picks this up
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
…ock counts

Spec 034.

Settings search matched page names only (#143 had relabelled the box "Filter
categories…" to be honest about it). It now matches the text each page renders
— group titles, field labels, hints — in the displayed language. Choosing a
result opens its page and brings the text into view. The index is generated
from the page sources (npm run gen:settings-search) and a test fails when a
page renders a key the index lacks. The box says "Search settings…" again, and
the IA test now allows that label only while the search is wired.

The filter bar named types by storage name (http_navigation, credential_use).
It now uses the Timeline's lane names from one shared table
(LANE_LABEL_KEYS / agentTypeLabel); the stored name is the tooltip, and a
plugin type with no lane keeps its own name.

The status-bar clock counts from the project's creation — deliberately, per
audit P1 #33 — but next to REC it read as this session's recording time. It
keeps its meaning and now says it: tooltip and aria-label name the creation
date and "not this session".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Seven P1 findings from the UI/UX audit, batched:

  • #15 HUD auto-collapse now pauses while the pointer is on the overlay
    (audit was: hard 8s timer, no way to keep it open while reading the
    topology chain / Reveal button).
  • #16 Terminal tab labels ("Shell 1", "Shell 2" …) used tabs.length + 1
    → duplicated after any close. Now uses a monotonic counter.
  • #17 Closing a terminal tab kills the PTY silently. Now confirms via
    ConfirmDialog when the tab is still alive (matches ProjectPicker
    delete pattern).
  • #21 Settings CDP test callback had a `const tab = ...` shadowing the
    outer `tab` state (settings tab name). Renamed to `cdpTab`.
  • #28-29 EventMarker showed raw enum strings ("info" / "initial_access")
    for severity + category — now i18n'd (marker.severity.*, marker.
    category.*). Also added an opt-out "Capture screenshot too" checkbox
    (default on) so a mark taken over sensitive UI doesn't force a capture.
  • #30 EventMarker gained role="dialog", aria-modal, aria-label, and an
    Escape-to-close handler on the backdrop. Autofocus lands on the dialog
    body so keyboard users have a hook.
  • #32 App title-bar Mark button title="Ctrl+Shift+M" was hardcoded —
    Mac users saw the wrong hint. Uses isMac to pick ⌘⇧M vs Ctrl+Shift+M.

Deferred (need bigger refactors): #9-14/#49-50 shared IPC store to stop
per-event refetches across StatusBar/Sidebar/Dashboard/LootPanel/TargetView/
ScopeStatus; #22-24 sidebar keyboard drag; #25-27 FindingsView/SearchPanel/
LootPanel interactive; #33 uptime should be engagement-scoped not window-
scoped; #34 StatusBar record toggle button styling; #37-38 timeline layout
constraints. All queued for the next batch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
…ocus

  • #25 FindingsView CDP poll now backs off from 3s → 10s while the browser
    isn't running. Was hitting IPC every 3s regardless.
  • #26 Mark URLs (both the primary and the auto-captured browserUrl) now
    open in the operator's real browser via app.openExternal — was inert
    plain text before. New http/https-only openExternal IPC (rejects file:
    and other schemes so untrusted content can't dispatch side effects).
  • #27 SearchPanel results are clickable — click jumps to the event on
    the Timeline via the existing focusEvent flow. Also dropped the q<2
    gate to q<1 so single-char IPs/octets work.
  • #37 Cluster popover now flips ABOVE the cluster when the natural
    position would drop it off the bottom of the timeline (last-lane
    clusters).
  • #39 Recent-project delete ✕ now shows on focus, not only hover —
    keyboard users can reach it. Also gained a focus ring.
  • #47 Timeline zoom-reset button gained a ↺ glyph so the click-to-reset
    behaviour is discoverable (was just the percentage number), plus is
    disabled at 100% and has aria-label + focus ring.

New i18n keys: marks.openUrl, search.openInTimeline (en + zh-TW).

Deferred (still queued): #24 already fixed by v0.6.29's shortcut order
change; #33 uptime → engagement start; #38 timeline layout with detail
panel; #48 MCP UI stdio vs http. Bigger P1s (#9-14, #49-50 shared IPC
store) and P2 shared-component extractions still need dedicated design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
  • #33 StatusBar uptime is now engagement-scoped: reads project.active()
    createdAt instead of window-open Date.now(). Closing the app mid-op
    and reopening no longer resets the counter — the timeline matches
    what "uptime" says. Also extended the project.active IPC to include
    createdAt (with a matching env.d.ts type bump).
  • #41 (partial) Screenshots + Loot cards gained role="button",
    tabIndex, aria-label, Enter/Space key handlers, and a focus-visible
    ring. Grid views are keyboard-navigable now.
  • #30/#40 (screenshot expanded overlay) got role="dialog", aria-modal,
    aria-label, autofocus, Escape-to-close — was click-only before.

TargetView cards still need the same keyboard-nav pass; queued for the
next batch alongside StatusBar sep buttons and Overlay ▲/▼/✕.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Second-pass audit (81 findings) shortlisted three P0 bugs. All fixed:

  • #33 TargetView in-scope / out-of-scope filter always returned empty.
    Every entry's `inScope` was set to null and never populated; both filter
    chips compared === true/false, so they always yielded zero results while
    "All" worked. Compute inScope client-side by matching each target against
    the current scope config (wildcard subdomains + CIDR + exact). Reclassify
    when the scope config changes. Also extended the source query from
    shell-only to all events (audit finding #34) — screenshot / http_navigation
    / loot events with a detectedTarget now surface here too.

  • #1 Timeline reveal state was sticky across the session. `revealedEvents`
    Set only shrank when the user clicked Hide — leaving and coming back kept
    everything unmasked. Now the set clears on every selectedEvent.id change,
    so mask-by-default holds.

  • #2 Copy JSON always dumped raw bytes regardless of what the panel was
    showing. Now respects the reveal state: masked panel → masked clipboard,
    revealed panel → raw clipboard. New toast tells the user which they got.

  • #43 CDP port had TWO controls: a separate FieldGroup with local `cdpPort`
    state (bypassed auto-save entirely) plus BrowserPanel's `config.browser.
    cdpPort` field that did save. Users editing one thought they'd changed
    both. Removed the standalone Field + local state; the Test Connection
    button now reads from config.browser.cdpPort like everything else.

Second-pass audit produced 81 findings across 14 feature areas; these are
the three called out as P0. Batches of P1/friction items to follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
docs: a handover for whoever picks this up
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
…ock counts

Spec 034.

Settings search matched page names only (#143 had relabelled the box "Filter
categories…" to be honest about it). It now matches the text each page renders
— group titles, field labels, hints — in the displayed language. Choosing a
result opens its page and brings the text into view. The index is generated
from the page sources (npm run gen:settings-search) and a test fails when a
page renders a key the index lacks. The box says "Search settings…" again, and
the IA test now allows that label only while the search is wired.

The filter bar named types by storage name (http_navigation, credential_use).
It now uses the Timeline's lane names from one shared table
(LANE_LABEL_KEYS / agentTypeLabel); the stored name is the tooltip, and a
plugin type with no lane keeps its own name.

The status-bar clock counts from the project's creation — deliberately, per
audit P1 #33 — but next to REC it read as this session's recording time. It
keeps its meaning and now says it: tooltip and aria-label name the creation
date and "not this session".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant