Create Java AWS CDK v2 infrastructure the same way a business application is built: as BCE business components, not as a flat pile of resources. A construct is a reusable capability; a stack is a deployment boundary. Keep that split and the code stays readable, testable, and refactorable.
Composition
- compose with
bce for the architecture pattern (business components, boundary/control/entity, package structure) — this skill specializes it for the AWS CDK context and never contradicts it
- compose with
java-conventions for all language-level rules (modern Java 25 syntax, var, records, pattern matching, text blocks, naming, visibility, streams, exceptions)
- this skill adds only what is specific to authoring CDK: project layout, the app→stack→construct split, region pinning, typed configuration,
grant* permissions, and synthesis-based tests
What this skill produces
A Maven, Java 25 CDK v2 project whose packages are BCE business components. The entry-point class loads typed configuration, wires stacks, and calls app.synth(). Each business component is named after the AWS capability it provisions (s3, cloudfront, certificate, route53, codebuild, cognito, iam, stepfunctions). Stacks live in boundary; the reusable resource factories and helpers live in control; immutable specs and value objects live in entity.
A generic, domain-neutral blueprint — the BCE layout, build files, and one worked business component per layer — is in references/project-blueprint.md. Read it when scaffolding a new project or when you need a concrete template for a stack, a control factory, an entity, or the tests; copy the shapes, not the example domain. Read references/naming-conventions.md for the full CloudFormation / CDK / Java naming tables — casing rules for logical IDs, stack names, tags, and construct IDs.
Scaffolding a new project
A clone of AdamBien/aws-cdk-plain is a valid starting point; otherwise generate the files directly. Either way, work in this order — it mirrors the dependency direction of synthesis:
pom.xml + cdk.json — Maven with aws-cdk-lib and constructs, Java 25 source/target, the exec-maven-plugin pointing mainClass at the app class. cdk.json sets "app": "mvn -e -q compile exec:java". Templates in references/project-blueprint.md. Ask before adding any dependency beyond these.
- Application entry point — the
CDKApp class at the root. It reads CDK context, loads configuration, applies app-level tags, instantiates stacks in dependency order, and calls app.synth(). Its appName constant is the deployment name used to derive stack names.
Stacks interface — pinned StackProps constants, one per region (see Regions below).
Configuration — typed records parsed from a properties/context source (see Configuration below).
- Business components — one package per AWS capability, each with the layers it needs.
- Tests — synthesize each stack and assert on the template; drive
entity build/spec logic with parameterized tests.
Do not generate speculative resources. Create each business component with the minimal set of resources its responsibility requires, and grow from there.
Package structure (BCE)
- package path:
[organization].[application].[businessComponent].[boundary|control|entity] — the same shape microprofile-server uses
- the application package
[organization].[application] (e.g. airhacks.website) is the BCE top level: it reflects the application name and holds the shared Configuration and Stacks. Business components are its direct children — never placed directly under the organization
- the
CDKApp entry-point class sits at the root — in the application package, or at the organization root just above it, as your projects do
- business components are named after the AWS capability they provision (
s3, dynamodb, lambda, apigateway, cloudfront, route53, cognito); when a component spans multiple services, name it after its domain responsibility instead of any single service
- the
appName constant (e.g. aws-cicd-website-cdk) is the deployment name used to derive stack names — a separate concern from the [application] package segment
- a component uses only the layers it needs — a stateless resource factory is a
control-only component (e.g. s3.control.Buckets, route53.control.Route53); no boundary is required to reach it
boundary, control, entity segments appear only inside a business component
Layer responsibilities in a CDK project
- boundary — the stack classes (
extends Stack). A stack is the CloudFormation deployment boundary: it composes constructs, connects cross-stack dependencies, applies tags, and declares outputs. Every stack except the entry-point app lives in a boundary package.
- control — reusable, stateless resource factories and wiring helpers (bucket factories, Route53 alias-record setup, a CodeBuild publishing project). Prefer
interface with static methods. These are the CDK "constructs" in the capability sense — the reusable behavior.
- entity — immutable data that describes infrastructure but creates no resources: build specs, typed value objects, configuration records local to a component (e.g. a
BuildSpec factory, a GitRepository record).
IAM (roles, policy statements) belongs in a dedicated iam component. Cognito always gets its own stack.
Application entry point
- name the entry-point class
CDKApp and keep it at the root — the application package [organization].[application], or the organization root just above it
- the
appName constant here (e.g. aws-cicd-website-cdk) is the deployment name used to derive CloudFormation stack names — distinct from the [application] package segment
- read environment-specific values from CDK context (
app.getNode().tryGetContext("...")), never hardcode them and never read context or System.getenv from inside a stack
- load configuration once here, pass typed records down
- apply organization/environment tags at the app scope with
Tags.of(app).add(key, value) so every resource inherits them
- instantiate stacks in dependency order and pass resource interfaces (not stack instances) from producer to consumer, then call
app.synth()
Regions and StackProps
- maintain a central
Stacks interface exposing pinned StackProps constants, one per region — never inline StackProps in each stack
- set account/Region at this boundary via
Environment.builder().region(...)
- enable
crossRegionReferences(true) only on stacks that consume a resource from a different region (e.g. CloudFront in one region consuming an ACM certificate pinned to us-east-1)
- bootstrap each pinned region once:
cdk bootstrap aws://ACCOUNT/REGION
Configuration
- model configuration as immutable Java
records (a Configuration interface with nested records and static factory methods is a clean home)
- parse raw properties/context in one place and surface typed records; give records domain behavior (derived names, normalization,
withX copy methods) rather than leaving them anemic
- pass configuration records into stack constructors — a stack never reaches back to the raw property source
Stacks (boundary)
- every stack class ends with
Stack; never ends with Construct
- pass the
Construct/scope as the first constructor parameter, followed by typed configuration and the resource interfaces it consumes
- stacks are independent: never pass a
Stack instance to another stack. Pass only the interfaces consumers need (IBucket, ITable, IFunction, IDistribution, ICertificate). CDK derives the CloudFormation cross-stack reference from the object
- keep stacks thin — they compose constructs and connect dependencies; the resource configuration itself lives in
control factories
- expose only what other stacks need via package-visible getters; keep internals encapsulated
- derive the CloudFormation stack name from configuration (e.g.
appName-normalizedDomain-component); set it via the StackProps you pass to super(...)
Constructs (control)
- prefer
Builder.create(scope, "LogicalId").…build() over constructor invocation
- use the highest-level construct available (L2/L3); drop to
Cfn* (L1) only when no L2/L3 exposes the capability, and give the wrapped principal L1 resource the logical id "Resource"
- prove the absence of an L2/L3 before writing any
Cfn* usage — memory of what a CDK package contains is reliably stale, because services gain L2s in minor aws-cdk-lib releases (bedrockagentcore shipped a full L2 family — Runtime, Gateway, Memory — while only the Cfn* layer was widely known). Enumerate the service package in the project's resolved aws-cdk-lib jar and look for non-Cfn classes: unzip -l ~/.m2/repository/software/amazon/awscdk/aws-cdk-lib/<version>/aws-cdk-lib-<version>.jar | grep 'services/<service>/'. Listing the whole package matters: javap on the Cfn* class you expect will succeed whether or not an L2 exists, so a targeted lookup only confirms the assumption it started from. If the L1 is genuinely alone, say so where the Cfn* construct is introduced (commit message or PR), so the next pass re-checks instead of inheriting the choice
- give every resource a stable, semantic PascalCase logical id — it becomes the CloudFormation logical id and is deployment identity. Never derive ids from timestamps, randomness, or list positions; do not rename deployed ids for cosmetic reasons
- let CloudFormation generate physical names — omit
bucketName, tableName, roleName unless an operator-facing name is genuinely required
- accept and return interfaces (
IBucket, ITable) in factory signatures; return the interface type from getters so consumers depend on behavior, not the concrete class
- protect stateful resources:
RemovalPolicy.RETAIN for buckets/tables that hold data, isolated in their own stack
- expose outputs with
CfnOutput.Builder.create(...); attach component-level tags with Tags.of(scope).add(...)
IAM and permissions
- prefer
grant* methods on the target construct (bucket.grantReadWrite(role), table.grantReadData(fn), distribution.grantCreateInvalidation(role), logGroup.grantWrite(role)) — they generate least-privilege, correctly-scoped policies
- fall back to an explicit
PolicyStatement.Builder / Role.Builder only when no grant* expresses the permission
- keep roles and policy statements in the dedicated
iam component
- always give Cognito its own stack
AWS Step Functions
- use JSONata as the query language
- define workflows with
IChainable and DefinitionBody.fromChainable(...)
- give every
StateMachine a descriptive name reflecting its business purpose
Synthesis and efficiency
- keep synthesis deterministic and side-effect free: no AWS SDK calls, no randomness, no timestamps during construction — the same source and context must synthesize an equivalent template
- commit
cdk.context.json when it holds required lookup results, so CI runs reproduce
- minimize runtime AWS API calls in any Lambda/handler code you generate; S3
PUT/DELETE are idempotent — do not check existence first unless business logic requires it
Java conventions for CDK
Language-level rules (syntax, naming, visibility, structure) come from java-conventions. CDK-specific deltas only:
- a stack class must end in
Stack — the exception to the no-suffix rule; *Construct remains forbidden
- prefer
interface with static methods for stateless control factories and helpers
- for synth-time diagnostics a tiny
Log control over System.Logger (as in the reference) is fine; System.out.println is acceptable for one-off output
Testing
- test the synthesized contract, not a snapshot: build an
App, instantiate the stack(s), call app.synth(), and assert the stack artifact's template has the expected Resources (and, where it matters, properties, counts, and grants)
- drive
entity logic (specs, ordering, derived names) with parameterized JUnit 5 tests — one labelled row per requirement — since that logic is pure and cheaply verifiable without synthesis
- the blueprint shows both test styles
- when the project carries EARS requirements in a
package-info.java, compose with ears-tests to generate the parameterized rows
- keep tests in the same package as the code under test to use package-private access
Build and deployment
- Maven, Java 25 source/target; core dependencies
software.amazon.awscdk:aws-cdk-lib and software.constructs:constructs; JUnit 5 + AssertJ for tests
- entry point run via
exec-maven-plugin with mainClass set to the app class; cdk.json "app" invokes mvn -e -q compile exec:java
- deploy multi-stack apps with
cdk deploy --all --context key=value; a bare cdk deploy errors when the app synthesizes more than one stack
- provide
buildAndDeploy.sh (mvn -DskipTests clean package && cdk deploy --all) and destroy.sh (cdk destroy) helper scripts
README
The README's map is the deployables, not the business components: every stack by the CloudFormation name an operator types, what it creates, and whose credentials apply it. A reader arrives to deploy — the BCE structure is authoring shape, visible in the packages.
- one bullet per stack: the deployed stack name (or its pattern, e.g.
app-workload-[ACCOUNT_ID]-stack for a per-account stack), what it provisions, and a link to its package-info spec when the project carries one
- state the deploy order whenever stacks must be applied in sequence, and name what carries a value from one to the next — a cross-account or cross-region value is configuration, never a resolved reference
- compose with
readme for the rest of the document; when sbce also applies, omit its generated BC map and Components diagram (insert no markers) rather than carrying two maps of one system
Reference files
references/naming-conventions.md — full CloudFormation, CDK, and Java naming tables (casing for logical IDs, stack names, construct IDs, tags, physical names). Read when unsure how to name any element.
references/project-blueprint.md — a domain-neutral CDK app walked through file by file: pom.xml, cdk.json, app entry point, Stacks, Configuration records, a boundary stack, control factories, an entity, and the two test styles. Read when scaffolding or when you need a concrete template; copy the shapes, not the example domain.
- AdamBien/aws-cdk-plain — a compilable starter template (
CDKApp, Configuration, a placeholder stack) for clone-and-go project starts. It is a seed, not the worked example; when it and this skill or the blueprint disagree, the blueprint governs.
1---2name: aws-cdk3description: Create Java AWS CDK v2 infrastructure the same way a business application is built: as BCE business components, not as a flat pile of resources. A construct is a reusable capability; a stack is a deployment boundary. Keep that split and the code stays readable, testable, and refactorable.4---56Create Java AWS CDK v2 infrastructure the same way a business application is built: as BCE business components, not as a flat pile of resources. A construct is a reusable capability; a stack is a deployment boundary. Keep that split and the code stays readable, testable, and refactorable.78## Composition910- compose with `bce` for the architecture pattern (business components, boundary/control/entity, package structure) — this skill specializes it for the AWS CDK context and never contradicts it11- compose with `java-conventions` for all language-level rules (modern Java 25 syntax, `var`, records, pattern matching, text blocks, naming, visibility, streams, exceptions)12- this skill adds only what is specific to authoring CDK: project layout, the app→stack→construct split, region pinning, typed configuration, `grant*` permissions, and synthesis-based tests1314## What this skill produces1516A Maven, Java 25 CDK v2 project whose packages are BCE business components. The entry-point class loads typed configuration, wires stacks, and calls `app.synth()`. Each business component is named after the AWS capability it provisions (`s3`, `cloudfront`, `certificate`, `route53`, `codebuild`, `cognito`, `iam`, `stepfunctions`). Stacks live in `boundary`; the reusable resource factories and helpers live in `control`; immutable specs and value objects live in `entity`.1718A generic, domain-neutral blueprint — the BCE layout, build files, and one worked business component per layer — is in `references/project-blueprint.md`. Read it when scaffolding a new project or when you need a concrete template for a stack, a control factory, an entity, or the tests; copy the shapes, not the example domain. Read `references/naming-conventions.md` for the full CloudFormation / CDK / Java naming tables — casing rules for logical IDs, stack names, tags, and construct IDs.1920## Scaffolding a new project2122A clone of [AdamBien/aws-cdk-plain](https://github.com/AdamBien/aws-cdk-plain) is a valid starting point; otherwise generate the files directly. Either way, work in this order — it mirrors the dependency direction of synthesis:23241. **`pom.xml` + `cdk.json`** — Maven with `aws-cdk-lib` and `constructs`, Java 25 source/target, the `exec-maven-plugin` pointing `mainClass` at the app class. `cdk.json` sets `"app": "mvn -e -q compile exec:java"`. Templates in `references/project-blueprint.md`. Ask before adding any dependency beyond these.252. **Application entry point** — the `CDKApp` class at the root. It reads CDK context, loads configuration, applies app-level tags, instantiates stacks in dependency order, and calls `app.synth()`. Its `appName` constant is the deployment name used to derive stack names.263. **`Stacks` interface** — pinned `StackProps` constants, one per region (see Regions below).274. **`Configuration`** — typed `record`s parsed from a properties/context source (see Configuration below).285. **Business components** — one package per AWS capability, each with the layers it needs.296. **Tests** — synthesize each stack and assert on the template; drive `entity` build/spec logic with parameterized tests.3031Do not generate speculative resources. Create each business component with the minimal set of resources its responsibility requires, and grow from there.3233## Package structure (BCE)3435- package path: `[organization].[application].[businessComponent].[boundary|control|entity]` — the same shape `microprofile-server` uses36- the application package `[organization].[application]` (e.g. `airhacks.website`) is the BCE top level: it reflects the application name and holds the shared `Configuration` and `Stacks`. Business components are its **direct children** — never placed directly under the organization37- the `CDKApp` entry-point class sits at the root — in the application package, or at the organization root just above it, as your projects do38- business components are named after the AWS capability they provision (`s3`, `dynamodb`, `lambda`, `apigateway`, `cloudfront`, `route53`, `cognito`); when a component spans **multiple** services, name it after its domain responsibility instead of any single service39- the `appName` constant (e.g. `aws-cicd-website-cdk`) is the deployment name used to derive stack names — a separate concern from the `[application]` package segment40- a component uses only the layers it needs — a stateless resource factory is a `control`-only component (e.g. `s3.control.Buckets`, `route53.control.Route53`); no boundary is required to reach it41- `boundary`, `control`, `entity` segments appear only inside a business component4243### Layer responsibilities in a CDK project4445- **boundary** — the stack classes (`extends Stack`). A stack is the CloudFormation deployment boundary: it composes constructs, connects cross-stack dependencies, applies tags, and declares outputs. Every stack except the entry-point app lives in a `boundary` package.46- **control** — reusable, stateless resource factories and wiring helpers (bucket factories, Route53 alias-record setup, a CodeBuild publishing project). Prefer `interface` with `static` methods. These are the CDK "constructs" in the capability sense — the reusable behavior.47- **entity** — immutable data that describes infrastructure but creates no resources: build specs, typed value objects, configuration records local to a component (e.g. a `BuildSpec` factory, a `GitRepository` record).4849IAM (roles, policy statements) belongs in a dedicated `iam` component. Cognito always gets its own stack.5051## Application entry point5253- name the entry-point class `CDKApp` and keep it at the root — the application package `[organization].[application]`, or the organization root just above it54- the `appName` constant here (e.g. `aws-cicd-website-cdk`) is the deployment name used to derive CloudFormation stack names — distinct from the `[application]` package segment55- read environment-specific values from CDK context (`app.getNode().tryGetContext("...")`), never hardcode them and never read context or `System.getenv` from inside a stack56- load configuration once here, pass typed records down57- apply organization/environment tags at the app scope with `Tags.of(app).add(key, value)` so every resource inherits them58- instantiate stacks in dependency order and pass **resource interfaces** (not stack instances) from producer to consumer, then call `app.synth()`5960## Regions and StackProps6162- maintain a central `Stacks` interface exposing pinned `StackProps` constants, one per region — never inline `StackProps` in each stack63- set account/Region at this boundary via `Environment.builder().region(...)`64- enable `crossRegionReferences(true)` only on stacks that consume a resource from a different region (e.g. CloudFront in one region consuming an ACM certificate pinned to `us-east-1`)65- bootstrap each pinned region once: `cdk bootstrap aws://ACCOUNT/REGION`6667## Configuration6869- model configuration as immutable Java `record`s (a `Configuration` interface with nested records and `static` factory methods is a clean home)70- parse raw properties/context in one place and surface typed records; give records domain behavior (derived names, normalization, `withX` copy methods) rather than leaving them anemic71- pass configuration records into stack constructors — a stack never reaches back to the raw property source7273## Stacks (boundary)7475- every stack class ends with `Stack`; never ends with `Construct`76- pass the `Construct`/scope as the **first** constructor parameter, followed by typed configuration and the resource interfaces it consumes77- stacks are **independent**: never pass a `Stack` instance to another stack. Pass only the interfaces consumers need (`IBucket`, `ITable`, `IFunction`, `IDistribution`, `ICertificate`). CDK derives the CloudFormation cross-stack reference from the object78- keep stacks thin — they compose constructs and connect dependencies; the resource configuration itself lives in `control` factories79- expose only what other stacks need via package-visible getters; keep internals encapsulated80- derive the CloudFormation stack name from configuration (e.g. `appName-normalizedDomain-component`); set it via the `StackProps` you pass to `super(...)`8182## Constructs (control)8384- prefer `Builder.create(scope, "LogicalId").…build()` over constructor invocation85- use the **highest-level** construct available (L2/L3); drop to `Cfn*` (L1) only when no L2/L3 exposes the capability, and give the wrapped principal L1 resource the logical id `"Resource"`86- **prove the absence of an L2/L3 before writing any `Cfn*` usage** — memory of what a CDK package contains is reliably stale, because services gain L2s in minor `aws-cdk-lib` releases (bedrockagentcore shipped a full L2 family — `Runtime`, `Gateway`, `Memory` — while only the `Cfn*` layer was widely known). Enumerate the service package in the project's resolved `aws-cdk-lib` jar and look for non-`Cfn` classes: `unzip -l ~/.m2/repository/software/amazon/awscdk/aws-cdk-lib/<version>/aws-cdk-lib-<version>.jar | grep 'services/<service>/'`. Listing the whole package matters: `javap` on the `Cfn*` class you expect will succeed whether or not an L2 exists, so a targeted lookup only confirms the assumption it started from. If the L1 is genuinely alone, say so where the `Cfn*` construct is introduced (commit message or PR), so the next pass re-checks instead of inheriting the choice87- give every resource a **stable, semantic PascalCase logical id** — it becomes the CloudFormation logical id and is deployment identity. Never derive ids from timestamps, randomness, or list positions; do not rename deployed ids for cosmetic reasons88- let CloudFormation generate physical names — omit `bucketName`, `tableName`, `roleName` unless an operator-facing name is genuinely required89- accept and return **interfaces** (`IBucket`, `ITable`) in factory signatures; return the interface type from getters so consumers depend on behavior, not the concrete class90- protect stateful resources: `RemovalPolicy.RETAIN` for buckets/tables that hold data, isolated in their own stack91- expose outputs with `CfnOutput.Builder.create(...)`; attach component-level tags with `Tags.of(scope).add(...)`9293## IAM and permissions9495- prefer `grant*` methods on the target construct (`bucket.grantReadWrite(role)`, `table.grantReadData(fn)`, `distribution.grantCreateInvalidation(role)`, `logGroup.grantWrite(role)`) — they generate least-privilege, correctly-scoped policies96- fall back to an explicit `PolicyStatement.Builder` / `Role.Builder` only when no `grant*` expresses the permission97- keep roles and policy statements in the dedicated `iam` component98- always give Cognito its own stack99100## AWS Step Functions101102- use **JSONata** as the query language103- define workflows with `IChainable` and `DefinitionBody.fromChainable(...)`104- give every `StateMachine` a descriptive name reflecting its business purpose105106## Synthesis and efficiency107108- keep synthesis deterministic and side-effect free: no AWS SDK calls, no randomness, no timestamps during construction — the same source and context must synthesize an equivalent template109- commit `cdk.context.json` when it holds required lookup results, so CI runs reproduce110- minimize runtime AWS API calls in any Lambda/handler code you generate; S3 `PUT`/`DELETE` are idempotent — do not check existence first unless business logic requires it111112## Java conventions for CDK113114Language-level rules (syntax, naming, visibility, structure) come from `java-conventions`. CDK-specific deltas only:115116- a stack class must end in `Stack` — the exception to the no-suffix rule; `*Construct` remains forbidden117- prefer `interface` with `static` methods for stateless `control` factories and helpers118- for synth-time diagnostics a tiny `Log` control over `System.Logger` (as in the reference) is fine; `System.out.println` is acceptable for one-off output119120## Testing121122- test the synthesized contract, not a snapshot: build an `App`, instantiate the stack(s), call `app.synth()`, and assert the stack artifact's template has the expected `Resources` (and, where it matters, properties, counts, and grants)123- drive `entity` logic (specs, ordering, derived names) with **parameterized** JUnit 5 tests — one labelled row per requirement — since that logic is pure and cheaply verifiable without synthesis124- the blueprint shows both test styles125- when the project carries EARS requirements in a `package-info.java`, compose with `ears-tests` to generate the parameterized rows126- keep tests in the same package as the code under test to use package-private access127128## Build and deployment129130- Maven, Java 25 source/target; core dependencies `software.amazon.awscdk:aws-cdk-lib` and `software.constructs:constructs`; JUnit 5 + AssertJ for tests131- entry point run via `exec-maven-plugin` with `mainClass` set to the app class; `cdk.json` `"app"` invokes `mvn -e -q compile exec:java`132- deploy multi-stack apps with `cdk deploy --all --context key=value`; a bare `cdk deploy` errors when the app synthesizes more than one stack133- provide `buildAndDeploy.sh` (`mvn -DskipTests clean package && cdk deploy --all`) and `destroy.sh` (`cdk destroy`) helper scripts134135## README136137The README's map is the **deployables**, not the business components: every stack by the CloudFormation name an operator types, what it creates, and whose credentials apply it. A reader arrives to deploy — the BCE structure is authoring shape, visible in the packages.138139- one bullet per stack: the deployed stack name (or its pattern, e.g. `app-workload-[ACCOUNT_ID]-stack` for a per-account stack), what it provisions, and a link to its `package-info` spec when the project carries one140- state the deploy order whenever stacks must be applied in sequence, and name what carries a value from one to the next — a cross-account or cross-region value is configuration, never a resolved reference141- compose with `readme` for the rest of the document; when `sbce` also applies, omit its generated BC map and Components diagram (insert no markers) rather than carrying two maps of one system142143## Reference files144145- `references/naming-conventions.md` — full CloudFormation, CDK, and Java naming tables (casing for logical IDs, stack names, construct IDs, tags, physical names). Read when unsure how to name any element.146- `references/project-blueprint.md` — a domain-neutral CDK app walked through file by file: `pom.xml`, `cdk.json`, app entry point, `Stacks`, `Configuration` records, a boundary stack, `control` factories, an `entity`, and the two test styles. Read when scaffolding or when you need a concrete template; copy the shapes, not the example domain.147- [AdamBien/aws-cdk-plain](https://github.com/AdamBien/aws-cdk-plain) — a compilable starter template (`CDKApp`, `Configuration`, a placeholder stack) for clone-and-go project starts. It is a seed, not the worked example; when it and this skill or the blueprint disagree, the blueprint governs.