Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/profile-consistency.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
name: Profile consistency

on:
schedule:
- cron: "19 7 * * *"
workflow_dispatch:
pull_request:
paths:
- ".github/workflows/profile-consistency.yml"
- "LAUNCH_PLAN.md"
- "REPOSITORY_LIFECYCLE.md"
- "profile/README.md"
- "production-lifecycle-admissions.json"
- "production-lifecycle-policy.json"
- "README.md"
- "repository-lifecycle.yml"
- "scripts/check_profile.py"
- "scripts/validate_production_lifecycle.py"
- "schemas/production-lifecycle-admissions.schema.json"
- "schemas/production-lifecycle-evidence-manifest.schema.json"
- "schemas/production-lifecycle-evidence-summary.schema.json"
- "schemas/production-lifecycle-policy.schema.json"
- "tests/test_production_lifecycle.py"
push:
branches: [main]
paths:
- ".github/workflows/profile-consistency.yml"
- "LAUNCH_PLAN.md"
- "REPOSITORY_LIFECYCLE.md"
- "profile/README.md"
- "production-lifecycle-admissions.json"
- "production-lifecycle-policy.json"
- "README.md"
- "repository-lifecycle.yml"
- "scripts/check_profile.py"
- "scripts/validate_production_lifecycle.py"
- "schemas/production-lifecycle-admissions.schema.json"
- "schemas/production-lifecycle-evidence-manifest.schema.json"
- "schemas/production-lifecycle-evidence-summary.schema.json"
- "schemas/production-lifecycle-policy.schema.json"
- "tests/test_production_lifecycle.py"

permissions:
contents: read
Expand All @@ -30,5 +49,48 @@ jobs:
timeout-minutes: 5
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Test Production lifecycle admission failures
run: python3 -m unittest discover -s tests -p 'test_*.py'
- name: Refuse Production release-ledger rollback
if: github.event_name == 'pull_request' || github.event_name == 'push'
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
if git cat-file -e "$BASE_SHA:production-lifecycle-admissions.json"; then
git show "$BASE_SHA:production-lifecycle-admissions.json" > "$RUNNER_TEMP/previous-production-lifecycle-admissions.json"
elif git cat-file -e "$BASE_SHA:production-lifecycle-policy.json"; then
echo "REFUSED: the trusted base has policy but no admission ledger" >&2
exit 1
else
printf '{"admissions":[]}\n' > "$RUNNER_TEMP/previous-production-lifecycle-admissions.json"
fi
python3 scripts/validate_production_lifecycle.py --previous-admissions "$RUNNER_TEMP/previous-production-lifecycle-admissions.json"
- name: Validate product truth and links
run: python3 scripts/check_profile.py

report-expired-admission:
needs: validate-profile
if: >-
${{ always() && needs.validate-profile.result == 'failure' &&
(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') }}
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: File or update the Production lifecycle failure
env:
GH_TOKEN: ${{ github.token }}
run: |
TITLE="Production lifecycle admission needs attention"
BODY="The scheduled evidence-gated lifecycle check failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

An admission record or its current evidence is invalid. Consumers derive Production from the latest exact signed release and must fail closed."
EXISTING=$(gh issue list --repo "${{ github.repository }}" --state open \
--search "in:title \"$TITLE\"" --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
gh issue comment "$EXISTING" --repo "${{ github.repository }}" --body "$BODY"
else
gh issue create --repo "${{ github.repository }}" --title "$TITLE" --body "$BODY"
fi
54 changes: 52 additions & 2 deletions REPOSITORY_LIFECYCLE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpenAdapt Repository Lifecycle Registry

Last reviewed: 2026-07-27
Last reviewed: 2026-08-18

This public registry separates the product from experiments and records the
intended lifecycle of organization repositories. It does not authorize moving
Expand All @@ -14,6 +14,7 @@ The machine-readable source is [`repository-lifecycle.yml`](repository-lifecycle

| Status | Meaning |
|--------|---------|
| **Production** | Exact latest release in the signed Production channel with an active, unexpired, non-revoked, independently attested acceptance admission |
| **Beta** | Active product surface with compatibility intent, but not a blanket production-readiness claim |
| **Experimental** | Active prototype or optional component with no production support promise |
| **Research** | Evidence-generating work, not required by the product runtime |
Expand All @@ -24,7 +25,56 @@ The machine-readable source is [`repository-lifecycle.yml`](repository-lifecycle
| **Deprecated** | Superseded; migration fixes only, no new integrations |
| **Archived** | Historical and read-only |

## Current Product Boundary
## Production Admission

Production is a derived per-release state. It is not a static repository label.
A person cannot create it by changing a table or repository description. The canonical
[`production-lifecycle-policy.json`](production-lifecycle-policy.json) names
the seven eligible targets and their required release artifacts. The
[`production-lifecycle-admissions.json`](production-lifecycle-admissions.json)
file contains only admissions that pass the machine validator.

Each admission binds the exact public package release or deployment identity,
the complete required artifact inventory and hashes, and an independently
attested remote-safe evidence summary. The summary binds the private Cloud
acceptance certificate by schema, digest, and signer-provenance digest. It does
not publish the private certificate or its location. The summary also binds an
immutable public evidence-manifest URL and digest. A private Cloud deployment
uses an opaque release identity and digest. It does not require a public source
or artifact URL. Public artifacts use a pinned authority. The validator checks
current PyPI metadata, immutable GitHub release metadata, or content-addressed
managed evidence before it derives Production.

The signer-provenance digest uses the domain `OpenAdapt production certificate
signer provenance v1\0`. Its canonical input is the normalized, verified Cloud
GitHub provenance plus the qualification admission signer-registry digest and
revision. The private v2 evidence identity must bind the exact target release
or deployment and its complete artifact inventory. Each target has a distinct
claim scope. Evidence for one target cannot admit a different target. The
public evidence manifest must bind the same target, scope, policy, release,
artifact inventory, evidence identity, qualification, failure taxonomy,
reliability counts, oracle, trial inventory, and immutable retention record.

A qualified workflow is one exact compiled workflow version that passed its
declared qualification contract on its bound execution environment. The signed
qualification identity binds the workflow bundle, runtime release, dependency
set, environment, input schema, policy, required identity checks, required
effect checks, and verification rules. A run gate must reject an absent,
expired, revoked, or mismatched qualification. A new workflow version or a
change to a bound input requires a new qualification. A Production runtime must
accept only these exact qualified workflow identities.

Each target has an append-only hash chain of signed Production release
identities. The highest sequence is current. A new release cannot reuse an old
release identity. If the latest admission expires or is revoked, Production is
empty for that target. The validator does not fall back to an older release.
Static Production membership is forbidden. Consumers derive current Production
at read time from the signed admission, its expiry, and its revocation state.

## Baseline Lifecycle

The baseline applies when a target does not have a current Production
admission. The admission overlay does not rewrite repository history.

| Repository | Lifecycle | Role |
|------------|-----------|------|
Expand Down
6 changes: 6 additions & 0 deletions production-lifecycle-admissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "schemas/production-lifecycle-admissions.schema.json",
"schema_version": "openadapt.production-lifecycle-admissions/v1",
"policy_sha256": "sha256:e1444a08ce6b16736168cce027ce9d48abb2e0e246fc0cd79c0772fa8e423e11",
"admissions": []
}
121 changes: 121 additions & 0 deletions production-lifecycle-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"$schema": "schemas/production-lifecycle-policy.schema.json",
"schema_version": "openadapt.production-lifecycle-policy/v1",
"revision": 1,
"maximum_admission_days": 30,
"summary_authority": {
"repository": "OpenAdaptAI/openadapt-evals",
"workflow": ".github/workflows/production-lifecycle-evidence.yml",
"source_ref": "refs/heads/main",
"oidc_issuer": "https://token.actions.githubusercontent.com",
"certificate_identity": "https://github.com/OpenAdaptAI/openadapt-evals/.github/workflows/production-lifecycle-evidence.yml@refs/heads/main",
"summary_schema_version": "openadapt.production-lifecycle-evidence-summary/v1",
"private_certificate_schema_version": "openadapt.execute-live-acceptance-record/v2",
"evidence_manifest_schema_version": "openadapt.production-acceptance/v1",
"acceptance_policy_sha256": "sha256:9b1fe55bc6796ae0a46960ca4aa335d88de60b0562c383afa1e85fa0a0c204b8",
"release_identity_schema_version": "openadapt.monotonic-production-release/v1",
"production_channel": "production",
"signer_provenance_digest_domain": "OpenAdapt production certificate signer provenance v1\u0000"
},
"targets": [
{
"id": "agent",
"display_name": "OpenAdapt Agent",
"lifecycle_scope": "repository",
"lifecycle_subject": "openadapt-agent",
"source_repository": "OpenAdaptAI/openadapt-agent",
"release_kind": "public_package",
"required_claim_scope": "qualified_agent_bridge_release",
"required_artifact_kinds": ["sdist", "wheel"],
"package_index_project": "openadapt-agent",
"artifact_authority_by_kind": {"sdist": "pypi", "wheel": "pypi"}
},
{
"id": "capture",
"display_name": "OpenAdapt Capture",
"lifecycle_scope": "repository",
"lifecycle_subject": "openadapt-capture",
"source_repository": "OpenAdaptAI/openadapt-capture",
"release_kind": "public_package",
"required_claim_scope": "qualified_native_recorder_release",
"required_artifact_kinds": ["sdist", "wheel"],
"package_index_project": "openadapt-capture",
"artifact_authority_by_kind": {"sdist": "pypi", "wheel": "pypi"}
},
{
"id": "cloud",
"display_name": "OpenAdapt Cloud",
"lifecycle_scope": "repository",
"lifecycle_subject": "openadapt-cloud",
"source_repository": "OpenAdaptAI/openadapt-cloud",
"release_kind": "private_deployment",
"required_claim_scope": "qualified_workflow_control_plane_deployment",
"required_artifact_kinds": [],
"package_index_project": null,
"artifact_authority_by_kind": {}
},
{
"id": "desktop",
"display_name": "OpenAdapt Desktop",
"lifecycle_scope": "repository",
"lifecycle_subject": "openadapt-desktop",
"source_repository": "OpenAdaptAI/openadapt-desktop",
"release_kind": "public_package",
"required_claim_scope": "qualified_native_workflow_desktop_release",
"required_artifact_kinds": [
"linux-installer",
"macos-installer",
"sdist",
"wheel",
"windows-installer"
],
"package_index_project": "openadapt-desktop",
"artifact_authority_by_kind": {
"linux-installer": "github_release",
"macos-installer": "github_release",
"sdist": "pypi",
"wheel": "pypi",
"windows-installer": "github_release"
}
},
{
"id": "docs",
"display_name": "OpenAdapt Documentation",
"lifecycle_scope": "public_surface",
"lifecycle_subject": "docs.openadapt.ai",
"source_repository": "OpenAdaptAI/openadapt-ops",
"release_kind": "public_deployment",
"required_claim_scope": "production_documentation_deployment",
"required_artifact_kinds": ["deployment-manifest", "site-archive"],
"package_index_project": null,
"artifact_authority_by_kind": {
"deployment-manifest": "managed_evidence",
"site-archive": "managed_evidence"
}
},
{
"id": "flow",
"display_name": "OpenAdapt Flow",
"lifecycle_scope": "repository",
"lifecycle_subject": "openadapt-flow",
"source_repository": "OpenAdaptAI/openadapt-flow",
"release_kind": "public_package",
"required_claim_scope": "qualified_workflow_runtime_release",
"required_artifact_kinds": ["sdist", "wheel"],
"package_index_project": "openadapt-flow",
"artifact_authority_by_kind": {"sdist": "pypi", "wheel": "pypi"}
},
{
"id": "openadapt",
"display_name": "OpenAdapt",
"lifecycle_scope": "repository",
"lifecycle_subject": "OpenAdapt",
"source_repository": "OpenAdaptAI/OpenAdapt",
"release_kind": "public_package",
"required_claim_scope": "qualified_workflow_launcher_release",
"required_artifact_kinds": ["sdist", "wheel"],
"package_index_project": "openadapt",
"artifact_authority_by_kind": {"sdist": "pypi", "wheel": "pypi"}
}
]
}
9 changes: 7 additions & 2 deletions repository-lifecycle.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
schema_version: 1
reviewed_on: 2026-07-27
schema_version: 2
reviewed_on: 2026-08-18
canonical_product:
launcher: OpenAdapt
engine: openadapt-flow
Expand All @@ -25,6 +25,7 @@ public_metadata:
Beta local bridge exposing governed OpenAdapt workflows as MCP tools and
Agent Skills; halts remain halts.
lifecycle:
production: []
beta:
- OpenAdapt
- openadapt-flow
Expand Down Expand Up @@ -70,3 +71,7 @@ lifecycle:
- openadapt-gitbook
- OpenReflector
- OpenAdapter
public_surfaces:
production: []
beta:
- docs.openadapt.ai
Loading