catnip 0.2.1 — a leather tannery, and a fix it surfaced
Added
-
tannery/— a leather tannery.catnip-collectruns the fetch daily
at 05:07,catnip-reportwrites the deterministic report an hour and
forty-five minutes behind it, andcatnip-prowlhunts every third day.
The gaps are headroom, not estimates: the fetch is serial and paginated so
its duration tracks repo count. Overrunning one is safe by construction —
the store has not advanced, the interval guard refuses, and the report
recordsskippedrather than describing yesterday as today. -
Per-turn tool scoping, which is the reason to use leather here at all.
Each agent is multi-turn and a turn replaces its tool scope rather than
extending it, so an agent reaches only what its current turn declares:catnip-collect catnip-pipeline -> catnip-inspect -> catnip-record catnip-report catnip-inspect -> catnip-report-write -> catnip-record catnip-prowl catnip-evidence -> catnip-file -> catnip-publishcatnip-collectcannot write state while the pipeline turn runs.
catnip-reportcannot reach the writer before reading the store's newest
day.catnip-prowlcannot file during the turn it gathers evidence and
cannot gather more once filing starts, so everything it files came from
evidence already in context. That replaced a paragraph asking the agent to
test before filing: there is now no turn in which it can do otherwise. -
Provenance as argument validation.
catnip_prowl_findingrejects any
tieroutsidemeasured|inferred|speculativeand anyevidencethat does
not name the catnip tool the claim rests on. No path through the toolset
records an untagged or unsourced claim. Refutations have their own tool,
because a cycle with none tested nothing, and publishing fails on an empty
cycle rather than writing an empty file. -
make smoke-toolsexecs every read-only tool's real argv straight from
shell-tools.json, so an argv or quoting regression surfaces before the
scheduler hits it at 05:07 with nobody watching. It is what caught
catnip view why. -
--why-view, andcatnip view why <view>in the dispatcher.
Changed
- Funnel
views/uniqrenamed topgviews/pguniq. They sum GitHub's
top ten paths and are not repo traffic, but wore names every other view
uses for something else. One repo read 10/10 where its real figures were 19
views from 1 unique visitor:pguniqcounted one person once per page, and
pgviewscaught ten of nineteen because ten paths is all the API returns.
Re-sourcing them from the store would have been worse — the store's window
and the paths snapshot genuinely disagree, so real windowed traffic beside
path-derived depth trades a naming problem for an arithmetic one. bin/catnipruns insidemain(). bash reads a script incrementally,
andcatnip runis a 41-minute job; rewriting the file in place mid-run
moves the bytes under bash's stored offset. Measured: an unwrapped script
loses the rest of its body, a wrapped one always completes. Not a total
fix — bash may still read garbage aftermainreturns and exit non-zero
having done all the work. Treat a trailing syntax error from a run that
otherwise reported success as this, and check the store, not the exit code.
Fixed
- Tannery timeouts are sized from a measurement instead of the first
draft's guess. The draft of this release boundedcatnip_runat 2100
seconds without measuring anything; a real run took 2459. Shipped as
drafted, shell-mcp would have SIGKILLed the pipeline 35 minutes into its
first scheduled cycle and the agent would have reported a timeout. Now
5400s/6000s/6600s, innermost-first, roughly twice the measurement. The
same draft told the agent to expect "10–20 minutes", which would have made
a normal 41-minute run read as anomalous; the prompt now states the
measured duration. catnip view why <view>had never worked. It took the view name from
--timeframe, which argparse restricts to1d/1w/2w/all/epoch, so the
name was rejected and a bareview whyasked derive for the derivation of
"2w". It is how both the README and thecatnip-prowlskill say to read
a derivation from a shell — the third instance of the same defect after
catnip reportshipping undispatched andcatnip config --jsoncolliding
with its own mutually-exclusive group.- Printing a derivation no longer requires a populated store. A
derivation is documentation, not data; it rode the same path as the views
and so failed on a fresh install — exactly when someone asks what a number
will mean before collecting any. attribution()returned different keys depending on whether the window
was empty, and the view read the missing one unconditionally, so an empty
window raisedKeyErrormid-render inside curses. The test asserts the two
returns carry identical key sets rather than the one key that was missing.- Config tests compared a resolved path to an unresolved tmpdir, which
fails only on macOS, where/varis a symlink to/private/var. Caught by
the cross-platform matrix, which runs onmainand on any PR carrying the
full-testlabel.