Skip to content

THROWAWAY: tiny-skia drag fence diagnostics (do not merge) - #346

Closed
charliek wants to merge 10 commits into
mainfrom
debug/tinyskia-drag-diag
Closed

THROWAWAY: tiny-skia drag fence diagnostics (do not merge)#346
charliek wants to merge 10 commits into
mainfrom
debug/tinyskia-drag-diag

Conversation

@charliek

Copy link
Copy Markdown
Owner

Temporary diagnostic branch to capture CI-side evidence for the deterministic tiny-skia iced_clipboard_check.py drag-fence failure. Will be closed and deleted once the log is captured.

charliek and others added 9 commits August 16, 2026 01:49
…ib.sh

Pull the version derivation, libghostty-vt precondition, icon pipeline,
roostctl build+embed, and the signing machinery out of bundle.sh into a
sourced bundle-lib.sh, parameterized over (app dir, entitlements, config)
so plan 027's bundle-iced.sh can reuse them. Behavior-preserving: the
assembled Roost.app file set, Info.plist, entitlements, and identifier
are byte-identical before/after (evidence recorded with plan 027), and
the failure paths (missing archive/entitlements/codesign, with and
without ROOST_ALLOW_UNSIGNED=1) keep their exact semantics.

codex review finding (fixed): roost_workspace_version ran its pipeline
inside a command substitution, where bash 3.2 suppresses errexit — a
missing version line would have silently become 0.0.0 where the original
inline pipeline aborted under pipefail; now checked explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
bundle-iced.sh assembles mac/build/Roost-Iced.app from cargo build -p
roost-iced via the shared bundle-lib.sh stages: stamped Info-iced.plist
(id ai.stridelabs.Roost.iced, display/executable Roost-Iced, TCC purpose
strings kept, Sparkle keys deliberately absent so the two apps never
offer each other's updates), Roost-Iced.entitlements (mic/camera/
apple-events; disable-library-validation omitted — no embedded
frameworks), shared icon art, embedded roostctl, ad-hoc/dev-id signing.
New `make bundle-iced` target. Three more verbatim stages (skeleton,
plist stamp, PkgInfo) hoisted into bundle-lib.sh; Swift bundle
re-verified byte-identical after the hoist.

Live parallel-install verified on this machine: bundle launched via
open, answered identify (app_label Roost-iced) and screenshot on its own
socket while the production Roost.app kept answering on its own; quit
confirmed by pid. Evidence with plan 027.

codex review finding (fixed): a relative CARGO_TARGET_DIR misresolved
during binary discovery (cargo anchors it at the repo root where the
build runs; discovery anchored at the caller's CWD) — now anchored at
REPO_ROOT in both bundle-iced.sh and the shared roostctl stage, where
the same latent bug was inherited from the original bundle.sh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
…ck (M6 6a)

W3: on macOS the default profile kind now consults the main bundle
identifier (CFBundle via objc2-core-foundation 0.3, target-scoped;
rides the arboard/softbuffer objc2 0.6 generation) — a pure, table-
tested mapping where ai.stridelabs.Roost.iced and everything else
(including the unrecognized production id — the 6c cutover mapping is
deliberately not taken) resolve Iced, so behavior is unchanged today
and the identity is logged at startup ("resolved bundle identity
bundle_id=... profile=..."). ROOST_BUNDLE_PROFILE still wins; the
Linux linux-package logic is untouched. Seam-neutral wrt the 6b
decision (CoreFoundation, not AppKit).

W4: the window-title fallback is chosen from the resolved profile kind
(Iced → "Roost-Iced", Mac/Gtk → "Roost") via a new
window_title_with_fallback in roost-ui-model (existing window_title
delegates, signature stable; GTK path untouched). identify/app_label
unchanged on the wire.

codex review findings: (fixed) the fallback test bypassed
App::window_title — the branch structure is now a pure
compose_window_title both branches flow through, pinned by tests;
(skipped) the identity log is lost when profile resolution itself
fails before logging exists — pre-existing ordering (the log dir
comes from the profile), and the resolve error is the diagnostic in
that path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
When ROOST_ICED_APP names a Roost-Iced.app on macOS, the harness
launches the iced target through LaunchServices (open --env) via a
target-parameterized launcher: eager validation (never a silent
fallback to the bare binary), an enumerated env allowlist that
deliberately does NOT forward ROOST_BUNDLE_PROFILE (the C3 bundle-id
path is the thing under test — every bundle launch asserts the
"resolved bundle identity" log line), identify-pid adoption verified
against both the Roost-Iced process name and the bundle's own
executable path, pid-based SIGTERM→SIGKILL teardown with proof-of-death
before state cleanup, per-target log-offset diagnostics, and a
test-mode canary (tab.feed_pty_bytes round-trip in a throwaway project)
so a dropped ROOST_TEST_MODE fails loudly. New `make e2e-iced-bundle`
(macOS-guarded before any build work) runs the curated smoke +
walking-skeleton modules against the assembled bundle; 24→28 new unit
tests cover selection, validation, offsets, teardown.

codex review findings (all fixed): launch-failure paths now tear the
spawned bundle down before re-raising; adoption also checks the
executable path, not just the basename; a stale bundle pid is cleared
on the Popen path; teardown revalidates the pid before signalling
(macOS pid reuse); canary cleanup swallows only not-found; the canary
gate requires ROOST_TEST_MODE == "1" exactly, matching the Rust gate;
the log reader resets on rotation/truncation; the Makefile guard runs
before bundling; the adoption unit test asserts the real open argv.
Skipped (pre-existing generic-quit semantics shared with gtk/iced bare
targets): --roost-fresh against an unowned instance still waits on IPC
silence rather than pid death; adoption of a racing same-path instance
remains theoretically possible.

Verified live twice: make e2e-iced-bundle → 14 passed against the real
bundle; make test-harness → 99 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
… cells

New macbundle path filter (bundle scripts, iced plist/entitlements, and
the shared icon + roostctl-entitlements inputs) OR'd into
iced-build-e2e's condition — narrow by design so Swift-only PRs never
pay the 2x2 iced matrix. The macOS cells gain three steps: assemble
Roost-Iced.app (debug), a mechanical assertion block (bundle id,
executable, stamped version, no SU* keys, no Frameworks dir, deep
codesign verify, capture entitlements present AND true,
disable-library-validation absent, hardened runtime, otool -L closure
system-only), and the curated bundle smoke via ROOST_ICED_APP with
ICED_BACKEND from the matrix and distinct artifact dirs. Diagnostics
now also collect the bundle's persistent profile log, crash files, and
Roost-Iced*.ips (fnmatch is case-sensitive). Job timeout 30→40 for the
added pass. Assertion block verified locally against the real bundle
(all checks pass).

codex review findings (all fixed): filter was missing bundle-iced.sh's
shared icon/roostctl-entitlements inputs; entitlement checks now
require the value true, not mere key presence; the otool pipeline no
longer masks a missing/non-Mach-O binary as "no deps"; the bundle's
persistent log is collected explicitly (ROOST_E2E_LOG_DIR never sees
bundle-mode logs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
…adge op (M6 6b)

The 6b native-shim seam lands as crates/roost-iced/src/macos/ on the
objc2 route, decided by the C6 symmetric spike (both routes built live:
objc2 8/8 probe passes including a define_class! NSMenuItem action
calling back into Rust; the Swift static-lib route works but costs a
cargo-invoked swiftc toolchain and its best argument — import Sparkle —
does not survive the bare-swiftc shape). Deps are target-scoped at the
already-locked objc2 0.6 generation (arboard/softbuffer's; zero new
[[package]] entries; NSResponder included as NSApplication's
compile-required superclass).

First consumer, deliberately pulled forward from 6g: the dock badge
mirrors the notification-inbox count exactly as App.swift's
refreshDockBadge does (nil at zero), zero unsafe, synced on
window_opened and after every reconcile_notification_inbox — all on the
iced update loop via MainThreadMarker.

Test-mode op app.dock_badge ({"label": string|null}) reads the live
AppKit badge without re-deriving it; GTK rejects in the exhaustive
match, non-macOS iced rejects not-implemented, Swift verified live to
answer unknown-op (no case added). e2e test_dock_badge.py (darwin+iced
only) drives notification → "1" → "2" → clear → nil against a bundle
launch; wired into ICED_E2E_TESTS + the three full ci.yml lanes.
Documented in docs/reference/ipc.md.

simplify: single-caller apply() inlined into sync().
codex review findings (fixed): bootstrap's initial reconcile ran
sync_dock_badge before winit constructs the event loop, where
NSApplication::sharedApplication is documented-unsupported — now
guarded on window_id, the window_opened sync covers boot; non-macOS
iced answered not-enabled instead of not-implemented when test mode was
off — platform rejection now outranks the gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
…n 027)

6a's shipped shape (bundle-lib.sh + bundle-iced.sh, bundle-id probe,
title-fallback narrowing incl. the Linux dev-profile title change,
ROOST_ICED_APP harness path, CI macbundle lane, live parallel-install
evidence, ad-hoc CDHash/TCC caveat); the 6b decision record (objc2 over
a Swift static lib — both probes built and run, comparison table, what
6c/6d/6e inherit) replacing the pre-spike "leaning Swift lib" framing;
dock badge marked done under 6g as 6b's deliberately-pulled-forward
proof consumer; the stale entry-gate "remaining" sentence corrected
(iced-release CI shipped in plan 022; audit clean 2026-08-07).
make docs clean; list-nesting verified structurally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
…the bundle

CI's e2e steps set RUST_LOG=warn, which filtered the INFO-level
"resolved bundle identity" line out of the file log — the very line
every bundle launch asserts — so the macOS bundle smoke failed on CI
while passing locally (where RUST_LOG was unset and the default info
level applied). The forward now appends roost_iced=info when the
operator's filter doesn't name roost_iced, keeping an explicit
roost_iced choice verbatim. Reproduced and verified locally under
RUST_LOG=warn (14 passed); unit tests pin the floor, the verbatim
case, and the unset case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
…fixes

roost_find_cargo / roost_setup_cargo_profile / roost_cargo_target_dir
extracted so bundle-iced.sh and the roostctl embed stage share one
copy of cargo discovery, profile mapping, and CARGO_TARGET_DIR
anchoring (the comment said the paths must not diverge; a second copy
is what permits divergence). bundle-iced.sh's header no longer files
shared deferrals (notarize/DMG) under "unlike bundle.sh", and its
Developer ID bullet is gone — the script does sign with one when
ROOST_DEVELOPER_ID_IDENTITY is set. client.py's app_dock_badge
docstring now names the Swift app's unknown-op answer instead of
claiming every other UI says not-implemented. tempfile.mktemp replaced
with a uuid-based never-created path helper (ruff S306).

Verified: shellcheck clean, test-harness 101 OK, bundle rebuilt +
e2e-iced-bundle 14 passed.

Skipped (replied on the thread): the cross-language bundle-identity
consistency check — executable-name drift already fails the eager
Contents/MacOS/Roost-Iced validation, and app-id drift fails the
identity assertion with the exact wanted line quoted, so drift is loud
today; a three-way generator is more machinery than the risk warrants.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvCPrbetEKy3iHgKLQmwq
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0b3870bd-7141-42fd-83d0-bbbdc4a59720

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@charliek
charliek force-pushed the debug/tinyskia-drag-diag branch from 2d68daa to 2a570d6 Compare August 16, 2026 11:29
@charliek

Copy link
Copy Markdown
Owner Author

Diagnostics complete; root cause identified and the harness fix verified green on the previously-failing tiny-skia cell. Closing.

@charliek charliek closed this Aug 16, 2026
@charliek
charliek deleted the debug/tinyskia-drag-diag branch August 16, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant