Build: ModelClient + the Append-Only Log
Maps to: Task 7. Kind: Build.
Objective
Create the panoptes-harness crate. Define the ModelClient trait (with #[async_trait]) and ModelResponse. Write the append-only JSONL writer and the test that guards its most important property: a second append must not overwrite the first.
Scaffold
Create (new crate — add it to workspace members):
crates/panoptes-harness/Cargo.toml—[dependencies]:panoptes-core = { path = "../panoptes-core" }, plusserde,serde_json,reqwest,tokio,async-trait,chrono,sha2,clap,anyhow(all{ workspace = true });[dev-dependencies]:wiremock = "0.6",tempfile = "3". (sha2is for the dispatch chapter's response-id hashing — the original task plan omits it there, so declare it now.)crates/panoptes-harness/src/lib.rs,src/client.rs(the trait),src/jsonl.rs(the writer).
Dependencies this chapter exercises: async-trait, serde_json (one record per line), tempfile (dev).
Expected result: cargo test -p panoptes-harness jsonl → 1 test passes (appends_without_truncating).
The spec (givens)
ModelResponsefields:text: String,usage: Usage(from core). Derives:Debug, Clone.- The trait:
#[async_trait] pub trait ModelClient: Send + Syncwith exactly two methods —fn model_name(&self) -> &str(the pinned model string) andasync fn generate(&self, prompt: &str) -> anyhow::Result<ModelResponse>(single-turn; the prompt is the entire input). append_record(path: &Path, rec: &ResponseRecord) -> anyhow::Result<()>— opens withOpenOptions::new().create(true).append(true), writes oneserde_jsonline.
Full code: Answer Key, Task 7.
Concepts exercised
- Defining an async trait with
async_trait. std::fs::OpenOptionswith.append(true)for append-only semantics.- Testing filesystem behavior with
tempfile.
The build loop (you drive)
- Write the failing test
appends_without_truncating: write two records, assert the file has two lines and each is valid JSON. - Predict: what would the test show if you opened the file with
.create(true).write(true)instead of.append(true)? (This is the bug the test exists to catch.) - Run, check.
- Implement the writer.
- Run green, commit.
responses.jsonl is the dataset of record — the thing the repo archives and a replicator re-analyzes. If a run could truncate it, a single mistake destroys evidence. The append-only test encodes that the log only ever grows.
Done when
cargo test -p panoptes-harness jsonl passes and the append-only property is proven.