# Layer 2 — Product contract of Objective Guard

## Objective

Objective Guard must accompany a programming agent during a task and return, with latency proportional to the moment, one of four result classes:

- `pass`: the executed checks found no violations and the scope of the assertion is declared;
- `warn`: a non-blocking fact or calibrated signal exists that requires attention;
- `block`: an explicit policy applied to reproducible evidence prevents continuing or closing;
- `error`: the guard could not evaluate; must never be confused with `pass`.

The result must be compact, reproducible, and traceable to rule, file, location, evidence, and next action.

## Users

### Programming agent

Consumes signals during editing, corrects violations, and attaches evidence before declaring a task complete.

### Supervising developer

Defines or approves objective, exceptions, and sensitive policies. Inspects explanations without reading complete traces.

### Module owner

Maintains local contracts, public boundaries, focused commands, and invariants of their area.

### Platform team

Integrates hooks, CI, sandbox, global policies, storage, and telemetry.

### Researcher or evaluator

Uses passive events and benchmarks to validate statistical metrics without first altering observed behavior.

## Scope

### Level 0 — Universal reflex

Operates without session contract on the newly modified file or diff:

- broken syntax;
- disabled or weakened tests;
- stubs and placeholders in production;
- new dependencies;
- fingerprints and delta-only output;
- append-only events for investigation.

### Level 1 — Session and contract

Activates intention-specific controls:

- task type;
- original immutable objective;
- acceptance criteria;
- declared target set;
- expected scope and sensitive zones;
- applicable invariants and contracts;
- evidence state by criterion.

### Level 2 — Incremental impact

Calculates affected paths, modules, symbols, boundaries, and checks. Selects quick verifications and reuses cache.

### Level 3 — Final verification

Requires full traceability, executes higher-coverage checks, and produces an auditable artifact for CI or human review.

### Parallel scientific level

Records surface, evidence, trajectory, latency, and results. Statistical signals remain passive until surpassing calibration and intervention criteria.

## Non-goals

- Replace CI, static analyzers, or test suites.
- Manually maintain an exhaustive specification of the repository.
- Execute the entire repository on each edit.
- Allow an LLM to be the final authority on correctness.
- Block by an opaque score.
- Build from the start a universal semantic index for all languages.
- Recommend complete rewrites as an automatic response to an anomaly.

## Requirements

### Hierarchical OKR contract

The versioned file `oguard.contract.json` links the main objective to the round objective. It declares stable IDs, target KRs, observable evidence by path, expected scope, non-goals, and signal policy. An invalid contract produces a visible error; it does not degrade to `pass`.

Modified paths are candidates for attributed evidence, not semantic proof of compliance. The output preserves that limitation through per-KR counts and does not automatically transform a touched file into an achieved KR.

The agent can query `oguard align` after a patch. The compact output recalls objective, round, surface, and KRs; a warning preserves exit code zero so that an early integration phase does not by itself stop the work.

Before the first material change, `oguard task-flow` verifies that a typed contract, matching baseline, and governance health exist. It logs the `task-flow` event with sanitized data and returns `ready` or `action-required`. Global harnesses deliver this instruction at the start of the request; they do not substitute for human authority in inventing objective, scope, or task type.

The global Claude and Codex harnesses additionally apply a `PreToolUse` gate over the structured editing tools. It only lets work continue when the last `task-flow: ready` corresponds to the contract's current hash and is less than one hour old. The policy is fail-open for repositories without a contract and does not attempt to inspect arbitrary writes inside shell commands; the limit is stated explicitly so as not to present partial coverage as total isolation.

A project can version `oguard.kpis.json` to make the global inventory's KPIs part of the preflight. `task-flow` validates that policy before granting authorization and persists its hash alongside the contract's. A `block` rule with sufficient sample prevents editing; a policy change invalidates the prior authorization. `warn` rules and `unknown` results from insufficient sample inform without simulating premature certainty or blocking.

The global inventory also logs each `task-flow` with a sanitized status. `oguard inventory dashboard --days N` aggregates adoption, flow usage, intervention, and resolution by project and harness. The dashboard declares the causal effect as `not-evaluable` while no adjudication or experimental design exists: usage volume and a later correction are not enough to attribute time saved, tokens saved, or avoided drift to the guard.

`oguard init` creates a v1 contract in `observe` mode a single time. It is an on-ramp, not a correct default configuration: the user must replace objective, round, KRs, scope, and non-goals before enabling `warn`. The command refuses to overwrite an existing contract.

`oguard start` exclusively fills in that placeholder using IDs, objective/round/KR text, task type, and scope patterns. It rejects an already-started session: a subsequent round requires a versioned, deliberate edit of the contract, not an implicit rewrite. On starting it saves an immutable snapshot in `.oguard/session-baseline.json` with objective, round, scope, and initial hash.

`oguard next-round` opens a typed successor before new work. It requires a clean Git tree and that the active baseline match the current contract; it archives the previous contract and baseline under `.oguard/history/` with hash-directed names, installs the new contract, and replaces only the active baseline pointer. It also preserves an append-only `round-transition` event with both rounds, hashes, and file locations. It does not rotate a session with a pending diff nor a contract manually edited since its baseline; for that reason it cannot retroactively accommodate the work that E-005 observed.

For historical contracts that were versioned before a baseline existed, `oguard adopt-baseline` only operates on a clean tree, requires an already-typed contract, and fails if a baseline already exists. It creates the first baseline without rewriting the contract and logs `baseline-adopted` with commit, hash, objective, and round. It is a local, one-time migration, not a way to edit history or approve pending diffs.

When a closed round did not obtain `pass`, but an owner explicitly accepts non-promotable debt in order to start subsequent work, `oguard accept-baseline --reason --actor` allows a single local acceptance of the current contract. It requires a clean tree and an already-logged `round-end`; it archives the previous baseline and records actor, reason, and prior status. It does not change the historical verdict, does not silence checks, and is not equivalent to a promotion.

`oguard.plan.json` is the plan versioned outside the round contract. It contains the objective and KR hierarchy that is meant to be preserved; `oguard anchor-plan` only anchors it from a clean tree and against a matching contract baseline. The baseline preserves the plan's hash and content. If the file changes afterward, closing emits `plan-amendment`; editing the current contract is not accepted as redefining that reference.

Operational feedback from long multi-agent development requires a future split between durable governance and active execution state. Objectives, KRs, criteria, policies, and deliberate changes remain versioned. The active round pointer, preflight authorization, worker or agent identity, and lifecycle progress belong to local append-only operational state and must not force a permanent rewrite of the durable contract for every inherited subround. Until that split is implemented, the current versioned round transition remains authoritative; the product must not silently emulate the future model by mutating or ignoring the contract.

A native subround is an execution unit beneath a stable parent round. Definition, implementation, review, and correction subrounds inherit objective, KRs, non-goals, policy, and applicable criteria; they may narrow work scope and attach evidence, but cannot widen or redefine the parent objective implicitly. Each subround has a stable ID, role, actor or agent, parent ID, timestamps, baseline fingerprint, changed surface, evidence, result, and causal predecessor. Parallel subrounds merge evidence by criterion and preserve contradictions rather than overwriting one another.

A plan evolution declares `amendment: {id, reason, actor, previous_hash}`. The previous hash must match the anchor; otherwise the alert remains. A `contract_change` must reference `plan_hash` or an approved `amendment_id`, in addition to its reason. Anchor and amendment events are exported as sanitized evidence.

Before editing the plan, `oguard register-plan-amendment` is run from a clean tree. The command archives the previous content under `.oguard/history/plan-<hash>.json` through exclusive creation and emits `plan-amendment-registered` with the previous hash. The export preserves that event without local paths; a rewrite that has no historical file is not a verifiable amendment.

The export also verifies each event against the archived file and its hash. It reports `plan-chain-incomplete`, `plan-chain-archive-missing`, or `plan-chain-hash-mismatch` without statistical inference.

Chain findings have a stable fingerprint and persistent state: the first close emits them as novelties, repeated closes do not duplicate them, and a repair logs its resolution. The evidence exports both counts.

`oguard health --json` deterministically consolidates the plan's hash, number of amendments, integrity, and active/resolved findings. The same object is included as `governance_health` in the exported evidence.

A subsequent change to objective, round, or scope must declare `contract_change.reason`. The baseline is not updated: closing preserves an append-only change event and, if reason is missing, emits `contract-accommodation`. At this stage the signal is preventive, not proof of intent: it informs that the current contract may normalize work already done. An explicit reason suppresses the warning but does not erase the difference nor the event.

Each round can declare `work_context.kind`: `normal`, `merge`, `rebase`, `migration`, or `generated`. In transitional contexts, if the fraction of files within scope falls below `policy.min_scope_coverage` (0.5 by default), the alignment analysis switches to `scope_validity: not-evaluable`. It preserves the surface and deterministic failures, but does not emit per-file drift noise nor count it as detector accuracy.

The contract can declare `public_boundaries` as a list of `{id, paths, consumer_workspaces}`. It is a human, structured, validated assertion: if a changed file matches `paths`, the planner incorporates only those consumer workspaces as candidates. A declared dependency between workspaces is not enough to propagate checks from an internal file; propagation can also arise from an observed static relative import. A boundary does not implicitly execute commands: the consumer's check stays `skipped` until authorized. The output preserves the IDs of affected boundaries, unknown consumers, and confidence limits; it does not infer APIs from symbols.

The same contract can declare `checks` as a list of `{id, argv, timeout_ms, modes?}`. `modes`, when present, contains a unique combination of `fast` and `final`; if omitted, the check applies to both. In the beta, `oguard round-end --mode fast|final` executes only the commands declared for that mode (without shell), plus the universal detectors and `git diff --check`. The planner discovers `test` whenever it exists and `lint`/`typecheck` when code is touched; without authorization, or outside the chosen mode, they stay `skipped` with their reason visible. One or more omitted candidates return `unknown` with `verification: incomplete`; an omission never widens the `pass` assertion.

Criteria live in `task.acceptance_criteria` and link IDs of reproducible checks. A criterion can additionally declare `evidence.semantic` as assertions `{id, check, contains}`: a passing check only proves the criterion if its output contains that declared evidence. If the check passes but the assertion does not appear, it stays `unknown`; a matching path never turns it into `proven`. Closing identifies both sources as `reproducible-check` or `semantic-assertion` and reports them as `proven`, `violated`, `unknown`, or `not_applicable`; the latter requires explicit justification. In `fast`, a required criterion that is `unknown` keeps the `unknown` verdict (except for the `bugfix` regression obligation, which still blocks); in `final`, every required criterion that is `unknown` blocks.

The types `feature`, `refactor`, `improvement`, `migration`, and `investigation` declare `task.obligations`: each obligation references one or more IDs of existing criteria. The required set is fixed and visible: feature (`behavior`, `compatibility`), refactor (`preservation`), improvement (`baseline`, `metric`, `guardrails`), migration (`compatibility`, `integrity`, `recovery`), and investigation (`evidence`, `conclusion`). An obligation is only `proven` if all its referenced criteria are proven by checks; if the reference is missing it stays `unknown` and blocks closing. An obligation is never inferred from paths, objective text, or model judgment.

### RF-01 — Automatic hook

Must receive the edited file or patch and execute level 0 without deliberate agent invocation.

### RF-02 — Delta-only protocol

Must fingerprint findings, emit only novelties, and summarize resolutions.

### RF-03 — Output budget

Must order by severity, limit lines, and offer an explicit command for full detail.

### RF-04 — Reproducible evidence

Each finding must include rule, location, message, reproducible command or comparison, and detector version.

### RF-05 — Session contract

Must accept a structured representation of intention without altering the original request. Automatic classification may propose, but not hide ambiguity.

### RF-06 — Task types

Must support at least `feature`, `bugfix`, `refactor`, `improvement`, `migration`, `maintenance`, `investigation`, and `discovery`.

### RF-07 — Obligations by type

- `bugfix`: reproduction or regression test.
- `feature`: evidence of new behavior and relevant compatibility.
- `refactor`: observable preservation.
- `improvement`: baseline, metric, and guardrails.
- `migration`: compatibility, integrity, and recovery.
- `investigation`: evidence and conclusions; productive changes require explicit transition.

### RF-08 — Partial impact

Must declare confidence and uncertainty when the impact graph is incomplete.

### RF-09 — Check planning

Must select checks by task type, diff, boundaries, historical cost, risk, and uncertainty through inspectable rules.

### RF-10 — Criterion states

Each criterion must end in `proven`, `violated`, `unknown`, or `not_applicable`, with evidence or justification.

### RF-11 — Auditable exceptions

An exception must indicate rule, reason, scope, actor, and expiration. It does not eliminate the observed fact; it modifies the policy decision.

The beta implements versioned local exceptions in `exceptions[]`, with `id`, `rule`, `reason`, `actor`, a future `expires_at`, and a non-empty `scope.paths`. They can only exempt policy warnings whose observed paths are completely within scope. Closing keeps the original warning and logs `exception-applied`; it separately exposes `effective_warnings`, which is the only set that can modify the current verdict. An expired exception or one with an invalid schema prevents loading the contract. There is no external identity, remote approval, or self-approval.

### RF-12 — Passive instrumentation

Each relevant action must produce an append-only event with hashes, surface, checks, duration, and link to the contract.

### RF-13 — Same engine local and CI

The same rules and contracts must be reproducible outside the agent session.

### RNF-01 — Latency

- Level 0: p95 target under 200 ms warm and under 400 ms cold.
- Level 1 fast: p50 under 2 s and p95 under 8 s with cache.
- Final level: no single budget; must report progress and expected cost.

### RNF-02 — Security

Commands use timeouts, limited resources, and declared permissions. Code does not leave the environment by default.

### RNF-03 — Reproducibility

Each result records baseline, relevant hashes, rule version, and environment fingerprint.

`round-end` classifies each unmet check or criterion independently as `new-failure`, `pre-existing-baseline`, `infrastructure-unavailable`, `insufficient-evidence`, or `contradicted`. A global failure that matches the baseline is still visible but is not reported as introduced by the current round. Infrastructure inability is not equivalent to a failed assertion, and neither is equivalent to absent evidence.

The cumulative objective view reports each acceptance criterion as `proven`, `partial`, `without-evidence`, or `contradicted`, with evidence provenance. A future `oguard objective-status --json` exposes this view without treating file count, churn, or number of checks as progress. At closure, the same data produces an auditable requirement → changed entity → check or proof → result → commit matrix. External evidence may carry generic correlation IDs for run, task, dispatch, worker, commit, and completion events; tool-specific ingestion, including Orca, is deferred to adapters rather than embedded in the core contract.

Preflight authorization reports its creation time, validity duration, expiration time, and the exact invalidating action or state transition. A denial names the precise remedy. Scope remains declarative, but a legitimate cross-boundary correction can attach an explicit impact expansion with reason and evidence; this does not retroactively redefine the parent scope or suppress the fact that the boundary was crossed.

### RNF-04 — Scalability

Indices are updated per commit or changed file. An internal boundary with no public changes must not automatically invalidate the entire repository.
