151 lines
6.9 KiB
Markdown
151 lines
6.9 KiB
Markdown
# ChatGPT Bridge v2 Control Plane Convergence Design
|
|
|
|
Date: 2026-08-09
|
|
Task: `TASK-P0-CHATGPT-BRIDGE-V2-CONTROL-PLANE-CONVERGENCE-20260809`
|
|
Repository: `aios/aios`
|
|
Approved development base: `2e8fa22989808a448065d1d76b5b18948774a637`
|
|
Target branch: `agent/p0-chatgpt-bridge-v2-control-plane-convergence-20260809`
|
|
|
|
## Scope and authority
|
|
|
|
This design converges the ChatGPT GitOps Bridge, the existing Authorized Task Writer, the continuation lease protocol, the Durable GitOps Job Controller, and immutable control-plane runtime identity.
|
|
|
|
The development base is exact and must never be replaced with a dynamically resolved `HEAD`, `latest`, or `main`. If Authority `refs/heads/main` differs from the approved OID before the first governed writer push, execution fails with `BASE_OID_CHANGED`.
|
|
|
|
This task does not authorize production changes. The following remain immutable:
|
|
|
|
- Production Baseline `V2R1C7`.
|
|
- Production target OID `c7adece1cc8beffe7c718d53c775898b45d6c7f8`.
|
|
- Production tag OID `82792347937c0df59a8e02d6162775252bcad2e2`.
|
|
- Production Registry, services, deployment state, runtime, tags, and release evidence.
|
|
- Authority `main`.
|
|
|
|
Force push, history rewrite, direct main push, production mutation, tag mutation, baseline mutation, and secret commits are always denied.
|
|
|
|
## Immutable control-plane runtime identity
|
|
|
|
A control-plane release is installed into a versioned immutable directory equivalent to:
|
|
|
|
```text
|
|
/opt/aios/gitops-control-plane/<release-id-or-oid>/
|
|
```
|
|
|
|
The release manifest binds:
|
|
|
|
```text
|
|
control_plane_release_version
|
|
control_plane_target_oid
|
|
artifact_sha256
|
|
runtime_path
|
|
bridge_schema_version
|
|
repository_identity
|
|
authoritative_git_dir
|
|
deployment_state
|
|
```
|
|
|
|
The validator is independent from the mutable Git workspace. It rejects execution when the runtime path is a workspace/worktree, the observed runtime commit or artifact digest differs from the manifest, the repository identity is not `aios/aios`, the authoritative Git directory is absent or mismatched, or the Bridge schema version is absent or unsupported.
|
|
|
|
Every failure is fail closed with `CONTROL_PLANE_RUNTIME_DRIFT`. No fallback to a mutable workspace is permitted. The installer and systemd template are staging-safe; this task may install and restart only a staging/test service.
|
|
|
|
## Bridge v2 adapter
|
|
|
|
The Bridge schema identity is `aios.chatgpt-gitops-bridge.v2`. It is independent from the production baseline, control-plane release version, and runtime release commit.
|
|
|
|
The Bridge exposes:
|
|
|
|
- `getRuntimeStatus`
|
|
- `getGovernedWriteCapabilities`
|
|
- `createGovernedTask`
|
|
- `acquireWriterLease`
|
|
- `commitFileGoverned`
|
|
- `commitFilesGoverned`
|
|
- `getGitOpsJob`
|
|
- `resumeGitOpsJob`
|
|
- `reconcileGitOpsJob`
|
|
|
|
The adapter reuses existing mechanisms and does not create a second writer, lease protocol, branch state store, job database, or direct Git mutation path.
|
|
|
|
## Governed task and lease flow
|
|
|
|
`createGovernedTask` binds an exact task ID, repository, approved base OID, non-main branch, risk, and description. Existing branches are read back and bound to their observed full OID. Idempotent replay returns the original binding; conflicting replay fails closed.
|
|
|
|
`acquireWriterLease` uses `WriterLeaseRequestV2`. Continuation uses:
|
|
|
|
```text
|
|
branch_mode=CONTINUE_EXISTING
|
|
expected_branch_oid=<full OID>
|
|
generation=<monotonic integer>
|
|
create_target_branch=false
|
|
worktree_mode=detached_at_expected_head
|
|
cas_ref_update_required=true
|
|
```
|
|
|
|
Credentials remain server-side and never appear in responses, Git, durable job metadata, or logs.
|
|
|
|
## Governed commit flow
|
|
|
|
`commitFileGoverned` and `commitFilesGoverned` submit work to the existing `GitOpsJobController` and `JobStore`. The server computes payload digests. Raw file content is stored only in the content-addressed payload domain. Secret scanning, protected-path policy, repository binding, lease validation, and branch authorization run before side effects.
|
|
|
|
`commitFilesGoverned` is one atomic Git commit and enforces bounded file count, per-file size, and total payload size. Any failure leaves no partial commit or ref update.
|
|
|
|
All ref updates use compare-and-swap. Stale `expected_branch_oid` returns conflict and never triggers automatic rebase. After push, Authority and remote Gitea refs are independently read and must equal the resulting commit OID.
|
|
|
|
## Durable job lifecycle
|
|
|
|
Job reads return only non-sensitive metadata: `job_id`, `state`, `revision`, `side_effect_state`, `retryable`, `binding`, and `receipt_summary`.
|
|
|
|
Terminal jobs cannot be changed by ordinary resume. Resume requires `job_id` and `expected_revision` and uses revision CAS. Reconciliation is observation-first: for `UNKNOWN`, `RECONCILIATION_REQUIRED`, or `REMOTE_PUSH_PENDING`, local, Authority, and remote refs are read before state changes. A blind repeated push is never reconciliation.
|
|
|
|
## Legacy behavior
|
|
|
|
Legacy writes remain disabled while governed writes are enabled:
|
|
|
|
```text
|
|
legacy_writes_enabled=false
|
|
governed_writes_enabled=true
|
|
```
|
|
|
|
The global `AIOS_GITOPS_WRITES_ENABLED` flag is never enabled as the solution. Legacy operations remain temporarily visible for compatibility and diagnostics, but return:
|
|
|
|
```json
|
|
{
|
|
"error": "LEGACY_WRITE_DISABLED",
|
|
"replacement": "createGovernedTask",
|
|
"governed_writes_available": true
|
|
}
|
|
```
|
|
|
|
## OpenAPI convergence
|
|
|
|
`docs/gitops/openapi-chatgpt-actions.yaml` is the canonical Bridge v2 schema and integrates the Authorized Task Writer fragment. The canonical CAS field is `expected_branch_oid`. `expected_head_oid` may be accepted only at an explicit deprecated adapter boundary.
|
|
|
|
Contract tests require exact equality between OpenAPI required fields, runtime parser required fields, and generated GPT Action schema required fields.
|
|
|
|
## Acceptance
|
|
|
|
Automated coverage includes runtime path/OID/digest/repository drift, exact task/branch/OID/lease/CAS behavior, job DB failure, restart during remote verification, remote timeout, response loss after remote success, idempotency replay/conflict, concurrent branch movement, unauthorized or main branch writes, protected paths, secret-like payloads, disabled governed writer, missing/expired lease, wrong repository identity, and observation-first reconciliation.
|
|
|
|
The staging sequence is:
|
|
|
|
```text
|
|
getRuntimeStatus
|
|
getGovernedWriteCapabilities
|
|
createGovernedTask
|
|
acquireWriterLease
|
|
commitFilesGoverned
|
|
getGitOpsJob
|
|
verify Authority branch ref
|
|
verify remote Gitea branch ref
|
|
restart staging control-plane service
|
|
getRuntimeStatus
|
|
acquire continuation lease
|
|
second governed commit
|
|
verify remote ref again
|
|
```
|
|
|
|
Completion requires all tests, staging restart continuation, Authority/remote OID equality, unchanged production invariants, no force push, no tag rewrite, no direct main push, and no secret commit.
|
|
|
|
## Implementation boundaries
|
|
|
|
Implementation is limited to the Bridge, existing writer and job-controller adapters, runtime identity/installer, staging systemd template, OpenAPI documents, tests, and engineering evidence. Hermes Adapter integration and production cutover are outside this task and require separate approval.
|