Stabilization: pre-PR audit fixes, AppKit-first document tabs, transcription off-main#7
Merged
Conversation
…o feat/pensieve-mvp3-machete2
…feat/pensieve-mvp3-machete2
Refactors Makefile help output to use structured `printf` output with ANSI color constants, improving readability and alignment of command descriptions. Authored-By: codex <agents@vetcoders.io> session_id: 019e90db-cdfe-7ad2-ab53-d62bef636222 time: Thu Jun 4 14:08:52 MDT 2026 runtime: iterm2
…b UX Addresses six findings from a ScreenScribe review of the editor. The window toolbar (EditorToolbelt) existed but was never mounted; this attaches it via `.toolbar` on ContentView, restoring the mode picker, block-format strip, and preview controls. The find bar gains a disclosure toggle next to the search field so Find & Replace is reachable inline, not only via the menu shortcut. The document tab strip pins its "+" New File button to the trailing edge instead of letting it scroll away, and a window-scoped scroll-wheel monitor (HorizontalWheelRedirector) maps vertical wheel input onto the strip's horizontal axis for plain-mouse users. Automatic macOS window tabbing is disabled so the only tab surface is the app's own strip, removing the duplicate native tab bar that always showed the same document. A new DocumentSharing helper backs File - Share and a toolbar Share button, sharing the file URL (or buffer text when unsaved). .gitignore now ignores *.log. Verified: swift build (debug+release), swift test 242/242, make lint clean, make release-clean -> notarized + stapled + Gatekeeper-accepted. Authored-By: claude <agents@vetcoders.io> session_id: 9c13d55e-1af1-4dc0-ae3b-382659e4f766 date: 2026-06-04T15:36:27 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks .gitignore to stop blanket-ignoring every *.md. Only root-level and docs-direct markdown stay ignored, with README/CHANGELOG/CONTRIBUTING/SECURITY/ CODE_OF_CONDUCT/AGENTS and VERSION whitelisted, and docs/superpowers + docs/ workforce excluded. Design and plan specs under docs/specs/ are now tracked. Adds the per-window-documents + native-window-tabs implementation plan (Stream S0b of the Pensieve mega-meta atlas): state split into a shared WorkspaceStore + per-window DocumentWindowModel, native tabbing, sidebar in every window, removal of the programmatic DocumentTabStrip, with a measurable cut/verifier per step. Authored-By: claude <agents@vetcoders.io> session_id: 314040e7-b4ec-4bf8-afde-46cf128fd083 date: 2026-06-04T18:02:29 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d *.md ignore Internal documents (specs, plans, agent prompts) sync between the operator's machines over Tailscale + rsync, NOT through git/GitHub. The broad *.md ignore was a deliberate privacy guard; a narrower rule had let an internal plan doc be tracked. This reinstates the broad *.md ignore (named governance/root files still whitelisted) and untracks the per-window-tabs plan, which stays on disk for rsync but no longer ships to the remote. Reverts the tracking introduced in 2a1ffca (file content remains in history; purge requires a separate force-push rewrite, operator-gated). Authored-By: claude <agents@vetcoders.io> session_id: 314040e7-b4ec-4bf8-afde-46cf128fd083 date: 2026-06-04T18:07:58 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split workspace and per-window document state so native macOS tabs can host independent documents. Route open-file intents through value-scoped windows, activate existing document tabs, remove the in-app DocumentTabStrip, and keep menu commands focused on the frontmost document window.
Two Pensieve bugfixes (plans 10 + 20), living tree, no push. Plan 10 — floating format bar must NOT steal focus - Replace NSPopover (a separate key window → NSTextView resigns first-responder → user had to press Esc before typing/copying) with an in-window subview accessory (FloatingFormatBarView) that hosts the existing MarkdownFloatingFormatBar (reuse, no second bar). - acceptsFirstResponder=false → the bar never becomes key → text view keeps first-responder → no focus theft, no Esc. - Draggable via a leading grip (mouseDown/Dragged moves the bar, clamped to visibleRect); anchored in text-view coordinates so it scrolls with the text and never floats over a stale spot. Lifecycle parity preserved (show on non-empty selection, hide on empty / apply / Esc). show/hide/apply API names and the EditorView caller unchanged. Plan 20 — P0: workspace index hangs the app (DB off the main thread) Root: @mainactor IndexDatabase ran SQLite on main — open()'s DatabasePool + migrate (incl. FTS5 rebuild) and every sync read/write blocked the run loop; ensureOpen() was sync at the head of the "...InBackground" methods, so even those migrated on first touch on main. - makeDatabasePool (nonisolated static) + openInBackground/ensureOpenInBackground (async, detached executor, coalesced via openTask) move open+migrate off main. - All ...InBackground methods now await ensureOpenInBackground (first-open off main systemically). refreshSearchResultsInBackground moves the post-reindex search read off main. indexedDocumentCountInBackground for the skip-gate. - DocumentStore live background path: open, cold skip-gate count, performColdIndex content-guard, and hot-reopen open all moved off main (precomputed off-main values injected; legacy sync path keeps sync). AppController.start warms the index off main instead of a synchronous open at launch. Verified: swift build (debug+release) green; swift test 242/242, 0 failures; make lint exit 0; git diff --check clean. NOT verified (operator-owned): make ui-smoke (System Events AppleEvent -1712 in headless session; needs signed .app) and the Time-Profiler no-beachball runtime gate. Residual (documented): single-doc autosave index() stays sync on main to preserve the synchronous save-test contract — not the import storm. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a new `make install-app` target that builds the signed app, safely stops any running Pensieve process, replaces `/Applications/Pensieve.app`, and relaunches it. Also updates the project version from `0.2.1` to `0.2.3`.
…in thread (P0 R1) The autosave/save tail ran IndexDatabase.index(document:body:) — ensureOpen + pool.write (ensure-workspace + upsert) + refreshSearchResults (a pool.read) — synchronously ON THE MAIN ACTOR on every persisted edit, a per-save SQLite stall on the run loop. Add an off-main twin indexInBackground(document:body:) mirroring updateSearchIndexInBackground (shared pendingIndexUpdateTask supersede chain, detached .utility pool.write, refreshSearchResultsInBackground hop), and repoint the single production caller (DocumentStore's default index closure) to it so the file write stays synchronous while the FTS update commits in the background. The sync index() is kept for the explicit one-shot/test callers (same sync/background duality as reindex/reindexInBackground); the two ad-hoc single-doc index tests now sync on the awaited background write instead of the sync method. swift test 242/242 green, make lint clean. Authored-By: claude <agents@vetcoders.io> session_id: 52e36949-a5c9-4b44-8951-37cbd6aafce2 date: 2026-06-05T18:00:13 MDT runtime: claude
…store edit toolbar + degut ghosting Three P0 regressions surfaced by a 2026-06-05 ScreenScribe review of the per-window build (a152d00 + 9646193). The per-window state bridge (windowModel/workspaceStore objectWillChange re-broadcast onto AppState) re-renders the whole UI on every keystroke, and the editor's NSScrollView re-scrolled to the caret each time — "the screen goes wild on every letter". updateNSView now pins the clip-view origin across a pure re-render (text unchanged) and the text re-sync path preserves caret + scroll, so the viewport only moves when the user's own typing pushes the caret past the edge. The window-toolbar format strip gated on document != nil, so it vanished while editing any buffer whose DocumentRef was nil (e.g. an opened doc that did not carry a ref) — it now lights up for any hasEditableBuffer, untitled included. The line-number gutter ghosted/doubled because partial ruler redraws left stale numbers at the old scroll offset; contentView now posts bounds changes so every scroll forces a full gutter repaint. Native window tabs / Merge All Windows confirmed working and untouched. Authored-By: claude <agents@vetcoders.io> session_id: 1e9d8b44-cdef-4c26-b152-b3d0e664a6b4 date: 2026-06-05T20:26:55 MDT runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d off the main actor (P0 beachball)
The constant beachball ("the app churns every ~0.5-3s, non-stop") on a 54k-file workspace was
the watcher-refresh path re-enumerating the whole tree ON the main actor. performWatcherRefresh
computed the .md signature off-main, but applyRefresh -> rebuildWorkspace then re-walked all 54k
files + per-file stat synchronously on the main actor on every .md change — and a live workspace
full of agent reports, rsync and .git churns .md constantly, so the rebuild fired in a loop and
pinned the main thread. Now the rebuild enumeration also runs on a detached .utility task: the
.md signature scan is off-main, a non-.md change skips the rebuild entirely on the cheap delta
check, and only a genuine .md change pays for an off-main rebuild scan whose result is handed to
the main actor purely to assign the tree. rebuildWorkspace accepts precomputed scans so the main
actor never enumerates the workspace.
Authored-By: claude <agents@vetcoders.io>
session_id: 286d1e8c-3f76-492f-85d8-3f8a58f2fb80
date: 2026-06-05T20:46:57 MDT
runtime: claude
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guard DocumentWindowRegistry open and attach ordering while AppKit has an active modal window, then retry on a clean main-queue turn. Keep SwiftUI window accessor repeats idempotent so pending merge targets are only consumed once native tab mutation is safe. Add coverage for the modal-blocked attach path: no merge or order work runs while blocked, duplicate accessor updates coalesce to one retry, and the deferred attach completes once unblocked. Authored-By: codex Session-Id: pending Date: 2026-06-06 Runtime: unknown
…ab attach test testDocumentWindowAttachDefersNativeTabMutationDuringModalRunLoop created an NSWindow via init(contentRect:styleMask:backing:defer:), which defaults to isReleasedWhenClosed = true. The deferred window.close() then released the window once, and ARC released the local reference again at scope exit — a double free that crashed the whole xctest process with SIGSEGV (objc_release EXC_BAD_ACCESS on the main thread), taking the full suite down to a non-result. Setting isReleasedWhenClosed = false lets ARC own the single reference so teardown is balanced. Suite is green again at 243/243 (gate for the off-main index work). Surgical, test-only; production NSWindow lifetime is unchanged. Authored-By: claude <agents@vetcoders.io> session_id: b6ad7720-7637-4dae-ac54-2675e4174309 date: 2026-06-06T04:44:51 MDT runtime: interactive
- Pensieve/Sources/Pensieve/App/DocumentWindowRegistry.swift: decouple window opening from SwiftUI OpenWindowAction for direct deferred-open testing and use NSApplication.shared for optional key/main window lookup in headless or launch-timing paths. - Pensieve/Sources/Pensieve/App/PensieveApp.swift: preserve production openWindow(value:) routing through the registry's document opener closure. - Pensieve/Tests/PensieveTests/PensieveTests.swift: cover modal-time open deferral, retry coalescing, and single resumed document open. Gate: pass Tests: swift test targeted open/attach modal tests; make test; make lint; make release-local; make ui-smoke; scripted About/open-file runtime probe with 12 confirmed modal passes plus 2 no-crash automation-noise attempts Regressions: 0 Round-ID: marb-044111-62487-005
…ction Protect workspace cache and metadata artifacts with complete file protection and lock the contract with regression tests. Authored-By: junie <agents@vetcoders.io> session_id: 8ec86487-629a-4883-bf86-310672271e8c date: 2026-06-06T21:32:08 MDT runtime: interactive Co-authored-by: Junie <junie@jetbrains.com>
Replace blind autosave sleeps with deterministic file-write and waitForPendingReindex-gated search assertions. Authored-By: junie <agents@vetcoders.io> session_id: 7bfa8e36-d960-4bf7-a9a5-65a397ad3d41 date: 2026-06-06T22:01:34 MDT runtime: gpt-5.4 Co-authored-by: Junie <junie@jetbrains.com>
Adds Return-time Markdown continuation behind the Rich Markdown toggle and pins inline highlight rendering with tests. Authored-By: codex <agents@vetcoders.io> session_id: b201a096-5522-4563-b2bb-05b05cbd895e date: 2026-06-07T06:38:33 MDT runtime: codex
Adds the first wikilink/backlink core seam by parsing [[target]] text, rendering safe preview anchors, and covering extraction plus escaping behavior. Authored-By: codex <agents@vetcoders.io> session_id: 1c51fd30-a2ec-4e68-aeec-ef48f46681e1 date: 2026-06-07T06:49:38 MDT runtime: codex
Wire the existing preview viewport bridge to the editor with paragraph-index mapping and tests. Authored-By: codex <agents@vetcoders.io> session_id: c7a5555f-d83d-47d2-8bbf-44652a758430 date: 2026-06-07T06:58:27 MDT runtime: codex
Adds an offline-safe markdown math layer to the existing HTML preview pipeline with tests for inline and display delimiters. Authored-By: codex <agents@vetcoders.io> session_id: c83ccf4e-9aaf-461b-8df4-045715e88099 date: 2026-06-07T07:08:17 MDT runtime: unknown
Focus mode now keeps the insertion line centered during typing and selection changes without adding a parallel editor mode. Authored-By: codex <agents@vetcoders.io> session_id: 77e0ed10-9cdd-45f5-ab93-baf33b1d4131 date: 2026-06-07T07:17:28 MDT runtime: unknown
Adds File menu export paths backed by the existing preview renderer, with standalone HTML coverage and WebKit PDF generation. Authored-By: codex <agents@vetcoders.io> session_id: 3d18a8e2-b50e-439a-abe9-1ae8dcf58373 date: 2026-06-07T07:28:13 MDT runtime: unknown
Pensieve now vendors the generated qube UniFFI bridge and links the debug libqube_ffi dylib through SwiftPM, unblocking the transcription overlay W0 build seam. Authored-By: codex <agents@vetcoders.io> session_id: 1e82d76f-f6b2-4c5e-98a9-bcca2f793aa3 date: 2026-06-07T07:42:42 MDT runtime: codex
…rvice Adds the headless TranscriptionService seam for W1, wires it into the existing app graph, and locks preview/final accumulation with tests. Authored-By: codex <agents@vetcoders.io> session_id: 0f4d69e2-4812-4b18-9a76-4b12ffa719bf date: 2026-06-07T07:53:01 MDT runtime: codex
Adds scoped backlink queries over the existing documents index so wikilinks can resolve incoming references without a parallel parser. Authored-By: codex <agents@vetcoders.io> session_id: 0fd1aa2d-ea85-4f7c-8ed2-5809194a56b6 date: 2026-06-07T08:03:01 MDT runtime: codex
Extend the existing MarkdownFormatter typing pipeline so a single closing equals finishes source-first ==highlight== markup without touching closed spans. Authored-By: codex <agents@vetcoders.io> session_id: 30489637-018d-4550-9112-878978a25f35 date: 2026-06-07T08:08:45 MDT runtime: codex
…edback loop on keystroke The editor↔preview scroll sync (c7ed51f) yanked the editor to the caret on every character in split mode: typing posts the editor viewport, the preview re-renders + emits a viewport change, and handlePreviewViewportChanged scrollRangeToVisible'd the editor back — a loop the operator hit as "every char jumps the whole document". Guard handlePreviewViewportChanged so preview-driven scroll only moves the editor when the editor is NOT first responder; while the user is typing the editor drives and is never scrolled by the sync. User-driven preview scrolling still syncs. Authored-By: claude <agents@vetcoders.io> session_id: b83b0fb9-3bfb-4853-8d5e-1da067c81836 date: 2026-06-07T15:40:52 MDT runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an Application Support recovery store for dirty untitled buffers, restore the latest draft during startup, and delete drafts after Save As or discard. Bound the Open Files working set, add clear/close affordances, pin default scanner noise filtering, and fix the vendored qube_ffi install name so SwiftPM tests load the repo-local dylib instead of a stale external path. Verification: make test (281 tests, 0 failures); make lint; scoped semgrep scan; targeted recovery/working-set/regression tests. Authored-By: codex session_id: pending date: 2026-06-07T23:20:00-06:00 runtime: codex-cli
Cut 42-A3 had default noise filtering but no .gitignore layer, so agent artifacts and project-local ignore rules could still leak into the notes tree/index. Extend the existing WorkspaceScanner path with scan-local GitIgnoreRule handling for anchored, directory, wildcard, nested, and negation rules while preserving the default deny-list and manual exclusions. Verification: targeted Cut 42 cluster passed; make test passed 282 tests; make lint passed. Semgrep 1.164.0 was run and failed on 5 pre-existing blocking findings outside this scoped patch: ATS pinning in plist files and one existing WorkspaceSubstrateTests storage-protection fixture. Authored-By: codex/gpt-5 session_id: pending date: 2026-06-07T23:37:37 MDT runtime: codex
…menu; floating bar clamped out of chrome Cut 5-1R after the operator bounce (18:20/18:47 evidence): the raw B/S/I/quote/ code/link/list cluster leaves the titlebar and lives behind one Aa (textformat) Menu in the principal slot that iterates MarkdownFormat.allCases — the same single source of truth the floating selection bar and editor context menu render, so the surfaces cannot drift. The rich-markdown toggle (the old misleading bare Aa button) relocates into that menu. Trailing side reduced to daily drivers share/appearance/reload (+dispatch in ContentView); tafla, scroll-sync and auto-reload fold into one ellipsis overflow menu. The floating formatter now clamps to visibleRect ∩ window.contentLayoutRect (chrome truth): static accessoryOrigin/clampedAccessoryOrigin are pure and tested, re-pinned on every bounds/layout tick and during grip drags, so the bar pins at the toolbar edge instead of ghosting under the translucent chrome. Regression suite EditorToolbeltFloatingClampTests pins the seam; EditorToolbeltTests pins the shared allCases order. Authored-By: claude <agents@vetcoders.io> session_id: 27e19f58-fb6b-4e94-aaea-c75305a25dc3 time: 2026-07-05T19:53:50-07:00 runtime: claude
…nt-seam suite swept into the lane Concurrent shared work landed mid-cut: VoiceOver accessibilityLabels on the toolbelt buttons/menus and FormattingAccessoryPlacementTests — 10 tests over accessoryOrigin/clampedAccessoryOrigin (flipped + unflipped + degenerate) and a real fullSizeContentView NSWindow proving accessoryAllowedRect excludes the titlebar band. Verified green together with the Cut 5-1R suites (48/48). Authored-By: claude <agents@vetcoders.io> session_id: 27e19f58-fb6b-4e94-aaea-c75305a25dc3 time: 2026-07-05T19:55:34-07:00 runtime: claude
…to EditorToolbeltTests Peer consolidation swept into the lane: FormattingAccessoryPlacementTests.swift folds into EditorToolbeltTests.swift as FormattingAccessoryChromeTruthTests — unflipped branches, full origin→clamp pin path, and the real fullSizeContentView window proof for accessoryAllowedRect — deduped against EditorToolbeltFloatingClampTests. Extended filter green 43/43. Authored-By: claude <agents@vetcoders.io> session_id: 27e19f58-fb6b-4e94-aaea-c75305a25dc3 time: 2026-07-05T19:57:22-07:00 runtime: claude
…ar seam + toolbelt a11y labels Marbles L1 on the Cut 5-1R surface: the pure clamp suite pinned the flipped geometry but left three blind spots — the unflipped accessoryOrigin branch, the full origin→clamp pin path, and accessoryAllowedRect against a REAL window.contentLayoutRect under .fullSizeContentView (the actual chrome truth the pure tests only model). FormattingAccessoryChromeTruthTests covers all three. The image-only toolbar controls (share, appearance, reload, Aa edit menu, overflow) also gain explicit accessibilityLabel: VoiceOver had no accessible name for them, only tooltips and identifiers. Gate: pass Tests: swift test --filter 'EditorToolbelt|FormattingAccessory' (19 green), make lint clean Regressions: 0 Authored-By: claude <agents@vetcoders.io> session_id: 42efe5dc-9c8f-4990-8e61-e98feace15f4 time: 2026-07-05T19:57:47-07:00 runtime: claude
…d from the vendored banner Polarize L2 cycle-2 cut, continuing L1's 'version speaks once' axis onto component versions. The Mermaid version claim had two hand-written producers that silently outlive an upgrade of the vendored runtime: the Info.plist template (with an explicit test exemption hiding it) and a hardcoded literal in scripts/build-release.sh:270. Now the banner of mermaid.min.js (line 1) is the ONLY producer: the release script extracts the version at stamp time and dies hard when extraction fails; the template drops to the 0.0.0 placeholder like every other component; the placeholder test loses its Mermaid exemption; and a new guard pins the extraction contract (banner must carry 'Mermaid v<x.y.z>'). Gates: swift build green, swift test --filter 'BuildIdentityTests|PreviewPipelineTests' 21/21 green, make lint green, bash -n + shellcheck -S warning clean, sed extraction verified against the real vendored file (yields 11.15.0, byte-identical to the removed literal). Authored-By: claude <agents@vetcoders.io> session_id: 6c0285e5-588c-4cda-9058-ece881adc796 time: 2026-07-05T20:16:49-07:00 runtime: claude
Add the 0.3.0 release note, source-trial install path, and social/crawler metadata for the public representation surface. This stays local-lane honest: MAS submission, signing identities, push, and LFS/provenance decisions remain operator-gated. Authored-By: codex <agents@vetcoders.io> session_id: ce64cf14-7eb4-4eed-b6b9-d373672262a2 time: 2026-07-06T01:15:58-07:00 runtime: codex
Orphaned claude-marbles lane left the directory-routing fix in the Living Tree without a commit after the 2026-07-06 spend-limit stop. Codex verified the full diff, Loctree slice and literal context, swift build, the requested filtered tests, and make lint, then committed the existing fix as the routing unit. Directory URLs entering openFile(url:) now dispatch through openFolder(url:) before document registry and markdown rejection so Finder, Dock drop, and open -a workspace opens do not surface unsupported-file errors. Authored-By: codex <agents@vetcoders.io> session_id: 232dc134-5b70-4370-9773-33f702af911d time: 2026-07-06T01:48:45-07:00 runtime: codex
…downFormat Orphaned claude-marbles lane left this formatter-completeness latch in the Living Tree beside the directory-routing fix after the 2026-07-06 spend-limit stop. Codex verified the full diff, Loctree context, swift build, the requested filtered tests, and make lint, then committed the existing test-only latch as a separate unit. The wrapper-string expectations now assert parity with MarkdownFormat.allCases so future enum additions force an explicit Format-menu coverage decision. Authored-By: codex <agents@vetcoders.io> session_id: 232dc134-5b70-4370-9773-33f702af911d time: 2026-07-06T01:49:06-07:00 runtime: codex
Move contextual wrapping-toggle semantics into MarkdownFormatter.formatSelection so shared toolbar, menu, and floating-bar paths stop double-wrapping selections that already sit inside bold, italic, strike, or code spans. Selections exactly covering a wrapping span now unwrap the span. Selections inside the span content also unwrap the whole span. Partially overlapping selections no-op because the requested toggle crosses delimiter boundaries and preserving Markdown structure is safer than producing malformed mixed markup. EditorView now applies the formatter's explicit edit range/replacement instead of wrapping the selected substring directly. EditorToolbelt and FloatingFormatBar UI surfaces are untouched. Verified: cd Pensieve && swift build Verified: cd Pensieve && swift test --filter 'MarkdownFormatter|EditorToolbelt' Verified: make lint Authored-By: codex <agents@vetcoders.io> session_id: 07d5cca5-2a56-4e3c-a953-ec9d3d99ee9a time: 2026-07-06T02:05:59-07:00 runtime: codex
Move preview heading sizing into appearanceCSS so vendored flavor px rules cannot flatten H1-H6 when --vc-font-size grows. Set the shared heading rhythm to em-based sizes, 1.25 line-height, and relative margins. Raise Vercel headings to 700 for dark-surface readability; leave Vista at its existing 600 overlay because the contract allows conscious skin overrides at 600+ and this cut diagnosed Vercel specifically. Add CSS string coverage for default, vercel, and paper skins, including 16px/24px body-font checks that keep heading scale in em units. Vibecrafted-Trail: cut-7-4 Owner-Agent: codex/vc-ownership Verification: swift build; swift test --filter 'Preview|DocumentExport'; make lint; semgrep --config auto --quiet touched files Authored-By: codex <agents@vetcoders.io> session_id: 019f36fd-8c78-7c21-9050-156288805390 time: 2026-07-06T04:02:26-07:00 runtime: terminal
Replace the Aa dropdown menu with an inline horizontal formatting toolbelt in the titlebar. The row keeps MarkdownFormat.allCases as the single action source, routes every format through controller.applyMarkdownFormat, and keeps Rich Markdown as the final toolbar toggle. State is per-window chrome state owned by ContentView and resets on launch and when the editable buffer identity changes, so the expansion does not persist across documents. Gates: - cd Pensieve && swift build - cd Pensieve && swift test --filter 'Toolbelt|EditorToolbelt' - make lint Authored-By: codex <agents@vetcoders.io> session_id: 77e30457-3190-481a-9a07-ad142acbb695 time: 2026-07-08T20:47:22-07:00 runtime: codex
Non-markdown preview requests now render escaped preformatted text instead of entering the markdown renderer, while known markdown extensions keep the existing HTML path. Shebangs force the plain path so scripts with comment lines no longer become headings. Tests cover .sh/.txt shebang plain output and the .md markdown regression path. Gates: - cd Pensieve && swift build - cd Pensieve && swift test --filter 'Preview|DocumentExport' - make lint - wrapper visual: /private/tmp/PensieveCut76.app with /private/tmp/vibecrafted-rescue.txt screenshot inspected Vibecrafted-Skill: vc-ownership Vibecrafted-Cut: 7-6 Vibecrafted-Report: /Users/maciejgad/.vibecrafted/artifacts/vetcoders/pensieve/2026_0708/reports/ownership/2026-07-08_codex_cut-7-6_report.md Authored-By: codex <agents@vetcoders.io> session_id: 019f44f6-5594-7472-a79d-2fef68dd819f time: 2026-07-08T20:59:12-07:00 runtime: terminal
Move titlebar glass height and chrome-clipped content rect truth into WindowChromeRecipe, then route PreviewTitlebarGlassController and editor accessory geometry through it. Pin preview top padding to the shared chrome recipe instead of responsive 3vw drift, reset the first preview child margin, and keep horizontal/bottom preview padding responsive. Measurements: baseline split preview was about 24.5-25pt lower than editor; final split, resize, and fullscreen screenshots measure 0.5pt delta. Verification: cd Pensieve && swift build; cd Pensieve && swift test --filter 'Preview|Chrome|Toolbelt'; make lint. Vibecrafted-Run: owne-260708-204025-26000 Vibecrafted-Report: /Users/maciejgad/.vibecrafted/artifacts/vetcoders/pensieve/2026_0708/reports/ownership/2026-07-08_codex_cut-7-7_report.md Authored-By: codex <agents@vetcoders.io> session_id: 019f44f7-0012-7d50-abf8-cd83afc98ab7 time: 2026-07-08T21:03:27-07:00 runtime: terminal
Korekta polityki operatora po 7-5: keep the 911b77d horizontal formatting row, but remove the artificial expand/collapse policy around the Aa opener. Format actions now render directly in the principal toolbar for editable source, split, and focus buffers. Preview-only and empty buffers hide the row. Rich Markdown becomes the last icon in the row, with no separate Aa opener, because fewer controls beats ceremony. Verification: cd Pensieve && swift build; cd Pensieve && swift test --filter 'Toolbelt|EditorToolbelt'; make lint; wrapper-.app live proof with screenshots in /Users/maciejgad/.vibecrafted/artifacts/vetcoders/pensieve/2026_0708/live-proof/cut-7-5b. Vibecrafted-Run: owne-260708-205330-46000 Vibecrafted-Report: /Users/maciejgad/.vibecrafted/artifacts/vetcoders/pensieve/2026_0708/reports/ownership/2026-07-08_codex_cut-7-5b_report.md Authored-By: codex <agents@vetcoders.io> session_id: f9e4d05c-2beb-42f8-a4c8-2f2730840d89 time: 2026-07-08T21:19:17-07:00 runtime: terminal
…uth over preview Cut 7-9: over the preview pane the titlebar glass composited WKWebView's default underPageBackgroundColor (a light warm system gray), so in dark chrome the strip right of the split divider read as a lighter sepia-tinted patch while the strip over the editor drank the neutral editor surface. Root cause proven on a live wrapper-app rig: seam pixels measured (44,42,39) warm over preview vs (30,30,30) flat over editor, position- independent. Fix pins the under-page backing to the same surface truth the editor feeds the chrome — textBackgroundColor — owned by WindowChromeRecipe as titlebarGlassBackingColor and wired in PreviewWebView. Post-fix rig measurements: strip uniform across the divider in dark (paper + code skins), light mode unchanged, fullscreen bands identical both sides, editor/preview content start delta 0.0pt (no 7-7 regression). Verification: cd Pensieve && swift build; swift test --filter 'Preview|Chrome' (83/0); make lint. Authored-By: claude <agents@vetcoders.io> session_id: 8c3fe192-8ec7-4358-b642-cae3961f7f93 time: 2026-07-08T22:03:49-07:00 runtime: claude
Rework the macOS toolbar so the native title leads after the sidebar toggle, then share and dispatch sit before the always-on edit row, with modes, appearance, reload, and overflow trailing. Keep dispatch presentation state and sheet ownership in ContentView while exposing the button through the toolbelt composition. Add EditorToolbelt identifier-order tests for the new titlebar contract while preserving the MarkdownFormat.allCases guard. Vibecrafted-Cut: 7-8 Vibecrafted-Report: ~/.vibecrafted/artifacts/vetcoders/pensieve/2026_0708/reports/ownership/2026-07-08_codex_cut-7-8_report.md Verification: cd Pensieve && swift build Verification: cd Pensieve && swift test --filter 'Toolbelt|EditorToolbelt' Verification: make lint Authored-By: codex <agents@vetcoders.io> session_id: 019f4546-26f3-7b61-a998-8875271730b4 time: 2026-07-08T22:19:04-07:00 runtime: terminal
Separate share and dispatch into their own native principal toolbar group, then start the edit row with the existing Rich Markdown Aa toggle before the unchanged MarkdownFormat action order. Gates: swift build; swift test --filter 'Toolbelt|EditorToolbelt'; make lint. Authored-By: codex <agents@vetcoders.io> session_id: 960421b1-4c64-42fc-9647-414940054d02 time: 2026-07-08T22:52:26-07:00 runtime: codex
…view the editor's glass glide Cut 7-10: both panes now treat the chrome boundary the same way the editor text view does (the post-7-7/7-9 pattern). - LineNumberGutter clips fill + separator + numbers to WindowChromeRecipe.chromeClippedVisibleRect, so the ruler stops painting into the titlebar and across the window title; the anti-ghosting full-bounds repaint contract survives inside the clipped region (fast-scroll probe: no stale numbers). - PreviewWebView zeroes WKWebView.obscuredContentInsets (macOS 26 public API) and re-asserts on window moves/layout, because WebKit re-adopts the safe area on window attach; the automatic pocket was the hard mid-glyph cut of scrolled preview content at the toolbelt. Body top padding now rides on the measured glass-height CSS var. - PreviewTitlebarGlassController KVO-observes window.contentLayoutRect: SwiftUI attaches the toolbar after the preview joins the window, which changes the chrome height without any resize notification or web-view layout pass — the stale mid-construction measurement (88px vs real 52px) both parked the page start a band below the editor's and painted the 7-9 light-mode underlay stripe, which is gone now. Verified on a live wrapper build (5-1R rig): seam editor/preview 0.5 pt (baseline -0.5), titlebar tint identical per-pixel both sides in dark and light, gutter line/background end at the chrome edge, fullscreen clean, 120/120 filtered tests, make lint exit 0. Authored-By: claude <agents@vetcoders.io> session_id: 3b2e449f-9e04-4852-82b7-f243e5ebb90a time: 2026-07-08T23:29:54-07:00 runtime: claude
… titlebar glass like the editor does Cut 7-12 (follow-up to 7-10's glide parity): the strip above the preview now dissolves gliding content the way the editor's scroll-edge effect does, instead of letting sharp glyphs ride between the toolbelt buttons. - Measured platform limit (probe app + live rig): CSS backdrop-filter is implemented via Core Animation backdrop capture, and CA refuses nested capture under the native titlebar glass — the identical rule blurs fine in a plain window and below the glass line, but under the glass it silently drops the whole effect including its mask. Native knob for WebKit's own scroll-edge blur stays private (7-10), and a non-zero obscuredContentInsets would re-introduce the hard-clip pocket. So the parity is the closest achievable approximation: a masked dissolve veil. - appearanceCSS gains a fixed body::after band owned by the measured glass-height var, painted in the native glass backing colour and mask-faded (black 50% -> 0.35 residual at the band edge, hidden in the chrome seam), pointer-events: none, zero layout impact. - The veil colour is plumbed by PreviewTitlebarGlassController alongside the height: WindowChromeRecipe.titlebarGlassBackingCSSColor resolves the one backing truth (textBackgroundColor) through the window's effective appearance to a concrete sRGB value, and viewDidChangeEffectiveAppearance re-plumbs on dark/light flips (same height, different colour — the guard tracks both). Verified on a live wrapper build (5-1R rig): dark + light scrolled show zero sharp glyphs in the band and class parity with the editor's fade; at-rest band is per-pixel identical to the native backing (30,30,30 dark) so the 7-9 stripe class stays dead, paper skin keeps its clean seam, glide and content start unchanged. 90/90 filtered tests, make lint exit 0. Authored-By: claude <agents@vetcoders.io> session_id: 36a46027-2e59-4086-9fe3-a7b517d19949 time: 2026-07-09T01:02:26-07:00 runtime: claude
Widen the native principal spacer between the share/dispatch group and the editor formatting group so the toolbar reads as two distinct islands instead of one continuous edit strip. Pin the spacer rhythm in EditorToolbeltTests while preserving the titlebar identifier order and MarkdownFormat allCases contract. Gates: swift build; swift test --filter 'Toolbelt|EditorToolbelt'; make lint. Authored-By: codex <agents@vetcoders.io> session_id: d546f5cd-fbe7-4315-b11d-652500b0a7bc time: 2026-07-09T01:05:00-07:00 runtime: codex
Move share and dispatch out of the principal toolbar strip and into their own automatic ToolbarItemGroup so macOS can render a separate native capsule next to the file title. Replace the old spacer-width regression pin with an explicit toolbar island order contract covering share/dispatch, edit, and trailing clusters while preserving the existing identifier order and MarkdownFormat allCases guard. Loctree-Recon: context atlas read; slice/impact EditorToolbelt; literal checks for ToolbarItemGroup/shareEditIslandGap/Color.clear Gates: swift build; swift test --filter 'Toolbelt|EditorToolbelt'; make lint; semgrep changed Swift files Screenshots: wide-open.png; narrow-open.png Authored-By: codex <agents@vetcoders.io> session_id: 019f45f2-cba3-76f2-9c3a-1b628cac2014 time: 2026-07-09T01:24:58-07:00 runtime: terminal
…ts across the whole glass band
Cut 7-12b (correction of 7-12's veil): the operator's screenshot showed
two defects in the dissolve band — a solid plate directly under the
toolbar buttons and the ghost zone hanging tens of pixels below them.
Row-probe measurement (5-1R rig, dark, split, scroll) found a single
root: the 7-12 mask ('black 50% -> 0.35') made the upper half of the
band 100% opaque, compressing all transmission into the bottom quarter.
The editor's native scroll-edge effect transmits ghosts across the WHOLE
band instead: ~9% at the window edge, ~15% mid-band, ~38% at 80%, ~55%
just above the chrome seam.
- Geometry hypothesis falsified by measurement: a diagnostic red-band
build showed the veil footprint at exactly 0..52pt == frame minus
contentLayoutRect, in BOTH window variants (direct file open and
in-place open from a workspace root) — the veil never painted below
the seam; no var fix needed.
- The mask is now a 4-stop gradient tracking the measured editor profile
(alpha = 1 - transmission): 0.92 0%, 0.86 45%, 0.62 80%, 0.42 100% —
no fully-opaque stop anywhere.
- Test pin updated and extended: the veil mask must never carry a 'black'
stop (the solid-plate failure class), with the measurement rationale in
a comment.
Verified pre-lock on the live rig (dark, scroll, max-over-5-scroll-offsets
row probe): preview transmission 0.08/0.12/0.15-0.25/0.41-0.55 vs editor
0.09/0.12/0.15-0.17/0.46-0.53 at matching band depths; ghosts start at the
same top edge in both panes, zero solid segment, zero dissolve below the
seam. At-rest dark band per-pixel uniform with the native backing (mean
30.0, var 0.0 outside static chrome). 90/90 filtered tests, make lint 0.
Light/sepia at-rest eyeball check blocked by session screen-lock mid-rig;
structural argument and follow-up noted in the cut report.
Authored-By: claude <agents@vetcoders.io>
session_id: 373cd437-c4cb-4dc0-a50c-6b9d73ad498d
time: 2026-07-09T01:53:03-07:00
runtime: claude
…ly owner of the veil mask profile Polarize L1, cut A: the last chrome number living outside WindowChromeRecipe was the preview veil's measured transmission profile (cut 7-12b row probe), hardcoded twice — in PreviewWebView's appearanceCSS gradient and again as a string literal in PreviewThemeTests. Move the stops into WindowChromeRecipe.titlebarGlassVeilMaskStops with a CSS-emitting accessor; the veil rule and its regression pins now both consume the Recipe, and new WindowChromeRecipeTests pin the measured curve, the no-opaque-stop constraint, and the downward-only dissolve. After this cut every chrome number, colour, and profile has exactly one home. Gates: swift build; swift test --filter 'Preview|Chrome|Toolbelt|Editor' (128 passed); make lint Authored-By: claude <agents@vetcoders.io> session_id: b1738e62-d46d-4c45-98c4-94a33e998270 time: 2026-07-09T12:58:29-07:00 runtime: claude
…oolbar layout truth Polarize L1, cut B: the 7-14 island split relied on mixing an .automatic share/dispatch group with a .principal edit island — a per-window system heuristic that rendered the capsule beside the title on one rig and to the RIGHT of the edit island on the operator's window (screenshot 12:41). Kill both placement modes: every group now uses the default placement, so the system renders TITLE, SHARE/DISPATCH, EDIT, MODES/THEMES strictly in declaration order. Island separation comes from native ToolbarSpacer(.fixed) behind #available(macOS 26.0, *) (the 7-14 SDK probe), and ToolbarSpacer(.flexible) keeps the trailing cluster on the window edge. Verified live on the installed /Applications build, dark + split: capsule order matches the operator contract. Gates: swift build; swift test --filter 'Preview|Chrome|Toolbelt|Editor' (128 passed); make lint Authored-By: claude <agents@vetcoders.io> session_id: b1738e62-d46d-4c45-98c4-94a33e998270 time: 2026-07-09T12:58:52-07:00 runtime: claude
…chrome geometry event Polarize L2: the preview's chrome offset still had TWO competing runtime truths. Pixel measurement on the operator-class window (evidence pair, scrolled minus at-rest) showed the editor ghosting 3-7/255 through the whole 52pt glass band while the preview transmitted EXACTLY 0/255, with content hard-clipped and WebKit's own fade at ~63-77pt and the page start parked ~50pt below the editor's — the double offset (WebKit pocket + CSS glass var). Root cause: WebKit re-adopts obscuredContentInsets on chrome geometry changes that give the container no layout pass (SwiftUI attaches the toolbar after the preview joins the window, shrinking contentLayoutRect silently); enforceFullBleedViewport only ran on layout()/viewDidMoveToWindow, and the 7-10 KVO channel refreshed the CSS var but never the insets. Fix: viewport enforcement now rides the glass controller's geometry channel — every event that funnels into apply() (attach, window notifications, contentLayoutRect KVO, navigation finish) re-zeroes the pocket first, even when the script guard short-circuits. Two new pins: controller runs the enforcer on every apply; integration probe simulates the silent re-adoption and drives the notification path back to zero insets. Gates: swift build; swift test --filter 'Preview|Chrome|Toolbelt|Editor' (130 passed); make lint Authored-By: claude <agents@vetcoders.io> session_id: 35ec1bf7-4697-48fb-91d8-7bf1ab50a28b time: 2026-07-09T13:19:35-07:00 runtime: claude
…S pocket on both panes Polarize L3 verdict from rig measurement: WebKit's auto-adopted obscuredContentInsets pocket renders the SAME native scroll-edge ghosts as the editor band (2-12/255 vs 3-11/255), while zeroing it painted scrolled text crisp through the window title (192/255). The pocket is the one chrome truth on macOS 26 for both panes — AppKit automatic content insets for the editor, the WebKit pocket for the preview. Dead mechanisms removed: viewport zeroing (L2 enforcer), the masked backing veil (7-12/7-12b) and its Recipe mask profile, the backing CSS variable and its plumbing. The glass controller survives only as the explicit pre-macOS-26 fallback for the CSS offset variable (0px default on 26). Verified on operator-class rig windows: dark/light, split, preview-only, tab bar (pocket auto-adapts 52->88pt), live resize. Authored-By: claude <agents@vetcoders.io> session_id: 45d7ed93-53cc-4206-97aa-af1d15a58f85 date: 2026-07-09T14:11:48 PDT runtime: claude time: 2026-07-09T14:11:54-07:00
…s into the Recipe Polarize L4 residual cut: PreviewTitlebarGlassController carried two static forwards (titlebarGlassHeight(frameHeight:contentLayoutHeight:) and titlebarGlassHeight(for:)) that re-exported WindowChromeRecipe's glass arithmetic under a second name, and PreviewThemeTests duplicated WindowChromeRecipeTests' delta test byte-for-byte against that shim (loct twins flagged the pair). One number, one name, one pinned test: the controller now consumes WindowChromeRecipe.titlebarGlassHeight directly and the duplicate test dies. No behavior change - the fallback path evaluates the identical function. Authored-By: claude <agents@vetcoders.io> session_id: 5cf8dff1-04da-46e8-9857-9631fb5ef190 date: 2026-07-09T14:29:56 PDT runtime: claude time: 2026-07-09T14:29:56-07:00
Consolidation + de-privatization for public release (stacked on #7)
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
Full-day stabilization pass on top of
fix/broken-native-toolbar-and-others(18 commits). Three blocks:1. Pre-PR audit follow-ups (findings-max audit of PR #6)
PENSIEVE_VIBECRAFTED_PATHenv override + home-relative default,LocalizedErrorwhen absent), workspace root falls back to the open folder, in-flight guard against double dispatch, report-path regex no longer matches URL substrings; tafla Shift+Return sends to editor only (agent dispatch is click-only by design)scripts/vendor-katex.sh, fonts embedded as data URIs) — math actually renders now, also in exports; assets cached after first read; inline-embed sanitization case-insensitiveVistaEngine.complete()is a hand-added stub returning""), so the default controller now has no engine and surfaces a clear error instead of loading the LLM to render nothing; model-init failure latch is engine-global with single-flight guard; mock moved to the test targetNSLogformat-string fixes, file-protection fallback logged, silent catches surfacedlibqube_ffi.dylibrepointed to@rpath(without thisswift testfails on every machine except the builder's — CI included);build-ffi.shapplies it on every sync;build-release.shhard-fails when the dylib is missing (the app links it unconditionally)2. Window/tab architecture rebuilt (tab per document, AppKit-first)
The
openWindow(value:)scene-per-document path presented a half-built window for its 0.5–1.2 s cold start; five suppression layers could not fully hide it, and re-clicks during materialization clobbered merge targets (duplicate windows). Document windows are now built directly in AppKit (DocumentWindowFactory) and attached to the native tab group before first presentation — the flash is impossible by construction, all suppression machinery deleted.@State→ window retain cycle broken)PENSIEVE_TRACE=1) for window/document flow3. Transcription
Known gaps (deliberate, follow-up rounds)
NSHostingView.sceneBridgingOptions)Test plan
make testgreen at every commit (336 tests at HEAD, +30 vs base: registry merge ordering, close/teardown, coalescing, zombie guards, autocomplete latch, transcription preparing state)make lintclean on touched files🤖 Generated with Claude Code