Signed scenario allocation for CI resources¶
Finite scenario allocation chooses among explicitly declared CI resource plans.
It is separate from finite coverage selection and from PortfolioUCB, which
selects learning policies. Signed modeled returns remain signed; neither a ranking,
a bounded reward nor a scenario weight is interpreted as calibrated evidence.
The API evaluates complete alternatives over shared joint scenarios, checks resources/risk separately, and returns exact conditional forecasts and an auditable choice. It executes no allocation and mutates no holdings. Native CI scheduling, NAPFD/APFDc and RNFail remain unchanged.
Complete synthetic CI fixture¶
from decimal import Decimal
from coleman.allocation import (
AllocationLimits, AllocationProblem, CurrentAllocation, DiscreteAllocation,
JointScenario, NamedAmount, ProbabilityEvidence, ResourceCapacity,
RiskConstraints, ScenarioPayoff, SignedPayoff, select_allocation,
)
from coleman.results.domain import fingerprint
from coleman.selection import Quantity, UnitSemantics
credit = UnitSemantics(unit="credit", meaning="synthetic-ci-credit-accounting-v1")
seconds = UnitSemantics(unit="s", meaning="modeled-serial-ci-resource-time-v1")
def amount(value, semantics=credit):
return Quantity(value=Decimal(value), semantics=semantics)
def signed(value):
return SignedPayoff(value=Decimal(value), semantics=credit)
states = ("idle", "busy")
gross = {"no_action": ("0", "0"), "stable": ("2", "2"), "variable": ("10", "-8")}
durations = {"no_action": "0", "stable": "3", "variable": "4"}
def action(name):
return DiscreteAllocation(
action_id=name, holdings=(),
resource_use=(NamedAmount(name="runner_time", amount=amount(durations[name], seconds)),),
capital_required=amount("0"), transaction_cost=amount("0"),
gross_payoffs=tuple(
ScenarioPayoff(scenario_id=state, gross=signed(value))
for state, value in zip(states, gross[name], strict=True)
),
)
problem = AllocationProblem(
schema_version=1,
data_fingerprint=fingerprint({
"gross": {name: list(values) for name, values in gross.items()},
"durations": durations, "probabilities": ["0.5", "0.5"],
}),
value_semantics=credit, initial_balance=amount("10"),
current=CurrentAllocation(
holdings=(), reserved_balance=amount("0"),
resource_use=(NamedAmount(name="runner_time", amount=amount("0", seconds)),),
),
holding_definitions=(),
resources=(ResourceCapacity(name="runner_time", capacity=amount("5", seconds)),),
scenarios=tuple(JointScenario(scenario_id=state, probability=Decimal("0.5")) for state in states),
probability_evidence=ProbabilityEvidence(kind="assumed"),
actions=tuple(action(name) for name in gross), no_action_id="no_action",
risk=RiskConstraints(downside_target=signed("0")),
)
result = select_allocation(problem, limits=AllocationLimits(deadline_seconds=None))
assert result.choice.selected_action_id == "stable"
assert result.choice.status == "optimal"
forecasts = {row.forecast.action_id: row.forecast for row in result.completed}
assert forecasts["variable"].expected_net.value == Decimal("1")
assert forecasts["variable"].variance.value == Decimal("81")
Credits are synthetic modeled units, not currency or measured CI savings. All fees are zero in this fixture, so its gross increments equal the issue's net payoffs:
| Plan | Joint net increments | Expected net | Variance | Expected shortfall below 0 |
|---|---|---|---|---|
| no_action | 0, 0 | 0 | 0 | 0 |
| stable | 2, 2 | 2 | 0 | 0 |
| variable | 10, -8 | 1 | 81 | 4 |
The negative scenario remains in the result. If all changed plans have negative
expected net and the unchanged plan returns zero, no_action is optimal. If every
feasible plan loses, the least-bad modeled optimum can still be negative.
Accounting roles and complete input¶
Each modeled accounting amount carries explicit units and versioned meaning; the example uses a generic CI credit accounting context. The roles are distinct:
initial_balance: initial modeled stock, not an expected payoff;current: current complete holdings/resource vectors and reserved liquidity;capital_required: liquidity reserved for an alternative, including fee funding;transaction_cost: one deterministic expense per action, charged once;gross_payoffs: the entire target allocation's joint-state increment before that fee;net = gross - transaction_costandterminal_balance = initial_balance + net.
Reserved capital is not another expense and is not subtracted from terminal balance. Holdings are explicit target quantities, not an automatic valuation or additional return transformation. A producer must define whole-plan gross increments consistently with its accounting context. Scenario-varying fees, automatic holding valuation and implicit financing are outside this v1 contract.
Every action must include every declared resource/holding component, even if its amount is zero. Omitted/extra components and unit/meaning mismatches fail rather than becoming free or unavailable quantities. Resources are total chosen-plan use, including current commitments; their ceilings are inclusive. The fee must be funded by reserved liquidity, and a plan's reservation must fit initial balance to be feasible. A structurally valid plan exceeding a resource/capital ceiling is a rejected alternative, not a malformed forecast.
no_action_id identifies a required explicit action preserving current holdings,
resource use and reservation with zero new transaction cost. Its gross increments
are declared; existing commitments can have nonzero/negative outcomes. The unchanged
choice is not assumed feasible if its actual modeled constraints fail.
Joint weights, units and exact definitions¶
Each action declares exactly one gross payoff for every joint scenario ID. Joining is by ID, so changing row order cannot scramble correlated outcomes. A bundled plan's joint gross increment already represents the complete plan; the API does not add independent marginal variances or manufacture scenarios from seeds.
Scenario probabilities carry dimensionless unit 1 and explicit joint-probability
meaning. They are finite nonnegative decimals with at most twelve fractional
places and must sum exactly to one (tolerance zero). Zero-probability states
retain their raw outcomes. Malformed weights are rejected and never silently
renormalized; producers own any explicitly versioned estimation/rounding procedure.
For net payoff X, target T, and weights p, the exact summaries are:
- expected net:
sum(p * X); - population scenario variance:
sum(p * X^2) - sum(p * X)^2, in squared payoff units; - expected target shortfall:
sum(p * max(T - X, 0)), in payoff units.
Target shortfall is an unconditional positive-part expectation, not CVaR or a tail-conditioned confidence measure. Risk ceilings optionally constrain variance, expected target shortfall and minimum terminal balance in every positive-point-weight scenario. A null ceiling means that constraint was not requested. Raw negative outcomes remain visible when the alternative is infeasible.
UtilitySpec(kind="expected_net") maximizes expected signed net. For nonlinear
utility use quadratic_target and a nonnegative coefficient c with the inverse
payoff semantics returned by penalty_semantics(value_semantics):
from coleman.allocation import UtilitySpec, penalty_semantics
utility = UtilitySpec(
kind="quadratic_target",
coefficient=amount("0.1", penalty_semantics(credit)),
)
This evaluates sum(p * (X - c * max(T-X,0)^2)), in payoff units. It is not utility
of the mean. For [12,-6], equal weights and T=0,c=0.1, expected net is 3 but
expected utility is 1.2; a stable return 2 is preferred. Missing/unused coefficients
and incompatible inverse/squared units fail validation, including for zero values.
Input amounts/holdings/resources and signed gross increments are bounded by
10^12 units with twelve decimal places. Integer arithmetic retains products at
24/48 fractional places; exact outputs allow 48 fractional and 110 total digits,
bounded by 10^48. Decisions have zero arithmetic rounding tolerance and do
not depend on process Decimal precision. Equivalent decimal spellings/signed zero
serialize canonically. Continuous optimization, log utility, CVaR and unspecified
nonconvex objectives are explicitly unsupported; unknown objective kinds fail.
Assumptions, estimated weights and conservative choices¶
ProbabilityEvidence(kind="assumed") declares a conditional model assumption,
not verified real-world calibration. optimal means the exact best feasible
alternative in this complete supplied finite model. It does not certify external
universe completeness, forecast accuracy, independent observations or production CI
value. Exact ties favor no_action, then ascending action ID.
Estimated weights require evidence fingerprint/method ID and lower/upper bounds for every joint scenario. Bounds must contain the point weights; no statistical confidence/coverage is assigned automatically. Independent-unit/count metadata may be explicitly unknown; a supplied count requires a named observation unit. Zero is not used for an unknown count, and repeated seeds never become independent observations.
The selector retains estimated weights, bounds and conditional forecasts but
returns insufficient_evidence. It can select only the unchanged action when its
capital/resources and risk can be conservatively certified over declared support.
For this fallback, variance is bounded by squared payoff range, target shortfall
by the largest supported shortfall, and terminal floors are checked in every
state with positive probability upper bound. These loose support bounds apply to
every normalized distribution there; failure to certify is not proof of
infeasibility. If no fallback is certified, selection is null. Nothing activates a
new plan merely because its point estimate is favorable.
External evidence or undisclosed scenarios cannot be authenticated by a hash. Use protected evaluation to justify empirical assumptions; declaring a weight source never substitutes for a scientific evaluation protocol.
Execution limits, checkpoints and result evidence¶
AllocationLimits bounds new action examinations, overall cooperative seconds and
estimated additional working bytes. Input caps are 64 discrete actions, 256 joint
scenarios and 64 resource/holding components. No-action is evaluated first; remaining
IDs are canonical. One work unit is one attempted whole-action evaluation. Deadline
polling also occurs between scenario operations. An interrupted action contributes
no partial forecast, while completed evaluations and the best incumbent survive.
Zero work can produce no incumbent; this is limited, not fabricated infeasibility.
The timer starts at API entry and never resets per phase. Validation/checkpoint replay/output/serialization have bounded overhead. The deadline is cooperative, not a hard process kill; the memory preflight is an estimate, not measured RSS, and excludes already supplied input, interpreter and artifact payload. Malformed inputs and unexpected callback errors propagate. Keyboard interruption during search returns complete progress with explicit termination status.
AllocationResult embeds the complete source, limits/preflight, checkpoint input,
completed evaluations, exact forecasts/risk rejections and a separate choice.
Reading/serialization recomputes every reported forecast/check from joint evidence
and verifies choice, scope completion and work accounting. A forged utility,
feasibility, selected ID or falsely complete enumeration is rejected.
| Choice status | Meaning |
|---|---|
optimal |
Every finite action checked, best feasible under assumed point weights |
feasible |
Best complete incumbent during interrupted/limited enumeration |
infeasible |
Full declared model checked; no feasible alternative |
limited |
Preflight or execution left no complete feasible incumbent |
insufficient_evidence |
Estimated weights; only a certified no-action fallback is allowed |
termination_reason separately records enumeration_complete, work/deadline,
cancellation/interruption or memory preflight. Null selection is not zero payoff.
Negative/inconclusive results are valid artifacts. No bounded-reward normalization
or learning reward is produced.
result.checkpoint() exports versioned complete evaluations, including rejected
alternatives. Store the JSON with existing CheckpointPayload.extra and
LocalCheckpointStore (trusted local pickle state). Resume with
select_allocation(problem, checkpoint=...); source and each cached row are checked
before early preflight returns. Verified rows do not consume new search units;
verification overhead can repeat computation and is not a performance claim.
Cached rows still poll deadline/cancellation, including fully completed checkpoints.
Stopping that invocation preserves its explicit termination reason and verified
cached evidence: a previously complete optimum remains mathematically optimal,
without falsely reporting that this invocation completed enumeration.
Changed/future/corrupt checkpoints fail rather than inventing progress.
publish_allocation_result(result, ArtifactWriter(root)) immutably publishes exact
JSON under allocation-results/<content-digest>.json; existing manifests inventory
it. Identical concurrent publication is idempotent. Existing local hard-link/fsync
and power-loss limits apply; incomplete writes expose no completed JSON. The core
does not write files unless this adapter is explicitly called.
allocation_record(result, run_id=..., available_at=...) projects selected modeled
summaries to existing #251 sinks. Exact JSON is authoritative; each projected
meaning ends in binary64-projection-v1 and identifies a modeled quantity. Signed
losses remain negative, variance has squared units, and no selection yields
unavailable measurements. Supply actual zoned availability after calculation and
retain it on retries. Native cost/APFDc and rewards are not reinterpreted.
Installed native CI examples¶
Copy ci.py
or resources.py
outside the repository before running; outputs remain within the invocation
directory. The CI example freezes the synthetic model, selects stable, maps its
declared three-second resource plan into the actual native fixed-time runner, and
verifies native scheduling before publishing the separate plan record. Native
Greedy/RNFail/NAPFD/Parquet components are real and unchanged. The resolved RunSpec
retains source, limits, result identity and adapter version. Repeated publication
uses a committed domain record's availability timestamp and checks identical content.
Legacy native-row retry semantics remain unchanged. The resource example evaluates
synthetic runner-slot alternatives; neither example claims measured savings or
policy superiority.
flowchart TD
State[Explicit current holdings, resources and initial balance] --> Problem[Versioned finite joint-scenario problem]
Payoffs[Signed whole-plan gross increments and one fee] --> Problem
Weights[Assumed weights or estimated weights with bounds] --> Problem
Problem --> Guard[Shared work timer and memory preflight]
Guard --> Forecast[Exact scenario moments and pointwise utility]
Forecast --> Check[Separate capital, resource and risk checks]
Check --> Choice[Conditional best complete action]
Weights --> Evidence[Insufficient evidence for estimated weights]
Evidence --> Fallback[Certified unchanged fallback or null]
Choice --> Result[Self-contained exact result and completed evidence]
Fallback --> Result
Result --> Artifacts[Existing ArtifactWriter, manifests and local sinks]
Result --> Checkpoint[Verified progress in existing checkpoint store]
Checkpoint --> Guard
Choice --> Native[Existing native CI runner example]
Compatibility and limits¶
Problem/result/checkpoint artifacts require integer schema_version=1 and supported
allocation-v1 semantics. Missing/old/future versions, duplicate JSON keys, unknown
fields, mismatched units and forged evidence fail closed. No migration invents
weights, fees, holdings, uncertainty or execution history. Existing native,
coverage and protected-evaluation artifact bytes retain their contracts; shared
decimal conversion keeps its twelve-place default and adds exact product scales.
This finite offline model provides mathematical decisions, not a market connector, live execution, learned probability calibration or continuous allocation engine. Independent mathematical/performance benchmarking remains #255; broader CI generalization needs protected evaluation and diversified-corpus evidence.
coleman.allocation ¶
Finite joint-scenario resource allocation with signed payoffs and conservative evidence handling.
ActionEvaluation ¶
Bases: Immutable
A complete forecast plus explicit conditional feasibility reasons; no selection yet.
ActionForecast ¶
Bases: Immutable
Conditional distribution summaries in explicit payoff/squared units, without clipping.
Gross is the entire allocation's increment before one deterministic fee. Net deducts that fee once. Variance is E[net^2]-E[net]^2. Target shortfall is the unconditional E[max(target-net,0)], distinct from CVaR. Utility is evaluated pointwise before expectation. These are modeled forecasts, not CI rewards.
AllocationCheckpoint ¶
Bases: VersionedContract
Complete forecast rows tied to a frozen source; integrity is checked on binding/resume.
Store JSON in existing CheckpointPayload.extra. Cached forecasts (including rejected actions) are recomputed against source before use, so no invented utility, risk or completion flag can bypass a fresh budget. Validation has bounded overhead; cached rows are not new search work or independent evidence.
AllocationLimits ¶
Bases: Immutable
Limit new action examinations, cooperative overall seconds and estimated working bytes.
A unit is one attempted action evaluation, with polling within joint scenarios. Validation, checkpoint verification, bounded output and serialization add overhead; this is neither a hard real-time kill nor a measured RSS promise. Already verified checkpoint rows do not consume new search units. No phase resets the timer. Input action/scenario/component caps remain non-overridable.
AllocationProblem ¶
Bases: VersionedContract
Complete finite action universe over shared joint scenarios and explicit current state.
Offline modeled decisions only; no holdings are mutated and no live action is executed. Optimality is conditional on this finite declared universe and its assumed weights, never a continuous/global or calibrated forecasting claim.
action ¶
Find a declared action; unknown identity raises ValueError without creating a fallback.
AllocationResult ¶
Bases: VersionedContract
Self-contained exact finite-model result, preserving negative and inconclusive outcomes.
Full declared actions/scenarios and completed forecasts permit arithmetic/risk replay without running a selector. Optimal means every finite action was checked under supplied assumed weights, not empirical efficacy or continuous optimality. Estimated weights remain insufficient evidence with at most a certified no-action fallback. Null selection means no certified incumbent, never an invented zero payoff. No external action or policy activation occurs.
checkpoint ¶
Export complete verified progress to existing checkpoint infrastructure, without I/O.
CurrentAllocation ¶
Bases: Immutable
Current holdings, total resource use and liquidity reserved, separate from expenses.
DiscreteAllocation ¶
Bases: Immutable
One complete finite target, with signed gross increments and one deterministic fee.
Capital_required is liquidity reserved (including fee funding), not another expense. Net payoff is gross minus transaction_cost exactly once. Terminal balance is initial_balance plus net; reserved capital is not subtracted again. Holdings describe the target, not an extra payoff transformation. Joint gross increments already describe the entire target including correlated outcomes.
ExactPayoff ¶
HoldingDefinition ¶
Bases: Immutable
Unit/meaning of a holding component; finite alternatives declare every component.
JointScenario ¶
Bases: Immutable
One joint state shared by all actions; probabilities are dimensionless, not rewards.
Point weights are nonnegative decimals summing exactly to one across states (zero tolerance; never silently renormalized). Estimated lower/upper bounds retain supplied uncertainty and are not assigned a confidence/coverage claim.
NamedAmount ¶
Bases: Immutable
One complete holding/resource component; explicit zero is different from missing data.
NonnegativeMoment ¶
ProbabilityEvidence ¶
Bases: Immutable
Weight provenance, not certification that learned probabilities are calibrated.
Estimated weights require producer evidence/method and per-scenario bounds. Independent-unit/count metadata may be explicitly unknown; seeds are never inferred as observations. This v1 selector conservatively abstains from new allocations under estimated weights, retaining conditional forecasts/bounds.
ResourceCapacity ¶
Bases: Immutable
Inclusive total resource ceiling for a chosen allocation, including current commitments.
RiskConstraints ¶
Bases: Immutable
Precisely defined conditional risk ceilings; null means the constraint is not requested.
Shortfall is E[max(target-net,0)], not CVaR/tail-conditioned expected loss. Variance is the population scenario variance of net payoff, in squared units. A terminal floor applies in every positive-probability scenario. Raw negative outcomes remain visible even when these constraints reject an allocation.
ScenarioPayoff ¶
Bases: Immutable
Total gross increment of one whole allocation in a joint state, before its one fee.
SignedPayoff ¶
Bases: Quantity
Finite signed modeled payoff in declared units, with twelve decimal places.
Values lie in [-10^12,10^12]. Losses stay negative; no probability/reward normalization or implicit transformation is applied. Signed zero uses the shared canonical zero before hashing/projection.
UtilitySpec ¶
Bases: Immutable
Expected net or E[net - coefficient*max(target-net,0)^2], in payoff units.
The quadratic coefficient has inverse payoff units and is nonnegative. Utility is evaluated on joint scenarios before expectation; losses are not clipped or normalized into rewards. Log/CVaR/continuous objectives are unsupported in v1.
allocation_record ¶
Project selected conditional forecasts into #251 records, preserving signed losses.
Exact JSON is authoritative; binary64 projection is explicit in each meaning and is never used by selection or evidence validation. No incumbent yields unavailable measurements, not zeros. Supply actual zoned result availability after calculation and retain it on retry. No learning reward or policy activation is fabricated, including for estimated-weight fallback decisions.
evaluate_allocation_action ¶
Validate a frozen problem and forecast/check one declared action without selecting or I/O.
Unknown action or malformed/version-incompatible input raises ValueError or Pydantic ValidationError. No external data, inference or probability calibration is invented. Returned feasibility is conditional on declared point weights.
penalty_semantics ¶
Declare the inverse-unit coefficient keeping quadratic downside utility in payoff units.
publish_allocation_result ¶
Publish revalidated exact evidence atomically and idempotently through ArtifactWriter.
Limited/negative/inconclusive results retain their status. Conflicting replay and I/O errors propagate; incomplete writes never expose completed artifacts. Existing local hard-link/fsync and power-loss limitations apply.
select_allocation ¶
Evaluate finite actions under one deadline/work budget; never execute an allocation.
No-action is examined first, then canonical action IDs. Interrupted attempts publish no partial forecast; all completed evidence and the best certified incumbent survive. Zero work can yield no incumbent, not fake infeasibility. Checkpoint integrity is validated before preflight returns. Estimated weights preserve uncertainty and allow at most a certified unchanged fallback. No RNG, reward normalization, continuous optimization, external data or I/O is used.
variance_semantics ¶
Declare variance in squared payoff units, separate from payoff/credit magnitudes.