Skip to main content

Generated State CI Policy

This document defines the CI contract for generated TraderX code branches.

Scope

  • Security and license CI is required for all generated states from 002+.
  • States 001-003 are pre-container states and should not carry Docker/Compose artifacts in published generated snapshots.
  • Container image build validation CI starts at state 004+ for states that include buildable container images.
  • Container image build/publish CI is required only for convergence states from C0+.

Required CI For States 002+

Each generated code/generated-state-* branch must include CI workflows for dependency security and license scanning:

  • .github/workflows/security.yml
  • .github/workflows/license-scanning-node.yml (required when the state contains Node.js components)

These workflows must cover every applicable component in the generated state:

  • Java/Gradle components in Gradle scan jobs
  • .NET components in .NET scan jobs
  • Node.js components in Node scan and license jobs
  • containerized components in container vulnerability scan jobs

Coverage must be derived from generated component manifests/catalog data, not a manually maintained static list.

Node License Requirement

All generated Node.js projects must declare:

"license": "Apache-2.0"

Policy:

  • Any new Node.js project introduced by a state transition must include this license field in its generated package.json.
  • License scanning workflows should fail when a generated Node.js project omits this declaration.

Node Lockfile Generation Policy

Node lockfiles are source-controlled generated artifacts and part of state lineage.

Policy:

  • Generated Node projects must include a package-lock.json.
  • Lockfiles must be refreshed only when the corresponding package.json changes, or when lockfiles are missing/invalid.
  • State patchsets should include lockfile deltas when state changes affect Node manifests.
  • Generated-branch publish is blocked if Node manifests and lockfiles are inconsistent.

Hermetic Default Test Policy

Default build/test CI must not depend on external runtime services.

Policy:

  • Generated branch default build/test jobs must run hermetically on CI runners without requiring external databases, brokers, or network endpoints.
  • Database-backed tests in default suites must use in-memory/embedded engines (or equivalent isolated local test engines).
  • External runtime validation (for example real PostgreSQL or broker integration) must run in explicitly named integration profiles/jobs separate from default build/test gates.
  • State deltas introducing new database-backed modules must include test profile/config updates that preserve this policy.

CVE Suppression Contract

Generated branches must carry the CVE suppression files used by security scanning:

  • .github/gradle-cve-ignore-list.xml
  • .github/node-cve-ignore-list.xml
  • .github/dotnet-cve-ignore-list.xml

Policy:

  • Keep a baseline suppression set shared across generated states.
  • Allow state-specific suppression deltas when dependency sets diverge.
  • When a state changes dependencies, update scanner coverage and suppression files in the same change.

Dependency Source-Of-Truth Contract

Version policy changes must be landed in generator sources, not as ad-hoc generated-output edits.

  • Baseline runtime/dependency versions belong in templates/**.
  • State-specific version deltas belong in specs/<state>/generation/patches/*.patch.
  • Post-generation mutation scripts are not allowed in steady-state; generation must be reproducible directly from templates and state patchsets.

Messaging Subject Map Contract

Messaging states must keep a canonical subject registry in-state.

Policy:

  • States 006+ must include system/messaging-subject-map.md.
  • The file must be cumulative for that state (all active subject families).
  • Subject-map format requirements are defined in docs/spec-kit/messaging-subject-map-standard.md.
  • Generated-state contract validation must fail when order-matcher states omit required order subjects.

External Dependency Pin Contract (Sail / State 014)

State 014-fdc3-intent-interoperability depends on a local Sail sidecar and must use explicit pin governance.

Policy:

  • Sail pin metadata is state-owned in specs/014-fdc3-intent-interoperability/generation/sail-pin.env.
  • Pin metadata must include repo URL, tracking ref, pinned commit SHA, and updated-on date.
  • Generated state 014 artifacts must consume that pin (sail/bootstrap/sail-pin.env + bootstrap defaults).
  • Root quality gates must validate pin-manifest contract (bash pipeline/validate-sail-pin-contract.sh).
  • Maintenance workflows must run drift detection (bash pipeline/check-sail-pin-drift.sh --fail-on-drift) before repinning.

Jump-Point Overlay Parity Contract

When a state first materializes full runtime files that no longer point directly at templates/** (for example, root-level module build.gradle files in a convergence jump-point), that state must preserve inherited base-template policy unless an explicit state requirement overrides it.

Policy:

  • Generic dependency/security/runtime controls remain owned by base templates.
  • Jump-point state patchsets must not silently drop inherited template controls (dependency pins, exclusion blocks, plugin/runtime version guards).
  • If a base template policy changes, maintainers must re-evaluate the nearest jump-point state patchset and propagate required parity updates.
  • Any intentional divergence must be explicitly documented in the state FR/NFR deltas.

Gradle Wrapper Ownership Policy

Gradle wrapper assets are baseline template artifacts, not state patch artifacts.

Policy:

  • Canonical wrapper files live in templates/gradle-wrapper/:
    • gradlew
    • gradlew.bat
    • gradle/wrapper/gradle-wrapper.jar
    • gradle/wrapper/gradle-wrapper.properties
  • Generated Gradle modules must receive wrapper assets from this canonical baseline during generation.
  • State patchsets must not carry wrapper binary/script/properties diffs; wrapper version updates are made once in templates and inherited by all states.

Patch Hygiene Ownership Policy

State patchsets must contain authored state deltas only, not local build byproducts.

Policy:

  • Do not include compiled/restored output directories in state patch payloads:
    • .gradle/**
    • build/**
    • target/**
    • bin/**
    • obj/**
    • dist/**
    • coverage/**
    • node_modules/**
  • Keep dependency lockfiles consistent with their manifests; include lockfile deltas in patchsets when manifests change.
  • Build/restored artifacts must be produced by generation/runtime/build commands, never maintained by state patch files.

Preflight gates:

bash pipeline/validate-template-version-consistency.sh
bash pipeline/validate-generated-dependency-targets.sh generated/code/components generated/code/target-generated

# verifies dependency key versions are consistent across generated state branches
bash pipeline/validate-generated-branch-dependency-consistency.sh

Convergence CI For C0+

Each convergence state from C0+ must include:

  • .github/workflows/build-and-publish.yml

The workflow must build and publish all containerized components present in that convergence state to GHCR.

Non-Convergence Container CI

For non-convergence states that include containerized components, generated branches must include:

  • .github/workflows/build-container-images.yml

Policy:

  • Build all detected container images for validation.
  • Do not publish images to GHCR.
  • Do not generate GHCR runtime bundles for non-convergence states.
  • This policy applies from state 004+ onward; pre-container states (001-003) must not emit container build workflows.

GHCR Namespace Policy For Convergence States

Use convergence-level namespaces (not numeric state ids):

  • C0: ghcr.io/finos/traderx-c0/<component>
  • C1: ghcr.io/finos/traderx-c1/<component>
  • C2: ghcr.io/finos/traderx-c2/<component>
  • C3: ghcr.io/finos/traderx-c3/<component>

Each image publish must include:

  • immutable tag: commit SHA
  • moving tag: latest

State Run Bundle Requirement For C0+

Each convergence state from C0+ must publish a generated run bundle for consuming GHCR images without local source builds.

Minimum bundle artifacts:

  • runtime manifest(s) that reference published GHCR images
  • .env.example or equivalent runtime config template
  • state run README with copyable startup commands

Deployment Bundle Contract For Containerized Demo States

Generated snapshots may include deployment bundles only for containerized states that explicitly opt in via state catalog metadata.

Policy:

  • Pre-container states (001-003) MUST NOT emit deployment bundles.
  • Deployment bundle assets, when enabled, live under runtime/deploy/<profile>/.
  • Initial profile contract is aws-ec2-compose for compose-based demo rollout.
  • Deployment scripts MUST support --dry-run and use env vars for environment-specific values (for example target branch, domain/FQDN, image tag).
  • Deployment scripts MUST NOT contain embedded credentials/tokens/secrets.
  • Deployment bundles MUST include host-prerequisite setup assets (host-setup-check.sh and host-setup-install.sh) for the emitted profile.
  • Default generated deploy-clone instructions MUST use tokenless public repository URLs; token-authenticated clone guidance should be optional and only for private forks.
  • Deployment bundle generation must come from canonical templates/generator logic, not manual edits on generated-state branches.

Profile matrix:

  • aws-ec2-compose (active): compose-runtime states.
  • aws-ec2-k8s (planned): Kubernetes-runtime states (010+) once profile-generation support lands.

Recommended minimum deployment bundle assets:

  • runtime/deploy/<profile>/README.md
  • runtime/deploy/<profile>/deploy.sh
  • runtime/deploy/<profile>/upgrade.sh
  • runtime/deploy/<profile>/cleanup.sh
  • runtime/deploy/<profile>/host-setup-check.sh
  • runtime/deploy/<profile>/host-setup-install.sh
  • runtime/deploy/<profile>/nginx.reverse-proxy.snippet.conf

Reverse-proxy snippet contract:

  • Must include websocket upgrade headers (Upgrade, Connection, HTTP/1.1) for websocket routes.
  • Must include websocket path mappings required by runtime messaging transport for the emitted state (for example /nats-ws for NATS-enabled state lineage), and avoid transport-specific stale routes that are no longer active for that state.

Planned Kubernetes deploy profile contract (aws-ec2-k8s):

  • Must emit Kubernetes-specific deploy assets (for example ingress values/templates and cluster smoke checks), not Compose-only scripts.
  • Must include host setup check/install scripts for Kubernetes operator dependencies (kubectl, helm, and cluster access checks).
  • Must include dry-run deploy/upgrade/cleanup behavior consistent with compose profile expectations.
  • Must remain disabled in catalog (deploy.enabled=false) until generator support and profile smoke tests are implemented.

Local CI Preflight Before Publish

Generated branch publish runs a prepublish CI-parity gate by default via pipeline/publish-generated-state-branch.sh.

Run the same gate manually when validating outside publish flow:

bash pipeline/prepublish-generated-state-gate.sh <state-id>

The gate enforces:

  • generated-state contract validation
  • compile preflight for Node/Gradle/.NET modules
  • dependency target/version propagation checks
  • UI status metadata + lineage invariants
  • Node license scanning
  • container image buildability checks
  • dependency CVE scanning with suppression rules

Emergency override remains explicit and operator-invoked:

bash pipeline/publish-generated-state-branch.sh <state-id> --skip-prepublish-gate

Publish Gate

Generated branch publish is blocked unless:

  • required CI workflows are present for the target state,
  • scanner/build matrices include all applicable components,
  • required suppression files are present and valid,
  • prepublish CI-parity gate checks pass.