# Review contract compatibility **Purpose:** Record how direct-edit type and function review fits configuration, rules, identity, and delivery. **Audience:** Contributors, including coding agents; Rule authors; Product and specification owners. **Status:** Maintained. **Authority:** Accepted product contract for the named compatibility decisions. Tests and conformance records supply implementation evidence. **Expected use:** Check changes to configuration, rule definitions, review input, and review result reuse. **Lifecycle:** Review when any of those boundaries or the #93 type/function contract changes. Direct-edit type and function review uses cross-file source within graph limits. The [#93 contract](type-function-review-proposal.md) owns the source, completeness, and input requirements. ## Configuration and individual rules Individual rule documents separate intrinsic input requirements from configured application policy. This contract owns configuration composition, rule identity and input compatibility. The [configuration guide](configuration.md#configuration-composition) describes composition; the [rule reference](rules.md) describes authoring and commands. Formats are version 1. Ordinary settings resolve from built-in defaults through user settings to project settings. Omission inherits. Includes and languages use the highest supplied list; an empty list selects nothing. Exclusions accumulate and win over includes. Per-rule fields resolve independently by stable rule identity. User-owned privacy, review destination, shared resource and stronger-feedback restrictions cannot be overridden by ordinary project precedence. Configuration explanation uses the same resolved policy as review. It reports the supplying layer, configuration source and field, distinguishing overridden include lists from effective selection. A path-only explanation leaves artifact kind and evidence explicitly unexamined. Explanation makes no classifier request. Rule settings resolve by stable rule identity under configuration composition and intersect global root selection and intrinsic input support. There is no separate repository grant. Invalid selected configuration fails before source capture, even when other selected rules are valid; it cannot fall back to that valid subset. Global `includes`/`excludes` select edited roots. `contextIncludes`/`contextExcludes` select supporting source; omitted context selection follows the effective root file policy. Explicit context settings may allow related files outside root scope without making them review roots. `privacyExcludes`, containment, protected paths, Git-ignore, file kind, and capture bounds apply before every root or supporting read. No include can restore a privacy-denied file. Freshness checks retain each file's root or context role. Each version-one JSONC rule document declares a stable ID, optional display title, question, criteria, message, threshold, and `inputs`. Each input declares `languages`, `kind` (`type` or `function`), and required evidence in `requires`. The compiler maps accepted combinations to the exact direct-review contract; authors do not supply transport contract identifiers. TypeScript, Rust, and Bend types and TypeScript functions can be reviewed within their analyzer profiles. Unknown fields or versions fail validation. Enabled input combinations selected by configured languages must be accepted by the compiler, including their evidence requirements. A disabled rule may retain an unsupported schema input for future use; enabling it fails. Configured languages must be a subset of authored languages, or configuration fails. An eligible subset of a multi-input rule may be selected explicitly. Runtime schemas have no execution support, and concrete values are unsupported roots; a schema is not implicitly a type declaration or a higher evidence rung. One file defines one rule. Files become active only through explicit configuration `rules` references. New rule references enable their rule unless disabled. References use either a local path or an inherited rule ID, with optional activation, languages, paths, threshold, and message settings. Paths belong to configuration. A duplicate identity or rebinding to a different file is an error. Rule content and effective settings have content digests; there are no pack identities or content version labels. Shipped default IDs use descriptive names without numeric prefixes (for example, `meaningless_combinations`). Existing authored files and explicit selections remain authoritative; setup preserves them. Initial setup provisions the shipped editable defaults only when no configuration layer declares `rules`. Any explicit selection, including `rules: []`, is authoritative: repeat setup preserves it and authored files, without enabling unselected defaults. Missing rule files fail validation instead of being recreated. The default body rule requires the exact function signature and body, not complete call/type closure. Missing references are explicit omissions and are not findings. Other inputs retain their declared evidence requirements. Every shipped and custom rule uses the same validation, compilation, and evidence-admission boundary. Choice and Score result forms remain separate decisions. A finding requires a validated probability strictly greater than the effective rule threshold; equality produces no finding. Probabilities and thresholds are finite values between zero and one, inclusive. ## Smoke test the rule `hapsland rules check --path FILE --line N` sends the enclosing declaration and related code to the classifier, without an agent session or resident. Add `--id` to select one enabled rule. Results include probabilities and findings; `--json` includes code. Unsupported, ambiguous or stale selections cannot yield a valid result. See [usage and limits](rules.md#try-a-rule-on-a-file-and-line). ## Review input and result identity The active input contracts are direct-event/type-shape/v1 and direct-event/function/v1. Each request carries one changed root and its evidence tree within graph limits with marked omissions. Supporting declarations can come from other selected files through local imports the analyzer resolves. They do not become separate edited roots. Omitted reference sites may contain opaque expression text, such as an anonymous callback or dynamic call, rather than a named binding. This text remains a size-limited JSON string with its omission reason; it neither adds a resolved node nor makes the graph complete. Resolved edges retain their named-reference grammar, and the aggregate evidence-size limit still applies. The request contains neither a whole file nor an edit diff, agent transcript, absolute path, or unrelated source. ### Review content isolation For fixed selected source, selected rule questions and criteria, and provider configuration, request content must not depend on task prompts, conversation history, prompt/transcript digests, local inspection records, or agent attribution. These private values must not be copied into otherwise valid source, rule, URL, or header fields. A schema-valid request alone does not establish this property. The same boundary applies to retained snapshots and subsequent dispatches. Inspection observes a copy of encoded request bytes and cannot rewrite them; review transports disable ambient trace-header propagation. Permitted review content includes the selected declaration/evidence tree (with relative source identities and renderer metadata), authored rule IDs, questions and criteria, and provider framing. Authentication is sent separately in the provider's authorization header. A user or agent can copy conversation text into selected source or rule files; that text then belongs to the explicitly permitted input. This contract does not require semantic redaction of code or rules. The content guarantee does not claim independence of request timing, count, admission, cancellation, or reviewed edits from the conversation. The agent's work and prompt lifecycle can affect those. The [production Bend content laws and host obligations](../packages/agent-flow-bend/README.md#content-isolation-proofs) distinguish the proved top-level selection/framing properties from implementation evidence and remaining gaps. These laws do not prove the full content-isolation contract. ### Edit-owned settings Configuration and compiled rules belong to the originating edit's captured settings snapshot. Pre-edit registration captures that snapshot; observation admission captures it when no registration exists. Duplicate pending registration preserves the original snapshot. It remains unchanged through preparation, dispatch, advice and delivery, including provider selection, file policy and feedback mode. Later collect or Stop requests do not reload it, and cache expiry does not replace it. Saved configuration and rule changes apply only to subsequently captured edit snapshots, with the cache behavior described in [configuration](configuration.md#runtime-behavior). In particular, changing exclusions does not cancel dispatch for an edit whose settings were already captured, and cannot recall a request already sent. Source freshness and current credential authority remain separate checks; frozen settings do not waive them. ### Freshness and result reuse Hapsland selects each rule only when its declared evidence needs are met. A rule may run with a marked omission that is irrelevant to it. If no rule applies, Hapsland sends no request. A review input's identity includes the exact input contract, renderer, root, evidence tree and its omissions and completeness, selected rule definitions, and effective policy. Retain each contributing file's fingerprint for freshness checks; a changed fingerprint does not by itself change semantic identity when an unrelated comment moves. Review requests use the captured input under the [edit-owned settings](#edit-owned-settings); source is not reread before dispatch or while selecting pending advice. Before a selected delivery is handed to its caller or IPC transport, Hapsland rebuilds the complete canonical review input under those settings and checks that the evaluated unit remains current. This includes supporting evidence and import resolution. File hashes alone are insufficient: adding a second import candidate can make resolution ambiguous without changing any previously captured file. Unrelated source changes may preserve the canonical unit input and therefore preserve its advice. Each delivery has a fresh, scoped source snapshot cache: selected results sharing the same physical root and path use one stable capture. Cached bytes remain charged to the resident capacity ledger; parsing and import resolution still run for each evaluated unit. Later results can enter a later delivery while reviews continue; they cannot reuse an earlier delivery's cache. The final member or an interrupted delivery immediately erases cached source bytes and clears the cache. Parsed trees are not retained in this cache. Recipient and physical-root identity follow the [advice contract](advicing-target-contract.md#advicee-identity-and-admission). Credential and final handoff checks follow its [handoff contract](advicing-target-contract.md#handoff-reoffer-and-continuation-count). Only a still-current matching unit may reuse a successful review-backend result. The prepared identity includes the selected provider, model selector, and full destination; a change to any of these invalidates reuse. See the [provider boundary](review-providers.md) for transport validation and declared limits. Update attribution currently requires an exact verified post-edit span. Codex `apply_patch` hunks, Claude `Edit`/`Write` native content evidence, and Pi native `edit` unified-result patches can supply one. Codex and Pi share post-edit patch verification with explicit placement rules: Codex requires a unique text match; Pi verifies native line coordinates against current source within capture limits without a text-search fallback or a separate pre-edit image. Pi derives ranges from the successful result patch independently of how `oldText`/`newText` replacements are grouped, including replacements spanning omitted context across hunks. Claude derives spans directly from its native content evidence. Attribution compares one-based UTF-16 code-unit columns from the pinned Node parser binding and verified edit spans. Unicode comments and strings do not prevent Add or verified Update selection. Missing or uncertain spans still produce no Update review unit; OpenCode Update currently supplies no verified span, while its Add path selects eligible declarations. Runtime-specific limits still apply: the [Pi profile](pi-installation.md) currently requires ASCII input and source. Native Pi `write`, nested/child mutations, shell mutations, and custom tools are unsupported/incomplete rather than inferred Add or Update observations. The previous compatibility assessment for the one-file input remains in Git history. Its old prospective gates do not govern the 2026-09-29 decision.