grounding_unverified() now returns "ungrounded"; the bracketed token of
0.2.0 and earlier is still accepted by combine_grounding(), decision()
and valuation().A manifest whose outputs columns are named something other than the
candidate labels is now declined, classed outputs_not_action_indexed.
Positional correspondence between outputs columns and candidates was an
assumption the contract never stated. A gpfield spatial-prediction manifest
carries x, y, z, mean, sd and n_support; against six candidate
nitrogen rates the column count matched, and the tail returned a confident
action built from a spatial coordinate and a posterior standard deviation. It
now declines. Supply utility to say how a column is priced, or emit
action-indexed outputs.
A structure manifest is declined by target, classed
target_not_priceable, rather than waiting for a shape check to happen to
catch it. A recovered causal graph is not a predictive quantity, and pricing
one reads adjacency entries as action values.
The remaining two bare stop() calls in the tail -- a candidate/column shape
mismatch and a single posterior column with no utility -- are now typed
declines (candidate_shape_mismatch, utility_required), so every outcome
of the tail is either a decision or something is_orchestra_decline() can
read.
Found by a cross-member probe, not by this package's own suite: every manifest fixture here is shaped correctly by construction, so none of the three paths above could be reached from inside decideR. The workspace conformance suite now drives this tail with a real manifest from each of the eight fleet emitters.
A manifest this tail cannot price now raises a typed decline, classed
decideR_abstention / orchestra_refusal, instead of a bare stop(). The
fleet predicate is_orchestra_decline() reads the class, so an untyped error
here defeated the refusal contract every other seam honours: a caller could
not tell "the producer issued no number" from "decideR broke". A quorum
verdict that reached no quorum is exactly the first case.
A failure in the caller's arguments is still an error. The distinction is deliberate: what the manifest carries is the producer's business and declines typed; what the caller passed is a programming mistake and must not be dressed as an abstention.
Fixes from the 2026-08-25 ORCHESTRA fitness audit.
decide_evpi() prices the expected value of perfect information over the
same manifest, candidate set and utility the decision tail takes:
E[max_a U(a, theta)] - max_a E[U(a, theta)] over the feasible candidates.
It is the ceiling on what any study addressing the latent state could be
worth.decide_evsi() prices one named prospective sample -- this soil test, this
trial, at this site -- by the standard two-loop pre-posterior algorithm, with
the inner update obtained by importance re-weighting the manifest's own draws
rather than by a nested re-fit, so the manifest remains the single source of
the posterior and the package gains no sampler. The effective sample size of
the weights is reported and warned about when it degenerates.decide_bcr() discounts a benefit stream and a cost stream at an explicit
rate over an explicit horizon and reports the components an impact assessment
is written from: both streams, the present value of each, the net present
value and the ratio, plus a posterior ratio summary when the benefit stream
arrives as manifest draws.bcr_crrdc(): CRRDC-guideline benefit-cost with mandatory counterfactual,
attribution and adoption profile; closes the fleet-audit gap. It refuses --
with a message naming the unmet requirement -- to construct a ratio without
an explicit counterfactual (a benefits-under-counterfactual stream, or a
declared-already-net label), an explicit attribution share in (0, 1], or
an adoption profile with lags covering every benefit year (never an
implicit 100% uptake). The ratio is reported at the central discount rate
and at the CRRDC sensitivity band side by side in a decider_bcr object's
rates table, and an ungrounded input abstains -- with every rate's
bcr/npv/pv_benefits/pv_costs NA -- rather than pricing a ratio a
funding submission would quote.valuation, a new S7 result class for all three. It carries the value beside
its grounding token and its abstention record, so an ungrounded input
prices out as a typed abstention with value = NA_real_ -- never a number a
reader would spend money on. An abstained valuation is class-stamped
decideR_abstention, so the federation's is_orchestra_decline() predicate
recognises it without decideR depending on the contract layer.insufficient_evidence) does not block a value
of information: it is exactly the situation in which information is worth
buying, and the indecisive decision is returned in the valuation's
@baseline.safe_action (D-01). .match_candidate()
returning no numeric match now falls back to the per-draw argmax
probability, so the gate stays live for every candidate shape instead of
becoming inert -- previously decide()'s own safe_action = NULL default,
and every list/categorical candidate set, disabled the check with no
warning.decide_input_rate() and decide_position_size() no longer silently
discard constraint, safe_label, method, metadata, and inputs
passed through ... (D-02). Both now harvest the documented ... names and
stop loudly on an unrecognised one rather than accepting and dropping it. A
caller constraint to decide_position_size() ANDs onto the hard drawdown
guard rather than replacing it.print.grade_band_value() now dispatches on an installed package. The S3
method was correctly registered in the package's own method table but never
reached by print()'s ordinary S3 dispatch once S7::methods_register()
had run (D-03) -- the package's headline loss primitive printed as a raw
closure dump. .onLoad() now explicitly re-registers the method after
S7::methods_register().decide() (and every reference decision routed through the shared core)
now abstains with a new degenerate_utility reason instead of failing with
an opaque base-R error when every feasible candidate's expected utility is
NA/NaN (D-04).decide_from_manifest() now accepts a manifest whose draws are a single
posterior column (the shape a flexyBayes posterior arrives in), recycling
it across every candidate when utility is supplied, rather than refusing
with a column-count mismatch (D-06).@examples for decide_from_manifest() and
decide_rate_from_manifest() now build a readable S7 stand-in and actually
run the manifest-tail call, rather than wrapping it in \dontrun{} around
an undefined variable (D-07).low_ess abstention trigger is opt-in -- it never fires
unless the caller supplies min_ess -- in decide()'s roxygen and the
vignette's abstention table (D-05).decide_position_size()'s max_drawdown is now documented as a hard
one-period loss-quantile (value-at-risk) floor, not a multi-period
peak-to-trough drawdown statistic, which the previous wording could be read
to promise (D-09).is_grounded()'s roxygen and the vignette's abstention section now state
the correct downstream gate: is_grounded() alone is TRUE for a decision
that abstained for no_feasible_action, low_ess, or
insufficient_evidence, since none of those reasons downgrades the
grounding label; a consumer that must also refuse an abstained decision
gates on is_grounded(x) && !x@abstained (D-14).decide_position_size()'s expected
log-growth objective and fixed a grammatical ellipsis in
decide_from_manifest()'s utility documentation._pkgdown.yml now groups the reference index into four named sections
(Decisions, Manifest tail, Grounding, Loss) keyed to the existing
@family tags, replacing the single undifferentiated catch-all list
(D-17).README.Rmd now knits with md_extensions: -smart, so the generated
README.md uses plain ASCII -- throughout instead of pandoc's
smart-typography en dashes (D-20); README.md re-knitted, which also
fixes the stale example output that printed grade_band_value()'s return
as a raw closure dump instead of the band table (the D-03 print-dispatch
fix landed after the README was last knitted).Suggests-guarded test that drives decide_rate_from_manifest()
through a REAL orchestra_manifest built from the ORCHESTRA workspace's own
reference contract (hash-verified), rather than only ever consuming a
decideR-authored stand-in -- the Independent Oracle Principle gap the audit
named (D-08). Skips cleanly when the workspace is not present alongside the
package.decision now carries an additional "decideR_abstention"
class tag (recognised by the ORCHESTRA leader-node's cross-member
is_orchestra_decline() predicate) alongside its existing S7 class, so a
decideR abstention is identifiable at a cross-member seam without the
consumer depending on decideR's namespace.First formal release. decideR is the decision layer of the ORCHESTRA
analytics framework: the loss-optimal, grounding-aware closer of the
inference-to-decision loop. It maps a posterior -- or an upstream member's
orchestra_manifest inference result -- into an action under an explicit
utility and a hard feasibility constraint, with calibrated abstention and an
Independent Oracle Principle grounding firewall. This release adds the
manifest-native pipeline tail and the grade-band loss primitive, and formalises
the decision engine, grounding vocabulary, and reference decisions that the
development series exercised.
decide_from_manifest() turns an
upstream orchestra_manifest into a decision by reading the predictive
draws and the producer's grounding token straight off the manifest, then
routing them through the same expected-utility engine decide() uses. The
grounding rides from the producer through the decision, so an ungrounded
payload forces an abstention at the pipeline boundary. decideR does not
depend on the contract package: the manifest is read through its public S7
properties (outputs, metadata, summary), so the tail consumes any
conforming producer rather than special-casing each one.decide_rate_from_manifest(), the agronomic convenience that sources a
yield-per-rate posterior and its grounding from a manifest and emits a
profit-optimal nitrogen-rate decision -- the formalised crop-pipeline tail.grade_band_value()
builds a step value schedule whose payoff jumps at quality breakpoints (a
grain price that steps up as protein clears a milling and a premium
threshold, say), and grade_band_utility() turns the schedule into a
decide()-ready utility. Under a step payoff the optimal decision is governed
by the posterior probability of clearing each band, not by the posterior mean.
This is a building block for the future grainPlan orchestrator.decide() chooses the feasible action of greatest expected utility over
posterior draws, abstaining to a safe action on any of four triggers --
un-grounded input, no feasible action, low effective sample size, or a move
that is not clearly better than the status quo.decide_input_rate() and decide_position_size() are two reference
decisions -- a crop nitrogen rate chosen by expected profit, and a trading
position size chosen by drawdown-capped expected log-growth -- that route
through the same engine, demonstrating one decision layer across two domains.decision is the S7 result class, carrying the chosen action, the candidate
ledger, the grounding label, and the abstention record, with print() and
is_grounded() methods.grounding_grounded(), grounding_unverified(), and combine_grounding()
are the canonical provenance vocabulary, hardcoded to match the ORCHESTRA
federation's ungrounded / grounded tokens (worst-case combination: one
un-grounded input taints the decision).