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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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: cost on runs and number on issues take >, <, >= or <= before a number, e.g. run cost:>0.5.
  • Ages: created (repo, run, issue) and updated (issue) take an age in m, h, d or w. created:<7d means younger than 7 days, created:>7d older. A bare created:7d means "within 7 days".
  • Lists: a comma means "any of" on every field, e.g. run state:queued,running.
  • Negation: ! comes first, as in cost:!>0.5 or state:!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:abc used 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-ops test 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, %, ; and x';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.ts checks the grammar is shown on /fleet.
  • The gate, bun x tsc --noEmit, bun scripts/design-lint.ts and 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

Closes #566

commented

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: cost on runs and number on issues take >, <, >= or <= before a number, e.g. run cost:>0.5.
  • Ages: created (repo, run, issue) and updated (issue) take an age in m, h, d or w. created:<7d means younger than 7 days, created:>7d older. A bare created:7d means "within 7 days".
  • Lists: a comma means "any of" on every field, e.g. run state:queued,running.
  • Negation: ! comes first, as in cost:!>0.5 or state:!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:abc used 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-ops test 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, %, ; and x';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.ts checks the grammar is shown on /fleet.
  • The gate, bun x tsc --noEmit, bun scripts/design-lint.ts and 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

commented

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: cost on runs and number on issues take >, <, >= or <= before a number, e.g. run cost:>0.5.
  • Ages: created (repo, run, issue) and updated (issue) take an age in m, h, d or w. created:<7d means younger than 7 days, created:>7d older. A bare created:7d means "within 7 days".
  • Lists: a comma means "any of" on every field, e.g. run state:queued,running.
  • Negation: ! comes first, as in cost:!>0.5 or state:!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:abc used 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-ops test 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 to src/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, %, ; and x';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.ts checks the grammar is shown on /fleet.
  • The gate, bun x tsc --noEmit, bun scripts/design-lint.ts and the fleet-selection, fleet-ops, fleet-table and tui-fleet tests all pass locally. The gate passed here even before the Try: 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

Changes requested — before the latest push

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.

commented

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

  • cost and number take a number and accept >, <, >= and <=.
  • created and updated take an age: 30m, 12h, 7d or 2w. created:<7d means younger than seven days and created:>7d older; a bare created:7d means 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.ts holds the grammar text: GRAMMAR (one sentence), GRAMMAR_EXAMPLES (two example lines) and FLEET_KINDS, alongside fieldsOf. Both places read it from there.
  • On /fleet, the block under the query line is now that sentence, the two examples, and one status-rows row 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.ts checks the rows per kind and the absence of the middle-dot list.
  • A new test in test/tui-fleet.test.ts checks 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 /fleet with nothing typed: the sentence, the examples and one row per kind appear under the line.
  • /fleet?q=run+cost:abc shows "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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs