Skip to content
bitzorcas
中EN

Concept

Production readiness

The manifest-driven production-readiness model — the surface-to-manifest mapping, the legacy ledger ratchet, and the adapter readiness guard that fails closed in Production/Staging.

Last updated

Production readiness is manifest-driven: adding or modifying a runtime surface requires updating the corresponding machine-readable manifest, guarded by architecture tests. This replaces drift-prone human checklists — whose failure mode is well known: every box gets ticked in the review meeting, two weeks later every item has diverged from reality, and not a single test turns red.

drift

Runtime surface or contract change

Owning governance manifest

Architecture / contract tests

Layered CI verification

Production / Staging startup guard

Immutable release evidence

Fail closed

Surface-to-manifest mapping

Runtime surfaceManifest / gate
Module roots / IAppModule0001-module-governance-legacy-ledger.json
Default adapters / production replacements0002-production-adapter-readiness.json
Docker contract testsCI matrix + DockerContractTraitTests
Template versions / upgrade flow0004-template-upgrade-map.json
Operations visibility (probes, jobs, config, health, smoke)0003-operations-runtime-surface.json
GA cutover runbookdocs/guides/ga-cutover-runbook.md
Fail-closed production configuration baselinedocs/guides/production-configuration-template.md
Strong-typed error catalog / legacy compatibility0008-error-catalog.json + 0009-error-catalog-legacy-baseline.json
Commercial package catalog / Profile closure / release provenance0010-commercial-package-catalog.json + 0011-profile-package-closure.json + 0012-… schema
Runtime License policies / static composition admission0013-runtime-license-policy-catalog.json
Document lifecycle & hot-path budget0014-document-lifecycle-budget.json
Mediator pipeline capabilities & Consumer projection0015-pipeline-capability-catalog.json
Third-party license evidence0016-third-party-license-evidence.json
Field-security resources & execution-surface closure0017-field-security-resource-catalog.json
Package signing / private feed / SBOMADR 0605 + commercial release gates
Runtime License state / readinessADR 0503 + License contracts + Host integration tests

The manifest naming itself is test-guarded

Manifests are more than data — their structure is governed too. ProductionReadinessNamingTests (in the architecture test project) forces long-term readiness manifests to declare "scope": "production-readiness" and forbids a phase field, preventing transitional states from quietly becoming permanent ledgers. The same test group bans CreatedAt/createdAt naming repository-wide (everything aligns on the entity base class’s CreateTime). In other words: to add a new manifest field you first have to convince an architecture test to accept the new schema shape.

The legacy ledger ratchet

0001-module-governance-legacy-ledger.json is a ratchet: it can only shrink. New modules cannot bypass owner-local compile-time markers by adding legacy entries, and maxLegacyRoots must decrease as legacy roots are deleted (currently zero). ModuleGovernanceRegistrationTests enforces this at compile time.

The adapter readiness guard

0002-production-adapter-readiness.json currently tracks 38 default-port-to-production-adapter replacement relationships, each record carrying its own readiness semantics and evidence fields. Here is a real entry (the ledger’s first):

0002-production-adapter-readiness.json
{
"port": "IUnitOfWork",
"defaultAdapter": "NullUnitOfWork",
"riskLevel": "ProductionReady",
"replacementRequired": true,
"requiredProductionAdapter": "SqlSugarUnitOfWork, CapSqlSugarUnitOfWork, EfCoreUnitOfWork, or CapEfCoreUnitOfWork",
"configDiagnostic": "ConnectionStrings:Default or SqlSugar:ConnectionString plus CAP/RabbitMQ configuration for outbox wiring",
"healthDiagnostic": "runtime-dependencies readiness plus database/CAP adapter health",
"contractGate": "RepositoryContractTestBase and OrmAdapterParityTests",
"registrationEvidence": "src/Framework/BitzOrcas.Infrastructure.SqlSugar/DependencyInjection.cs; src/Framework/BitzOrcas.Infrastructure.EfCore/DependencyInjection.cs",
"operationsVisibility": "OperationsService adapter probe for IUnitOfWork"
}

The nine fields each answer one operational question: configDiagnostic tells operators which missing key causes failure and how to fix it; healthDiagnostic says what signal health checks watch; contractGate points at the concrete test base classes proving the adapter works; registrationEvidence pins the source files where registration happens — so every declaration traces to code in one click during review.

Risk tiers use a controlled enum with five levels, from “shippable now” to “developer machines only”:

riskLevelEntries todayRuntime semantics
ProductionReady35Production replacement backed by config diagnostics, health diagnostics, and a contract gate
FailClosedUnavailable3Explicitly unavailable ports (e.g. IAuditQueryPort → UnavailableAuditQueryPort); callers get a stable failure instead of silent no-op
ProductionBlocker0 (reserved)Once registered, the Production/Staging startup guard blocks outright
ProductionConditional0 (reserved)Once registered, production compositions are refused until explicit conditions are met
DevelopmentOnly0 (reserved)API Shell/local development/tests only

At startup, ProductionAdapterReadinessGuard resolves every Required port and fails fast if the resolved default belongs to a blocking tier. The rule is plain but effective: before any InMemory*/Null*/Unavailable* default adapter reaches production, a production adapter with health diagnostics, config diagnostics, and contract tests must exist. See Persistence defaults.

Current manifest scale

Scale is not a quality verdict, but it helps spot the drift pattern of “source expanded, manifest stayed behind.” When reviewing, measure the JSON directly — never quote numbers from memory:

Measure the manifests
# Run at the framework repo root; number drift means source or manifest was updated without the other.
jq '.entries | length' docs/architecture/00-governance/manifests/0008-error-catalog.json # 1968 strong-typed error codes
jq '.entries | length' docs/architecture/00-governance/manifests/0002-production-adapter-readiness.json # 38 port replacement relationships
jq '.packages | length' docs/architecture/00-governance/manifests/0010-commercial-package-catalog.json # 142 commercial packages
jq '.capabilities | length' docs/architecture/00-governance/manifests/0015-pipeline-capability-catalog.json # 15 pipeline capabilities
jq '[.packages[]?] | length' docs/architecture/00-governance/manifests/0016-third-party-license-evidence.json # 19 third-party license evidence packages

All counts must be read from the JSON manifests and guarded by architecture tests; never maintain a parallel hand-written list in documentation — this page’s own history includes the lesson of an error catalog whose count sat at three different values across documents after one expansion.

0015-pipeline-capability-catalog.json also generates the Host’s PipelineCapabilityProjection.g.cs and constrains Consumer Profile pipeline closures. New behavior cannot just push types into DI; register the capability first — applicable pipelines, ordering relations, projection, and coverage policy — then update generated artifacts and Consumer contract tests.

Gate execution order

  1. From source, locate the changed owner, public contracts, and runtime execution surfaces.
  2. Update the single manifest that owns that fact; do not duplicate the same state in a second JSON.
  3. Regenerate manifest-driven code, catalogs, or doc artifacts, and check that the diff contains only expected changes.
  4. Run manifest schema and architecture ratchets first, then behavior and failure tests for the affected module.
  5. Run startup validation against the Production/Staging composition to prove defaults and Unavailable adapters cannot silently take over.
  6. Replay delivery paths from cold cache, an isolated Consumer, or real containers so local ProjectReference cannot mask missing packages.
  7. Assemble commit, manifest hashes, test results, package hashes, and approval tickets into one release evidence package.

Passing manifest validation only proves internal consistency; external services still need their own contracts, health checks, and failure drills — databases, message brokers, object storage, private feeds, signing gateways, license services.

Release evidence package

EvidenceQuestion answered
Source commit & clean-tree recordWhich implementation was tested
Manifest files plus SHA-256Were the governance facts reviewed at approval replaced
Architecture & contract test resultsDo ownership, closures, ratchets, failure semantics agree
Container / Consumer cold-cache resultsDoes the deliverable work outside the product repo
Package signature, SBOM, license & vulnerability resultsIs supply chain traceable
Production config & readiness snapshotDoes the target environment run production adapters with dependencies met
Rollback version, data-compatibility verdict, ownersCan recovery happen within explicit boundaries after failure

Failure handling

  • Manifest drift: stop the release; determine whether source or manifest represents intent; never update numbers just to make tests green.
  • ProductionBlocker: add the production adapter, health, and contract tests, or explicitly disable the feature; never degrade to Null behavior.
  • Consumer restore failures: check Package Source Mapping, version closure, and analyzer/buildTransitive assets; do not fall back to ProjectReference.
  • License or signing evidence failures: keep the commercial entry fail-closed while preserving established safety nets for identity recovery, backup, export, and migration.
  • External dependency outages: follow the runbook for retry, grace period, DLQ, or degraded state, then capture fresh evidence after recovery.

See also

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%