plans/ held 58 documents and exactly one said whether it was open. The rest
mixed finished work, reviews of shipped work, parked specs and genuinely
pending ones, with nothing distinguishing them, so "how many plans are in
the queue" had no answer short of reading all 58.
Now `grep -H '^Status:' plans/*.md` is the answer:
50 done 3 in progress 2 planned 2 reference 1 parked
Statuses were derived rather than guessed: CLAUDE.md's own built list and
"What's NOT built yet" section, plus checking the subject exists in the
code. A review of work that shipped counts as done -- it records what was
found, it is not a request for anything. `reference` separates the two docs
that are conventions rather than work items (admin-design-standards,
admin-work-framework), which otherwise read as permanently-open plans.
The vocabulary is deliberately five words. A larger one invites "mostly
done" and "blocked-ish", which is how the directory became unreadable.
test_plans_declare_status.py keeps it from rotting: a new plan without a
marker fails, as does an unknown status, one buried below the eighth line,
or an open status with no reason -- "planned" alone is the state that rots,
since nobody can tell later whether it waits on a decision, a dependency,
or just nobody's turn.
Also updates the sweep plan with what landed and what did not, including
that #9 was not a defect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
174 lines
8.6 KiB
Markdown
174 lines
8.6 KiB
Markdown
# flex-preference-knob review
|
|
|
|
Status: done -- review of shipped work
|
|
|
|
Source: manual review (this session) of `65da4a1` ("feat(routing): add
|
|
flex-preference knob for -flex variant selection") against
|
|
`.omo/plans/flex-preference-knob.md`. Full suite is green (601 passed) and
|
|
the plan's stated behavior — swap only the serving class, never the base
|
|
model, re-price on swap, log telemetry — checks out. One finding, confirmed
|
|
live against `routing.py` and against the current catalog, not just read off
|
|
the diff.
|
|
|
|
---
|
|
|
|
## 1. A flex swap bypasses every hard filter except latency
|
|
|
|
**File:** `routing.py`, `apply_flex_preference` (~line 195-269), called from
|
|
`dispatcher.route()` (~line 798-811).
|
|
|
|
**Problem.** `get_flex_sibling` is deliberately structural — it matches a
|
|
row by `base_model_id`/`reasoning_mode`/`context_variant` + `latency_class ==
|
|
"flex"` and nothing else. Its own test says why that's fine:
|
|
|
|
```python
|
|
def test_flex_sibling_ignores_stale_or_unroutable_flex_rows():
|
|
# The helper is purely structural: it matches by identity dims regardless
|
|
# of freshness/access. Routing-level gating is the caller's job.
|
|
```
|
|
|
|
But the caller — `apply_flex_preference` — never does that gating. It
|
|
checks exactly one thing before swapping: `latency_tolerance == INTERACTIVE`
|
|
(for `prefer-flex`; `force-flex` doesn't even check that). It never re-runs
|
|
`rejection_reason`/`is_eligible` against the sibling, so a swap can hand back
|
|
a row that `select_candidates` would have thrown out for being stale,
|
|
deprecated, outside `allowed_access_levels`, under-tiered, or missing a
|
|
required capability. The comment justifying the latency-only check —
|
|
"the only hard filter that distinguishes it is the latency filter" — is an
|
|
assumption about the catalog, not something the code checks, and the live
|
|
catalog already violates the premise: `glm-5.2` (`access_level: canary`) and
|
|
`glm-5.2-flex` (`access_level: public`) share `base_model_id`/
|
|
`reasoning_mode`/`context_variant` and differ in access level, not just
|
|
latency class. Nothing stops that divergence from appearing in the other
|
|
direction (a `-flex` row going stale, deprecated, or more restricted than
|
|
its standard sibling) — the poller marks `stale`/`deprecated` per row from
|
|
each row's own `last_updated`, and access level is parsed from the
|
|
provider's free-text description per row (`poller.parse_access_level`),
|
|
independently for every `model_id`.
|
|
|
|
Confirmed live, calling `apply_flex_preference` directly:
|
|
|
|
```python
|
|
>>> from routing import apply_flex_preference
|
|
>>> std = {"model_id": "kimi-k3", "base_model_id": "kimi-k3",
|
|
... "reasoning_mode": "default", "context_variant": "full",
|
|
... "latency_class": "standard", "cost": 0.01,
|
|
... "proficiency_score": 0.9, "cost_score": 0.5, "composite": 0.9,
|
|
... "cost_per_1m_prompt": 1.0, "cost_per_1m_completion": 2.0}
|
|
>>> stale_flex = {**std, "model_id": "kimi-k3-flex", "latency_class": "flex",
|
|
... "availability": "stale"}
|
|
>>> apply_flex_preference(std, [std, stale_flex], "force-flex", "interactive",
|
|
... prompt_tokens=1000, completion_tokens=400, cache_rate=0.5)
|
|
({'model_id': 'kimi-k3-flex', ..., 'availability': 'stale'}, True, True, ...)
|
|
```
|
|
|
|
and the same for an access-restricted sibling under `prefer-flex`/`batch`
|
|
(no `force` needed — `prefer-flex` doesn't check access either):
|
|
|
|
```python
|
|
>>> canary_flex = {**std, "model_id": "glm-5.2-short-flex",
|
|
... "latency_class": "flex", "access_level": "canary"}
|
|
>>> apply_flex_preference(std, [std, canary_flex], "prefer-flex", "batch",
|
|
... prompt_tokens=1000, completion_tokens=400, cache_rate=0.5)
|
|
({'model_id': 'glm-5.2-short-flex', ..., 'access_level': 'canary'}, True, False, ...)
|
|
```
|
|
|
|
Both swaps go through with no error, and `dispatcher.route()` puts the
|
|
result straight into `RouteResponse.selected` — there is no gate between
|
|
`apply_flex_preference` and the actual provider call. A restricted-access
|
|
swap dispatches to a model the account almost certainly gets a 403 from; a
|
|
stale/deprecated swap dispatches to a row the freshness filter exists
|
|
specifically to keep traffic away from. This is exactly the "silent empty
|
|
axis" failure class the project has hit before (the `6e729ad`/`1d1f3af`
|
|
seed-sweep crash, the `client_capped` over-marking) — a real check exists
|
|
elsewhere in the codebase (`rejection_reason`) and this new path just
|
|
doesn't call it.
|
|
|
|
Not just access/freshness: the same gap covers `required_tier`,
|
|
`effective_context_window`, `min_tool_proficiency`, and the vision/json-mode
|
|
capability gates, for the same reason — none of them are re-checked on the
|
|
sibling. Access and staleness are the two proven-live cases; the others are
|
|
plausible but unconfirmed against current data.
|
|
|
|
**Fix.** `apply_flex_preference` needs the same filter arguments
|
|
`select_candidates`/`rejection_reason` already take, and must refuse the
|
|
swap unless the sibling clears them. The cleanest way to get "every filter
|
|
except latency" without a second copy of the rule is to call
|
|
`rejection_reason` on the sibling with `latency_tolerance` forced to
|
|
`BATCH` (which always admits flex rows), so only the non-latency filters can
|
|
reject it:
|
|
|
|
```python
|
|
def apply_flex_preference(
|
|
selected_row, all_candidates, flex_preference, latency_tolerance,
|
|
*, prompt_tokens, completion_tokens, cache_rate,
|
|
required_context_tokens, required_tier, allowed_access_levels,
|
|
exclude_stale, exclude_deprecated, min_tool_proficiency=None,
|
|
require_vision=False, require_json_mode=False,
|
|
) -> tuple[dict, bool, bool, float | None]:
|
|
...
|
|
sibling = get_flex_sibling(selected_row, all_candidates)
|
|
if sibling is None:
|
|
return selected_row, False, False, selected_row.get("cost")
|
|
|
|
# The sibling is a different catalog row and can independently be stale,
|
|
# deprecated, access-restricted, or under-tiered -- BATCH is used here
|
|
# only to neutralize the latency filter itself, which prefer-flex/
|
|
# force-flex evaluate separately below.
|
|
if rejection_reason(
|
|
sibling,
|
|
required_context_tokens=required_context_tokens,
|
|
required_tier=required_tier,
|
|
latency_tolerance=BATCH,
|
|
allowed_access_levels=allowed_access_levels,
|
|
exclude_stale=exclude_stale,
|
|
exclude_deprecated=exclude_deprecated,
|
|
min_tool_proficiency=min_tool_proficiency,
|
|
require_vision=require_vision,
|
|
require_json_mode=require_json_mode,
|
|
) is not None:
|
|
return selected_row, False, False, selected_row.get("cost")
|
|
...
|
|
```
|
|
|
|
`dispatcher.route()` already builds exactly this filter set as `filters`
|
|
(line ~749-762, used for `select_candidates`) — pass it through to
|
|
`apply_flex_preference` rather than assembling a second, narrower one.
|
|
|
|
**Test to add** (`tests/test_routing.py`, next to the existing
|
|
`test_apply_force_flex_*` cases): a flex sibling with `availability="stale"`
|
|
and one with `access_level="canary"` (allowed levels `["public"]`), under
|
|
both `prefer-flex`/batch and `force-flex`/interactive — assert no swap
|
|
(`flex_swapped is False`, original `selected_row` returned) in all four
|
|
combinations. `tests/test_route_decisions.py`'s `decision_router` fixture
|
|
only ever inserts `CHEAP_FLEX` as `public`/`active`; add a second flex
|
|
fixture row with `availability="stale"` for an end-to-end version of the
|
|
same check through `/route`.
|
|
|
|
---
|
|
|
|
## Everything else checked out
|
|
|
|
- `get_flex_sibling` is pure, O(N), matches the plan's three identity
|
|
dimensions exactly, and correctly returns `None` when the selected row is
|
|
already flex.
|
|
- `route_decisions` migration (`ensure_route_decisions`) is a proper
|
|
idempotent `ALTER TABLE ... ADD COLUMN` guarded by `PRAGMA table_info`,
|
|
matching the `proficiency_store.ensure_columns` pattern this project
|
|
already uses elsewhere.
|
|
- `flex_preference`/`flex_swapped`/`flex_forced` telemetry is wired
|
|
correctly end-to-end: `RouteResponse` → `persist_route_decision` →
|
|
`route_decisions` INSERT → SSE event payload. This was the one thing
|
|
flagged as worth re-checking when the config-default question was settled
|
|
([[project-flex-preference-knob]]), and it holds up — confirmed by reading
|
|
the full call chain, not just the happy-path tests.
|
|
- Cost re-estimation on swap reads the sibling's own
|
|
`cost_per_1m_prompt`/`cost_per_1m_completion` via `estimated_cost`, and
|
|
carries over `proficiency_score`/`cost_score`/`composite` from the ranked
|
|
winner so the returned dict stays a well-formed `Candidate` — correct,
|
|
since a flex twin ties its standard sibling on every scored dimension by
|
|
construction.
|
|
- `no-flex`/`auto` are true no-ops (never swap, never touch an
|
|
already-flex winner for `no-flex`), matching the plan.
|
|
- Full `pytest` (601 tests) and `python config.py` both pass clean.
|