Public contract: serialized candidates carry their catalog reasoning effort (D-057, #148) #149
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
P1
P2
P3
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Creatidy/scarcity-router!149
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "contract/reasoning-effort-serialization"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Extends the public recommendation contract (issue #148, decision D-057): every serialized
CandidateEvaluationnow carriesselected,alternatives,excluded,closest_candidatesandrecoverable_candidates— one representation, no specialselectedshape.ModelCatalogEntrythat participated in ranking, as a required construction argument (a candidate evaluation cannot exist without its catalog provenance). Never reconstructed fromModelIdentity.variantor any other opaque identity; no new inference rule.null≠"none":nullmeans unconfigured;"none"is the real configured effort.docs/machine-interfaces.md(D-039eligibilityprecedent). Envelopeschema_versionstays1; no compatibility serializer./v1/select, MCPscarcity_select, authenticated control/v1/selectand the remote bridge with zero transport-adapter logic.Motivating consumer evidence: Creatidy Kernel K8 issue #11 — its public-contract gate failed because
/v1/selectcould not convey the exact execution configuration without forbidden inference (in the shipped catalog,identity.variantnames coincide with effort names — a calibration coincidence, not a contract). Recorded as evidence only; repositories are not coupled operationally.Changes
scarcity_router/selector.py—CandidateEvaluation.reasoning_effort(required, construction-validated against the frozenREASONING_EFFORTSvocabulary), always-presentto_dict()member, andreasoning_effort=entry.reasoning_effortat all seven_evaluate_candidateconstruction sites. Nothing else.tests/test_selector.py— newReasoningEffortSerializationTests(9 tests): decision-wide catalog provenance walk, independent alternative efforts, capacity-excluded/recoverable and closest-candidate preservation, explicit-null for unconfigured,"none"serializes as"none", variant≠effort proves no inference, ranking still consumes the catalog effort, constructor rejects out-of-vocabulary values. Updated the one assertion that pinned the old contract (assertNotIn("reasoning_effort", ...)).tests/test_interfaces_guardrails.py—test_select_reasoning_effort_parity(direct == CLI == REST == MCP, key present on every candidate list, values match the catalog) andtest_remote_select_passes_reasoning_effort_through_verbatim(bridge neither strips nor invents).tests/test_control_api.py—test_authenticated_select_decision_carries_reasoning_effort(real authenticated server, bearer client key).docs/machine-interfaces.md(additive v1 note on/v1/select),docs/selection-policy.md(supersedes the D-032 "public explicit effort output is deferred" sentence),docs/architecture.md, and the D-057 record indocs/decisions.md.Not changed
Selector ranking, capability ratings, model identity semantics, execution routing/gateway behavior, provider telemetry, request contracts. No account/access-mode/business-model fields; no Kernel-specific code.
Validation
uv sync --only-dev,make check(2112 tests OK),uv run basedpyright(0 errors, 0 warnings, 0 notes),git diff --check— all green on the reviewed head.origin/develop..HEADcontains exactly this change (single commit, no merge commits); touched files in scope.Notes for review
developduring investigation and one on this branch each hittest_e2e_execution…test_scenario_11_cancel_reaches_exactly_the_owning_workerunder load; it passes 8/8 in isolation on both — the known load-sensitive race family tracked in issue #143, unrelated to this diff.security_critical(no credential, network-exposure, auth or storage change) — no daybreak gate required.Reviewed head:
2ffc224— frozen for review; no pushes during the review window. PR left open for human merge gate; workers never merge.Independent review record (bounded review lifecycle)
2ffc224(origin/develop..HEAD= exactly one non-merge commit; no pushes during review)security_critical, so no daybreak gate is required — recorded perdocs/llm-operating-policy.md)VERDICT: APPROVED
MERGE_BLOCKER: none.
Verified against the code (not the PR text):
reasoning_effortis an unconditional member ofCandidateEvaluation.to_dict();null= unconfigured, distinct from"none".REASONING_EFFORTSvocabulary; all 7_evaluate_candidatesites passentry.reasoning_effort(the only construction sites in the codebase) — catalog provenance guaranteed, no variant reconstruction path exists._ranking_key,select_model,effort_by_identityuntouched; the effort tie-break still sources from catalog entries. Fulltests.test_selectormodule (89 tests) green."none"-vs-null, and whole-document parity across direct/CLI/REST/MCP/remote-bridge each fail under their target regression.DEFER (awareness only, no action required for this diff):
tests/test_interfaces_guardrails.py— theclosest_candidates/recoverable_candidateswalk is vacuous in thedeep_codingparity scenario; real coverage comes from the core-level tests plus full-document equality on every surface.model-catalog.jsonhas no unconfigured or"none"-effort entries; thenullvs"none"distinction is exercised via synthetic fixtures (correct vehicle per repo fixture policy).reasoning_effortmid-field-list insertion changes the frozen dataclass's positional construction signature; all production and test sites use keyword arguments (verified) — internal-API only.Gate evidence at reviewed head:
make check2112 tests OK;uv run basedpyright0 errors/0 warnings/0 notes;git diff --checkclean. One full-suite flake observation (test_scenario_11_cancel_reaches_exactly_the_owning_worker, passes 8/8 isolated on branch and pristine develop) recorded on issue #143.No remediation round required. PR left open, unmerged for the human merge gate; workers and reviewers never merge.