diff --git a/.custodian-brief.md b/.custodian-brief.md deleted file mode 100644 index 319d8f6..0000000 --- a/.custodian-brief.md +++ /dev/null @@ -1,24 +0,0 @@ - -# Custodian Brief — rail-kubernetes - -**Domain:** financials -**Last synced:** 2026-07-25 16:56 UTC -**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* - -## Active Workstreams - -### Bootstrap rail-kubernetes and import the wave-1 contract -Progress: 1/4 done | workplan_id: `1f2254f5-a873-46fc-a77c-bc725eeaaeb8` - -**Open tasks:** -- ! T03 - Prepare the compatibility handoff from `railiance-cluster` `18140d90` -- ► T02 - Import the reviewed generic contract material `148276a2` -- ► T04 - Register `rail-kubernetes` in State Hub and Fabric `d78b5712` - ---- -## MCP Orientation (when available) - -If the state-hub MCP server is reachable, call: -`get_domain_summary("financials")` -This provides richer cross-domain context. -If the MCP call fails, use this file as your orientation source. diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 52b0764..0000000 --- a/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -Thumbs.db -__pycache__/ -*.pyc -.venv/ -venv/ -env/ diff --git a/.repo-classification.yaml b/.repo-classification.yaml deleted file mode 100644 index 0fb3609..0000000 --- a/.repo-classification.yaml +++ /dev/null @@ -1,18 +0,0 @@ -repo_classification: - standard: Repo Classification Standard - version: "1.0" - classified_at: "2026-07-25" - classified_by: agent - category: project - domain: financials - secondary_domains: - - infotech - capability_tags: - - platform - - operations - business_stake: - - technology - - operations - business_mechanics: - - coordination - - operation diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index b1d50d5..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,41 +0,0 @@ -# rail-kubernetes — Agent Instructions - -## Repo Identity - -**Purpose:** Default Railiance execution rail for generic -workload-on-Kubernetes semantics. - -**Domain:** financials -**Repo slug:** rail-kubernetes -**Topic slug:** railiance -**Workplan prefix:** `RAIL-K8S-WP-` - ---- - -## Session Protocol - -**Start:** -1. Read `README.md`, `INTENT.md`, and `SCOPE.md` -2. Review active work in `workplans/` -3. Re-read the current rail declaration in `declarations/rail.yaml` - -**During work:** -- Keep the boundary with `railiance-cluster` explicit -- Keep workload packaging concerns out of this repo -- Prefer source-controlled declarations over implicit conventions - -**Close:** -1. Update workplan files to reflect progress -2. Register or refresh the repo from `.repo-classification.yaml` when needed -3. Run `statehub fix-consistency` - ---- - -## Boundary Reminders - -- Do not move substrate bootstrap into this repo -- Do not normalize workload-specific helper commands here -- Do not let `rapp-*` packaging or `reef-*` substrate inventory drift into this repo - -The canonical framework boundary lives in -`railiance-master/docs/rail-kubernetes-boundary.md`. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 48a886b..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,4 +0,0 @@ -# rail-kubernetes — Claude Code Instructions - -@SCOPE.md -@AGENTS.md diff --git a/INTENT.md b/INTENT.md deleted file mode 100644 index d8a36d7..0000000 --- a/INTENT.md +++ /dev/null @@ -1,55 +0,0 @@ -# INTENT - -## Why This Repo Exists - -`rail-kubernetes` exists so Railiance has a first-class home for the default -execution rail used by platform services and managed workloads. - -Before this repo, generic workload lifecycle semantics, workload declarations, -and Kubernetes rollout helpers were mixed into `railiance-cluster`. That was -pragmatic while Railiance had only one runtime path, but it is the wrong steady -state once Railiance starts introducing multiple rails. - -This repo establishes the durable answer to: - -- how a Railiance-managed workload targets Kubernetes as a rail -- which workload lifecycle semantics are generic to Kubernetes-managed - workloads -- which substrate guarantees the rail expects from S2 -- where future packages such as `rapp-openbao` attach when they run on the - default rail - -## What This Repo Must Protect - -This repo must keep the wave-1 Kubernetes rail narrow and reusable. - -That means: - -- protect the distinction between rail semantics and cluster ownership -- protect the distinction between rail semantics and workload packaging -- keep the compatibility path from `railiance-cluster` explicit while the - extraction is incomplete -- avoid encoding assumptions that only work for one workload or one substrate - -## What This Repo Is Not - -This repo is not: - -- the ownership home for the Kubernetes substrate -- the ownership home for OpenBao, Forgejo, or any other single workload -- the ownership home for one specific server or cluster substrate -- the place to normalize workload-specific operator commands - -## Initial Operating Context - -Wave 1 is intentionally centered on Kubernetes. - -Railiance should treat this repo as the default rail path until a later -workload presents a strong enough reason to justify a different rail such as -`rail-knative`. - -The first version of this repo therefore prioritizes: - -- a clean boundary with `railiance-cluster` -- a stable attachment point for future `rapp-*` repos -- compatibility with the currently published S2 substrate profile diff --git a/README.md b/README.md index 0a331f1..e65a7c9 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,3 @@ # rail-kubernetes -Wave-1 execution rail for Railiance-managed workloads on Kubernetes. - -## Purpose - -`rail-kubernetes` is the default base rail for the current Railiance -ecosystem. It owns the generic workload-on-Kubernetes execution contract that -should no longer stay mixed into `railiance-cluster`. - -This repo exists to hold: - -- the Kubernetes rail declaration -- the generic workload lifecycle contract -- the migration path from the current `railiance-cluster` compatibility surface -- future rail-local tooling and docs for Railiance-managed workloads on Kubernetes - -## Boundary - -`rail-kubernetes` does not own: - -- k3s bootstrap -- cluster-level operator ownership -- cluster backup/restore posture -- workload-specific wrappers that belong in `rapp-*` repos -- substrate inventories that belong in `reef-*` repos - -Those concerns stay with `railiance-cluster`, the relevant `rapp-*` repo, or -the relevant `reef-*` repo. - -## Current Status - -This repo is in first-wave bootstrap. - -The boundary and source material come from: - -- `railiance-master/docs/rail-kubernetes-boundary.md` -- `railiance-cluster/docs/rail-kubernetes-extraction-map.md` -- `railiance-cluster/docs/rail-kubernetes-substrate-profile.md` - -## Initial Layout - -- `declarations/rail.yaml` — source-controlled rail contract -- `docs/` — wave-1 contract and import plan -- `schemas/` — machine-readable workload contract schema -- `examples/` — canonical example workload declarations for the rail -- `workplans/` — repo-local execution work +Railiance support for kubernetes workloads \ No newline at end of file diff --git a/SCOPE.md b/SCOPE.md deleted file mode 100644 index 89f87ec..0000000 --- a/SCOPE.md +++ /dev/null @@ -1,118 +0,0 @@ -# SCOPE - -> This file helps you quickly understand what this repository is about, -> when it is relevant, and when it is not. -> It is intentionally lightweight and may be incomplete. - ---- - -## One-liner - -Default Railiance execution rail for generic workload-on-Kubernetes semantics. - ---- - -## Core Idea - -`rail-kubernetes` is the first concrete `rail-*` repo in Railiance. -It exists to hold the generic execution contract for Railiance-managed -workloads that run on Kubernetes, without keeping those semantics mixed into -the S2 ownership repo. - ---- - -## In Scope - -- Kubernetes rail declaration and compatibility notes -- Generic workload lifecycle semantics for Kubernetes-managed workloads -- Generic workload contract surface such as `railiance/app.toml` -- Generic rollout, observe, promote, and rollback semantics for the rail -- Migration compatibility guidance while the extraction from `railiance-cluster` - is still in progress - ---- - -## Out of Scope - -- k3s bootstrap and cluster installation -- cluster-level ingress, operator, and certificate ownership -- cluster backup, restore, and preflight safety rails -- workload-specific wrappers and app packaging -- substrate inventories and machine grouping - ---- - -## Relevant When - -- Defining how a workload targets the default Kubernetes rail -- Moving generic workload lifecycle material out of `railiance-cluster` -- Attaching a `rapp-*` package to its Kubernetes execution contract -- Clarifying which S2 substrate facts the rail may depend on - ---- - -## Not Relevant When - -- The work is purely cluster substrate ownership -- The work is workload-specific packaging -- The work is substrate inventory or server grouping - ---- - -## Current State - -- Status: active bootstrap -- Implementation: baseline repo, declaration, and first repo-local workplan are present -- Stability: evolving -- Usage: wave-1 home for the default Kubernetes rail - ---- - -## How It Fits - -- Upstream dependencies: `railiance-cluster`, `railiance-master` -- Downstream consumers: future `rapp-*` repos and reefs that host the Kubernetes rail -- Often used with: `railiance-fabric`, `railiance-platform`, `railiance-infra` - ---- - -## Terminology - -- Preferred terms: rail, execution contract, workload lifecycle, substrate profile -- Also known as: default base rail -- Potentially confusing terms: this repo defines rail semantics; it does not own the Kubernetes substrate itself - ---- - -## Related / Overlapping Repositories - -- `railiance-cluster` — owns the Kubernetes substrate; `rail-kubernetes` owns the generic workload-on-Kubernetes contract -- `railiance-master` — defines the framework architecture and boundary -- future `rapp-*` repos — own workload packaging and scaffolding on top of this rail -- future `reef-*` repos — own the substrate boundaries that host this rail - ---- - -## Getting Oriented - -- Start with: `README.md`, `INTENT.md` -- Key files / directories: `declarations/`, `docs/`, `workplans/` -- Entry points: `declarations/rail.yaml`, `docs/wave-1-contract.md` - ---- - -## Provided Capabilities - -```capability -type: governance -title: Kubernetes execution rail contract -description: Defines the generic execution contract for Railiance-managed workloads that run on Kubernetes. -keywords: [railiance, rail, kubernetes, workload, execution] -``` - ---- - -## Notes - -Keep this repo generic. If a behavior is specific to one workload or one -substrate, it belongs somewhere else. diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md deleted file mode 100644 index 98e3aed..0000000 --- a/WORK-RECORDS.md +++ /dev/null @@ -1,15 +0,0 @@ -# Work Records — rail-kubernetes - -> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record -> stage 3). Do not edit by hand — edit the source file/block listed for -> each record and re-run fix-consistency to refresh this index. Archived -> workplans are omitted; closed decisions/intakes/engagements stay listed -> so recently-resolved work is still visible. [auto] - -| Kind | ID | Status | Lane | Source | -| --- | --- | --- | --- | --- | -| workplan | RAIL-K8S-WP-0001 | active | — | workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md | -| task | RAIL-K8S-WP-0001-T01 | done | — | workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md | -| task | RAIL-K8S-WP-0001-T02 | progress | — | workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md | -| task | RAIL-K8S-WP-0001-T03 | wait | — | workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md | -| task | RAIL-K8S-WP-0001-T04 | progress | — | workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md | diff --git a/declarations/rail.yaml b/declarations/rail.yaml deleted file mode 100644 index 7af8ac2..0000000 --- a/declarations/rail.yaml +++ /dev/null @@ -1,26 +0,0 @@ -kind: execution-rail -rail_id: rail-kubernetes -repo: rail-kubernetes -ownership_repo: railiance-cluster -execution_architecture: kubernetes -status: wave-1-bootstrap -supported_rollout_modes: - - stage1-run - - stage2-isolated-canary - - stage3-promote-rollback -substrate_prerequisites: - - kubernetes-api - - helm-apply-path - - operator-driven-kubeconfig-access - - namespace-creation-supported -compatibility_notes: - - Weighted routing is optional and must not be assumed in wave 1. - - Metrics availability is opportunistic and not a rollout success criterion. - - Storage guarantees remain explicit-review territory until S2 publishes them. -source_documents: - - repo: railiance-master - path: docs/rail-kubernetes-boundary.md - - repo: railiance-cluster - path: docs/rail-kubernetes-extraction-map.md - - repo: railiance-cluster - path: docs/rail-kubernetes-substrate-profile.md diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index eaff010..0000000 --- a/docs/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# rail-kubernetes Docs - -- `app-toml-contract.md` — canonical workload declaration contract for the rail -- `overlay-repo-pattern.md` — compatibility-era overlay pattern on the path to `rapp-*` -- `canary-helm-template.md` — stage-aware canary/stable chart pattern -- `deployment-lifecycle.md` — canonical stage 1 / 2 / 3 lifecycle contract -- `stage2-deploy-observe.md` — stage 2 command behavior contract -- `promote-rollback-onboarding.md` — representative lifecycle command path -- `railiance-run-command.md` — stage 1 command behavior contract -- `wave-1-contract.md` — current rail contract and boundary summary -- `source-import-plan.md` — source material and migration direction from existing repos diff --git a/docs/app-toml-contract.md b/docs/app-toml-contract.md deleted file mode 100644 index 3088047..0000000 --- a/docs/app-toml-contract.md +++ /dev/null @@ -1,240 +0,0 @@ -# Railiance app.toml Contract - -This document defines the repository-local `railiance/app.toml` contract used by -Railiance staged promotion tooling. The file tells Railiance how a workload -moves through Stage 1 local validation, Stage 2 production canary, and Stage 3 -production promotion without relying on bespoke operator notes. - -The contract is intentionally declarative. Commands, health checks, platform -dependencies, and secret references are described by stable names. Plaintext -secrets, bearer tokens, kubeconfigs, and private key material must never appear -in `railiance/app.toml`. - -Ownership note: this contract now lives in `rail-kubernetes` as part of the -wave-1 split. `railiance-cluster` may keep compatibility copies during the -migration window, but long-term ownership belongs with the generic -workload-on-Kubernetes contract here rather than with S2 cluster substrate -ownership. - -The machine-readable schema lives at `schemas/railiance-app.schema.json`. A -minimal example lives at `examples/railiance/app.toml`. - -## File Location - -Participating workload repositories declare the contract at: - -```text -railiance/app.toml -``` - -Overlay repositories for third-party applications use the same path in the -overlay repo, not in the upstream source repository. - -## Versioning - -Every file must include: - -```toml -schema_version = "railiance.app.v1" -``` - -Breaking contract changes require a new schema version. Tooling must fail closed -when it sees an unsupported `schema_version`. - -## Top-Level Sections - -### app - -Identifies the workload and its ownership boundary. - -Required fields: - -- `id`: stable lowercase id using letters, numbers, and hyphens. -- `name`: human-readable workload name. -- `repo`: owning source or overlay repository slug. -- `owner`: owning team, domain, or operator group. -- `criticality`: one of `low`, `medium`, `high`, or `critical`. -- `description`: short purpose statement. - -Production-critical workloads include source forge, identity, State Hub, -Inter-Hub, databases, object stores, backup systems, ingress, and cluster-wide -policy controllers. For those workloads, `criticality = "critical"` requires -explicit human approval before Stage 2 traffic exposure and Stage 3 promotion. - -### source - -Identifies the candidate under promotion. - -Required fields: - -- `revision`: commit id, tag, or immutable source revision expression. -- `artifact`: artifact kind, normally `image`, `helm-chart`, or `bundle`. -- `digest_policy`: one of `required`, `preferred`, or `not-applicable`. - -If an image is promoted, Stage 2 and Stage 3 tooling should prefer immutable -image digests over mutable tags. - -### platform.dependencies - -Declares platform services required before canary or production promotion. - -Each dependency has: - -- `name`: stable service name. -- `kind`: dependency kind such as `postgres`, `redis`, `object-store`, - `identity`, `state-hub`, `inter-hub`, `network`, or `other`. -- `required`: boolean. -- `stage`: earliest stage that needs it, one of `stage1`, `stage2`, `stage3`. -- `evidence`: non-secret evidence expected before promotion, such as a health - endpoint result, Kubernetes Ready condition, or State Hub progress id. - -### secrets.references - -Declares required secret references without secret values. - -Each reference has: - -- `name`: workload-local secret name. -- `route`: approved credential route id, for example `openbao-api-key`, - `key-cape-oidc-login`, or `activity-core-issue-sink`. -- `target`: non-secret target reference such as a Kubernetes Secret name, - ExternalSecret name, OpenBao path, or environment variable name. -- `stage`: earliest stage that needs the secret. -- `required`: boolean. - -Forbidden fields include plaintext values, tokens, passwords, kubeconfigs, or -private keys. Tooling must reject suspicious field names such as `value`, -`token`, `password`, `secret`, `private_key`, or `kubeconfig` inside secret -reference objects unless they are part of the approved non-secret `target` text. - -### observability - -Defines how promotion tooling proves the workload is alive and observable. - -Required fields: - -- `health_endpoints`: one or more HTTP health endpoint declarations. -- `metrics`: optional metrics endpoint or query references. -- `logs`: optional log selectors or query references. - -Health endpoint declarations include `name`, `url`, `stage`, and expected -status code. URLs may be internal service URLs for Stage 2/3; they must not -embed credentials. - -### rollback - -Defines how the workload returns to a previous stable state. - -Required fields: - -- `strategy`: one of `helm-revision`, `image-digest`, `traffic-shift`, - `manual-runbook`, or `none`. -- `command`: command name or runbook path. This may be a placeholder before - T07 implements automation, but it must tell the operator where rollback lives. -- `verification`: non-secret check to confirm rollback succeeded. - -`strategy = "none"` is allowed only for Stage 1-only workloads and must not be -used for production-critical workloads. - -## Stage Sections - -The contract has one table for each stage: - -```toml -[stages.stage1] -[stages.stage2] -[stages.stage3] -``` - -Each stage includes: - -- `enabled`: boolean. -- `namespace`: target Kubernetes namespace, or a local namespace for Stage 1. -- `release`: release identity. -- `commands`: ordered command aliases or shell commands that tooling may run. -- `checks`: ordered check ids to evaluate. -- `evidence`: expected non-secret evidence outputs. -- `requires_approval`: boolean. - -Stage 2 additionally includes `canary_mode`, one of `weighted`, `header`, -`path`, `shadow`, or `isolated`, plus `observation_minutes` and optional -`traffic_percent` when weighted routing is used. - -Stage 3 additionally includes `promotion_mode`, one of `traffic-shift`, -`release-replace`, `selector-switch`, or `workflow`, plus `previous_stable`. - -## Check Definitions - -Checks live under `[[checks]]` entries and are referenced by stage `checks`. - -Required fields: - -- `id`: stable check id. -- `type`: one of `command`, `http`, `kubernetes`, `helm`, `metric`, `log`, or - `manual`. -- `stage`: earliest stage that may run the check. -- `description`: human-readable purpose. -- `required`: boolean. - -Type-specific fields: - -- `command`: `run` command string and optional `timeout_seconds`. -- `http`: `url`, `expected_status`, and optional `timeout_seconds`. -- `kubernetes`: `namespace`, `resource`, and `condition`. -- `helm`: `chart`, `values`, and `mode` such as `template` or - `server-dry-run`. -- `metric`: `query`, `window_minutes`, and `threshold`. -- `log`: `selector`, `window_minutes`, and `forbidden_patterns`. -- `manual`: `evidence_required` text. - -Checks must not print secrets. If a check needs secret-backed access, the result -records only the route, target object, and pass/fail state. - -## Command Semantics - -Commands in `app.toml` are declarations for Railiance tooling. Stage 1, Stage -2, and Stage 3 commands now have local CLI support; workload scripts may still -wrap them for service-specific checks. - -Expected mapping: - -- Stage 1 commands are consumed by `bin/railiance run `. -- Stage 2 commands are consumed by `bin/railiance deploy --stage 2 ` - and `bin/railiance observe --stage 2 `. -- Stage 3 commands are consumed by `bin/railiance promote ` and - `bin/railiance rollback `. - -Tooling must emit machine-readable results with workload identity, candidate -revision, checks run, pass/fail status, non-secret evidence, rollback target, -and approval state. - -## Minimal Example - -See `examples/railiance/app.toml`. It declares a critical internal service with: - -- immutable image digest requirement; -- Stage 1 local validation; -- Stage 2 isolated canary; -- Stage 3 release replacement; -- OpenBao-routed secret references without values; -- HTTP, Helm, Kubernetes, and manual approval checks. - -## Adoption Rules - -A workload can enter Stage 1 when `app.toml` passes schema validation and all -Stage 1 required checks are declared. - -A workload can enter Stage 2 only when: - -- Stage 1 passed for the same candidate artifact; -- Stage 2 namespace, release, canary mode, health checks, dependencies, and - rollback target are declared; -- secret references use approved routes and contain no values; -- production-critical workloads have explicit approval. - -A workload can enter Stage 3 only when: - -- Stage 2 acceptance gates passed for the same candidate artifact; -- `previous_stable` and rollback verification are recorded; -- backup/restore posture is current for stateful workloads; -- production-critical workloads have explicit human approval. diff --git a/docs/canary-helm-template.md b/docs/canary-helm-template.md deleted file mode 100644 index 54d4ce1..0000000 --- a/docs/canary-helm-template.md +++ /dev/null @@ -1,55 +0,0 @@ -# Canary Helm Template - -Generated Railiance overlays include a stage-aware Helm chart for Stage 2 -canaries and Stage 3 stable promotion. - -The chart keeps stable and canary release identities explicit: - -- `railiance.stableRelease` names the current stable release; -- `railiance.canaryRelease` names the Stage 2 candidate release; -- `railiance.stage` selects the rendered identity, labels, and selectors; -- `railiance.previousStable` records rollback context before promotion. - -## Traffic Shape - -The default Stage 2 values use an isolated canary ingress: - -```yaml -railiance: - stage: canary - traffic: - mode: isolated - -ingress: - enabled: true -``` - -This creates canary Deployment, Service, and Ingress resources without changing -the stable release. For environments that use Traefik weighted routing, set: - -```yaml -railiance: - traffic: - mode: weighted - provider: traefik - stableWeight: 95 - canaryWeight: 5 -``` - -The chart then renders a `TraefikService` and `IngressRoute` that split traffic -between the stable and canary services. Other ingress controllers can use the -same stable/canary values layout with controller-specific annotations or a later -provider template. - -## Observability And Safety - -Generated workloads include: - -- Prometheus-compatible scrape annotations on pods and services; -- readiness and liveness HTTP probes; -- conservative resource requests/limits for single-node clusters; -- separate `values/stage2-canary.yaml` and `values/stage3-production.yaml` so - canary exposure and stable promotion can be reviewed independently. - -Run `tests/stage2-template.sh` in the overlay repo before any Stage 2 attempt. -It verifies the scaffold and runs `helm template` when Helm is available. diff --git a/docs/deployment-lifecycle.md b/docs/deployment-lifecycle.md deleted file mode 100644 index 58f2939..0000000 --- a/docs/deployment-lifecycle.md +++ /dev/null @@ -1,340 +0,0 @@ -# Railiance Deployment Lifecycle - -This document defines the Railiance three-stage promotion lifecycle for -workloads that run on the Railiance Kubernetes substrate. - -The lifecycle exists so production workloads move through repeatable gates -instead of one-off operator memory. It is intentionally conservative: every -stage must leave evidence, every promotion must have a rollback path, and -critical workloads require explicit human approval before production traffic is -changed. - -Ownership note: this specification now lives in `rail-kubernetes` as the -wave-1 home of the default Kubernetes execution rail. `railiance-cluster` may -retain compatibility shims during migration, but long-term ownership of the -generic lifecycle contract belongs here rather than in the S2 substrate repo. - -## Scope - -This specification now lives beside the Kubernetes rail contract rather than -beside the cluster substrate. The compatibility tooling may still live -elsewhere during migration, but long-term ownership is not S2. - -Repo boundaries: - -- `rail-kubernetes` owns lifecycle semantics, generic promotion gates, - canary validation, production routing expectations, rollback expectations, - and the generic workload contract. -- `railiance-cluster` owns only the substrate prerequisites published to that - rail: cluster connectivity, namespace behavior, ingress availability, and - operator/runtime expectations. -- `railiance-apps` owns workload-specific Helm values, application release - definitions, and production workload configuration. -- `railiance-platform` owns shared platform services such as databases, - caches, object storage, and backup targets. -- `railiance-enablement` owns developer-facing templates, CI workflows, and - local ergonomics. -- `railiance-infra` owns host provisioning, OS hardening, SSH, firewall, and - node bootstrap below Kubernetes. - -## Lifecycle Overview - -Railiance promotes a workload through three stages: - -1. Stage 1: local validation. -2. Stage 2: production canary. -3. Stage 3: production promotion. - -The stages are sequential. A workload may return to an earlier stage at any -time, but it must not skip a stage when moving toward production unless an -operator records an emergency exception in State Hub. - -Each stage emits a machine-readable result with: - -- workload identity; -- source revision or image digest; -- target environment; -- checks run; -- pass/fail status; -- non-secret evidence references; -- rollback target, when applicable; -- approving human or explicit "not required" decision. - -## Workload Declaration - -Each participating workload should declare its promotion contract in a -repository-local `railiance/app.toml`. The contract is defined in -`docs/app-toml-contract.md`, with a machine-readable schema at -`schemas/railiance-app.schema.json`. This lifecycle expects every workload -declaration to provide at least: - -- stable workload name and owning repo; -- source revision, image tag, or image digest policy; -- stage-specific namespaces or release names; -- health checks and observability endpoints; -- ingress or routing targets; -- platform dependencies; -- rollback command or previous-stable reference; -- secret references by name or path, never plaintext secret values. - -If a workload cannot provide a machine-readable declaration yet, it may still -use this lifecycle through a written operator runbook, but that is a temporary -compatibility path. The runbook must identify the missing declaration fields. - -## Stage 1: Local Validation - -Stage 1 proves that the workload can be built, configured, and checked outside -production traffic. - -Typical Stage 1 targets: - -- local container runtime; -- local Kubernetes such as k3d, kind, or a disposable namespace; -- dry-run Helm rendering; -- unit, integration, migration, and smoke checks that do not require production - credentials. - -Required Stage 1 checks: - -- source revision is cleanly identified; -- build or artifact selection is deterministic; -- Helm templates or manifests render without invalid Kubernetes objects; -- local health checks pass; -- required secrets are referenced by name only and are not printed; -- database migrations, if any, are classified as reversible, forward-only, or - requiring human approval; -- a Stage 2 candidate artifact is named by immutable digest or equivalent - immutable revision. - -Stage 1 fails closed when: - -- local checks are skipped without an approved reason; -- generated manifests contain plaintext secrets; -- the artifact cannot be traced to source; -- the workload cannot state how it will be observed in Stage 2. - -Stage 1 completion does not authorize production traffic. It only makes a -workload eligible for Stage 2 review. - -## Stage 2: Production Canary - -Stage 2 deploys the candidate to production infrastructure with limited or -isolated exposure. The goal is to observe the candidate against real platform -dependencies while keeping blast radius small. - -Acceptable canary forms: - -- weighted ingress split between stable and canary; -- header-based or path-based routing for operator traffic only; -- shadow deployment receiving replicated non-mutating traffic; -- isolated production namespace with manually triggered probes. - -The selected canary form must be declared before deployment. If weighted -routing is unavailable, the fallback must preserve the same safety property: -the candidate can be observed without silently replacing stable production. - -Required Stage 2 prechecks: - -- Stage 1 result passed for the same candidate artifact; -- cluster connectivity and namespace readiness are verified; -- target image digest or immutable tag exists in the registry; -- Helm server-side dry-run succeeds; -- ingress, certificate, and DNS prerequisites are present where applicable; -- platform dependencies are healthy or explicitly degraded with operator - approval; -- rollback target is known before the canary is applied; -- monitoring and log queries are available for the canary release. - -Required Stage 2 evidence: - -- rendered release identity; -- applied namespace and release name; -- pod readiness and restart status; -- ingress or routing state; -- key health endpoint result; -- relevant metrics window or explicit "metrics unavailable" note; -- State Hub progress note with non-secret evidence; -- operator approval when the workload is production-critical. - -Canary acceptance gates: - -- canary pods remain ready for the configured observation window; -- no crash loops, repeated restarts, or pending pods remain unexplained; -- health checks pass from inside and outside the cluster when both are - applicable; -- error rate, latency, and saturation do not regress beyond the workload's - declared threshold; -- no unexpected schema, storage, or queue side effects are observed; -- logs show no secret leakage and no repeated authorization failures; -- rollback has been tested previously or is a single documented command with a - known previous-stable target. - -Default observation windows: - -- non-critical internal service: 15 minutes; -- user-facing or shared platform service: 30 minutes; -- production-critical infrastructure such as Forgejo, identity, registry, or - State Hub: operator-defined window, minimum 60 minutes unless explicitly - waived. - -Stage 2 fails closed when: - -- the canary cannot be distinguished from stable production; -- production routing changes more traffic than intended; -- any required evidence is missing and no operator waiver is recorded; -- rollback target is unknown; -- the candidate needs a secret, credential, or platform dependency that was not - declared before the canary. - -## Stage 3: Production Promotion - -Stage 3 promotes the accepted candidate to the stable production path. - -Promotion may mean: - -- shifting weighted traffic to the canary release; -- replacing the stable Helm release with the accepted candidate; -- changing an ingress selector or service target; -- activating an operator-approved rollout workflow. - -Required Stage 3 prechecks: - -- Stage 2 acceptance gates passed for the same candidate artifact; -- the previous stable version is recorded; -- backup and restore posture is current for stateful workloads; -- migrations are approved and sequenced; -- production-critical workloads have explicit human approval; -- a rollback command and rollback verification check are available. - -Required Stage 3 evidence: - -- promotion command or workflow id; -- previous stable version; -- new stable version; -- production routing state after promotion; -- smoke result after promotion; -- rollback target retained; -- State Hub progress note with non-secret evidence. - -Stage 3 is complete only after the post-promotion smoke passes and the -workload's stable routing points at the promoted candidate. - -## Rollback Expectations - -Rollback is part of every promotion, not an afterthought. - -Every Stage 2 and Stage 3 action must identify one of: - -- previous stable Helm release revision; -- previous image digest and values file; -- previous ingress/routing configuration; -- documented manual recovery path when automation is not yet safe. - -Rollback must be immediate when: - -- production availability is degraded; -- canary traffic escapes the declared blast radius; -- the workload emits repeated authorization or secret-handling errors; -- data integrity is at risk; -- an operator revokes approval during the observation window. - -Rollback may be deferred only when the rollback itself is more dangerous than -the incident state. That decision requires a State Hub note and human approval. - -After rollback, record: - -- triggering symptom; -- rollback action; -- final stable version; -- remaining cleanup; -- whether the failed candidate is blocked, abandoned, or returned to Stage 1. - -## Human Approval Gates - -Human approval is required before production traffic changes for -production-critical workloads. - -Production-critical workloads include: - -- source forge and package registry workloads such as Forgejo or Gitea; -- identity, MFA, SSO, or authorization systems; -- State Hub, Inter-Hub, and operator coordination services; -- databases, object stores, and backup systems; -- ingress, certificate, or cluster-wide policy controllers; -- any workload whose failure blocks multiple repos or domains. - -Approval must be recorded as a non-secret State Hub note or task comment. The -approval record should name: - -- approving operator; -- candidate artifact; -- stage being approved; -- observation window; -- rollback target; -- any waived gates and why. - -Emergency approval can be retrospective only when delaying the action would -increase production risk. Retrospective approval must be recorded immediately -after stabilization. - -## Evidence And Secret Handling - -Lifecycle evidence must be useful without being sensitive. - -Allowed evidence: - -- commit ids; -- image tags and digests; -- workflow ids; -- Kubernetes object names; -- pod status summaries; -- HTTP status codes; -- timestamps; -- State Hub progress ids; -- pass/fail summaries. - -Forbidden evidence: - -- plaintext secrets; -- bearer tokens; -- static API keys; -- kubeconfigs; -- private key material; -- full environment dumps; -- logs that contain credentials or user private data. - -When a check needs secret-backed access, record only the access path and result, -for example: "OpenBao path configured, token exchange returned 200". - -## Forgejo Readiness Interpretation - -This lifecycle is clear enough for Forgejo when a future Forgejo workplan can -answer these questions before production cutover: - -- What source revision and image digest are being promoted? -- What local checks prove the candidate is viable? -- How is the production canary isolated or traffic-limited? -- Which health, registry, SSH, web, Actions, and email recovery checks define - acceptance? -- Who approves the Stage 3 traffic switch? -- What is the previous stable target? -- How is repository data protected before and after promotion? -- How will rollback be verified without losing package or repository state? - -If any answer is missing, Forgejo remains in Stage 1 or Stage 2 preparation and -must not cut over to Stage 3. - -## Minimum Command Contract - -The Railiance CLI makes these lifecycle operations repeatable: - -```text -bin/railiance run # Stage 1 local validation -bin/railiance deploy --stage 2 --plan # Stage 2 canary plan -bin/railiance observe --stage 2 --plan # Stage 2 evidence targets -bin/railiance promote --plan # Stage 3 production promotion -bin/railiance rollback --plan # rollback to previous stable -``` - -The exact command names may change as implementation lands, but the behavior -must preserve the stage gates and evidence requirements in this document. diff --git a/docs/overlay-repo-pattern.md b/docs/overlay-repo-pattern.md deleted file mode 100644 index f3cc109..0000000 --- a/docs/overlay-repo-pattern.md +++ /dev/null @@ -1,179 +0,0 @@ -# Railiance Overlay Repo Pattern - -A Railiance overlay repo wraps a third-party upstream application without -forking Railiance deployment logic into the upstream source repository. - -The overlay repo owns the Railiance deployment contract, promotion evidence, -Helm/Kubernetes overlay, values, probes, and runbooks. The upstream repository -remains the source of application code and release artifacts. - -This pattern is a compatibility-era scaffolding model inside the -`rail-kubernetes` migration. Long-term first-class package ownership should -move toward `rapp-*` repos. Until the `rapp-*` path is fully materialized, the -overlay structure remains a useful generic pattern for Kubernetes-managed -workloads. - -## Goals - -- Keep upstream code and Railiance deployment mechanics separate. -- Make Stage 1, Stage 2, Stage 3, and rollback behavior reproducible from Git. -- Declare all platform dependencies, health checks, and secret references in - `railiance/app.toml` without plaintext secret values. -- Allow third-party applications to adopt the staged promotion lifecycle without - requiring changes to their upstream repositories. - -## Repo Layout - -A generated compatibility overlay repo should look like this: - -```text --railiance-overlay/ - README.md - railiance/ - app.toml - upstream.toml - charts/ - / - Chart.yaml - values.yaml - templates/ - deployment.yaml - service.yaml - values/ - stage1.yaml - stage2-canary.yaml - stage3-production.yaml - patches/ - upstream/.gitkeep - tests/ - stage1.sh - runbooks/ - rollback.md - docs/ - promotion.md -``` - -When a workload graduates into a durable package repo, the preferred target is -to keep the same contract surfaces while moving the repo identity toward -`rapp-`. - -## Ownership Boundary - -The overlay repo owns: - -- `railiance/app.toml` staged promotion declaration; -- Railiance-specific Helm chart, values, probes, and runbooks; -- canary and promotion evidence expectations; -- secret references by approved route and target object name; -- compatibility notes for a specific upstream revision or release line. - -The upstream repo owns: - -- application source code; -- upstream build and release artifacts; -- upstream tests and release notes; -- upstream vulnerability and license notices. - -The overlay must not vendor upstream source by default. If a patch is required, -store the patch under `patches/upstream/` and record why the patch exists, when -it can be retired, and which upstream issue or release should replace it. - -## Required Files - -### `railiance/app.toml` - -This file follows `docs/app-toml-contract.md` and -`schemas/railiance-app.schema.json` from `rail-kubernetes`. It is the primary -machine-readable contract for promotion tooling. - -### `railiance/upstream.toml` - -This file records non-secret upstream identity: - -```toml -[upstream] -url = "https://example.com/vendor/app.git" -revision = "v1.2.3" -tracking = "tag" -license = "see-upstream" -notes = "Railiance overlay only; upstream code is not vendored here." -``` - -`revision` should be immutable where possible: tag, commit SHA, release id, or -image digest. Mutable branches are acceptable only before a workload becomes a -Stage 2 candidate. - -### `charts//` - -The chart is the Railiance deployment wrapper. It may start as a thin Helm -chart around an upstream image and grow only as required by the promotion gates. -Generated charts include stable/canary release identities, Prometheus-compatible -annotations, HTTP probes, resource limits, isolated canary ingress, and optional -Traefik weighted routing. Production-specific choices stay in `values/` files. - -### `values/` - -Stage values separate local validation, canary, and production settings: - -- `stage1.yaml`: local or dry-run defaults; -- `stage2-canary.yaml`: limited exposure canary defaults; -- `stage3-production.yaml`: stable production defaults. - -Secret values do not belong in these files. Use Kubernetes Secret, -ExternalSecret, OpenBao, KeyCape, or another approved route and record only the -reference name. - -### `tests/stage1.sh` And `tests/stage2-template.sh` - -Stage 1 should be runnable without production credentials. The generated script -performs syntax and Helm rendering checks when the relevant tools are available. - -Stage 2 template validation verifies the canary scaffold, stable/canary values, -Prometheus annotations, rollback labels, and Helm rendering when Helm is -available. Workload-specific tests can extend either script. - -### `runbooks/rollback.md` - -Rollback instructions must exist before Stage 2. Early overlays may include a -placeholder, but it must name the intended rollback target and verification -check. - -## Creation Tool - -During the migration window, the compatibility scaffold still comes from: - -```bash -railiance-cluster/tools/create_railiance_overlay_repo.sh \ - --app-id forgejo \ - --name "Forgejo" \ - --owner railiance-forge \ - --criticality critical \ - --upstream-url https://codeberg.org/forgejo/forgejo.git \ - --upstream-revision v12.0.0 \ - --out-dir /tmp/forgejo-railiance-overlay -``` - -The tool writes only local files. It does not call Gitea, clone upstream code, -fetch secrets, or push Git remotes. - -Long-term, the generic scaffolding behavior should move under the rail and/or -become `rapp-*`-aware rather than preserving the overlay name forever. - -## Promotion Use - -1. Generate or update the overlay repo. -2. Fill in accurate image, namespace, health, dependency, and rollback fields. -3. Validate `railiance/app.toml` against the schema. -4. Run `tests/stage1.sh` and `tests/stage2-template.sh`. -5. Use later Stage 2 and Stage 3 commands to deploy, observe, promote, and - rollback. - -## Safety Rules - -- No plaintext secrets in `railiance/app.toml`, values files, tests, runbooks, - or generated evidence. -- Do not hide deployment logic in upstream source patches. -- Do not promote mutable upstream branches to Stage 2/3 without an explicit - operator exception. -- Production-critical overlays require human approval before canary exposure and - production promotion. diff --git a/docs/promote-rollback-onboarding.md b/docs/promote-rollback-onboarding.md deleted file mode 100644 index 99ced46..0000000 --- a/docs/promote-rollback-onboarding.md +++ /dev/null @@ -1,71 +0,0 @@ -# Promote, Rollback, And Onboarding - -This guide shows the representative Railiance lifecycle for an overlay repo. -Commands default to plan mode so the path is repeatable before cluster access or -operator approval exists. - -## Stage 1 - -```bash -bin/railiance run /path/to/overlay --pretty -``` - -Stage 1 validates `railiance/app.toml`, local commands, and local checks. Save -the JSON result as non-secret evidence before Stage 2. - -## Stage 2 - -```bash -bin/railiance deploy --stage 2 /path/to/overlay --plan --pretty -bin/railiance observe --stage 2 /path/to/overlay --plan --pretty -``` - -When Helm, kubectl, cluster access, and approval evidence are ready: - -```bash -bin/railiance deploy --stage 2 /path/to/overlay --apply --approval-id -bin/railiance observe --stage 2 /path/to/overlay --live --pretty -``` - -For critical workloads, Stage 2 apply must not run until the operator has -approved canary exposure and rollback context is known. - -## Stage 3 - -```bash -bin/railiance promote /path/to/overlay --plan --pretty -bin/railiance rollback /path/to/overlay --plan --pretty -``` - -Promotion plan mode emits a `railiance.stage3-promote-result.v1` JSON result -with stable release identity, chart and values paths, previous-stable target, -expected evidence, and approval requirements. - -Rollback plan mode emits a `railiance.stage3-rollback-result.v1` JSON result -with rollback strategy, release identity, verification text, and apply-time -requirements. - -When approval evidence and Helm access are ready: - -```bash -bin/railiance promote /path/to/overlay --apply --approval-id -bin/railiance rollback /path/to/overlay --apply --approval-id --revision -``` - -Stage 3 apply fails closed if the chart or values are missing, previous stable -is not recorded, Helm is unavailable, or approval evidence is missing. Rollback -apply fails closed if the rollback strategy is missing, Helm is unavailable, -approval evidence is missing, or a Helm revision is required but absent. - -## Human Approval Points - -Critical infrastructure workloads require explicit operator approval before: - -- Stage 2 canary exposure; -- Stage 3 stable promotion; -- rollback apply, unless an incident runbook defines a narrower break-glass - process and records the evidence id. - -Progress notes should include only non-secret result summaries: schema version, -status, release, namespace, approval id, check counts, and command byte counts. -Do not paste command logs, kubeconfigs, tokens, or private service output. diff --git a/docs/railiance-run-command.md b/docs/railiance-run-command.md deleted file mode 100644 index 7390e2a..0000000 --- a/docs/railiance-run-command.md +++ /dev/null @@ -1,52 +0,0 @@ -# Railiance Run Command - -`bin/railiance run` executes Stage 1 local validation for a repository that -contains `railiance/app.toml`. - -The command is intentionally local and conservative: - -- reads `railiance/app.toml` using the `railiance.app.v1` contract; -- runs `[stages.stage1].commands` from the app directory; -- evaluates Stage 1 check ids listed in `[stages.stage1].checks` when they can - be checked locally; -- emits a machine-readable `railiance.run-result.v1` JSON result; -- records command references, exit codes, durations, and output byte counts, - but not shell text or command stdout/stderr content; -- strips credentials, query strings, and fragments from URLs before reporting HTTP - check results. - -## Usage - -```bash -bin/railiance run /path/to/app-or-overlay --pretty -bin/railiance run . --json-out .railiance/stage1-result.json -``` - -The process exits `0` only when all Stage 1 commands and required checks pass. -Optional checks may be skipped without failing the run. For example, an optional -local health endpoint can be declared before a local server command exists. - -## Supported Local Checks - -- `command`: runs the check `run` command in the app directory. -- `http`: calls the declared URL and compares the HTTP status. -- `helm`: runs `helm template` when Helm is installed. Required Helm checks fail - if Helm is unavailable; optional Helm checks are skipped. - -Other check types are reported as skipped or failed depending on whether the -check is required. Stage 2 and Stage 3 checks are never executed by -`railiance run`. - -## Result Shape - -The JSON result includes: - -- app identity and source revision; -- contract path and app directory; -- command/check status summaries using contract references instead of raw shell - commands; -- expected evidence labels from Stage 1; -- timing and exit status metadata. - -The result is suitable for later promotion gates and State Hub progress notes, -without embedding secrets or verbose logs. diff --git a/docs/source-import-plan.md b/docs/source-import-plan.md deleted file mode 100644 index 892c0bd..0000000 --- a/docs/source-import-plan.md +++ /dev/null @@ -1,45 +0,0 @@ -# Source Import Plan - -## Purpose - -Record which reviewed source materials are expected to seed this repo. - -## Imported In The Current Wave - -Imported source documents from `railiance-cluster`: - -- `docs/deployment-lifecycle.md` -- `docs/app-toml-contract.md` -- `docs/overlay-repo-pattern.md` -- `docs/canary-helm-template.md` -- `docs/stage2-deploy-observe.md` -- `docs/promote-rollback-onboarding.md` -- `docs/railiance-run-command.md` - -Imported source assets from `railiance-cluster`: - -- `schemas/railiance-app.schema.json` -- `examples/railiance/app.toml` - -## Pending First-Wave Imports - -Expected source assets from `railiance-cluster`: - -- `tools/create_railiance_overlay_repo.sh` -- `tools/cmd/railiance-run` -- `tools/cmd/railiance-stage2` -- `tools/cmd/railiance-stage3` - -## Deferred Migration Debt - -Do not import these into `rail-kubernetes` as part of wave 1: - -- workload-specific activity-core helper commands -- workload-specific smoke or reconciliation helpers -- cluster substrate operations -- shared bootstrap helpers that still need a separate placement review - -## Rule - -Imports into this repo should preserve the boundary already reviewed in -`railiance-master` and `railiance-cluster`. diff --git a/docs/stage2-deploy-observe.md b/docs/stage2-deploy-observe.md deleted file mode 100644 index b6e315b..0000000 --- a/docs/stage2-deploy-observe.md +++ /dev/null @@ -1,49 +0,0 @@ -# Stage 2 Deploy And Observe - -`bin/railiance deploy --stage 2` and `bin/railiance observe --stage 2` provide -the repeatable command path for production canaries declared in -`railiance/app.toml`. - -Both commands default to non-mutating plan mode. - -## Deploy - -```bash -bin/railiance deploy --stage 2 /path/to/overlay --pretty -bin/railiance deploy --stage 2 /path/to/overlay --server-dry-run --pretty -bin/railiance deploy --stage 2 /path/to/overlay --apply --approval-id -``` - -Plan mode validates the local Stage 2 chart and values paths and emits a -`railiance.stage2-deploy-result.v1` JSON plan. It does not contact the cluster. - -`--server-dry-run` runs `helm upgrade --install --dry-run=server` when Helm and -cluster access are available. `--apply` runs the Helm canary apply path with -`--atomic --wait`. If Stage 2 declares `requires_approval = true`, apply mode -fails closed unless `--approval-id` is provided. - -The result records release identity, namespace, chart path, values path, -expected checks/evidence, precheck status, and command byte counts. It does not -embed Helm or kubectl logs. - -## Observe - -```bash -bin/railiance observe --stage 2 /path/to/overlay --pretty -bin/railiance observe --stage 2 /path/to/overlay --live --pretty -``` - -Plan mode emits the rollout, pod selector, ingress selector, health URL, and -metrics targets that live observation will query. - -Live mode uses `kubectl` to check rollout status, deployment JSON, canary pods, -ingress/routing resources, and pod metrics when metrics-server is available. -Metrics unavailability is reported separately so a canary can fail for rollout -or readiness problems without hiding missing observability. - -## Safety - -Stage 2 remains blocked when required local paths are missing, Helm is missing -for dry-run/apply, `kubectl` is missing for live observe, or approval evidence -is missing for an apply that requires approval. Use the emitted JSON as -non-secret evidence in State Hub progress notes. diff --git a/docs/wave-1-contract.md b/docs/wave-1-contract.md deleted file mode 100644 index f7fd29e..0000000 --- a/docs/wave-1-contract.md +++ /dev/null @@ -1,59 +0,0 @@ -# Wave-1 Kubernetes Rail Contract - -## Purpose - -Summarize the initial contract `rail-kubernetes` owns in wave 1. - -This repo starts from already-reviewed source documents rather than inventing a -new runtime model: - -- `railiance-master/docs/rail-kubernetes-boundary.md` -- `railiance-cluster/docs/rail-kubernetes-extraction-map.md` -- `railiance-cluster/docs/rail-kubernetes-substrate-profile.md` - -## What `rail-kubernetes` Owns - -Wave 1 assigns these concerns to the rail: - -- the generic workload-on-Kubernetes execution contract -- the generic `railiance/app.toml` workload declaration surface -- generic stage 1 / stage 2 / stage 3 lifecycle semantics -- generic canary, observe, promote, and rollback behavior -- generic wrapper and overlay guidance for workloads that still use the current - overlay pattern during migration - -## What Stays In `railiance-cluster` - -Wave 1 keeps these concerns in the S2 ownership repo: - -- k3s bootstrap and host-to-cluster installation -- cluster backup, restore, smoke, and preflight operations -- operator ownership for ingress, TLS, and other cluster-level components -- cluster access delivery and kubeconfig handling -- substrate-level safety rails - -## Published Substrate Assumptions - -Wave 1 `rail-kubernetes` may assume: - -- a Kubernetes API backed by k3s -- Helm-based apply paths -- operator-driven kubeconfig access -- isolated canary exposure as the safe default -- namespace creation during workload rollout - -Wave 1 `rail-kubernetes` must not assume: - -- guaranteed weighted routing -- a generic workload RBAC model -- a generic persistent-storage contract -- a secret-delivery contract at the S2 layer - -## Migration Constraint - -Until the extraction is complete, `railiance-cluster` remains the compatibility -surface for current operators. - -`rail-kubernetes` should become the durable home of the contract first. Only -then should commands, docs, schemas, and helpers move here in a migration-safe -sequence. diff --git a/examples/railiance/app.toml b/examples/railiance/app.toml deleted file mode 100644 index d97f37b..0000000 --- a/examples/railiance/app.toml +++ /dev/null @@ -1,176 +0,0 @@ -schema_version = "railiance.app.v1" - -[app] -id = "example-service" -name = "Example Service" -repo = "railiance-apps/example-service" -owner = "platform" -criticality = "critical" -description = "Reference declaration for the Railiance staged promotion lifecycle." - -[source] -revision = "git:main" -artifact = "image" -digest_policy = "required" - -[rollback] -strategy = "helm-revision" -command = "bin/railiance rollback example-service" -verification = "GET /health returns 200 on the restored stable release." - -[[platform.dependencies]] -name = "state-hub" -kind = "state-hub" -required = true -stage = "stage2" -evidence = "State Hub /healthz returns ok from the cluster path." - -[[platform.dependencies]] -name = "postgres" -kind = "postgres" -required = true -stage = "stage2" -evidence = "Target database reports Ready and backup posture is current." - -[[secrets.references]] -name = "runtime-api-key" -route = "openbao-api-key" -target = "ExternalSecret/example-service-runtime" -stage = "stage2" -required = true - -[[observability.health_endpoints]] -name = "local-health" -url = "http://127.0.0.1:8080/health" -stage = "stage1" -expected_status = 200 - -[[observability.health_endpoints]] -name = "cluster-health" -url = "http://example-service.example-service.svc.cluster.local:8080/health" -stage = "stage2" -expected_status = 200 - -[[observability.metrics]] -name = "request-errors" -reference = 'promql:rate(http_requests_total{status=~"5.."}[5m])' -stage = "stage2" - -[[observability.logs]] -name = "secret-leak-scan" -reference = "kubectl logs -n example-service deploy/example-service-canary" -stage = "stage2" - -[stages.stage1] -enabled = true -namespace = "local" -release = "example-service-local" -commands = ["make test", "helm template charts/example-service"] -checks = ["unit-tests", "helm-template", "local-health"] -evidence = ["pytest output", "helm template success", "local health 200"] -requires_approval = false - -[stages.stage2] -enabled = true -namespace = "example-service" -release = "example-service-canary" -commands = ["bin/railiance deploy --stage 2 example-service", "bin/railiance observe example-service"] -checks = ["server-dry-run", "canary-ready", "cluster-health", "operator-approval"] -evidence = ["release name", "pod readiness", "health 200", "State Hub progress id"] -requires_approval = true -canary_mode = "isolated" -observation_minutes = 60 - -[stages.stage3] -enabled = true -namespace = "example-service" -release = "example-service" -commands = ["bin/railiance promote example-service", "bin/railiance observe example-service"] -checks = ["stage2-accepted", "rollback-target", "cluster-health", "operator-approval"] -evidence = ["promotion command id", "new stable digest", "post-promotion smoke"] -requires_approval = true -promotion_mode = "release-replace" -previous_stable = "helm:example-service:previous" - -[[checks]] -id = "unit-tests" -type = "command" -stage = "stage1" -description = "Run repository unit tests." -required = true -run = "make test" -timeout_seconds = 600 - -[[checks]] -id = "helm-template" -type = "helm" -stage = "stage1" -description = "Render Helm templates locally." -required = true -chart = "charts/example-service" -values = "values/local.yaml" -mode = "template" - -[[checks]] -id = "local-health" -type = "http" -stage = "stage1" -description = "Confirm local service health." -required = true -url = "http://127.0.0.1:8080/health" -expected_status = 200 -timeout_seconds = 10 - -[[checks]] -id = "server-dry-run" -type = "helm" -stage = "stage2" -description = "Render and submit a server-side dry run before canary." -required = true -chart = "charts/example-service" -values = "values/canary.yaml" -mode = "server-dry-run" - -[[checks]] -id = "canary-ready" -type = "kubernetes" -stage = "stage2" -description = "Canary deployment reaches Available." -required = true -namespace = "example-service" -resource = "deploy/example-service-canary" -condition = "Available" - -[[checks]] -id = "cluster-health" -type = "http" -stage = "stage2" -description = "Cluster health endpoint returns 200." -required = true -url = "http://example-service.example-service.svc.cluster.local:8080/health" -expected_status = 200 -timeout_seconds = 10 - -[[checks]] -id = "operator-approval" -type = "manual" -stage = "stage2" -description = "Human approval is recorded before production-critical traffic changes." -required = true -evidence_required = "State Hub approval note id, candidate digest, rollback target." - -[[checks]] -id = "stage2-accepted" -type = "manual" -stage = "stage3" -description = "Stage 2 gates passed for the same candidate artifact." -required = true -evidence_required = "State Hub Stage 2 acceptance progress id." - -[[checks]] -id = "rollback-target" -type = "manual" -stage = "stage3" -description = "Previous stable release is recorded before promotion." -required = true -evidence_required = "Previous Helm revision or image digest." diff --git a/schemas/railiance-app.schema.json b/schemas/railiance-app.schema.json deleted file mode 100644 index 2ff92a5..0000000 --- a/schemas/railiance-app.schema.json +++ /dev/null @@ -1,596 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://railiance.local/schemas/railiance-app.schema.json", - "title": "Railiance app.toml contract", - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "app", - "source", - "platform", - "secrets", - "observability", - "rollback", - "stages", - "checks" - ], - "properties": { - "schema_version": { - "const": "railiance.app.v1" - }, - "app": { - "type": "object", - "additionalProperties": false, - "required": [ - "id", - "name", - "repo", - "owner", - "criticality", - "description" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z0-9][a-z0-9-]*$" - }, - "name": { - "type": "string", - "minLength": 1 - }, - "repo": { - "type": "string", - "minLength": 1 - }, - "owner": { - "type": "string", - "minLength": 1 - }, - "criticality": { - "enum": [ - "low", - "medium", - "high", - "critical" - ] - }, - "description": { - "type": "string", - "minLength": 1 - } - } - }, - "source": { - "type": "object", - "additionalProperties": false, - "required": [ - "revision", - "artifact", - "digest_policy" - ], - "properties": { - "revision": { - "type": "string", - "minLength": 1 - }, - "artifact": { - "enum": [ - "image", - "helm-chart", - "bundle", - "manifest", - "other" - ] - }, - "digest_policy": { - "enum": [ - "required", - "preferred", - "not-applicable" - ] - } - } - }, - "platform": { - "type": "object", - "additionalProperties": false, - "required": [ - "dependencies" - ], - "properties": { - "dependencies": { - "type": "array", - "items": { - "$ref": "#/$defs/dependency" - } - } - } - }, - "secrets": { - "type": "object", - "additionalProperties": false, - "required": [ - "references" - ], - "properties": { - "references": { - "type": "array", - "items": { - "$ref": "#/$defs/secretReference" - } - } - } - }, - "observability": { - "type": "object", - "additionalProperties": false, - "required": [ - "health_endpoints" - ], - "properties": { - "health_endpoints": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/$defs/healthEndpoint" - } - }, - "metrics": { - "type": "array", - "default": [], - "items": { - "$ref": "#/$defs/observationReference" - } - }, - "logs": { - "type": "array", - "default": [], - "items": { - "$ref": "#/$defs/observationReference" - } - } - } - }, - "rollback": { - "type": "object", - "additionalProperties": false, - "required": [ - "strategy", - "command", - "verification" - ], - "properties": { - "strategy": { - "enum": [ - "helm-revision", - "image-digest", - "traffic-shift", - "manual-runbook", - "none" - ] - }, - "command": { - "type": "string", - "minLength": 1 - }, - "verification": { - "type": "string", - "minLength": 1 - } - } - }, - "stages": { - "type": "object", - "additionalProperties": false, - "required": [ - "stage1", - "stage2", - "stage3" - ], - "properties": { - "stage1": { - "$ref": "#/$defs/stage1" - }, - "stage2": { - "$ref": "#/$defs/stage2" - }, - "stage3": { - "$ref": "#/$defs/stage3" - } - } - }, - "checks": { - "type": "array", - "minItems": 1, - "items": { - "$ref": "#/$defs/check" - } - } - }, - "$defs": { - "stageName": { - "enum": [ - "stage1", - "stage2", - "stage3" - ] - }, - "dependency": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "kind", - "required", - "stage", - "evidence" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "kind": { - "enum": [ - "postgres", - "redis", - "object-store", - "identity", - "state-hub", - "inter-hub", - "network", - "other" - ] - }, - "required": { - "type": "boolean" - }, - "stage": { - "$ref": "#/$defs/stageName" - }, - "evidence": { - "type": "string", - "minLength": 1 - } - } - }, - "secretReference": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "route", - "target", - "stage", - "required" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "route": { - "type": "string", - "minLength": 1 - }, - "target": { - "type": "string", - "minLength": 1 - }, - "stage": { - "$ref": "#/$defs/stageName" - }, - "required": { - "type": "boolean" - } - }, - "not": { - "anyOf": [ - { - "required": [ - "value" - ] - }, - { - "required": [ - "token" - ] - }, - { - "required": [ - "password" - ] - }, - { - "required": [ - "secret" - ] - }, - { - "required": [ - "private_key" - ] - }, - { - "required": [ - "kubeconfig" - ] - } - ] - } - }, - "healthEndpoint": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "url", - "stage", - "expected_status" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "url": { - "type": "string", - "minLength": 1 - }, - "stage": { - "$ref": "#/$defs/stageName" - }, - "expected_status": { - "type": "integer", - "minimum": 100, - "maximum": 599 - } - } - }, - "observationReference": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "reference", - "stage" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "reference": { - "type": "string", - "minLength": 1 - }, - "stage": { - "$ref": "#/$defs/stageName" - } - } - }, - "check": { - "type": "object", - "additionalProperties": true, - "required": [ - "id", - "type", - "stage", - "description", - "required" - ], - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "enum": [ - "command", - "http", - "kubernetes", - "helm", - "metric", - "log", - "manual" - ] - }, - "stage": { - "$ref": "#/$defs/stageName" - }, - "description": { - "type": "string", - "minLength": 1 - }, - "required": { - "type": "boolean" - } - } - }, - "stage1": { - "type": "object", - "additionalProperties": false, - "required": [ - "enabled", - "namespace", - "release", - "commands", - "checks", - "evidence", - "requires_approval" - ], - "properties": { - "enabled": { - "type": "boolean" - }, - "namespace": { - "type": "string", - "minLength": 1 - }, - "release": { - "type": "string", - "minLength": 1 - }, - "commands": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "checks": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "evidence": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "requires_approval": { - "type": "boolean" - } - } - }, - "stage2": { - "type": "object", - "additionalProperties": false, - "required": [ - "enabled", - "namespace", - "release", - "commands", - "checks", - "evidence", - "requires_approval", - "canary_mode", - "observation_minutes" - ], - "properties": { - "enabled": { - "type": "boolean" - }, - "namespace": { - "type": "string", - "minLength": 1 - }, - "release": { - "type": "string", - "minLength": 1 - }, - "commands": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "checks": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "evidence": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "requires_approval": { - "type": "boolean" - }, - "canary_mode": { - "enum": [ - "weighted", - "header", - "path", - "shadow", - "isolated" - ] - }, - "observation_minutes": { - "type": "integer", - "minimum": 1 - }, - "traffic_percent": { - "type": "integer", - "minimum": 0, - "maximum": 100 - } - } - }, - "stage3": { - "type": "object", - "additionalProperties": false, - "required": [ - "enabled", - "namespace", - "release", - "commands", - "checks", - "evidence", - "requires_approval", - "promotion_mode", - "previous_stable" - ], - "properties": { - "enabled": { - "type": "boolean" - }, - "namespace": { - "type": "string", - "minLength": 1 - }, - "release": { - "type": "string", - "minLength": 1 - }, - "commands": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "checks": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "evidence": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - } - }, - "requires_approval": { - "type": "boolean" - }, - "promotion_mode": { - "enum": [ - "traffic-shift", - "release-replace", - "selector-switch", - "workflow" - ] - }, - "previous_stable": { - "type": "string", - "minLength": 1 - } - } - } - } -} diff --git a/workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md b/workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md deleted file mode 100644 index a1712a1..0000000 --- a/workplans/RAIL-K8S-WP-0001-bootstrap-and-wave1-import.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -id: RAIL-K8S-WP-0001 -type: workplan -title: "Bootstrap rail-kubernetes and import the wave-1 contract" -domain: financials -repo: rail-kubernetes -status: active -owner: codex -topic_slug: railiance -created: "2026-07-25" -updated: "2026-07-25" -state_hub_workstream_id: "1f2254f5-a873-46fc-a77c-bc725eeaaeb8" ---- - -# RAIL-K8S-WP-0001 - Bootstrap rail-kubernetes and import the wave-1 contract - -## Goal - -Turn `rail-kubernetes` into the concrete home of the default Railiance -execution rail. - -## Boundaries - -This workplan may bootstrap the repo, publish the initial declaration, and -import the generic wave-1 contract. - -It must not: - -- absorb S2 substrate ownership from `railiance-cluster` -- normalize workload-specific helper commands into the rail -- pretend the migration is complete before compatibility shims exist - -## T01 - Establish the repo baseline and rail declaration - -```task -id: RAIL-K8S-WP-0001-T01 -status: done -priority: high -state_hub_task_id: "9bab36db-e094-4e41-af76-b6bf5e73be78" -``` - -Create the baseline repo files, the initial rail declaration, and the first -wave-1 contract summary. - -Acceptance: - -- baseline repo files exist -- `declarations/rail.yaml` exists -- the repo states its boundary with `railiance-cluster` - -2026-07-25: Created the initial repo baseline, declaration, and wave-1 -contract summary. - -## T02 - Import the reviewed generic contract material - -```task -id: RAIL-K8S-WP-0001-T02 -status: progress -priority: high -state_hub_task_id: "148276a2-2e40-4d56-89dd-2930c5e4309c" -``` - -Bring the reviewed generic lifecycle docs, schema, examples, and helper -surfaces into this repo in a migration-safe sequence. - -Acceptance: - -- the import sequence is anchored in the reviewed extraction map -- imported material stays generic to the Kubernetes rail -- the repo becomes a real home for the default rail rather than only a shell - -2026-07-25: Established the repo-local contract summary and explicit source -import plan. Full import of docs, schema, examples, and helper surfaces is -still pending. - -2026-07-25: Imported the first core generic contract artifacts from -`railiance-cluster`: `docs/deployment-lifecycle.md`, -`docs/app-toml-contract.md`, `schemas/railiance-app.schema.json`, and -`examples/railiance/app.toml`. Helper command surfaces and the remaining -supporting docs are still pending. - -2026-07-25: Imported the remaining generic supporting docs from -`railiance-cluster`: `docs/overlay-repo-pattern.md`, -`docs/canary-helm-template.md`, `docs/stage2-deploy-observe.md`, -`docs/promote-rollback-onboarding.md`, and -`docs/railiance-run-command.md`. Helper scripts and command implementations -remain pending. - -## T03 - Prepare the compatibility handoff from `railiance-cluster` - -```task -id: RAIL-K8S-WP-0001-T03 -status: wait -priority: medium -state_hub_task_id: "18140d90-d10e-47fe-b7da-d454550466b1" -``` - -Define the thin compatibility path that keeps current operators functional -while the extraction proceeds. - -Acceptance: - -- the compatibility path is explicit -- current operators do not need a flag day -- the retained S2 surface stays narrow and temporary - -## T04 - Register `rail-kubernetes` in State Hub and Fabric - -```task -id: RAIL-K8S-WP-0001-T04 -status: progress -priority: medium -state_hub_task_id: "d78b5712-f305-4967-9034-9b9471633755" -``` - -Register the repo from classification and add it to the Fabric repository -registry with rail-family metadata. - -Acceptance: - -- State Hub recognizes the repo and its workplan -- Fabric recognizes the repo as `repo_family: rail` -- ownership and primary contract metadata are visible - -2026-07-25: Registered `rail-kubernetes` in State Hub and generated -`WORK-RECORDS.md` plus `.custodian-brief.md`. Added `rail-kubernetes` to -`railiance-fabric/registry/railiance-repos.yaml` as `repo_family: rail` with -`ownership_repo: railiance-cluster`. Live Fabric registry sync and Forgejo -remote provisioning remain pending. diff --git a/workplans/archived/.gitkeep b/workplans/archived/.gitkeep deleted file mode 100644 index 8b13789..0000000 --- a/workplans/archived/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -