Safe Android Reverser uses immutable semantic-version releases. From 0.3 onward, one plugin release may require multiple capability images plus exact runtime-cache images.
The release must keep plugin metadata, control-plane version, required capability image provenance, Worker ABI/Capability API, and Git tag consistent.
Canonical release version:
plugins/safe-android-reverser/VERSION
The following must match it:
- plugin manifest version;
- marketplace entry version;
- normal required capability image
org.opencontainers.image.versionlabels; - public MCP
serverInfo.version.
safe-android-reverser plugin VERSION
|
+-- host control plane
+-- static-core image
+-- framework-flutter base image
+-- exact Flutter runtime-cache images
Required baseline capability repositories are defined in manifests, not hard-coded into the launcher.
For 0.3:
ghcr.io/salingnh/safe-android-reverser:<VERSION>
ghcr.io/salingnh/safe-android-reverser-flutter:<VERSION>
Exact Flutter runtime-cache images use deterministic runtime identities rather than the plugin semver tag alone.
Published semver images are immutable.
Do not overwrite a broken release tag. Fix source and publish a new patch release.
Runtime Driver verifies requested image labels, resolves canonical image ID, and executes:
sha256:<64 hex image id>
rather than re-running the mutable tag after verification.
Pull requests may build/load/test images but do not publish release semver tags.
Pushes to master may publish moving development references such as:
<repository>:master
<repository>:sha-<commit>
master must not overwrite/publish a hard-coded semver release tag.
Capability-specific workflows may publish their own master/sha-* development references while preserving the same release/version labels.
Use generic capability image overrides:
export SAFE_REVERSER_CAPABILITY_IMAGE_STATIC_CORE=safe-android-reverser:ci
export SAFE_REVERSER_CAPABILITY_IMAGE_FRAMEWORK_FLUTTER=safe-android-reverser-flutter:ciThe generic naming convention is:
SAFE_REVERSER_CAPABILITY_IMAGE_<CAPABILITY_ID>
with - converted to _ and uppercase.
Do not add new release tooling around pre-0.3 single-image variables.
A milestone release branch is not the place to finish architecture work.
Before preparing 0.3.0 release metadata:
- final platform PR is merged;
- exact-head CI was green;
- architecture/security review passed;
- senior milestone acceptance is recorded;
- required release docs match implementation;
- known Blocker/High findings are closed.
Create a dedicated release branch from accepted master and select a new semver.
Update:
plugins/safe-android-reverser/VERSION
plugins/safe-android-reverser/.claude-plugin/plugin.json
.claude-plugin/marketplace.json
README/docs release references when applicable
Do not reuse an already-published version.
At minimum:
python3 scripts/check_release_consistency.py
PYTHONPATH=plugins/safe-android-reverser/lib \
python3 plugins/safe-android-reverser/tests/test_platform_architecture.py
PYTHONPATH=plugins/safe-android-reverser/lib \
python3 plugins/safe-android-reverser/tests/test_public_operation_contract.py
PYTHONPATH=plugins/safe-android-reverser/lib \
python3 plugins/safe-android-reverser/tests/test_cross_worker_contracts.py
PYTHONPATH=plugins/safe-android-reverser/lib \
python3 plugins/safe-android-reverser/tests/test_runtime_image_pinning.py
bash sandbox/test_wrapper.shRun static-core and Flutter capability-specific suites as well.
The CI run must correspond to the exact commit intended for release/tagging.
A green run from an earlier branch head is not sufficient.
Before a production release that changes runtime-cache resolution, verify at least one controlled exact-runtime cache build end-to-end:
- deterministic cache tag;
- Dart version/snapshot/arch/OS/compressed-pointer identity;
- full Blutter commit;
- Capability API;
- Worker ABI;
- runtime-cache schema;
- expected OCI provenance labels;
- immutable image execution readiness.
This does not require building every possible Dart runtime before release; cache misses remain an explicit supported state.
From Flutter cache schema 3 onward, the controlled build request contains the provider-independent runtime identity and every exact identity field. The stable request identity identifies the cache; a separate private attempt identity identifies only the current bounded build attempt. Workflow run names carry both identities so reconciliation cannot attach a retry to a historical run, while concurrency by stable request identity remains defense-in-depth rather than an idempotency claim. Provider workflow/run identifiers, attempt identity and authoritative creation metadata remain private. A successful workflow run is insufficient until Runtime Driver verifies the published labels, source revision, and immutable image ID.
Schema-2 cache images are not retagged or overwritten. Rebuild the same compatible Dart runtime under schema 3 so the OS label and new deterministic identity are present.
VERSION="$(tr -d '[:space:]' < plugins/safe-android-reverser/VERSION)"
git tag -a "safe-v$VERSION" -m "Safe Android Reverser $VERSION"
git push origin "safe-v$VERSION"The tag must resolve to the exact tree that passed release CI.
The release workflows should rerun required validation and publish semver images only for a matching safe-vX.Y.Z tag.
For required baseline capabilities, 0.3 should publish at least:
ghcr.io/salingnh/safe-android-reverser:X.Y.Z
ghcr.io/salingnh/safe-android-reverser:sha-<release-commit>
ghcr.io/salingnh/safe-android-reverser-flutter:X.Y.Z
ghcr.io/salingnh/safe-android-reverser-flutter:sha-<release-commit>
Release workflows must refuse to overwrite an existing semver image.
For each required baseline image verify:
org.opencontainers.image.version = X.Y.Z
io.safe-reverser.capability.id = expected capability
io.safe-reverser.capability.api = 1
io.safe-reverser.worker.abi = 1
org.opencontainers.image.revision = expected release commit (where configured)
Also verify the runtime returns a canonical immutable image ID.
After required semver images are available, merge the already-tested release change according to repository merge policy.
Avoid a window where marketplace/plugin metadata advertises a version whose required images do not exist.
If policy requires release tags to be reachable from master, use a merge strategy that preserves/reaches the exact tagged release tree. Do not create a materially different tree under the same semver.
If plugin metadata is visible first, users can install a version whose required workers are not yet available.
Correct ordering:
exact release commit tested
↓
safe-vX.Y.Z tag
↓
required semver images published/verified
↓
marketplace-visible release merged
scripts/check_release_consistency.py is an architecture/release gate, not merely a version-string check.
It should verify invariants including:
- valid canonical VERSION;
- plugin/marketplace version equality;
- exactly one public
safe-android-reverserMCP; - legacy dual-MCP/server files do not return;
- canonical static worker path exists;
- launcher delegates image lifecycle to Runtime Driver;
- launcher does not create data root before Path SDK validation;
- required baseline capability manifests exist and validate;
- additional compatible capability manifests are not rejected solely for being additional;
- operation ownership does not collide;
- Capability API/Worker ABI constants agree across host/workers/cache identity;
- worker images carry required labels;
- immutable image-ID execution markers remain present;
- workflows publish
sha-*development references and derive semver only fromsafe-v*tags; - tag version equals
VERSION.
A release may define required baseline capabilities, for example 0.3:
static-core
framework-flutter
Release gates should require that baseline as a subset, not require that it is the complete forever list of capability manifests.
This allows later compatible optional/native/framework/security capability modules without rewriting central architecture gates merely because the set grew.
Exact runtime caches are not normal plugin semver images.
They use deterministic identities bound to the runtime/analyzer ABI inputs. Never retag an incompatible runtime under an existing cache identity.
If any identity input changes in a compatibility-significant way, increment the relevant cache/ABI contract so a new immutable identity is produced.
Never mutate a published semver image.
Example:
0.3.0 contains a release defect
↓
fix source
↓
release 0.3.1
A plugin rollback can select an older marketplace/plugin release whose immutable images remain available.
After release:
- install/update through the documented plugin path;
- run
/mcp; - call
healthandlist_capabilities; - verify required capability states and immutable image IDs;
- fingerprint a known native Android fixture;
- fingerprint/analyze a known Flutter fixture;
- verify a runtime cache miss is explicit rather than triggering an in-sandbox build;
- update roadmap release status and start the next milestone only after acceptance is complete.