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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Parameterized or manual acceptance runs are issue-scoped; they are not the defau
- **Resolve acceptance criteria** — preserve user-supplied criteria; when absent, use [performance-ceiling-analysis](src/inferrsi/knowledge/data/skill_library/methods/performance-ceiling-analysis/references/acceptance-criteria.md) to derive evidence-backed campaign targets. Retain partial requirements and derive only missing fields; unresolved evidence stays explicit.
- **Freeze gates before search** — checklist and `validator/` locked in `plan/` before Phase 3 candidate experiments ([validation levels](docs/contributing.md#validation-levels)).
- **One plane per campaign step** — change only the declared SIAS plane per step: `harness` | `model` | `infra` (under `src/inferrsi/`).
- **Emit RunSpec snapshots** — record repo × revision × backend × device × model × scenario (`runspec.py`, campaign `plan/`).
- **Emit RunSpec snapshots** — record repo × revision × backend × device × model × scenario (`contracts/runspec.py`, campaign `plan/`).
- **Evaluator + evidence win** — never treat agent narrative as `PASS`; verdicts follow frozen gates and `evidence/<campaign-id>/` artifacts.

## Issues and claims (PM)
Expand All @@ -81,7 +81,7 @@ Parameterized or manual acceptance runs are issue-scoped; they are not the defau

## Evidence and clearing the bar

Verdicts are **`PASS`**, **`FAIL`**, or **`INCONCLUSIVE`** only (`src/inferrsi/claim.py`).
Verdicts are **`PASS`**, **`FAIL`**, or **`INCONCLUSIVE`** only (`src/inferrsi/contracts/claim.py`).

A public **`PASS`** requires:

Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@

### Changed

- Shared technical contracts now live in `inferrsi.contracts` (Refs #451). The four
root files `_json_v1.py`, `runspec.py`, `claim.py`, and `contracts.py` are removed
in the same change. Canonical implementations are `contracts/json_v1.py`,
`contracts/runspec.py`, and `contracts/claim.py`; `contracts/__init__.py`
re-exports only `RunSpec` from its single definition. Public
`from inferrsi.contracts import RunSpec` remains supported, and Harness
re-exports the same `inferrsi.contracts.claim.Verdict` object.
- The old `inferrsi._json_v1`, `inferrsi.runspec`, and `inferrsi.claim` imports
and pickle module paths are retired, with no forwarding shells or
`sys.modules` aliases. Historical pickles require explicit migration or the
prior release; new pickles name the canonical implementation modules.
- Canonical JSON bytes, error stages, RunSpec serialization/validation, and
Verdict values are unchanged. Frozen evidence is not rewritten.
- `tests/test_package_root_inventory.py` locks the exact current 23-file root
inventory and rejects unexpected additions; each later removal must shrink
that set in its own PR, rather than requiring the final two-file root now.
- The `inferrsi.observability` package is dissolved into its owning packages. No forwarding
modules remain, so imports must use the new paths:
- `campaign_records`, `campaign_trace`, `optimization_log`, `optimization_trace`,
Expand Down
5 changes: 3 additions & 2 deletions docs/contracts/current-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ Historical candidate text, review dispositions, and the earlier Proposed drafts

## D001 — One distribution, three cores plus Apps, document contracts rather than shared business DTOs

Decision: keep Knowledge, Harness, and Benchmark as sibling independent cores; Apps is the only assembler. Each core owns its types. Cross-boundary traffic uses versioned JSON envelopes with explicit conversion; there is no shared business `contracts` package. `contracts.py` remains a single-file `RunSpec` re-export. The legacy `claim.py` enum stays for compatibility but is not a new shared business model.
Decision: keep Knowledge, Harness, and Benchmark as sibling independent cores; Apps is the only assembler. Each core owns its types. Cross-boundary traffic uses versioned JSON envelopes with explicit conversion; there is no shared business `contracts` package. The technical-only `inferrsi.contracts` package re-exports only `RunSpec`, defined once in `contracts/runspec.py`; `contracts/claim.py` owns the same Verdict enum re-exported by Harness. These are not shared business DTOs. The old root `contracts.py`, `runspec.py`, `claim.py`, and `_json_v1.py` files are retired without forwarding shells.

Permitted shared technical leaves are only:

- `inferrsi._json_v1` — the canonical encoder (D002);
- `inferrsi.contracts.json_v1` — the canonical encoder (D002);
- `inferrsi.contracts.runspec` and `inferrsi.contracts.claim` — the existing RunSpec and Verdict technical types, with only RunSpec re-exported by the package initializer;
- `inferrsi._repo_pack_data` — the neutral raw pack-data reader and the existing static data enumeration (D020).

The neutral leaf carries no target selection, task, scoring, scheduling, or public business DTO, and imports none of K/H/B/Apps.
Expand Down
11 changes: 7 additions & 4 deletions docs/module-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ commands, including ordinary optimization, still load no Benchmark module.

The four target modules are peers: `knowledge`, `harness`, `benchmark`, and
`apps`. Knowledge, Harness, and Benchmark do not import one another. Apps is
the only assembler. `src/inferrsi/contracts.py` stays a `RunSpec`
re-export. It must not become a shared business-contracts package.
the only assembler. `src/inferrsi/contracts/__init__.py` re-exports only
`RunSpec`, defined once in `contracts/runspec.py`. The technical-only package
also owns `json_v1.py` and `claim.py`; it contains no shared business DTOs
and performs no core or host initialization.

The current `src/inferrsi/harness/` tree is a mixed implementation. Its
presence is not the target Harness boundary and is not evidence that the four
Expand Down Expand Up @@ -236,8 +238,9 @@ The leaf's own import rule and `REPO_TYPES` object identity govern it.
annotations`, anywhere in the file. It defines only `REPO_TYPES` and
`repository_pack`. Any `inferrsi.*` import or dynamic import in it fails.
- **Closures.** A Knowledge module reaches nothing outside Knowledge except
the data leaf and `inferrsi._json_v1`, the canonical encoder in the P0a
design. Benchmark modules and every `inferrsi.harness.*` module reach no
the data leaf and `inferrsi.contracts.json_v1`, the canonical encoder in the P0a
design. The gate admits its exact RunSpec-only parent initialization closure,
not arbitrary `contracts.*` modules. Benchmark modules and every `inferrsi.harness.*` module reach no
other core, no Apps module, and no old root leaf. Apps reaches no old root
leaf. `inferrsi.infra`
reaches no Knowledge, Harness, Benchmark, or Apps module, so `infra` → root
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pathlib import Path
from typing import Protocol

from inferrsi._json_v1 import decode, encode
from inferrsi.contracts.json_v1 import decode, encode
from inferrsi.harness.errors import PublicError
from inferrsi.harness.execution_spec import request_digest

Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from typing import BinaryIO
from uuid import uuid4

from inferrsi._json_v1 import decode, encode
from inferrsi.contracts.json_v1 import decode, encode
from inferrsi.harness.errors import PublicError

from .result import publication_error, validate_artifact_ref, validate_result
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/artifact_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from io import BytesIO

from inferrsi._json_v1 import encode
from inferrsi.contracts.json_v1 import encode
from inferrsi.harness.errors import PublicError

from .archive import _logical_path, _read_directory_artifact, _storage_mounts
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from copy import deepcopy
from hashlib import sha256

from inferrsi._json_v1 import decode, encode
from inferrsi.contracts.json_v1 import decode, encode
from inferrsi.harness.errors import PublicError

from .archive import _logical_path
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/context_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclasses import dataclass
from hashlib import sha256

from inferrsi._json_v1 import MAX_SAFE_INTEGER
from inferrsi.contracts.json_v1 import MAX_SAFE_INTEGER
from inferrsi.knowledge.knowledge_operations import KnowledgeReader

_REQUEST_FIELDS = {"query", "ids", "pins", "selection_limits", "max_bytes", "round_id"}
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/legacy/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from inferrsi.benchmark.legacy_run_v0 import RunRules, _summary, read_metric
from inferrsi.benchmark.legacy_run_v0 import evaluate as _evaluate
from inferrsi.runspec import RunSpec
from inferrsi.contracts import RunSpec

__all__ = ["evaluate", "read_metric", "run_rules", "_summary"]

Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/legacy/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

from inferrsi.benchmark.legacy_run_v0 import evaluate as _evaluate
from inferrsi.benchmark.legacy_run_v0 import read_metric, trial_metric
from inferrsi.contracts import RunSpec
from inferrsi.harness.runner import run_experiment as _run_experiment
from inferrsi.harness.scenarios.external import execute_trial as _execute_trial
from inferrsi.infra.targets import repository_identity
from inferrsi.runspec import RunSpec

from .evaluation import run_rules
from .reporting import write_report
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dataclasses import fields
from hashlib import sha256

from inferrsi._json_v1 import encode
from inferrsi.contracts.json_v1 import encode
from inferrsi.harness.errors import PUBLIC_ERROR_CODES, PartialExecutionFacts

_EXIT_CODES = {
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/apps/views/attempt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from copy import deepcopy

from inferrsi._json_v1 import decode
from inferrsi.contracts.json_v1 import decode
from inferrsi.harness.errors import PublicError

from ..archive import read_assessment
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from . import __version__
from ._skill_selection import RELEVANCE_METHODS
from .catalog import BACKENDS, KNOWLEDGE_REPOS, KNOWLEDGE_SCOPES, REPO_TYPES
from .runspec import RunSpec
from .contracts import RunSpec


def _fixed_attempt_args(
Expand Down
5 changes: 0 additions & 5 deletions src/inferrsi/contracts.py

This file was deleted.

10 changes: 10 additions & 0 deletions src/inferrsi/contracts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Shared data and byte contracts: canonical JSON, RunSpec and claim types.

``RunSpec`` is the only name this initializer re-exports. Import the canonical
encoder from ``contracts.json_v1`` and the verdict types from ``contracts.claim``.
No module here imports a core, Apps, Infra or Model module, or does I/O on import.
"""

from .runspec import RunSpec

__all__ = ["RunSpec"]
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/inferrsi/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

from .apps.legacy.run import execute_trial as _execute
from .apps.legacy.run import run_experiment as _run_experiment
from .contracts import RunSpec
from .harness.local_process import _stop_tree, _WindowsJob
from .infra.targets import repository_identity
from .runspec import RunSpec

__all__ = ["run_experiment", "repository_identity", "_execute", "_WindowsJob", "_stop_tree"]

Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/harness/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Harness plane: scenario composition, AB/BA orchestration, verdicts and reports."""

from inferrsi.claim import Verdict, parse_verdict
from inferrsi.contracts.claim import Verdict, parse_verdict

__all__ = ["Verdict", "parse_verdict"]
8 changes: 4 additions & 4 deletions src/inferrsi/harness/execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from datetime import datetime, timezone
from pathlib import Path

from inferrsi import _json_v1
from inferrsi.contracts import json_v1
from inferrsi.harness import input_binding, local_process, run_store
from inferrsi.harness.errors import PublicError

Expand Down Expand Up @@ -125,7 +125,7 @@ def _is_ids(value: object) -> bool:


def _is_uint(value: object) -> bool:
return type(value) is int and 0 <= value <= _json_v1.MAX_SAFE_INTEGER
return type(value) is int and 0 <= value <= json_v1.MAX_SAFE_INTEGER


def _is_definition(value: object) -> bool:
Expand Down Expand Up @@ -328,8 +328,8 @@ def validate(spec: object, target: LocalCpuTarget) -> None:
errors += _input_errors(spec["inputs"])
errors += _step_errors(spec["steps"], ordinary=not evaluation)
try:
_json_v1.encode(spec)
except _json_v1.CanonicalError as exc:
json_v1.encode(spec)
except json_v1.CanonicalError as exc:
errors.append(f"spec: not canonical inferrsi-json-v1 ({exc.stage})")
if errors:
raise PublicError(
Expand Down
4 changes: 2 additions & 2 deletions src/inferrsi/harness/execution_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import hashlib
from collections.abc import Mapping

from inferrsi import _json_v1
from inferrsi.contracts import json_v1


def request_digest(spec: Mapping) -> str:
"""Return the D017 semantic identifier of a complete ExecutionSpec."""
return "sha256:" + hashlib.sha256(_json_v1.encode(spec)).hexdigest()
return "sha256:" + hashlib.sha256(json_v1.encode(spec)).hexdigest()
10 changes: 5 additions & 5 deletions src/inferrsi/harness/run_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from datetime import datetime, timezone
from pathlib import Path

from inferrsi import _json_v1
from inferrsi.contracts import json_v1
from inferrsi.harness.errors import PartialExecutionFacts, PublicError
from inferrsi.harness.execution_spec import request_digest as request_digest

Expand Down Expand Up @@ -575,8 +575,8 @@ def _load_record(
if digest != row["sha256"] or len(data) != row["size_bytes"]:
raise _IntegrityFault(f"record version {version} bytes do not match their index row")
try:
payload = _json_v1.decode(data)
except _json_v1.CanonicalError as exc:
payload = json_v1.decode(data)
except json_v1.CanonicalError as exc:
raise _IntegrityFault(f"record version {version} is not canonical: {exc.stage}") from exc
if (
not _has_fields(payload, PAYLOAD_FIELDS)
Expand Down Expand Up @@ -689,7 +689,7 @@ def committed(self, attempt_id: str, record_version: int | None = None) -> Commi
errors = [] if _is_id(attempt_id) else ["attempt_id: not an Id"]
if record_version is not None and (
type(record_version) is not int
or not 1 <= record_version <= _json_v1.MAX_SAFE_INTEGER
or not 1 <= record_version <= json_v1.MAX_SAFE_INTEGER
):
errors.append("record_version: must be null or a positive integer")
if errors:
Expand Down Expand Up @@ -1017,7 +1017,7 @@ def commit(
errors.extend(_payload_artifact_errors(payload, artifacts, self._store.namespace))
if errors:
raise ValueError(f"illegal record commit: {errors}")
data = _json_v1.encode(payload)
data = json_v1.encode(payload)
try:
for ref, source in artifacts:
self._store._retain(ref, source)
Expand Down
2 changes: 1 addition & 1 deletion src/inferrsi/harness/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime, timezone
from pathlib import Path

from ..runspec import RunSpec
from ..contracts import RunSpec
from .atomic_json import atomic_write_json as _write_json
from .scenarios.external import collect_trial_checks

Expand Down
Loading
Loading