Generated State Branches
TraderX keeps the canonical source of truth in specs/** + .specify/**, and publishes code-only snapshots in dedicated code/generated-state-* branches.
Canonical State Definitions
Each state is defined in two places:
- SpecKit feature pack:
specs/NNN-<state-name>/ - State catalog entry:
catalog/state-catalog.json
The state catalog is the publish contract for generated snapshots:
- state id/title/status
- predecessor states (
previous) - convergence metadata (
isConvergence,convergenceLevel,dottedParents,primaryLineageRole) - generation readiness (
generation.mode) - default generated-state branch name
- release tag hint
- optional deployment-bundle metadata (
deploy.enabled,deploy.profile, environment labels/domain hints)
Live demo environment mappings are tracked separately in:
catalog/live-environments.json/docs/spec-kit/live-environments
State Independence + Lineage
Each state must be buildable from its own feature pack without requiring branch-local edits.
Publish lineage is explicit through previous in catalog/state-catalog.json.
Dotted-line parents are documentation lineage only and are not used for branch ancestry.
Generated branches include metadata files so consumers can always see provenance:
STATE.md.traderx-state/state.jsonLEARNING.mdFUNCTIONAL_TESTING.mddocs/learning/*generated learning artifacts (component list, system design, architecture, diagram)- optional
runtime/deploy/*deployment bundle artifacts for containerized states that explicitly opt in
These files record:
- current state id/title
- prior states and known next states
- source branch/commit used to generate snapshot
- generation timestamp
- state-oriented learning links back to canonical docs/specs
- plain-English functional behavior expectations plus smoke-test entrypoints for that snapshot
Canonical portal learning guides live at:
/docs/learning
Publish The Baseline Generated Branch
From a clean working tree:
bash pipeline/publish-generated-state-branch.sh 001-baseline-uncontainerized-parity --push
By default, publish now runs a prepublish CI-parity gate before commit/push
(pipeline/prepublish-generated-state-gate.sh) against generated outputs.
Use --skip-prepublish-gate only for explicit operator override cases.
When adding or updating a state, publish the lineage neighborhood so adjacent branches get refreshed lineage/compare links:
bash pipeline/publish-generated-state-neighborhood.sh <state-id> --push
Default branch target for baseline:
code/generated-state-001-baseline-uncontainerized-parity
State 002-edge-proxy-uncontainerized now uses:
- generation:
bash pipeline/generate-state.sh 002-edge-proxy-uncontainerized - runtime (first run/build):
./scripts/start-state-002-edge-proxy-generated.sh --build-only - runtime (start after build):
./scripts/start-state-002-edge-proxy-generated.sh - publish branch:
code/generated-state-002-edge-proxy-uncontainerized
Publish branch snapshot:
bash pipeline/publish-generated-state-branch.sh 002-edge-proxy-uncontainerized --push
State 004-containerized-compose-runtime now uses:
- generation:
bash pipeline/generate-state.sh 004-containerized-compose-runtime - runtime (default build + start):
./scripts/start-state-004-containerized-generated.sh(NGINX ingress onhttp://localhost:8080) - runtime (restart without image rebuild):
./scripts/start-state-004-containerized-generated.sh --skip-build - publish branch:
code/generated-state-004-containerized-compose-runtime
Publish branch snapshot:
bash pipeline/publish-generated-state-branch.sh 004-containerized-compose-runtime --push
Current published generated branches:
code/generated-state-001-baseline-uncontainerized-paritycode/generated-state-002-edge-proxy-uncontainerizedcode/generated-state-004-containerized-compose-runtime
Branch Invariant -- One Commit Per State
Every code/generated-state-<id> branch, in both upstream and any custom overlay, must contain exactly one content commit on top of its base branch.
How this works:
- The publish script always starts from the base branch (the previous state's branch, or the root anchor), not from the existing generated branch tip.
- The publish script creates or resets the generated branch to the base tip using
git checkout -B. - The full generated snapshot is applied as a single commit.
- The publish script force-pushes that branch (
git push --force) to replace the prior snapshot commit.
Why this matters:
git diff code/generated-state-A code/generated-state-Bstays a clean state-to-state diff.- Lineage is expressed through branch ancestry (the base branch), not through cumulative commit depth.
- History remains readable and reproducible for both humans and automation.
Custom overlay pipelines must enforce the same invariant. Using --force-with-lease on a branch that accumulates commits does not satisfy this model.
Behavior Invariant -- Inherit Unless Explicitly Replaced
Across upstream and custom overlays, each state must preserve parent behavior by default.
Required rule:
- Downstream states inherit all prior behavior from
previouslineage unless the state spec explicitly declares a conflict, replacement, or deprecation. - Runtime migrations (for example Compose to Kubernetes) must carry inherited capabilities forward unless an explicit requirement says otherwise.
- Smoke tests for downstream states should include inherited capability checks so regressions are detected during publish.
CI Invariant -- Required Generated Workflows
Generated-state branches must carry CI workflows that match the state's technology surface.
- States
002+must include security and license scanning workflows. - Coverage must include all applicable generated components (Java/.NET/Node/containerized).
- CVE suppression files used by the scans must be present and versioned with the generated state.
Convergence states C0+ must also include container image build/publish workflows and a generated run bundle that references published images.
Canonical policy and local preflight guidance:
/docs/spec-kit/generated-state-ci
Template Invariant -- Source Of Truth Lives In Templates/Patchsets
Dependency/runtime version changes must be maintained in canonical generator sources, not as post-generation edits.
Required rule:
- Baseline component defaults are maintained in
templates/**(for example Javabuild.gradle, Gradle wrapper, and shared runtime/library versions). - Derived state deviations are maintained in state patchsets under
specs/<state>/generation/patches/*.patch. - Post-generation mutation scripts are not allowed in steady-state generation; canonical templates and patchsets must fully define output content.
- Version targets are declared in
catalog/dependency-version-targets.jsonand must pass before publish:
bash pipeline/validate-template-version-consistency.sh
bash pipeline/validate-generated-dependency-targets.sh generated/code/components generated/code/target-generated
bash pipeline/validate-generated-branch-dependency-consistency.sh
How To Add A New State
- Scaffold the feature pack:
bash pipeline/scaffold-state-pack.sh <NNN-state-name> --title "<Title>" --previous <prior-state-id> --track <prelude|baseline|architecture|nonfunctional|functional|devex>
- Add/update requirements, plan, tasks, contracts, and traceability for the new state.
- Confirm state entry in
catalog/state-catalog.jsonwith:previouslineage- publish branch/tag conventions
generation.mode=planneduntil implemented
- Implement state generation pipeline and change
generation.modetoimplemented. - Publish generated branch + tag with validation evidence.
Recommended publish sequence after implementing a new state:
bash pipeline/publish-generated-state-neighborhood.sh <state-id> --pushbash pipeline/publish-generated-state-tree.sh --push(optional full refresh)
This keeps specification and generated code distribution clearly separated while preserving state-to-state continuity.