lunartrace.science.study
STUDY plane: run a MethodContract against SOURCE_FROZEN inputs and emit a receipt.
The DIRECT plane is lunartrace.science.slope_quality.evaluate over in-memory
inputs. The STUDY plane adds custody: inputs are resolved from a SourceWitness manifest
into the content-addressed store by sha256, each byte stream is re-verified before use,
and the run writes a deterministic canonical result plus a non-deterministic
ExecutionReceipt describing how the result was produced.
Authority: the method is defined by the lunartrace.slope_quality/v1 MethodContract; this
module only executes it and records custody. Its output is a computation record. Emitting
a receipt or a projection does not by itself grant any scientific standing; the standing
label is supplied by the caller (see build_projection) and is validated, not
assigned, here. Sample validity and the missing-is-never-zero rule belong to
lunartrace.science.slope_quality, which this module calls.
Spec: docs/r2/SCIENCE-API-DECISION.md. Usage:
python -I -m lunartrace.science.study run \ --manifest research/sources/pgda78-site01.manifest.json \ --store <store>/lt-source-store --out <dir>FrozenInput
Section titled “FrozenInput”class
FrozenInputOne SOURCE_FROZEN input resolved from the content-addressed store.
Attributes
Section titled “Attributes”| Name | Type | Description |
|---|---|---|
role | str | Role name from the manifest entry (for example "slope" or "roi_shp"). |
name | str | Original file name recorded in the manifest. |
sha256 | str | Hex SHA-256 digest that the blob was verified against. |
path | pathlib.Path | Location of the verified blob inside the store (store / cas). |
load_manifest
Section titled “load_manifest”function
def load_manifest(path: Path) -> dict[str, object]Read and check a lunartrace.source_witness/v0 manifest.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
path | pathlib.Path | Manifest JSON file, decoded as UTF-8. |
Returns
Section titled “Returns”dict[str, object]— The parsed manifest object, unmodified.
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— If the file is not a JSON object with schemalunartrace.source_witness/v0, or if itsstatusis notSOURCE_FROZEN.
Only the schema and status are checked here. Blob integrity is checked later by
resolve_inputs.
resolve_inputs
Section titled “resolve_inputs”function
def resolve_inputs(manifest: Mapping[str, object], store: Path) -> dict[str, FrozenInput]Map manifest roles to verified content-addressed blobs.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
manifest | Mapping[str, object] | A checked manifest as returned by load_manifest. Its entries list is read. |
store | pathlib.Path | Root of the content-addressed store; each entry’s cas path is taken relative to it. |
Returns
Section titled “Returns”dict[str, FrozenInput]— One entry per role, keyed by role name.
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— Ifentriesis not a list; if a dict entry lacks a stringrole,cas,sha256orname; if a blob is missing; if a blob’s SHA-256 differs from the manifest; or if the rolesslope,slope_rms,roi_shp,roi_shx,roi_dbforroi_prjare not all present.
Entries that are not JSON objects are skipped silently. Every blob is re-hashed in full before use, so a result built from this mapping cannot silently use altered bytes.
run_study
Section titled “run_study”function
def run_study( manifest_path: Path, store: Path, out_dir: Path, taus: Sequence[float] = sq.DEFAULT_TAUS, repo: Path | None = None,) -> dict[str, object]Execute lunartrace.slope_quality/v1 from the CAS and write its outputs.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
manifest_path | pathlib.Path | A SOURCE_FROZEN source-witness manifest. |
store | pathlib.Path | Content-addressed store holding the manifest’s blobs. |
out_dir | pathlib.Path | Output directory, created if missing. Existing files with the same names are overwritten. |
taus | Sequence[float] | RMS thresholds, in degrees, passed to the method. Defaults to lunartrace.science.slope_quality.DEFAULT_TAUS. Default sq.DEFAULT_TAUS. |
repo | pathlib.Path or None | Repository root used for the source and environment records. If None, it is inferred from this file’s location. The records use the root only if it is this package’s own checkout; otherwise source.commit, source.dirty and environment.uv_lock_sha256 are recorded as None (UNKNOWN). Default None. |
Returns
Section titled “Returns”dict[str, object]— The receipt written toreceipt.json.
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— Propagated from manifest checks, blob verification or the method’s own input checks.
Two files are written to out_dir. result.json is canonical JSON: the same
inputs and taus give the same bytes. receipt.json is not deterministic; it holds
timestamps, git state and environment versions. The receipt status is
METHOD_EXECUTED, which is an execution record and is not a scientific standing.
Inputs are read only from the local store and the network is not used.
projection_provenance
Section titled “projection_provenance”function
def projection_provenance(manifest: Mapping[str, object]) -> tuple[str, str]Return the citation and CRS that every cross-client projection carries.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
manifest | Mapping[str, object] | A checked source-witness manifest. |
Returns
Section titled “Returns”tuple[str, str]—(citation, crs_proj4). The citation is the firstcitationsentry formatted as"<text> doi:<doi>". The CRS is the manifest’snative_semantics.crswith any text from the first" ("onward removed; it is passed through as a string and not parsed here.
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— If there is no first citation dict, or no string native CRS.
check_reproduces
Section titled “check_reproduces”function
def check_reproduces(result_sha256: str, witness: object, reference: Path) -> NoneCheck that a result hash reproduces a committed slope_quality/v0 projection.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
result_sha256 | str | Hex SHA-256 of the canonical result bytes being labelled. |
witness | object | The id of the manifest the result came from. |
reference | pathlib.Path | A committed lunartrace.projection.slope_quality/v0 document. |
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— If the reference names another witness, has noresult_sha256, or records a different hash.
This is the comparison that earns NUMERIC_REPRODUCED. It is not a scientific
admission.
build_projection
Section titled “build_projection”function
def build_projection( result_path: Path, manifest_path: Path, standing: str, reproduces: Path | None = None,) -> dict[str, object]Wrap canonical result bytes in the typed cross-client projection.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
result_path | pathlib.Path | A result.json written by run_study. Its bytes must already be canonical. |
manifest_path | pathlib.Path | The source-witness manifest the result came from. Its citation, CRS and id are copied into the projection. |
standing | str | Standing label recorded on the projection. It is validated by the projection model (lunartrace.projection.Standing). "NUMERIC_REPRODUCED" is recorded only when the result reproduces reproduces, and "SCIENCE_VERTICAL_QUALIFIED" is refused. |
reproduces | pathlib.Path or None | A committed slope_quality/v0 projection whose result_sha256 the result must match. Required for "NUMERIC_REPRODUCED". See check_reproduces. Default None. |
Returns
Section titled “Returns”dict[str, object]— The projection as JSON-compatible data, using the model’s aliased field names.
Raises
Section titled “Raises”lunartrace.science.slope_quality.MethodInputError— If the result bytes are not canonical JSON, the manifest lacks a citation or native CRS, or the requested standing is not earned by a matching reference.pydantic.ValidationError— If the projection model rejects the assembled document, for example an unknown standing label.
The result’s SHA-256 is computed over the exact bytes read from result_path.
function
def main(argv: Sequence[str] | None = None) -> intCommand-line entry point with the run and project subcommands.
Parameters
Section titled “Parameters”| Name | Type | Description |
|---|---|---|
argv | Sequence[str] or None | Arguments without the program name. If None, sys.argv is used. Default None. |
Returns
Section titled “Returns”int—0on success. Errors are not converted to exit codes here; they propagate.
run takes --manifest, --store, --out and optional repeated --tau.
project takes --result, --manifest, --standing, --out and
--reproduces, which NUMERIC_REPRODUCED requires.
Method and input errors propagate as exceptions; argparse exits on usage errors.