refactor: split the parser crate and move the recorder into the lib #14

Merged
natsukium merged 5 commits from refactor/split-record-and-format into main 2026-10-14 20:49:25 +09:00
Owner

Two structural changes, plus their cascade.

  • The recorder moves into the lib. record::run(socket, &RecordOpts) now mirrors serve::run(socket, cast, ServeOpts); main.rs is the command line alone (flags, file I/O, dispatch).
  • The parser becomes its own crate. The repo is a workspace in felis core's layout: crates/felis-cast-format (the parser, serde_json only) and crates/felis-cast (unit grammar, record, serve, CLI, every felis dependency). A program that only reads recordings, such as felis-reel, no longer builds felis at felis-cast's tag. just format-deps, now part of just check, refuses a felis crate in the parser's graph.

Why record and serve stay together and why the parser does not is in the new docs/explanation/architecture.md.

Also: mutants.out/ is ignored, the doc-cascade sweep greps crates/, and the README shows how to depend on the parser from git.

Verified: just check, just msrv, nix build .#default (71 tests in the sandbox), just fuzz 10, a git-pinned consumer of felis-cast-format resolving to serde_json alone, and the packaged binary recording a serve replay.

Two structural changes, plus their cascade. - **The recorder moves into the lib.** `record::run(socket, &RecordOpts)` now mirrors `serve::run(socket, cast, ServeOpts)`; main.rs is the command line alone (flags, file I/O, dispatch). - **The parser becomes its own crate.** The repo is a workspace in felis core's layout: `crates/felis-cast-format` (the parser, serde_json only) and `crates/felis-cast` (unit grammar, `record`, `serve`, CLI, every felis dependency). A program that only reads recordings, such as felis-reel, no longer builds felis at felis-cast's tag. `just format-deps`, now part of `just check`, refuses a felis crate in the parser's graph. Why `record` and `serve` stay together and why the parser does not is in the new `docs/explanation/architecture.md`. Also: `mutants.out/` is ignored, the doc-cascade sweep greps `crates/`, and the README shows how to depend on the parser from git. Verified: `just check`, `just msrv`, `nix build .#default` (71 tests in the sandbox), `just fuzz 10`, a git-pinned consumer of `felis-cast-format` resolving to serde_json alone, and the packaged binary recording a `serve` replay.
`serve` was a lib module behind a thin CLI shell, but `record` lived
inline in main.rs, mixed with flag parsing: the recorder, the theme
hint, and the file rendering shared a 930-line binary with the
command line. The two halves of the tool were shaped differently for
no reason, and the recorder's tests could only sit inside the binary.

`record::run(socket, &RecordOpts)` now mirrors `serve::run(socket,
cast, ServeOpts)`: the lib does the session work and main.rs reads the
flags and does the file I/O on both sides. `BoxErr` moves to the crate
root since both modules report it.
The parser keeps `msg` opaque so a program that only reads recordings
needs no felis types, but the crate around it linked felis-client-core,
felis-transport and tokio for `record` and `serve`. Such a program
still compiled all of that at felis-cast's felis tag. felis-reel is
one: it pins its own felis revision for its renderer, so depending on
the parser built felis twice.

The repo is now a workspace in felis core's layout. `felis-cast-format`
holds the parser and depends on serde_json alone; `felis-cast` holds
the unit grammar, `record`, `serve` and the CLI, and every felis
dependency. `just format-deps`, part of `just check`, refuses a felis
crate in the parser's graph, so the boundary cannot erode silently.

Cargo features on one crate were the alternative. They leave the
boundary to every consumer turning the defaults off, and any crate in
that consumer's graph that turns them back on brings felis back without
a warning. The argument, and why `record` and `serve` stay together,
is the new docs/explanation/architecture.md.
A `just mutants` run writes mutants.out/ at the repo root, and nothing ignored it, so a plain `git add -A` after a sweep staged the run's logs.
The sources moved under crates/, so the sweep's grep over src/ found nothing and a stale doc path in a source comment would go unnoticed.
docs: show how to read a recording from Rust
All checks were successful
ci / cargo fmt / clippy / test / deny (pull_request) Successful in 1m51s
ci / cargo fuzz smoke (pull_request) Successful in 1m58s
ci / cargo fmt / clippy / test / deny (push) Successful in 37s
ci / cargo fuzz smoke (push) Successful in 1m59s
dca9baa671
The parser is now a crate a program can depend on without felis, but nothing told a reader its name or that it lives inside this repo's workspace, where Cargo finds it by package name from the git URL.
natsukium deleted branch refactor/split-record-and-format 2026-10-14 20:49:25 +09:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
natsukium/felis-fcast!14
No description provided.