docs(spec): application profiles hold essentials only; additive rule; client-side presets

- profiles hold only what every job of the application must have; every
  profile value binds and a job may add to it, never change or remove it
  (replaces the default/fixed markers of 2026-10-09)
- convenience defaults move to client-side presets (new xcecli-presets
  brief): option-level expansion on the client, the apiserver only shares
  admin-deployed presets read-only, pull copies, export/import
- service section stays in the profile: probes, restart policy, ports bind;
  replica count within the profile range; spread/rollout if unset
- job-config-layering, job-config-merge brief/requirements, roadmap and
  resource-questions updated to the additive rule
- app:override and profile inheritance deferred; recommendations target
  site presets

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-12 09:47:30 +00:00
parent 3fa9361ad8
commit 4536d36f47
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
7 changed files with 267 additions and 115 deletions

View file

@ -14,11 +14,10 @@ decisions):**
(min / default / max, LSF TASKLIMIT), **project** = resource ownership
(`project-config`).
- Every attribute has one owning level (`.kiro/steering/job-config-layering.md`).
How the levels interact is owned by **`job-config-merge`**: each profile
attribute is *default* (the job may replace it) or *fixed* (the job may
not; for `select` it may only add ANDed terms); queue ceilings and project
quotas only check, never change, the job's values. This answers the open
question "how resource defaults combine with a job's own resreq" below.
How the levels interact is owned by **`job-config-merge`**; queue
ceilings and project quotas only check, never change, the job's values.
(The job-vs-profile rule of this update, *default*/*fixed* markers, is
replaced by the additive rule of 2026-10-12 below.)
- **Pre/post-exec moves here from the queue** (queue `pre_exec`/`post_exec`
deprecated). The profile's pre/post-exec is admin-defined and always runs
as the outer layer; the job's own pre/post-exec is the inner layer, allowed
@ -38,8 +37,9 @@ decisions):**
**Update 2026-10-10 (`/kiro-discovery`, long-running services):** a profile
may declare **kind `service`** with a service section: restart policy
(always / on-failure / never, backoff, give-up), liveness and readiness
probes (command / TCP / HTTP), named ports, default replica count, spread
rule and rollout settings. The section is defined with this spec and
probes (command / TCP / HTTP), named ports, replica range, spread rule and
rollout settings (how these follow the additive rule: "Essentials and the
additive rule" below). The section is defined with this spec and
consumed by `service-supervision` (worker probes and restarts),
`service-replica-set` (replicas, scaling, rolling update) and
`service-endpoint` (ports, endpoints).
@ -53,23 +53,38 @@ consumed by `service-supervision` (worker probes and restarts),
that is not defined is a configuration error everywhere (`xceadmin`, live
upgrade, controller start), never a silent fallback. See "Default profile"
below.
- **This spec owns the profile's attribute schema**: which attributes exist
and how each is marked *default* or *fixed*. `job-config-merge` consumes
that schema and owns only the merge and live re-evaluation.
- **Purpose: convenience first, enforcement where needed** (user, 2026-10-12).
A profile saves users from repeating the same resreq and other settings on
every job; most values are defaults the job may change. Only what the
application cannot run without is fixed. Consequences:
- Profile defaults will sometimes not fit, and users will tune them
(sizing, placement). The profile gives room to try: default terms, with
admin-set ranges for numeric values.
- **This spec owns the profile's attribute schema** (which attributes exist
and what each holds). `job-config-merge` consumes that schema and owns the
merge and live re-evaluation.
- **A profile holds only essentials; convenience lives in client-side
presets** (user decision, 2026-10-12). "The profile holds what the job must
have; the preset holds what the user would like." A profile value is
something the application needs or the admin enforces, and it binds every
job of that profile. The *default*/*fixed* markers of 2026-10-09 are
dropped: there are no markers, and no per-term markers or ranges. See
"Essentials and the additive rule" below.
- **Additive rule:** the job may add to the profile's values, never change
or remove them. A conflict is rejected at submit with an error naming the
profile value, never resolved silently.
- **Convenience defaults** (tuning such as `rusage[mem=...]`,
`span[ptile=...]`, task count, extra env) go into **presets**, handled
fully by the client (`xcecli-presets`). The server only shares
admin-deployed presets read-only; presets never reach the controller,
WAL or scheduler and carry no privilege.
- **Rule of thumb for admins:** something every job of the application must
have (required host properties, licenses, launch type, mode,
pre/post-exec, limits) goes into the profile; an optional variant or
tuning shortcut goes into a site preset, typically one with the profile's
name.
- **Recommendations are advisory** (user decision): usage-based
suggestions for a profile's defaults (requested vs. used, OOM kills,
runtime by variant) are reported to the admin, who changes
`applications.yaml`; a profile never tunes itself. Backlog:
`profile-usage-insight`.
suggestions (requested vs. used, OOM kills, runtime by variant) are
reported to the admin, who changes site presets (or a profile, for an
essential); nothing tunes itself. Backlog: `profile-usage-insight`.
- Job details show the effective resreq with each term's origin (profile
or job), so users see what they are tuning.
or job).
- Deferred: a privileged `app:override` for one-off exceptions (an admin
can modify the pending job instead; recurring variants are presets), and
profile inheritance (`base:`), no longer needed for variants.
- **Later sections are added by their consumers**: `service:`
(`service-supervision`), I/O claims (resource-model PR-6), relationship
and compound templates (PR-14/15), `container:` (R6). This spec only makes
@ -82,7 +97,7 @@ scripts, vendor binaries, MPI solvers. Each needs a different way of running:
identity (and later in a container or vm);
- a particular launch type (serial, `openmpi`, `mpich`);
- particular environment and pre/post-exec steps;
- sensible resource defaults and limits.
- resource requirements it cannot run without, and limits.
Today every one of these must be set per job by hand, and several (execution
mode, sandbox options) cannot be set at all. Many users log in through the
@ -130,21 +145,24 @@ fits XCE's LSF-style job model.
first version contains the following (user decision; the format must be
extensible for "maybe others"):
1. **Execution mode and its options.** `direct` or `sandbox` now, with room for
`container`/`vm`. Sandbox options include allowed and default input/output
mounts and isolation extras.
`container`/`vm`. Sandbox options include the allowed input/output
prefixes and isolation extras.
2. **Launch type.** Serial, `openmpi` or `mpich`.
3. **Environment and pre/post-exec.** Default environment variables and
pre/post-exec commands.
4. **Resource requirement and limits.** The job's resource requirement
(select / rusage / `span[...]` / same / order), its task range (min /
default / max), and per-job execution limits (memory, runtime, CPU,
tasks), mapped onto the existing worker cgroup limits.
3. **Environment and pre/post-exec.** Environment variables the application
needs, and the outer pre/post-exec commands.
4. **Essential resource requirement and limits.** The resreq terms the
application cannot run without (select / rusage / `span[...]` / same /
order), its task range (min / max), and per-job execution limits as
maximums (memory, runtime, CPU, tasks), mapped onto the existing worker
cgroup limits.
All of these are essentials under the additive rule; none is a
convenience default.
- **Users pick a profile at submit** (REST, `xcecli jobs submit --app <name>`,
harness, libxce). A **cluster default profile** applies when none is given.
- **Limited overrides.** A job may override only the attributes its profile
marks as overridable (for example its own input/output directories within the
allowed prefixes, or env additions). Anything else is rejected with a clear
error.
- **Jobs add, never override.** A job may add to its profile's values (more
`select` terms, other resources, its own env variables, its own I/O
directories within the allowed prefixes, lower limits) but not change or
remove any. Anything else is rejected with a clear error.
- **Access by RBAC permission.** No new access mechanism; this follows the
existing named-instance pattern (user decision, 2026-09-29: fold profile RBAC
into this spec). Today, `queue:submit` scoped to `type: queue`,
@ -176,9 +194,9 @@ fits XCE's LSF-style job model.
fairshare or preemption).
- Any combination of an allowed queue and an allowed profile is valid. Each is
governed by its own access rules; for profiles, that is RBAC permission.
- Resource defaults in a profile describe what the application needs (its
default resource requirement and per-job execution limits). They are not
scheduling policy. Queue-level scheduling limits keep applying on top,
- Resource values in a profile describe what the application needs (its
essential resource requirement and per-job execution limits). They are
not scheduling policy. Queue-level scheduling limits keep applying on top,
unchanged.
- **Live merge** (`job-config-merge`). The job records its profile name and
its own values, not the effective values. The scheduler computes the
@ -186,8 +204,8 @@ fits XCE's LSF-style job model.
that no longer satisfies its profile pends with a reason, and running jobs
are unaffected. Job details show the profile name and the effective mode.
- **The apiserver never checks node accounts** (user decision, 2026-09-29).
- Submit-time validation covers profile existence, RBAC permission, overrides
and paths only.
- Submit-time validation covers profile existence, RBAC permission, the
additive rule and paths only.
- The execution account is the worker's concern. If a `direct` job's execution
user doesn't exist on the node, the worker fails the job at launch with a
clear, user-visible reason, instead of today's opaque systemd failure.
@ -203,7 +221,7 @@ fits XCE's LSF-style job model.
"Profile configuration" below), with xceadmin validation and live-upgrade
replication.
- **The controller validates the profile at submit**: the named profile
exists, and the job overrides only attributes the profile marks *default*.
exists, and the job only adds to the profile's values (additive rule).
This makes it authoritative for every submit path (REST, libxce, harness).
It stores the profile name and the job's own values; the effective values
come from the live merge (`job-config-merge`).
@ -220,8 +238,8 @@ fits XCE's LSF-style job model.
two checks. If the profile has gone by then, the job is rejected, never run
with a fallback profile.
- **The apiserver additionally enforces the RBAC permission** for the profile
(middleware chain unchanged; a `RequirePermission`-style check) and validates
overrides early (`preCheckJobSubmitRequest`).
(middleware chain unchanged; a `RequirePermission`-style check) and checks
the additive rule early (`preCheckJobSubmitRequest`).
- **The job's own values stay in its existing fields** (`launch_type`,
pre/post exec, exdata env and limits, resreq). New job fields are added only
for the profile name and the job's own I/O directories. All wire changes
@ -254,9 +272,9 @@ fits XCE's LSF-style job model.
at the rate of queues, as occasional admin edits (frequency rule).
- **The file is optional.** Without it there is one built-in profile
`default` (mode `direct`, no attributes), which is today's behaviour.
- **Every attribute carries its override marker** (`default` or `fixed`,
`job-config-layering.md`). Profile pre/post-exec is always fixed; whether
the job's own pre/post-exec is allowed is a profile setting.
- **No override markers.** Every value in a profile is an essential and
binds the job (additive rule). Whether the job's own pre/post-exec is
allowed is a profile setting.
- **Open to new sections.** Later specs add top-level sections to a profile
(`service:`, I/O claims, relationship templates, `container:`); the schema
must allow that without reshaping existing sections.
@ -268,14 +286,10 @@ fits XCE's LSF-style job model.
description: "OpenFOAM, MPI"
mode: direct
launch_type: openmpi
resreq: { value: "select[ib] span[ptile=32] rusage[mem=4000]", override: default }
tasks: { min: 32, default: 64, max: 512 }
limits:
runtime: { value: 24h, override: fixed }
memory: { value: 128G, override: fixed }
env:
vars: { FOAM_INST_DIR: /opt/openfoam }
job_env: allow
resreq: "select[ib] rusage[license_foam=1]" # essentials only
tasks: { min: 32, max: 512 }
limits: { runtime: 24h, memory: 128G } # maximums
env: { FOAM_INST_DIR: /opt/openfoam }
pre_exec: /opt/xce/app/openfoam/pre.sh
post_exec: /opt/xce/app/openfoam/post.sh
job_pre_post_exec: allow
@ -286,6 +300,60 @@ fits XCE's LSF-style job model.
job_pre_post_exec: forbid
```
Tuning such as `rusage[mem=4000] span[ptile=32]` and a task count of 64
is not in the profile; the admin publishes it as a site preset named
`openfoam`.
### Essentials and the additive rule
How each profile attribute combines with the job's own value (owned by
`job-config-merge`, which implements it):
| Profile attribute | Holds | The job may |
|---|---|---|
| resreq `select` | required terms (`ib`, GPU model, OS) | add terms (ANDed) |
| resreq `rusage` | required consumptions (`license=1`) | add other resources; not change these |
| resreq `span` / `same` / `order` | only if essential (e.g. a code that runs on one host only) | set them if the profile does not; otherwise rejected |
| task range | `min` / `max` | choose within it; no `-n` means `min` |
| env | variables the application needs | add others; not redefine these |
| launch type, mode, sandbox options | fixed values | nothing |
| limits | maximums | ask for less (checked like a ceiling) |
| pre/post-exec | outer layer, always runs | add its own inner layer if the profile allows |
- A job with no `-R` gets the profile's essentials only; the scheduler's
existing empty-resreq default (`type == any`) still applies to what
neither sets.
- **The `service:` section is configured in the profile** (user,
2026-10-12; defined with this spec, consumed by `service-supervision`,
`service-replica-set`, `service-endpoint`) and follows the same rule:
- restart policy (always / on-failure / never, backoff, give-up),
liveness and readiness probes, and named ports are the application's
definition: profile values, the service cannot change them;
- replicas work like the task range: the profile may set `min` / `max`,
and the service chooses its count within them (from its own spec or a
preset);
- spread rule and rollout settings (max unavailable / surge): if the
profile sets them they bind; otherwise the service sets them.
- Other later sections (I/O claims, relationship templates, `container:`)
state in their own specs how they follow the additive rule.
- Compound or alternative resreqs: a compound job resreq under a profile
whose resreq sets terms is rejected until PR-15 named parts define
per-part merging (leaning; requirements decide).
### Presets (client side, `xcecli-presets`)
Not part of this spec, recorded here because they replace profile defaults:
- A preset is a set of job options (`--app`, `--queue`, `-R`, `-n`, env,
limits). The client expands it; a command-line flag replaces the preset's
value for that option as a whole. The submit carries only the expanded
values.
- Personal presets live in `~/.config/xce/presets.yaml`.
- The apiserver **only shares**: admin-deployed preset files served
read-only (`GET /api/v1/presets`, `GET /api/v1/presets/{name}`). Pulling
copies a preset into the local file, so a server preset being removed
never affects users. `preset diff` / `pull --force` are user-initiated.
- User-to-user sharing by `preset export` / `import` (file, mail, git).
- Presets carry no privilege: `app:use`, `queue:submit`, the profile's
essentials, queue ceilings and project quotas still apply at submit.
### Default profile
- **Set by `default_application: <name>` in `xce.yaml`**, a cluster
parameter (as LSF keeps `DEFAULT_APPLICATION` in `lsb.params`), not a flag
@ -321,9 +389,9 @@ fits XCE's LSF-style job model.
## Scope
- **In**:
- The profile schema (attributes and override markers) and
`applications.yaml`, and the default profile (`default_application`).
- Submit-time validation of the profile and the job's overrides.
- The profile schema (essentials, additive rule) and `applications.yaml`,
and the default profile (`default_application`).
- Submit-time validation of the profile and the additive rule.
- RBAC permission for profile use.
- Submit surfaces: REST, `xcecli --app`, harness, libxce.
- The profile name and the job's own values persisted on the job.
@ -332,9 +400,10 @@ fits XCE's LSF-style job model.
- A worker launch error when a `direct` exec user is missing.
- Profile name and mode shown in job details.
- Listing available profiles (REST and xcecli).
- Profile `--dry-run` support: the effective values a job would get
(shared with `job-config-merge`).
- Tests.
- **Open for requirements**:
- The exact per-attribute override rules.
- Which extra attributes go into v1 beyond the four ("maybe others"). Examples:
requeue exit values, runtime estimate, job starter or wrapper, output path
template, checkpoint settings.
@ -350,35 +419,14 @@ fits XCE's LSF-style job model.
- Removing a non-default profile that pending jobs still name (leaning:
xceadmin warns, the jobs pend with "profile X not defined", running
jobs continue).
- Limits a job may lower but not raise: either a third "bounded" marker,
or the profile value is a fixed maximum and the job's own value a
request checked against it like a ceiling (keeps the two-interaction
rule of `job-config-layering.md`, which should then say so).
- Env merge: per-variable default/fixed, plus a denylist for sandbox
profiles (e.g. `LD_PRELOAD`)?
- Resreq override granularity (leaning, follows from the convenience
purpose): markers per term instead of per section. `select` has
*required* terms (always ANDed) and *default* terms (the job's select
replaces only these); `rusage` is per resource (fixed, or default with
optional min/max); `span`/`same`/`order` default unless marked. An
unmarked term is *default*. Amends `job-config-layering.md` once
decided. Also settles per-resource `rusage` merging and the "limits a
job may lower" question (default with a range is still only a check).
- Privileged override for one-off exceptions: an `app:override`
permission per profile (fixed terms treated as default for that job),
recorded on the job (WAL/snapshot) and shown in job details; queue
ceilings and project quotas still apply. v1 or later?
- Profile inheritance (`base: <profile>`) for recurring variants such as
"openfoam, large memory": v1 or later (leaning later).
- Personal presets for a user's tuned settings: xcecli only (leaning),
or server-side for the portal (a per-user layer, which conflicts with
one owner per attribute)?
- Job labels (`--label key=value`) and a summary grouped by label, to
compare tuning variants: here, `job-status-detail-display`, or its own
spec?
- Compound or alternative resreqs: reject a compound job resreq under a
profile with fixed resreq terms until PR-15 named parts define
per-part merging (leaning).
- A denylist of env variables a sandbox profile forbids jobs to add
(e.g. `LD_PRELOAD`)?
- Job labels (`--label key=value`, e.g. the preset name) and a summary
grouped by label, to compare tuning variants: here,
`job-status-detail-display`, or `xcecli-presets`?
- Settled 2026-10-12: override granularity (no markers; additive rule),
limits a job may lower (profile limits are maximums), personal presets
(client side), `app:override` and inheritance (deferred).
- Splitting the spec: execution mode, I/O directories, capability
advertisement and placement as a separate spec (or folded into
`job-sandbox-execution`), leaving this spec the profile core.
@ -390,7 +438,7 @@ fits XCE's LSF-style job model.
## Boundary Candidates
- The profile model and config (schema, validation, live upgrade).
- Submit-time validation of the profile and overrides (controller).
- Submit-time validation of the profile and the additive rule (controller).
- Access control (RBAC permission) and early validation (apiserver).
- Submit and listing surfaces (REST, xcecli, harness, libxce).
- Persisting the profile name and the job's own values (wire, WAL submit
@ -400,7 +448,10 @@ fits XCE's LSF-style job model.
## Out of Boundary
- Worker execution backends and sandbox mechanics.
- Output file location and retrieval inside the sandbox.
- Scheduler policy beyond capability filtering and resreq defaults.
- Scheduler policy beyond capability filtering and the profile's essential
resreq.
- Presets (`xcecli-presets`): client side; the read-only preset listing on
the apiserver belongs to that spec.
## Upstream / Downstream
- **Upstream**:
@ -424,7 +475,9 @@ fits XCE's LSF-style job model.
- **Adjacent**:
- `job-status-detail-display`
- `controller-job-cleanup`
- `resreq-maxtasks-wiring` (resreq defaults)
- `resreq-maxtasks-wiring` (task range)
- `xcecli-presets` (convenience defaults, client side)
- `profile-usage-insight` (advisory recommendations)
- `xce-node-manager`
## Constraints
@ -436,7 +489,7 @@ fits XCE's LSF-style job model.
the job's own values (including I/O directories) round trip through the
submit facts and snapshots. Run
`/xce-audit-invariants`.
- Input validation (`security.md`): overrides and paths are validated
- Input validation (`security.md`): the job's additions and paths are validated
server-side. No path traversal, and mount prefixes are restricted by the
profile.
- Size: this is likely 20 or more tasks. If requirements confirm that, split