feat(job-array-one-based-index): client identity and selection parser (task 8.1)

xcecli's format package gains ParseSelection (written or decimal key
with optional [k]/[a-b], the server's grammar and check order; 5.8 and
5.7 also on decimal keys with [...], so an upgraded client protects
itself against an older server; query ranges refused after the other
checks), the bracket-aware SplitSelections, the raw -J
ParseNameSelection and Selection.APIKey. ParseJobID is bounded;
ToAPIJobID(s, allowRange) no longer passes unrecognised text through;
peek keeps today's behaviour via ToAPIJobIDLegacy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-01 12:47:39 +00:00
parent 1fa0107357
commit bc616e8c4a
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
9 changed files with 866 additions and 39 deletions

View file

@ -181,7 +181,7 @@
- _Depends: 5.4, 7.2, 7.4_
- [ ] 8. Command-line client
- [ ] 8.1 (P) Parse identities and selections in the client
- [x] 8.1 (P) Parse identities and selections in the client
- Add the client selection parser (written and decimal keys, the shared order, alignment and element bound on decimal keys with an element part, range refusal for queries only after the other checks), the bracket-aware list splitter and the raw `-J` name check
- Make identity parsing bounded and change the API-key conversion to take whether ranges are allowed; keep a legacy conversion for peek; update its two command callers mechanically (control allows ranges, the list filter does not) so the client keeps building
- Update the conversion tests: `"123456"` and `"32768[3]"` pass through, `"123456[3]"` is rejected under 5.8, a range passes only when allowed; move peek and its test to the legacy conversion
@ -249,3 +249,4 @@
- 7.1: `ParseNameSelection` on a value without `[`/`]` returns `SelBare` with `Name` = the raw untrimmed value (`Raw` is trimmed); 7.2 must match bare names on `Name` and must not treat a bare result as validated. Rule tags on `*SelError` are "5.16", "5.14", "5.17", "5.8", "5.7", "5.5"; decimal keys above uint64 are 5.14.
- 7.2: `BuildSelectionPredicates(filters []utils.FilterCondition) (plain []utils.FilterCondition, preds []func(utils.OrderMap) bool, err error)` in `controllers/jobmatch.go`; parser rejections come back as `*SelError`, other rejections with today's texts. Accepted consequence of the one-rule decision: bare `job_id` values under identity operators now go through `ParseIdentitySelection`, so `job_id:eq:+5` / `-1` (previously accepted) are rejected under 5.16. For 7.3: keep the `array_stats` bracket rejection before the builder, and run the builder in the validate-all-first pass before the `exec_hosts` store lookup.
- 7.3: query pre-pass is `validateJobQueryFilters`; `returnSelectionError` maps `*SelError` → 400 with its message. `RestartJobByID` (jobs.go ~:863) still builds unevaluated `CompFilterCondition`s — restart is out of scope, so bug-1898 stays partial for that path. Pre-existing: GetJobsInfo `page_token` does not advance (logged separately).
- 8.1: client `format.ParseSelection(raw, allowRange)`, `ParseNameSelection(raw)`, `SplitSelections(list)`, `Selection.APIKey()`; query-range refusal rule tag "range" (`RuleQueryRange`); `ToAPIJobID(s, allowRange)`; peek uses `ToAPIJobIDLegacy`. For 8.2: `filters/job_filter.go` still runs `isValidJobId` before `ToAPIJobID` and both ID lists still split at every comma.