Integrating Conseqa Verification into Your CI Pipeline
Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.
Running Conseqa in CI gives your team a formal check on every change that touches the architecture model. A regression that would introduce a disproven obligation or break a previously proven one is caught before it merges, and the obligation report and visualization HTML become searchable artifacts attached to every build.
Verify your model and write the obligation report to a file:
conseqa model.yaml --report report.json
The tool prints an obligation summary to stdout and exits with a non-zero code only when the model fails to parse or fails validation (malformed YAML, invalid references). A model that validates and verifies, regardless of how many obligations are proven, unknown, or disproven, exits zero. Use the report JSON to inspect verdicts and enforce your own pass/fail policy.
unknown obligations are epistemic: the checker could not establish the property from the declared facts. They are never evidence of a violation. disproven obligations mean the checker found a counterexample: inspect these with conseqa-viz --report report.json to understand the evidence.
This step uses the already-computed report rather than re-running verification, so it adds minimal time to the pipeline. The output is a single self-contained HTML file with the full interactive proof overlay.
The if: always() guards on the visualization and upload steps ensure that artifacts are produced even when the verify step fails, so you can inspect the proof state on a failing build.
Store model.yaml in the same repository as your service code, not in a separate architecture repository. This keeps the model in sync with the implementation it describes and makes diff review natural:
my-service/ src/ model.yaml ← lives here report.json ← committed baseline (see tip below) Cargo.toml
When a code change requires a model update, the model diff and the implementation diff land in the same pull request. Reviewers can see both together, and CI verifies the updated model against the updated code in the same build.
conseqa exits zero after verification regardless of verdict counts: the exit code only signals whether the model is structurally valid. To fail the build on unwanted obligation statuses, add an explicit check using the report JSON:
# Fail if any obligation is disprovenjq -e '[.obligations[] | select(.status == "disproven")] | length == 0' report.json
To require that every obligation is proven, rejecting both unknown and disproven:
# Fail if any obligation is not 'proven'jq -e '[.obligations[] | select(.status != "proven")] | length == 0' report.json
Adjust the filter to match your team’s policy. A newly added requirement starts as unknown; you can choose to treat that as a warning or a hard block depending on your workflow.
Commit report.json to your repository as a baseline. When the verifier’s output changes (a previously unknown obligation becomes proven, or a new requirement is added), the diff in report.json makes the change visible in code review. Reviewers can confirm that new obligations are intentional and that any regression from proven to unknown is understood.
A committed report also means the visualization step in CI never needs to re-run verification: it loads the committed report directly, which keeps the viz step fast regardless of model complexity.
Each obligation in the report now carries a scope field:
l0_only: the proof required no runtime facts.
runtime_dependent: the proof consumed at least one L1 fact (delivery semantics, routing, pool concurrency, outbox runtime, and so on).
This is useful for CI matrices that verify both a minimal L0-only model and a full model with runtime topology. Removing the runtime block from a valid model leaves it valid: runtime-dependent proofs simply become unproven, never structural errors. A CI job that strips the runtime block and re-runs the verifier can confirm that the L0 layer stands on its own, while the full-runtime variant checks the complete architecture.
{"docsConfig":{"theme":"aspen","$schema":"https://mintlify.com/docs.json","name":"Conseqa","colors":{"primary":"#5B4FCF","light":"#EDE9FF","dark":"#2D2460"},"favicon":"https://mintcdn.com/archspec/CgpsaKCVXill437h/favicon.svg?fit=max\u0026auto=format\u0026n=CgpsaKCVXill437h\u0026q=85\u0026s=fcfb437e6c8de76218c8ba7d2b92cc45","navbar":{"primary":{"type":"github","href":"https://github.com/umran/conseqa"}},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"archspec","hasAudioNarration":false,"actualSubdomain":"archspec","customDomains":["docs.conseqa.umran.ca"],"gitSource":{"type":"github","owner":"umran","repo":"mintlify-docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"chroma":{"latestBuiltDeploymentHistoryId":"6aa2a2cbaa1ac635e5bd65c9","collectionId":"f56c2ea9-4331-4a26-b87e-2004157e0ead","liveDeploymentHistoryId":"6aa2a2cbaa1ac635e5bd65c9","schemaVersion":"v3"},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6aa2a2cbaa1ac635e5bd65c9","clientVersion":"0.0.4045","searchFilterCounts":[{"language":"default","tag":"Documentation","count":32},{"language":"default","tag":"Core Concepts","count":8},{"language":"default","tag":"DSL Reference","count":6},{"language":"default","tag":"Runtime Topology","count":5},{"language":"default","tag":"Visualization","count":4},{"language":"default","tag":"Guides","count":3},{"language":"default","tag":"Get Started","count":3},{"language":"default","tag":"Verification","count":3},{"language":"default","tag":"CLI Reference","count":2},{"language":"default","tag":"Commands","count":2}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"guides/ci-integration","slug":"/guides/ci-integration","pageMetadata":{"title":"Integrating Conseqa Verification into Your CI Pipeline","sidebarTitle":"CI Integration","description":"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.","href":"/guides/ci-integration"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Note,Tip}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);if(!Tip)_missingMdxReference(`Tip`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`Running Conseqa in CI gives your team a formal check on every change that touches the architecture model. A regression that would introduce a disproven obligation or break a previously proven one is caught before it merges, and the obligation report and visualization HTML become searchable artifacts attached to every build.`}),`\n`,_jsx(Heading,{level:`2`,id:`build-step`,children:`Build step`}),`\n`,_jsx(_components.p,{children:`Conseqa ships as a Rust crate. Build the release binaries once per pipeline environment or Docker layer:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`cargo`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` build`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --release`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# binaries at target/release/conseqa and target/release/conseqa-viz`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`If you maintain pre-built binaries or a container image, place them on `,_jsx(_components.code,{children:`PATH`}),` and use `,_jsx(_components.code,{children:`conseqa`}),` and `,_jsx(_components.code,{children:`conseqa-viz`}),` directly in subsequent steps.`]}),`\n`,_jsx(Heading,{level:`2`,id:`run-the-verifier`,children:`Run the verifier`}),`\n`,_jsx(_components.p,{children:`Verify your model and write the obligation report to a file:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`conseqa`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` model.yaml`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --report`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` report.json`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The tool prints an obligation summary to stdout and exits with a non-zero code only when the model fails to parse or fails validation (malformed YAML, invalid references). A model that validates and verifies, regardless of how many obligations are `,_jsx(_components.code,{children:`proven`}),`, `,_jsx(_components.code,{children:`unknown`}),`, or `,_jsx(_components.code,{children:`disproven`}),`, exits zero. Use the report JSON to inspect verdicts and enforce your own pass/fail policy.`]}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`unknown`}),` obligations are epistemic: the checker could not establish the property from the declared facts. They are never evidence of a violation. `,_jsx(_components.code,{children:`disproven`}),` obligations mean the checker found a counterexample: inspect these with `,_jsx(_components.code,{children:`conseqa-viz --report report.json`}),` to understand the evidence.`]})}),`\n`,_jsx(Heading,{level:`2`,id:`generate-the-visualization-artifact`,children:`Generate the visualization artifact`}),`\n`,_jsx(_components.p,{children:`After the report is written, generate the HTML visualization:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`conseqa-viz`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` model.yaml`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --report`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` report.json`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` --out`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` architecture.html`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`This step uses the already-computed report rather than re-running verification, so it adds minimal time to the pipeline. The output is a single self-contained HTML file with the full interactive proof overlay.`}),`\n`,_jsx(Heading,{level:`2`,id:`github-actions-example`,children:`GitHub Actions example`}),`\n`,_jsx(_components.p,{children:`Add a job to your workflow that runs on any push touching the model file:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`57`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`57`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Architecture verification`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`on`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` push`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` paths`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"model.yaml\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Cargo.toml\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"Cargo.lock\"`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` pull_request`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` paths`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"model.yaml\"`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`jobs`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` verify`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` runs-on`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`ubuntu-latest`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` steps`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/checkout@v4`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Install Rust toolchain`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`dtolnay/rust-toolchain@stable`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Cache Cargo registry`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/cache@v4`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` with`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`|`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ~/.cargo/registry`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ~/.cargo/git`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` target`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` key`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:\"${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock')}}\"})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Build Conseqa`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`cargo build --release`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Verify architecture model`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`./target/release/conseqa model.yaml --report report.json`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Generate visualization`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`always()`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`>`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ./target/release/conseqa-viz model.yaml`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` --report report.json`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` --out architecture.html`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:' --title \"${{ github.repository }} architecture\"'})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Upload proof report`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`always()`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/upload-artifact@v4`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` with`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`proof-report`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`report.json`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`Upload visualization`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`always()`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/upload-artifact@v4`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` with`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` name`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`architecture-visualization`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` path`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`architecture.html`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`if: always()`}),` guards on the visualization and upload steps ensure that artifacts are produced even when the verify step fails, so you can inspect the proof state on a failing build.`]}),`\n`,_jsx(Heading,{level:`2`,id:`keeping-the-model-with-your-service-code`,children:`Keeping the model with your service code`}),`\n`,_jsxs(_components.p,{children:[`Store `,_jsx(_components.code,{children:`model.yaml`}),` in the same repository as your service code, not in a separate architecture repository. This keeps the model in sync with the implementation it describes and makes diff review natural:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`6`,language:`text`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`text`,children:_jsxs(_components.code,{language:`text`,numberOfLines:`6`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:`my-service/`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` src/`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` model.yaml ← lives here`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` report.json ← committed baseline (see tip below)`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{children:` Cargo.toml`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{})})]})})}),`\n`,_jsx(_components.p,{children:`When a code change requires a model update, the model diff and the implementation diff land in the same pull request. Reviewers can see both together, and CI verifies the updated model against the updated code in the same build.`}),`\n`,_jsx(Heading,{level:`2`,id:`failing-on-disproven-obligations`,children:`Failing on disproven obligations`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`conseqa`}),` exits zero after verification regardless of verdict counts: the exit code only signals whether the model is structurally valid. To fail the build on unwanted obligation statuses, add an explicit check using the report JSON:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Fail if any obligation is disproven`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`jq`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '[.obligations[] | select(.status == \"disproven\")] | length == 0'`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` report.json`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`To require that every obligation is `,_jsx(_components.code,{children:`proven`}),`, rejecting both `,_jsx(_components.code,{children:`unknown`}),` and `,_jsx(_components.code,{children:`disproven`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:`# Fail if any obligation is not 'proven'`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`jq`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -e`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` '[.obligations[] | select(.status != \"proven\")] | length == 0'`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` report.json`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Adjust the filter to match your team’s policy. A newly added requirement starts as `,_jsx(_components.code,{children:`unknown`}),`; you can choose to treat that as a warning or a hard block depending on your workflow.`]}),`\n`,_jsx(Heading,{level:`2`,id:`tracking-obligation-status-over-time`,children:`Tracking obligation status over time`}),`\n`,_jsx(Tip,{children:_jsxs(_components.p,{children:[`Commit `,_jsx(_components.code,{children:`report.json`}),` to your repository as a baseline. When the verifier’s output changes (a previously `,_jsx(_components.code,{children:`unknown`}),` obligation becomes `,_jsx(_components.code,{children:`proven`}),`, or a new requirement is added), the diff in `,_jsx(_components.code,{children:`report.json`}),` makes the change visible in code review. Reviewers can confirm that new obligations are intentional and that any regression from `,_jsx(_components.code,{children:`proven`}),` to `,_jsx(_components.code,{children:`unknown`}),` is understood.`]})}),`\n`,_jsx(_components.p,{children:`A committed report also means the visualization step in CI never needs to re-run verification: it loads the committed report directly, which keeps the viz step fast regardless of model complexity.`}),`\n`,_jsx(Heading,{level:`2`,id:`obligation-scope-in-the-report`,children:`Obligation scope in the report`}),`\n`,_jsxs(_components.p,{children:[`Each obligation in the report now carries a `,_jsx(_components.code,{children:`scope`}),` field:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`l0_only`}),`: the proof required no runtime facts.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`runtime_dependent`}),`: the proof consumed at least one L1 fact (delivery semantics, routing, pool concurrency, outbox runtime, and so on).`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`This is useful for CI matrices that verify both a minimal L0-only model and a full model with runtime topology. Removing the `,_jsx(_components.code,{children:`runtime`}),` block from a valid model leaves it valid: runtime-dependent proofs simply become `,_jsx(_components.code,{children:`unproven`}),`, never structural errors. A CI job that strips the runtime block and re-runs the verifier can confirm that the L0 layer stands on its own, while the full-runtime variant checks the complete architecture.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`13`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`13`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`jobs`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` verify-l0`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` steps`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/checkout@v4`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`yq 'del(.runtime)' model.yaml > model.l0.yaml`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`conseqa model.l0.yaml --report report.l0.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`jq -e '[.obligations[] | select(.scope == \"l0_only\" and .status != \"proven\")] | length == 0' report.l0.json`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` verify-full`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` steps`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`uses`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`actions/checkout@v4`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`conseqa model.yaml --report report.full.json`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` - `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`run`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`jq -e '[.obligations[] | select(.status != \"proven\")] | length == 0' report.full.json`})]}),`\n`]})})})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Integrating Conseqa Verification into Your CI Pipeline","sidebarTitle":"CI Integration","description":"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.","href":"/guides/ci-integration"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Build step","slug":"build-step","depth":2,"children":[]},{"title":"Run the verifier","slug":"run-the-verifier","depth":2,"children":[]},{"title":"Generate the visualization artifact","slug":"generate-the-visualization-artifact","depth":2,"children":[]},{"title":"GitHub Actions example","slug":"github-actions-example","depth":2,"children":[]},{"title":"Keeping the model with your service code","slug":"keeping-the-model-with-your-service-code","depth":2,"children":[]},{"title":"Failing on disproven obligations","slug":"failing-on-disproven-obligations","depth":2,"children":[]},{"title":"Tracking obligation status over time","slug":"tracking-obligation-status-over-time","depth":2,"children":[]},{"title":"Obligation scope in the report","slug":"obligation-scope-in-the-report","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"archspec","siteName":"Conseqa","title":"Integrating Conseqa Verification into Your CI Pipeline - Conseqa","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-10T11:35:29.489Z","originalFileLocation":"guides/ci-integration.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Conseqa\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/svg+xml\" sizes=\"180x180\" href=\"https://mintcdn.com/archspec/CgpsaKCVXill437h/favicon.svg?fit=max\u0026amp;auto=format\u0026amp;n=CgpsaKCVXill437h\u0026amp;q=85\u0026amp;s=fcfb437e6c8de76218c8ba7d2b92cc45\">\u003clink data-mint-head rel=\"icon\" type=\"image/svg+xml\" sizes=\"32x32\" href=\"https://mintcdn.com/archspec/CgpsaKCVXill437h/favicon.svg?fit=max\u0026amp;auto=format\u0026amp;n=CgpsaKCVXill437h\u0026amp;q=85\u0026amp;s=fcfb437e6c8de76218c8ba7d2b92cc45\">\u003clink data-mint-head rel=\"icon\" type=\"image/svg+xml\" sizes=\"16x16\" href=\"https://mintcdn.com/archspec/CgpsaKCVXill437h/favicon.svg?fit=max\u0026amp;auto=format\u0026amp;n=CgpsaKCVXill437h\u0026amp;q=85\u0026amp;s=fcfb437e6c8de76218c8ba7d2b92cc45\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/svg+xml\" href=\"https://mintcdn.com/archspec/CgpsaKCVXill437h/favicon.svg?fit=max\u0026amp;auto=format\u0026amp;n=CgpsaKCVXill437h\u0026amp;q=85\u0026amp;s=fcfb437e6c8de76218c8ba7d2b92cc45\">\u003cmeta data-mint-head property=\"og:title\" content=\"Integrating Conseqa Verification into Your CI Pipeline - Conseqa\">\u003cmeta data-mint-head property=\"og:description\" content=\"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Conseqa\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.conseqa.umran.ca/guides/ci-integration\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://archspec.mintlify.app/_mintlify/api/og/v2?division=Guides\u0026amp;title=Integrating+Conseqa+Verification+into+Your+CI+Pipeline\u0026amp;description=Run+Conseqa+in+CI+to+catch+regressions%2C+detect+disproven+obligations%2C+and+archive+proof+reports+and+HTML+visualizations+as+pipeline+artifacts.\u0026amp;theme=58f7995d7e1441fc71279f43\u0026amp;signature=ef9bc586af7b62b4e93c2f11cd2cf7ba400b2f43b465ecc302247e55a9adf080\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Integrating Conseqa Verification into Your CI Pipeline - Conseqa\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://archspec.mintlify.app/_mintlify/api/og/v2?division=Guides\u0026amp;title=Integrating+Conseqa+Verification+into+Your+CI+Pipeline\u0026amp;description=Run+Conseqa+in+CI+to+catch+regressions%2C+detect+disproven+obligations%2C+and+archive+proof+reports+and+HTML+visualizations+as+pipeline+artifacts.\u0026amp;theme=58f7995d7e1441fc71279f43\u0026amp;signature=ef9bc586af7b62b4e93c2f11cd2cf7ba400b2f43b465ecc302247e55a9adf080\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"https://mintlify.s3.us-west-1.amazonaws.com/archspec/_generated/favicon/browserconfig.xml?v=3\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Conseqa\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#5B4FCF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.conseqa.umran.ca/guides/ci-integration\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/guides/ci-integration.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.conseqa.umran.ca/#organization\",\"name\":\"Conseqa\",\"url\":\"https://docs.conseqa.umran.ca\"},{\"@type\":\"WebSite\",\"@id\":\"https://docs.conseqa.umran.ca#website\",\"name\":\"Conseqa\",\"url\":\"https://docs.conseqa.umran.ca\",\"publisher\":{\"@id\":\"https://docs.conseqa.umran.ca/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.conseqa.umran.ca/guides/ci-integration#webpage\",\"url\":\"https://docs.conseqa.umran.ca/guides/ci-integration\",\"name\":\"Integrating Conseqa Verification into Your CI Pipeline\",\"description\":\"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\",\"dateModified\":\"2026-09-10T11:35:29.489Z\",\"isPartOf\":{\"@id\":\"https://docs.conseqa.umran.ca#website\"},\"breadcrumb\":{\"@id\":\"https://docs.conseqa.umran.ca/guides/ci-integration#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.conseqa.umran.ca/guides/ci-integration#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Guides\",\"item\":\"https://docs.conseqa.umran.ca/guides/modeling-a-checkout-flow\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Integrating Conseqa Verification into Your CI Pipeline\",\"item\":\"https://docs.conseqa.umran.ca/guides/ci-integration\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.conseqa.umran.ca/guides/ci-integration#article\",\"headline\":\"Integrating Conseqa Verification into Your CI Pipeline\",\"name\":\"Integrating Conseqa Verification into Your CI Pipeline\",\"description\":\"Run Conseqa in CI to catch regressions, detect disproven obligations, and archive proof reports and HTML visualizations as pipeline artifacts.\",\"url\":\"https://docs.conseqa.umran.ca/guides/ci-integration\",\"mainEntityOfPage\":{\"@id\":\"https://docs.conseqa.umran.ca/guides/ci-integration#webpage\"},\"dateModified\":\"2026-09-10T11:35:29.489Z\",\"publisher\":{\"@id\":\"https://docs.conseqa.umran.ca/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.conseqa.umran.ca#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Conseqa\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Conseqa","nav":{"global":null,"tabs":[{"tab":"Documentation","groups":[{"group":"Get Started","pages":[{"title":"Conseqa: Formal Proofs for Distributed Correctness","sidebarTitle":"Introduction","href":"/introduction"},{"title":"Quickstart: Verify Your First Conseqa Model in Minutes","sidebarTitle":"Quickstart","href":"/quickstart"},{"title":"Install Conseqa: Build from Source and Verify Setup","sidebarTitle":"Installation","href":"/installation"}]},{"group":"Core Concepts","pages":[{"title":"Conseqa Model Overview: Application Layer and Runtime Topology","sidebarTitle":"Model Overview","href":"/concepts/model-overview"},{"title":"Conseqa Services and Schemas Reference","sidebarTitle":"Services and Schemas","href":"/concepts/services-and-schemas"},{"title":"Conseqa Data Models and Outboxes","sidebarTitle":"Data Models and Outboxes","href":"/concepts/data-models-and-outboxes"},{"title":"Conseqa Operations: Inputs, Programs, and Effects","sidebarTitle":"Operations","href":"/concepts/operations"},{"title":"Conseqa Transactions: Idempotency, Isolation, and Steps","sidebarTitle":"Transactions","href":"/concepts/transactions"},{"title":"Conseqa Topics: Logical Channels Without Runtime Facts","sidebarTitle":"Topics and Messaging","href":"/concepts/topics-and-messaging"},{"title":"Conseqa State Machines and Transition Side Effects","sidebarTitle":"State Machines","href":"/concepts/state-machines"},{"title":"Conseqa Operation Requirements: Serialization, Ordering, Idempotency, and Recoverability","sidebarTitle":"Requirements","href":"/concepts/requirements"}]},{"group":"Runtime Topology","pages":[{"title":"L1 Runtime Topology: How the Abstract Machine Runs","sidebarTitle":"Overview","href":"/runtime/overview"},{"title":"Topic and Subscription Runtime: Transport Semantics in Conseqa","sidebarTitle":"Topic \u0026 Subscription Runtime","href":"/runtime/topic-and-subscription-runtime"},{"title":"Outbox Runtime: Consumption and Dispatch Semantics","sidebarTitle":"Outbox Runtime","href":"/runtime/outbox-runtime"},{"title":"Routers and Execution Pools: Request Routing and Concurrency","sidebarTitle":"Routers \u0026 Pools","href":"/runtime/routers-and-pools"},{"title":"Storage Layouts: Physical Partitioning for Data Objects","sidebarTitle":"Storage Layouts","href":"/runtime/storage-layouts"}]},{"group":"DSL Reference","pages":[{"title":"Conseqa DSL Model Structure: All Top-Level Keys","sidebarTitle":"Model Structure","href":"/dsl/model-structure"},{"title":"Conseqa DSL Field Types, Scalars, and Schema Forms","sidebarTitle":"Field Types","href":"/dsl/field-types"},{"title":"Conseqa DSL Effects: Publication, Request, External","sidebarTitle":"Effects","href":"/dsl/effects"},{"title":"Conseqa Operation Program: All Steps and Control Flow","sidebarTitle":"Program Control","href":"/dsl/program-control"},{"title":"Async Effect Execution, Handles, and Synchronization Barriers","sidebarTitle":"Async Effects","href":"/dsl/async-effects"},{"title":"Value References, Field Paths, and Derivations DSL","sidebarTitle":"Value References","href":"/dsl/value-references"}]},{"group":"Verification","pages":[{"title":"How Conseqa Verifies Models: Validation, Forward Analysis, and Fixpoints","sidebarTitle":"How It Works","href":"/verification/how-it-works"},{"title":"Verification Verdicts: Proven, Unknown, and Disproven","sidebarTitle":"Verdicts","href":"/verification/verdicts"},{"title":"Obligation Report Format: JSON Structure and Fields","sidebarTitle":"Obligations Report","href":"/verification/obligations-report"}]},{"group":"Visualization","pages":[{"title":"Generate Interactive HTML Visualizations with conseqa-viz","sidebarTitle":"Overview","href":"/visualization/overview"},{"title":"System View: Services, Topics, Outboxes, and Routes in conseqa-viz","sidebarTitle":"System View","href":"/visualization/system-view"},{"title":"Operation View: Program Steps and Flow in conseqa-viz","sidebarTitle":"Operation View","href":"/visualization/operation-view"},{"title":"State Machine View: Lifecycle Diagrams in conseqa-viz","sidebarTitle":"State Machine View","href":"/visualization/state-machine-view"}]},{"group":"Guides","pages":[{"title":"Step-by-Step: Modeling a Flash-Sale Checkout in Conseqa","sidebarTitle":"Checkout Flow","href":"/guides/modeling-a-checkout-flow"},{"title":"Proving Idempotency Requirements in Conseqa Models","sidebarTitle":"Proving Idempotency","description":"Learn how Conseqa's verifier uses three-leg proofs and greatest-fixpoint coinductive reasoning to establish idempotency across requests, publications, and outbox writes.","href":"/guides/proving-idempotency"},{"title":"Integrating Conseqa Verification into Your CI Pipeline","sidebarTitle":"CI Integration","href":"/guides/ci-integration"}]}]},{"tab":"CLI Reference","pages":[{"title":"CLI Reference","href":"/cli/conseqa"}]}]},"basePath":"","title":"Integrating Conseqa Verification into Your CI Pipeline - Conseqa","buildId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","deploymentId":"dpl_36EDyZCDfRuoUD9af5CH4M1bqY2h","dynamics":[],"chunks":[]}