PtcRunner.Kernel.RunCatalogProbe (PtcRunner v0.15.0)

Copy Markdown View Source

Bounded non-payload probes behind one private run-catalog generation.

A probe answers what a sealed artifact pair already states about itself without opening either payload:

  • a canonical trace contributes its first line (guaranteed run-started) and the last complete line inside a bounded tail window (run-stopped for a complete run);
  • a .ptcins artifact contributes its 16-byte header and 192-byte footer, read with two pread/3 calls. No evidence frame is decoded.

Every read is bounded before it is issued: the two directory listings are capped, the union of run stems is capped, and each file contributes at most a head window, a tail window, and the container's fixed edges. Nothing here classifies — PtcRunner.Kernel.RunCatalog owns the row vocabulary and the failure matrix, so this module reports only what it observed and stays a pure function of the filesystem.

A probe reports only bytes it can prove belong to the entry it inventoried. Each file is lstated before the open, the opened descriptor is fstated and compared before a byte is read, and the path is lstated again after — so neither a file replaced under its path nor one rewritten mid-probe is described as the file that was listed. Either reports :unstable.

What survives is validated rather than trusted: the two probed trace events go through the same canonical trace-event validation a directory capture applies, and a sealed container whose versions are this build's is validated against the same header and footer contract its reader enforces.

Summary

Types

A half whose bytes were read but did not decode into a describable state.

Types

inspection_probe()

@type inspection_probe() ::
  %{present: :absent | :unstable}
  | malformed_probe()
  | %{
      present: :versions,
      bytes: non_neg_integer(),
      identity: stat_identity(),
      commitment: binary(),
      format_version: pos_integer(),
      schema_version: pos_integer()
    }
  | %{
      present: :probed,
      format_version: pos_integer(),
      schema_version: pos_integer(),
      bytes: non_neg_integer(),
      identity: stat_identity(),
      commitment: binary(),
      record_count: non_neg_integer(),
      run_id_sha256: binary(),
      trace_id_sha256: binary(),
      artifact_digest: binary()
    }

malformed_probe()

@type malformed_probe() :: %{
  :present => :malformed,
  optional(:identity) => stat_identity(),
  optional(:commitment) => binary()
}

A half whose bytes were read but did not decode into a describable state.

It still carries what it observed — the descriptor identity and a digest of the exact bytes probed — because a generation must distinguish one malformed file from another. Only a half that never reached any bytes carries neither.

probe()

@type probe() :: %{
  run_ref: binary(),
  trace: trace_probe(),
  inspection: inspection_probe()
}

stat_identity()

@type stat_identity() ::
  {non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer(),
   term()}

trace_probe()

@type trace_probe() ::
  %{present: :absent | :ambiguous | :unstable}
  | malformed_probe()
  | %{
      present: :probed,
      source_kind: :sanitized | :private,
      bytes: non_neg_integer(),
      identity: stat_identity(),
      commitment: binary(),
      head: map(),
      tail: map() | nil
    }

Functions

default_directory_entries()

@spec default_directory_entries() :: pos_integer()

default_files()

@spec default_files() :: pos_integer()

head_bytes()

@spec head_bytes() :: pos_integer()

probe_all(traces_directory, inspection_directory, opts \\ [])

@spec probe_all(binary(), binary(), keyword()) ::
  {:ok, %{probes: [probe()], excluded_files: non_neg_integer()}}
  | {:error, atom()}

Probes every canonical run stem under one trace and inspection root pair.

Returns the probes in stem order together with the number of listed files that carry no canonical stem, which the catalog reports as excluded_files rather than as rows. Fails whole-operation with :source_unavailable for an unusable root and :catalog_limit_exceeded for a listing or stem count beyond its bound. :listing_hook and :file_probe_hook exist only for tests that need deterministic synchronization around filesystem operations.

tail_bytes()

@spec tail_bytes() :: pos_integer()