mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 13:22:19 +01:00
123 lines
7.7 KiB
Markdown
123 lines
7.7 KiB
Markdown
# Design
|
|
|
|
This document records why the recorder is built the way it is. It is organized as questions, because each answer is a
|
|
decision that could have gone another way. The facts in it were measured or read from the code, and where a reason is a
|
|
judgment it says so. It is written in the first person only where the decision was the owner's.
|
|
|
|
## Why record the screen, the log, the events and the OS trace together?
|
|
|
|
Most of the komorebi bugs I see show up when a laptop is docked or undocked, or wakes when the screen is opened. To
|
|
reproduce one, I had to watch the screen, hand-grep komorebi's log and export the system log from Console, and there was
|
|
no way to say: at 00:12.5 in the video, what was komorebi doing, and what was the OS doing? The recorder puts the four on
|
|
one clock so that the question has an answer, and so that the answer also works the other way, from a log line to the
|
|
moment in the video.
|
|
|
|
OS-level tracing is in scope because the interesting seam is between komorebi and the system, and between the system and
|
|
the application being tiled; komorebi's own log only shows one side of each.
|
|
|
|
## Why one clock, and why that one?
|
|
|
|
Every record is stamped on the host's monotonic clock (`mach_absolute_time` on macOS, `QueryPerformanceCounter` on
|
|
Windows) because the two sources that cannot be re-stamped are already on it: ScreenCaptureKit frame timestamps and the
|
|
unified log's `machTimestamp` on a Mac, and Windows.Graphics.Capture frame times on Windows. komorebi's log lines carry
|
|
UTC wall-clock time, so they are mapped onto the master clock with paired readings of both clocks (anchors) sampled while
|
|
recording, interpolated piecewise so that a step or a sleep between two anchors does not smear the mapping.
|
|
|
|
The alignment is as good as that allows: video to OS trace within about one frame, and video to komorebi's log within
|
|
about one frame plus the error of the wall-clock anchor, tens of microseconds.
|
|
|
|
## Why are fields called `*_mach_ns` on Windows?
|
|
|
|
They hold nanoseconds on the master clock, whichever clock that was. The spelling is historical and was kept: renaming
|
|
them would make a session written by one build unreadable by another. The manifest's `host.clock` says which clock a
|
|
session was on.
|
|
|
|
## Why does the recorder never change komorebi's log level or lifecycle?
|
|
|
|
That was decided at the start: the recorder only observes. It warns when komorebi is logging at a level that leaves out
|
|
most of what the window manager decided, and says how to restart it, but it never restarts komorebi or changes its
|
|
settings. (The reason for the decision is not written down anywhere the design could be checked against; this entry
|
|
needs the owner's words.)
|
|
|
|
## Why does the accept loop never block, and why is an event stamped when its handler finished?
|
|
|
|
komorebi connects to each subscriber synchronously and sends a notification while it holds its own locks, so a recorder
|
|
that was slow to read would stall komorebi. The accept thread stamps the arrival, reads, and hands the event to a channel;
|
|
a writer thread does everything else. For the same reason the per-event window probe (`--probe-windows`) runs on the
|
|
writer thread and never on the accept thread.
|
|
|
|
komorebi sends the notification after it has handled the event, so the stamp is when the handler finished. The start of
|
|
the handler is the `processing event` line in komorebi's log, which is why `trace` pairs the two.
|
|
|
|
## Why ScreenCaptureKit through `objc2` and not the `screencapturekit` crate?
|
|
|
|
The `screencapturekit` crate needs a Swift bridge at build time, which complicates the nix build. `objc2-screen-capture-kit`
|
|
and its siblings exist at the versions the rest of komorebi already uses, so there is no Swift and no Xcode dependency.
|
|
|
|
## Why fragmented mp4, and why re-submit the last frame?
|
|
|
|
A recorder that is killed, or a machine that loses power, must not lose the recording, and a plain mp4 is unreadable
|
|
until it is finalized. Fragmented mp4 plays up to the last fragment. Two measured facts decided the rest: ScreenCaptureKit
|
|
only emits frames when the screen changes, and fragments are cut on media time, so a static display never flushed a
|
|
fragment; the capture therefore re-submits the last frame to keep it moving. And the duration `ffprobe` reports for a
|
|
truncated fragmented file under-reads, so recovery asks AVFoundation instead.
|
|
|
|
## Why a new file for every segment?
|
|
|
|
Docking and undocking, sleep and lock change what can be recorded, and I want the recording to carry on through all of
|
|
them without losing what was already captured. A display that disappears has its video finalized on the spot, so the file
|
|
is complete and playable whatever happens next, and a display that returns starts a new segment in a new file. Every
|
|
display's segments are listed in the manifest with their time spans, so a gap is a fact the session states rather than a
|
|
hole.
|
|
|
|
## Why raw files plus an index, and not one file or a database?
|
|
|
|
The raw files are written as the data arrives and are never duplicated or rewritten; `timeline.jsonl` only references byte
|
|
ranges in them, so the streams stay separate and can be reconciled or re-indexed later. The index can be rebuilt from the
|
|
raw files at any time (`reindex`), including after a crash and after a hand edit.
|
|
|
|
## Why does reading a session never ask which host it is on?
|
|
|
|
A session recorded on Windows is investigated on a Mac, and the other way round. The host and the komorebi flavor are
|
|
recorded in the manifest, and everything that reads a session asks the manifest.
|
|
|
|
## Why can a bug only be marked in the viewer?
|
|
|
|
The Record tab has no button for marking a bug, and a session's tab has one. I found it confusing to have two places to do
|
|
the same thing, so a bug is marked in a session's tab only. `komorebi-recorder annotate` writes the same annotations for a
|
|
script or an agent that has no window.
|
|
|
|
## Why is there one window?
|
|
|
|
Recording and reviewing used to be two windows, and the recorder's buttons for opening a recording started the other one.
|
|
Now the recorder is the pinned first tab of the one window and each recording is a tab after it, so there is one thing to
|
|
keep out of the video and out of komorebi's layout. It starts small, always on top, with only the Record tab, which is what
|
|
the old recorder window was for, and grows when a recording is opened.
|
|
|
|
## Why is the window untitled?
|
|
|
|
komorebi does not manage windows with an empty title, so an untitled window is never tiled: opening the recorder
|
|
does not move the layout of the machine whose bug is being recorded.
|
|
|
|
## Why is ffmpeg not part of the program?
|
|
|
|
ffmpeg is used only to extract frames (`frames`) and to make test videos, and never for capture. It is in the dev shell and
|
|
not in the packaged binary.
|
|
|
|
## Why is a komorebi source from a different commit "skewed" by files and not by commit?
|
|
|
|
The recorder's own commits advance the repository's head without touching komorebi, so comparing commits calls almost
|
|
everything skewed. The files that differ between the commit a session recorded and the commit indexed are what say whether
|
|
a line of the log can still be traced to the statement that wrote it.
|
|
|
|
## Why is the hidden-window check skipped on Windows?
|
|
|
|
komorebi for Windows hides a window by cloaking it where it is, so a window's rectangle says nothing about whether it is
|
|
hidden. The check that flags a window parked off screen on the showing workspace holds only where komorebi hides windows
|
|
by moving them, so it is skipped on Windows, and `--probe-windows` reads the real state from Windows instead.
|
|
|
|
## Why do the Windows rules say they are unverified?
|
|
|
|
They were written from komorebi for Windows' source. Until a recording of it has been read, an analysis that uses them says
|
|
so; `Rules::verified` is the flag, and it is flipped once the first checks on a Windows machine confirm the rules.
|