feat(BA-6889): add kernel scheduling-history query conditions and orders#12867
Draft
jopemachine wants to merge 5 commits into
Draft
feat(BA-6889): add kernel scheduling-history query conditions and orders#12867jopemachine wants to merge 5 commits into
jopemachine wants to merge 5 commits into
Conversation
This was referenced Jul 15, 2026
Merged
Base automatically changed from
fix/kernel-scheduling-history-status-columns
to
main
July 15, 2026 03:53
jopemachine
force-pushed
the
feat/BA-6889-kernel-history-conditions-orders
branch
from
July 15, 2026 04:30
348ec2a to
1d85def
Compare
Add the models-layer query building blocks that the rest of the kernel scheduling-history stack builds on, mirroring the session equivalents: - KernelSchedulingHistoryConditions: MatchSpec filter variants for id, kernel_id and session_id; string match variants for phase, error_code and message; from/to status, result and timestamp conditions. - orders.py: KERNEL_ORDER_FIELD_MAP, default forward/backward orders, tiebreaker order and resolve_kernel_order. - KernelHistoryOrderField, which orders.py resolves against. - EntityType.KERNEL_HISTORY and KERNEL_SCOPED_HISTORY. Tests pin each condition to the column it compiles against; the factories build lazy closures, so a wrong column name surfaces nowhere else. Nothing calls these yet. The repository scope lands in BA-6890. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…edulingHistoryID The kernel scheduling-history record had no dedicated identifier type, so its primary key travelled the stack as a bare uuid.UUID. Introduce the NewType and thread it through the row, the domain model, and the by_ids query condition. NewType is identity at runtime and GUID's subtype argument only satisfies the type checker, so the column mapping and emitted SQL are unchanged and no migration is needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y module The rebase onto main left two modules covering KernelSchedulingHistoryConditions: the one merged upstream under models/scheduling_history/, and the flat module this branch added. Both defined their own _ConditionCase and both covered by_from_status/by_to_status. Move the cases the flat module uniquely covered (from/to statuses, kernel_id, session_id, their filter-spec variants, result, error_code) into the per-entity module and drop the flat one, matching the layout the sibling entities already use. GUID resolves to CHAR(16) on the default dialect and has no literal processor, so UUID columns cannot render inline there. Carry the dialect on the case and pass it to compile(), which keeps the existing cases and their expectations untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jopemachine
force-pushed
the
feat/BA-6889-kernel-history-conditions-orders
branch
from
July 15, 2026 09:40
1d85def to
657f1a6
Compare
The kernel string-filter conditions hoisted the column into `col` and then rebound it to `sa.func.lower(col)`. That rebinding is the only reason the `cast(sa.ColumnElement[...], ...)` calls existed: mypy fixes a variable's type at its first assignment, so `Function[Any]` does not fit an `InstrumentedAttribute[str | None]`. The cast was also untrue. `InstrumentedAttribute` is not a `ColumnElement` — both descend from `SQLColumnExpression`, so they are siblings. `cast` is unchecked, so it silenced a mismatch mypy rejects outright when written as an annotation. No other conditions module does this. Of the 47 `conditions.py` files, this was the only one casting (48 times); 33 use `.ilike()` and never rebind the column variable. `login_client_type` shows nullability is not the reason either: it wraps a nullable column in `coalesce` once and calls `.ilike()` on it. So the kernel filters now build the condition per branch, as the convention does. The casts on the session / deployment / route blocks are pre-existing and left alone. Case-insensitive matching moves from `lower(col) LIKE lower_pattern` to `ILIKE` on postgresql. The two are equivalent here and no index is affected: `phase`, `error_code` and `message` carry no index, functional or otherwise. Tests are updated to the SQL the convention emits.
by_from_status, by_to_status and by_error_code have no production caller. Every filter reaches the conditions through the adapter, which uses the plural and MatchSpec factories instead: by_from_statuses / by_to_statuses for status, and convert_string_filter(equals_factory=by_error_code_equals, ...) for error_code. The only thing referencing the three was the test written for them. They are a strict subset of what replaces them — by_error_code_equals with a non-negated, case-sensitive spec compiles to the same `error_code = 'ERR'`, and also covers the case-insensitive and negated variants the plain one cannot. The from_status / to_status cases are dropped outright: by_from_statuses and by_to_statuses already pin the same columns. The error_code case moves onto by_error_code_equals rather than going away, so the column stays covered — a factory returns a lazy closure, so a wrong column only fails when compiled, which is the fault #12857 fixed and the reason these tests compile each condition. The identical factories on the session / deployment / route classes are equally dead but out of scope here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📚 Stacked PRs
BA-6887fix: kernel history conditions reference the real status columnsBA-6889models: kernel query conditions and orders ← you are hereBA-6890repository: kernel search scope and scoped searchBA-6891DTO + service: kernel v2 DTOs and search actionsBA-6892adapter + REST v2: kernel endpointsBA-6893SDK + CLI: kernel commandsMerge in order, bottom-up. Each PR is based on the one above it, so its diff shows only its own layer.
What
The models-layer query building blocks the rest of the kernel scheduling-history stack builds on, mirroring the session equivalents:
KernelSchedulingHistoryConditions— MatchSpec filter variants forid/kernel_id/session_id; string match variants (contains / equals / starts_with / ends_with / in) forphase,error_code,message; from/to status, result, and timestamp conditions.orders.py—KERNEL_ORDER_FIELD_MAP, default forward/backward orders, tiebreaker order,resolve_kernel_order.KernelHistoryOrderField— the DTO enumorders.pyresolves against. Only this enum is added here; the rest of the kernel DTOs land in feat(BA-6891): add kernel scheduling-history v2 DTOs and service actions #12869.EntityType.KERNEL_HISTORY/KERNEL_SCOPED_HISTORY.Review notes
Bulky but mechanical: it mirrors
SessionSchedulingHistoryConditionsaxis for axis. The interesting part is the tests.Each factory returns a lazy closure, so a wrong column name raises
AttributeErroronly when the condition is finally evaluated — not at import, and not under type checking.tests/unit/manager/models/test_scheduling_history_conditions.pytherefore compiles every condition and asserts the column it targets. That is the same class of fault #12857 fixes, and the coverage Copilot asked for there.Nothing calls any of this yet — the repository scope that consumes it is #12868.
Size
~429 lines, slightly over the 300–400 target.
conditions.pyis a single indivisible block of sibling factories; splitting it would cut across one class for no reviewer benefit.🤖 Generated with Claude Code