RFC 1770-decision-policy-governance: Decision Policy Governance
- Proposal Name:
decision_policy_governance - Start Date: 2026-09-28
- RFC PR: oceanbase/powercontext#1770
- Tracking Issue: oceanbase/powercontext#1649
- Related RFCs: RFC 0046, RFC 0050, RFC 0080, RFC 1223, RFC 1560, RFC 1652, RFC 1745
- Related work: #1643, #1644, #1645, #1647, #1648, #1739, #1740, #1742, and #1745
Summary
This RFC defines a shared governance layer for narrow decision gates in PowerContext. A decision gate is a deterministic
Runtime consumer that asks one bounded question through the existing provider-neutral DecisionModel port, combines the
answer with local rules, and returns a typed assessment that a domain service may observe, flag, review, hold, or ignore.
The governance layer supplies policy manifests, shadow/advisory/enforcing modes, audit observations, replay/rescore
rules, privacy boundaries, and promotion criteria. It does not add a new model provider, expose the decision model as a
tool, change public HTTP/OpenAPI contracts, or claim that Jev, Laya, or any other backend improves PowerContext quality.
It establishes the contract that later Memory, Handoff, Experience, Skill, and safety-gate consumers must satisfy before
they can move from experiments to runtime behaviour.
This RFC also distinguishes decision gates from adjacent recall-preparation and context-projection helpers. Those helpers may improve query recall, make an injected projection safer, or describe what a host actually received, but they do not become policy consumers merely by using a model or a local rule. They cannot alter Scope resolution, authorization, Artifact history, or a domain action.
Motivation
PowerContext now has a provider-neutral decision role through #1739 and #1740. Several follow-up issues ask whether a cheap decision backend can help with narrow judgements:
- #1643: Memory reranking;
- #1644: semantic relevance and evidence coverage;
- #1645: Handoff and Task Outcome evidence checks;
- #1647: Experience and Skill applicability;
- #1648: duplicate and conflicting Memory candidates.
Those consumers have different domain effects, but they share the same risks:
- A model probability can be mistaken for authorization.
- A provider outage can be hidden as a clean pass.
- Hosted backends can receive material that a deployment did not intend to send.
- Thresholds can be copied from another system even though the loss function is different.
- A shadow experiment can be promoted without replay evidence.
- A failed or abstaining decision can be recorded as if it had actually judged the content.
The project already has concrete pressure on this boundary. #1742 proposes a Memory write-time evidence gate. #1745 proposes a decision-model reranker and explicitly separates rerank fail-closed behaviour from advisory fail-open behaviour. RFC 1652 reserves Memory consolidation, supersession, and lifecycle effects for review-gated flows. Without a shared policy and observation contract, each consumer will reinvent its own threshold, fallback, privacy, and audit rules.
For a policy that seeks promotion beyond shadow or advisory, the shared layer supports this evidence sequence:
- define a policy in shadow mode;
- collect observations without changing domain behaviour;
- replay and rescore the observations under candidate thresholds;
- promote only the narrow action a policy has earned;
- keep domain authority, review, persistence, and access control in the owning service.
This is an enablement RFC, not an adoption recommendation for a specific backend or a commitment to implement every
listed consumer. A consumer may stop at disabled, shadow, or advisory; it does not need a replay runner, dashboard,
or cross-consumer evaluation bundle unless it seeks a stronger mode.
Guide-level explanation
What a decision policy is
A decision policy is a versioned description of one narrow judgement. It says:
- which deterministic Runtime consumer may call it;
- what bounded question is being asked;
- which subject and evidence fields may be sent;
- which local rules should decide before any model request;
- which backend failure policy applies;
- whether the policy is disabled, shadow-only, advisory, or allowed to affect the domain action;
- what to record for audit and replay;
- which promotion criteria must be met before changing behaviour.
A policy is not a prompt registry for agents. It is called by PowerContext code, not by the host model. A host model
never sees a decision_evaluate tool and never decides when to call the decision backend.
What a narrow gate is
A narrow gate is a consumer of a decision policy. It receives a domain event, builds a policy-shaped request, and returns a typed assessment.
Examples:
- a Memory write gate asks whether the cited evidence covers the candidate Memory claim;
- a Handoff consult asks whether a claim should be treated as requiring human verification;
- an Experience/Skill applicability gate asks whether an exact approved revision applies to the current task;
- a duplicate/conflict gate asks whether a candidate Memory entry appears equivalent, conflicting, complementary, or unknown relative to exact existing entries.
The gate may use local rules before the model. For example, a Memory write gate can accept content that is too short to judge, decline to send content that contains sensitive material, or avoid repeated calls during a cooldown. A local rule that actually judges the content is an adjudication. A local rule that only refuses to send content to a hosted backend is not an adjudication; it is a fallback observation.
Runtime modes
Every decision policy starts disabled or shadow-only.
disabled:
The consumer is absent. It makes no decision call and produces no observation.
shadow:
The consumer records what it would have decided, but the domain action is exactly the same as if the gate did not exist.
Shadow mode is the default for new policies that have not been measured on PowerContext data.
advisory:
The consumer may annotate the domain result, add a warning, or create a review suggestion. It still cannot block, approve,
merge, retire, or execute anything by itself.
enforcing:
The consumer may take one explicitly allowed domain action, such as holding a Memory write or failing a configured
rerank stage. Enforcing mode is available only when the owning domain contract defines that action, the policy declares
the exact effect, and the promotion criteria have been satisfied. Enforcing does not grant approval authority.
The default progression is:
disabled -> shadow -> advisory -> enforcingA policy may stop permanently at any mode. Some consumers should never become enforcing.
What users and operators should expect
Decision assistance is opt-in. A normal PowerContext installation does not need Jev, Laya, or any other decision provider.
When a hosted provider is used, the deployment must explicitly choose what content may leave the process. The policy records that content boundary. If a gate cannot send enough material because of privacy rules, the observation is marked as fallback or unknown. It must not be recorded as "checked and clean".
When a policy is in shadow mode, the user sees no behaviour change. Operators may inspect aggregate observations and run replay jobs. Replay can answer questions such as:
- What would the write gate have held at threshold X?
- How many extra human reviews would advisory mode create?
- Which reasons account for most fallbacks?
- Did a candidate threshold produce any known false holds?
Promotion is based on replay and labeled evidence, not on provider claims.
Boundaries that users should not expect
This RFC does not add a general decision workflow engine. It does not let a model approve Review candidates, accept a Handoff, verify task completion, deactivate Memory, install a Skill, or select tools for an agent. Those remain domain actions owned by existing PowerContext services and their review or authorization contracts.
This RFC also does not change RFC 1745. Decision reranking is a special non-advisory consumer whose failure policy is fail-closed under RFC 0080. The shared policy layer may describe that role, but it must not turn reranking into a fail-open advisory gate.
Reference-level explanation
Named concepts
DecisionPolicy
A DecisionPolicy is a versioned, low-cardinality runtime policy. Its stable identity is independent of the backend
model version.
Required fields:
| Field | Meaning |
|---|---|
policy_id | Stable identifier such as memory.write.evidence_sufficiency.v1. |
decision_kind | Low-cardinality selector passed to DecisionRequest.decision_kind. |
version | Policy schema/question version, separate from backend model version. |
consumer | Owning consumer, such as memory_write_gate, handoff_evidence_consult, or experience_applicability. |
mode | disabled, shadow, advisory, or enforcing. |
failure_policy | fail_open or fail_closed, resolved per consumer role. |
privacy_boundary | Whether subject/evidence content may be sent to local-only, hosted-redacted, or no external backend. |
local_rules | Deterministic pre-rules and their reason codes. |
question | The bounded question template. |
subject_selector | The domain value judged by the question. |
evidence_selector | Exact references or excerpts allowed as evidence. |
outcome_mapping | How yes, no, abstain, fallback, and local-rule results map to a gate assessment. |
promotion_criteria | Minimum evidence before advancing modes. |
Policy files or in-code policy constants must be reviewable. A policy cannot silently change the question text or
threshold while keeping the same policy_id and version.
DecisionAssessment
A gate returns a domain-neutral assessment before the owning service maps it to a domain action.
DecisionAssessment:
policy_id
policy_version
mode
coverage # adjudicated | unadjudicated
verdict # allow | deny | review | unknown
source # local_rule | decision_model | none
reason
confidence
used_fallback
usage
latency_mscoverage is the first truth axis:
adjudicated: a local rule or backend made a substantive judgement about the content.unadjudicated: the gate did not judge the content; any domain pass-through is fallback behaviour.
used_fallback=true implies coverage=unadjudicated. A policy must not record adjudicated+allow when the only thing
that happened was "content was too sensitive to send", "no backend is configured", "cooldown is active", or "the backend
failed". Those cases may pass through, but they are not evidence that the candidate is clean.
DecisionObservation
A DecisionObservation is the audit/replay record for one gate evaluation. It is intentionally distinct from the
domain object. It may be emitted to logs, an evaluation artifact, or a future internal ledger; the first implementation
does not need a public HTTP or OpenAPI surface.
Required observation fields:
- operation identity and scope;
- consumer and policy identity;
- mode;
- sanitized subject/evidence references;
- redaction and privacy-boundary outcome;
- model provider id and backend model id when a backend was called;
- model/policy versions;
- assessment;
- final domain action actually taken;
- usage and latency;
- fallback reason, if any.
Raw subject/evidence text is not stored by default. Replay should prefer exact PowerContext references and re-resolve them under the same authorization context. If a deployment chooses to retain raw snippets for offline evaluation, that retention must be explicit and separately documented.
Adjacent recall and projection helpers
DecisionPolicy governs a bounded verdict. A helper that transforms a retrieval query or renders a context projection has
a different contract: it prepares information for a host or model but cannot adjudicate a domain object. Implementations
must keep that distinction explicit rather than representing a rewrite, redaction, cache hit, or omitted context as a
policy allow result.
Query preparation
A host may optionally derive a retrieval query from the current user request before recall. A model-assisted rewrite is a
preparation helper, not a DecisionModel consumer: it returns a candidate query, not a yes/no/abstain verdict.
- It runs at a host/context boundary after Scope and authorization resolution, never inside a generic Memory service.
- The original query remains the authoritative request. The helper must preserve it for diagnostics, and timeout, invalid output, privacy refusal, or model failure must fall back to that original query without changing domain behaviour.
- A rewrite must be treated as untrusted transformation output. It cannot introduce a Scope, Artifact reference, access claim, instruction, or tool action. Local validation must bound its size and reject malformed output before search.
- A new rewrite begins in shadow evaluation. It records a privacy-safe request fingerprint, rewrite/fallback reason, latency, and candidate-set comparison, then earns activation only from PowerContext replay evidence. Evaluation must measure recall quality, bad-recall and instruction-like cases, fallback rate, P95 latency, and added model cost.
The deterministic query analyzer and recall-sufficiency policy remain the default path. A rewrite may complement them; it must not replace their bounded, model-free guarantees without a separate RFC.
Projection safety and Context Receipt
Memory, Source, and Artifact revisions remain authoritative evidence even when their text is unsafe or unsuitable for a
particular host/model projection. A deterministic safety helper may flag, redact, or withhold a projection before host
injection or external-provider egress, but it must not silently rewrite history or claim that an uninspected item is
clean. A privacy/transport refusal is unadjudicated, and a safety finding may create an existing review suggestion but
does not authorize a Memory lifecycle action.
Hosts need a separate Context Receipt for operational debugging and replay. It is a sidecar, not extra prompt text, and may contain the exact selected Artifact/Memory revisions and entry versions, selected and omitted item counts, truncation facts, safety/projection outcome, query-preparation outcome, and the relevant policy or model version. The receipt lets a host explain what it received without weakening the rule that current user instructions and live state take precedence over historical context. It does not create a public API, persist a new ledger, or expose raw content by itself.
Consumer classes
Advisory consumers
Most gates are advisory by default. Advisory consumers use fail-open runtime semantics: backend failure becomes
unknown or pass-through, and the owning domain behaviour proceeds unchanged unless the policy has been explicitly
promoted to a stronger mode.
Examples:
- Handoff evidence consult;
- Experience/Skill applicability recommendation;
- duplicate/conflict observation before Memory lifecycle review;
- hosted-provider safety screens whose result can suggest review but cannot authorize.
Advisory consumers may annotate, warn, or create a pending review suggestion where the domain already has such a concept. They must not approve, accept, execute, publish, deactivate, supersede, or merge.
Enforcing consumers
An enforcing consumer can change behaviour only inside an explicit domain contract.
Allowed examples:
- A Memory write evidence gate may hold a write if the Memory service defines a visible, structured refusal and the policy has been promoted.
- A reranker may fail closed because RFC 0080 and RFC 1745 define reranking as non-advisory.
Disallowed examples:
- A duplicate/conflict gate cannot deactivate or supersede Memory by itself; RFC 1652 reserves those effects for review proposals and approved lifecycle operations.
- A Handoff consult cannot mark work complete or accept a Handoff.
- A Skill applicability gate cannot install, publish, or execute a Skill.
Local rules and code-first decisions
Policies may run local rules before model calls. Local rules are valuable when code can answer a cheaper, more reliable question:
- the candidate is empty or outside supported length bounds;
- the action is outside the gate's scope;
- a sensitive key was detected and the hosted privacy boundary forbids sending;
- the same content was already adjudicated under the same policy version;
- a deterministic citation or revision check already fails.
Local rules must return reason codes. They also must distinguish content judgements from transport/privacy decisions.
Examples:
| Local result | Coverage | Reason |
|---|---|---|
| Candidate below minimum useful length and policy defines it as pass-through | adjudicated | too_short |
| Candidate contains a sensitive value and hosted sending is disabled | unadjudicated | sensitive_not_sent |
| No backend credentials | unadjudicated | no_backend |
| Policy cooldown active after provider failure | unadjudicated | cooldown |
| Citation reference cannot resolve | Domain error before gate | invalid_evidence_reference |
Shadow, audit, and replay
Shadow mode is required before a policy can change production behaviour unless maintainers explicitly accept a narrower fast path in the implementation PR.
Shadow mode requirements:
- The final domain output is byte-for-byte or semantically identical to the no-gate path.
- Every gate attempt emits a
DecisionObservation. - Observations distinguish no-call, local-rule, successful backend, backend fallback, privacy fallback, and parse failure.
- A policy considered for
enforcingcan be replayed or rescored without re-running the whole workload when enough exact references remain resolvable.
Replay has two forms:
- Rescore: reuse stored backend outputs and apply a new threshold or outcome mapping.
- Re-evaluate: re-resolve exact references and call a backend under a new policy or model version.
Both forms must report their input coverage. A replay result that cannot resolve enough original material is not a negative result for the policy; it is an incomplete replay.
Replay/rescore is required promotion evidence, not a required runtime feature for every shadow or advisory consumer.
A consumer without that evidence must not be promoted to enforcing.
Memory write-gate promotion evidence is tracked separately in #1930.
Promotion criteria
A policy must declare promotion criteria before moving beyond shadow.
Minimum criteria:
- a labeled calibration set separate from held-out evaluation;
- a held-out result covering English and Chinese cases when the consumer can see both;
- no known high-severity false action for the enforcing action being promoted;
- measured fallback rate by reason;
- measured added latency and request cost;
- a friction budget for human-review or hold outcomes;
- a rollback path to the prior mode.
The exact numeric threshold belongs to the policy and the domain loss function. A Memory write gate that tries not to lose true observations and a duplicate/conflict gate that tries not to merge history have different acceptable errors. Thresholds from Hermes, OpenClaw, Jev cookbooks, Laya reports, or any other prior art are hypotheses, not defaults.
Privacy boundary
Every policy declares one of these content boundaries:
| Boundary | Meaning |
|---|---|
local_only | Subject/evidence content may be sent only to an in-process or loopback backend. |
hosted_redacted | Content may be sent to a hosted backend only after PowerContext redaction/sanitization. |
references_only | Hosted calls may receive identifiers, metadata, or bounded non-secret labels, but not raw content. |
no_external_call | The policy can use only local rules. |
The implementation must use PowerContext's existing sanitization primitives where applicable rather than inventing a
parallel redaction scheme. If sanitization removes material required to answer the question, the observation is
unadjudicated; it is not allow.
Interaction with existing RFCs
RFC 0080 and RFC 1745
Decision reranking is covered by RFC 1745. This RFC does not change its fail-closed stance. The shared policy layer can record observations and policy metadata for a reranker, but it must preserve RFC 0080's startup validation and runtime failure semantics.
RFC 1560
The recall sufficiency gate is model-free and remains the default recall expansion policy. Decision policies may add semantic observations around retrieval quality, but they do not replace the deterministic sufficiency gate unless a future RFC explicitly changes that contract.
RFC 1652
Memory quality and lifecycle effects remain review-oriented and evidence-preserving. A duplicate/conflict gate may produce observations or proposals that feed RFC 1652 evaluation, but it cannot directly merge, deactivate, supersede, or rewrite Memory.
RFC 0050
Review Inbox remains the place for review-owned families and explicit review proposals. A gate may create a pending Candidate only where the owning family already supports that flow, and the model cannot approve the Candidate it creates.
Compatibility, persistence, and API impact
This RFC adds no public HTTP endpoint, no OpenAPI field, no required database table, and no migration by itself.
Implementation PRs may add internal data structures, structured logs, evaluation artifacts, or optional private ledgers. Any public diagnostic API, persisted audit table, or externally visible error contract must be proposed in that implementation PR or a follow-up RFC.
Existing installations continue to work without a decision backend. Existing Memory, Handoff, Experience, Skill, Review, and PreparedContext contracts are unchanged by accepting this RFC.
Drawbacks
- The policy layer adds concepts before all consumers exist. That can feel heavy for the first gate.
- Shadow and replay delay visible product behaviour.
- Observation design can become a second telemetry system if it is not kept aligned with RFC 0046.
- Privacy-safe replay is harder than storing raw snippets, and some replay attempts will be incomplete.
- A shared layer can overfit to Jev-shaped yes/no decisions if reviewers do not keep provider neutrality explicit.
Rationale and alternatives
Why a shared policy layer
The consumers are narrow, but their risk controls are the same. A shared layer lets each implementation PR focus on its domain question while reusing the same vocabulary for fallback, audit, shadow, replay, privacy, and promotion.
Alternative: each consumer defines its own gate
This is faster for the first PR, but it creates incompatible meanings for "fallback", "unknown", "checked", "shadow", and "promoted". It also makes cross-consumer evaluation impossible.
Alternative: make every decision model call fail-open
This is safe for advisory consumers but wrong for non-advisory roles such as RFC 1745 reranking. Failure policy belongs to the consumer role, not the backend.
Alternative: use Review Inbox for every uncertain result
This would turn uncertainty into user friction. Some uncertainty should be counted and observed rather than sent to a
human. A policy must justify when review is the correct verdict.
Alternative: store complete raw prompts for replay
This makes replay easy but violates the privacy boundary that motivated explicit hosted-provider opt-in. Exact PowerContext references and optional deployment-controlled retention are a safer default.
Prior art
PowerContext already has the building blocks:
- #1739 and #1740 add the provider-neutral DecisionModel role.
- RFC 1745 defines a decision-model rerank seam and the fail-closed distinction for reranking.
- RFC 1560 defines a model-free recall sufficiency gate with bounded expansion.
- RFC 1652 defines evidence-preserving Memory quality and lifecycle boundaries.
- RFC 0050 defines the Review Inbox and the rule that generated candidates cannot approve themselves.
- RFC 0046 defines observability foundations that the observation stream should reuse rather than bypass.
Adjacent systems provide cautionary examples. Hermes-style Jev plugins show the value of cheap code-invoked gates, shadow modes, and local rules, but their thresholds and host-specific hooks are not PowerContext defaults. OpenClaw-style decision roles show why decision models should be runtime collaborators rather than model-callable tools. Jev and Laya are candidate backends or reference points, not policy owners.
Unresolved questions
- Should policy definitions live as Python constants, JSON/YAML resources, or both?
- Which numeric promotion criteria should #1742 use if it is revised to conform to this RFC?
- Do hosted-provider privacy boundaries need a user-facing configuration document before the first hosted backend is enabled?
- How should replay jobs report authorization changes when an exact reference was visible during shadow collection but is no longer visible during replay?
Future possibilities
- A policy registry page in the dashboard showing active policies, modes, fallback rates, and last replay results.
- A CLI command that replays one policy against recent observations and prints candidate thresholds.
- A standard evaluation bundle for decision policies, shared by Jev, Laya, local rules, and future backends.
- Policy-aware Review Inbox grouping, where a review item links back to the policy observation that suggested it.
- Local-only decision backends for air-gapped deployments, using the same policy and observation contract.

