- .wolf/anatomy*, memory.md: hook-maintained index and session log through the bug-1851..1854 work. - .kiro/specs/libxce-alloc-preason-equality/: requirements, design, research and tasks generated; none approved yet (spec.json phase tasks-generated). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
74 lines
7.7 KiB
Markdown
74 lines
7.7 KiB
Markdown
# Research & Design Decisions
|
|
|
|
## Summary
|
|
- **Feature**: `libxce-alloc-preason-equality`
|
|
- **Discovery Scope**: Extension (relocate existing comparison logic, add public API, migrate consumers)
|
|
- **Key Findings**:
|
|
1. The type-level equality comparators in `sim_verify.c` operate purely on libxce structs with zero scheduler/capnp/replay dependency — they are cleanly movable; the decision-level dispatcher and mismatch reporting are not.
|
|
2. The comparators are already shared across four translation units, but via white-box `#include "../src/sim_verify.c"` + direct calls to `static` functions (`test_sim_equivalence.c`, `test_repl_equivalence.c`, `test_repl_limit_table.c`).
|
|
3. The controller (`persist.c`, `resync.c`, `job.c`) already consumes `xce_job_alloc_t`/`xce_host_alloc_t`/`xce_job_preason_t`/`xce_alloc_t` with no equality API — confirming these structs are genuinely cross-component, not scheduler-only.
|
|
4. One deliberate field exclusion is baked into the alloc comparators (`from`/`instid`), which generalizes cleanly into a shared identity contract. The preason comparator's main-reason-only narrowing is *not* an identity property — it is a replay artifact (bug-1845) that must stay in the simulator while the shared `job_preason_eq` becomes a full match.
|
|
|
|
## Research Log
|
|
|
|
### Where do the equality checks live?
|
|
- **Context**: locate all comparison logic in the scheduler simulator.
|
|
- **Sources Consulted**: `src/scheduler/src/sim_verify.c` (full read); `src/scheduler/src/sim_loop.c`, `sim_alloc.c`, `sim_picker.c`, `sim_limit.c` (grep for `_eq`/`_equal`/`compare`).
|
|
- **Findings**: `sim_verify.c` (474 lines) is the only file with equality logic. It holds five `static` leaf comparators plus `sim_decision_eq`, `sim_log_mismatch`, and two `describe_*` helpers. No other sim file compares these structs.
|
|
- **Implications**: the split point is exactly between the five `static` leaf functions and `sim_decision_eq`.
|
|
|
|
### Who consumes these comparators, and how?
|
|
- **Context**: understand the "future sharing" concern.
|
|
- **Sources Consulted**: grep for `sim_verify_job_alloc_eq`/`sim_verify_job_preason_eq`/`sim_verify_alloc_eq` across `src/scheduler/testsuite/`.
|
|
- **Findings**: three test files call the two leaf comparators directly after white-box-including `sim_verify.c`: `test_sim_equivalence.c:894,902`, `test_repl_equivalence.c:734,742`, `test_repl_limit_table.c:2662,2670`. Each builds its own `replay_decision_content_eq`-style helper on top of the two leaves.
|
|
- **Implications**: moving the leaves to libxce turns a fragile include-and-call-static hack into a normal public API; these three files must migrate their call sites.
|
|
|
|
### Are these structs shared beyond the scheduler?
|
|
- **Context**: justify libxce as the destination rather than "scheduler convenience".
|
|
- **Sources Consulted**: grep for the four struct names across `src/controller`, `src/worker`, `src/harness`, `src/lib`.
|
|
- **Findings**: `xce_job_alloc_t`/`xce_host_alloc_t`/`xce_job_preason_t`/`xce_alloc_t` are consumed by `src/controller/persist.c` (Cap'n Proto encode/decode), `src/controller/resync.c`, and `src/controller/job.c`, plus the scheduler. No equality API exists anywhere.
|
|
- **Implications**: the controller is a real future consumer of equality; the API belongs in libxce.
|
|
|
|
### Where do the structs' construction/dup helpers already live?
|
|
- **Context**: choose the destination module.
|
|
- **Sources Consulted**: `src/lib/xcealloc.c` (read full), `src/include/xcealloc.h`, `src/lib/preason.c`, `src/include/preason.h`.
|
|
- **Findings**: `make_alloc`/`make_host_alloc`/`make_job_alloc`/`dup_job_alloc`/`make_job_account` in `xcealloc.c`; `erase_job_preason`/`add_job_preason`/`make_pendreason` in `preason.c`. No existing `_eq`/`_equal` convention in libxce (only `float_equal` in `utils.h`); no NULL-safe string-equality helper exists.
|
|
- **Implications**: co-location with construction is the natural home; the string helper is new and only needed by the alloc family today.
|
|
|
|
## Architecture Pattern Evaluation
|
|
|
|
| Option | Description | Strengths | Risks / Limitations | Notes |
|
|
|--------|-------------|-----------|---------------------|-------|
|
|
| Co-locate in existing modules | equality beside `make_*`/`dup_*`/`erase_*` | matches precedent, no new module | none material | selected |
|
|
| New `xce_equality.{c,h}` | one module for all four | single discoverable location | new module for 4 small functions | rejected (YAGNI) |
|
|
| Leave in scheduler, expose via header | promote the statics to scheduler-external | minimal | controller can't use them; wrong ownership | rejected |
|
|
|
|
## Design Decisions
|
|
|
|
(Full decisions live in `design.md`; the significant trade-offs are recapped here.)
|
|
|
|
### Decision: `job_preason_eq` is a full structural match; the simulator keeps its own main-reason-only PEND check
|
|
- **Context**: `sim_verify_job_preason_eq` compares only `main_reason`, deliberately (bug-1845) — sim has no alloc cache, so its full detail can never match a recorded cache-hit's main-reason-only shape; requiring detail to match produced systematic false mismatches. That narrowing answers "same replay outcome", not "identical pending-reason objects".
|
|
- **Alternatives Considered**:
|
|
1. Publish full-deep `job_preason_eq` + keep a `static` main-reason-only helper in `sim_verify.c` for the PEND branch (selected).
|
|
2. Publish `job_preason_eq` as main-reason-only (rejected — leaks a replay artifact into a general-purpose equality API).
|
|
- **Selected Approach**: `job_preason_eq(a, b)` returns non-zero iff `main_reason` matches and both detail lists (host-based, resource-based) match in order field-for-field. `sim_decision_eq`'s PEND branch uses a small simulator-local `static` main-reason-only comparison instead of `job_preason_eq`.
|
|
- **Rationale**: a public "same pending reason" predicate must be identity-honest; the replay asymmetry is a scheduler-only concern and stays where it belongs.
|
|
- **Trade-offs**: two PEND-comparison shapes exist (full-match in libxce, main-reason-only in sim_verify.c) — intentional, they answer different questions, and the sim-local helper is `static` and small.
|
|
- **Follow-up**: none expected; the sim-local helper is not exported.
|
|
|
|
### Decision: preserve NULL and order semantics exactly
|
|
- **Context**: the current leaf comparators use "identical pointer (including both NULL) → equal; exactly one NULL → not-equal", and ordered list comparison.
|
|
- **Selected Approach**: reproduce exactly in libxce.
|
|
- **Rationale**: the relocation is required to be zero-behavioral-change (Requirement 3); ordered comparison is correct because both sides come from the same deterministic construction.
|
|
|
|
## Risks & Mitigations
|
|
- Risk: a consumer silently relies on the excluded fields (`from`/`instid`, preason detail) → Mitigation: explicit doc contract on each function + revalidation triggers; no behavior change for existing consumers.
|
|
- Risk: migration of the three white-box test files breaks their `replay_decision_content_eq` helpers → Mitigation: mechanical call-site rename, verified by the full scheduler suite (task 7).
|
|
- Risk: duplicate-symbol collisions if a test both white-box-includes `sim_verify.c` and links libxce after the statics are removed → Mitigation: the statics are deleted from `sim_verify.c` (task 4) before the test files migrate (task 5), so the names resolve only against libxce.
|
|
|
|
## References
|
|
- `src/scheduler/src/sim_verify.c` — current home of the comparators (source of truth for field lists and exclusion rationale).
|
|
- `src/include/xce/types.h` — the four struct definitions.
|
|
- `src/lib/xcealloc.c`, `src/lib/preason.c` — destination modules and their construction/dup conventions.
|
|
- `.kiro/specs/scheduler-snapshot-job-allocation/` — precedent for a scheduler-driven spec adding libxce helpers (`dup_job_alloc`) to `xcealloc.c`.
|