Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/config-snapshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -9699,6 +9699,7 @@ export default nextConfig;
"check:engine-date": "npm run ts:esm -- scripts/guardrails/run.mts check:engine-date",
"check:engine-optimality": "npm run ts:esm -- scripts/guardrails/run.mts check:engine-optimality",
"check:engine-optimality-version": "npm run ts:esm -- scripts/guardrails/run.mts check:engine-optimality-version",
"check:objective-semantics": "npm run ts:esm -- scripts/guardrails/run.mts check:objective-semantics",
"check:catch-unknown": "npm run ts:esm -- scripts/guardrails/run.mts check:catch-unknown",
"check:guardrails-core": "npm run ts:esm -- scripts/guardrails/run.mts check:guardrails-core",
"check:repo-guardrails": "npm run ts:esm -- scripts/guardrails/run.mts check:repo-guardrails",
Expand Down Expand Up @@ -10774,6 +10775,7 @@ const CONFIG_SNAPSHOT_PATH = `${CHECK_PATH_BASE}config-snapshot.mts` as const;
const ENGINE_OPTIMALITY_PATH = `${CHECK_PATH_BASE}engine-optimality.mts` as const;
const ENGINE_OPTIMALITY_VERSION_PATH = `${CHECK_PATH_BASE}engine-optimality-version.mts` as const;
const ENGINE_INPUT_BOUNDARY_PATH = `${CHECK_PATH_BASE}engine-input-boundary.mts` as const;
const OBJECTIVE_SEMANTICS_PATH = `${CHECK_PATH_BASE}objective-semantics.mts` as const;
const REPLAY_STAGING_EMPTY_PATH = `${CHECK_PATH_BASE}replay-staging-empty.mts` as const;
const REPLAY_OBJECT_STORE_PATH = `${CHECK_PATH_BASE}replay-object-store.mts` as const;
const ENV_CONTRACT_PATH = `${CHECK_PATH_BASE}env-contract.mts` as const;
Expand Down Expand Up @@ -10882,6 +10884,7 @@ export const GUARDRAILS = Object.freeze({
'check:engine-optimality': ENGINE_OPTIMALITY_PATH,
'check:engine-optimality-version': ENGINE_OPTIMALITY_VERSION_PATH,
'check:engine-input-boundary': ENGINE_INPUT_BOUNDARY_PATH,
'check:objective-semantics': OBJECTIVE_SEMANTICS_PATH,
'check:replay-staging-empty': REPLAY_STAGING_EMPTY_PATH,
'check:replay-object-store': REPLAY_OBJECT_STORE_PATH,
'check:env-contract': ENV_CONTRACT_PATH,
Expand Down
11 changes: 10 additions & 1 deletion docs/engine-optimality/objective.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ Last updated: 2026-01-18

The vector is total for all finite scores and uses only stable strings.

The underlying scalar score that feeds this vector is bounded heuristic scoring, not a claim of economic optimality. Live dimensions are limited to `rewards`, `runway`, and `debtRelief`, and raw issuer points are not treated as monetary value unless runtime truth provides an explicit valuation.
The underlying scalar score that feeds this vector is `objectiveUtilityCents`
with serialized unit label `utility_usd_cents`. It is bounded heuristic scoring,
not a claim of economic optimality. Live dimensions are converted into
documented utility-adjusted USD cents before ranking. Component `utilityCents`
values are final objective contributions after configured preference weights and
should not be interpreted as literal market cash value.

Raw issuer points do not enter objective math directly. They are converted
through `REWARD_POINT_VALUE_CENTS`.

### Ordering and tie-break

Expand Down Expand Up @@ -58,3 +66,4 @@ and injective.
- `docs/engine-optimality/candidate-space.md`
- `docs/engine-optimality/status.md`
- `docs/engine-optimality/trace.md`
- `docs/simulation/objective-semantics.md`
5 changes: 5 additions & 0 deletions docs/engine-optimality/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Last updated: 2026-04-28

Cherry evaluates a bounded generated candidate set with deterministic heuristic ranking. It does not prove global optimality over all possible financial actions.

Live candidate ranking uses `objectiveUtilityCents` with serialized unit label
`utility_usd_cents`. This is a bounded heuristic objective expressed in one
canonical unit, not a true global utility function.

### Proven (bounded)

- Bounded exact optimality is proven for `(objective_v1, candidates_v1)` under
Expand Down Expand Up @@ -38,3 +42,4 @@ Cherry evaluates a bounded generated candidate set with deterministic heuristic
- `docs/engine-optimality/objective.md`
- `docs/engine-optimality/candidate-space.md`
- `docs/engine-optimality/trace.md`
- `docs/simulation/objective-semantics.md`
7 changes: 7 additions & 0 deletions docs/guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Last updated: 2026-01-31
- Accounting invariants run as deterministic guardrails over `lib/accounting` and its property tests.
- Engine optimality guardrail runs bounded oracle tests via `check:engine-optimality`.
- Engine optimality versions are frozen by `check:engine-optimality-version`.
- Objective semantics are enforced for live objective paths via `check:objective-semantics`.
- Guardrail runner supports `--aggregate` shadow execution; it accepts guardrail names only (no per-guardrail args) and reports in registry order by default (`--sort=name` for alphabetical).
- Workflow presence, quoted expressions, runner-context, and delete-safety are enforced (`check:workflow-files-present`, `check:workflow-expressions-quoted`, `check:workflow-runner-context`, `check:no-workflow-force-delete`).

Expand Down Expand Up @@ -351,6 +352,12 @@ Guardrail checks: `check:branded-literal` and `tests/node/guardrails/branded-typ
- Boundary files (`lib/engine/input/**`, `check:engine-freeze`) may not use array element access (`arr[i]`).
- Enforcement: `check:engine-input-boundary`.

### Guardrail 57 — Objective Semantics

- Live objective math under `lib/engine/objective.ts`, `lib/engine/objective/**`, and `lib/simulation/**` must not use raw issuer points or legacy `POINTS_PER_DOLLAR` values as objective value.
- Reward points must convert through `rewardPointsToUtilityCents`.
- Enforcement: `check:objective-semantics`.

### Guardrail 58 — Replay Staging Hygiene

- Replay staging artifacts must never be committed under `tests/replay/_staging/**`.
Expand Down
74 changes: 74 additions & 0 deletions docs/simulation/objective-semantics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Status: Active
Last updated: 2026-04-28

# Objective Semantics

## Current behavior

### Canonical unit

Cherry scores live candidates as `objectiveUtilityCents`.

Canonical unit: utility-adjusted USD cents.
Serialized unit label: `utility_usd_cents`.

Legacy `score` is a compatibility alias for `objectiveUtilityCents`; both values
must come from the same computation.

### Reward value

Cashback reward value enters the objective at face value in cents.

Issuer reward points are converted through `REWARD_POINT_VALUE_CENTS`. The
current live mapping is 1 point = 1 utility-adjusted cent. Raw points do not
enter objective math directly.

### Weighted component semantics

Component `utilityCents` values are final objective contributions after
configured preference weights. They should not be interpreted as literal market
cash value.

### Cash benefit

Cash-denominated benefits enter the objective through cent-denominated
conversion before profile weighting.

### Debt relief

Debt relief enters as a bounded utility-adjusted contribution. Utilization
relief is converted with
`UTILIZATION_RELIEF_UTILITY_CENTS_PER_BASIS_POINT`; balance relief is converted
from debt cents with an explicit utility mapping. These constants make the
heuristic objective interpretable without claiming that the result is literal
market cash value.

The current debt-relief constants are intentionally conservative. Debt relief is
allowed to influence ranking, especially under debt-focused profile weights, but
it is not treated as face-value cash benefit.

### Liquidity pressure

Liquidity and affordability pressure are bounded non-utility heuristic
contributions. They discourage fragile near-term liquidity outcomes and are
reported as bounded heuristic components in `scoreComponents`.

### Final interpretation

Cherry uses a bounded heuristic objective expressed in one canonical unit. It
does not define a true global utility function.

Cherry does not claim long-horizon global optimality. It ranks the currently generated candidate set under a documented, unit-consistent objective.

## Future/Target behavior

- Any new score dimension must either convert into `objectiveUtilityCents` or be
explicitly documented as a bounded non-utility heuristic contribution.
- Any change to live objective semantics must update this document, tests, and
engine behavior versioning.

## Related docs

- `docs/engine-optimality/objective.md`
- `docs/engine-optimality/status.md`
- `docs/engine-optimality/candidate-space.md`
Loading
Loading