* feat(bookkeeping): bypassable chain-depth guard on corrections and stornos
Correcting or reversing an entry that already sits 3+ links deep in a
rattelse chain (correction_of_id/reverses_id walked in the DB, never
description matching) now throws CORRECTION_CHAIN_TOO_DEEP, steering the
caller to book ONE correction expressing the chain's net effect. Agents
looped storno+rattelse 10 deep on a live company (63/193 vouchers noise).
The guard is advisory, never a dead end: allow_deep_chain bypasses it on
every surface (correctEntry/reverseEntry option, REST body, MCP tool arg
staged through pending_operations, and confirm dialogs with Ratta anda /
Aterfor anda in the web UI). MCP staging pre-flight fires the guard at
stage time so the agent reconsiders in the same turn, and the executor
re-checks at commit. tools/list payload ceiling bumped 59K -> 59.5K for
the two bypass properties (trimmed to one sentence first).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(agent): retry the Bedrock stream once on transient failures
A transient stream death (429/5xx, transport cut, or the two known
stream-corruption signatures: 'Unexpected event order' and 'request ended
without sending any chunks') killed the whole chat turn, stranding the
user mid-answer. The turn now retries once per turn after a short backoff:
safe because nothing is persisted until finalMessage() succeeds. A new
stream_restart event carries the pre-attempt text snapshot so the chat
client resets the partial bubble, drops uncompleted tool chips, and shows
'Forsoker igen...' until the retried stream produces text. Non-transient
errors (403, 400) keep the existing immediate-error path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(api): regenerate accounted-api skill and wire allow_deep_chain through v1
apiskill:check failed: CorrectJournalEntrySchema gained allow_deep_chain,
making references/journal-entries.md stale. Regenerated (hand-applied: the
generator output is deterministic from the registry). While wiring: the v1
correct route validated allow_deep_chain but dropped it, and the v1 reverse
route's strict body schema would have rejected it outright, leaving API
clients no bypass when the chain-depth guard fires. Both now forward the
flag to the engine and document CORRECTION_CHAIN_TOO_DEEP as a pitfall.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: re-trigger CI after Vercel infra hang
The preview for e527e4044 compiled in 91s then hung 40 minutes in the
TypeScript phase and was killed with no error output; a CLI redeploy of
the identical code went Ready in 5m. Empty commit to refresh the git-
triggered deployment status.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(bookkeeping): address CodeRabbit review on the chain-depth guard
- correction-chain: report rootVoucher only when the walk reached a
genuine parentless root; a broken link, cycle, or hop-cap now yields
null instead of presenting an intermediate voucher as the chain root.
- recordate: propagate allow_deep_chain end-to-end (recordateEntry
option, route schema, and a Flytta anda bypass confirm in the dialog);
a date move is another storno+rattelse layer and carried the guard
with no override path.
- v1 correct/reverse: run the chain-depth guard before the dry-run
return so a dry run gives the same verdict as the real execution.
- dashboard reverse route: 400 on malformed JSON or a non-boolean
allow_deep_chain instead of silently reversing without the override;
empty body stays the supported no-body case. Tests added.
- AgentChat stream_restart: discard the dead attempt's reasoning and
re-arm the post-tool paragraph break so a retried turn doesn't render
thinking twice or glue its continuation onto restored text.
- v1 reverse route doc comment updated for allow_deep_chain.
Not changed: the journal-list reverse flow (flagged as a dead end) can
never receive CORRECTION_CHAIN_TOO_DEEP: the list renders Aterfor only
for entries that are neither storno nor correction, and such entries
have no backward chain links, so their depth is always 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(bookkeeping): recordate route test expects the new options arg
recordateEntry now takes { allowDeepChain } as a sixth argument; the
route test's called-with assertion predates it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>