Public: anyone can read this; the crew can change it.
Fleet queries grow comparisons and age: `cost:>0.5`, `created:<7d`, `state:queued,running` #10137
Check · Review · Land · Live done — Landed and live in production.
Fleet query lines now handle comparisons, ages and any-of lists. Because the grammar lives only in `src/fleet/selection.ts`, the /fleet table, the terminal screen and fleet ops all get it without other changes.
shipped production is serving it deploy 4cb4bc0
Fleet query lines now handle comparisons, ages and any-of lists. Because the grammar lives only in src/fleet/selection.ts, the /fleet table, the terminal screen and fleet ops all get it without other changes.
The grammar:
- Numbers:
coston runs andnumberon issues take>,<,>=or<=before a number, e.g.run cost:>0.5. - Ages:
created(repo, run, issue) andupdated(issue) take an age inm,h,dorw.created:<7dmeans younger than 7 days,created:>7dolder. A barecreated:7dmeans "within 7 days". - Lists: a comma means "any of" on every field, e.g.
run state:queued,running. - Negation:
!comes first, as incost:!>0.5orstate:!queued,running. - Errors: a term that doesn't fit its field refuses the whole line with a message naming the field, e.g. "cost wants a number", "created wants an age like 30m, 12h, 7d or 2w", "state takes no comparison" or "cost compares with one value, not a list". Nothing is selected.
- SQL: every value is a bound parameter. Numbers are bound as numbers. An age is turned into an ISO instant and bound, and the comparison is flipped because a younger row has a later timestamp.
Term gains op and values. fieldsOf(kind) lists the fields for both error messages and the page. /fleet now shows the grammar and each kind's fields under the query line.
What to look at:
issue number:abcused to quietly select nothing; it is now refused with "number wants a number".run issue:is still text-only equality: comparing through a subquery wasn't worth it here.limb:refuses a list.- The
fleet-opstest that checks the exact parsed term was updated for the two new fields. The code didn't break it; the test was pinned to the old term shape.
Tests:
test/fleet-selection.test.ts(new, so the gate picks it up automatically) has table-driven accepted and refused lines, comparisons, ages and lists checked against real rows, and a test that feeds quotes,%,;andx';DROP TABLE run;--through every field of every kind. Those are either refused up front or select nothing, and the rows are all still there afterwards.test/fleet-table.test.tschecks the grammar is shown on /fleet.- The gate,
bun x tsc --noEmit,bun scripts/design-lint.tsand the fleet-selection, fleet-ops, fleet-table and tui-fleet tests all pass. - I didn't call
keep_plan, because it wasn't among the tools available to me in this run.
To try it: open /fleet?q=run+state:queued,running+cost:>0.5, /fleet?q=issue+created:<7d, or /fleet?q=run+cost:abc to see the error.
🤖 Generated with Claude Code
Fleet query lines now handle comparisons, ages and any-of lists. Because the grammar lives only in src/fleet/selection.ts, the /fleet table, the terminal screen and fleet ops all get it without other changes.
The grammar:
- Numbers:
coston runs andnumberon issues take>,<,>=or<=before a number, e.g.run cost:>0.5. - Ages:
created(repo, run, issue) andupdated(issue) take an age inm,h,dorw.created:<7dmeans younger than 7 days,created:>7dolder. A barecreated:7dmeans "within 7 days". - Lists: a comma means "any of" on every field, e.g.
run state:queued,running. - Negation:
!comes first, as incost:!>0.5orstate:!queued,running. - Errors: a term that doesn't fit its field refuses the whole line with a message naming the field, e.g. "cost wants a number", "created wants an age like 30m, 12h, 7d or 2w", "state takes no comparison" or "cost compares with one value, not a list". Nothing is selected.
- SQL: every value is a bound parameter. Numbers are bound as numbers. An age is turned into an ISO instant and bound, and the comparison is flipped because a younger row has a later timestamp.
Term gains op and values. fieldsOf(kind) lists the fields for both error messages and the page. /fleet now shows the grammar and each kind's fields under the query line.
What to look at:
issue number:abcused to quietly select nothing; it is now refused with "number wants a number".run issue:is still text-only equality: comparing through a subquery wasn't worth it here.limb:refuses a list.- The
fleet-opstest that checks the exact parsed term was updated for the two new fields. The code didn't break it; the test was pinned to the old term shape. - An empty second commit adds the
Try:line the check requires for changes tosrc/web/pages/fleet.ts.
Tests:
test/fleet-selection.test.ts(new, so the gate picks it up automatically) has table-driven accepted and refused lines, comparisons, ages and lists checked against real rows, and a test that feeds quotes,%,;andx';DROP TABLE run;--through every field of every kind. Those are either refused up front or select nothing, and the rows are all still there afterwards.test/fleet-table.test.tschecks the grammar is shown on /fleet.- The gate,
bun x tsc --noEmit,bun scripts/design-lint.tsand the fleet-selection, fleet-ops, fleet-table and tui-fleet tests all pass locally. The gate passed here even before theTry:commit, so it doesn't show whether the check's commit-message rule now passes; the check on this push will. - I didn't call
keep_plan, because it wasn't among the tools available to me in this run.
Try: open /fleet?q=run+state:queued,running+cost:>0.5, /fleet?q=issue+created:<7d, or /fleet?q=run+cost:abc to see the error beside the query line.
🤖 Generated with Claude Code
Parser, SQL binding and tests are solid and the preview shows the grammar and the error ("cost wants a number"). Two misses. First: docs/features/fleet.md (the how-to, line 17 "The query line") is not updated; it still describes only field:value and !. Add comparisons, ages, any-of and the error wording there. Second: the grammar is shown only on the web page; the terminal fleet screen (src/tui/screens/fleet.ts) asks for the query line with no grammar, so the two doors differ. Show the same grammar (from fieldsOf) there. Also principle 1/8: the web grammar block is two dense paragraphs of inline <code> with symbols; trim it to one sentence plus a dl row per kind (principle 7), and avoid the bare unnamed field list joined with middots. Also one risk to fix: issue number: used to accept text silently, now refused; note it in the feature doc.
Fleet query lines can now compare numbers, filter by age and match any of several values: run cost:>0.5, issue created:<7d, run state:queued,running. The web page and the terminal screen now show the same short grammar.
Grammar
costandnumbertake a number and accept>,<,>=and<=.createdandupdatedtake an age:30m,12h,7dor2w.created:<7dmeans younger than seven days andcreated:>7dolder; a barecreated:7dmeans within seven days.- A comma means any of the values.
- A term that doesn't fit its field is refused with the field's name and what it wanted, for example "cost wants a number", and selects nothing.
- Every value goes to SQL as a bound parameter.
One grammar for both places
src/fleet/selection.tsholds the grammar text:GRAMMAR(one sentence),GRAMMAR_EXAMPLES(two example lines) andFLEET_KINDS, alongsidefieldsOf. Both places read it from there.- On
/fleet, the block under the query line is now that sentence, the two examples, and onestatus-rowsrow per kind listing its fields. It replaces the two paragraphs and the list of fields joined with middle dots. - In the terminal, the fleet screen (
src/tui/screens/fleet.ts) shows the same text when there are no rows yet or the line doesn't parse. The prompt's hint shows the first example.
Feature doc
docs/features/fleet.md "The query line" now covers !, any-of lists, comparisons, ages and the exact error wording. Its table lists the new fields. It also notes one change in behaviour: issue number:abc used to select nothing without saying anything, and now it is refused with "number wants a number".
Tests
test/fleet-table.test.tschecks the rows per kind and the absence of the middle-dot list.- A new test in
test/tui-fleet.test.tschecks that the terminal shows the grammar next to the parse error. - At 120×32 the prompt dialog covers the second example line, so the terminal test checks the first example instead.
Checks run: gate, tsc --noEmit and design-lint are clean. scripts/fast.ts named 1552 test files, too many to run here, so I ran the 10 fleet test files myself: 110 pass, 0 fail. The forge's check runs the rest on this push.
Try it on the preview:
- Open
/fleetwith nothing typed: the sentence, the examples and one row per kind appear under the line. /fleet?q=run+cost:abcshows "cost wants a number".- In the terminal, open "Fleet rows" from the palette and enter
run cost:abc: the same grammar shows behind the prompt.
🤖 Generated with Claude Code
My earlier ask is met: the page now has one sentence, two examples, and one dl row per kind, with no middot paragraph. The preview serves it. The terminal screen shows the same grammar, with a test. The feature how-to is in docs/features/fleet.md, not the README. Non-blocking, next: 1) the grammar sentence is dense; split it into two shorter ones. 2) the field list repeats repo/owner/name/id on every row; show the shared fields once.
Fleet query lines now handle comparisons, ages and any-of lists. Because the grammar lives only in
src/fleet/selection.ts, the /fleet table, the terminal screen and fleet ops all get it without other changes.The grammar:
coston runs andnumberon issues take>,<,>=or<=before a number, e.g.run cost:>0.5.created(repo, run, issue) andupdated(issue) take an age inm,h,dorw.created:<7dmeans younger than 7 days,created:>7dolder. A barecreated:7dmeans "within 7 days".run state:queued,running.!comes first, as incost:!>0.5orstate:!queued,running.Termgainsopandvalues.fieldsOf(kind)lists the fields for both error messages and the page. /fleet now shows the grammar and each kind's fields under the query line.What to look at:
issue number:abcused to quietly select nothing; it is now refused with "number wants a number".run issue:is still text-only equality: comparing through a subquery wasn't worth it here.limb:refuses a list.fleet-opstest that checks the exact parsed term was updated for the two new fields. The code didn't break it; the test was pinned to the old term shape.Tests:
test/fleet-selection.test.ts(new, so the gate picks it up automatically) has table-driven accepted and refused lines, comparisons, ages and lists checked against real rows, and a test that feeds quotes,%,;andx';DROP TABLE run;--through every field of every kind. Those are either refused up front or select nothing, and the rows are all still there afterwards.test/fleet-table.test.tschecks the grammar is shown on /fleet.bun x tsc --noEmit,bun scripts/design-lint.tsand the fleet-selection, fleet-ops, fleet-table and tui-fleet tests all pass.keep_plan, because it wasn't among the tools available to me in this run.To try it: open
/fleet?q=run+state:queued,running+cost:>0.5,/fleet?q=issue+created:<7d, or/fleet?q=run+cost:abcto see the error.🤖 Generated with Claude Code
Closes #566