3 Commits

Author SHA1 Message Date
4bd552f389 Certify alpha7 compatibility candidates 2026-07-18 15:10:59 -07:00
Ajay Krishnan
49604f18bd Merge pull request #1 from ajaynomics/feature/runtime-tuple-promotion
Some checks failed
Candidate compatibility / prepare (push) Successful in 7s
Candidate compatibility / repository (push) Successful in 8s
Candidate compatibility / image ${{ matrix.id }} (push) Failing after 9m39s
Candidate compatibility / fixture-contract (push) Successful in 9m41s
Add atomic runtime tuple promotion gate
2026-07-18 14:18:40 -07:00
a640f44972 Add atomic runtime tuple promotion gate 2026-07-18 14:14:41 -07:00
21 changed files with 1591 additions and 123 deletions

View File

@@ -20,7 +20,7 @@ jobs:
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.4"
- run: ruby test/repository_test.rb
- run: ruby test/repository_test.rb && ruby test/runtime_tuple_promoter_test.rb && ruby test/exact_live_contract_test.rb
prepare:
runs-on: ubuntu-latest

View File

@@ -18,6 +18,9 @@ prompts, credentials, sessions, or user data belong here.
neither workflow deploys or changes a consumer.
- Each consumer retains both `current` and `previous` certified tuples so a
rollback restores the gem and server together.
- A failing bootstrap baseline is never relabeled as a certified `previous`
tuple. Promotion stays blocked until a distinct rollback consumer commit is
pinned to a passing client/runtime tuple and canaried.
## What is covered
@@ -41,9 +44,11 @@ Prerequisites are Ruby 3.2+, Python 3, `jq`, and Docker.
```sh
ruby test/repository_test.rb
OPENCODE_RUBY_PATH=/data/projects/opencode-ruby-alpha6 \
ruby test/runtime_tuple_promoter_test.rb
ruby test/exact_live_contract_test.rb
OPENCODE_RUBY_PATH=/path/to/opencode-ruby-at-78b6f9c9e9c7d58b699af1c3c17764acd33de798 \
ruby ruby/opencode_ruby_fixture_contract.rb
OPENCODE_RUBY_PATH=/data/projects/opencode-ruby-alpha6 \
OPENCODE_RUBY_PATH=/path/to/opencode-ruby-at-78b6f9c9e9c7d58b699af1c3c17764acd33de798 \
OPENCODE_IMAGE='ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a' \
scripts/run_image_contract.sh
```
@@ -51,7 +56,9 @@ OPENCODE_IMAGE='ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca
The live contract starts a deterministic local OpenAI-compatible model stub and
an isolated OpenCode container. It creates a session, subscribes, submits an
async prompt, observes terminal SSE, fetches the authoritative exchange, and
deletes the session. It never calls an external model provider.
deletes the session. Passing requires the authoritative final text to equal the
expected text byte-for-byte and the deterministic model stub to observe exactly
one request. It never calls an external model provider.
## Adding an upstream release

View File

@@ -18,6 +18,11 @@ The gate requires:
Health-only probes do not certify a tuple.
The shared live probe is intentionally strict: `full_text` must equal the
expected text byte-for-byte and the deterministic model must receive exactly
one request. A response that merely contains the expected text, including a
duplicated `compat-ok\n\ncompat-ok`, fails.
## Promotion
Promotion is a reviewed manifest change that moves the old `current` tuple to
@@ -25,6 +30,88 @@ Promotion is a reviewed manifest change that moves the old `current` tuple to
merged and deployed separately. Workflows in this repository have no deploy
credentials or deploy steps.
Use the repository promotion command; do not hand-edit the three tuple slots.
It binds evidence to a canonical SHA-256 of the complete tuple, requires full
consumer and gem commits, rejects mutable runtime image coordinates, and writes
the manifest with a same-filesystem atomic rename. The command only changes
`manifests/runtime-tuples.json`; it cannot deploy a consumer.
First inspect the fingerprints for both the candidate and rollback tuple:
```sh
ruby scripts/promote_runtime_tuple.rb fingerprint \
--consumer travelwolf \
--consumer-commit FULL_40_CHARACTER_CONSUMER_COMMIT
```
Commit one or more JSON evidence documents under `evidence/`. Each document
must explicitly contain values matching the promotion:
```json
{
"schema_version": 1,
"consumer": "travelwolf",
"profile": "rails-persisted-turn",
"consumer_commit": "FULL_40_CHARACTER_CONSUMER_COMMIT",
"status": "pass",
"certified_at": "2026-07-18T12:00:00Z",
"tuple_sha256": "sha256:FULL_64_CHARACTER_FINGERPRINT"
}
```
Preview the exact manifest transition with `--dry-run`, then repeat without it
to write the manifest:
```sh
ruby scripts/promote_runtime_tuple.rb promote \
--consumer travelwolf \
--consumer-commit FULL_40_CHARACTER_CONSUMER_COMMIT \
--status pass \
--certified-at 2026-07-18T12:00:00Z \
--evidence evidence/travelwolf-candidate.json \
--previous-status pass \
--previous-certified-at 2026-07-17T12:00:00Z \
--previous-evidence evidence/travelwolf-rollback.json \
--dry-run
```
The `--previous-*` arguments are required while the old `current` tuple lacks a
valid certification record. Later promotions reuse and revalidate that record.
Both candidate and previous evidence must match the printed tuple fingerprint,
consumer, full consumer commit, timestamp, and `pass` status. A tag may be kept
only in a `tag_provenance` field; `image`, `registry_ref`, and base image fields
must use `image@sha256:...`, while a private local artifact may use an exact
`docker_image_id`.
An application canary and the shared deterministic contract prove different
layers. For example, a consumer may instrument one application prompt without
being able to observe the underlying model request. Record that distinction
explicitly; do not infer a model request count from an application prompt
count. The exact-image shared contract supplies the model-request proof.
Likewise, the public image job executes `ruby-rest-sse`; it does not silently
certify Rails persistence, plugin hooks, voice streaming, strict route gates,
or provider hooks. Those appear as `required_consumer_profiles` in the image
matrix and need their own consumer evidence before a full tuple can pass.
The command clears `candidate` after promotion. It sets the repository-wide
`migration_state` to `certified` only after every consumer has certified
`current` and `previous` tuples and no pending candidate.
## Bootstrap with a failing baseline
If the observed production baseline fails the current contract, keep its full
coordinates for emergency recovery but mark it failed. Do not create passing
evidence for it and do not promote it into `previous`. The promoter rejects
known-failed baselines even if a document claims `pass`.
The safe bootstrap is two-stage: certify and roll out the new candidate, then
create and canary a distinct consumer rollback commit that preserves the same
known-good client and exact runtime. Only after both immutable consumer commits
have real passing evidence can the manifest honestly contain certified
`current` and `previous` tuples. Until then, `promotion_readiness` remains
blocked and the candidate PR must not be treated as a deploy authorization.
## Rollback
Rollback restores the whole `previous` tuple. Do not roll back only the gem or

View File

@@ -0,0 +1,16 @@
{
"schema_version": 1,
"consumer": "ajent-rails",
"profile": "rails-persisted-turn",
"consumer_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"status": "pass",
"certified_at": "2026-07-18T22:03:14Z",
"tuple_sha256": "sha256:2fc1026cf247b5ad5677bfa4673c1073f7c2478769dca0cc8443a0924cebfca3",
"shared_evidence": "evidence/2026-07-18-opencode-ruby-alpha7.json",
"canary": {
"checked_at": "2026-07-18T21:58:00Z",
"docker_image_id": "sha256:239e3dc6cd2958251cda636fb20bd7cd7c46f596bd4c61cb81863ebc49d824e8",
"persisted_final_text": "compat-ok",
"model_request_count": 1
}
}

View File

@@ -0,0 +1,17 @@
{
"schema_version": 1,
"consumer": "mushu",
"profile": "ruby-rest-sse",
"consumer_commit": "f26d958b64f214a422aeb629860c8c9a46a4c084",
"status": "pass",
"certified_at": "2026-07-18T22:03:14Z",
"tuple_sha256": "sha256:6171647c7db6d88d52882695c6106a4391e87d0bb1f9e0c48151b2bc1e95b318",
"shared_evidence": "evidence/2026-07-18-opencode-ruby-alpha7.json",
"canary": {
"run_id": "mushu-alpha7-20260718T215300Z-f26d958",
"checked_at": "2026-07-18T21:53:00Z",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"persisted_final_text": "compat-ok",
"model_request_count": 1
}
}

View File

@@ -0,0 +1,51 @@
{
"schema_version": 1,
"client": {
"repository": "ajaynomics/opencode-ruby",
"version": "0.0.1.alpha2",
"commit": "889d38332f98f5f7b76d16952b7204d8a5b9a662"
},
"rails_client": {
"repository": "ajaynomics/opencode-rails",
"version": "0.0.1.alpha2",
"commit": "9b0c4cd3cd31bdfebbb89567daca012d68a356ea"
},
"recorded_at": "2026-07-18T22:04:14Z",
"status": "fail",
"failure": {
"expected_text": "compat-ok",
"full_text": "compat-ok\n\ncompat-ok",
"llm_request_count": 1,
"reason": "The client concatenates the streamed and authoritative text, duplicating the final response."
},
"exact_image_contracts": [
{
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"server_version": "1.16.1",
"status": "fail"
},
{
"image": "ghcr.io/anomalyco/opencode@sha256:bf9d0e84b7cedef436a8f57db4d48767cd5d8fc6604f666335c1cc916b199a97",
"server_version": "1.17.18",
"status": "fail"
},
{
"image": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"server_version": "1.18.3",
"status": "fail"
},
{
"target": "ajent-production-artifact",
"docker_image_id": "sha256:6fb2b3bf8e4cdf48e16bf6c3475e953df2f8304e77f5efe816ceb46f905eead8",
"server_version": "1.18.3",
"status": "fail"
},
{
"target": "mushu-production-artifact",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"server_version": "0.0.0-permission-shortcuts-202606300721",
"status": "fail"
}
],
"promotion_effect": "The observed alpha2 consumer baselines are not eligible for certified previous tuples. A distinct, tested rollback consumer commit pinned to alpha7 is required before the two-certified-tuples policy can be satisfied."
}

View File

@@ -1,69 +0,0 @@
{
"schema_version": 1,
"candidate": {
"repository": "ajaynomics/opencode-ruby",
"version": "0.0.1.alpha6",
"commit": "a116b2708cc148f61b1e1fae0405553c099f4202",
"certified_payload_commit": "8adc95985a79b16e6e4bc0c0f827d638f244d509",
"payload_equivalence": "release differs only in .github/workflows/test.yml, which is outside the gem payload",
"transport_implementation_commit": "5113a953db8026697262bd4f97197a3d13077762"
},
"fixture_contract": {
"status": "pass",
"fixture_count": 7
},
"unit_contract": {
"status": "pass",
"runs": 24,
"assertions": 56
},
"image_contracts": [
{
"target": "travelwolf-1.16.1",
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"server_version": "1.16.1",
"checked_at": "2026-07-18T20:34:05Z",
"status": "pass"
},
{
"target": "opencode-ajent-1.17.18",
"image": "ghcr.io/anomalyco/opencode@sha256:bf9d0e84b7cedef436a8f57db4d48767cd5d8fc6604f666335c1cc916b199a97",
"server_version": "1.17.18",
"checked_at": "2026-07-18T20:34:08Z",
"status": "pass"
},
{
"target": "ajent-base-1.18.3",
"image": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"server_version": "1.18.3",
"checked_at": "2026-07-18T20:34:08Z",
"status": "pass"
},
{
"target": "ajent-blackline-live-artifact",
"image_id": "sha256:6fb2b3bf8e4cdf48e16bf6c3475e953df2f8304e77f5efe816ceb46f905eead8",
"registry_ref": "docker-registry:5000/opencode-blackline:83eed3c247a352842b08fc5cf339c4d0acdaacba",
"server_version": "1.18.3",
"checked_at": "2026-07-18T20:34:10Z",
"status": "pass"
},
{
"target": "mushu-permission-shortcuts-live-artifact",
"image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"registry_ref": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"source_commit": "99d6328b18ff8a340a928449a2aa8bc184a063f9",
"server_version": "0.0.0-permission-shortcuts-202606300721",
"checked_at": "2026-07-18T20:34:08Z",
"status": "pass"
}
],
"contract": [
"health",
"create-session",
"subscribe-ready-before-async-prompt",
"deterministic-model-request",
"sse-terminal",
"authoritative-final-exchange",
"delete-session"
]
}

View File

@@ -0,0 +1,123 @@
{
"schema_version": 1,
"candidate": {
"opencode_ruby": {
"repository": "ajaynomics/opencode-ruby",
"version": "0.0.1.alpha7",
"commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "abfce3ec8cb1ee468107d0845521769502251645",
"peeled_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798"
}
},
"opencode_rails": {
"repository": "ajaynomics/opencode-rails",
"version": "0.0.1.alpha7",
"commit": "2a391ccad1d098e4bb51eb19b6ca52adaa79e5cb",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "61e128084b2b665c0ba20b332987e41794948d7c",
"peeled_commit": "2a391ccad1d098e4bb51eb19b6ca52adaa79e5cb"
}
}
},
"fixture_contract": {
"status": "pass",
"fixture_count": 7
},
"opencode_ruby_unit_contract": {
"status": "pass",
"runs": 26,
"assertions": 63
},
"opencode_rails_unit_contract": {
"status": "pass",
"runs": 55,
"assertions": 145
},
"exact_image_contracts": [
{
"target": "travelwolf-1.16.1",
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"server_version": "1.16.1",
"checked_at": "2026-07-18T22:03:12Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1,
"status": "pass"
},
{
"target": "opencode-ajent-1.17.18",
"image": "ghcr.io/anomalyco/opencode@sha256:bf9d0e84b7cedef436a8f57db4d48767cd5d8fc6604f666335c1cc916b199a97",
"server_version": "1.17.18",
"checked_at": "2026-07-18T22:03:13Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1,
"status": "pass"
},
{
"target": "ajent-base-1.18.3",
"image": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"server_version": "1.18.3",
"checked_at": "2026-07-18T22:03:14Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1,
"status": "pass"
}
],
"consumer_canaries": [
{
"consumer": "ajent-rails",
"consumer_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"tag_provenance": "ajent-opencode-blackline-canary:96552893",
"docker_image_id": "sha256:239e3dc6cd2958251cda636fb20bd7cd7c46f596bd4c61cb81863ebc49d824e8",
"source_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"upstream_base": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"server_version": "1.18.3",
"checked_at": "2026-07-18T21:58:00Z",
"application_path": "Blackline::GenerateResponseJob",
"persisted_final_text": "compat-ok",
"model_request_count": 1,
"status": "pass"
},
{
"consumer": "mushu",
"consumer_commit": "f26d958b64f214a422aeb629860c8c9a46a4c084",
"run_id": "mushu-alpha7-20260718T215300Z-f26d958",
"tag_provenance": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"source_commit": "99d6328b18ff8a340a928449a2aa8bc184a063f9",
"server_version": "0.0.0-permission-shortcuts-202606300721",
"checked_at": "2026-07-18T21:53:00Z",
"persisted_final_text": "compat-ok",
"model_request_count": 1,
"status": "pass"
},
{
"consumer": "travelwolf",
"consumer_commit": "19747b59fa21e12560afd9edd73ed674ab3a644c",
"run_id": "20260718215135-8d8102c0",
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"server_version": "1.16.1",
"started_at": "2026-07-18T21:51:35Z",
"checked_at": "2026-07-18T21:51:56.552Z",
"final_text": "TRAVELWOLF_ALPHA7_SUBSCRIBE_READY",
"application_prompt_count": 1,
"model_request_count_observed": false,
"cleanup_status": "pass",
"status": "pass"
}
],
"contract": [
"health",
"create-session",
"subscribe-ready-before-async-prompt",
"exactly-one-deterministic-model-request",
"sse-terminal",
"exact-authoritative-final-exchange",
"delete-session"
]
}

View File

@@ -0,0 +1,18 @@
{
"schema_version": 1,
"consumer": "travelwolf",
"profile": "rails-persisted-turn",
"consumer_commit": "19747b59fa21e12560afd9edd73ed674ab3a644c",
"status": "pass",
"certified_at": "2026-07-18T22:03:14Z",
"tuple_sha256": "sha256:a7519e661f74d86788928540429c953edcbf20d26321c0dd2b72cd0a1b995b61",
"shared_evidence": "evidence/2026-07-18-opencode-ruby-alpha7.json",
"canary": {
"run_id": "20260718215135-8d8102c0",
"checked_at": "2026-07-18T21:51:56.552Z",
"final_text": "TRAVELWOLF_ALPHA7_SUBSCRIBE_READY",
"application_prompt_count": 1,
"model_request_count_observed": false,
"cleanup_status": "pass"
}
}

View File

@@ -0,0 +1,501 @@
# frozen_string_literal: true
require "digest"
require "json"
require "pathname"
require "tempfile"
require "time"
module OpenCodeCompat
class PromotionError < StandardError; end
class RuntimeTuplePromoter
FULL_COMMIT = /\A[0-9a-f]{40}\z/
DIGEST = /\Asha256:[0-9a-f]{64}\z/
IMMUTABLE_IMAGE = /\A[^@\s]+@sha256:[0-9a-f]{64}\z/
UTC_TIMESTAMP = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\z/
CERTIFICATION_STATUS = "pass"
NON_CERTIFIABLE_TUPLE_STATUSES = %w[observed-production-contract-failed].freeze
TUPLE_METADATA_KEYS = %w[
certification
certified_at
compatibility_certified_at
promoted_at
status
].freeze
EXACT_IMAGE_REFERENCE_KEYS = %w[
base_image
image
registry_ref
source_image
upstream_base
].freeze
def initialize(root:, manifest_path: File.join(root, "manifests/runtime-tuples.json"))
@root = File.realpath(root)
@manifest_path = File.expand_path(manifest_path)
end
def fingerprints(consumer:, consumer_commit:)
validate_full_commit!(consumer_commit, "consumer commit")
manifest = read_manifest
consumer_entry = fetch_consumer!(manifest, consumer)
profile = fetch_profile!(consumer_entry, consumer)
candidate = prepare_candidate!(consumer_entry, consumer_commit)
current = consumer_entry.fetch("current") do
raise PromotionError, "#{consumer} has no current tuple to preserve as previous"
end
validate_tuple!(current, "#{consumer} current")
{
"consumer" => consumer,
"profile" => profile,
"candidate_tuple_sha256" => tuple_fingerprint(candidate, consumer: consumer, profile: profile),
"current_tuple_sha256" => tuple_fingerprint(current, consumer: consumer, profile: profile)
}
end
def promote(consumer:, consumer_commit:, certification:, previous_certification: nil, dry_run: false)
validate_full_commit!(consumer_commit, "consumer commit")
if dry_run
manifest = read_manifest
return promote_manifest(
manifest,
consumer: consumer,
consumer_commit: consumer_commit,
certification: certification,
previous_certification: previous_certification
)
end
with_current_manifest_lock do |manifest|
promoted = promote_manifest(
manifest,
consumer: consumer,
consumer_commit: consumer_commit,
certification: certification,
previous_certification: previous_certification
)
atomic_write(promoted)
promoted
end
end
private
def read_manifest
parse_json(File.read(@manifest_path), @manifest_path)
rescue Errno::ENOENT
raise PromotionError, "runtime tuple manifest does not exist: #{@manifest_path}"
end
def promote_manifest(manifest, consumer:, consumer_commit:, certification:, previous_certification:)
consumer_entry = fetch_consumer!(manifest, consumer)
profile = fetch_profile!(consumer_entry, consumer)
candidate = prepare_candidate!(consumer_entry, consumer_commit)
current = consumer_entry.fetch("current") do
raise PromotionError, "#{consumer} has no current tuple to preserve as previous"
end
validate_tuple!(current, "#{consumer} current")
candidate_fingerprint = tuple_fingerprint(candidate, consumer: consumer, profile: profile)
current_fingerprint = tuple_fingerprint(current, consumer: consumer, profile: profile)
if candidate_fingerprint == current_fingerprint
raise PromotionError, "#{consumer} candidate is identical to its current tuple"
end
certified_candidate = certify_tuple!(
candidate,
consumer: consumer,
profile: profile,
supplied: certification,
expected_fingerprint: candidate_fingerprint,
label: "candidate"
)
certified_previous = certify_previous!(
current,
consumer: consumer,
profile: profile,
supplied: previous_certification,
expected_fingerprint: current_fingerprint
)
consumer_entry["previous"] = certified_previous
consumer_entry["current"] = certified_candidate
consumer_entry["candidate"] = nil
manifest["migration_state"] = all_consumers_certified?(manifest) ? "certified" : "candidate"
manifest
end
def fetch_consumer!(manifest, consumer)
unless manifest.is_a?(Hash) && manifest["schema_version"] == 1 && manifest["consumers"].is_a?(Hash)
raise PromotionError, "runtime tuple manifest must use schema_version 1 and contain consumers"
end
manifest.fetch("consumers").fetch(consumer) do
raise PromotionError, "unknown consumer #{consumer.inspect}"
end
end
def prepare_candidate!(consumer_entry, consumer_commit)
candidate = consumer_entry["candidate"]
unless candidate.is_a?(Hash)
raise PromotionError, "consumer has no candidate tuple to promote"
end
unless candidate["status"] == "compatibility-certified"
raise PromotionError, "candidate status must be compatibility-certified"
end
validate_timestamp!(candidate["certified_at"], "candidate compatibility certification timestamp")
if candidate.key?("consumer_commit") && candidate["consumer_commit"] != consumer_commit
raise PromotionError, "explicit consumer commit does not match the candidate"
end
prepared = deep_copy(candidate)
prepared["consumer_commit"] = consumer_commit
validate_tuple!(prepared, "candidate")
prepared
end
def fetch_profile!(consumer_entry, consumer)
profile = consumer_entry["profile"]
unless profile.is_a?(String) && profile.match?(/\A[a-z0-9][a-z0-9-]*\z/)
raise PromotionError, "#{consumer} must declare a valid compatibility profile"
end
profile_path = File.join(@root, "profiles", "#{profile}.json")
unless File.file?(profile_path)
raise PromotionError, "#{consumer} compatibility profile does not exist: profiles/#{profile}.json"
end
profile
end
def certify_previous!(tuple, consumer:, profile:, supplied:, expected_fingerprint:)
if NON_CERTIFIABLE_TUPLE_STATUSES.include?(tuple["status"])
raise PromotionError,
"current tuple is known to fail the compatibility contract and cannot become a certified rollback"
end
if tuple["status"] == "certified"
validate_recorded_certification!(
tuple,
consumer: consumer,
profile: profile,
expected_fingerprint: expected_fingerprint,
label: "current rollback"
)
return deep_copy(tuple)
end
unless supplied
raise PromotionError,
"current tuple is not certified; explicit previous certification evidence, timestamp, and status are required"
end
certify_tuple!(
tuple,
consumer: consumer,
profile: profile,
supplied: supplied,
expected_fingerprint: expected_fingerprint,
label: "previous"
)
end
def certify_tuple!(tuple, consumer:, profile:, supplied:, expected_fingerprint:, label:)
certification = validate_supplied_certification!(
supplied,
consumer: consumer,
profile: profile,
tuple: tuple,
expected_fingerprint: expected_fingerprint,
label: label
)
certified = deep_copy(tuple)
if certified.key?("certified_at")
certified["compatibility_certified_at"] = certified.delete("certified_at")
end
certified["status"] = "certified"
certified["certification"] = certification
certified
end
def validate_supplied_certification!(supplied, consumer:, profile:, tuple:, expected_fingerprint:, label:)
unless supplied.is_a?(Hash)
raise PromotionError, "#{label} certification evidence, timestamp, and status are required"
end
status = supplied["status"]
certified_at = supplied["certified_at"]
evidence = Array(supplied["evidence"])
unless status == CERTIFICATION_STATUS
raise PromotionError, "#{label} certification status must be #{CERTIFICATION_STATUS.inspect}"
end
validate_timestamp!(certified_at, "#{label} certification timestamp")
raise PromotionError, "#{label} certification requires at least one evidence file" if evidence.empty?
raise PromotionError, "#{label} certification evidence files must be unique" unless evidence.uniq == evidence
consumer_commit = tuple.fetch("consumer_commit")
normalized_evidence = evidence.map do |reference|
validate_evidence!(
reference,
consumer: consumer,
profile: profile,
consumer_commit: consumer_commit,
status: status,
certified_at: certified_at,
tuple_fingerprint: expected_fingerprint,
label: label
)
end
{
"status" => status,
"certified_at" => certified_at,
"tuple_sha256" => expected_fingerprint,
"evidence" => normalized_evidence
}
end
def validate_recorded_certification!(tuple, consumer:, profile:, expected_fingerprint:, label:)
certification = tuple["certification"]
unless certification.is_a?(Hash) && certification["tuple_sha256"] == expected_fingerprint
raise PromotionError, "#{label} tuple has invalid or stale certification metadata"
end
validate_supplied_certification!(
certification,
consumer: consumer,
profile: profile,
tuple: tuple,
expected_fingerprint: expected_fingerprint,
label: label
)
end
def validate_evidence!(
reference,
consumer:,
profile:,
consumer_commit:,
status:,
certified_at:,
tuple_fingerprint:,
label:
)
unless reference.is_a?(String) && !reference.empty?
raise PromotionError, "#{label} evidence references must be non-empty strings"
end
relative = Pathname.new(reference).cleanpath
if relative.absolute? || relative.each_filename.first != "evidence"
raise PromotionError, "#{label} evidence must be a repository-relative path under evidence/"
end
full_path = File.join(@root, relative.to_s)
evidence_root = File.realpath(File.join(@root, "evidence"))
real_path = File.realpath(full_path)
unless real_path.start_with?("#{evidence_root}#{File::SEPARATOR}")
raise PromotionError, "#{label} evidence resolves outside evidence/"
end
document = parse_json(File.read(real_path), relative.to_s)
unless document.is_a?(Hash) && document["schema_version"] == 1
raise PromotionError, "#{label} evidence #{relative} must use schema_version 1"
end
expected = {
"consumer" => consumer,
"profile" => profile,
"consumer_commit" => consumer_commit,
"status" => status,
"certified_at" => certified_at,
"tuple_sha256" => tuple_fingerprint
}
expected.each do |key, value|
next if document[key] == value
raise PromotionError,
"#{label} evidence #{relative} has #{key}=#{document[key].inspect}; expected #{value.inspect}"
end
relative.to_s
rescue Errno::ENOENT
raise PromotionError, "#{label} evidence does not exist: #{reference}"
end
def validate_tuple!(tuple, label)
raise PromotionError, "#{label} tuple must be an object" unless tuple.is_a?(Hash)
validate_full_commit!(tuple["consumer_commit"], "#{label} consumer commit")
validate_client!(tuple["opencode_ruby"], "#{label} opencode_ruby", required: true)
validate_client!(tuple["opencode_rails"], "#{label} opencode_rails", required: false)
validate_runtime!(tuple["runtime"], "#{label} runtime")
end
def validate_client!(client, label, required:)
if client.nil?
raise PromotionError, "#{label} is required" if required
return
end
unless client.is_a?(Hash) && client["version"].is_a?(String) && !client["version"].empty?
raise PromotionError, "#{label} must include a non-empty version"
end
validate_full_commit!(client["git_commit"], "#{label} git commit")
end
def validate_runtime!(runtime, label)
raise PromotionError, "#{label} must be an object" unless runtime.is_a?(Hash)
unless runtime["reported_version"].is_a?(String) && !runtime["reported_version"].empty?
raise PromotionError, "#{label} must include the reported OpenCode server version"
end
exact_execution_coordinate = false
runtime.each do |key, value|
if key == "docker_image_id" || key.end_with?("_image_id")
unless value.is_a?(String) && value.match?(DIGEST)
raise PromotionError, "#{label} #{key} must be an exact sha256 image ID"
end
exact_execution_coordinate = true if key == "docker_image_id"
elsif image_reference_key?(key)
unless value.is_a?(String) && value.match?(IMMUTABLE_IMAGE)
raise PromotionError, "#{label} #{key} must be an immutable image@sha256 digest, not a tag"
end
exact_execution_coordinate = true if %w[image registry_ref].include?(key)
elsif key == "source_commit"
validate_full_commit!(value, "#{label} source commit")
end
end
unless exact_execution_coordinate
raise PromotionError, "#{label} must include an immutable image, registry_ref, or docker_image_id"
end
end
def image_reference_key?(key)
EXACT_IMAGE_REFERENCE_KEYS.include?(key) ||
(key.end_with?("_image") && key != "tag_provenance") ||
(key.end_with?("_ref") && key != "tag_provenance")
end
def validate_full_commit!(value, label)
return if value.is_a?(String) && value.match?(FULL_COMMIT)
raise PromotionError, "#{label} must be a full 40-character lowercase Git commit"
end
def validate_timestamp!(value, label)
unless value.is_a?(String) && value.match?(UTC_TIMESTAMP)
raise PromotionError, "#{label} must be an explicit RFC 3339 UTC timestamp"
end
Time.iso8601(value)
rescue ArgumentError
raise PromotionError, "#{label} is not a valid timestamp"
end
def tuple_fingerprint(tuple, consumer:, profile:)
payload = deep_copy(tuple)
TUPLE_METADATA_KEYS.each { |key| payload.delete(key) }
envelope = {
"consumer" => consumer,
"profile" => profile,
"tuple" => payload
}
"sha256:#{Digest::SHA256.hexdigest(JSON.generate(canonicalize(envelope)))}"
end
def canonicalize(value)
case value
when Hash
value.keys.sort.to_h { |key| [key, canonicalize(value.fetch(key))] }
when Array
value.map { |item| canonicalize(item) }
else
value
end
end
def deep_copy(value)
JSON.parse(JSON.generate(value))
end
def parse_json(contents, label)
JSON.parse(contents)
rescue JSON::ParserError => e
raise PromotionError, "invalid JSON in #{label}: #{e.message}"
end
def all_consumers_certified?(manifest)
manifest.fetch("consumers").all? do |consumer, entry|
next false unless entry["candidate"].nil?
profile = fetch_profile!(entry, consumer)
%w[current previous].all? do |slot|
tuple = entry[slot]
next false unless tuple.is_a?(Hash) && tuple["status"] == "certified"
validate_tuple!(tuple, "#{consumer} #{slot}")
validate_recorded_certification!(
tuple,
consumer: consumer,
profile: profile,
expected_fingerprint: tuple_fingerprint(tuple, consumer: consumer, profile: profile),
label: "#{consumer} #{slot}"
)
true
rescue PromotionError
false
end
end
end
def with_current_manifest_lock
loop do
retry_with_new_inode = false
result = nil
File.open(@manifest_path, File::RDONLY) do |locked_file|
locked_file.flock(File::LOCK_EX)
unless File.identical?(locked_file, @manifest_path)
retry_with_new_inode = true
next
end
result = yield parse_json(locked_file.read, @manifest_path)
end
return result unless retry_with_new_inode
end
rescue Errno::ENOENT
raise PromotionError, "runtime tuple manifest does not exist: #{@manifest_path}"
end
def atomic_write(manifest)
directory = File.dirname(@manifest_path)
mode = File.stat(@manifest_path).mode & 0o777
payload = JSON.pretty_generate(manifest) + "\n"
Tempfile.create([".runtime-tuples-", ".tmp"], directory) do |temporary|
temporary.chmod(mode)
temporary.write(payload)
temporary.flush
temporary.fsync
temporary.close
File.rename(temporary.path, @manifest_path)
fsync_directory(directory)
end
end
def fsync_directory(directory)
File.open(directory, File::RDONLY, &:fsync)
rescue Errno::EINVAL, Errno::ENOTSUP
# Some filesystems do not support directory fsync; rename is still atomic.
end
end
end

View File

@@ -1,6 +1,11 @@
{
"repository": "ajaynomics/opencode-ruby",
"ref": "a116b2708cc148f61b1e1fae0405553c099f4202",
"version": "0.0.1.alpha6",
"ref": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"version": "0.0.1.alpha7",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "abfce3ec8cb1ee468107d0845521769502251645",
"peeled_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798"
},
"status": "candidate"
}

View File

@@ -7,8 +7,14 @@
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"tag_provenance": "ghcr.io/anomalyco/opencode:1.16.1",
"consumers": ["travelwolf"],
"profiles": ["ruby-rest-sse", "rails-persisted-turn"],
"certification_status": "certified"
"profiles": ["ruby-rest-sse"],
"required_consumer_profiles": ["rails-persisted-turn"],
"certification_status": "certified",
"certified_client_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"certified_at": "2026-07-18T22:03:12Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1
},
{
"id": "upstream-1.17.18",
@@ -16,8 +22,14 @@
"image": "ghcr.io/anomalyco/opencode@sha256:bf9d0e84b7cedef436a8f57db4d48767cd5d8fc6604f666335c1cc916b199a97",
"tag_provenance": "ghcr.io/anomalyco/opencode:1.17.18",
"consumers": ["opencode-ajent"],
"profiles": ["plugin-ledger", "ruby-rest-sse"],
"certification_status": "certified"
"profiles": ["ruby-rest-sse"],
"required_consumer_profiles": ["plugin-ledger"],
"certification_status": "certified",
"certified_client_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"certified_at": "2026-07-18T22:03:13Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1
},
{
"id": "upstream-1.18.3",
@@ -25,34 +37,49 @@
"image": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"tag_provenance": "ghcr.io/anomalyco/opencode:1.18.3",
"consumers": ["ajent-rails"],
"profiles": ["ruby-rest-sse", "rails-persisted-turn", "plugin-ledger"],
"certification_status": "certified"
"profiles": ["ruby-rest-sse"],
"required_consumer_profiles": ["rails-persisted-turn", "plugin-ledger"],
"certification_status": "certified",
"certified_client_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"certified_at": "2026-07-18T22:03:14Z",
"expected_text": "compat-ok",
"full_text": "compat-ok",
"llm_request_count": 1
}
],
"host_canary": [
{
"id": "ajent-blackline-live",
"id": "ajent-blackline-alpha7-canary",
"consumer": "ajent-rails",
"registry_ref": "docker-registry:5000/opencode-blackline:83eed3c247a352842b08fc5cf339c4d0acdaacba",
"docker_image_id": "sha256:6fb2b3bf8e4cdf48e16bf6c3475e953df2f8304e77f5efe816ceb46f905eead8",
"consumer_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"tag_provenance": "ajent-opencode-blackline-canary:96552893",
"docker_image_id": "sha256:239e3dc6cd2958251cda636fb20bd7cd7c46f596bd4c61cb81863ebc49d824e8",
"source_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"reported_version": "1.18.3",
"upstream_base": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e",
"profiles": ["ruby-rest-sse", "rails-persisted-turn", "plugin-ledger"],
"profiles": ["rails-persisted-turn"],
"certification_status": "candidate-certified",
"certified_candidate": "a116b2708cc148f61b1e1fae0405553c099f4202",
"certified_at": "2026-07-18T20:34:10Z"
"certified_client_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"certified_rails_commit": "2a391ccad1d098e4bb51eb19b6ca52adaa79e5cb",
"certified_at": "2026-07-18T21:58:00Z",
"persisted_final_text": "compat-ok",
"model_request_count": 1
},
{
"id": "mushu-permission-shortcuts-live",
"id": "mushu-permission-shortcuts-alpha7-canary",
"consumer": "mushu",
"registry_ref": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"consumer_commit": "f26d958b64f214a422aeb629860c8c9a46a4c084",
"run_id": "mushu-alpha7-20260718T215300Z-f26d958",
"tag_provenance": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"reported_version": "0.0.0-permission-shortcuts-202606300721",
"source_commit": "99d6328b18ff8a340a928449a2aa8bc184a063f9",
"reported_version": "0.0.0-permission-shortcuts-202606300721",
"profiles": ["ruby-rest-sse"],
"certification_status": "candidate-certified",
"certified_candidate": "a116b2708cc148f61b1e1fae0405553c099f4202",
"certified_at": "2026-07-18T20:34:08Z"
"certified_client_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"certified_at": "2026-07-18T21:53:00Z",
"persisted_final_text": "compat-ok",
"model_request_count": 1
}
]
}

View File

@@ -1,16 +1,28 @@
{
"schema_version": 1,
"migration_state": "candidate",
"promotion_readiness": {
"status": "blocked",
"reason": "Every observed alpha2 baseline fails the hardened exact-final-text contract, so none can be certified as the previous rollback tuple.",
"evidence": "evidence/2026-07-18-opencode-ruby-alpha2-regression.json",
"required_action": "Create and canary a distinct rollback consumer commit that pins alpha7 and the exact runtime before promoting any candidate."
},
"consumers": {
"ajent-rails": {
"profile": "rails-persisted-turn",
"current": {
"status": "observed-production",
"status": "observed-production-contract-failed",
"consumer_commit": "83eed3c247a352842b08fc5cf339c4d0acdaacba",
"opencode_ruby": {"version": "0.0.1.alpha2", "git_commit": "889d383"},
"opencode_rails": {"version": "0.0.1.alpha2", "git_commit": "9b0c4cd"},
"opencode_ruby": {
"version": "0.0.1.alpha2",
"git_commit": "889d38332f98f5f7b76d16952b7204d8a5b9a662"
},
"opencode_rails": {
"version": "0.0.1.alpha2",
"git_commit": "9b0c4cd3cd31bdfebbb89567daca012d68a356ea"
},
"runtime": {
"registry_ref": "docker-registry:5000/opencode-blackline:83eed3c247a352842b08fc5cf339c4d0acdaacba",
"tag_provenance": "docker-registry:5000/opencode-blackline:83eed3c247a352842b08fc5cf339c4d0acdaacba",
"docker_image_id": "sha256:6fb2b3bf8e4cdf48e16bf6c3475e953df2f8304e77f5efe816ceb46f905eead8",
"reported_version": "1.18.3",
"upstream_base": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e"
@@ -18,24 +30,54 @@
},
"candidate": {
"status": "compatibility-certified",
"opencode_ruby": {"version": "0.0.1.alpha6", "git_commit": "a116b2708cc148f61b1e1fae0405553c099f4202"},
"opencode_rails": {"version": "0.0.1.alpha6", "git_commit": "17025f0ed955899c57830eaea34da49f07250fcc"},
"consumer_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"opencode_ruby": {
"version": "0.0.1.alpha7",
"git_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "abfce3ec8cb1ee468107d0845521769502251645"
}
},
"opencode_rails": {
"version": "0.0.1.alpha7",
"git_commit": "2a391ccad1d098e4bb51eb19b6ca52adaa79e5cb",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "61e128084b2b665c0ba20b332987e41794948d7c"
}
},
"runtime": {
"docker_image_id": "sha256:6fb2b3bf8e4cdf48e16bf6c3475e953df2f8304e77f5efe816ceb46f905eead8",
"tag_provenance": "ajent-opencode-blackline-canary:96552893",
"docker_image_id": "sha256:239e3dc6cd2958251cda636fb20bd7cd7c46f596bd4c61cb81863ebc49d824e8",
"source_commit": "96552893baccd5ccba1592b2585edfef1299b4f9",
"reported_version": "1.18.3",
"upstream_base": "ghcr.io/anomalyco/opencode@sha256:c2d5d6398df72aac85cb1bdc8f900c71a9b75a33fb7c0a76dc1484e4b126e41e"
},
"certified_at": "2026-07-18T20:34:10Z"
"application_canary": {
"checked_at": "2026-07-18T21:58:00Z",
"path": "Blackline::GenerateResponseJob",
"persisted_final_text": "compat-ok",
"model_request_count": 1,
"status": "pass"
},
"certified_at": "2026-07-18T22:03:14Z"
},
"previous": null
},
"travelwolf": {
"profile": "rails-persisted-turn",
"current": {
"status": "repository-configured",
"status": "observed-production-contract-failed",
"consumer_commit": "1ca756d64f058c9e0379f69fc4a3d53330cfcd15",
"opencode_ruby": {"version": "0.0.1.alpha2", "git_commit": "889d383"},
"opencode_rails": {"version": "0.0.1.alpha2", "git_commit": "9b0c4cd"},
"opencode_ruby": {
"version": "0.0.1.alpha2",
"git_commit": "889d38332f98f5f7b76d16952b7204d8a5b9a662"
},
"opencode_rails": {
"version": "0.0.1.alpha2",
"git_commit": "9b0c4cd3cd31bdfebbb89567daca012d68a356ea"
},
"runtime": {
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"reported_version": "1.16.1"
@@ -43,24 +85,51 @@
},
"candidate": {
"status": "compatibility-certified",
"opencode_ruby": {"version": "0.0.1.alpha6", "git_commit": "a116b2708cc148f61b1e1fae0405553c099f4202"},
"opencode_rails": {"version": "0.0.1.alpha6", "git_commit": "17025f0ed955899c57830eaea34da49f07250fcc"},
"consumer_commit": "19747b59fa21e12560afd9edd73ed674ab3a644c",
"opencode_ruby": {
"version": "0.0.1.alpha7",
"git_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "abfce3ec8cb1ee468107d0845521769502251645"
}
},
"opencode_rails": {
"version": "0.0.1.alpha7",
"git_commit": "2a391ccad1d098e4bb51eb19b6ca52adaa79e5cb",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "61e128084b2b665c0ba20b332987e41794948d7c"
}
},
"runtime": {
"image": "ghcr.io/anomalyco/opencode@sha256:e975a0647576016dfdf77d54b979ca30d32b4750472c10263e9894aad6628c2a",
"reported_version": "1.16.1"
},
"certified_at": "2026-07-18T20:34:05Z"
"application_canary": {
"run_id": "20260718215135-8d8102c0",
"checked_at": "2026-07-18T21:51:56.552Z",
"final_text": "TRAVELWOLF_ALPHA7_SUBSCRIBE_READY",
"application_prompt_count": 1,
"model_request_count_observed": false,
"cleanup_status": "pass",
"status": "pass"
},
"certified_at": "2026-07-18T22:03:14Z"
},
"previous": null
},
"mushu": {
"profile": "ruby-rest-sse",
"current": {
"status": "observed-production",
"status": "observed-production-contract-failed",
"consumer_commit": "fe16e5bab028e3c92cd5508ef2cebd9bfa23386f",
"opencode_ruby": {"version": "0.0.1.alpha2", "git_commit": "889d383"},
"opencode_ruby": {
"version": "0.0.1.alpha2",
"git_commit": "889d38332f98f5f7b76d16952b7204d8a5b9a662"
},
"runtime": {
"registry_ref": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"tag_provenance": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"source_commit": "99d6328b18ff8a340a928449a2aa8bc184a063f9",
"reported_version": "0.0.0-permission-shortcuts-202606300721"
@@ -68,13 +137,29 @@
},
"candidate": {
"status": "compatibility-certified",
"opencode_ruby": {"version": "0.0.1.alpha6", "git_commit": "a116b2708cc148f61b1e1fae0405553c099f4202"},
"consumer_commit": "f26d958b64f214a422aeb629860c8c9a46a4c084",
"opencode_ruby": {
"version": "0.0.1.alpha7",
"git_commit": "78b6f9c9e9c7d58b699af1c3c17764acd33de798",
"tag_provenance": {
"tag": "v0.0.1.alpha7",
"annotated_tag_object": "abfce3ec8cb1ee468107d0845521769502251645"
}
},
"runtime": {
"tag_provenance": "docker-registry:5000/mushu-opencode:sha-99d6328b1",
"docker_image_id": "sha256:ed6293ca87e6db1dc07870d3ed6da21960743e6e2e904533b3c566d334b58d6a",
"source_commit": "99d6328b18ff8a340a928449a2aa8bc184a063f9",
"reported_version": "0.0.0-permission-shortcuts-202606300721"
},
"certified_at": "2026-07-18T20:34:08Z"
"application_canary": {
"run_id": "mushu-alpha7-20260718T215300Z-f26d958",
"checked_at": "2026-07-18T21:53:00Z",
"persisted_final_text": "compat-ok",
"model_request_count": 1,
"status": "pass"
},
"certified_at": "2026-07-18T22:03:14Z"
},
"previous": null
}

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module OpenCodeCompat
module ExactLiveContract
class ContractError < StandardError; end
module_function
def assert_final_text!(actual, expected)
return if actual == expected
raise ContractError, "Expected final text to equal #{expected.inspect}, got #{actual.inspect}"
end
def assert_model_request_count!(value)
count = Integer(value, 10)
return if count == 1
raise ContractError, "Expected exactly one deterministic model request, got #{count}"
rescue ArgumentError, TypeError
raise ContractError, "Deterministic model request count is not an integer: #{value.inspect}"
end
end
end
if $PROGRAM_NAME == __FILE__
begin
OpenCodeCompat::ExactLiveContract.assert_model_request_count!(ARGV.fetch(0))
rescue IndexError, OpenCodeCompat::ExactLiveContract::ContractError => error
warn error.message
exit 1
end
end

View File

@@ -2,6 +2,7 @@
require "json"
require "time"
require_relative "exact_live_contract"
gem_path = File.expand_path(ENV.fetch("OPENCODE_RUBY_PATH"))
$LOAD_PATH.unshift(File.join(gem_path, "lib"))
@@ -32,9 +33,7 @@ begin
observed_parts << JSON.parse(JSON.generate(part))
end
unless result.full_text.include?(expected_text)
raise "Expected final text to include #{expected_text.inspect}, got #{result.full_text.inspect}"
end
OpenCodeCompat::ExactLiveContract.assert_final_text!(result.full_text, expected_text)
messages = client.get_messages(session_id)
assistant_messages = Array(messages).select { |message| message.dig(:info, :role) == "assistant" }

104
scripts/promote_runtime_tuple.rb Executable file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require "json"
require "optparse"
require_relative "../lib/opencode_compat/runtime_tuple_promoter"
root = File.expand_path("..", __dir__)
command = ARGV.shift
options = {
"evidence" => [],
"previous_evidence" => []
}
parser = OptionParser.new do |opts|
opts.banner = <<~USAGE
Usage:
ruby scripts/promote_runtime_tuple.rb fingerprint --consumer NAME --consumer-commit SHA
ruby scripts/promote_runtime_tuple.rb promote --consumer NAME --consumer-commit SHA \\
--status pass --certified-at TIMESTAMP --evidence evidence/FILE.json \\
[--previous-status pass --previous-certified-at TIMESTAMP \\
--previous-evidence evidence/FILE.json] [--dry-run]
USAGE
opts.on("--consumer NAME") { |value| options["consumer"] = value }
opts.on("--consumer-commit SHA") { |value| options["consumer_commit"] = value }
opts.on("--status STATUS") { |value| options["status"] = value }
opts.on("--certified-at TIMESTAMP") { |value| options["certified_at"] = value }
opts.on("--evidence PATH") { |value| options["evidence"] << value }
opts.on("--previous-status STATUS") { |value| options["previous_status"] = value }
opts.on("--previous-certified-at TIMESTAMP") { |value| options["previous_certified_at"] = value }
opts.on("--previous-evidence PATH") { |value| options["previous_evidence"] << value }
opts.on("--dry-run") { options["dry_run"] = true }
end
def required!(options, *keys)
missing = keys.reject { |key| options[key] && (!options[key].respond_to?(:empty?) || !options[key].empty?) }
raise OptionParser::MissingArgument, missing.join(", ") unless missing.empty?
end
begin
parser.parse!(ARGV)
raise OptionParser::InvalidArgument, "unexpected arguments: #{ARGV.join(' ')}" unless ARGV.empty?
promoter = OpenCodeCompat::RuntimeTuplePromoter.new(root: root)
case command
when "fingerprint"
required!(options, "consumer", "consumer_commit")
puts JSON.pretty_generate(
promoter.fingerprints(
consumer: options.fetch("consumer"),
consumer_commit: options.fetch("consumer_commit")
)
)
when "promote"
required!(options, "consumer", "consumer_commit", "status", "certified_at", "evidence")
previous_fields = %w[previous_status previous_certified_at previous_evidence]
supplied_previous_fields = previous_fields.select do |key|
value = options[key]
value && (!value.respond_to?(:empty?) || !value.empty?)
end
if supplied_previous_fields.any? && supplied_previous_fields.length != previous_fields.length
raise OptionParser::MissingArgument, (previous_fields - supplied_previous_fields).join(", ")
end
previous_certification = if supplied_previous_fields.empty?
nil
else
{
"status" => options.fetch("previous_status"),
"certified_at" => options.fetch("previous_certified_at"),
"evidence" => options.fetch("previous_evidence")
}
end
promoted = promoter.promote(
consumer: options.fetch("consumer"),
consumer_commit: options.fetch("consumer_commit"),
certification: {
"status" => options.fetch("status"),
"certified_at" => options.fetch("certified_at"),
"evidence" => options.fetch("evidence")
},
previous_certification: previous_certification,
dry_run: options.fetch("dry_run", false)
)
if options.fetch("dry_run", false)
puts JSON.pretty_generate(promoted)
else
current = promoted.fetch("consumers").fetch(options.fetch("consumer")).fetch("current")
puts JSON.pretty_generate(
"consumer" => options.fetch("consumer"),
"current_consumer_commit" => current.fetch("consumer_commit"),
"current_tuple_sha256" => current.dig("certification", "tuple_sha256"),
"migration_state" => promoted.fetch("migration_state")
)
end
else
raise OptionParser::InvalidArgument, "command must be fingerprint or promote"
end
rescue OpenCodeCompat::PromotionError, OptionParser::ParseError => e
warn "error: #{e.message}"
warn parser
exit 1
end

View File

@@ -34,7 +34,8 @@ unless matrix.fetch("public_ci").any? { |target| target.fetch("image") == image
"image" => image,
"tag_provenance" => "ghcr.io/anomalyco/opencode:#{version}",
"consumers" => ["upstream-candidate"],
"profiles" => ["ruby-rest-sse", "rails-persisted-turn", "voice-stream", "strict-v2", "plugin-ledger", "provider-hooks"],
"profiles" => ["ruby-rest-sse"],
"required_consumer_profiles" => ["rails-persisted-turn", "voice-stream", "strict-v2", "plugin-ledger", "provider-hooks"],
"certification_status" => "pending"
}
end

View File

@@ -127,10 +127,7 @@ OPENCODE_RUBY_COMMIT="$gem_commit" \
llm_stats="$(docker exec "$llm_container_name" wget -qO- http://127.0.0.1:8080/stats)"
request_count="$(jq -r '.request_count' <<<"$llm_stats")"
if [[ "$request_count" -lt 1 ]]; then
echo "OpenCode never called the deterministic model" >&2
exit 1
fi
ruby "$repo_root/ruby/exact_live_contract.rb" "$request_count"
jq -cn \
--arg status pass \

View File

@@ -0,0 +1,29 @@
# frozen_string_literal: true
require "minitest/autorun"
require_relative "../ruby/exact_live_contract"
class ExactLiveContractTest < Minitest::Test
def test_accepts_only_exact_final_text
assert_nil OpenCodeCompat::ExactLiveContract.assert_final_text!("compat-ok", "compat-ok")
error = assert_raises(OpenCodeCompat::ExactLiveContract::ContractError) do
OpenCodeCompat::ExactLiveContract.assert_final_text!("compat-ok\n\ncompat-ok", "compat-ok")
end
assert_match(/equal/, error.message)
assert_raises(OpenCodeCompat::ExactLiveContract::ContractError) do
OpenCodeCompat::ExactLiveContract.assert_final_text!("prefix compat-ok", "compat-ok")
end
end
def test_accepts_only_one_model_request
assert_nil OpenCodeCompat::ExactLiveContract.assert_model_request_count!("1")
%w[0 2 not-a-number].each do |count|
assert_raises(OpenCodeCompat::ExactLiveContract::ContractError) do
OpenCodeCompat::ExactLiveContract.assert_model_request_count!(count)
end
end
end
end

View File

@@ -2,6 +2,7 @@
require "json"
require "minitest/autorun"
require_relative "../lib/opencode_compat/runtime_tuple_promoter"
class RepositoryTest < Minitest::Test
ROOT = File.expand_path("..", __dir__)
@@ -11,7 +12,7 @@ class RepositoryTest < Minitest::Test
end
def test_every_json_document_parses
paths = Dir.glob(File.join(ROOT, "{fixtures,manifests,profiles}/**/*.json"))
paths = Dir.glob(File.join(ROOT, "{evidence,fixtures,manifests,profiles}/**/*.json"))
refute_empty paths
paths.each { |path| JSON.parse(File.read(path)) }
end
@@ -42,17 +43,102 @@ class RepositoryTest < Minitest::Test
assert_match %r{\Aghcr\.io/anomalyco/opencode@sha256:[0-9a-f]{64}\z}, target.fetch("image")
refute_includes target.fetch("image"), ":latest"
refute_empty target.fetch("profiles")
next unless target.fetch("certification_status") == "certified"
assert_match(/\A[0-9a-f]{40}\z/, target.fetch("certified_client_commit"))
assert_equal target.fetch("expected_text"), target.fetch("full_text")
assert_equal 1, target.fetch("llm_request_count")
end
end
def test_candidate_is_bound_to_an_annotated_tag
candidate = json("manifests/client-candidate.json")
provenance = candidate.fetch("tag_provenance")
assert_match(/\A[0-9a-f]{40}\z/, candidate.fetch("ref"))
assert_match(/\Av\d+\.\d+\.\d+\.alpha\d+\z/, provenance.fetch("tag"))
assert_match(/\A[0-9a-f]{40}\z/, provenance.fetch("annotated_tag_object"))
assert_equal candidate.fetch("ref"), provenance.fetch("peeled_commit")
end
def test_certified_migration_keeps_previous_tuple
tuples = json("manifests/runtime-tuples.json")
return unless tuples.fetch("migration_state") == "certified"
tuples.fetch("consumers").each_value do |consumer|
refute_nil consumer["current"]
refute_nil consumer["previous"]
assert_equal "certified", consumer.fetch("current").fetch("status")
%w[current previous].each do |slot|
tuple = consumer.fetch(slot)
assert_equal "certified", tuple.fetch("status")
assert_equal "pass", tuple.fetch("certification").fetch("status")
assert_match(/\Asha256:[0-9a-f]{64}\z/, tuple.fetch("certification").fetch("tuple_sha256"))
refute_empty tuple.fetch("certification").fetch("evidence")
end
end
end
def test_runtime_tuple_profiles_exist
tuples = json("manifests/runtime-tuples.json")
tuples.fetch("consumers").each_value do |consumer|
profile = consumer.fetch("profile")
assert_path_exists File.join(ROOT, "profiles", "#{profile}.json")
end
end
def test_runtime_tuples_use_full_commits_and_no_mutable_registry_coordinate
tuples = json("manifests/runtime-tuples.json")
tuples.fetch("consumers").each_value do |consumer|
%w[current candidate previous].each do |slot|
tuple = consumer[slot]
next unless tuple
assert_match(/\A[0-9a-f]{40}\z/, tuple.fetch("consumer_commit"))
%w[opencode_ruby opencode_rails].each do |client_name|
client = tuple[client_name]
assert_match(/\A[0-9a-f]{40}\z/, client.fetch("git_commit")) if client
end
runtime = tuple.fetch("runtime")
if runtime.key?("registry_ref")
assert_match(/\A[^@\s]+@sha256:[0-9a-f]{64}\z/, runtime.fetch("registry_ref"))
end
if runtime.key?("tag_provenance")
refute_empty runtime.fetch("tag_provenance")
end
end
end
end
def test_failed_alpha2_baselines_block_promotion_instead_of_becoming_previous
tuples = json("manifests/runtime-tuples.json")
readiness = tuples.fetch("promotion_readiness")
assert_equal "blocked", readiness.fetch("status")
assert_path_exists File.join(ROOT, readiness.fetch("evidence"))
tuples.fetch("consumers").each_value do |consumer|
assert_equal "observed-production-contract-failed", consumer.dig("current", "status")
assert_nil consumer.fetch("previous")
end
end
def test_candidate_evidence_is_bound_to_complete_tuple_fingerprints
promoter = OpenCodeCompat::RuntimeTuplePromoter.new(root: ROOT)
evidence_paths = {
"ajent-rails" => "evidence/2026-07-18-ajent-rails-alpha7-candidate.json",
"travelwolf" => "evidence/2026-07-18-travelwolf-alpha7-candidate.json",
"mushu" => "evidence/2026-07-18-mushu-alpha7-candidate.json"
}
evidence_paths.each do |consumer, path|
evidence = json(path)
fingerprints = promoter.fingerprints(
consumer: consumer,
consumer_commit: evidence.fetch("consumer_commit")
)
assert_equal consumer, evidence.fetch("consumer")
assert_equal fingerprints.fetch("profile"), evidence.fetch("profile")
assert_equal fingerprints.fetch("candidate_tuple_sha256"), evidence.fetch("tuple_sha256")
assert_equal "pass", evidence.fetch("status")
end
end
@@ -60,4 +146,26 @@ class RepositoryTest < Minitest::Test
workflow = File.read(File.join(ROOT, ".github/workflows/watch-upstream.yml"))
refute_match(/\b(kamal|kubectl|helm|nomad|docker\s+service)\b/i, workflow)
end
def test_tuple_promotion_has_no_command_execution_or_deployment_client
paths = %w[
lib/opencode_compat/runtime_tuple_promoter.rb
scripts/promote_runtime_tuple.rb
]
implementation = paths.map { |path| File.read(File.join(ROOT, path)) }.join("\n")
refute_match(/\b(system|exec|spawn|popen|Open3)\b/, implementation)
refute_match(/`[^`]+`/, implementation)
refute_match(/\b(kamal|kubectl|helm|nomad|docker\s+service)\b/i, implementation)
end
def test_live_contract_requires_exact_text_and_one_model_request
probe = File.read(File.join(ROOT, "ruby/live_probe.rb"))
runner = File.read(File.join(ROOT, "scripts/run_image_contract.sh"))
assert_includes probe, "ExactLiveContract.assert_final_text!"
refute_includes probe, "full_text.include?"
assert_includes runner, "exact_live_contract.rb"
refute_match(/request_count.*-lt\s+1/, runner)
end
end

View File

@@ -0,0 +1,329 @@
# frozen_string_literal: true
require "fileutils"
require "json"
require "minitest/autorun"
require "tmpdir"
require_relative "../lib/opencode_compat/runtime_tuple_promoter"
class RuntimeTuplePromoterTest < Minitest::Test
CONSUMER = "example"
CURRENT_COMMIT = "1" * 40
CANDIDATE_COMMIT = "2" * 40
RUBY_CURRENT = "3" * 40
RUBY_CANDIDATE = "4" * 40
RAILS_CURRENT = "5" * 40
RAILS_CANDIDATE = "6" * 40
CURRENT_IMAGE = "ghcr.io/anomalyco/opencode@sha256:#{'a' * 64}"
CANDIDATE_IMAGE = "ghcr.io/anomalyco/opencode@sha256:#{'b' * 64}"
CURRENT_TIME = "2026-07-17T12:00:00Z"
CANDIDATE_TIME = "2026-07-18T12:00:00Z"
def setup
@root = Dir.mktmpdir("opencode-compat-promotion")
FileUtils.mkdir_p(File.join(@root, "manifests"))
FileUtils.mkdir_p(File.join(@root, "evidence"))
FileUtils.mkdir_p(File.join(@root, "profiles"))
File.write(File.join(@root, "profiles", "rails-persisted-turn.json"), "{}\n")
write_manifest(valid_manifest)
@promoter = OpenCodeCompat::RuntimeTuplePromoter.new(root: @root)
end
def teardown
FileUtils.remove_entry(@root)
end
def test_promotion_atomically_moves_certified_tuples_and_clears_candidate
candidate, previous = write_matching_evidence
promoted = @promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate),
previous_certification: certification(CURRENT_TIME, previous)
)
consumer = promoted.fetch("consumers").fetch(CONSUMER)
assert_nil consumer["candidate"]
assert_equal CANDIDATE_COMMIT, consumer.dig("current", "consumer_commit")
assert_equal RUBY_CANDIDATE, consumer.dig("current", "opencode_ruby", "git_commit")
assert_equal "certified", consumer.dig("current", "status")
assert_equal candidate.fetch("tuple_sha256"), consumer.dig("current", "certification", "tuple_sha256")
assert_equal CURRENT_COMMIT, consumer.dig("previous", "consumer_commit")
assert_equal RUBY_CURRENT, consumer.dig("previous", "opencode_ruby", "git_commit")
assert_equal "certified", consumer.dig("previous", "status")
assert_equal previous.fetch("tuple_sha256"), consumer.dig("previous", "certification", "tuple_sha256")
assert_equal "certified", promoted.fetch("migration_state")
assert_equal promoted, JSON.parse(File.read(manifest_path))
end
def test_dry_run_returns_promotion_without_changing_manifest
candidate, previous = write_matching_evidence
before = File.binread(manifest_path)
promoted = @promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate),
previous_certification: certification(CURRENT_TIME, previous),
dry_run: true
)
assert_equal "certified", promoted.dig("consumers", CONSUMER, "current", "status")
assert_equal before, File.binread(manifest_path)
end
def test_rejects_missing_candidate_without_touching_manifest
manifest = valid_manifest
manifest.fetch("consumers").fetch(CONSUMER)["candidate"] = nil
write_manifest(manifest)
before = File.binread(manifest_path)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, {"path" => "evidence/missing.json"})
)
end
assert_match(/no candidate/, error.message)
assert_equal before, File.binread(manifest_path)
end
def test_rejects_mutable_candidate_image_even_with_an_exact_image_id
manifest = valid_manifest
runtime = manifest.dig("consumers", CONSUMER, "candidate", "runtime")
runtime["registry_ref"] = "ghcr.io/anomalyco/opencode:latest"
runtime["docker_image_id"] = "sha256:#{'c' * 64}"
write_manifest(manifest)
before = File.binread(manifest_path)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.fingerprints(consumer: CONSUMER, consumer_commit: CANDIDATE_COMMIT)
end
assert_match(/immutable image@sha256 digest/, error.message)
assert_equal before, File.binread(manifest_path)
end
def test_rejects_short_consumer_and_client_commits
assert_raises(OpenCodeCompat::PromotionError) do
@promoter.fingerprints(consumer: CONSUMER, consumer_commit: "abc123")
end
manifest = valid_manifest
manifest.dig("consumers", CONSUMER, "candidate", "opencode_ruby")["git_commit"] = "abc123"
write_manifest(manifest)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.fingerprints(consumer: CONSUMER, consumer_commit: CANDIDATE_COMMIT)
end
assert_match(/full 40-character/, error.message)
end
def test_rejects_missing_server_version_or_unknown_profile
manifest = valid_manifest
manifest.dig("consumers", CONSUMER, "candidate", "runtime").delete("reported_version")
write_manifest(manifest)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.fingerprints(consumer: CONSUMER, consumer_commit: CANDIDATE_COMMIT)
end
assert_match(/reported OpenCode server version/, error.message)
manifest = valid_manifest
manifest.dig("consumers", CONSUMER)["profile"] = "untracked-profile"
write_manifest(manifest)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.fingerprints(consumer: CONSUMER, consumer_commit: CANDIDATE_COMMIT)
end
assert_match(/profile does not exist/, error.message)
end
def test_rejects_missing_previous_certification_for_an_uncertified_baseline
candidate, = write_matching_evidence
before = File.binread(manifest_path)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate)
)
end
assert_match(/current tuple is not certified/, error.message)
assert_equal before, File.binread(manifest_path)
end
def test_rejects_known_failed_baseline_even_with_passing_evidence
manifest = valid_manifest
manifest.dig("consumers", CONSUMER, "current")["status"] = "observed-production-contract-failed"
write_manifest(manifest)
candidate, previous = write_matching_evidence
before = File.binread(manifest_path)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate),
previous_certification: certification(CURRENT_TIME, previous)
)
end
assert_match(/known to fail/, error.message)
assert_equal before, File.binread(manifest_path)
end
def test_rejects_evidence_that_does_not_match_the_complete_tuple
candidate, previous = write_matching_evidence
manifest = JSON.parse(File.read(manifest_path))
manifest.dig("consumers", CONSUMER, "candidate", "runtime")["image"] =
"ghcr.io/anomalyco/opencode@sha256:#{'f' * 64}"
write_manifest(manifest)
before = File.binread(manifest_path)
error = assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate),
previous_certification: certification(CURRENT_TIME, previous)
)
end
assert_match(/tuple_sha256/, error.message)
assert_equal before, File.binread(manifest_path)
end
def test_rejects_non_passing_or_implicit_certification_metadata
candidate, previous = write_matching_evidence
assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate).merge("status" => "pending"),
previous_certification: certification(CURRENT_TIME, previous),
dry_run: true
)
end
assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification("today", candidate),
previous_certification: certification(CURRENT_TIME, previous),
dry_run: true
)
end
end
def test_rejects_duplicate_or_unversioned_evidence
candidate, previous = write_matching_evidence
assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate).merge(
"evidence" => [candidate.fetch("path"), candidate.fetch("path")]
),
previous_certification: certification(CURRENT_TIME, previous),
dry_run: true
)
end
path = File.join(@root, candidate.fetch("path"))
document = JSON.parse(File.read(path))
document.delete("schema_version")
File.write(path, JSON.pretty_generate(document) + "\n")
assert_raises(OpenCodeCompat::PromotionError) do
@promoter.promote(
consumer: CONSUMER,
consumer_commit: CANDIDATE_COMMIT,
certification: certification(CANDIDATE_TIME, candidate),
previous_certification: certification(CURRENT_TIME, previous),
dry_run: true
)
end
end
private
def valid_manifest
{
"schema_version" => 1,
"migration_state" => "candidate",
"consumers" => {
CONSUMER => {
"profile" => "rails-persisted-turn",
"current" => {
"status" => "observed-production",
"consumer_commit" => CURRENT_COMMIT,
"opencode_ruby" => {"version" => "0.0.1.alpha2", "git_commit" => RUBY_CURRENT},
"opencode_rails" => {"version" => "0.0.1.alpha2", "git_commit" => RAILS_CURRENT},
"runtime" => {"image" => CURRENT_IMAGE, "reported_version" => "1.16.1"}
},
"candidate" => {
"status" => "compatibility-certified",
"certified_at" => "2026-07-18T10:00:00Z",
"opencode_ruby" => {"version" => "0.0.1.alpha7", "git_commit" => RUBY_CANDIDATE},
"opencode_rails" => {"version" => "0.0.1.alpha7", "git_commit" => RAILS_CANDIDATE},
"runtime" => {"image" => CANDIDATE_IMAGE, "reported_version" => "1.18.3"}
},
"previous" => nil
}
}
}
end
def write_matching_evidence
fingerprints = @promoter.fingerprints(consumer: CONSUMER, consumer_commit: CANDIDATE_COMMIT)
candidate = write_evidence(
"candidate.json",
commit: CANDIDATE_COMMIT,
timestamp: CANDIDATE_TIME,
fingerprint: fingerprints.fetch("candidate_tuple_sha256")
)
previous = write_evidence(
"previous.json",
commit: CURRENT_COMMIT,
timestamp: CURRENT_TIME,
fingerprint: fingerprints.fetch("current_tuple_sha256")
)
[candidate, previous]
end
def write_evidence(name, commit:, timestamp:, fingerprint:)
path = File.join("evidence", name)
document = {
"schema_version" => 1,
"consumer" => CONSUMER,
"profile" => "rails-persisted-turn",
"consumer_commit" => commit,
"status" => "pass",
"certified_at" => timestamp,
"tuple_sha256" => fingerprint
}
File.write(File.join(@root, path), JSON.pretty_generate(document) + "\n")
{"path" => path, "tuple_sha256" => fingerprint}
end
def certification(timestamp, evidence)
{
"status" => "pass",
"certified_at" => timestamp,
"evidence" => [evidence.fetch("path")]
}
end
def manifest_path
File.join(@root, "manifests", "runtime-tuples.json")
end
def write_manifest(manifest)
File.write(manifest_path, JSON.pretty_generate(manifest) + "\n")
end
end