Skip to content

Utility-aware policy

The host-issued memory decision: gap planning, gap-driven retrieval, draft-relative admission, and the control plane around them. The specification is utility-aware-memory-architecture.md.

retold.policy.utility_aware

Utility-aware host path: gap planning, draft-relative admission, and fail-closed orchestration.

The host decides whether stored information will improve an answer, not whether it concerns the query. On each user turn the orchestrator generates a baseline draft from public context plus the ambient profile while a gap policy names the user-specific facts the draft may be missing. Only when there are gaps does it retrieve, and only when an admission policy says a candidate would change the draft does it regenerate. Every other path returns the draft unchanged, and every path writes one turn-decision row.

Policies are protocols. Hosted adapters live outside the core package. The orchestrator takes callbacks for baseline and final generation so this module never depends on a model vendor.

UtilityAwareOrchestrator

Deterministic orchestration of one turn. Fails closed to the draft on every error and budget path.

Serving, meaning shadow is off and the path is enabled, requires a bundle registry that holds a passing fitness result for this configuration's bundle. Without one the constructor refuses, so a host cannot serve an unapproved bundle by accident. Shadow mode needs no approval.

retrieval_config is the RetoldConfig the retrieve callable searches with. Given it, the bundle's retrieval hash is derived from that configuration and a manifest that disagrees is refused.

bundle_components

bundle_components(
    config: UtilityAwareConfig, retrieval_config: Any = None
) -> dict[str, object]

Everything that changes what the path does. Hashing this identifies a bundle.

Pass the RetoldConfig the host retrieves with and the retrieval half of the hash is derived from it rather than taken on trust. A manifest that declares a different retrieval_config_sha256 is refused: a bundle's fitness result was earned under one retrieval configuration, and a hash copied from that run into a host that retrieves differently would claim an approval nothing measured.

render_decision

render_decision(decision: TurnMemoryDecision) -> str

Compact one-line rendering for logs and tests.

retold.policy.activation

Ambient activation: which records sit in the always-present profile, decided by rule and audited.

A record is conditional by default and must pass retrieval and admission on each turn. A small class of broadly applicable preferences about the principal, such as answer style or the language of code examples, is promoted to ambient and rendered into a bounded profile at session start. Promotion is never a model's decision alone: a category policy proposes a classification, the host verifies the supporting claim in the principal's own transcript turns, and deterministic rules decide. Anything ambiguous, low-confidence, or flagged unsafe goes to a durable review queue and stays conditional until a trusted reviewer resolves it.

Every record also receives a content-free retrieval category from a fixed taxonomy. The distinct categories present in a principal's conditional store form the inventory a gap planner may see; record text never does.

ActivationService

Run the activation policy for one committed record and persist every step of the decision.

ProfileAssembler

Render the principal's ambient records into one bounded block, built once per session.

The profile is what the model is told applies to every reply, so it has to be the same text for the whole session: a promotion, a review resolution, or an expiry landing mid-session would otherwise change the standing instructions between one turn and the next, and the turn decisions of one session would no longer be comparable. The block is therefore assembled on the session's first turn and held until the session ends, which is also what stops every turn from paying for the query.

build

build(principal: Principal) -> ProfileBlock

Return this session's profile, assembling it on the first call and reusing it afterwards.

forget

forget(session_id: str) -> None

Drop a finished session's profile. The next session assembles a fresh one.

ProfileBlock dataclass

ActivationDecision dataclass

CategoryPolicy

Bases: Protocol

CategoryDecision dataclass

What a category policy proposes for one record. It never decides activation on its own.

inventory

inventory(store: Store, principal: Principal) -> list[str]

Content-free labels of the fact categories present in the principal's readable conditional store.

decide_activation

decide_activation(
    record: Record,
    decision: CategoryDecision | None,
    principal_entity_id: str,
    evidence_turn: int | None,
    *,
    min_confidence: float = 0.7,
) -> tuple[ActivationOutcome, str]

Deterministic activation rule. The order matters: eligibility first, safety next, classification last.

retold.policy.bundles

Policy bundles: the complete set of components that produced a decision, hashed, and their fitness.

A bundle is every component that changes what the utility-aware path does: planner model and prompt, judge model and prompt, classifier, taxonomy, inventory builder, retrieval configuration, stage timeouts, budget, and candidate and gap caps. Any change to any of them is a new bundle hash. Active serving is allowed only for a bundle with a recorded passing fitness result; an unapproved bundle may run in shadow mode only.

BundleNotApprovedError

Bases: RuntimeError

Raised when a host tries to serve with a bundle that has no recorded passing fitness result.

BundleMismatchError

Bases: RuntimeError

Raised when a bundle's declared components do not describe the runtime that would serve them.

BundleRegistry

Records fitness results and answers whether a bundle may serve.

bundle_hash

bundle_hash(components: Mapping[str, Any]) -> str

Stable hash of a bundle's components; key order and whitespace do not matter.

retrieval_config_hash

retrieval_config_hash(retrieval_config: Any) -> str

The retrieval half of a bundle hash, derived from the configuration a host actually retrieves with.

retrieval_config is the whole RetoldConfig when the caller has one: the hash then covers the retrieval section and the reranker section together, because an enabled reranker changes what the judge sees as much as a gate floor does. A bare retrieval section or a plain mapping is hashed as given.

retold.policy.metrics

Metrics over the turn-decision log, for reports and for a host's rollback decisions.

Every turn decision is assigned exactly one stage outcome, so a change in served injection or recall can be attributed to one stage:

  • path_disabled: the utility-aware path was off or the budget was zero, so nothing ran;
  • planner_silence: the planner returned no gaps, so no retrieval happened;
  • retrieval_miss: the planner named gaps but retrieval returned no conditional candidates;
  • judge_rejection: candidates were judged and none admitted;
  • policy_failure: a policy failed, timed out beyond its stage limit, or returned malformed output;
  • budget_withheld: the per-request budget cut the path short, before admission or before regeneration;
  • admitted: memory was admitted; served when it regenerated, shadow when it only would have.

Production turns carry no labels, so unsafe and unexpected admissions cannot be counted here; those come from the fitness suite. What a host can watch is the served and shadow admission rates, the stage counts, latency, cost, the admitted-record distribution, and the review backlog, per bundle and per time window.

RollbackThresholds dataclass

Limits a host applies to a report. Any breach is a reason to disable the newest stage.

stage_outcome

stage_outcome(decision: Mapping[str, Any]) -> StageOutcome

Map one turn decision to its single stage outcome.

aggregate

aggregate(
    store: Store,
    *,
    since: datetime | None = None,
    until: datetime | None = None,
    bundle_hash: str | None = None,
    session_id: str | None = None,
) -> MetricsReport

Aggregate the turn-decision log into one report. Reads only; a host may call this on a schedule.

rollback_reasons

rollback_reasons(
    report: MetricsReport, thresholds: RollbackThresholds
) -> list[str]

Return every threshold the report breaches; empty means no rollback signal.

render

render(report: MetricsReport) -> str

Human-readable rendering for the CLI.

summarise_many

summarise_many(
    reports: Iterable[MetricsReport],
) -> dict[str, Any]

Convenience for hosts comparing windows or bundles.