Spec for numbering job-array elements from 1 (bug-1896): approved requirements, a design reviewed over 20 rounds until clean (log in research.md), and a 30-task plan. The design review found two live apiserver defects, logged here: bracketed job_id/job_name filters are never evaluated (bug-1898) and ControlJobByID re-dispatches earlier selections (bug-1899). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
27 KiB
Research & Design Decisions
Summary
- Feature:
job-array-one-based-index - Discovery Scope: Extension (light discovery; four parallel codebase investigations on 2026-10-01 at
8f5ba635: libxce + controller, apiserver, xcecli, harness + worker + scheduler + skill scripts) - Key Findings:
- The requirements' Boundary notes are accurate line for line. Discovery adds a set of defects in the same code that the design must absorb because the acceptance criteria depend on them (listed under "Discovery corrections" below).
- Every identity parser in the system (C
parse_jobid, Go apiserverParseHumanJobID/parseArrayName/parseArrayIndexSection/IsNumeric, Go xcecliParseJobID/ToAPIJobID/isValidJobId) is unbounded and lenient in its own way. Requirements 5.7, 5.8 and 5.12-5.17 reduce to one grammar plus one set of range checks. The design therefore has exactly one bounded parser per language, with every caller routed through it. - Nothing on the persistence, replication or scheduler-recording side depends on where element numbering starts: WAL
JOB_ARRAY_SUBMIT, snapshots, HA apply and scheduler recording carry(first element ID, size)and expand withfirst + i. Scheduler expansion happens indriver.ctranslation, before core events, so the recording and the simulator see expanded jobs and the driver state-equivalence invariant is untouched.
Research Log
Job identity bit layout and helpers
- Context: Option B (decided in requirements) puts the element number in the existing 15-bit index field and submits the first element as
base | 1. - Sources Consulted:
src/include/config.h:37-72,src/include/utils.h:20-48,src/lib/utils.c:578-710,src/frontend/apiserver/backend/convert_pure.go:12-133,src/frontend/xcecli/common/format/jobid.go:9-148. - Findings:
- Layout: tag (2 bits, 62-63), cluster (6, 56-61), API server (4, 52-55), timestamp (32, 20-51), sequence (20, 0-19). For arrays, sequence = block (5 bits, 15-19) + index (15 bits, 0-14). So there are 32 array blocks per second per API server.
MAKE_JOBIDand both GoMakeJobIDs OR fields without masking. An oversized field silently spills into its neighbour.- The array identity (
EXTRACT_ARRAY_BASEID, Carray_jobid, GoExtractArrayBaseID) is untagged with the low 15 bits clear. - Array marking disagrees:
fmt_jobidand xcecli testtag & 1;array_jobid/array_idxand apiserverExtractArrayBaseIDtreat any non-zero tag as an array; apiserverIsArrayJob/FormatJobIDtesttag == 1.
- Implications: The array test becomes
tag == 1wherever a new decision is made (controller 7.5, element-only matching, worker). The display helpers keep their behaviour, because only tags 0 and 1 have ever been issued.
ID generation
- Sources:
src/lib/idgen.c:22-55,backend/clib.go:338-347,controllers/jobs.go:1185,1426,src/harness/test.c:3721,6893-6898. - Findings:
idgen(ctx, c, a, size, *out)returnssizeon success.- Size 1 returns an untagged ordinary ID. Size > 1 returns a tagged index-0 ID after rounding the sequence up to a 32768 block.
- Size 32768 is accepted.
- There is no sequence-overflow guard. The harness seeds the sequence randomly in [0, 2^20).
- The harness ignores the return code.
- Implications: A one-element array needs a distinct request (decision D2). The overflow guard in general is out of scope (separately tracked). The new array request refuses a block that would leave the 20-bit sequence, because otherwise the 1-based first ID could land in the timestamp.
Controller submission path
- Sources:
src/controller/job.c:108-229, 2224-2356, 2389-2552,persist.c:5930-5938,src/include/xce/errnox.h:11-26,cluster.c:1685. - Findings:
- Order today: field checks →
HOOK_BEFORE_EVENT→jobid_range_exists→inflight_range_try_add→ array/ordinary build. - Release happens on success (
:2321), on commit failure (:2356) and on early errors. - Duplicate submission replies
-EEXIST. - Size 0 reaches payload building and is likely never answered.
jobmgris a uint64-keyed hash with per-lookup read locks.
- Order today: field checks →
- Implications:
- Validation (7.1-7.5) becomes a pure function called before any registry or table work.
- The table checks move after registration (Boundary note).
- The array-identity check is at most 32768 hash lookups (CPU-bound, no blocking), which is acceptable in the vtask handler under the async-I/O invariant.
- 7.1 needs a new
errnox.hvalue.
API server
- Sources:
controllers/jobs.go(createArrayName :1824-1979, preCheckJobRequest :1565-1578, :1734, CreateJob :1375-1523, parseArrayName :1761-1821, parseArrayIndexSection :3271-3295 and 5 callers, GetJobsInfo :227-437, GetJobByIDs :725-860, ControlJobByID :2261-2635, foundJob :3111-3131, ControlJob :2652-2830, FetchJobList :3299-3480),utils/config.go:211-227,cmd/main.go:92-101,backend/handler.go:272-275,models/jobs.go:709-713. - Findings:
createArrayNametrims whitespace, accepts+1, rejects[k-k]and parses%N.- The named-job branch returns early, so the interactive check never runs for named jobs.
parseArrayNameslices tolen-1, so text after]is lost.parseArrayIndexSectionreads1-2-3as(1,1). All its callers replace its error with a generic one.IsNumericisParseFloat.foundJobcannot distinguish explicit[0]from "no index".- The submit response has no count.
- The config rejects values above 2147483646 and does not clamp at 32767. The logger is initialised before the config, so a startup warning is possible.
- The in-memory
store.Jobsand the existing hook-variable pattern (validateResreqSyntax,fetchFile) make all of this unit-testable without CGO.
- Implications: There is one selection parser and one key validator (D4), and they replace the scattered parsing.
foundJobgains an explicit-index flag. The response gains a count field.
xcecli
- Sources:
common/format/jobid.go,cmd/jobs/{submit,controller,list}.go,filters/job_filter.go,models/jobs.go:365-376,454-458. - Findings:
ParseJobIDdiscardsParseUinterrors and checks neither the index nor alignment.ToAPIJobIDpasses anything unrecognised through, andTestToAPIJobIDPassthroughlocks that in for"123456[3]".- Control-by-ID never validates.
- Both ID lists split at every comma.
FormatArrayChildID(base, 0)prints the bare array ID.- Checkpoint has no filter flags.
- Implications:
- There is one client-side identity parser that both paths use (D6).
- Numeric keys (
123456[3]) still pass through, because only the API server can judge them (5.17, 5.8 for numeric forms). The passthrough test keeps its numeric case. - Control results print from the element's own ID.
Harness, worker, scheduler, skills
- Sources:
src/harness/test.c(jobsub :3615-3866, substitute_autovars :1283-1360, cmd_expect_job :2787-2817, joblist_query :2543-2608, single-job commands :3327/3517/4140/4276/4921/5073/5268/5377/5481),src/harness/cmdutil.c+testsuite/test_cmdutil.c,testsuite/test_test_cli.c,src/worker/src/xcecd_exdata.c:396-457,src/scheduler/src/driver.c:440-512,scheduler/testsuite/test_driver_translate.c:720-826, both skill scripts and SKILL.md files,src/docs/xce.md. - Findings:
arsizeisuint32_t, so a negative-awraps to about 4.29e9 rather than becoming a plain job.taskrunsends job 0 for a rejected ID.test.cis not linked into any unit test. Logic must move into a paired file (ascmdutil.cis) to be unit-tested; otherwise it can only be tested over a pty withtest_test_cli.c.- The worker sets
XCE_JOBINDEX=0and then lets user variables override it. - The scheduler expansion has no tag or overflow guard, and the expansion tests use untagged IDs.
xce.mdhas no array section.
Architecture Pattern Evaluation
| Option | Description | Strengths | Risks / Limitations | Notes |
|---|---|---|---|---|
| A: start field | Add an explicit start index to the submission | Supports any start | Wire, WAL and snapshot format change; HA replay compatibility | Rejected in requirements (decision 1) |
| B: index in ID (selected) | First element ID is base|k0; elements are first + i |
No format change; existing expansion and apply unchanged | Index range is 1..32767 (one slot lost) | Decided with the user in requirements |
| Per-caller fixes | Patch each parser where it is used | Smallest diffs | Ten-plus divergent copies of the same grammar; 5.12 precedence impossible to keep consistent | Rejected (synthesis: generalization) |
| One bounded parser per language (selected) | C parse_jobsel, Go apiserver jobsel and Go xcecli jobsel share one grammar and one check order |
One place enforces 5.7/5.8/5.12-5.17; callers stay thin | Three implementations of one grammar (C, two Go modules) | The two Go modules cannot share code today (separate modules); a shared conformance case table keeps them aligned |
Design Decisions
Decision: one selection grammar and check order, implemented once per language
- Context: 5.7, 5.8, 5.12, 5.14, 5.15, 5.16 and 5.17 apply to the CLI, REST and harness alike, with one fixed precedence (5.15, 5.16, 5.14, 5.17, 5.8, 5.7, 5.5).
- Alternatives Considered: 1) fix each caller; 2) one parser per language.
- Selected Approach: C
parse_jobsel()in libxce (the harness andparse_jobiduse it); Gojobselin the apiserver (all REST selection paths); Gojobselin xcecli. Each returns a typed result{key, form, lo, hi}or the first failed check. - Rationale: The precedence rule (5.12) can only hold if one function evaluates the checks in order.
- Trade-offs: Three implementations of one grammar, mitigated by a single conformance table (
selection-casesin design.md's Testing Strategy) copied into each test suite. - Follow-up: Keep the three case tables identical in review.
Decision: a distinct ID request for one-element arrays
- Context:
idgen(..., 1, ...)must keep returning an ordinary ID (harness-a 1, restart).name[1]must create a one-element array (1.2, 7.8). - Selected Approach: A new
idgen_array(ctx, c, a, n, *first)for 1 <= n <= 32767 returns the tagged first elementblock|1.idgenkeeps size 1 only for ordinary IDs; its size > 1 path is removed, because both callers switch toidgen_array. The apiserver gets a matching cgo wrapperGenerateArrayJobID. - Rationale: Callers name their intent; size 1 stays unambiguous.
- Trade-offs: A new libxce symbol; the non-cgo stub needs a matching stub.
Decision: controller validation before collision checks, collision checks after registration
- Context: 7.1-7.11 and the Boundary note on the registry window.
- Selected Approach:
- Pure
jobsubmit_classify(jobid, size)→OK | INDEX0 | INVALID, evaluated first (7.9: INDEX0 wins over everything; INVALID wins over collisions). - Then
inflight_range_try_addextended to also compare array identities among array entries. - Then the job-table element-range and array-identity checks; a hit releases the registration.
- Pure
- Rationale: This closes the window between the table check and registration; the precedence matches 7.9 and 7.10.
- Trade-offs: A rejected collision now costs one registry add and release.
Decision: whole-array identity in replies is derived by clients
- Context: Decision 3 / round 3 in the requirements. The controller reply keeps the first element ID;
clib.goandRecordAcceptedJobrely on it. - Selected Approach: The apiserver response
jobidbecomesarray_jobid(first)with a newarray_sizefield. The harness prints and storesarray_jobid. The controller is unchanged.
Decision: the worker skips a user-supplied XCE_JOBINDEX
- Selected Approach: In the user-variable loop, a variable named
XCE_JOBINDEXis skipped with a WARN naming the job. The system value isarray_idxfor tag-1 IDs and 0 otherwise.XCE_JOBIDbehaviour is unchanged (6.5).
Synthesis outcomes
- Generalization:
- All identity and selection parsing collapses into one grammar per language.
- The five apiserver
parseArrayIndexSectioncallers and thefoundJobindex-0 branch become consumers of one parsed selection type. - The harness's ten single-job commands share one argument helper.
- Build vs adopt: Nothing external fits. Go
strconv.ParseUintwith explicit bit-size and CstrtoullwitherrnoreplaceatoiandParseFloat. No new dependencies. - Simplification:
- The
idgensize > 1 path is removed rather than kept besideidgen_array. - No start field and no format change (option B).
%Nand steps are rejected rather than parsed and dropped.- Start > 1 is not modelled anywhere in the clients. The controller accepts starts from 1 to 32767 only because 7.7 requires it.
- The
Discovery corrections to the requirements' Boundary notes (absorbed by the design)
parse_jobiddereferences its buffer before the NULL check (utils.c:625); the rewrite fixes this.- The harness
-avalue isuint32_t, so a negative value wraps to about 4.29e9 rather than turning into a plain job (4.4 covers it). taskrunhas nojobid == 0guard; the shared harness helper replaces every uncheckedparse_jobidcall.parseArrayNamehas six callers: the sixth,output.go:226, is peek, which is out of scope and left unchanged.FetchJobListalso replacesparseArrayNameerrors with a generic message.parseArrayIndexSectionsilently readsa-b-cas(a,a); the new parser rejects it (5.16).IsNumeric(ParseFloat) accepts1e3,-1,NaN; the new key validator usesParseUint.- The interactive check (
jobs.go:1734) is unreachable for named jobs because of the early return at :1578. The 2.1 check runs before the name branch. The early return itself (a separately listed defect) is otherwise left as it is. - Scheduler expansion tests (
test_driver_translate.c:720-826) use untagged IDs. The new tag guard requires them to become taggedblock|1IDs. - The jobsub help is at
test.c:600-613; :556-562 isexpect-job's. list.go's-Wflag is commented out at :345, not :360.- Submissions of size 0 are probably never answered today (empty payload). 7.4 now rejects them up front.
- bug-1898 (found in design review round 1): the apiserver builds bracketed
job_id/job_nameselections asCompConditionsthatstore.ExecuteQuerynever evaluates, soGetJobsInfo,GetJobByIDsandFetchJobList(hence filter-basedControlJob) ignore them. The design replaces them with evaluated row predicates (QueryOptions.Predicates), which this feature's element-only matching needs anyway. - The apiserver has no control-result struct; results are
map[string]interface{}, and accepted/failed maps already carryunique_job_id. Only not-found maps need it. - Today's
substitute_autovarsalso expands$?and$jobcount; the extractedautovar_substitutetakes a context struct for them. - libxce and controller tests are registered in
src/lib/meson.build/src/controller/meson.buildplus their runners (lib/testsuite/test.c,controller/testsuite/controller_test.c), not in per-testsuitemeson.buildfiles.
Design review log
-
Round 1 (2026-10-01): two independent reviewers (requirements fidelity; code feasibility) reported 18 issues, all fixed in design.md:
- Requirements fidelity: most-recent rule scoped to filters without
[...]; 5.8 only for keys with[...]; harness reversed range → 4.8; submit-number saturation for 2.9; client 5.7/5.8 on decimal keys; validate-all-first on REST; no array-name rule on name selections; 5.10 approximation documented;primaryJobIDstays the first element for%I/%J. - Code feasibility: unevaluated
CompConditions(bug-1898) → predicates; no apiserver control struct; autovar context; test registration paths; peek keeps a legacyToAPIJobID; one read-locked scan for the collision check;foundJobsignature and its existing test; a dispatch-log type conversion; the harness pty command form.
- Requirements fidelity: most-recent rule scoped to filters without
-
Round 2 (2026-10-01): 16 issues, all fixed:
- Requirements fidelity (7): control keeps identity ranges (
ToAPIJobID(s, allowRange)); range refusal ordered after 5.16/5.14/5.17/5.8/5.7;CreateJoblog lines name the array (5.9); the> 2147483646config rejection removed; element 0 by name has an explicit predicate; the count is printed once; one test bullet relocated; one upgrade order stated in both documents. - Code feasibility (9, one already fixed by round-2 edits): 64-bit size in
jobsubmit_classify; per-field OR / cross-field AND predicates; bracketed filters only witheq/in; whole-filter conversion; two scheduler tests andpeek_test.goadded to the plan;cluster_t; harness header paths; the autovar-ENOSPCreturn.
- Requirements fidelity (7): control keeps identity ranges (
-
Round 3 (2026-10-01): 12 issues (one already resolved by earlier round-3 edits), all fixed:
- Requirements fidelity (6): bracketed filters honour their operator instead of a new eq/in-only rejection (
notinnegates,contains/startwith/endwithmatch the name part,betweenasin,nekeeps today's rejection); REST queries evaluate identity ranges (only the xcecli list path refuses them); written-form bare keys normalised on every path; 5.9 log lines drop the raw first-element number; name-part grammar and test rows; schedulers in the upgrade order. - Code feasibility (6): harness sequence seed bounded below
30 * 32768; 7.2 and the scheduler guard written without addition (size > 32768 - idx); filter-basedControlJobvalidates names itself so rejections are 400; per-entry (not per-field) filter conversion;resolveMaxArraySizepure function for config tests.
- Requirements fidelity (6): bracketed filters honour their operator instead of a new eq/in-only rejection (
-
Round 4 (2026-10-01): 10 issues (two reviewers overlapped on the xcecli wildcard case), all fixed: xcecli checks the raw
-Jtext (5.16) before wildcard mapping and picks the search rule from the name part of a bracketed value; bracketedjob_nameoperators reuse today's condition semantics (BuildFilterConditions+MatchesCondition); operators outside a field's mapping table keep the existing "unsupported operator" error, andjob_idcomparison operators with brackets get the existingne-class error; identity parsing limited to identity operators and converted entries; serverParseIdentitySelectionhas no range flag;ControlJobname pre-validation only for bracketed names;test_idgenseed cases pin the timestamp; idgen overflow boundary stated exactly; line references corrected. -
Round 5 (2026-10-01): 8 issues (one overlap), all fixed: line references; xcecli rejects an all-
*name part; bracketedjob_namenull/notnullrejected like thejob_idcomparison operators, withnotcontainsnegation scope stated;GetJobsInfovalidates all filter entries in a pre-pass beforeexec_hostsresolution; the one new operator rejection stated honestly and added to the Error table; Allowed Dependencies split between parsers and predicate building; harness and xcecli rows completed in the Error table; pre-store key checks aligned with Matching for convertedbetweenentries. -
Round 6 (2026-10-01): requirements review found 1 issue, fixed: the round-5 client rejection of an all-
*name part (-J '*[1]') had no authorising criterion; the name part may now be empty (contains→ every array,eq→ no job), so no rejection is added. Code review found 1 issue, fixed: submit-expression errors pass throughpreCheckJobRequestunwrapped andCreateJobmaps*ArrayExprErrorto 400 viaerrors.As(it mapped every preCheck error to 500), with a typed-nil guard. -
Round 7 (2026-10-01): requirements review found 2 issues, fixed:
preCheckJobRequestreturns(n, isArray, err)andCreateJobbranches onisArray(soname[1]is a one-element array);createArrayNameis kept for names without brackets so their validation and errors are unchanged (1.4). Code review found 3 issues: 2 duplicated the requirements findings (already fixed); 1 new, fixed: unnamed jobs are stored withjob_name "", so an empty name part witheq/in/notinnow matches no row (otherwisekill -J '[1]'would hit every unnamed array). -
Round 8 (2026-10-01): code review found 3 low issues, fixed: the four
preCheckJobRequesttest call sites listed; error returns written for the new(n, isArray, err)shape; interactive passed asreq.Interactive != 0. Requirements review found 2 issues: 1 duplicated the code finding (fixed); 1 new, fixed: 1.4 traced to ApiCreateJob's unchangedcreateArrayNamepath instead of the parser. -
Round 9 (2026-10-01): requirements review found 2 issues, fixed:
CreateJobtest seams (generateJobID,generateArrayJobID,submitJobpackage variables) with the submit tests in a new!cgofile next to the JWT/RBAC fixtures; the bracketed-name success path stated (req.JobName = arrayName,(n, true, nil)at today's early return). Non-Goals wording on the interactive check corrected. Code review found 5 issues: 1 duplicated (test seams, fixed); 4 new, fixed: line numbers corrected; the unnamed-job success return (:1746) stated; the REPL claim corrected (itsstrtoullfallback keeps behaviour unchanged);ToAPIJobIDdescribed as a signature change with all call sites listed. -
Round 10 (2026-10-01): code review found 1 issue, fixed: the submit parser's limit comes from
utils.JobYamlConfig.MaxArraySize, and the!cgosubmit tests set and restoreJobYamlConfig(nil in tests otherwise). Requirements review found 1 issue, fixed: acontrolJobseam at both control dispatch sites; every handler-level submit/query/control test moved into the new!cgojobs_handler_test.go(fixtures and dispatch observable);jobs_test.gokeeps pure-function cases only. -
Round 11 (2026-10-01): code review found 2 issues, fixed: handler tests seed
store.Queuesand a controllablejob_status(else control returns 403 before dispatch);ControlJobByIDre-dispatches earlier selections per later selection -- logged as bug-1899, and the design now dispatches a de-duplicated list once after the selection loop. -
Round 12 (2026-10-01): requirements review found 1 issue, fixed: the bug-1899 "dispatch once" rule now keeps the per-selection not-found maps in the response (collected separately from the de-duplicated act-on list). Code review found 2 issues, fixed: handler tests seed after
setupRBACTest(which resets the stores) and assert real dispatch;validateJobControlruns once on the de-duplicated list after the loop, and a dispatch error stays a 500. -
Round 13 (2026-10-01): code review found 1 low issue, fixed:
validateJobControlis per row, so it is called once per de-duplicated job after the loop (signature unchanged). -
Round 14 (2026-10-01): code review found 1 issue, fixed:
TestToAPIJobIDPassthrough's"123456[3]"is misaligned under the client's 5.8 check; replaced by"32768[3]"plus a rejection case;jobid_test.go:109added to the call-site list withallowRange=false. -
Round 15 (2026-10-01): requirements review found 1 issue (introduced by the round-14 edit), fixed: the
ToAPIJobIDcall-site list now statescontroller.go:52passesallowRange=trueand only the list/test sites passfalse; tests added that catch a wrong flag. -
Round 16 (2026-10-01): code review: no issues. Requirements review found 2 issues, fixed: every rejection after registration replies before releasing the registry entry (table-hit path and the existing payload/OOM early-outs), so a submission blocks others until answered (7.11, Terms); the xcecli control test placed in a new
cmd/jobs/controller_test.gowith its httptest mechanism. -
Round 17 (2026-10-01): requirements review found 1 issue, fixed: reply and registry removal are now one atomic step under the registry lock (
inflight_reply_and_remove,xce_replybeing non-blocking) on every post-registration path, closing both ordering windows; the System Flows diagram matches. Code review found 1 issue (the undefined "reply hook"), fixed together with the atomic step: anXCE_TESTINGhook insideinflight_reply_and_removeplus a test-only overlap accessor; the concurrent check runs on a second thread because the hook holds the registry lock. -
Round 18 (2026-10-01): code review found 2 issues (no deadlock risk found), fixed:
inflight_reply_and_removeis the only registry removal --jobsubmit_async_ctx_releaseno longer callsinflight_range_remove, and the async paths call it inside their one-shot reply guard; the atomicity test uses deterministic in-hook checks (trylock EBUSY, reply queued, entry still present) instead of a second thread. Requirements review found 1 issue, fixed: classification runs before the existing field checks and hook, so 7.1/7.9 hold even when an index-0 array also has an empty field. -
Round 19 (2026-10-01): code review found 2 low issues (and confirmed no registry entry can leak and no hook consumer acts on the moved before-event), fixed:
inflight_reply_and_removetakes(ep, from, reply, base, size)so the async paths can call it; classification is anchored as the first statement afterinit_reply_by_req. -
Round 20 (2026-10-01): both reviewers (requirements fidelity; code feasibility) reported NO ISSUES. Review loop closed.
Risks & Mitigations
- Rolling upgrade: an old API server or harness sends index-0 arrays to an upgraded controller. Rejected with the distinct
E_XCE_ARRAY_START0status and an explanatory log line (7.1). Recommended order for clusters using arrays: API servers and harness first, then controllers (an old controller acceptsarray-id | 1submissions); controllers first is supported with that rejection window accepted (design.md, Migration Strategy). - Three parser implementations drift. Shared conformance case table, plus a review checklist item in tasks.
- Control-result display of pre-upgrade element 0 needs the element's own ID. Accepted and failed result maps already carry
unique_job_id; the apiserver adds it to not-found maps. xcecli printsFormatJobID(unique_job_id)when it is present and falls back to today's rendering otherwise (an older server). - The array-identity collision check walks up to 32768 hash keys inside a vtask handler. One read-lock hold for the whole scan, which also answers the element-range check; bounded CPU, no I/O, permitted by
ha-async-io.md. The cost is paid only by array submissions. An apply-maintained array-ID index was rejected (it would need completeness across apply, replay and snapshot load, audit dimension 7). idgen_arrayrefusing a block past the 20-bit sequence surfaces as a submit error after about 31 arrays in one second from one API server. That is the same limit as today, except it is now an error instead of a corrupted ID. It is recorded as a known limit. The harness's random sequence seed is bounded below30 * 32768so that its first array cannot hit the limit.
References
.kiro/specs/job-array-one-based-index/requirements.md: decisions 1-10 and the Boundary notes..kiro/specs/job-array-single-wal-record/: the array WAL record and expansion this design relies on unchanged..kiro/steering/ha-async-io.md,error-handling.md,api-standards.md,testing.md,persistence.md.- LSF 10.1 Administration Guide, "Chunk Jobs and Job Arrays" (p.519): index 0 is invalid;
LSB_JOBINDEXis 0 only for non-array jobs.