Skip to content

terse stats attributes break-even to the wrong ledger label: --server-name wraps are keyed on the interpreter basename (searxng-mcp inherits demo rows, secret-broker reads as never called) #285

Description

@inth3shadows

terse stats derives each wrapped server's ledger label from the downstream command, ignoring --server-name. Every wrap that uses --server-name therefore gets a break-even row built from the wrong rows — or from another server's rows.

src/terse/stats.py:1052:

labels = peers if is_router else ([server_label(wraps.split())] if wraps else [])

wraps is the post--- command. --server-name (added in #83) is exactly the flag that overrides what the proxy writes to server in the ledger, and it is not consulted here. The comment above the line — "the ledger keys on server_label of that, not on the MCP entry name" — was true before #83 and is now false for any entry that passes the flag.

Two live failures, both in my current fleet

1. Cross-attribution. searxng-mcp wraps .venv/bin/python -m searxng_mcp → label python, which collides with the unrelated python / demo_orders ledger rows:

  server         primer          blocks saved/block   cadence     to break even
  searxng-mcp       312               3       1,130        1x              0.28

--json shows the attribution outright:

"server": "searxng-mcp", "ledger_labels": ["python"], "blocks": 3,
"saved_per_block": 1130.0, "blocks_to_break_even": 0.276,
"contributors": [{"label": "python", "blocks": 3, "saved_tokens": 3390}],
"verdict": "KEEP", "verdict_reason": "cleared"

Those 3,390 tokens are demo_orders (6,152 → 2,762). searxng-mcp's own two rows are labeled searxng-mcp and sum to 338 saved over 2 blocks = 169/block → 1.85 blocks to break even, not 0.28. The verdict is right by luck; the number behind it is another server's.

2. Silent under-report. secret-broker wraps .venv/bin/python3 -m secret_broker → label python3, which matches nothing:

  secret-broker     248               0           –       1x-      never called

Same run, the per-tool table shows it plainly was called:

secret-broker  secret.list_credentials  21 blocks  222,496 -> 89,992  59.6%

So the table calls the fleet's second-best compressor "installed but not triggered, so costing nothing at all". That is the verdict #175 exists to prevent, inverted.

Note both failure directions are reachable: a colliding label can manufacture a KEEP, and a missing one can manufacture "never called". Neither is distinguishable from a real measurement in the rendered table.

Why the existing guards don't catch it

_break_even's vocabulary is careful about unknown-vs-zero (no ledger label, never called, no token data), but every one of those describes a missing label. There is no state for a label that resolved successfully to the wrong thing, which is the case here — python is a real label with real rows.

Suggested fix

Capture --server-name during the config scan and prefer it as the label, falling back to server_label(command) only when the flag is absent. The scan already parses the proxy argv far enough to split on --; the flag sits on the left of that split and is currently discarded.

Worth considering alongside: server_label(command) yielding a bare interpreter name (python, python3, node) is never a usable label and is what makes the collision reachable at all. Treating those as "no ledger label" would fail loudly instead of silently borrowing another server's savings, even before the --server-name fix lands.

Test

Two ledger rows under --server-name-tagged labels plus one row under the interpreter basename; assert the wrapped entry's contributors name only its own label, and that a python-command wrap with no matching rows reports never called rather than inheriting the demo rows.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions