--- id: "bug-1933" status: "fixed" status_updated: "2026-10-10" status_note: "" component: "scheduler" severity: "wrong-result" timestamp: "2026-10-10T03:36:53Z" last_seen: "2026-10-10T03:36:53Z" occurrences: 1 files: ["src/scheduler/src/plugins/limit.c", "src/lib/xcelimit.c"] tags: ["scheduler", "limit", "project", "hostgroup"] related: ["bug-1785"] fix_commits: ["6ecd418d"] gitea_issue: 358 gitea_synced_status: "fixed" gitea_synced_hash: "0d19e8b066b2" --- # bug-1933: xce_scheduler limit plugin resolves hosts: scopes against project groups (host-group limits ignored) ## Description **Observed:** The scheduler's limit plugin built every limit with the host-group and project-group managers swapped. A limit scoped to a host group never matched that group's hosts; a limit scoped to projects resolved its member names against the host groups. The new regression test, before the fix: ``` ../scheduler/testsuite/test_limit_plugin.c:491:test_limit_scopes_resolve_against_own_group_kind:FAIL: Expected 1 Was 0 ``` (host group `hg1` = {`hostA`}; a limit with `hosts: [hg1]` did not match host `hostA`.) **Expected:** a limit's `hosts:` members resolve against the host groups (`hosts: [hg1]` matches every host in `hg1`), and its `projects:` members resolve against the project groups (a project name never matches a host group). **Impact:** wrong result, silent. Every host limit that names a host group applies to no host (only to a host literally named like the group), so the limit is never enforced. A project limit whose member name equals a host group's name matches the projects named like that group's hosts instead of the project itself. Limits naming plain host or project names, and limits without host/project scopes, are unaffected. In addition, the groups a limit builds for its own scopes were registered in the wrong manager (`-pg-group` in the host groups, `-hg-group` in the project groups). **Found by:** review, during `/kiro-spec-requirements project-config` (2026-10-10, codebase survey of project-scoped limits). ## Environment - OS: no /etc/os-release; Docker container; NixOS kernel; kernel Linux 6.18.33 x86_64 - libc: glibc 2.42-47 (interpreter /nix/store/wb6rhpznjfczwlwx23zmdrrw74bayxw4-glibc-2.42-47/lib/ld-linux-x86-64.so.2) - Toolchain: gcc (GCC) 15.2.0, meson 1.9.1 - Build: asan (xce.build), `ASAN_OPTIONS=detect_leaks=0` - Code: scheduler-framework @ 25cdbc79-dirty - Deployment: n/a (unit test of the scheduler limit plugin); the defect is in code shared by the live scheduler and `xce_scheduler --sim`. ## Reproduction 1. `cd src && nix develop . --command meson compile -C xce.build sched_limit_plugin_test` 2. `ASAN_OPTIONS=detect_leaks=0 ./xce.build/scheduler/testsuite/sched_limit_plugin_test` 3. Test `test_limit_scopes_resolve_against_own_group_kind` (`src/scheduler/testsuite/test_limit_plugin.c`): loads host group `hg1` = {`hostA`}, configures limit `host_scoped` with `hosts: [hg1]` and limit `project_scoped` with `projects: [hg1]`, then checks `match_limit()` for host `hostA`/`hostB` and project `hostA`/`hg1`. - Frequency: deterministic - Evidence: the test above; no logs kept. ## Root cause `build_limit()` (`src/lib/xcelimit.c:292`) takes its group managers as `(ugmgr, qgmgr, hgmgr, pgmgr)`, but `limit_seed_config_impl()` (`src/scheduler/src/plugins/limit.c:77`) passed `(core->ugmgr, core->qgmgr, core->pgmgr, core->hgmgr)`. `build_consumer()` therefore built the HOST consumer with the project-group manager and the PROJECT consumer with the host-group manager. `make_g_member()` (`src/lib/group.c`) treats a member name as a nested group only if the manager it is given knows that group, so `hg1` became a literal host name (the project-group manager is empty) and a project member named like a host group became that host group. Since `ecf1916d` (2026-01-12, "support limit"), the first version of the plugin call; carried through `7c229284` and `487e7b94`. Scope: `limit.c:77` is the only production caller of `build_limit()` (checked with `grep -rn "build_limit("`); the lib tests (`src/lib/testsuite/test_limit.c`) pass the managers in the right order. ## Fix `src/scheduler/src/plugins/limit.c`: pass `(core->hgmgr), (core->pgmgr)` in the order `build_limit()` declares, so each scope resolves against its own kind of group. No wire, WAL, snapshot or config change. The project-group manager is still never loaded from config (projects have no config yet); that is `project-config` scope (Requirement 6.7). `src/scheduler/testsuite/test_limit_plugin.c`: new regression test; `main()` now initializes the interned-string table (`xstring_table_init()`), which group names need and which no earlier test in this binary exercised. ## Verification - Test: `test_limit_scopes_resolve_against_own_group_kind` (`src/scheduler/testsuite/test_limit_plugin.c`): RED before the fix (`Expected 1 Was 0` at line 491, `hosts: [hg1]` not matching `hostA`), GREEN after (6/6 in `sched_limit_plugin_test`). - Suites: scheduler suite 119/119 OK, libxce tests 2/2 OK, asan (`xce.build`), 2026-10-10. - Live: n/a: the change is one argument order in config-time limit construction, fully covered by the unit test; no live limit run. ## References - Found during: `.kiro/specs/project-config/requirements.md` (Requirement 6.7) - Introduced: `ecf1916d`