diff --git a/plan/config.md b/plan/config.md index a3b4e8e0..b69bb870 100644 --- a/plan/config.md +++ b/plan/config.md @@ -67,7 +67,7 @@ and from `didbot-serve/src/routes.rs`'s constants rather than guessed: (`collection_grace`, matching `didbot_pds::blobs::BlobLimits`'s field, is the name already in use on that branch — this section should accept it under the same name rather than inventing a second one). Wired, except - `collection_grace_secs`, which has no reader on this branch to wire it to + `collection_grace_secs`, which is wired now, against `--blob-collection-grace-hours` to wire it to yet. - **`[names]`** — the naming spec or template, the fallback namer, the hold period. @@ -86,12 +86,6 @@ is wired to anything that runs; see "What this pass wires" below. ## Behaviours every section has to satisfy -- [ ] **An unknown key refuses startup**, named in the error. Serde's default - behaviour is to ignore a key it does not recognise, which produces a - server that looks configured and is not; `plan/policy-store.md` applies - the same fail-closed reasoning to a policy version that will not - validate, and `#[serde(deny_unknown_fields)]` is the same call made - here. - [ ] **A secret is a path, never a value.** The file names where a secret lives — the same shape `--secret-file` already established for the command line — and never carries one itself. A key that looks like it @@ -99,12 +93,6 @@ is wired to anything that runs; see "What this pass wires" below. every wired secret path today (`--secret-file`, `--operator-secret-file`); still open because `[attestation]`'s own `secret_file` field is schema only, not yet read by anything. -- [ ] **A secret file's permissions are complained about.** World- or - group-readable is reported by path and mode, before the secret is used - for anything — a complaint, not a refusal: a deployment that starts - with a loose file today keeps starting, on the theory that the - complaint is what changes that, not a crash nobody sees the reason - for. - [ ] **One stated precedence.** Command-line arguments win over the file, which wins over the environment, decided in one place (`didbot_config::precedence`) and documented there rather than @@ -159,6 +147,28 @@ pass: ## Done +- [x] **An unknown key refuses startup**, named in the error. + `#[serde(deny_unknown_fields)]` is on `Config` and on every section + struct in `crates/didbot-config`, so a key nobody recognises is a + startup failure rather than a server that looks configured and is not — + the same fail-closed call `plan/policy-store.md` makes for a policy + version that will not validate. Proven at both levels: + `an_unknown_top_level_key_refuses`, + `an_unknown_key_inside_a_known_section_refuses` and + `a_malformed_value_refuses_naming_the_problem` in the crate, and + `an_unknown_key_refuses_and_names_it` end to end through the binary. + +- [x] **A secret file's permissions are complained about.** + `didbot_config::secret::check_secret_permissions` masks `0o077` and + reports path and mode; `didbot-dev` calls it at both `--secret-file` and + `--operator-secret-file` parse sites, collects the findings into + `Args::permission_warnings`, and emits them once tracing is up — so the + complaint is not swallowed by a logger that did not exist yet. A + complaint, not a refusal, exactly as this item asked: tests + `a_loose_secret_file_is_complained_about_not_refused` and + `a_tight_secret_file_is_not_complained_about`, over four unit tests in + `secret.rs`. + - [x] **The `didbot-config` crate: a schema for every section, and the refusal behaviours proven against it.** Every section carries `#[serde(deny_unknown_fields)]`, so an unknown key or a malformed diff --git a/plan/e-stop.md b/plan/e-stop.md index cad4cc66..bdff89b7 100644 --- a/plan/e-stop.md +++ b/plan/e-stop.md @@ -63,9 +63,11 @@ control that is.** way to throw it — is the exact failure mode this epic exists to close. The denial-of-service surface this opens is real and is the trade this epic is deliberately making. -- Pause vs Revoke as distinct settings, with Pause leaving outstanding - sessions and writes untouched and Revoke ending them — and releasing a - Revoke does not resurrect what it ended. +- [x] **Pause vs Revoke as distinct settings**, with Pause leaving + outstanding sessions and writes untouched and Revoke ending them — and + releasing a Revoke does not resurrect what it ended (`Mode` and + `revoke_hook` in `crates/didbot-pds/src/estop.rs`). Written as a plain + bullet before, so it counted in no tally. - [x] **The pane**, the third of the epic's three ways to throw it, in `plan/ops-dashboard.md`'s dashboard: current state, what it is refusing, and the controls to throw and release it, with the same diff --git a/plan/scrobble.md b/plan/scrobble.md index 6d63e9b9..175ebdfb 100644 --- a/plan/scrobble.md +++ b/plan/scrobble.md @@ -15,8 +15,6 @@ Short-term, broadcast status: what an agent is working on, written when the model has something to say. The lexicon is settled and the tool exists. The last hop is missing — the tool does not write to a real server. -- [ ] **Wire the `PreToolUse` stamping to a real personal data server.** - Blocked behind [pds-writes](pds-writes.md). - [ ] **Decide on compaction.** A separate low-retention collection, or ordinary repository growth. Growth is fine at this volume and not at a swarm's. @@ -25,6 +23,18 @@ The last hop is missing — the tool does not write to a real server. ## Done +- [x] **Wire the `PreToolUse` stamping to a real personal data server.** No + longer blocked behind [pds-writes](pds-writes.md), which landed. + `a_hook_payload_becomes_a_record_and_the_account_goes_away` in + `crates/didbot/tests/hook_to_record.rs` drives the real hook through + `didbot_hookd::handle`, the real scrobble host + (`didbot_mcp::ScrobbleServer` over its `PdsClient`, posting + `com.atproto.repo.createRecord`) across a real TCP socket to the real + router, then reads the record back through `getRecord` and asserts its + text and emoji — and that the account is gone afterwards. + `a_session_that_opened_with_no_server_scrobbles_once_there_is_one` + covers the same path when the server arrives late. + - [x] The `com.vibescrobble.scrobble` lexicon, with text and a single-grapheme emoji. - [x] The MCP server, and the `PreToolUse` rewrite that stamps the acting