477 lines
25 KiB
Markdown
477 lines
25 KiB
Markdown
# CI Control Plane Recovery Design
|
|
|
|
- **Date:** 2026-07-25
|
|
- **Status:** Approved
|
|
- **Scope:** repository control-plane recovery, Gitea Actions enablement, Gradle/CI gates,
|
|
container build context, dependency automation, and documentation parity
|
|
- **Depends on:**
|
|
[`2026-07-20-harness-policy-engine-design.md`](2026-07-20-harness-policy-engine-design.md)
|
|
- **Current revision audited:** `821fe00c323b5335980f271c7ee47b92ac2168f2`
|
|
- **Task-packet state:** unavailable. `.harness/validators/resolve_task.py` and its policy inputs
|
|
are absent from the audited revision, so no task-packet hash or formal evidence profile can be
|
|
produced before control-plane recovery.
|
|
|
|
## 1. Problem Statement
|
|
|
|
The repository describes a high-assurance CI and architecture-governance control plane, but the
|
|
audited Git tree does not contain the hidden root paths that implement it. The current revision
|
|
contains no `.harness`, `.agents`, `.claude`, `.codex`, or `.github` tree. It also lacks the root
|
|
`.tool-versions`, `.trivyignore.yaml`, and `.gitattributes` contracts referenced by the tracked
|
|
guidance and Gradle build.
|
|
|
|
This is not a Gradle wrapper failure. The tracked wrapper downloads and starts Gradle 9.0.0 under
|
|
Java 21, but every project task stops while evaluating `src/settings.gradle` because
|
|
`.harness/project/modules.yaml` is missing. The same missing registry also prevents the architecture
|
|
dependency gate and task-packet resolution from running.
|
|
|
|
The CI host is Gitea 1.27.0, not GitHub. The public repository API reports `has_actions: false`, so
|
|
the repository Actions unit is disabled. An unauthenticated request to the runner API returns
|
|
`401`, which proves that runner state must be checked with repository or administrator
|
|
authorization; it does not prove that a usable runner exists. Gitea Actions requires both the
|
|
repository Actions unit and an online runner.
|
|
|
|
The container build has an additional independent defect. Compose and both Dockerfile examples use
|
|
`src/` as the build context, while Gradle resolves the registry from the repository root. Even after
|
|
the hidden assets are restored, a build with the current context cannot copy the registry into the
|
|
builder.
|
|
|
|
## 2. Audit Baseline
|
|
|
|
| Surface | Command or source | Observed result |
|
|
| --- | --- | --- |
|
|
| Git revision | `git rev-parse HEAD` | `821fe00c323b5335980f271c7ee47b92ac2168f2` |
|
|
| Hidden assets | `git cat-file -e HEAD:.harness` and equivalent checks | `.harness`, `.agents`, `.claude`, `.codex`, `.github` absent |
|
|
| Ignore rules | `git check-ignore -v --no-index ...` | exit `1`; missing paths are not ignored |
|
|
| Recoverable local objects | `git fsck --full --no-reflogs --unreachable` | exit `0`; no unreachable objects reported |
|
|
| Gradle launcher | `cd src && ./gradlew --version` | exit `0`; Gradle 9.0.0 and Java 21 |
|
|
| Gradle project task | `cd src && ./gradlew tasks --console=plain` | exit `1`; missing module registry at `src/settings.gradle:12` |
|
|
| Gradle release gate | `cd src && ./gradlew check --console=plain` | exit `1`; same settings failure |
|
|
| Task resolver | `python3 .harness/validators/resolve_task.py ...` | impossible; resolver file absent |
|
|
| Compose syntax | `docker compose -f docker-compose.yml -f docker-compose.local.yml config --quiet` | exit `0` |
|
|
| Gitea version | `GET /api/v1/version` | `1.27.0` |
|
|
| Repository Actions | public repository API | `has_actions: false` |
|
|
| Runner API | unauthenticated runner request | `401`; authorized runner inventory still required |
|
|
|
|
The most recent commit added 971 files over a parent that contained only a two-line README. The
|
|
root tree contains no dot-prefixed entry, while nested files such as `src/.env`,
|
|
`src/.dockerignore`, and `src/.gitignore` were included. This is consistent with a top-level shell
|
|
glob used during copying or staging. That is a falsifiable root-cause hypothesis, not proof of the
|
|
exact command that was used.
|
|
|
|
## 3. Goals
|
|
|
|
1. Prefer byte-for-byte recovery of the authoritative hidden control-plane assets; when that source
|
|
is unavailable or incomplete, require an explicit human reconstruction decision and record new
|
|
provenance without presenting reconstruction as restoration.
|
|
2. Restore the 19-leaf module registry and the harness behavior approved in the 2026-07-20 design.
|
|
3. Make a fresh checkout fail early with a precise control-plane error before Gradle configuration.
|
|
4. Enable repository Actions on Gitea 1.27.0 and provide an isolated, repository-scoped runner.
|
|
5. Keep `.github/workflows` as the canonical workflow directory while preventing an accidental
|
|
`.gitea/workflows` shadow.
|
|
6. Restore a single release-blocking fan-in status and the complementary vulnerability status.
|
|
7. Make public-path, Trivy suppression, dependency-lock, and architecture gates fail closed.
|
|
8. Make Docker builds consume the same root registry without duplicating the registry under `src/`.
|
|
9. Pause Renovate automerge until required CI statuses and lockfile refresh behavior are proven.
|
|
10. Bring README, gate-matrix, workflow, and physical-path claims back into parity.
|
|
|
|
## 4. Non-Goals
|
|
|
|
- This recovery does not change production Java behavior or module boundaries.
|
|
- It does not redesign the 19-leaf registry approved in the 2026-07-20 harness policy design.
|
|
- It does not silently synthesize hidden policy files or present reconstructed content as recovered
|
|
authority.
|
|
- It does not store a Gitea API token, runner registration token, or repository secret in Git.
|
|
- It does not enable deployment to a production environment. Release artifact construction and
|
|
scanning are restored, but a separate deployment decision remains human-owned.
|
|
- It does not re-enable Renovate automerge merely because workflow files exist; branch protection
|
|
and a successful dependency-update exercise are also required.
|
|
|
|
## 5. Governing Invariants
|
|
|
|
### 5.1 Recovery mode is an explicit human decision
|
|
|
|
The original working tree, archive, or source repository that produced the 2026-07-20 harness
|
|
design is the preferred recovery authority. Before copying anything into this repository, the
|
|
recovery source must be inventoried and hashed outside the worktree.
|
|
|
|
The minimum authoritative set is:
|
|
|
|
- `.harness/`
|
|
- `.agents/`
|
|
- `.claude/`
|
|
- `.codex/`
|
|
- `.github/`
|
|
- `.tool-versions`
|
|
- `.trivyignore.yaml`
|
|
- `.gitattributes`
|
|
|
|
The human owner chooses one of two modes and records it before repository writes:
|
|
|
|
**Mode A — authoritative restore.** All minimum paths exist in the recovery source. The executor
|
|
hashes them, copies them byte-for-byte, proves source/destination equality, and preserves their
|
|
native provenance.
|
|
|
|
**Mode B — controlled reconstruction.** The original source is unavailable or incomplete. The
|
|
human records that fact and explicitly authorizes reconstruction from the approved
|
|
[`2026-07-20-harness-policy-engine-design.md`](2026-07-20-harness-policy-engine-design.md),
|
|
[`2026-07-20-harness-policy-engine.md`](../plans/2026-07-20-harness-policy-engine.md), the tracked
|
|
Gradle/module sources, and this design. Reconstructed artifacts receive new hashes and a
|
|
`controlled-reconstruction` provenance record. Schema, renderer parity, mutation coverage, Gradle
|
|
project discovery, and architecture dependency checks must pass before the new artifacts can act as
|
|
authority.
|
|
|
|
The first Mode B inventory covers the reconstructed harness and generated platform assets only.
|
|
After Tasks 3-6 and every later change to a covered path are final, the executor regenerates one
|
|
complete, sorted SHA-256 inventory for `.harness`, `.agents`, `.claude`, `.codex`, `.github`,
|
|
`.tool-versions`, `.trivyignore.yaml`, `.gitattributes`, `.dockerignore`, and
|
|
`docs/security/public-paths-snapshot.txt`. The provenance record names that final evidence path.
|
|
Only this post-change inventory is used for the human handoff.
|
|
|
|
Implementation stops only until the human chooses Mode A or Mode B. An incomplete Mode A export
|
|
must never be filled silently. It may instead cause the human to switch the recorded decision to
|
|
Mode B. The tracked `AGENTS.md`, `CLAUDE.md`, and design documents are evidence of intended
|
|
behavior, but reconstructed schemas, agents, registries, and workflows become authoritative only
|
|
after the required new evidence passes.
|
|
|
|
### 5.2 Human-only commit policy
|
|
|
|
Recovery and implementation may leave reviewed changes in the working tree, but agents do not
|
|
stage, commit, amend, or push. A human decides commit boundaries after reviewing recovery hashes,
|
|
generated-file parity, test evidence, and Gitea status checks.
|
|
|
|
### 5.3 One registry and one workflow source
|
|
|
|
`.harness/project/modules.yaml` remains the only module-edge and focused-command registry.
|
|
Container builds copy that file from the repository root; they do not create a second copy under
|
|
`src/`.
|
|
|
|
`.github/workflows` remains the canonical workflow directory because the repository documentation
|
|
and portability contract already point there. Gitea's default `WORKFLOW_DIRS` value is
|
|
`.gitea/workflows,.github/workflows`, and Gitea uses the first directory that exists. Therefore
|
|
`.gitea/workflows` must remain absent unless the project later adopts a generated-mirror design
|
|
with an explicit parity check and a separate approved specification.
|
|
|
|
### 5.4 Fail closed before expensive work
|
|
|
|
CI runs a repository control-plane preflight before invoking build or container work. Missing
|
|
policies, workflow shadowing, a missing committed public-path baseline, or an incomplete structured
|
|
Trivy contract fail immediately. Once Java/Gradle is available, that same blocking preflight runs
|
|
`verifyTrivyignore`; the vulnerability scanner must explicitly consume `.trivyignore.yaml`.
|
|
|
|
## 6. Target Architecture
|
|
|
|
```text
|
|
authoritative hidden-asset export
|
|
|
|
|
v
|
|
recovery inventory + SHA-256 comparison
|
|
|
|
|
v
|
|
.harness/.agents/.claude/.codex/.github restored
|
|
|
|
|
v
|
|
control-plane preflight
|
|
|-- required paths
|
|
|-- generated-agent parity
|
|
|-- canonical workflow directory
|
|
|-- committed security baselines
|
|
`-- task-packet resolver availability
|
|
|
|
|
v
|
|
resolved high-risk CI/deployment task packet
|
|
|
|
|
+-----------------------------+
|
|
| |
|
|
v v
|
|
Gradle quality gates Docker root-context builds
|
|
|-- dependency locks |-- production bootJar
|
|
|-- architecture edges `-- sample bootJar
|
|
|-- focused/ArchUnit tests
|
|
|-- test/check
|
|
`-- public/env/security contracts
|
|
| |
|
|
+--------------+--------------+
|
|
v
|
|
CI quality release-gate
|
|
+
|
|
dependency-vulnerability required status
|
|
|
|
|
v
|
|
Gitea protected-branch decision
|
|
```
|
|
|
|
## 7. Design Decisions
|
|
|
|
### 7.1 Recovery gate and physical control-plane manifest
|
|
|
|
After Mode A restore parity or Mode B reconstruction evidence passes, the harness gains a small
|
|
physical manifest at `.harness/project/control-plane.yaml`. It lists required files, required
|
|
directories, the canonical workflow directory, and the forbidden shadow directory. The file uses
|
|
JSON syntax, matching the 2026-07-20 design's stdlib-only JSON-as-YAML convention.
|
|
|
|
`.harness/validators/validate_control_plane.py` reads the manifest and reports every missing path in
|
|
one deterministic result. It also rejects `.gitea/workflows`. Its tests live at
|
|
`.harness/tests/test_control_plane.py`.
|
|
|
|
This validator checks physical availability only. It does not duplicate module edges, risk rules,
|
|
or workflow gate semantics. Module semantics stay in `modules.yaml`; the gate matrix stays in
|
|
`.github/ci-gate-matrix.yml`.
|
|
|
|
### 7.2 Gitea Actions and runner control
|
|
|
|
The repository owner enables `Enable Repository Actions` in the repository settings. The public API
|
|
must then report `has_actions: true`.
|
|
|
|
The runner is registered at repository scope, uses an isolated Docker execution mode, and exposes
|
|
the exact `ubuntu-22.04` label used by the workflows. Registration credentials remain in the runner
|
|
host's protected state or secret manager. They never enter workflow YAML, shell history captured by
|
|
CI, Docker image layers, or repository files.
|
|
|
|
An authenticated repository runner inventory must show at least one enabled, online runner before
|
|
the first required workflow is treated as operational. The previous unauthenticated `401` remains
|
|
an expected access-control result.
|
|
|
|
### 7.3 Canonical workflow directory and Gitea shadowing
|
|
|
|
The recovery restores canonical workflows under:
|
|
|
|
- `.github/workflows/ci-quality-gates.yml`
|
|
- `.github/workflows/build-release-supply-chain.yml`
|
|
- `.github/workflows/dependency-vulnerability.yml`
|
|
|
|
No workflow is copied to `.gitea/workflows`. With Gitea's default directory ordering, the mere
|
|
existence of `.gitea/workflows` would cause `.github/workflows` to be ignored. The preflight
|
|
validator makes that shadow a blocking failure.
|
|
|
|
Instance administration must confirm that `[actions].WORKFLOW_DIRS` still contains
|
|
`.github/workflows`. If the instance has a non-default value that excludes it, the administrator
|
|
changes the instance setting or the project stops before enabling required checks.
|
|
|
|
### 7.4 Preflight and release-gate topology
|
|
|
|
`ci-quality-gates.yml` starts with `control-plane-preflight`. No Gradle, test, or Docker job runs
|
|
unless preflight succeeds.
|
|
|
|
The release-blocking fan-out includes:
|
|
|
|
- restored harness unit and mutation suite
|
|
- `validate_modules.py`, renderer parity, policy parity, and `verify-gate-matrix.sh`
|
|
- structured Trivy validation through `verifyTrivyignore`
|
|
- Gradle wrapper launch and Java 21 assertion
|
|
- `verifyDependencyLocks`
|
|
- `verifyCleanArchitectureDependencies`
|
|
- focused ArchUnit coverage
|
|
- `verifyPublicPathSnapshot`
|
|
- `test`
|
|
- `check`
|
|
- production and sample Docker builds
|
|
- reproducible artifact verification when owned by the restored workflow contract
|
|
|
|
The workflow ends with a single `release-gate` job that uses `if: always()` and fails unless every
|
|
release-blocking dependency succeeded. Quarantine remains non-blocking and is intentionally absent
|
|
from the fan-in.
|
|
|
|
Gitea cannot express `needs` across separate workflow files. The dependency vulnerability workflow
|
|
therefore publishes its own blocking status. Protected branches require both the quality
|
|
`release-gate` status and the vulnerability status.
|
|
|
|
### 7.5 Missing contracts
|
|
|
|
The recovery must restore `.tool-versions`, `.gitattributes`, `.trivyignore.yaml`, workflow scripts,
|
|
gate matrix, CODEOWNERS, and vulnerability policy from the authoritative source.
|
|
|
|
The structured empty Trivy contract is retained even when there are no suppressions:
|
|
|
|
```yaml
|
|
vulnerabilities: []
|
|
licenses: []
|
|
misconfigurations: []
|
|
secrets: []
|
|
```
|
|
|
|
The quality preflight and release-tag preflight both run `verifyTrivyignore`. The independent
|
|
vulnerability workflow also runs that verifier and passes
|
|
`trivyignores: .trivyignore.yaml` to the pinned Trivy action, so a present-but-unconsumed or
|
|
malformed suppression file cannot satisfy a required status.
|
|
|
|
`docs/security/public-paths-snapshot.txt` becomes a committed baseline. The current approved value
|
|
derived from `src/.env` is `/api/healthcheck`. A missing baseline is a failure, not an instruction to
|
|
create one during verification.
|
|
|
|
The read-only `verifyPublicPathSnapshot` task compares the committed baseline to `src/.env`.
|
|
Generation moves to a separate, explicitly approved update task. `check` and the quality workflow
|
|
both depend on the read-only verification task.
|
|
|
|
### 7.6 Dependency locks
|
|
|
|
All 19 leaf modules retain Gradle strict locking. CI runs `verifyDependencyLocks` before compile or
|
|
test jobs so an incomplete Renovate update fails with a direct lock error.
|
|
|
|
The only supported lock refresh command remains:
|
|
|
|
```bash
|
|
cd src
|
|
./gradlew resolveAndLockAll --write-locks --console=plain
|
|
```
|
|
|
|
A dependency update is acceptable only when the declaration, all affected `gradle.lockfile` files,
|
|
and the quality gate agree. CI never runs `--write-locks`.
|
|
|
|
### 7.7 Docker root context
|
|
|
|
Compose changes the app build context from `src/` to the repository root and addresses the
|
|
Dockerfile as `src/Dockerfile`. Both Dockerfiles keep the Gradle project at `/build/src` and copy:
|
|
|
|
1. `.harness/project/modules.yaml` to `/build/.harness/project/modules.yaml`;
|
|
2. wrapper, build descriptors, and lockfiles to `/build/src`;
|
|
3. the complete `src/` tree only after dependency verification.
|
|
|
|
A root `.dockerignore` replaces the context role previously owned by `src/.dockerignore`. It
|
|
excludes Git metadata, build output, IDE state, environment files, and secrets, while explicitly
|
|
allowing the module registry, wrapper, build descriptors, lockfiles, and Java/resources trees.
|
|
|
|
This preserves a single registry and makes local Compose, production image, sample image, and CI use
|
|
the same context contract.
|
|
|
|
### 7.8 Renovate safety state
|
|
|
|
`renovate.json` sets `automerge: false` for every update type during recovery. The current comment
|
|
already states that automerge requires trustworthy CI, while the repository currently has no
|
|
operational Actions unit.
|
|
|
|
Limited patch/pin/digest automerge can be reconsidered only after all of the following are observed:
|
|
|
|
1. repository API reports `has_actions: true`;
|
|
2. an authenticated runner inventory reports an online runner;
|
|
3. protected branches require both blocking statuses;
|
|
4. a real Renovate dependency pull request updates strict lock state and passes;
|
|
5. a deliberately stale lockfile fails `verifyDependencyLocks`.
|
|
|
|
The configuration description must also stop claiming that the project has
|
|
`gradle/libs.versions.toml` unless the project separately adopts a version catalog.
|
|
|
|
### 7.9 Documentation parity
|
|
|
|
Root and `src/` README files must point to paths that exist in Git and commands that pass from a
|
|
fresh checkout. The control-plane validator covers required physical paths, and the restored
|
|
README-command and gate-matrix checks cover executable behavior.
|
|
|
|
The documentation must distinguish:
|
|
|
|
- Gitea repository Actions enablement from workflow files;
|
|
- unauthenticated runner API access from authorized runner health;
|
|
- `.github/workflows` as canonical from `.gitea/workflows` as a shadow risk;
|
|
- lock verification from lock regeneration;
|
|
- read-only public-path verification from approved baseline update.
|
|
|
|
## 8. Phased Recovery
|
|
|
|
### Phase 0 — Preserve evidence
|
|
|
|
Capture the current revision, clean status, missing-path evidence, Gitea version, repository
|
|
Actions state, and runner authorization behavior. Hash the authoritative recovery source before
|
|
copying it.
|
|
|
|
### Phase 1 — Establish authority
|
|
|
|
The human chooses Mode A or Mode B. Mode A restores the hidden asset set byte-for-byte and verifies
|
|
source equality. Mode B reconstructs from the two approved 2026-07-20 documents, records new
|
|
provenance/hashes, and runs schema, renderer-parity, mutation, Gradle discovery, and architecture
|
|
checks. The executor then writes a controller-approved overlay to the recorded recovery evidence
|
|
path, invokes the recovered resolver with that file, persists the resolved packet plus packet/rule
|
|
checksums, and proves deterministic re-resolution. Task 3 cannot start until those exact artifacts
|
|
verify.
|
|
|
|
### Phase 2 — Establish fail-fast local gates
|
|
|
|
Add the physical control-plane manifest and validator. Restore missing security contracts and make
|
|
the public-path baseline fail closed. Run harness checks before Gradle.
|
|
|
|
### Phase 3 — Repair build paths
|
|
|
|
Switch Docker to the repository-root context, add the root ignore contract, and verify production
|
|
and sample images.
|
|
|
|
### Phase 4 — Activate Gitea
|
|
|
|
Enable repository Actions, register the isolated runner, confirm workflow directory configuration,
|
|
and run the preflight workflow. Do not configure required statuses until job names are stable and a
|
|
successful run exists.
|
|
|
|
### Phase 5 — Enforce merge controls
|
|
|
|
Enable the quality `release-gate` and vulnerability status as protected-branch requirements. Seed
|
|
negative exercises for a missing required path, public-path drift, forbidden module edge, stale
|
|
lockfile, and failed Docker build.
|
|
|
|
### Phase 6 — Reassess automation
|
|
|
|
Run a real Renovate dependency update with automerge disabled. Re-enable limited automerge only by a
|
|
separate human decision backed by the acceptance evidence.
|
|
|
|
## 9. Verification Strategy
|
|
|
|
1. Mode A hashes match the authoritative export, or Mode B records the human decision, new hashes,
|
|
and `controlled-reconstruction` provenance.
|
|
2. Harness unit, mutation, schema, renderer, and parity tests pass under the selected mode.
|
|
3. Control-plane validator passes on the complete tree and fails on each seeded missing/shadow
|
|
mutation.
|
|
4. Task-packet resolver emits a stable high-risk CI/deployment packet from the recorded overlay;
|
|
the packet and governing-rule checksums verify again at the Task 3 boundary.
|
|
5. Gradle wrapper, project discovery, architecture dependency verification, focused ArchUnit,
|
|
dependency locks, `test`, and `check` pass.
|
|
6. Public-path verification passes with the committed baseline and fails when it is absent or
|
|
changed.
|
|
7. Production and sample Docker images build from repository-root context.
|
|
8. Gitea reports repository Actions enabled and at least one authorized runner online.
|
|
9. The preflight and quality fan-in statuses appear on a real pull request.
|
|
10. Protected branches reject seeded failures.
|
|
11. Renovate config validation and a real dependency update pass without automerge.
|
|
|
|
## 10. Risks and Countermeasures
|
|
|
|
| Risk | Countermeasure |
|
|
| --- | --- |
|
|
| Reconstructed policy differs from the lost authority | Require the human Mode B decision, label provenance as reconstruction, assign new hashes, and require schema/parity/mutation/Gradle evidence |
|
|
| `.gitea/workflows` silently shadows canonical workflows | Block the directory in the physical preflight and confirm instance `WORKFLOW_DIRS` |
|
|
| Runner can expose host Docker authority | Use a repository-scoped isolated runner, restrict fork execution, and keep registration credentials outside jobs |
|
|
| Workflow exists but repository Actions remains disabled | Require API `has_actions: true` and a real run before branch-protection setup |
|
|
| Required status name changes and bypasses protection | Keep stable job names in the gate matrix and verify protection after workflow changes |
|
|
| Public-path baseline is regenerated in CI | Separate update and verify tasks; verification fails when the committed file is missing |
|
|
| Docker root context sends secrets | Root `.dockerignore` excludes environment/secret paths and CI checks the context contract |
|
|
| Renovate updates declarations without strict locks | Run `verifyDependencyLocks` before tests and keep automerge disabled through a real update exercise |
|
|
| Restored workflows assume GitHub-only behavior | Exercise every event, context, action, and fan-in on Gitea 1.27.0 before making the status required |
|
|
|
|
## 11. Acceptance Criteria
|
|
|
|
- Mode A has a byte-identical authoritative inventory, or Mode B has a human-recorded reconstruction
|
|
decision, new provenance, preliminary hashes, and a post-change complete hash inventory.
|
|
- The 2026-07-20 harness registry, validators, generated agents, mutation suite, and parity checks
|
|
pass under the selected mode.
|
|
- A stable task packet is resolved after recovery; no implementation-complete claim relies on the
|
|
pre-recovery state. Its overlay, output packet, packet checksum, and rule checksums are retained in
|
|
the recovery evidence directory.
|
|
- Fresh checkout control-plane preflight reports no missing required path.
|
|
- `.gitea/workflows` is absent and `.github/workflows` is recognized by the Gitea instance.
|
|
- Repository API reports `has_actions: true`.
|
|
- An authorized runner inventory reports an enabled online runner with the workflow label.
|
|
- Gradle `projects`, dependency locks, architecture gates, focused tests, `test`, and `check` pass.
|
|
- Missing or changed public-path baseline fails read-only verification.
|
|
- Production and sample images build from repository-root context without a duplicated registry.
|
|
- The quality `release-gate` and vulnerability status are required on the protected branch.
|
|
- Release-blocking preflights run the full harness unit/mutation, module validation, renderer/parity,
|
|
gate-matrix, and structured Trivy checks; Trivy explicitly consumes `.trivyignore.yaml`.
|
|
- Renovate automerge remains disabled until the explicit five-part re-enable condition is met.
|
|
- README, gate matrix, workflow jobs, and physical repository paths agree.
|
|
- No agent stages, commits, amends, or pushes the recovery.
|
|
|
|
## 12. External Authorities
|
|
|
|
- [Gitea Actions quick start](https://docs.gitea.com/usage/actions/quickstart): repository Actions
|
|
enablement, runner requirement, and the `.gitea/workflows` quick-start location.
|
|
- [Gitea configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet):
|
|
`[actions].ENABLED` and the default
|
|
`WORKFLOW_DIRS=.gitea/workflows,.github/workflows` first-existing-directory behavior.
|
|
- [Gitea runner documentation](https://docs.gitea.com/usage/actions/act-runner): repository-scoped
|
|
registration, runner modes, credential handling, and Docker isolation trade-offs.
|