Skip to content

Controlled real-fault observations

Controlled buggy/fixed pairs answer a narrow question: does the same selected assertion fail against one source revision and pass against the corrected revision under the declared execution conditions? COLEMAN can retain that evidence, including unexpected and inconclusive results, without presenting a reconstructed sequence as historical CI.

This source slice of #261 adds an offline typed observation adapter. It does not complete source admission, fault diversity, baseline comparisons or the cross-corpus benchmark. The registry's seven required diversity cells remain uncovered. Source assessments for RTPTorrent and LRTS remain separate.

The optional pinned JUnit3 producer now provides a reproducible public Java source recipe, with bounded execution and raw-role recovery.

The optional Python source capture uses the same domain contracts for a pinned upstream PySnooper pair. Its two declared locales preserve actual exception-to-pass and both-pass results, with separate component terms, typed provenance and real process-interruption recovery.

Architecture and trust boundary

flowchart LR
    producer[External subject execution] --> report[Pinned producer observation report]
    inputs[Reviewed source / fixture / harness inputs] --> cache[Existing external source cache]
    report --> cache
    context[Frozen controlled context] --> adapter[Offline typed conversion]
    cache --> adapter
    adapter --> pairs[Expected / unexpected / inconclusive pairs]
    adapter --> writer[Existing immutable artifact writer]
    writer --> manifest[Native run artifact manifest]

The core reads and verifies cached bytes. It never starts a subject process, container, compiler, CLI or network transport. A receipt proves byte correspondence, not that a producer executed those bytes. Runtime and command descriptions remain producer attestations. Review and execution of external subjects belong outside this adapter, with their own component terms and resource limits.

ControlledContext freezes project, curated fault label, language, fault origin, source revisions, fixture revision, dependence group, declared test IDs, input receipts and runtime conditions. Exactly one buggy source, fixed source, common test fixture and harness input is required. Dependency inputs are separate. Source versions must match the declared revisions. Input names and test IDs are unique; permuting those declarations preserves context identity. Opaque source archives can be cached as raw packages; this adds no TAR or ZIP64 extraction capability.

ControlledReport binds observations to the context fingerprint. Each observation has a trial ID, role, test ID, explicit outcome, capture instants, nullable diagnostic digest and monotonic elapsed counter. A non-null diagnostic digest must match a separate regular member of the validated report package; absent references reject. Diagnostics are not predecision features. Capture instants are collection clocks, not historical event or feature availability. No observed CI chronology is inferred.

Execution identity hashes the context and (trial_id, test_id, role), excluding outcomes and capture values. A retry of the same collection retains its trial ID; a genuinely new execution gets a new trial ID. Both remain in the same declared dependence group. These IDs do not establish independent bugs or projects.

Outcomes, units and missingness

Buggy observation Fixed observation Comparison
Assertion failed Passed Expected
Passed Passed Both pass
Assertion failed Assertion failed Both fail
Passed Assertion failed Reversed
Missing role, test error, skipped, timeout, cancellation, infrastructure error or unavailable Any Inconclusive

The same inconclusive rule applies when the fixed role has a non-assertion outcome. Only actual test/trial groups are compared. An empty report has no comparisons; missing observations are never fabricated. Unexpected and inconclusive results are valid evidence and remain in the dataset.

Elapsed values are strict nonnegative integer nanoseconds, at most 2**63-1, with meaning observed-test-harness-monotonic-elapsed-v1. Zero is observed. Null requires unavailable or not_applicable; an observed null or absent-state zero rejects. Negative, fractional, boolean, nonfinite and incompatible-unit values reject. Counter resolution establishes no physical measurement accuracy.

Elapsed harness time includes whatever that harness times. It is not independently removable runner work, shared setup cost, queue delay or developer-visible CI latency. It must not be substituted for native scheduling costs. This contract does not claim that all negative numbers are invalid in other result families; negative signed measurements remain governed by their existing contracts.

Installed package workflow

Build and install the working branch's wheel in a separate environment. The released 4.5 wheel predates this adapter. From the checkout:

wheel_dir=$(mktemp -d /tmp/coleman-controlled-wheel.XXXXXX)
uv build --wheel --out-dir "$wheel_dir"
uv venv /tmp/coleman-controlled-installed --python 3.14
uv pip install --python /tmp/coleman-controlled-installed/bin/python "$wheel_dir"/*.whl
mkdir -p /tmp/coleman-controlled-workspace
cp examples/controlled_faults/ci.py /tmp/coleman-controlled-workspace/ci.py
cd /tmp/coleman-controlled-workspace
/tmp/coleman-controlled-installed/bin/python ci.py owned-ci /tmp/coleman-controlled-source-cache

The example's pairs are newly authored synthetic schema fixtures, not external real faults or measured executions. Their constructed capture instants and unavailable elapsed counters are explicit. A separate complete owned serial CI fixture runs real native Random/RNFail with budget 7 seconds, independently checked NAPFD/APFDc and a second call through the learning checkpoint. No counter from the controlled observations is projected into that serial fixture's costs.

Re-running the command preserves the controlled artifact and committed native result. The output includes the frozen spec, converted dataset, classifications (expected, inconclusive), native directory and explicit insufficient-evidence status. This demonstrates integration and recovery, not external effectiveness.

The following complete SDK example reopens that specification offline. It runs from the same external workspace and requires no CLI or MCP imports:

from pathlib import Path

from coleman.artifacts import ArtifactWriter
from coleman.corpus import SourceCache
from coleman.corpus.controlled import convert_controlled_source, publish_controlled_dataset
from coleman.corpus.controlled_contracts import ControlledSpec

cache = SourceCache("/tmp/coleman-controlled-source-cache")
spec = ControlledSpec.from_json(Path("owned-ci/controlled-spec.json").read_bytes())
dataset = convert_controlled_source(spec, cache)
assert [pair.classification for pair in dataset.pairs] == ["expected", "inconclusive"]
path = publish_controlled_dataset(dataset, cache, ArtifactWriter("offline-assessment"))
assert dataset.admission == "not_evaluated"
assert dataset.history == "constructed"
print(path)

For another cache location, replace the SDK path with the same location supplied to ci.py. Input/report materializations use the existing reviewed-license, source-digest, bounded-byte and offline validation contracts. Reports have an 8-MiB ceiling and at most 20,000 physical observations; contexts permit at most 10,000 test IDs and 64 input packages. Every report is checked against the bytes actually parsed, including EOF size/digest, after cache validation.

Compatibility, duplication and publication

All new interchange models require integer schema_version: 1, reject unknown fields, and reject missing, legacy and future versions. Existing native results, source manifests, checkpoints and historical artifacts keep their existing meaning. No migration or automatic reinterpretation occurs. A future converter must declare any migration separately and preserve original bytes.

Conversion conserves physical rows: input_rows = observations + duplicates_excluded. Identical role/test/trial repeats are counted and excluded; conflicting repetitions reject. Output observations are sorted by logical key. Permuting physical report rows preserves normalized observations but changes the pinned source report bytes and therefore the complete artifact fingerprint. This is deliberate provenance, not an input-order-dependent policy comparison.

Publication re-converts the actual cache before writing one corpus-controlled/<fingerprint>.json artifact. Identical concurrent publication is idempotent through the existing immutable writer. Partial work is never a completed experiment or learning checkpoint. A failed publication can be retried; recipe-only content must remain local. Artifact metadata alone does not establish source integrity, execution truth, scientific admission or independence.

Primary-source investigation and fresh local evidence

The Defects4J paper and pinned documentation describe isolated buggy/fixed subjects, including reconstructed revisions. The current documentation requires Java 11 and America/Los_Angeles; its current corpus differs from the paper's original snapshot. Framework MIT terms do not license every subject or dependency. Broad initialization downloads unrelated repositories and tools; it was not used for the bounded case below.

The BugsInPy paper describes selected real source revisions and common exposing tests, with manual isolation review. A later independent reproduction study demonstrates why declared metadata is insufficient: dependency installation and runtime selection can prevent paired reproduction, and both-pass/both-fail outcomes must remain visible. Its corpus snapshot and results are that study's observations, not COLEMAN measurements.

At BugsInPy revision 11c5f1eea954a42132cfd06bf257766a7963e0fd, no verified framework license was found. The existing upstream license question remains unresolved. The paper's license and a subject's license do not clear that framework. No BugsInPy framework code or data is admitted by this increment.

Two direct upstream selected-test pairs were freshly executed on 2026-10-16:

Subject Buggy revision Fixed / common test revision Observed result
Apache Commons CLI, CLI-13 8f46f467a33ace44ccd9f394910940b6c48a3827 b0e1b80b6d4a10a9c9f46539bc4c7a3cce55886e One assertion failure / one pass; zero errors or skips
Black, process-pool fallback 26c9465a22c732ab1e17b0dec578fa3432e9b558 c0a7582e3d4cc8bec3b7f5a6c52b36880dcb57d7 One assertion failure / one pass; zero errors or skips

Commons CLI used the official Apache fixed commit, Git-verified source blobs and its Apache-2.0 LICENSE/NOTICE, common fixed-revision BugCLI13Test.testCLI13, Commons Lang 2.1 and JUnit 3.8.1 (Maven Central bytes and checksums). It compiled directly with Java 11.0.32.1, linux/arm64 Temurin manifest sha256:e4b3ff0f1a427efb2deb02b092ff8316d58573480260720d767d6ecdd69999d8. This was a direct source-pair experiment, not the complete Defects4J reconstruction or a full original-suite reproduction. JUnit's component terms are CPL-1.0; Commons Lang retains its own Apache terms.

Black used the official upstream fallback fix, MIT source notices, CPython 3.8.3 and 16 pinned offline wheels. The common fixed-revision BlackTestCase.test_works_in_mono_process_only_environment explicitly injects ProcessPoolExecutor initialization OSError. Both roles use the same declared derived SCM version label controlled-upstream-source-v1. The linux/amd64 image manifest sha256:13af390c7ababf48b675e151c354de224f2ae6ec17ee08fe04ad3df8d0736501 was emulated on an arm64 host. Its elapsed counters are not native performance measurements. This direct upstream experiment does not resolve BugsInPy licensing.

Both used read-only subject/fixture/harness mounts, execution without network, non-root UID, bounded memory/CPU/processes and per-case timeout. All source/dependency bytes and raw observations remain outside Git. No third-party test code or rows are bundled. These are two selected functional reproductions, not a randomized sample, full corpus admission, fault-localization matrix, historical CI evidence or an algorithm comparison. The typed reader does not independently certify this external execution. A distributable pinned producer recipe, component-by-component admission dossier and broader fresh test/fault matrix remain necessary before claiming that the Java/non-Java diversity criteria are satisfied.

Constructed C source observations

The optional Juliet C producer uses these same generic contracts and existing source cache/artifacts. It collects a deliberately bounded synthetic function pair with an independent arithmetic oracle, retaining process errors, negative outcomes and incomplete recovery. Compiler/runtime acquisition and execution remain in optional transports; no C, Docker, CLI or MCP import is introduced into this domain. Its elapsed ns never become native CI Duration.