# Changelog

All notable changes to spt-pacer-tool (formerly spt-rebound-tool; renamed in 0.3.0).
Versions match `[adapter].version` in `manifest.toml` — that manifest field is the
version of truth. Sections below 0.3.0 predate the rename and keep their published
wording, "rebound" included.

## [0.7.0] — 2026-08-30

> Requires spt-core **v0.67.0 or newer** (up from 0.64.0 — the session-boundary events below need it).

### Changed
Pacer now learns that your agent's context was reset — a `/clear`, a `/compact`, or a fresh start — from the event spacetime sends it, instead of by re-reading your agent's recent history on every check. The reminder it sends after a reset is unchanged in wording and timing. Two things get better: a reset that happened while pacer was briefly down is no longer missed, and a reset older than the slice of history it used to read is no longer invisible.

### Fixed
A reset that happened while pacer was restarting used to be skipped. Pacer could not tell a reset it had already reminded you about from one it had simply never seen, so on starting up it treated all of them as already-handled — which was right for the ones it had seen and wrong for the rest. Resets now arrive as individual events, so each one is reminded about exactly once, whether or not pacer was running when it happened.

### Performance
Pacer no longer reads your agent's recent history on every single check. That read now happens only when there is something specific to fetch — a message long enough to have been cut short, where the rest has to be looked up. On a quiet session that is one fewer background command every cycle.

## [0.6.1] — 2026-08-28

### Changed
Pacer's `status` answer now lists the session events it received **broken down by kind**, instead of a single total plus a count of the one kind it acts on. The total on its own could not tell two different sessions apart — one that received a particular kind of event and one that did not produced exactly the same line — so it could not be used to check whether something was arriving. The counts were always available; only the report pooled them. Everything else about `status` is unchanged, and unfamiliar kinds are counted under their own name rather than dropped.

## [0.6.0] — 2026-08-28

Pacer reads your control codes from spacetime's published event feed instead of parsing your session log. Requires **spacetime v0.64.0 or newer** — read **Changed** before upgrading.

### Changed

- **Your codes now reach pacer by a supported route.** `!!done!!`, `!!wait=m!!` and `!!classify=…!!` used to be found by pacer reading your session's own log and looking for them. Spacetime now publishes what you said at the end of a turn as a proper event, delivered straight to pacer, so pacer reads a surface that is meant to be read instead of one it was guessing at. Nothing changes about how you write a code, and a code inside backticks or a fenced block is still ignored exactly as before.
- **A code at the end of a very long turn is no longer at risk of being missed.** Delivered events are capped in size, and the cut falls at the end of a turn — which is precisely where a code sits. When pacer receives a cut event it now goes and fetches the full text before reading it, so a long turn ending in `!!done!!` is treated the same as a short one.
- **`status` now reports what the feed delivered.** The answer gained a line counting the events pacer has received, how many carried your turn output, how many codes it read out of them, and — kept separate and always shown, including as zeros — the two cases where a code *could* have been missed. If pacer ever seems to be ignoring you, that line is the first thing to read.
- **This release requires spacetime v0.64.0 or newer.** The event feed above arrived in v0.64.0. The requirement is enforced when pacer is installed or updated, so an out-of-date spacetime refuses the update with a reason rather than leaving you with a pacer that silently never reads another code.

### Removed

- **The "last code acted" field is gone from `status`.** It reported a position in your session log, which is no longer where codes come from; left in place it would have shown a number frozen at whatever it last saw, which reads like live state and is not. The new event counters replace it.

## [0.5.1] — 2026-07-27

### Added

- **pacer now tells you which version is talking.** The onboarding reminder and the `status` answer end with a `pacer vX.Y.Z` stamp naming the version of the code actually running — so if an update ever leaves an older copy running underneath you (it happened in the field: a pre-update copy kept answering for hours), one glance at the reminder in your scrollback or one `spt shell cmd PACER-0 status` settles which code you are talking to. Stretch reports are deliberately left unstamped to stay short.

## [0.5.0] — 2026-07-27

The stretch model is reworked around one live board, and the extend command from 0.4.0 is removed — read the **Removed** section before upgrading.

### Changed

- **One stretch at a time, running until you classify it.** pacer now keeps a single live stretch per endpoint — born when the shell comes online or when you classify the previous one — and it keeps running, busy time included, until a classification ends it. Nothing closes a stretch behind your back anymore: going back to work no longer finalizes a number, it just reports where the stretch stands.
- **`!!wait=m!!` now marks a checkpoint on the live stretch.** Besides deferring the next nudge as before, each wait you declare adds a numbered checkpoint (`:1`, `:2`, …; `:0` is the stretch's start). The last 10 checkpoints are kept — older ones roll off. Nudge behavior itself is unchanged (`!!done!!` too).
- **Stretch reports are now the board.** When you come back to work after a minute or more of quiet, pacer sends one stretch id with its checkpoints, newest first, each showing the wall-clock time since it was marked — for example `:2 ~1m` up to `:0 ~21m`. One id per report, always; the old multiple-ids-in-flight model is gone.
- **Classifying names a checkpoint, and ends the stretch.** The classify forms now take the checkpoint designator: `!!classify=x7au34-2:ci_run!!` inline, or `spt shell cmd PACER-0 classify x7au34-2 ci_run`. The time folded into the average is exactly the number the board showed for that checkpoint. One classification per stretch: it clears the whole board and a fresh stretch begins on the spot. The old designator-less form (`!!classify=x7au34:ci_run!!`) no longer works — add the checkpoint number.
- **Status and the reminders teach the board.** The `status` answer names the live stretch id, its checkpoint range, and whether a report has anchored the numbers yet; the periodic reminder teaches waits-as-checkpoints and the designator classify form.

### Removed

- **The extend command is retired — breaking.** Both `!!extend=m!!` and `spt shell cmd PACER-0 extend <minutes>` are gone: with the live stretch running until classified, there is nothing left to bridge by hand — a wait marks a checkpoint instead. The command now answers a one-line pointer (`extend was retired in 0.5.0 — wait now extends the live stretch`); the inline code is inert text.
- **The claimable-ids window is gone.** Stretch ids from before an update or restart are no longer classifiable: a restart starts a fresh stretch by design. Your classified wait averages are untouched and still survive restarts and updates.

## [0.4.0] — 2026-07-27

Three additions: a wait can now outlive a busy blip without splitting in two, stale wait classes can be removed, and a command pacer cannot use gets an answer instead of silence.

### Added

- **Extend: one wait, one report, even across a busy blip.** Sometimes the agent answers a message mid-wait — the stretch report arrives, but the same wait goes on. The agent can now say so: `!!extend=m!!` inline (or `spt shell cmd PACER-0 extend <minutes>`, 1 to 1440) bridges the most recent stretch for m minutes, so going busy and idle again inside that window no longer cuts the wait in two. Written while the agent is busy, it reopens the stretch that was just reported — and when the wait finally ends, pacer re-reports the **same stretch id** with the full start-to-end duration, superseding the earlier partial number. Classified averages stay honest: one wait, one number. Extending is measurement only — nudges and their widening intervals run exactly as before (use `!!wait=m!!` to defer a nudge; the two compose). Extending a stretch that was already classified is declined: classification is final.
- **Retire: remove wait classes you no longer track.** `spt shell cmd PACER-0 retire "ci_run peer_wait"` (space-separated names) removes each named class and its running average from the registry, and the answer confirms each one — what was removed, with its final average and count, and which names matched nothing. Deliberately a command only, with no inline code form: registry surgery is an operator's deliberate act, not something to trip over mid-sentence.
- **Commands that cannot be used are refused out loud.** A pacer command with a wrong or missing argument — or naming a stretch id or class that does not exist — used to do nothing, silently, and reading that silence cost a real debugging session in the field. Every such command is now answered with a one-line refusal saying what was wrong (for example `⟳ **pacer** refused extend: needs whole minutes 1..=1440`), delivered quietly on the agent's own poll like every pacer answer. Only authenticated commands are answered — a line that fails the authenticity check is still dropped in silence, since a forger earns no hints. Inline `!!…!!` codes are unchanged: a malformed code has no reply channel and is simply not a code.

### Changed

- **Status and the reminders teach the new surfaces.** The `status` answer now shows a standing extend bridge and its remaining minutes, and both the status tail and the periodic reminder mention `!!extend=m!!` and `retire` alongside the codes the agent already knows.

## [0.3.0] — 2026-07-27

The rename release: rebound is now **pacer**, and it installs in one command.

### Added

- **One-command install.** `spt adapter add --release BigscreenVR/spt-pacer-tool --gh` then `spt shell spawn PACER` — that is the whole install. The release archive now carries the `pacer-shell` binary for every supported platform (Windows x86_64, Linux x86_64 glibc and musl), and spt-core 0.44.0+ launches it straight from the adapter's install directory. The old separate download-the-binary-onto-your-PATH step is gone, and `spt adapter update PACER` now updates the binary along with the manifest (restart the instance to pick it up).
- **Stretch reports.** When the agent comes back to work after a quiet stretch of a minute or more, pacer now tells it how long that stretch actually lasted — final duration, to the second (`8m20s`), with the wall-clock time it ended — delivered quietly on the agent's own poll so it never interrupts. Stretches shorter than a minute are turn-boundary noise and are not reported. Every report also shows the agent its classified wait averages so far.
- **Classify: name a wait, and pacer keeps the average.** Each reported stretch carries a short id (like `abc234`). The agent can label it — `!!classify=abc234:ci_run!!` inline, or `spt shell cmd PACER-0 classify abc234 ci_run` from outside — and pacer folds that stretch's duration into a per-name running average (snake_case names, up to 32 chars). Averages accumulate per endpoint across restarts, so over time the agent learns what a normal `ci_run` or `peer_review` wait looks like — and a drifting average is a signal in itself. Ids stay claimable while they are among the last 10 unclassified stretches; classifying is final, one label per stretch.
- **State survives restarts.** The wait averages, the claimable stretch ids, and the record of which steering codes were already obeyed now live in a small file under the adapter's own install directory (`state/<endpoint>.json`). A pacer that restarts picks up where it left off — and a steering code it acted on before the restart is never obeyed twice.

### Changed

- **rebound is renamed to pacer.** The tool paces an agent; it never reported liveness outward, so the old name's "heartbeat" reading was exactly what it is not. The adapter id is `PACER` (caps), so the instance you address and the sender you see are the same string: `spt shell cmd PACER-0 status`, and every message it sends you now arrives from `PACER-0` instead of an anonymous sender — you can always tell your pacer from a fellow agent. The repo is `BigscreenVR/spt-pacer-tool`, the binary is `pacer-shell`, and the steering codes are unchanged (`!!done!!`, `!!wait=m!!`).
- **Clean-break upgrade, by hand once.** There is no in-place update from `rebound` 0.2.x to `PACER` 0.3.0 — the adapter name changed, so re-register: `spt shell teardown rebound-0`, `spt adapter remove rebound`, then `spt adapter add --release BigscreenVR/spt-pacer-tool --gh` and `spt shell spawn PACER`. Old-repo links redirect, but update your bookmarks.
- **Requires spt-core 0.44.0 or newer.** That release resolves a shell's launch binary from the adapter's own install directory, which is what makes the one-command install below possible.

## [0.2.2] — 2026-07-26

One fix: a wait that outlived the work that should have ended it.

### Fixed

- **Going back to work now always clears a standing wait, even when rebound did not see it happen.** rebound learns that an agent is working from a state signal that carries only the current state and can be missed — if the agent went to work and finished again between two checks, or a check failed, all rebound saw afterwards was "still idle" and it kept counting down the old wait. A wait of half an hour could therefore stand through an interaction that had already put the agent back to work, and no nudge came when it should have. The signal also says *when* the current state began, and rebound now reads it: a state that started later than the stretch it was counting means the agent worked in between, so the wait is cleared, the countdown restarts from that moment, and the pacing returns to its base interval — the same result as if rebound had watched it happen.

## [0.2.1] — 2026-07-26

Two fixes: a steering code that could be silently discarded, and rebounds that outlived their own restart.

### Fixed

- **A `!!wait=m!!` written at the end of a turn is now honored.** A wait code written in the turn an agent is finishing lands at the same instant that agent's endpoint goes quiet, and rebound could read it a fraction too early — while it still saw the agent as working. It then discarded the wait and nudged after the usual minute anyway, so the code looked like it was obeyed at random: honored at half-hour gaps for a whole morning, then swallowed three times running in an afternoon. A wait now always applies to the quiet stretch the turn is ending into, whichever signal arrives first. `!!done!!` was never affected.
- **`status` now reports a wait it is holding** for the quiet stretch the agent is about to enter, so a code that landed is distinguishable from one that did not.
- **A rebound left behind by a restart now stops itself.** Bringing an instance back online starts a fresh rebound, but the previous one kept running — extra background processes that also kept the `rebound-shell` file open, which on Windows blocked replacing the binary with a new one. A superseded rebound now exits on its own.

## [0.2.0] — 2026-07-26

The first release with binaries. rebound no longer needs a Rust toolchain to install, and it can now report what it is doing.

### Added

- **Prebuilt binaries.** This release carries `rebound-shell` for Windows (x86_64) and Linux (x86_64, glibc and musl), with `SHA256SUMS` published beside them. Download the one for your platform onto your PATH, then `spt adapter add --release BigscreenVR/spt-rebound-tool --gh` and `spt shell spawn rebound`. The binary is a separate step because spt-core looks up a shell adapter's launch command on your PATH, not in the directory the release unpacks into — so a release can ship the binary but cannot place it. The README has both install paths.
- **`spt adapter update rebound`** now works: rebound ships its own updates from its GitHub releases, so the adapter stays current without re-registering it by hand. It updates the adapter, not the binary — replace that from the release assets when a new one ships, and rebound says so when it updates.
- **A `status` command.** `spt shell cmd rebound-0 status` asks a running rebound what state it thinks it is in: whether it is paced or paused, whether the endpoint is busy or idle and for how long, how long until the next nudge, where it sits on the widening interval, and the last steering code it acted on. It changes nothing, and the answer arrives as a message to the endpoint rebound is pacing. Previously there was no way to ask — the only way to find out whether rebound had armed was to wait and see whether a nudge arrived.

### Changed

- **`!!done!!` is described accurately now.** The nudge text and the reminder rebound sends after a context reset used to present the code as an open-ended "blocked on a human" signal. What it has always done, and still does, is cover **the current idle stretch**: anything that puts the agent back to work — a message from a peer included — starts the pacing again. Both messages now say so, and tell a still-blocked agent to re-emit the code. **No behavior changed** — only the wording, which had set the wrong expectation and cost a real agent a confusing hour in the field. The corresponding line in the 0.1.0 notes below is superseded by this one.

## [0.1.0] — 2026-07-25

First release. A source release: install with a Rust toolchain (`cargo install`), against spt-core 0.42.0 or newer. Binary archives for users without a toolchain are not shipped yet.

- rebound pings an idle agent back into motion. While its rebound latch is raised, a busy-to-idle edge on the bound endpoint arms a timer, and if the endpoint is still idle when the timer elapses, rebound sends an idle-only ephemeral message that reappears in the agent's inbound and provokes a turn.
- An unanswered ping re-arms on a widening interval — 60s, 2m, 5m, 15m cap. Any return to busy resets it to the base interval. rebound never gives up and never escalates to anyone else: it is a purely inward nudge and reports nothing outward.
- The agent steers its own pacing with inline codes read from the session digest: `!!done!!` lowers the latch when blocked open-endedly on a human, and `!!wait=m!!` defers the next ping by m minutes when waiting on a peer or a task with an ETA. The `pause` and `delay` capability verbs do the same from outside.
- Resuming work re-raises the latch automatically, so a paused agent that starts working again is paced again without anyone re-arming it.
- rebound re-explains its own codes to the agent on first launch and after every context boundary — clear, compact, or boot — because a reset agent has no memory of them.
- Owner-private by design: one instance per owner, no broadcast, and every ping goes only to the endpoint that owns the instance.
- Install: `cargo install --path .`, then `spt adapter add .`, then `spt shell spawn rebound`. `spt shell teardown rebound-0` stops it.
