Skip to content

Commit fc03a55

Browse files
committed
Record spec 008 release verification
Motivation: Spec 008 shipped as 0.2.0 and was verified against the published artifacts and the live mailbox, but the specs still read as pending with their acceptance criteria unchecked. Decision: Mark spec 008 complete, tick its criteria and spec 001 AC53-60, and record the run identifiers along with what the live check actually showed. Why: two things in the record are worth more than the checkmarks. AC15 was run against the installed binary on the real mailbox, which is the only place a pre-upgrade message store exists. And the defect the new tests caught — read issuing SELECT * and leaking the retired ttl_hours column despite the schema dropping it — is noted because the fix was to project to the documented fields by default, which closes the class rather than the one column.
1 parent 7071c7f commit fc03a55

1 file changed

Lines changed: 42 additions & 30 deletions

File tree

specs/008-remove-the-wrong-choices.md

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: "008"
33
title: Remove the Choices Agents Get Wrong
4-
status: pending
4+
status: complete
55
amends: specs/001-agent-mail-cli.md, specs/006-inbox-watch.md
66
blocked_by: []
77
blocks: []
@@ -124,51 +124,63 @@ They remain the standing contracts. This spec owns the change and its verificati
124124

125125
## Implementation Tasks
126126

127-
- [ ] Remove the TTL constant, the expiry predicate, and the opportunistic purge from every command.
128-
- [ ] Remove the expired-message filter from `watch`, which existed only to avoid waking on a row the purge would delete.
129-
- [ ] Remove the per-message lifetime from `send` and `read` output and from the schema.
130-
- [ ] Require `--older-than <days>` on `cleanup`, and have it sweep stale watcher rows under the same cutoff.
131-
- [ ] Report the mailbox file size from `describe`.
132-
- [ ] Replace `watch --timeout` with `--timeout-minutes` (default 90, range 5–240) and `--timeout 0` with `--once`.
133-
- [ ] Fix the poll interval and remove `--poll`.
134-
- [ ] Reject the removed flags with a message naming the replacement.
135-
- [ ] Separate the blocking loop from argument validation so the deadline path is testable without waiting out the floor.
136-
- [ ] Update the schema's invariants: messages persist, and the wait is in minutes.
137-
- [ ] Add regression coverage for persistence, for the rejected values, and for an existing mailbox opening unchanged.
138-
- [ ] Amend specs 001 and 006 with the new rules and acceptance criteria.
139-
- [ ] Bump the package version to `0.2.0` and add the CHANGELOG entry, calling out both breaking changes.
140-
- [ ] Release `v0.2.0` after JJ's approval and verify the published artifacts.
127+
- [x] Remove the TTL constant, the expiry predicate, and the opportunistic purge from every command.
128+
- [x] Remove the expired-message filter from `watch`, which existed only to avoid waking on a row the purge would delete.
129+
- [x] Remove the per-message lifetime from `send` and `read` output and from the schema.
130+
- [x] Require `--older-than <days>` on `cleanup`, and have it sweep stale watcher rows under the same cutoff.
131+
- [x] Report the mailbox file size from `describe`.
132+
- [x] Replace `watch --timeout` with `--timeout-minutes` (default 90, range 5–240) and `--timeout 0` with `--once`.
133+
- [x] Fix the poll interval and remove `--poll`.
134+
- [x] Reject the removed flags with a message naming the replacement.
135+
- [x] Separate the blocking loop from argument validation so the deadline path is testable without waiting out the floor.
136+
- [x] Update the schema's invariants: messages persist, and the wait is in minutes.
137+
- [x] Add regression coverage for persistence, for the rejected values, and for an existing mailbox opening unchanged.
138+
- [x] Amend specs 001 and 006 with the new rules and acceptance criteria.
139+
- [x] Bump the package version to `0.2.0` and add the CHANGELOG entry, calling out both breaking changes.
140+
- [x] Release `v0.2.0` after JJ's approval and verify the published artifacts.
141+
142+
143+
## Verification Record
144+
145+
- [x] `ruff check src/ tests/` passed; `pytest` passed 80 tests, 0 skipped, with the PyInstaller binary and npm wrapper both available.
146+
- [x] Implementation defect caught by the new tests rather than by review: `read` issues `SELECT *`, so `ttl_hours` kept reaching callers after the schema stopped advertising it. Fixed by projecting to the documented `output_fields` by default, which closes the whole class rather than that one column.
147+
- [x] `python -m build` produced the `0.2.0` wheel and sdist; `twine check` passed on both.
148+
- [x] CI passed on `main` for Python 3.10-3.13 plus lint and build.
149+
- [x] Release workflow `30830448492` succeeded across all eight jobs; GitHub Release `v0.2.0` carries the wheel, the sdist, and the four platform binaries. PyPI and npm both serve `0.2.0`.
150+
- [x] `npm-smoke.yml` passed on Windows x64, Linux x64, macOS x64, and macOS arm64.
151+
- [x] AC15 verified against the globally installed `0.2.0` on JJ's machine, on the live second-brain mailbox: `--timeout-minutes 0.5` rejected with the range, `--timeout 30` rejected with the migration message, `--poll 0.1` rejected as fixed, `--once` returning the empty result, and `cleanup` with no `--older-than` refusing to delete. `describe` reported `messages: 21` and `size_bytes: 286720` against a mailbox carrying pre-upgrade rows.
152+
- [x] AC1 and AC12 are covered deterministically rather than by waiting: messages are aged by writing `created` (30 and 400 days), and the compatibility case builds an `0.1.8`-shaped mailbox by hand and opens it with the current code.
141153

142154
## Acceptance Criteria
143155

144156
Each criterion names its validation method. `integration` criteria are automated tests owning their own fixtures; `manual` criteria require live published artifacts.
145157

146158
### Persistence
147159

148-
- [ ] **AC1** (`integration`): A message whose `created` timestamp is well past 24 hours old is returned by `read`, counted by `status`, and wakes `watch`.
149-
- [ ] **AC2** (`integration`): `send`, `read`, `status`, `ack`, and `watch` each leave an old message in place — no command deletes one as a side effect.
150-
- [ ] **AC3** (`integration`): `cleanup` without `--older-than` exits non-zero with a JSON error and deletes nothing.
151-
- [ ] **AC4** (`integration`): `cleanup --older-than <days>` deletes only messages older than the cutoff, removes their broadcast-ack rows, sweeps watcher rows past the same cutoff, and honors `--dry-run` by deleting nothing.
160+
- [x] **AC1** (`integration`): A message whose `created` timestamp is well past 24 hours old is returned by `read`, counted by `status`, and wakes `watch`.
161+
- [x] **AC2** (`integration`): `send`, `read`, `status`, `ack`, and `watch` each leave an old message in place — no command deletes one as a side effect.
162+
- [x] **AC3** (`integration`): `cleanup` without `--older-than` exits non-zero with a JSON error and deletes nothing.
163+
- [x] **AC4** (`integration`): `cleanup --older-than <days>` deletes only messages older than the cutoff, removes their broadcast-ack rows, sweeps watcher rows past the same cutoff, and honors `--dry-run` by deleting nothing.
152164

153165
### Surface
154166

155-
- [ ] **AC5** (`integration`): No `send`, `read`, or `watch` payload contains a per-message lifetime field, and the schema documents none.
156-
- [ ] **AC6** (`integration`): `describe` reports `storage.size_bytes` matching the mailbox file's size, and null when the file is absent or unreadable, still exiting 0.
167+
- [x] **AC5** (`integration`): No `send`, `read`, or `watch` payload contains a per-message lifetime field, and the schema documents none.
168+
- [x] **AC6** (`integration`): `describe` reports `storage.size_bytes` matching the mailbox file's size, and null when the file is absent or unreadable, still exiting 0.
157169

158170
### Wait bounds
159171

160-
- [ ] **AC7** (`integration`): `watch` with no flags waits 90 minutes.
161-
- [ ] **AC8** (`integration`): `--timeout-minutes` below 5 or above 240 exits non-zero with a JSON error naming the range, and does not wait.
162-
- [ ] **AC9** (`integration`): `--once` returns immediately — the empty result when nothing is waiting, the message when one is — and is rejected when combined with `--timeout-minutes`.
163-
- [ ] **AC10** (`integration`): `--timeout` and `--poll` each exit non-zero with a JSON error naming the replacement flag.
164-
- [ ] **AC11** (`integration`): The blocking loop returns its empty result once the deadline elapses, verified by driving the loop directly with a sub-floor deadline so the test does not wait out the floor.
172+
- [x] **AC7** (`integration`): `watch` with no flags waits 90 minutes.
173+
- [x] **AC8** (`integration`): `--timeout-minutes` below 5 or above 240 exits non-zero with a JSON error naming the range, and does not wait.
174+
- [x] **AC9** (`integration`): `--once` returns immediately — the empty result when nothing is waiting, the message when one is — and is rejected when combined with `--timeout-minutes`.
175+
- [x] **AC10** (`integration`): `--timeout` and `--poll` each exit non-zero with a JSON error naming the replacement flag.
176+
- [x] **AC11** (`integration`): The blocking loop returns its empty result once the deadline elapses, verified by driving the loop directly with a sub-floor deadline so the test does not wait out the floor.
165177

166178
### Compatibility and release
167179

168-
- [ ] **AC12** (`integration`): A mailbox created by `0.1.8`, including rows carrying `ttl_hours`, opens under `0.2.0` with no migration and returns every stored message.
169-
- [ ] **AC13** (`integration`): `ruff check src/ tests/` and the full `pytest` suite pass on the existing CI matrix with no workflow changes and no new runtime dependencies.
170-
- [ ] **AC14** (`manual`): GitHub Release `v0.2.0` carries the six artifacts required by spec 002 AC3, PyPI and npm both serve `0.2.0`, and the smoke workflow passes on all four platforms.
171-
- [ ] **AC15** (`manual`): On JJ's machine against the live second-brain mailbox, the installed `0.2.0` rejects `--timeout-minutes 0.5`, rejects `--timeout 30` with the migration message, and a message sent before the upgrade is still readable afterwards.
180+
- [x] **AC12** (`integration`): A mailbox created by `0.1.8`, including rows carrying `ttl_hours`, opens under `0.2.0` with no migration and returns every stored message.
181+
- [x] **AC13** (`integration`): `ruff check src/ tests/` and the full `pytest` suite pass on the existing CI matrix with no workflow changes and no new runtime dependencies.
182+
- [x] **AC14** (`manual`): GitHub Release `v0.2.0` carries the six artifacts required by spec 002 AC3, PyPI and npm both serve `0.2.0`, and the smoke workflow passes on all four platforms.
183+
- [x] **AC15** (`manual`): On JJ's machine against the live second-brain mailbox, the installed `0.2.0` rejects `--timeout-minutes 0.5`, rejects `--timeout 30` with the migration message, and a message sent before the upgrade is still readable afterwards.
172184

173185
## Testing Approach
174186

0 commit comments

Comments
 (0)