RheoclesREE-oh-kleez

Draft. Written against the spec, ahead of the code. The words are the intent; the software is not there yet.

Troubleshooting

The things that go wrong, what they look like, and what they mean. Most of them are macOS telling you something quietly.

Nothing prompts, and nothing records

You arm a camera, macOS does not ask, the row goes ochre, and the file is empty. Open System Settings → Privacy & Security → Camera: Rheocles is not in the list.

That is not “denied”. An app that has never been able to ask does not appear at all, and there are two ways to be unable to ask under the hardened runtime: a missing Info.plist usage description, or a missing entitlement. Both are required. A release build from this repo has both; a local build signed differently may not.

If you are building from source, codesign --verify will report the bundle valid even when --deep has skipped an executable in Contents/Resources. Only notarisation catches it. Sign inside out.

Displays are missing after granting Screen Recording

The grant takes effect on the daemon’s next launch, not the current one. Quit Rheocles and open it again; GET /streams then lists every display and permissions.screen reads authorized. The first stream list in a fresh process is what raised the prompt, and that process keeps the answer it had when it started.

Arming answers 403

permission_denied: macOS has not granted the device class this stream needs. For camera and microphone the prompt is raised first, so a 403 means it was refused — the grant is under System Settings → Privacy & Security. For system audio the grant is System Audio Recording, under Screen & System Audio Recording.

Arming answers 503

device_unavailable: the device is gone, busy, or refused the configuration. A camera another app holds exclusively, a display that was just unplugged, a window that closed between the list and the arm. Refresh the list and try again; if it persists, the device is the problem, not the request.

The armed camera is 720p

Arming takes the device’s current format and holds the configuration lock for the whole armed period. A camera another app left at 720p stays at 720p until that app or the user changes it. active on the stream says what you will get; set the format in the other app, or disarm, change it, and arm again.

framesSeen is not counting

An armed stream that delivers frames counts up. One that does not is stuck — a window that went off-screen, a device that stalled — and a take started now would record nothing from it. Disarm and arm again; if it stays at zero, the device is not delivering.

The port is in use

The daemon comes up on 7447 and 7448. If another daemon is already there — the NativePHP app’s, or one left over — the app uses it rather than starting another, which is the intended behaviour. If something else is on 7447, the app says so and will not start a daemon until the port is free. Sonocles is on 7357 and 7358 and does not collide.

409 conflict on create

The destination already exists and is not empty. Rheocles never silently suffixes a path — a client that named a path meant it. Pass overwrite: true if you meant to replace it, or name it something else. The same code answers start on a take that is not created and stop on one that is not recording.

409 take_active on create

A take is recording, and the error names it. One active take at a time in the MVP; stop it first. A take that was created but never started does not block — the next create supersedes it and its manifest reads incomplete, reason superseded before start.

The manifest says superseded before start

You created a take, never cued it, and created another. Nothing but the manifest ever existed for the first one, so it is marked and left. It is not an error; it is the record of a take that did not happen.

Create refused for disk space

The pre-flight estimated the take’s size from the armed set’s measured bitrates and expectedDuration (default thirty minutes) and found the free space short. The error carries both numbers. Free space, shorten the estimate if you know the take is short, or disarm the stream that is costing the most.

The manifest says incomplete

A write failed mid-take — the disk filled, a volume unmounted, a device disappeared — and Rheocles stopped cleanly rather than continuing with a lie. reason says what. Every file is playable up to the last fragment, and the manifest is truthful about what it has.

The manifest says recording and nothing is running

The daemon died mid-take. The files are fragmented MOVs and play to their last fragment; the manifest has every stream’s started and timecode. Nothing needs reconstructing — but nothing will mark the take complete either, and the state is the honest one.

Requests answer 401

The token does not match. It was rotated in the popover — rotation invalidates the old token for everyone — or the client is reading a stale copy. Re-read ~/Library/Application Support/Rheocles/token.

My late-joined file lands before the take

The stream joined after midnight into a take that started before it. Its time-of-day timecode is near zero, and the editor placed it twenty-four hours early. Every camera and field recorder shares this; there is no fix inside the file. Place it from the manifest’s started, which is absolute UTC — see Timecode and sync.

Two files are a frame apart

Look at drift for each stream in the manifest, in seconds. A capture device’s clock is not the host’s, and a long take can drift by a frame or two; the number is measured per stream and is there to conform with. An absent drift means it was not measured — a stream that wrote no frames — and is not the same as 0.

Six cameras are still armed

The mark in the menu bar is drawn in outline and the popover rows are ochre. That is what armed looks like, and armed streams cost CPU and hold their devices until you disarm them. Nothing disarms on your behalf.