Skip to content

fix(agent): the cycle line counts rail vetoes and names the rail (#812) - #813

Merged
eaitbrahim merged 2 commits into
mainfrom
feat/summary-line-vetoed
Sep 24, 2026
Merged

eaitbrahim merged 2 commits into
mainfrom
feat/summary-line-vetoed

Conversation

@eaitbrahim

@eaitbrahim eaitbrahim commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Closes #812.

What changed

render_loop_result in keel/commands/trading.py now ends each cycle line with a vetoed=N token:

before: ... signals=3 blocked=0 entered=0 exited=0
after:  ... signals=3 blocked=0 entered=0 exited=0 vetoed=3 (account_dd_breaker_weekly)
  • N counts entries that were evaluated, not placed, and have a non-empty vetoed_by. It is one per entry, not one per rail (the same one-per-entry rule activity.summarise_cycle uses).
  • The overlay's blocked still differs from this line's. For one cycle, overlay blocked = line blocked + vetoed + unplaced entries no rail named. Both docstrings now say so; the old summarise_cycle claim that its counts were the line's is corrected.
  • Rail names come from one parse. The new guards.rail_name replaces three copies: activity._first_clause, doctor's inline split, and this token's.
  • The rail list names each distinct rail once, in first-seen order, using the leading clause of each violation string. The drawdown arithmetic stays in the JSON log. Bare routing-gate tokens such as max_entry_spread are passed through as-is.
  • When nothing was vetoed the line prints vetoed=0 with no parentheses, so a missing token never has to be read as zero.
  • Existing tokens keep their meaning and order. keel-live-run.sh greps only signals=[0-9]+.

Out of scope

  • vetoed= counts entries only. A rail-vetoed exit (for example base_balance refusing a sell) still prints exited=0 with no reason. None has happened in any log yet.
  • An unplaced entry with an empty vetoed_by (a paper no-fill, a declined confirm) is still not shown on the line. It isn't a rail veto, and adding it would mean choosing a separate token.

Verification

  • Wrote 4 tests first and confirmed they failed on the missing token. They compare the exact line or its exact tail, not substrings.
  • Mutants for "an empty vetoed_by counts as a veto", "count per rail", and "no dedupe" were each applied and each killed.
  • The cycle-line tests pair each entry result with its signal, as run_once does, so the FET test pins the real line, signals=3 … vetoed=3. guards.rail_name has its own parametrised test.
  • Full suite: 6684 passed, 3 skipped. ruff check, ruff format --check and mypy are clean.

🤖 Generated with Claude Code

`signals=3 blocked=0 entered=0` read as a silent drop when the rails had
refused every entry: `blocked` counts only entries withheld before
evaluation. The line now ends with `vetoed=N (rail, ...)`, one per entry,
each rail named once by its leading clause. Appended after `exited=` so
the `signals=` token keel-live-run.sh greps is untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eaitbrahim eaitbrahim added the fix Bug fix (groups under Fixes) label Sep 24, 2026
…lay differ (#812)

- guards.rail_name replaces the three copies of the violation parse
  (activity._first_clause, doctor's inline split, trading._vetoed_token).
- _vetoed_token and summarise_cycle now state that the overlay's blocked
  = the line's blocked + vetoed + unplaced entries no rail named, and that
  vetoed counts entries only.
- The cycle-line tests pair each entry result with its signal, as run_once
  does, so the FET test pins the real line: signals=3 ... vetoed=3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eaitbrahim
eaitbrahim merged commit e97b4ac into main Sep 24, 2026
4 checks passed
@eaitbrahim
eaitbrahim deleted the feat/summary-line-vetoed branch September 24, 2026 22:47
eaitbrahim added a commit that referenced this pull request Sep 25, 2026
…e switcher with no tokens (#818)

MINOR: #810 and #814/#816 add console features. No schema change since
0.16.0, so a deployment needs no `keel migrate` step beyond the usual
idempotent run.

What lands:

  #807 -- a quote-increment cache record predating quote_increment is a
  MISS, not an "unknown".
  #810 -- the refused view says how to get the address it asks you to
  paste; #817 fixes its duplicate `const note`, which blanked the console.
  #813 (#812) -- the cycle line ends `vetoed=N (rail, ...)`, so a rail
  veto no longer reads as a silent drop.
  #815 + #816 (#814) -- a console switcher beside the session chip.
  /api/config carries no session token; /switch/<port> redirects into the
  chosen console's own hand-off, local deployments only.

Eight workspace versions and the inter-package `==` pins move together,
plus the refreshed uv.lock the release workflow checks first.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug fix (groups under Fixes)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Summary line hides rail vetoes: signals=3 blocked=0 entered=0 reads as a silent drop

1 participant