Skip to content

Commit 511bedc

Browse files
committed
docs(planning): publish capacity and storage reference navigation
1 parent d97c1e6 commit 511bedc

3 files changed

Lines changed: 174 additions & 1 deletion

File tree

‎docs/orgmode/index.org‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ Version 0.7.3 is the crates.io package and the GitHub release. ``package plan``
127127

128128
reference/glossary
129129
reference/cli
130+
reference/planning-capacity
130131
reference/mcp
131132
reference/package-bundles
132133
reference/targets

‎llms-full.txt‎

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6702,6 +6702,7 @@ Package commands take the toolchain as `--toolchain name/version`, the spelling
67026702
| `stack gap` | Route each site module the stack lacks, name the recipe that closes it, and write one TSV per route |
67036703
| `stack batch` | Plan software-layer pull requests whose builds do not overlap |
67046704
| `stack shard` | Split a Jenkins build list into shards that build at once, with a prelude of shared dependencies, capped by a scratch inode quota |
6705+
| `stack capacity` | Read timestamped advisory scheduler capacity with exact partition, host profile and resource constraints |
67056706
| `stack footprints` | Write the peak build-tree inode count per software name from ledger records, a static table, and a class table |
67066707
| `stack admit` | Admit one build job under the scratch inode quota, counting the reservations of the jobs still running |
67076708
| `stack easystack` | Write a lock as the YAML `eb --easystack` reads |
@@ -8868,7 +8869,7 @@ plus sandboxed recipe and easyblock tools:
88688869
(easyblocks; `eb_build_test` only with `EB_STACK_ALLOW_BUILD=1`);
88698870
- `eb_stack_solve`, `eb_stack_sbom`, `eb_stack_order`,
88708871
`eb_stack_easystack`, `eb_stack_gap`, `eb_stack_provided`,
8871-
`eb_stack_shadow`, `eb_stack_batch`, `eb_stack_shard`,
8872+
`eb_stack_shadow`, `eb_stack_batch`, `eb_stack_shard`, `eb_stack_capacity`,
88728873
`eb_stack_arch`, `eb_stack_files`,
88738874
`eb_stack_generation`, `eb_stack_cuda_cc`, `eb_stack_known_failures`,
88748875
`eb_stack_oom`, `eb_stack_bot_classify`, `eb_stack_sections`,
@@ -9024,6 +9025,176 @@ takes `changes` as an optional path array. `eb_recipe_check`'s
90249025
`eb_recipe_edit`, and `eb_recipe_write` edit files only inside the workspace
90259026
root.
90269027

9028+
# Scheduler capacity and phase storage
9029+
9030+
See [the captured capacity and storage-policy interface](https://eb-stack.rgoswami.me/planning-capacity.html.md) for schema, synthetic examples and the execution/admission contract. The optional `stack shard --storage-policy` path does not change default execution or grant admission.
9031+
9032+
# Scheduler capacity and phase storage
9033+
9034+
# Capacity is an observation
9035+
9036+
`stack capacity` reads one normalized JSON snapshot. It does not query the
9037+
scheduler, probe hosts, predict a queue wait, reserve a node or grant storage
9038+
admission. The collector owns a bounded cached scheduler query and its
9039+
provenance. The report contains aggregates and input hashes, not node names.
9040+
Account, QOS, priority, reservations and intervening scheduler changes can
9041+
prevent a reported fit from starting.
9042+
9043+
The node `target` is an explicit maintained physical-host profile label.
9044+
It is not a CPUID, guest or compiler-ISA attestation. Execution identity and
9045+
compiler-target checks remain authoritative. Available and active features
9046+
are distinct. Required features are literal names combined with AND;
9047+
expressions are rejected rather than simplified.
9048+
9049+
The synthetic input is [snapshot.json](https://eb-stack.rgoswami.me/../../../tests/planning_capacity_fixtures/snapshot.json.html.md). Its schema version is 1:
9050+
9051+
- `observed_at` is the observation start; `observed_until` optionally records
9052+
its end. `raw_sha256` optionally binds the original scheduler response.
9053+
- `partition_inventory_complete` must establish full requested-partition
9054+
visibility. `selected_partitions` can explicitly name a known empty view.
9055+
An incomplete or missing view produces unknown/null advice, never a
9056+
measured zero or automatic storage route.
9057+
- `nodes` contains unique `name`/`target` pairs, exact `partitions`,
9058+
`available_features`, `active_features` and `state_flags`.
9059+
- `cpus_allocatable` is scheduler-effective CPU capacity before subtracting
9060+
`cpus_allocated`. Memory and GPU fields have the same meaning, with
9061+
`memory_mib_**` and `gpus_**` names. Optional `*_total` fields bound them.
9062+
Missing values are null/unknown. Inconsistent allocations are excluded.
9063+
- Scheduler memory uses usable configured memory minus allocated memory.
9064+
OS `FreeMem` and `cpu_load` do not decide fit. The collector normalizes
9065+
scheduler-specific units and unknown sentinels; CPU load is informational.
9066+
- `pending_jobs` is optional. Each row has an ID, state, partitions, optional
9067+
physical target and feature constraints, and total job CPU/memory/GPU
9068+
demand. Missing constraints/resources remain visible as possible demand;
9069+
absent pending data is unknown. `pending_complete` must not claim absent
9070+
data is complete.
9071+
9072+
The [scheduler field reference](https://slurm.schedmd.com/scontrol.html) defines allocated memory and node states;
9073+
[the node-state reference](https://slurm.schedmd.com/sinfo.html) identifies drained, reserved and down resources.
9074+
The normalized schema avoids depending on one scheduler JSON plugin version.
9075+
Collectors must include hidden configured partitions when establishing a
9076+
complete view, and minimize scheduler RPCs.
9077+
9078+
```sh
9079+
eb-stack stack capacity \\
9080+
--snapshot tests/planning_capacity_fixtures/snapshot.json \\
9081+
--partition local --target example/host --feature scratch-node \\
9082+
--cpus 4 --memory-mib 4096 --exclusive-node true --max-slots-per-node 1 \\
9083+
--generated-at 2026-01-01T12:00:10Z
9084+
```
9085+
9086+
The example reports one queue-fitting node and one free slot. These are
9087+
advice, not an allocation. `ALLOCATED` can count as a future queue fit but
9088+
has no free slot; drained, reserved, down and unknown states do not count.
9089+
Per-node CPU, memory and GPU fits are computed before totals are added, so
9090+
fragments on different nodes cannot create a fictitious fitting node.
9091+
9092+
Requests contain resolved demands. Raw scheduler `--mem`0= means whole-node
9093+
memory; it is not a zero-memory request. Resolve it, and partition defaults,
9094+
before supplying a positive `memory_mib`. A CPU-only request does not require
9095+
known GPU capacity; the GPU aggregate stays null when unknown.
9096+
9097+
`exclusive_node`true= limits a node to one slot and excludes busy nodes from
9098+
free exclusive fits. Explicit `false` permits resource-based sharing;
9099+
`max_slots_per_node` can impose a stricter positive limit. Unknown
9100+
exclusivity yields null free-slot advice and disables automatic placement.
9101+
A configurable maximum observation age rejects stale or future snapshots.
9102+
`--generated-at` makes replay deterministic. SHA256 covers the exact input
9103+
bytes, including whitespace.
9104+
9105+
# Storage advice is opt-in on stack shard
9106+
9107+
The synthetic [storage-policy.json](https://eb-stack.rgoswami.me/../../../tests/planning_capacity_fixtures/storage-policy.json.html.md) selects one captured snapshot by path and
9108+
expected SHA256. Its fields are:
9109+
9110+
- `schema_version`1`, `capacity_snapshot`, `capacity_sha256=,
9111+
`max_age_seconds` and the literal `node_local_feature`.
9112+
- `shared_budget` with `observed_at`, live `available_inodes`,
9113+
`reserved_inodes` and `margin_inodes`. Its margin must equal the caller's
9114+
configured `--inode-margin`; stale shared observations are refused.
9115+
- `profiles` for `cpu_prerequisites`, `prelude` and `shards`.
9116+
Each specifies `compile_target`, `shared_route`, `node_local_route`,
9117+
and `shared`/`node_local` resolved capacity requests. Physical host labels
9118+
and compile targets are independent, including emulated execution routes.
9119+
The node-local request must retain the configured feature exactly.
9120+
9121+
```sh
9122+
eb-stack stack shard \\
9123+
--build-list tests/stack_shard_fixtures/wave1.list \\
9124+
--easyconfigs tests/stack_shard_fixtures/easyconfigs \\
9125+
--installed tests/stack_shard_fixtures/installed.txt \\
9126+
--installed-modules-dir tests/stack_shard_fixtures/modules/all \\
9127+
--shards 4 \\
9128+
--storage-policy tests/planning_capacity_fixtures/storage-policy.json \\
9129+
--generated-at 2026-01-01T12:00:10Z --out-dir build/capacity-demo
9130+
```
9131+
9132+
`--storage-policy` and `--inode-quota` are mutually exclusive planning budget
9133+
sources. Without a policy, existing constructors, fields and execution
9134+
behavior remain unchanged. The opt-in path annotates every nonempty CPU
9135+
prerequisite, prelude and shard phase. It orders phases by inode footprint,
9136+
then phase ID; smallest phases spend the observed shared budget first.
9137+
Overflow phases select `node-local` only when the exact configured route has
9138+
known queue-fitting feature-eligible hosts. They can be allocated already:
9139+
queue eligibility does not promise a free node. Without a verified eligible
9140+
view, a phase stays shared with `awaiting_shared_admission`.
9141+
9142+
Each real phase gains `placement` (`shared` or `node-local`) and `storage`:
9143+
`phase_id`, `decision`, `compile_target`, the exact `request`,
9144+
`execution_route`, `requires_real_disk`, `requires_node_local_disk`,
9145+
`admission_required`true`, `admission_bypass`false` and
9146+
`execution_storage_verification_required`true=. The plan-level
9147+
`storage_policy` records captured policy/snapshot hashes, observed budget,
9148+
capacity advice and deterministic phase order. Existing dependency/phase
9149+
ordering remains required; these annotations do not authorize parallelizing
9150+
CPU prerequisites with their consumers.
9151+
9152+
Footprint JSON accepts numeric rows and metadata rows, for example:
9153+
9154+
```json
9155+
{"default":60000,"footprints":{"Large":{"inodes":123456,"requires_real_disk":true}}}
9156+
```
9157+
9158+
Numbers, storage hints and their reported footprint digest come from the
9159+
same captured bytes. A pathname update cannot change one without changing
9160+
the others. Real-disk requirements are propagated to every affected phase.
9161+
9162+
# Execution contract
9163+
9164+
A planning string never disables shared quota admission. The execution
9165+
adapter verifies SHA256 of the final `plan.json` file, phase ID, exact
9166+
request/route, allocation/job identity, separate host/compiler identities,
9167+
and the selected storage domain before choosing its normal admission pool.
9168+
The plan's `inputs.sha256` is an input digest, not a substitute for hashing
9169+
the final plan file.
9170+
9171+
Build, temporary, source-index and isolated guest-home roots belong on the
9172+
verified node-local disk for node-local phases. Final installation prefixes
9173+
and declared durable work/log roots remain on their configured persistent
9174+
filesystems. Source archives remain in approved durable caches; there is no
9175+
redundant recipe-tree or source extraction. Any remaining mutable path in a
9176+
shared scratch quota domain still requires that domain's admission.
9177+
9178+
The adapter binds mount/device/backing facts and all mutable-root roles in
9179+
an execution receipt. A guest needs a host backing proof and the existing
9180+
kernel-bound execution identity; a guest filesystem name alone cannot prove
9181+
NVMe backing. Disk requirements reject RAM-backed execution. Only validated
9182+
observations select domain-scoped available-inode counters, reservations
9183+
and live writers for the ordinary `stack admit` gate. The receipt/domain
9184+
identity is retained in execution records. This interface adds no bypass
9185+
flag and performs no installation relocation.
9186+
9187+
Each emitted phase `storage` object binds `list_file` and `list_sha256` to the
9188+
exact generated list bytes. Execution verifies these fields together with the
9189+
final plan file digest; `inputs.sha256` is an input fingerprint, not the final
9190+
plan digest.
9191+
9192+
With `--materialize`, `execution_list_file` and `execution_list_sha256` bind
9193+
the generated `*.local.list` bytes actually consumed by the build driver.
9194+
Without materialization these fields bind the ordinary list. The original
9195+
`list_file` and `list_sha256` remain available in both modes. An executor
9196+
accepts only the explicitly bound execution list, not a filename alias.
9197+
90279198
# Model Context Protocol server
90289199

90299200
`eb-stack mcp` serves the version-one commands on stdin and stdout.

‎llms.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ The binary is `eb-stack`. The crate is `eb_stack`. Rust 1.90 or newer builds it
5353

5454
- [Glossary](https://eb-stack.rgoswami.me/reference/glossary.html.md): Names shared by the tutorial, the how-to guides, and the reference.
5555
- [Command-line reference](https://eb-stack.rgoswami.me/reference/cli.html.md): eb-stack has seven namespaced command groups (package, recipe, stack, target, campaign, repro, ledger), four reports (easyblock-reach, pr-overlap, rebuild-set, component-reach), and a Model Context Protocol (MCP) server.
56+
- [Scheduler capacity and phase storage](https://eb-stack.rgoswami.me/reference/planning-capacity.html.md): stack capacity reads one normalized JSON snapshot.
5657
- [Model Context Protocol server](https://eb-stack.rgoswami.me/reference/mcp.html.md): eb-stack mcp serves the version-one commands on stdin and stdout.
5758
- [Package bundle reference](https://eb-stack.rgoswami.me/reference/package-bundles.html.md): package inspect, package plan, and package bump write a version-one package bundle.
5859
- [Build target configuration](https://eb-stack.rgoswami.me/reference/targets.html.md): A target routes one EasyBuild workload through four independent layers: transport, executor, runtime, and EasyBuild settings.

0 commit comments

Comments
 (0)