Skip to content

Stabilization: pre-PR audit fixes, AppKit-first document tabs, transcription off-main#7

Merged
Szowesgad merged 211 commits into
mainfrom
fix/pr6-audit-fixes
Jul 10, 2026
Merged

Stabilization: pre-PR audit fixes, AppKit-first document tabs, transcription off-main#7
Szowesgad merged 211 commits into
mainfrom
fix/pr6-audit-fixes

Conversation

@m-szymanska

Copy link
Copy Markdown

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)

  • agent dispatch: launcher path resolved per machine (PENSIEVE_VIBECRAFTED_PATH env override + home-relative default, LocalizedError when 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)
  • preview/math: KaTeX 0.17.0 vendored (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-insensitive
  • autocomplete: the bridge has no completion FFI (VistaEngine.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 target
  • export: PDF no longer cropped to the first page
  • storage: NSLog format-string fixes, file-protection fallback logged, silent catches surfaced
  • build: vendored libqube_ffi.dylib repointed to @rpath (without this swift test fails on every machine except the builder's — CI included); build-ffi.sh applies it on every sync; build-release.sh hard-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.

  • click = new tab; already-open document activates its window; native tab-bar "+" opens an untitled tab (deferred, not dropped, during modals)
  • closed tabs: hosting-view teardown deferred one runloop turn (AppKit finishes the tab-group reshuffle first), registry rejects late accessor re-registration — no more ghost windows, no resurrecting tabs, no per-tab memory leak (window → SwiftUI @State → window retain cycle broken)
  • perf: accessor attaches coalesced (10–15 redundant calls per interaction in field traces → no-op passes skipped), launcher sweeps share one pending timer
  • opt-in runtime tracer (PENSIEVE_TRACE=1) for window/document flow

3. Transcription

  • whisper model init (dequantization, seconds of CPU) moved off the main actor — tapping Start no longer freezes the app (1.77 s+ hang reports); explicit "Preparing" state in the tafla; recording-state reset on stop failure

Known gaps (deliberate, follow-up rounds)

  • factory document tabs do not participate in window state restoration across relaunches
  • toolbar/title bridging for factory windows needs macOS 14+ (NSHostingView.sceneBridgingOptions)
  • real autocomplete blocked on vista-kernel shipping the completion FFI; vendored dylib is still a debug build (release rebuild needs vista-kernel on the builder's machine)
  • external opens (Finder) still spawn through the legacy WindowGroup scene path

Test plan

  • make test green at every commit (336 tests at HEAD, +30 vs base: registry merge ordering, close/teardown, coalescing, zombie guards, autocomplete latch, transcription preparing state)
  • make lint clean on touched files
  • manual: tab open/close/reopen cycles, drag-out + Merge All Windows, tafla Start without beachball — verified on silver (macOS 26 beta)

🤖 Generated with Claude Code

Szowesgad and others added 30 commits June 3, 2026 08:40
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
Szowesgad and others added 28 commits July 5, 2026 19:53
…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)
@Szowesgad Szowesgad changed the base branch from fix/broken-native-toolbar-and-others to main July 10, 2026 00:21
@Szowesgad Szowesgad merged commit 892d3d8 into main Jul 10, 2026
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.

2 participants