Skip to content

Problem contracts ​

metewand-core parses each version-1 problem contract into a strict typed envelope and validates its family-owned semantics with repository schemas. The caller supplies the contract text, its logical repository path, and a complete offline SchemaCatalog; parsing and validation perform no filesystem or network access.

The manifest's contract field accepts either a repository-relative YAML file path or the complete versioned contract mapping:

yaml
problems:
  sum:
    contract:
      version: 1
      name: sum
      family: arithmetic
      parameter-schema: { type: object, additionalProperties: false }
      dataset-schemas: []
      result-schema:
        type: object
        properties: { answer: { type: integer } }
        required: [answer]
        additionalProperties: false
      metric-schema:
        type: object
        properties: { absolute_error: { type: integer, minimum: 0 } }
        required: [absolute_error]
        additionalProperties: false
      semantics-schema: schemas/sum-semantics.json
      allowed-timing-scopes: [prepare_and_execute]
      supported-budgets: [none]
      semantics:
        preprocessing: { allowed_outside_timed_scope: [] }
        validity: { finite_integer: true }
        one_shot_completion: { absolute_error: 0 }
      reference-cases:
        - result: reference/result.json
          expected-metrics: reference/metrics.json
    evaluator:
      runner: python
      entrypoint: evaluate.py
      sources: [evaluate.py]
      environment: local

Every schema field can mix inline schemas and reusable JSON files, including semantics-schema. Contract version, scientific semantics, reference cases, and validation rules are identical in both forms. File paths in the envelope remain relative to the repository root. Relative $ref values inside an inline schema use the owning document's directory. Separate semantics schemas remain required.

rust
use std::path::{Path, PathBuf};

use metewand_core::{
    problem_contract::parse_problem_contract,
    schema::SchemaCatalog,
};
use serde_json::Value;

fn load_contract(
    source: &str,
    schema_documents: Vec<(PathBuf, Value)>,
) -> Result<(), Box<dyn std::error::Error>> {
    let schemas = SchemaCatalog::try_new(schema_documents)?;
    let contract = parse_problem_contract(
        Path::new("problems/example.yaml"),
        source,
        &schemas,
    )?;
    assert_eq!(contract.version, 1);
    Ok(())
}
# let _ = load_contract;

Validation boundary ​

The common envelope requires parameter, accepted-dataset, result, metric, and semantics schemas; a nonempty, duplicate-free set of timing scopes; the Gate 1 none budget; and at least one reference case. Every referenced schema must be present in the supplied catalog. Dataset-backed reference cases require a dataset path, while dataset-free cases must omit it.

The semantics mapping is otherwise family-owned, but it always separates two operational concerns:

  • validity defines whether a schema-valid result is semantically usable; and
  • one_shot_completion defines whether a valid final result completes a one-shot attempt.

Both rule mappings must be present and nonempty. Their exact fields, along with all other family-specific semantics, are validated against semantics-schema. This separation lets later profile observations remain valid without implying that a one-shot completion threshold has been reached.

The family semantics also define preprocessing and any preparation allowed outside the timed scope. These rules distinguish shared scientific dataset construction from implementation-specific conversion and form part of the contract identity. The execution policy must select an allowed timing scope; contract permission alone does not exclude work from that policy's timer. See materialization and implementation preparation for the boundary, a concrete contract, and executable conformance cases.

An evaluator is not embedded in the language-neutral contract. The owning problem definition in metewand.yaml must declare its evaluator worker, including its environment and, for interpreted workers, its complete source bundle. The manifest parser rejects problem definitions without an evaluator.

Typed-envelope failures retain the decoder's source span. Missing schemas name their role and repository path, while family-schema failures retain every JSON Schema violation in deterministic order.

Repository loaders may use the same validation in two explicit phases. parse_problem_contract_document parses the strict typed envelope so the loader can discover its schema paths; validate_problem_contract checks that parsed document after the complete offline catalog has been compiled. parse_problem_contract remains the convenient combined operation. A document returned by the parsing-only phase is not valid for planning until the second phase succeeds.

Executable reference suites ​

The SDK conformance suites include complete sum and argmin contracts with reference datasets, results, and expected metrics. Both Python and R implementations run against both evaluators through the Rust transport and scientific-schema validator. Correct implementations reach completion; malformed, numerically wrong, and semantically invalid variants fail their respective checks. The semantic cases include a later tied minimum with zero numerical error, so matching the objective value alone cannot pass conformance.

Released under the MIT or Apache-2.0 license.