diff --git a/.ciagent/ARCHITECTURE.md b/.ciagent/ARCHITECTURE.md index 587c716..d70c786 100644 --- a/.ciagent/ARCHITECTURE.md +++ b/.ciagent/ARCHITECTURE.md @@ -15,7 +15,7 @@ locked commitments and the v1.1 spike scope. ## Overview The platform is **four layers + six cross-cutting concerns**. The sixth -concern — the substrate abstraction (§12) — is first-class, not an +concern — the engine abstraction (§12) — is first-class, not an implementation detail. The vision's "Two Consumer Surfaces, One Platform" tenet binds everything: L3A and L3B converge on the same contract schema, the same policy envelope, and the same evidence stream. @@ -53,7 +53,7 @@ the same policy envelope, and the same evidence stream. ## Layers ### Layer 1 — Foundational Primitives -Single-purpose, **substrate-agnostic** primitive modules. L1 modules do +Single-purpose, **engine-agnostic** primitive modules. L1 modules do not compose with other L1s; L1 takes its environment as input. The L1 interface is defined against the **Target Stack IR**, not against Terraform directly (the IR is shaped to round-trip to Terraform in v1, per §12.1). @@ -181,15 +181,15 @@ platform does not run the skill. Stateless agents, all state in the platform. Skills are reviewed for sensitive data before release (Infra & Ops owns the review; it is the mandatory release gate). -### Substrate execution (§12) — the binding constraint -**Target Stack IR** (locked): a substrate-neutral description of resources +### Angine execution (§12) — the binding constraint +**Target Stack IR** (locked): a engine-neutral description of resources (typed inputs/outputs/NFRs), relationships (single parent per child), composition (tree, max depth 5), and policy hooks. The L1 registry, L2 thin-composition tree, contract YML, and PolicyCheckResult schema are all -defined against the IR — none against any specific substrate. +defined against the IR — none against any specific engine. -**Substrate adapters** are the only substrate-specific code. An adapter -compiles the IR into a substrate execution plan. **v1 ships exactly one +**Angine adapters** are the only engine-specific code. An adapter +compiles the IR into a engine execution plan. **v1 ships exactly one adapter: the Terraform adapter.** v2+ may add OpenTofu, Pulumi, K8s CRDs without architectural change. @@ -335,20 +335,20 @@ extends the *implementation*, not the design. ECS Fargate service serving HTTP 200 → evidence event to the DynamoDB outbox → acdl-evidence timeline. -### Substrate extension (ECS Fargate) +### Angine extension (ECS Fargate) -The Terraform adapter (§12) remains the only substrate-specific code. v1.2 +The Terraform adapter (§12) remains the only engine-specific code. v1.2 expands the adapter `TYPE_MAP` to cover the six new ECS-shaped IR resource types. The L1 interface shape (IR-typed inputs/outputs/NFRs, registered in `modules-ir/registry.json`) is unchanged — only the set of registered L1s grows. The IR commitments (REQ-28) continue to hold: `modules-ir/`, `schemas/`, `contracts/`, `core/confidence_signal.py`, `core/contract_resolver.py`, `core/outbox_writer.py` -remain substrate-agnostic. +remain engine-agnostic. ### `terraform apply` (dev only) -v1.2 lifts the substrate execution from `plan` to `apply` for the `dev` +v1.2 lifts the engine execution from `plan` to `apply` for the `dev` environment only. Dev is autonomous per §10 (confidence ≥ 0.50, no HITL). `apply` for qa/prod/dr remains HITL-gated and out of scope for v1.2. The apply result (resources created, plan diff) is captured in the evidence diff --git a/.ciagent/PERSONAS.md b/.ciagent/PERSONAS.md index 7e766a9..b4145e5 100644 --- a/.ciagent/PERSONAS.md +++ b/.ciagent/PERSONAS.md @@ -43,9 +43,9 @@ verification_toolchain: - **Active:** true - **Phase-specific:** false - **Frameworks:** terraform, aws-iam, aws-s3, aws-dynamodb, aws-lambda, aws-cloudfront, aws-waf, aws-ssm, aws-secretsmanager, oidc, json-schema -- **Constraints:** ir-is-substrate-agnostic, adapter-is-only-substrate-specific-code, state-in-s3+dynamodb-single-region, oidc-only-no-long-lived-keys (waiver D-034 for bootstrap), terraform-plan-only-in-spike, cross-account-iam-scoped-via-abac +- **Constraints:** ir-is-engine-agnostic, adapter-is-only-engine-specific-code, state-in-s3+dynamodb-single-region, oidc-only-no-long-lived-keys (waiver D-034 for bootstrap), terraform-plan-only-in-spike, cross-account-iam-scoped-via-abac - **Territory:** `adapters/terraform/**`, `modules/**` (l1 + l2 + registry.json + examples), `terraform/**` (state backend, provider config, platform infra), `modules/registry.json` -- **Reason:** Owns the Target Stack IR, the L1/L2 IR-typed modules (incl. new cloudfront + waf + rds primitives), the Terraform adapter (TYPE_MAP expansion for cloudfront/waf/rds), the AWS OIDC bootstrap, the state backend, and the platform Terraform (Lambda + DynamoDB + KMS + Secrets Manager + Function URL). The IR is substrate-agnostic; the adapter is the only substrate-specific code (the binding constraint per §12). +- **Reason:** Owns the Target Stack IR, the L1/L2 IR-typed modules (incl. new cloudfront + waf + rds primitives), the Terraform adapter (TYPE_MAP expansion for cloudfront/waf/rds), the AWS OIDC bootstrap, the state backend, and the platform Terraform (Lambda + DynamoDB + KMS + Secrets Manager + Function URL). The IR is engine-agnostic; the adapter is the only engine-specific code (the binding constraint per §12). ### security-engineer (custom) - **Domain:** security @@ -79,7 +79,7 @@ verification_toolchain: ### infra-stub-engineer (custom, v1.0 only) - **Domain:** backend - **Active:** false -- **Reason:** Owned L1 stub modules (`modules/l1/**`) in the v1.0 demo. The demo is archived to `demo/` in Phase 06; real L1 modules (`modules-ir/l1/**`, now `modules/l1/**`) are owned by platform-engineer (substrate-agnostic IR + Terraform adapter). The stub engineer is no longer needed. +- **Reason:** Owned L1 stub modules (`modules/l1/**`) in the v1.0 demo. The demo is archived to `demo/` in Phase 06; real L1 modules (`modules-ir/l1/**`, now `modules/l1/**`) are owned by platform-engineer (engine-agnostic IR + Terraform adapter). The stub engineer is no longer needed. - **Phase-specific:** false (was v1.0) - **Territory (would have been):** `demo/modules/l1/**` @@ -127,9 +127,9 @@ lambda owns the SNS topic Terraform; frontend is unchanged from v1.0 ## Conflict resolutions (lead-developer arbitration) -- `backend-engineer` vs `platform-engineer` over `schemas/ir.schema.json` + `schemas/stack.schema.json`: platform-engineer owns the IR (substrate-agnostic but infra-shaped); backend-engineer owns the contract schema and the contract→IR resolution. Co-authoring is expected; conflict goes to lead-developer. +- `backend-engineer` vs `platform-engineer` over `schemas/ir.schema.json` + `schemas/stack.schema.json`: platform-engineer owns the IR (engine-agnostic but infra-shaped); backend-engineer owns the contract schema and the contract→IR resolution. Co-authoring is expected; conflict goes to lead-developer. - `backend-engineer` vs `security-engineer` over `core/confidence_signal.py`: security-engineer owns the severity→penalty mapping + critical-override semantics; backend-engineer owns the 6-input weighted sum + per-env thresholds. Co-owned; conflicts go to lead-developer. -- `platform-engineer` vs `security-engineer` over `adapters/terraform/policy/**`: security-engineer owns the Checkov→PolicyCheckResult adapter + custom rules + the Wiz/Kyverno adapters (policy is a security concern); platform-engineer owns the Terraform adapter (substrate translation). No overlap. +- `platform-engineer` vs `security-engineer` over `adapters/terraform/policy/**`: security-engineer owns the Checkov→PolicyCheckResult adapter + custom rules + the Wiz/Kyverno adapters (policy is a security concern); platform-engineer owns the Terraform adapter (engine translation). No overlap. - `lambda-engineer` vs `platform-engineer` over `terraform/platform/main.tf`: lambda-engineer owns the Lambda + DynamoDB + Secrets Manager definitions; platform-engineer reviews the Terraform structure + state backend. Co-authoring expected; conflicts go to lead-developer. - `backend-engineer` vs `lambda-engineer` over `core/lambda/contract_ingestor.py` vs `scripts/run_platform.sh` + `.github/workflows/deploy.yml` error-report step: lambda-engineer owns the Lambda handler; backend-engineer owns the workflow step that invokes it. The interface (the JSON payload) is co-authored; conflicts go to lead-developer. - `lead-developer` vs any: lead-developer owns `.ciagent/**` + `docs/**` meta + verification scripts; persona engineers do not edit CIAgent metadata or the vision/architecture source docs. diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 4ea819f..a1a78da 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -56,7 +56,7 @@ Finalize the architecture to v1.0 (resolve all 11 open design decisions in `docs/architecture.md` §13) and prove the locked commitments with one end-to-end v1 implementation spike: -- **One L1 module** (`l1-s3`) — substrate-agnostic, IR-typed interface. +- **One L1 module** (`l1-s3`) — engine-agnostic, IR-typed interface. - **One L2 thin-composition** (`l2-static-assets`) — references the L1. - **Terraform adapter** — compiles the IR to a real `terraform plan` against AWS via OIDC (no long-lived credentials, per §12.5). @@ -439,7 +439,7 @@ appendix below. The demo is **archived** to `demo/` in Phase 06. New requirements REQ-16..REQ-28 — see `REQUIREMENTS.md` §v1.1. Summary: - **REQ-16:** Architecture finalized to v1.0 (11 open decisions resolved). -- **REQ-17:** Target Stack IR defined as JSON Schema; substrate-agnostic. +- **REQ-17:** Target Stack IR defined as JSON Schema; engine-agnostic. - **REQ-18:** PolicyCheckResult normalized schema defined; Checkov adapter. - **REQ-19:** Six-input confidence signal specified with per-env thresholds (dev 0.50 / qa 0.75 / prod 0.90 / dr 0.95) and severity→penalty mapping. @@ -459,7 +459,7 @@ New requirements REQ-16..REQ-28 — see `REQUIREMENTS.md` §v1.1. Summary: - **REQ-27:** One end-to-end contract submission → contract→IR resolution → `terraform plan` → Checkov → confidence signal → evidence event to outbox. - **REQ-28:** Spike verification proves the IR-shaped commitments hold (no - polyglot mess; the adapter is the only substrate-specific code). + polyglot mess; the adapter is the only engine-specific code). ### v1.2 (Prior milestone — platform hardening + first real consumer deployment, complete) @@ -524,8 +524,8 @@ D-080+ to avoid collision with v1.8 research decisions D-073..D-077): - **Cloud:** AWS via OIDC federation. **Long-lived credentials are forbidden** (§12.5). The v1.1 spike uses a temporary long-lived key **once** to bootstrap OIDC (waiver D-034), then rotates it. -- **Substrate:** Terraform adapter in v1 (the only adapter). L1/L2 are - substrate-agnostic in shape; the adapter is the only substrate-specific code. +- **Angine:** Terraform adapter in v1 (the only adapter). L1/L2 are + engine-agnostic in shape; the adapter is the only engine-specific code. - **State:** S3 (state files) + DynamoDB (locking), single-region in v1. - **Environments:** dev (autonomous) → qa (QA HITL) → prod (SRE HITL) → dr (SRE HITL). **Staging does not exist** (Path A locked). @@ -550,7 +550,7 @@ D-080+ to avoid collision with v1.8 research decisions D-073..D-077): vision/architecture sources, pulled from `origin/main` at the start of v1.1. - The v1.0 demo (tag `v1.1.0`) is the reference of intent — it proved the shape (L1/L2/contract/confidence/evidence/HITL) on stubs. v1.1 replaces the - stubs with the real platform substrate. + stubs with the real platform engine. ## Key Decisions (v1.1) @@ -629,8 +629,8 @@ or user-directed scope). New v1.7 decisions: | BA.C | On-call / operational ownership | **Decided.** Platform on-call = Infra & Ops rotation. Escalation: L3A/L3B halt → platform on-call pager (Sev2); consumer-visible outage → consumer on-call (Sev1) with platform on-call support. Consumer on-call relationship is contractual, defined at onboarding (BA.E). | | BA.D | Cost / capacity governance | **Decided.** Cloud cost owner = Infra & Ops FinOps. Per-contract consumption reported monthly. Runaway spend: hard halt at 120% of contract-declared budget envelope via the confidence signal (cost is one of the 6 inputs); override = FinOps + SRE joint sign-off. | | BA.E | Consumer onboarding | **Decided.** Two paths: developer (L3A) — `getting-started` walks through contract schema + central pipeline template; citizen developer (L3B) — onboarding grants a scoped agent + skill catalog, no workflow authoring. Both end in a sandbox dev submission that must pass the confidence gate before the consumer is promoted. | -| BA.F | Cross-platform evolution | **Decided.** The contract schema, IR, PolicyCheckResult, confidence signal, and audit stream are portable (substrate- and forge-agnostic). Forge-specific code: workflow YAML, OIDC trust, CODEOWNERS, Environments. A second forge (e.g., GitLab) requires a forge adapter + a workflow-template translator; no change to L1/L2/IR/confidence/audit. | -| Q1.3 | OpenTofu timing | **Decided (deferred).** Not in v1 or v1.1. The substrate abstraction (§12) makes OpenTofu a future adapter, not an architecture change. Revisit when an OpenTofu adapter is requested; no version committed. | +| BA.F | Cross-platform evolution | **Decided.** The contract schema, IR, PolicyCheckResult, confidence signal, and audit stream are portable (engine- and forge-agnostic). Forge-specific code: workflow YAML, OIDC trust, CODEOWNERS, Environments. A second forge (e.g., GitLab) requires a forge adapter + a workflow-template translator; no change to L1/L2/IR/confidence/audit. | +| Q1.3 | OpenTofu timing | **Decided (deferred).** Not in v1 or v1.1. The engine abstraction (§12) makes OpenTofu a future adapter, not an architecture change. Revisit when an OpenTofu adapter is requested; no version committed. | ## Appendix — Prior milestone (v1.0 demo) decisions diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 33c9e71..82fa1d6 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -39,7 +39,7 @@ ### Category: Architecture Finalization - **REQ-16:** Architecture reaches v1.0 — all 11 open decisions in `docs/architecture.md` §13 are resolved and recorded in `PROJECT.md` (W1.A, W1.B, W2.A, W3.D, W3.E, BA.A–F, OpenTofu timing). -- **REQ-17:** Target Stack IR is defined as a JSON Schema under `schemas/ir.schema.json`; substrate-agnostic (resources, relationships, composition max-depth-5, policy hooks). +- **REQ-17:** Target Stack IR is defined as a JSON Schema under `schemas/ir.schema.json`; engine-agnostic (resources, relationships, composition max-depth-5, policy hooks). - **REQ-18:** `PolicyCheckResult` normalized schema is defined under `schemas/policy_check_result.schema.json`; a Checkov adapter translates Checkov JSON to this schema. - **REQ-19:** Six-input confidence signal is specified under `platform/confidence_signal.py` with per-env thresholds (dev 0.50 / qa 0.75 / prod 0.90 / dr 0.95) and severity→penalty mapping (critical=hard override, high=-0.2, medium=-0.05, low=-0.01, info=0.0). - **REQ-20:** Tiered audit ledger design is authored: S3 Object Lock (compliance mode, 7-yr) + DynamoDB outbox (RPO=0, JWS detached signatures, `prev_event_hash` chain, daily checkpoints). @@ -56,7 +56,7 @@ ### Category: v1 Spike — End-to-End - **REQ-27:** One end-to-end contract submission (`contracts/spike.yaml` for `l2-static-assets`) flows through: contract schema validation → contract→IR resolution → `terraform plan` (real AWS) → Checkov `PolicyCheckResult` → confidence signal → evidence event written to the DynamoDB outbox. -- **REQ-28:** Spike verification (`scripts/verify_phase10.sh`) proves the IR-shaped commitments hold: the adapter is the only substrate-specific code; no polyglot mess; the L1 content, contract YML, and thin-composition tree are substrate-agnostic. +- **REQ-28:** Spike verification (`scripts/verify_phase10.sh`) proves the IR-shaped commitments hold: the adapter is the only engine-specific code; no polyglot mess; the L1 content, contract YML, and thin-composition tree are engine-agnostic. ## Out of Scope (v1.1) diff --git a/.ciagent/RESEARCH.md b/.ciagent/RESEARCH.md index a13c75b..10e1003 100644 --- a/.ciagent/RESEARCH.md +++ b/.ciagent/RESEARCH.md @@ -106,7 +106,7 @@ step without a long-lived key) | (b) Self-hosted OIDC broker | Stand up a tiny OIDC IdP (e.g. `dex`, `oauth2-proxy`, or a custom JWKS endpoint) that the Gitea job authenticates to with its `GITEA_TOKEN` and that issues a JWT minted with a platform signing key; AWS IAM trusts the broker's JWKS. | Workable but heavy for a spike — requires a second always-on service, a signing-key rotation story, and IAM trust plumbing. Better suited to v1.2. | | (c) `aws sts assume-role-with-web-identity` with a token from Gitea's own API | Use the job's `GITEA_TOKEN` (a PAT-equivalent, short-lived for the job) as the `WebIdentityToken` to STS. | **Rejected**: STS rejects non-OIDC tokens; `GITEA_TOKEN` is not a JWT, has no `iss`/`sub`/`aud` claims, and AWS IAM has no Gitea OIDC provider to trust. (This is exactly the gap #33681 describes for GCP.) | | (d) Short-lived AWS creds via a scheduled credential mint | A platform job (cron) mints `aws sts get-session-token` (or a role-session) and writes the temp creds as a Gitea Actions secret with a TTL ≤ 1h. The spike workflow reads the secret. | Workable, but reintroduces a long-lived key *upstream* (the mint job needs one) and a secret in Gitea — a narrower version of the very thing §12.5 forbids. Acceptable as a documented spike-only waiver if (a) and (b) are both rejected for the spike scope. | -| (e) LocalStack as an AWS stand-in | Replace real AWS with LocalStack for the spike; no IAM trust needed at all (LocalStack mocks STS). | Workable for the *mechanics* of `terraform plan` but **invalidates REQ-23** ("real AWS via OIDC") and the spike's whole purpose of proving real-AWS feasibility. Reject for the spike; keep as a unit-test substrate only. | +| (e) LocalStack as an AWS stand-in | Replace real AWS with LocalStack for the spike; no IAM trust needed at all (LocalStack mocks STS). | Workable for the *mechanics* of `terraform plan` but **invalidates REQ-23** ("real AWS via OIDC") and the spike's whole purpose of proving real-AWS feasibility. Reject for the spike; keep as a unit-test engine only. | | (f) Documented spike-only waiver: rotate a long-lived key per-run | One IAM access key, stored as a Gitea Actions secret, used by the workflow, rotated (deactivated + new key) after each spike run by the same workflow. | The cleanest *available* option that still touches real AWS. Still violates the *letter* of §12.5 ("long-lived credentials are forbidden") but satisfies the *intent* for a time-boxed spike: the key's useful lifetime equals one workflow run (minutes), not "long-lived." Requires an explicit, logged waiver. | | (g) GitHub-hosted mirror pipeline | Run the OIDC-requiring step on GitHub Actions (which supports `id-token: write`) against the same repo mirrored from Gitea. | Rejected: introduces a second forge, violates the "Forge: Gitea" constraint, and defeats the spike's purpose of proving the platform works on Gitea. | @@ -348,7 +348,7 @@ the adapter and the round-trip to Terraform is verified. - **A-3.1** (0.85): the IR's "nearly isomorphic to Terraform in v1" claim (architecture.md §12.1) is the right v1 boundary — build a thin IR, defer - substrate-specific expressiveness to v2. + engine-specific expressiveness to v2. - **A-3.2** (0.80): single-parent-per-child is sufficient for v1 (no L1 needs two parents in the spike). The "shared keyword for multi-relationship" (architecture.md §12.1) is a v2 concern; the v1 schema reserves the field @@ -1447,7 +1447,7 @@ AWS Terraform resources; the adapter `TYPE_MAP` (currently | `l1-alb` | `aws:elbv2:loadbalancer`, `aws:elbv2:listener`, `aws:elbv2:targetgroup` | `aws_lb`, `aws_lb_listener`, `aws_lb_target_group` | port, protocol | | `l1-ecr` | `aws:ecr:repository` | `aws_ecr_repository` | name | -The IR schema (`schemas/ir.schema.json`) is substrate-agnostic and already +The IR schema (`schemas/ir.schema.json`) is engine-agnostic and already supports arbitrary resource types — no schema change needed, only new `interface.json` files + `TYPE_MAP` entries. The `l2-microservice` thin-composition references all six (depth ≤ 5). diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index bd6633a..572691b 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -142,7 +142,7 @@ D-034 closed (root key deactivated by user).** - **Success Criteria:** - `l2-static-assets` references `l1-s3` only (depth 1). - One contract submission completes the full pipeline end-to-end. - - `scripts/verify_phase10.sh` proves the adapter is the only substrate-specific code. + - `scripts/verify_phase10.sh` proves the adapter is the only engine-specific code. - Evidence event is written to the DynamoDB outbox. After Phase 10: COMPLETE gate — review → ship `v1.2.0` → audit. **DONE.** diff --git a/README.md b/README.md index c1baf6f..9ac3df7 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Planned future features (no dates; tracked in the internal roadmap): "composition" mechanism, redesigned). - **Compliance milestone** — per-module compliance extension points (GDPR, SOX, SOC2, DORA) wired into the pipeline. -- **Additional substrate adapters** — beyond the Terraform adapter. +- **Additional engine adapters** — beyond the Terraform adapter. - **Environment self-service** — a consumer-facing flow to request and provision a new platform-managed environment (today it is a platform-team action). @@ -117,9 +117,9 @@ flowchart TD The platform validates the architecture's claim that the **stack commitments do not require a polyglot mess**: the adapter is the only -substrate-specific code. `modules/`, `schemas/`, `contracts/`, +engine-specific code. `modules/`, `schemas/`, `contracts/`, `core/confidence_signal.py`, `core/contract_resolver.py`, and -`core/outbox_writer.py` are all substrate-agnostic (no `aws_s3_bucket` / +`core/outbox_writer.py` are all engine-agnostic (no `aws_s3_bucket` / `aws_` infrastructure terms). ## How to run @@ -258,7 +258,7 @@ across all modules; `static-assets` is the worked example. | `core/` | Platform code: contract resolver, confidence signal, outbox writer, environment check, environments, separation of duties, HITL/ledger designs | active | | `schemas/` | JSON Schemas: stack, contract, PolicyCheckResult, pipeline contract, deploy pipeline contract (draft 2020-12) | active | | `pipelines/` | Central pipeline contracts: `ci.yaml` (CI), `deploy.yaml` (deployment) | active | -| `adapters/` | Substrate adapters — the substrate adapter (the only substrate-specific code per §12) + the policy adapter | active | +| `adapters/` | Angine adapters — the engine adapter (the only engine-specific code per §12) + the policy adapter | active | | `terraform/` | State backend (S3 + DynamoDB) + platform TF (`terraform/spike/`) + bootstrap scripts (`terraform/bootstrap/`) | active | | `modules/` | Primitives + modules + `registry.json`. Primitives: s3, vpc, ecs-cluster, ecs-service, iam-role, alb, ecr, cloudfront, waf, rds. Modules: microservice, static-assets. Each module has a `examples/` directory with validated contract examples | active | | `contracts/` | Sample consumer contracts (`static-assets.yaml`, `microservice.yaml`) | active | diff --git a/adapters/README.md b/adapters/README.md index 58438c4..71a6094 100644 --- a/adapters/README.md +++ b/adapters/README.md @@ -2,7 +2,7 @@ ## Overview -Adapters translate the substrate-agnostic Target Stack IR to substrate-specific formats. The Terraform adapter is the primary adapter (IR → HCL). Policy adapters translate security tool output into normalized `PolicyCheckResult` records that the confidence signal consumes in an engine-agnostic way. +Adapters translate the engine-agnostic Target Stack IR to engine-specific formats. The Terraform adapter is the primary adapter (IR → HCL). Policy adapters translate security tool output into normalized `PolicyCheckResult` records that the confidence signal consumes in an engine-agnostic way. ## Existing Adapters diff --git a/adapters/terraform/adapter.py b/adapters/terraform/adapter.py index 7dacb1e..b6f02af 100644 --- a/adapters/terraform/adapter.py +++ b/adapters/terraform/adapter.py @@ -6,7 +6,7 @@ root module that calls the L1 modules, the stack-typed relationships to Terraform module references, and emits a Terraform plan from the stack. The adapter is a THIN LAYER; it does not own L1/L2 content — it only -translates. Substrate-agnostic in, Terraform out. +translates. Angine-agnostic in, Terraform out. Phase 09 spike: handled one L1 (s3, stack type aws:s3:bucket). Phase 13: generalized the resource/output emission via TYPE_MAP + @@ -21,7 +21,7 @@ import os import sys -# Stack type -> Terraform resource type. The only substrate-specific table. +# Stack type -> Terraform resource type. The only engine-specific table. # As more L1s land, this grows; the L1 content + stack do not change. TYPE_MAP = { "aws:s3:bucket": "aws_s3_bucket", diff --git a/docs/architecture.md b/docs/architecture.md index 4c9a96b..e56d63d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -21,7 +21,7 @@ flowchart TD A["Consumer surfaces"] --> B["Contract schema"] B --> C["Central pipeline"] C --> D["Modules + primitives"] - C --> E["Substrate adapter"] + C --> E["Angine adapter"] C --> F["Confidence signal"] C --> G["Evidence stream"] D --> E @@ -31,7 +31,7 @@ flowchart TD The four layers: -1. **Primitives** — single-purpose, substrate-agnostic modules representing +1. **Primitives** — single-purpose, engine-agnostic modules representing the smallest reusable infrastructure pieces (a VPC, an S3 bucket, an ECS cluster). A primitive does not reference other primitives; it takes its environment as input. @@ -51,9 +51,9 @@ Both end in a contract submission that enters the same pipeline. ## 2. Primitives -Single-purpose, substrate-agnostic modules. Locked commitments: +Single-purpose, engine-agnostic modules. Locked commitments: -- No inter-primitive references. A primitive may call substrate data sources. +- No inter-primitive references. A primitive may call engine data sources. - Semver with three triggers: interface → MAJOR, behavior → MINOR, lifecycle → PATCH. - Immutability on publication. @@ -61,8 +61,8 @@ Single-purpose, substrate-agnostic modules. Locked commitments: - AI refinement is a flag, triggered by a joint operational condition (N ≥ 50 consecutive zero-rollback changes, no primitive/module incident in 6 months, Infra & Ops unilateral override). -- A primitive's interface is defined against the Target Stack (substrate- - agnostic), not against any substrate's variable block directly. +- A primitive's interface is defined against the Target Stack (engine- + agnostic), not against any engine's variable block directly. ## 3. Modules @@ -79,9 +79,9 @@ Patterns that combine primitives into deployable shapes. Locked commitments: creation, key/secret creation, external data transfer. - Auto-promote after 3 observed usages. - A module's pattern tree wires field is defined against the stack's - relationship type, not against any substrate's module block. The stack → - substrate translation is the substrate adapter's job (§12). The pattern - pipeline itself is substrate-agnostic. + relationship type, not against any engine's module block. The stack → + engine translation is the engine adapter's job (§12). The pattern + pipeline itself is engine-agnostic. ## 4. Developer Surface @@ -110,7 +110,7 @@ Patterns that combine primitives into deployable shapes. Locked commitments: - Central repo + generated client libraries. - Multi-stage validation pipeline: schema → policy → NFR → confidence. - Distributed enrichment. -- GitOps reconciler + substrate execution layer. +- GitOps reconciler + engine execution layer. - The pipeline emits a `PolicyCheckResult` record per policy rule evaluated; the confidence signal consumes these as one normalized input (§8). @@ -174,12 +174,12 @@ integration, contract, security smoke, and performance smoke validation. - The DynamoDB outbox enforces identity distinctness across environment approvers. -## 12. Cross-Cutting — Substrate Execution +## 12. Cross-Cutting — Angine Execution -The technical execution layer. Primitives and modules are substrate-agnostic -in shape; substrate adapters are the only substrate-specific component. +The technical execution layer. Primitives and modules are engine-agnostic +in shape; engine adapters are the only engine-specific component. -The architecture defines a **Target Stack** — a substrate-neutral +The architecture defines a **Target Stack** — a engine-neutral description of: - The resources to create (typed against the stack schema). @@ -189,7 +189,7 @@ description of: The registry, the module pattern tree, the contract schema, and the `PolicyCheckResult` schema are all defined against the stack schema. None is -defined against any specific substrate. +defined against any specific engine. **v1 implementation reality:** the stack is shaped to round-trip cleanly to Terraform because there is no other adapter to differentiate from. As @@ -198,19 +198,19 @@ gain translation logic, but the primitive content, the module pattern tree, and the contract schema do not change. This is the design that prevents a polyglot mess. -The substrate adapter: +The engine adapter: -- Translates the stack-typed module pattern tree to a substrate root module +- Translates the stack-typed module pattern tree to a engine root module that calls the primitive modules. - Is a thin layer. It does not own primitive/module content; it only translates. -- Is the only substrate-specific code in the platform. +- Is the only engine-specific code in the platform. -Policy checks run on the substrate plan output. Results are normalized to +Policy checks run on the engine plan output. Results are normalized to `PolicyCheckResult` records by a policy adapter. The confidence signal consumes the union of all `PolicyCheckResult` records, regardless of engine -— substrate-agnostic over its inputs, matching the module model's -substrate-agnosticism over its outputs. +— engine-agnostic over its inputs, matching the module model's +engine-agnosticism over its outputs. ## 13. Cross-Cutting — Platform Runners @@ -237,5 +237,5 @@ See [Versioning](pipeline/versioning) for the consumer-facing details. ## 15. OpenTofu -Not in v1. The substrate abstraction (§12) makes OpenTofu a future adapter, +Not in v1. The engine abstraction (§12) makes OpenTofu a future adapter, not an architecture change. Revisit when an OpenTofu adapter is requested. \ No newline at end of file diff --git a/docs/consumer-guide.md b/docs/consumer-guide.md index 80d6508..72ffcec 100644 --- a/docs/consumer-guide.md +++ b/docs/consumer-guide.md @@ -10,7 +10,7 @@ step applies to `microservice` and any future module. Consumers have their own repos and consume ACDL by referencing `uses:` the central pipeline definitions. The consumer declares a **contract** (which module, which environment, which inputs); the ACDL platform owns the -pipelines, modules, substrate adapter, and evidence stream. +pipelines, modules, engine adapter, and evidence stream. You do not write infrastructure modules, workflow YAML, or adapter code. You write a contract YAML file and the platform does the rest. Your @@ -229,7 +229,7 @@ flowchart TD a stack JSON instance. 3. **security checks** (adapter) — security checks run on the resolved stack before any infrastructure is planned. -4. **infrastructure plan** (adapter) — the substrate adapter compiles the +4. **infrastructure plan** (adapter) — the engine adapter compiles the stack to an infrastructure plan. You see the plan in your run logs. 5. **policy checks** (adapter) — policy checks run on the plan. The results are normalized to `PolicyCheckResult` records. Each result has a @@ -314,7 +314,7 @@ per-module extension points. Common examples: | Sample contract | `contracts/microservice.yaml` | The microservice example contract (uses `@v1.9`). | | Module examples | `modules//examples/` | Validated per-module example contracts (`simple.yaml` + `complex.yaml`). | | Contract resolver | `core/contract_resolver.py` | Resolves contracts to stack instances. | -| Substrate adapter | `adapters/terraform/adapter.py` | Compiles stack instances to infrastructure. | +| Angine adapter | `adapters/terraform/adapter.py` | Compiles stack instances to infrastructure. | | Platform pipeline runner | `scripts/run_platform.sh` | The pipeline runner (platform-side; consumers do not invoke it directly). | | Environments | [environments/](environments/) | Platform-managed environments + onboarding. | | Versioning | [pipeline/versioning](pipeline/versioning) | The `uses:` tag + module versioning. | @@ -341,7 +341,7 @@ destruction: with: contract: .acdl/contract.yaml mode: decommission - changeRequestId: "CR-2026-001" + changeRequestId: "CHG0678912" ``` 3. **Step 1 — Disable deletion protection (HITL SRE gate):** The pipeline diff --git a/docs/index.md b/docs/index.md index 405fc19..a3e1cc0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,7 @@ There are two kinds of repository in the ACDL model: | [Pipeline](pipeline/) | Consumers + platform engineers | The central CI + deployment pipeline and its stages. | | [Versioning](pipeline/versioning) | Consumers + platform engineers | Module versioning + deploy-pipeline versioning (the `uses:` tag). | | [Environments](environments/) | Consumers | Platform-managed environments and the first-run onboarding flow. | -| [Architecture](architecture) | Platform engineers | The current architecture — layers, cross-cutting concerns, the substrate abstraction. | +| [Architecture](architecture) | Platform engineers | The current architecture — layers, cross-cutting concerns, the engine abstraction. | | [Vision](vision) | All | The why — the friction the platform absorbs and the north star. | ## Features @@ -64,7 +64,7 @@ Planned future features (no dates; tracked in the internal roadmap): mechanism, redesigned). - **Compliance milestone** — per-module compliance extension points (GDPR, SOX, SOC2, DORA) wired into the pipeline. -- **Additional substrate adapters** — beyond the Terraform adapter. +- **Additional engine adapters** — beyond the Terraform adapter. - **Environment self-service** — a consumer-facing flow to request and provision a new platform-managed environment. - **HITL gates for qa / prod / dr** — human attestation + higher confidence diff --git a/docs/modules/index.md b/docs/modules/index.md index 3b04a89..5cae942 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -9,7 +9,7 @@ Reusable building blocks for cloud infrastructure. There are two kinds: complete stack (e.g. an ECS Fargate microservice). Each module has a `composition.json` declaring its children and wires. -The substrate adapter compiles a module instance to infrastructure. Each +The engine adapter compiles a module instance to infrastructure. Each module's README documents which resources it creates. ## Primitives diff --git a/docs/pipeline/index.md b/docs/pipeline/index.md index 8d545fb..81d85d2 100644 --- a/docs/pipeline/index.md +++ b/docs/pipeline/index.md @@ -67,7 +67,7 @@ flowchart TD wires the contract inputs, emits a stack JSON instance). 3. **security checks** (adapter) — security checks run on the resolved stack before any infrastructure is planned. -4. **infrastructure plan** (adapter) — the substrate adapter compiles the +4. **infrastructure plan** (adapter) — the engine adapter compiles the stack to an infrastructure plan. 5. **policy checks** (adapter) — policy checks run on the plan. Results are normalized to `PolicyCheckResult` records (severity, rule ID, pass/fail). diff --git a/docs/presentations/README.md b/docs/presentations/README.md index 85832ac..ba6f398 100644 --- a/docs/presentations/README.md +++ b/docs/presentations/README.md @@ -58,8 +58,9 @@ Synthesize the full markdown into a lean Marp deck: - **`` + ``** on title and closing slides for the dark-background title style. - **Maturity badges** using inline spans: - `Available today` + `Testing` `Planned` + `Agentic` - **Tighter prose** than Step 1 — strip the speaker-note nuance; keep the leadership-relevant selling points. @@ -133,15 +134,16 @@ docs/presentations/ ### Maturity framing -Every capability claim in a deck is tagged with one of two badges: +Every capability claim in a deck is tagged with one of three badges: | Badge | Meaning | |---|---| -| `Available today` | Shipped and verified in the platform | -| `Planned` | On the roadmap, not yet shipped | +| `Testing` | Works internally, not yet released to consumers (0 adoption) | +| `Planned` | On the roadmap, not yet implemented | +| `Agentic` | Involves AI agents, autonomous decision-making, or the citizen developer flow | This is non-negotiable for a leadership audience: never present a roadmap -item as a current capability, and never bury a shipped capability's +item as a current capability, and never bury a tested capability's availability. When in doubt, check `.ciagent/ROADMAP.md` and the milestone status in `.ciagent/PROJECT.md`. diff --git a/docs/presentations/how-the-platform-works-marp.md b/docs/presentations/how-the-platform-works-marp.md index 5f84efb..e0f843e 100644 --- a/docs/presentations/how-the-platform-works-marp.md +++ b/docs/presentations/how-the-platform-works-marp.md @@ -23,8 +23,9 @@ style: | display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } - .today { background: #c6f6d5; color: #22543d; } + .testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } + .agentic { background: #EDE9FE; color: #4C1D95; } --- @@ -45,12 +46,14 @@ section.title h3 { color: #F0F0F0; font-weight: 400; font-size: 22px; margin-top Software delivery scales with the **coordination surface around it**, not the engineering inside it. -Two frictions slow every team: +Four frictions slow every team: - **Cognitive load** — authoring the infrastructure that runs a service *correctly*. The long tail of services that are difficult to deploy, inconsistent in security and observability posture. -- **Operational work** — moving a merged change from "merged" to "running in production with policy, observability, and security enforced." Manual work that **scales with the system, not with the change.** +- **Operational work** — promoting a change from "merged" to "running in production with policy, observability, and security enforced." Manual work that **scales with the system, not with the change.** +- **Red tape** — every deployment requires tickets, approvals, and manual handoffs that scale with the organization, not with the change. A merged change waits in a queue for someone to press a button. +- **Scalability without increasing headcount** — the platform allows delivery throughput to scale without linearly scaling platform engineers. Today, every new team adds load to the same ticket queue. -The platform absorbs **both** frictions. +The platform absorbs **all four** frictions. --- @@ -66,6 +69,22 @@ Success looks like: --- +# What This Platform Is — and Isn't + +**What it is:** + +- **A sovereign delivery boundary.** The platform governs infrastructure and delivery. It does not penetrate upstream product or software development lifecycles. Integration happens through validated, published contracts. +- **Infrastructure consumed, not maintained.** Compute is abstract, containerized, or serverless. The platform does not manage node, OS, or bare-metal lifecycles. Infrastructure is a utility, not a craft. + +**What it isn't:** + +- **Not an upstream development platform.** No product backlogs, sprint ceremonies, or IDE workflows. +- **Not a general-purpose AI.** Autonomy is narrow, scoped to delivery and infrastructure reconciliation, bounded by strict policy envelopes. +- **Not a legacy infrastructure bridge.** No VMs, bare metal, or OS lifecycles. +- **Not a permissive delivery highway.** No escape hatches to bypass the confidence framework or human attestation requirements. + +--- + # The Contract-Driven Model One small YAML file is all a consumer writes. The platform owns everything else. @@ -95,7 +114,7 @@ Every deployment runs the same stages, in the same order, with the same checks Consumer repositories hold **no long-lived cloud credentials.** Ever. -- **Authentication — OIDC federation.** Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. Available today (GitHub Actions) Planned: all runners +- **Authentication — OIDC federation.** Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. Testing (GitHub Actions) Planned: all runners - **Authorization — attribute-based (ABAC), not role-based.** Two attribute classes scope every action: - **Repository identity** — the role's trust policy binds to the exact consumer repo + branch - **Resource tags** — every resource is tagged `acdl:owner` + `acdl:contract`; the session policy grants access **only to matching tags** @@ -106,7 +125,7 @@ Consumer repositories hold **no long-lived cloud credentials.** Ever. # Safety is Computed, Not Assumed -Every delivery action produces a **measurable, explainable confidence signal** — the platform's certified answer to *"is this safe to proceed?"* +Every delivery action produces a **measurable, explainable confidence signal** — the platform's certified answer to *"is this safe to proceed?"* Agentic - **Six weighted inputs:** policy conformance, validation, freshness, source provenance, history, NFRs - **Per-environment thresholds** that rise with sensitivity: @@ -127,9 +146,9 @@ Every delivery action produces a **measurable, explainable confidence signal** Checks run on **every** deployment, normalized to a single schema regardless of which engine produced them. -- **Infrastructure policy** (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS references, **required tagging standards** (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`) Available today -- **Cloud security posture** (Wiz adapter) — translates cloud security findings into the same normalized record Adapter ready -- **Kubernetes-native policy** (Kyverno adapter) — ready for the GitOps reconciler Adapter ready +- **Infrastructure policy** (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS references, **required tagging standards** (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`) Testing +- **Cloud security posture** (Wiz adapter) — translates cloud security findings into the same normalized record Testing +- **Kubernetes-native policy** (Kyverno adapter) — ready for the GitOps reconciler Testing Every check produces a record with **severity, rule ID, pass/fail status, and a human-readable message** — consumed uniformly by the confidence signal. @@ -137,7 +156,7 @@ Every check produces a record with **severity, rule ID, pass/fail status, and a # Secure by Default -Security defaults that **do not require a team to opt in.** Available today +Security defaults that **do not require a team to opt in.** Testing - **Encryption on every resource** — at-rest encryption on by default for every primitive (S3, RDS, ECR, ECS, and more) - **Per-stack customer-managed keys** — one key per deployment, 90-day rotation, **no shared keys across stacks** @@ -151,10 +170,10 @@ Security defaults that **do not require a team to opt in.** Available today -- **Tiered storage:** cold, tamper-proof source of truth (S3 Object Lock, 7-year retention) + a hot query index Outbox shipped Full ledger: planned +- **Every deployment writes a hash-chained evidence event** — each event links to the previous via a cryptographic hash; tampering breaks the chain Testing +- **Tiered storage:** cold, tamper-proof source of truth (S3 Object Lock, 7-year retention) + a hot query index Outbox tested Full ledger: planned - **RPO = 0** — the evidence write is synchronous; a deployment is not acknowledged until the evidence event is durably recorded -- **Every production change is traceable to a human attestation** — approver identities are the only durable record outside the forge's audit log +- **Every production change is traceable to a human attestation** — approver identities are the only durable record outside the VCS's audit log --- @@ -162,16 +181,16 @@ Version control is a **coordination tool, not an evidentiary fortress.** True co Autonomy and accountability are **not in tension** — they apply at different environments. -- **Dev is fully autonomous.** The confidence signal (≥ 0.50) is the only gate. Queue-based handoffs are eliminated from lower environments. +- **Dev is fully autonomous.** The confidence signal (≥ 0.50) is the only gate. Queue-based handoffs are eliminated from lower environments. Agentic - **qa, prod, and dr require deliberate human attestation** — not rubber stamps, but policy-mandated acts of accountability via protected deployment approvals. -- **Separation of duties is enforced** — the QA approver **cannot** be the prod approver. The platform reads both identities from the outbox and **blocks on a match.** Design shipped Wiring: planned +- **Separation of duties is enforced** — the QA approver **cannot** be the prod approver. The platform reads both identities from the outbox and **blocks on a match.** Design tested Wiring: planned - **Timeout discipline** — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit --- # Observability Built In -Monitoring is **a platform default, not a per-team project.** Available today +Monitoring is **a platform default, not a per-team project.** Testing - **Uptime monitoring deployed automatically with every stack** — a dedicated monitoring instance is provisioned after any module deploy, in a separate state, with a feature flag to disable - **Monitored endpoints passed from the deployment's own outputs** — no manual endpoint registration @@ -194,7 +213,7 @@ A named environment is a platform-owned bundle of: The consumer selects an environment **by name** in their contract. The platform resolves the name to the underlying resources at run time. **The consumer never sees raw credentials.** -**Friendly onboarding:** the first run detects no environment and emits a guided prompt (not an opaque failure). Available today Self-service: planned +**Friendly onboarding:** the first run detects no environment and emits a guided prompt (not an opaque failure). Testing Self-service: planned --- @@ -202,42 +221,56 @@ The consumer selects an environment **by name** in their contract. The platform The platform is **opinionated, but not painted into a corner.** -- **Substrate-agnostic core.** The contract, the resolved stack, the policy results, the confidence signal, and the evidence stream are all defined *without reference to any specific infrastructure tool.* 1 adapter: Terraform OpenTofu / Pulumi / K8s -- **Forge-agnostic contract ingestion.** The platform Lambda reads a configurable API base for GitHub or Gitea. Available today -- **Portable contracts.** A second forge needs a forge adapter + a workflow translator — **no change to modules, contracts, confidence, or audit** -- **Pattern recognition compounds value over time.** As the platform observes recurring patterns, it can synthesize reusable modules. Future capability +- **Engine-agnostic core.** The contract, the resolved stack, the policy results, the confidence signal, and the evidence stream are all defined *without reference to any specific infrastructure tool.* 1 adapter: Terraform OpenTofu / Pulumi / K8s +- **VCS-agnostic contract ingestion.** The platform Lambda reads a configurable API base for GitHub or Gitea. Testing +- **Portable contracts.** A second VCS needs a VCS adapter + a workflow translator — **no change to modules, contracts, confidence, or audit** +- **Pattern recognition compounds value over time.** As the platform observes recurring patterns, it can synthesize reusable modules. Future capability Agentic --- -# Roadmap: Shipped vs. Planned +# Testing vs. Planned -**Available today** + + + + + +
+ +**Testing** (works internally, not yet released to consumers) - Contract-driven deploys with a versioned reusable workflow - Module catalog (primitives + modules) with validated examples - Zero-trust OIDC + ABAC on GitHub Actions runners - Security + policy checks before infra creation (Checkov; Wiz + Kyverno ready) -- Confidence signal (6 inputs, per-env thresholds) gating promotion +- Confidence signal (6 inputs, per-env thresholds) gating promotion Agentic - Hash-chained, tamper-evident evidence outbox (RPO = 0) - Encryption by default + per-stack customer-managed keys - Deletion protection by default + safe decommission with SRE gates - Uptime monitoring deployed automatically with every stack - Platform-managed environments + friendly onboarding -- Local reproducibility + forge-agnostic contract ingestion +- Local reproducibility + VCS-agnostic contract ingestion -**Planned (on the roadmap)** + + +**Planned** (on the roadmap) - Real OIDC federation on all platform runners - HITL wiring for qa / prod / dr environments - Full regulatory ledger: S3 Object Lock + JWS signatures + daily checkpoints - Compliance milestone: GDPR, SOX, SOC2, DORA extension points - Environment self-service provisioning -- Dynamic module creation from a contract (agentic citizen-developer flow) -- Additional substrate adapters (OpenTofu, Pulumi, Kubernetes CRDs) \ No newline at end of file +- Dynamic module creation from a contract (agentic citizen-developer flow) Agentic +- Additional engine adapters (OpenTofu, Pulumi, Kubernetes CRDs) + +
\ No newline at end of file diff --git a/docs/presentations/how-the-platform-works.html b/docs/presentations/how-the-platform-works.html index 5982e2d..e552eba 100644 --- a/docs/presentations/how-the-platform-works.html +++ b/docs/presentations/how-the-platform-works.html @@ -7,7 +7,7 @@ * @auto-scaling true * @size 16:9 1280px 720px * @size 4:3 960px 720px - */div#\:\$p > svg > foreignObject > section [data-theme=light],div#\:\$p > svg > foreignObject > section{color-scheme:light}div#\:\$p > svg > foreignObject > section [data-theme=dark],div#\:\$p > svg > foreignObject > section:where(.invert){color-scheme:dark}div#\:\$p > svg > foreignObject > section{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;margin:0;font-weight:var(--base-text-weight-normal, 400);color:var(--fgColor-default);background-color:var(--bgColor-default);font-family:var(--fontStack-sansSerif, -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji");font-size:16px;line-height:1.5;word-wrap:break-word}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:16px}div#\:\$p > svg > foreignObject > section a{text-decoration:underline;text-underline-offset:calc(var(--marpit-root-font-size, 1rem) * .2)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link:before{width:16px;height:16px;content:" ";display:inline-block;background-color:currentColor;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,');mask-image:url('data:image/svg+xml;charset=utf-8,')}div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section figcaption,div#\:\$p > svg > foreignObject > section figure{display:block}div#\:\$p > svg > foreignObject > section summary{display:list-item}div#\:\$p > svg > foreignObject > section [hidden]{display:none!important}div#\:\$p > svg > foreignObject > section a{background-color:transparent;color:var(--fgColor-accent);text-decoration:none}div#\:\$p > svg > foreignObject > section abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}div#\:\$p > svg > foreignObject > section b,div#\:\$p > svg > foreignObject > section strong{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section dfn{font-style:italic}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){margin:.67em 0;font-weight:var(--base-text-weight-semibold, 600);padding-bottom:.3em;font-size:2em;border-bottom:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section mark{background-color:var(--bgColor-attention-muted);color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section small{font-size:90%}div#\:\$p > svg > foreignObject > section sub,div#\:\$p > svg > foreignObject > section sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}div#\:\$p > svg > foreignObject > section sub{bottom:-.25em}div#\:\$p > svg > foreignObject > section sup{top:-.5em}div#\:\$p > svg > foreignObject > section img{border-style:none;max-width:100%;box-sizing:content-box}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section kbd,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp{font-family:monospace;font-size:1em}div#\:\$p > svg > foreignObject > section figure{margin:1em var(--base-size-40)}div#\:\$p > svg > foreignObject > section hr{box-sizing:content-box;overflow:hidden;background:transparent;height:.25em;padding:0;margin:var(--base-size-24) 0;background-color:var(--borderColor-default);border:0}div#\:\$p > svg > foreignObject > section input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}div#\:\$p > svg > foreignObject > section [type=button],div#\:\$p > svg > foreignObject > section [type=reset],div#\:\$p > svg > foreignObject > section [type=submit]{-webkit-appearance:button;-moz-appearance:button;appearance:button}div#\:\$p > svg > foreignObject > section [type=checkbox],div#\:\$p > svg > foreignObject > section [type=radio]{box-sizing:border-box;padding:0}div#\:\$p > svg > foreignObject > section [type=number]::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section [type=number]::-webkit-outer-spin-button{height:auto}div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-cancel-button,div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}div#\:\$p > svg > foreignObject > section ::-webkit-input-placeholder{color:inherit;opacity:.54}div#\:\$p > svg > foreignObject > section ::-webkit-file-upload-button{-webkit-appearance:button;appearance:button;font:inherit}div#\:\$p > svg > foreignObject > section a:hover{text-decoration:underline}div#\:\$p > svg > foreignObject > section ::-moz-placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section ::placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section hr:after,div#\:\$p > svg > foreignObject > section hr:before{display:table;content:""}div#\:\$p > svg > foreignObject > section hr:after{clear:both}div#\:\$p > svg > foreignObject > section table{border-spacing:0;border-collapse:collapse;display:block;width:-moz-max-content;width:max-content;max-width:100%;overflow:auto;font-variant:tabular-nums}div#\:\$p > svg > foreignObject > section td,div#\:\$p > svg > foreignObject > section th{padding:0}div#\:\$p > svg > foreignObject > section details summary{cursor:pointer}div#\:\$p > svg > foreignObject > section [role=button]:focus,div#\:\$p > svg > foreignObject > section a:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus{outline:2px solid var(--focus-outlineColor);outline-offset:-2px;box-shadow:none}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=radio]:focus:not(:focus-visible){outline:1px solid transparent}div#\:\$p > svg > foreignObject > section [role=button]:focus-visible,div#\:\$p > svg > foreignObject > section a:focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{outline:2px solid var(--focus-outlineColor);outline-offset:-2px;box-shadow:none}div#\:\$p > svg > foreignObject > section a:not([class]):focus,div#\:\$p > svg > foreignObject > section a:not([class]):focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{outline-offset:0}div#\:\$p > svg > foreignObject > section kbd{display:inline-block;padding:var(--base-size-4);font:11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);line-height:10px;color:var(--fgColor-default);vertical-align:middle;background-color:var(--bgColor-muted);border-bottom-color:var(--borderColor-neutral-muted);border:1px solid var(--borderColor-neutral-muted);border-radius:6px;box-shadow:inset 0 -1px 0 var(--borderColor-neutral-muted)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){margin-top:var(--base-size-24);margin-bottom:var(--base-size-16);font-weight:var(--base-text-weight-semibold, 600);line-height:1.25}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.25em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:.875em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-weight:var(--base-text-weight-semibold, 600);font-size:.85em;color:var(--fgColor-muted)}div#\:\$p > svg > foreignObject > section p{margin-top:0;margin-bottom:10px}div#\:\$p > svg > foreignObject > section blockquote{margin:0;padding:0 1em;color:var(--fgColor-muted);border-left:.25em solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section ul{margin-top:0;margin-bottom:0;padding-left:2em}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ul ol{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol ol ol,div#\:\$p > svg > foreignObject > section ol ul ol,div#\:\$p > svg > foreignObject > section ul ol ol,div#\:\$p > svg > foreignObject > section ul ul ol{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section dd{margin-left:0}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp,div#\:\$p > svg > foreignObject > section tt{font-family:var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);font-size:12px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){margin-top:0;margin-bottom:0;word-wrap:normal}div#\:\$p > svg > foreignObject > section .octicon{display:inline-block;overflow:visible!important;vertical-align:text-bottom;fill:currentColor}div#\:\$p > svg > foreignObject > section input::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section input::-webkit-outer-spin-button{margin:0;-webkit-appearance:none;appearance:none}div#\:\$p > svg > foreignObject > section .mr-2{margin-right:var(--base-size-8, 8px)!important}div#\:\$p > svg > foreignObject > section:after,div#\:\$p > svg > foreignObject > section:before{display:table}div#\:\$p > svg > foreignObject > section:after{clear:both}div#\:\$p > svg > foreignObject > section>:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section>:last-child{margin-bottom:0!important}div#\:\$p > svg > foreignObject > section a:not([href]){color:inherit;text-decoration:none}div#\:\$p > svg > foreignObject > section .absent{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section .anchor{float:left;padding-right:var(--base-size-4);margin-left:-20px;line-height:1}div#\:\$p > svg > foreignObject > section .anchor:focus{outline:none}div#\:\$p > svg > foreignObject > section blockquote,div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section dl,div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section p,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section table,div#\:\$p > svg > foreignObject > section ul{margin-top:0;margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section blockquote>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section blockquote>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) .octicon-link{color:var(--fgColor-default);vertical-align:middle;visibility:hidden}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor{text-decoration:none}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link{visibility:visible}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) code,div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) tt,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) code,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) tt,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) code,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) tt,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) code,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) tt,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) code,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) tt,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) code,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) tt{padding:0 .2em;font-size:inherit}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6){display:inline-block}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6) .anchor{margin-left:-40px}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2){padding-bottom:0;border-bottom:0}div#\:\$p > svg > foreignObject > section ol.no-list,div#\:\$p > svg > foreignObject > section ul.no-list{padding:0;list-style-type:none}div#\:\$p > svg > foreignObject > section ol[type="a s"]{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section ol[type="A s"]{list-style-type:upper-alpha}div#\:\$p > svg > foreignObject > section ol[type="i s"]{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol[type="I s"]{list-style-type:upper-roman}div#\:\$p > svg > foreignObject > section div>ol:not([type]),div#\:\$p > svg > foreignObject > section ol[type="1"]{list-style-type:decimal}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ol ul,div#\:\$p > svg > foreignObject > section ul ol,div#\:\$p > svg > foreignObject > section ul ul{margin-top:0;margin-bottom:0}div#\:\$p > svg > foreignObject > section li>p{margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section li+li{margin-top:.25em}div#\:\$p > svg > foreignObject > section dl{padding:0}div#\:\$p > svg > foreignObject > section dl dt{padding:0;margin-top:var(--base-size-16);font-size:1em;font-style:italic;font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section dl dd{padding:0 var(--base-size-16);margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section table th{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section table td,div#\:\$p > svg > foreignObject > section table th{padding:6px 13px;border:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section table td>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section table tr{background-color:var(--bgColor-default);border-top:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section table tr:nth-child(2n){background-color:var(--bgColor-muted)}div#\:\$p > svg > foreignObject > section table img{background-color:transparent}div#\:\$p > svg > foreignObject > section img[align=right]{padding-left:20px}div#\:\$p > svg > foreignObject > section img[align=left]{padding-right:20px}div#\:\$p > svg > foreignObject > section .emoji{max-width:none;vertical-align:text-top;background-color:transparent}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame,div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){display:block;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){float:left;width:auto;padding:7px;margin:13px 0 0;border:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) img{display:block;float:left}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) :is(span, marp-span){display:block;padding:5px 0 0;clear:both;color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center{display:block;overflow:hidden;clear:both}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center :is(span, marp-span) img{margin:0 auto;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right{display:block;overflow:hidden;clear:both}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right>:is(span, marp-span){display:block;margin:13px 0 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right :is(span, marp-span) img{margin:0;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left{display:block;float:left;margin-right:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left :is(span, marp-span){margin:13px 0 0}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right{display:block;float:right;margin-left:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section tt{padding:.2em .4em;margin:0;font-size:85%;white-space:break-spaces;background-color:var(--bgColor-neutral-muted);border-radius:6px}div#\:\$p > svg > foreignObject > section code br,div#\:\$p > svg > foreignObject > section tt br{display:none}div#\:\$p > svg > foreignObject > section del code{text-decoration:inherit}div#\:\$p > svg > foreignObject > section samp{font-size:85%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code{font-size:100%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)>code{padding:0;margin:0;word-break:normal;white-space:pre;background:transparent;border:0}div#\:\$p > svg > foreignObject > section .highlight{margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre){margin-bottom:0;word-break:normal}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){padding:var(--base-size-16);overflow:auto;font-size:85%;line-height:1.45;color:var(--fgColor-default);background-color:var(--bgColor-muted);border-radius:6px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) tt{display:inline;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}div#\:\$p > svg > foreignObject > section .csv-data td,div#\:\$p > svg > foreignObject > section .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}div#\:\$p > svg > foreignObject > section .csv-data .blob-num{padding:10px var(--base-size-8) 9px;text-align:right;background:var(--bgColor-default);border:0}div#\:\$p > svg > foreignObject > section .csv-data tr{border-top:0}div#\:\$p > svg > foreignObject > section .csv-data th{font-weight:var(--base-text-weight-semibold, 600);background:var(--bgColor-muted);border-top:0}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:before{content:"["}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:after{content:"]"}div#\:\$p > svg > foreignObject > section .footnotes{font-size:12px;color:var(--fgColor-muted);border-top:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section div#\:\$p > svg > foreignObject > section section.footnotes{--marpit-root-font-size:12px}div#\:\$p > svg > foreignObject > section .footnotes ol,div#\:\$p > svg > foreignObject > section .footnotes ol ul{padding-left:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes ol ul{display:inline-block;margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes li{position:relative}div#\:\$p > svg > foreignObject > section .footnotes li:target:before{position:absolute;top:calc(var(--base-size-8)*-1);right:calc(var(--base-size-8)*-1);bottom:calc(var(--base-size-8)*-1);left:calc(var(--base-size-24)*-1);pointer-events:none;content:"";border:2px solid var(--borderColor-accent-emphasis);border-radius:6px}div#\:\$p > svg > foreignObject > section .footnotes li:target{color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section .footnotes .data-footnote-backref g-emoji{font-family:monospace}div#\:\$p > svg > foreignObject > section .pl-c{color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section .pl-c1,div#\:\$p > svg > foreignObject > section .pl-s .pl-v{color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section .pl-e,div#\:\$p > svg > foreignObject > section .pl-en{color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section .pl-s .pl-s1,div#\:\$p > svg > foreignObject > section .pl-smi{color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section .pl-ent{color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section .pl-k{color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section .pl-pds,div#\:\$p > svg > foreignObject > section .pl-s,div#\:\$p > svg > foreignObject > section .pl-s .pl-pse .pl-s1,div#\:\$p > svg > foreignObject > section .pl-sr,div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sra,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sre{color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section .pl-smw,div#\:\$p > svg > foreignObject > section .pl-v{color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section .pl-bu{color:var(--color-prettylights-syntax-brackethighlighter-unmatched)}div#\:\$p > svg > foreignObject > section .pl-ii{color:var(--color-prettylights-syntax-invalid-illegal-text);background-color:var(--color-prettylights-syntax-invalid-illegal-bg)}div#\:\$p > svg > foreignObject > section .pl-c2{color:var(--color-prettylights-syntax-carriage-return-text);background-color:var(--color-prettylights-syntax-carriage-return-bg)}div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce{font-weight:700;color:var(--color-prettylights-syntax-string-regexp)}div#\:\$p > svg > foreignObject > section .pl-ml{color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section .pl-mh,div#\:\$p > svg > foreignObject > section .pl-mh .pl-en,div#\:\$p > svg > foreignObject > section .pl-ms{font-weight:700;color:var(--color-prettylights-syntax-markup-heading)}div#\:\$p > svg > foreignObject > section .pl-mi{font-style:italic;color:var(--color-prettylights-syntax-markup-italic)}div#\:\$p > svg > foreignObject > section .pl-mb{font-weight:700;color:var(--color-prettylights-syntax-markup-bold)}div#\:\$p > svg > foreignObject > section .pl-md{color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}div#\:\$p > svg > foreignObject > section .pl-mi1{color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}div#\:\$p > svg > foreignObject > section .pl-mc{color:var(--color-prettylights-syntax-markup-changed-text);background-color:var(--color-prettylights-syntax-markup-changed-bg)}div#\:\$p > svg > foreignObject > section .pl-mi2{color:var(--color-prettylights-syntax-markup-ignored-text);background-color:var(--color-prettylights-syntax-markup-ignored-bg)}div#\:\$p > svg > foreignObject > section .pl-mdr{font-weight:700;color:var(--color-prettylights-syntax-meta-diff-range)}div#\:\$p > svg > foreignObject > section .pl-ba{color:var(--color-prettylights-syntax-brackethighlighter-angle)}div#\:\$p > svg > foreignObject > section .pl-sg{color:var(--color-prettylights-syntax-sublimelinter-gutter-mark)}div#\:\$p > svg > foreignObject > section .pl-corl{text-decoration:underline;color:var(--color-prettylights-syntax-constant-other-reference-link)}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section button:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section summary:focus:not(:focus-visible){outline:none;box-shadow:none}div#\:\$p > svg > foreignObject > section [tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section details-dialog:focus:not(:focus-visible){outline:none}div#\:\$p > svg > foreignObject > section g-emoji{display:inline-block;min-width:1ch;font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:1em;font-style:normal!important;font-weight:var(--base-text-weight-normal, 400);line-height:1;vertical-align:-.075em}div#\:\$p > svg > foreignObject > section g-emoji img{width:1em;height:1em}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote){display:block}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote):not(:has(.snippet-clipboard-content,>:is(pre, marp-pre))){width:-moz-fit-content;width:fit-content}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote):has(.snippet-clipboard-content,>:is(pre, marp-pre)):focus-visible{outline:2px solid var(--focus-outlineColor);outline-offset:2px}div#\:\$p > svg > foreignObject > section .task-list-item{list-style-type:none}div#\:\$p > svg > foreignObject > section .task-list-item label{font-weight:var(--base-text-weight-normal, 400)}div#\:\$p > svg > foreignObject > section .task-list-item.enabled label{cursor:pointer}div#\:\$p > svg > foreignObject > section .task-list-item+.task-list-item{margin-top:var(--base-size-4)}div#\:\$p > svg > foreignObject > section .task-list-item .handle{display:none}div#\:\$p > svg > foreignObject > section .task-list-item-checkbox{margin:0 .2em .25em -1.4em;vertical-align:middle}div#\:\$p > svg > foreignObject > section ul:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section ol:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section .contains-task-list:focus-within .task-list-item-convert-container,div#\:\$p > svg > foreignObject > section .contains-task-list:hover .task-list-item-convert-container{display:block;width:auto;height:24px;overflow:visible;clip-path:none}div#\:\$p > svg > foreignObject > section ::-webkit-calendar-picker-indicator{filter:invert(50%)}div#\:\$p > svg > foreignObject > section .markdown-alert{padding:var(--base-size-8) var(--base-size-16);margin-bottom:var(--base-size-16);color:inherit;border-left:.25em solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section .markdown-alert>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section .markdown-alert>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section .markdown-alert .markdown-alert-title{display:flex;font-weight:var(--base-text-weight-medium, 500);align-items:center;line-height:1}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note{border-left-color:var(--borderColor-accent-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note .markdown-alert-title{color:var(--fgColor-accent)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important{border-left-color:var(--borderColor-done-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important .markdown-alert-title{color:var(--fgColor-done)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning{border-left-color:var(--borderColor-attention-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning .markdown-alert-title{color:var(--fgColor-attention)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip{border-left-color:var(--borderColor-success-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip .markdown-alert-title{color:var(--fgColor-success)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution{border-left-color:var(--borderColor-danger-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution .markdown-alert-title{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section>:first-child>.heading-element:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre):has(+.zeroclipboard-container){min-height:52px}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){color:var(--h1-color);font-size:1.6em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){border-bottom:none}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){font-size:1.3em}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1.05em}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-size:.9em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) strong,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) strong,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) strong,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) strong,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) strong,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) strong{font-weight:inherit;color:var(--heading-strong-color)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6)::part(auto-scaling){max-height:563px}div#\:\$p > svg > foreignObject > section hr{height:0;padding-top:.25em}div#\:\$p > svg > foreignObject > section img{background-color:transparent}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){border:1px solid var(--borderColor-default);line-height:1.15;overflow:visible}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)::part(auto-scaling){max-height:529px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-doctag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-tag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-variable),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-type),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable.language_){color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_.inherited__),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.function_){color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attribute),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-literal),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-number),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-operator),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-class),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-id),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable){color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-string),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-regexp),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-string){color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-built_in),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-symbol){color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-code),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-comment),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-formula){color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-name),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-quote),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-pseudo),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-tag){color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-subst){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-section){font-weight:700;color:var(--color-prettylights-syntax-markup-heading)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-bullet){color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-emphasis){font-style:italic;color:var(--color-prettylights-syntax-markup-italic)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-strong){font-weight:700;color:var(--color-prettylights-syntax-markup-bold)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-addition){color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-deletion){color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}div#\:\$p > svg > foreignObject > section footer,div#\:\$p > svg > foreignObject > section header{margin:0;position:absolute;left:30px;color:var(--header-footer-color);font-size:18px}div#\:\$p > svg > foreignObject > section header{top:21px}div#\:\$p > svg > foreignObject > section footer{bottom:21px}div#\:\$p > svg > foreignObject > section{--h1-color:light-dark(#246, #cee7ff);--header-footer-color:light-dark(hsla(0,0%,40%,.75), hsla(0,0%,60%,.75));--heading-strong-color:light-dark(#48c, #7bf);--paginate-color:light-dark(#777, #999);--base-size-4:4px;--base-size-8:8px;--base-size-16:16px;--base-size-24:24px;--base-size-40:40px;display:block;font-size:29px;height:720px;padding:78.5px;place-content:safe center center;width:1280px;flex-flow:column nowrap;align-items:stretch}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:29px}div#\:\$p > svg > foreignObject > section>:last-child,div#\:\$p > svg > foreignObject > section[data-footer]>:nth-last-child(2){margin-bottom:0}div#\:\$p > svg > foreignObject > section>:first-child,div#\:\$p > svg > foreignObject > section>header:first-child+*{margin-top:0}div#\:\$p > svg > foreignObject > section:after{position:absolute;padding:0;right:30px;bottom:21px;font-size:24px;color:var(--paginate-color)}div#\:\$p > svg > foreignObject > section:after{--marpit-root-font-size:24px}div#\:\$p > svg > foreignObject > section[data-color] :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section[data-color] :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section[data-color] :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section[data-color] :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section[data-color] :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section[data-color] :is(h6, marp-h6){color:currentcolor}div#\:\$p > svg > foreignObject > section{font-family:"Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;font-size:22px;color:#1B1B1B}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 22px}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){color:#D6002A;font-size:34px;margin-bottom:0.3em}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){color:#D6002A;font-size:26px;margin-bottom:0.2em}div#\:\$p > svg > foreignObject > section.title{background:#1B1B1B;color:#fff;border-top:8px solid #D6002A}div#\:\$p > svg > foreignObject > section.title :is(h1, marp-h1){color:#fff}div#\:\$p > svg > foreignObject > section table{font-size:18px;width:100%}div#\:\$p > svg > foreignObject > section th{background:#F0F0F0}div#\:\$p > svg > foreignObject > section blockquote{border-left:4px solid #D6002A;color:#2E2E2E;font-size:20px}div#\:\$p > svg > foreignObject > section img{display:block;margin:0 auto;max-height:320px}div#\:\$p > svg > foreignObject > section .badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:14px;font-weight:600}div#\:\$p > svg > foreignObject > section section.badge{--marpit-root-font-size: 14px}div#\:\$p > svg > foreignObject > section .today{background:#c6f6d5;color:#22543d}div#\:\$p > svg > foreignObject > section .planned{background:#fef3c7;color:#78350f}div#\:\$p > svg > foreignObject > section.title :is(h1, marp-h1){font-size:44px;margin-bottom:0.1em}div#\:\$p > svg > foreignObject > section.title :is(h3, marp-h3){color:#F0F0F0;font-weight:400;font-size:22px;margin-top:0}div#\:\$p > svg > foreignObject > section{font-size:20px}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 20px}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::after, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::after{display:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction="vertical"]{flex-direction:column}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split] > div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split, 50%)}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split="right"] > div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure > figcaption{position:absolute;border:0;clip:rect(0, 0, 0, 0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"], div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"]{background:transparent!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"], div#\:\$p > svg[data-marpit-svg] > foreignObject[data-marpit-advanced-background="pseudo"]{pointer-events:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background-split]{width:100%;height:100%} + */div#\:\$p > svg > foreignObject > section [data-theme=light],div#\:\$p > svg > foreignObject > section{color-scheme:light}div#\:\$p > svg > foreignObject > section [data-theme=dark],div#\:\$p > svg > foreignObject > section:where(.invert){color-scheme:dark}div#\:\$p > svg > foreignObject > section{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;margin:0;font-weight:var(--base-text-weight-normal, 400);color:var(--fgColor-default);background-color:var(--bgColor-default);font-family:var(--fontStack-sansSerif, -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji");font-size:16px;line-height:1.5;word-wrap:break-word}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:16px}div#\:\$p > svg > foreignObject > section a{text-decoration:underline;text-underline-offset:calc(var(--marpit-root-font-size, 1rem) * .2)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link:before{width:16px;height:16px;content:" ";display:inline-block;background-color:currentColor;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,');mask-image:url('data:image/svg+xml;charset=utf-8,')}div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section figcaption,div#\:\$p > svg > foreignObject > section figure{display:block}div#\:\$p > svg > foreignObject > section summary{display:list-item}div#\:\$p > svg > foreignObject > section [hidden]{display:none!important}div#\:\$p > svg > foreignObject > section a{background-color:transparent;color:var(--fgColor-accent);text-decoration:none}div#\:\$p > svg > foreignObject > section abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}div#\:\$p > svg > foreignObject > section b,div#\:\$p > svg > foreignObject > section strong{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section dfn{font-style:italic}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){margin:.67em 0;font-weight:var(--base-text-weight-semibold, 600);padding-bottom:.3em;font-size:2em;border-bottom:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section mark{background-color:var(--bgColor-attention-muted);color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section small{font-size:90%}div#\:\$p > svg > foreignObject > section sub,div#\:\$p > svg > foreignObject > section sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}div#\:\$p > svg > foreignObject > section sub{bottom:-.25em}div#\:\$p > svg > foreignObject > section sup{top:-.5em}div#\:\$p > svg > foreignObject > section img{border-style:none;max-width:100%;box-sizing:content-box}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section kbd,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp{font-family:monospace;font-size:1em}div#\:\$p > svg > foreignObject > section figure{margin:1em var(--base-size-40)}div#\:\$p > svg > foreignObject > section hr{box-sizing:content-box;overflow:hidden;background:transparent;height:.25em;padding:0;margin:var(--base-size-24) 0;background-color:var(--borderColor-default);border:0}div#\:\$p > svg > foreignObject > section input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}div#\:\$p > svg > foreignObject > section [type=button],div#\:\$p > svg > foreignObject > section [type=reset],div#\:\$p > svg > foreignObject > section [type=submit]{-webkit-appearance:button;-moz-appearance:button;appearance:button}div#\:\$p > svg > foreignObject > section [type=checkbox],div#\:\$p > svg > foreignObject > section [type=radio]{box-sizing:border-box;padding:0}div#\:\$p > svg > foreignObject > section [type=number]::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section [type=number]::-webkit-outer-spin-button{height:auto}div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-cancel-button,div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}div#\:\$p > svg > foreignObject > section ::-webkit-input-placeholder{color:inherit;opacity:.54}div#\:\$p > svg > foreignObject > section ::-webkit-file-upload-button{-webkit-appearance:button;appearance:button;font:inherit}div#\:\$p > svg > foreignObject > section a:hover{text-decoration:underline}div#\:\$p > svg > foreignObject > section ::-moz-placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section ::placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section hr:after,div#\:\$p > svg > foreignObject > section hr:before{display:table;content:""}div#\:\$p > svg > foreignObject > section hr:after{clear:both}div#\:\$p > svg > foreignObject > section table{border-spacing:0;border-collapse:collapse;display:block;width:-moz-max-content;width:max-content;max-width:100%;overflow:auto;font-variant:tabular-nums}div#\:\$p > svg > foreignObject > section td,div#\:\$p > svg > foreignObject > section th{padding:0}div#\:\$p > svg > foreignObject > section details summary{cursor:pointer}div#\:\$p > svg > foreignObject > section [role=button]:focus,div#\:\$p > svg > foreignObject > section a:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus{outline:2px solid var(--focus-outlineColor);outline-offset:-2px;box-shadow:none}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=radio]:focus:not(:focus-visible){outline:1px solid transparent}div#\:\$p > svg > foreignObject > section [role=button]:focus-visible,div#\:\$p > svg > foreignObject > section a:focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{outline:2px solid var(--focus-outlineColor);outline-offset:-2px;box-shadow:none}div#\:\$p > svg > foreignObject > section a:not([class]):focus,div#\:\$p > svg > foreignObject > section a:not([class]):focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{outline-offset:0}div#\:\$p > svg > foreignObject > section kbd{display:inline-block;padding:var(--base-size-4);font:11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);line-height:10px;color:var(--fgColor-default);vertical-align:middle;background-color:var(--bgColor-muted);border-bottom-color:var(--borderColor-neutral-muted);border:1px solid var(--borderColor-neutral-muted);border-radius:6px;box-shadow:inset 0 -1px 0 var(--borderColor-neutral-muted)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){margin-top:var(--base-size-24);margin-bottom:var(--base-size-16);font-weight:var(--base-text-weight-semibold, 600);line-height:1.25}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.25em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:.875em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-weight:var(--base-text-weight-semibold, 600);font-size:.85em;color:var(--fgColor-muted)}div#\:\$p > svg > foreignObject > section p{margin-top:0;margin-bottom:10px}div#\:\$p > svg > foreignObject > section blockquote{margin:0;padding:0 1em;color:var(--fgColor-muted);border-left:.25em solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section ul{margin-top:0;margin-bottom:0;padding-left:2em}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ul ol{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol ol ol,div#\:\$p > svg > foreignObject > section ol ul ol,div#\:\$p > svg > foreignObject > section ul ol ol,div#\:\$p > svg > foreignObject > section ul ul ol{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section dd{margin-left:0}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp,div#\:\$p > svg > foreignObject > section tt{font-family:var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);font-size:12px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){margin-top:0;margin-bottom:0;word-wrap:normal}div#\:\$p > svg > foreignObject > section .octicon{display:inline-block;overflow:visible!important;vertical-align:text-bottom;fill:currentColor}div#\:\$p > svg > foreignObject > section input::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section input::-webkit-outer-spin-button{margin:0;-webkit-appearance:none;appearance:none}div#\:\$p > svg > foreignObject > section .mr-2{margin-right:var(--base-size-8, 8px)!important}div#\:\$p > svg > foreignObject > section:after,div#\:\$p > svg > foreignObject > section:before{display:table}div#\:\$p > svg > foreignObject > section:after{clear:both}div#\:\$p > svg > foreignObject > section>:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section>:last-child{margin-bottom:0!important}div#\:\$p > svg > foreignObject > section a:not([href]){color:inherit;text-decoration:none}div#\:\$p > svg > foreignObject > section .absent{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section .anchor{float:left;padding-right:var(--base-size-4);margin-left:-20px;line-height:1}div#\:\$p > svg > foreignObject > section .anchor:focus{outline:none}div#\:\$p > svg > foreignObject > section blockquote,div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section dl,div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section p,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section table,div#\:\$p > svg > foreignObject > section ul{margin-top:0;margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section blockquote>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section blockquote>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) .octicon-link{color:var(--fgColor-default);vertical-align:middle;visibility:hidden}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor{text-decoration:none}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link{visibility:visible}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) code,div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) tt,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) code,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) tt,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) code,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) tt,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) code,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) tt,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) code,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) tt,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) code,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) tt{padding:0 .2em;font-size:inherit}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6){display:inline-block}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6) .anchor{margin-left:-40px}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2){padding-bottom:0;border-bottom:0}div#\:\$p > svg > foreignObject > section ol.no-list,div#\:\$p > svg > foreignObject > section ul.no-list{padding:0;list-style-type:none}div#\:\$p > svg > foreignObject > section ol[type="a s"]{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section ol[type="A s"]{list-style-type:upper-alpha}div#\:\$p > svg > foreignObject > section ol[type="i s"]{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol[type="I s"]{list-style-type:upper-roman}div#\:\$p > svg > foreignObject > section div>ol:not([type]),div#\:\$p > svg > foreignObject > section ol[type="1"]{list-style-type:decimal}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ol ul,div#\:\$p > svg > foreignObject > section ul ol,div#\:\$p > svg > foreignObject > section ul ul{margin-top:0;margin-bottom:0}div#\:\$p > svg > foreignObject > section li>p{margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section li+li{margin-top:.25em}div#\:\$p > svg > foreignObject > section dl{padding:0}div#\:\$p > svg > foreignObject > section dl dt{padding:0;margin-top:var(--base-size-16);font-size:1em;font-style:italic;font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section dl dd{padding:0 var(--base-size-16);margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section table th{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section table td,div#\:\$p > svg > foreignObject > section table th{padding:6px 13px;border:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section table td>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section table tr{background-color:var(--bgColor-default);border-top:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section table tr:nth-child(2n){background-color:var(--bgColor-muted)}div#\:\$p > svg > foreignObject > section table img{background-color:transparent}div#\:\$p > svg > foreignObject > section img[align=right]{padding-left:20px}div#\:\$p > svg > foreignObject > section img[align=left]{padding-right:20px}div#\:\$p > svg > foreignObject > section .emoji{max-width:none;vertical-align:text-top;background-color:transparent}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame,div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){display:block;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){float:left;width:auto;padding:7px;margin:13px 0 0;border:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) img{display:block;float:left}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) :is(span, marp-span){display:block;padding:5px 0 0;clear:both;color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center{display:block;overflow:hidden;clear:both}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center :is(span, marp-span) img{margin:0 auto;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right{display:block;overflow:hidden;clear:both}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right>:is(span, marp-span){display:block;margin:13px 0 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right :is(span, marp-span) img{margin:0;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left{display:block;float:left;margin-right:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left :is(span, marp-span){margin:13px 0 0}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right{display:block;float:right;margin-left:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section tt{padding:.2em .4em;margin:0;font-size:85%;white-space:break-spaces;background-color:var(--bgColor-neutral-muted);border-radius:6px}div#\:\$p > svg > foreignObject > section code br,div#\:\$p > svg > foreignObject > section tt br{display:none}div#\:\$p > svg > foreignObject > section del code{text-decoration:inherit}div#\:\$p > svg > foreignObject > section samp{font-size:85%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code{font-size:100%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)>code{padding:0;margin:0;word-break:normal;white-space:pre;background:transparent;border:0}div#\:\$p > svg > foreignObject > section .highlight{margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre){margin-bottom:0;word-break:normal}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){padding:var(--base-size-16);overflow:auto;font-size:85%;line-height:1.45;color:var(--fgColor-default);background-color:var(--bgColor-muted);border-radius:6px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) tt{display:inline;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}div#\:\$p > svg > foreignObject > section .csv-data td,div#\:\$p > svg > foreignObject > section .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}div#\:\$p > svg > foreignObject > section .csv-data .blob-num{padding:10px var(--base-size-8) 9px;text-align:right;background:var(--bgColor-default);border:0}div#\:\$p > svg > foreignObject > section .csv-data tr{border-top:0}div#\:\$p > svg > foreignObject > section .csv-data th{font-weight:var(--base-text-weight-semibold, 600);background:var(--bgColor-muted);border-top:0}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:before{content:"["}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:after{content:"]"}div#\:\$p > svg > foreignObject > section .footnotes{font-size:12px;color:var(--fgColor-muted);border-top:1px solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section div#\:\$p > svg > foreignObject > section section.footnotes{--marpit-root-font-size:12px}div#\:\$p > svg > foreignObject > section .footnotes ol,div#\:\$p > svg > foreignObject > section .footnotes ol ul{padding-left:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes ol ul{display:inline-block;margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes li{position:relative}div#\:\$p > svg > foreignObject > section .footnotes li:target:before{position:absolute;top:calc(var(--base-size-8)*-1);right:calc(var(--base-size-8)*-1);bottom:calc(var(--base-size-8)*-1);left:calc(var(--base-size-24)*-1);pointer-events:none;content:"";border:2px solid var(--borderColor-accent-emphasis);border-radius:6px}div#\:\$p > svg > foreignObject > section .footnotes li:target{color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section .footnotes .data-footnote-backref g-emoji{font-family:monospace}div#\:\$p > svg > foreignObject > section .pl-c{color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section .pl-c1,div#\:\$p > svg > foreignObject > section .pl-s .pl-v{color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section .pl-e,div#\:\$p > svg > foreignObject > section .pl-en{color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section .pl-s .pl-s1,div#\:\$p > svg > foreignObject > section .pl-smi{color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section .pl-ent{color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section .pl-k{color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section .pl-pds,div#\:\$p > svg > foreignObject > section .pl-s,div#\:\$p > svg > foreignObject > section .pl-s .pl-pse .pl-s1,div#\:\$p > svg > foreignObject > section .pl-sr,div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sra,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sre{color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section .pl-smw,div#\:\$p > svg > foreignObject > section .pl-v{color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section .pl-bu{color:var(--color-prettylights-syntax-brackethighlighter-unmatched)}div#\:\$p > svg > foreignObject > section .pl-ii{color:var(--color-prettylights-syntax-invalid-illegal-text);background-color:var(--color-prettylights-syntax-invalid-illegal-bg)}div#\:\$p > svg > foreignObject > section .pl-c2{color:var(--color-prettylights-syntax-carriage-return-text);background-color:var(--color-prettylights-syntax-carriage-return-bg)}div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce{font-weight:700;color:var(--color-prettylights-syntax-string-regexp)}div#\:\$p > svg > foreignObject > section .pl-ml{color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section .pl-mh,div#\:\$p > svg > foreignObject > section .pl-mh .pl-en,div#\:\$p > svg > foreignObject > section .pl-ms{font-weight:700;color:var(--color-prettylights-syntax-markup-heading)}div#\:\$p > svg > foreignObject > section .pl-mi{font-style:italic;color:var(--color-prettylights-syntax-markup-italic)}div#\:\$p > svg > foreignObject > section .pl-mb{font-weight:700;color:var(--color-prettylights-syntax-markup-bold)}div#\:\$p > svg > foreignObject > section .pl-md{color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}div#\:\$p > svg > foreignObject > section .pl-mi1{color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}div#\:\$p > svg > foreignObject > section .pl-mc{color:var(--color-prettylights-syntax-markup-changed-text);background-color:var(--color-prettylights-syntax-markup-changed-bg)}div#\:\$p > svg > foreignObject > section .pl-mi2{color:var(--color-prettylights-syntax-markup-ignored-text);background-color:var(--color-prettylights-syntax-markup-ignored-bg)}div#\:\$p > svg > foreignObject > section .pl-mdr{font-weight:700;color:var(--color-prettylights-syntax-meta-diff-range)}div#\:\$p > svg > foreignObject > section .pl-ba{color:var(--color-prettylights-syntax-brackethighlighter-angle)}div#\:\$p > svg > foreignObject > section .pl-sg{color:var(--color-prettylights-syntax-sublimelinter-gutter-mark)}div#\:\$p > svg > foreignObject > section .pl-corl{text-decoration:underline;color:var(--color-prettylights-syntax-constant-other-reference-link)}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section button:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section summary:focus:not(:focus-visible){outline:none;box-shadow:none}div#\:\$p > svg > foreignObject > section [tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section details-dialog:focus:not(:focus-visible){outline:none}div#\:\$p > svg > foreignObject > section g-emoji{display:inline-block;min-width:1ch;font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:1em;font-style:normal!important;font-weight:var(--base-text-weight-normal, 400);line-height:1;vertical-align:-.075em}div#\:\$p > svg > foreignObject > section g-emoji img{width:1em;height:1em}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote){display:block}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote):not(:has(.snippet-clipboard-content,>:is(pre, marp-pre))){width:-moz-fit-content;width:fit-content}div#\:\$p > svg > foreignObject > section a:has(>p,>div,>:is(pre, marp-pre),>blockquote):has(.snippet-clipboard-content,>:is(pre, marp-pre)):focus-visible{outline:2px solid var(--focus-outlineColor);outline-offset:2px}div#\:\$p > svg > foreignObject > section .task-list-item{list-style-type:none}div#\:\$p > svg > foreignObject > section .task-list-item label{font-weight:var(--base-text-weight-normal, 400)}div#\:\$p > svg > foreignObject > section .task-list-item.enabled label{cursor:pointer}div#\:\$p > svg > foreignObject > section .task-list-item+.task-list-item{margin-top:var(--base-size-4)}div#\:\$p > svg > foreignObject > section .task-list-item .handle{display:none}div#\:\$p > svg > foreignObject > section .task-list-item-checkbox{margin:0 .2em .25em -1.4em;vertical-align:middle}div#\:\$p > svg > foreignObject > section ul:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section ol:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section .contains-task-list:focus-within .task-list-item-convert-container,div#\:\$p > svg > foreignObject > section .contains-task-list:hover .task-list-item-convert-container{display:block;width:auto;height:24px;overflow:visible;clip-path:none}div#\:\$p > svg > foreignObject > section ::-webkit-calendar-picker-indicator{filter:invert(50%)}div#\:\$p > svg > foreignObject > section .markdown-alert{padding:var(--base-size-8) var(--base-size-16);margin-bottom:var(--base-size-16);color:inherit;border-left:.25em solid var(--borderColor-default)}div#\:\$p > svg > foreignObject > section .markdown-alert>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section .markdown-alert>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section .markdown-alert .markdown-alert-title{display:flex;font-weight:var(--base-text-weight-medium, 500);align-items:center;line-height:1}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note{border-left-color:var(--borderColor-accent-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note .markdown-alert-title{color:var(--fgColor-accent)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important{border-left-color:var(--borderColor-done-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important .markdown-alert-title{color:var(--fgColor-done)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning{border-left-color:var(--borderColor-attention-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning .markdown-alert-title{color:var(--fgColor-attention)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip{border-left-color:var(--borderColor-success-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip .markdown-alert-title{color:var(--fgColor-success)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution{border-left-color:var(--borderColor-danger-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution .markdown-alert-title{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section>:first-child>.heading-element:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre):has(+.zeroclipboard-container){min-height:52px}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){color:var(--h1-color);font-size:1.6em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){border-bottom:none}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){font-size:1.3em}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1.05em}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-size:.9em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) strong,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) strong,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) strong,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) strong,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) strong,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) strong{font-weight:inherit;color:var(--heading-strong-color)}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6)::part(auto-scaling){max-height:563px}div#\:\$p > svg > foreignObject > section hr{height:0;padding-top:.25em}div#\:\$p > svg > foreignObject > section img{background-color:transparent}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){border:1px solid var(--borderColor-default);line-height:1.15;overflow:visible}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)::part(auto-scaling){max-height:529px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-doctag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-tag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-variable),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-type),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable.language_){color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_.inherited__),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.function_){color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attribute),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-literal),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-number),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-operator),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-class),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-id),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable){color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-string),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-regexp),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-string){color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-built_in),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-symbol){color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-code),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-comment),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-formula){color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-name),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-quote),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-pseudo),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-tag){color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-subst){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-section){font-weight:700;color:var(--color-prettylights-syntax-markup-heading)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-bullet){color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-emphasis){font-style:italic;color:var(--color-prettylights-syntax-markup-italic)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-strong){font-weight:700;color:var(--color-prettylights-syntax-markup-bold)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-addition){color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-deletion){color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}div#\:\$p > svg > foreignObject > section footer,div#\:\$p > svg > foreignObject > section header{margin:0;position:absolute;left:30px;color:var(--header-footer-color);font-size:18px}div#\:\$p > svg > foreignObject > section header{top:21px}div#\:\$p > svg > foreignObject > section footer{bottom:21px}div#\:\$p > svg > foreignObject > section{--h1-color:light-dark(#246, #cee7ff);--header-footer-color:light-dark(hsla(0,0%,40%,.75), hsla(0,0%,60%,.75));--heading-strong-color:light-dark(#48c, #7bf);--paginate-color:light-dark(#777, #999);--base-size-4:4px;--base-size-8:8px;--base-size-16:16px;--base-size-24:24px;--base-size-40:40px;display:block;font-size:29px;height:720px;padding:78.5px;place-content:safe center center;width:1280px;flex-flow:column nowrap;align-items:stretch}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:29px}div#\:\$p > svg > foreignObject > section>:last-child,div#\:\$p > svg > foreignObject > section[data-footer]>:nth-last-child(2){margin-bottom:0}div#\:\$p > svg > foreignObject > section>:first-child,div#\:\$p > svg > foreignObject > section>header:first-child+*{margin-top:0}div#\:\$p > svg > foreignObject > section:after{position:absolute;padding:0;right:30px;bottom:21px;font-size:24px;color:var(--paginate-color)}div#\:\$p > svg > foreignObject > section:after{--marpit-root-font-size:24px}div#\:\$p > svg > foreignObject > section[data-color] :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section[data-color] :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section[data-color] :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section[data-color] :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section[data-color] :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section[data-color] :is(h6, marp-h6){color:currentcolor}div#\:\$p > svg > foreignObject > section{font-family:"Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;font-size:22px;color:#1B1B1B}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 22px}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){color:#D6002A;font-size:34px;margin-bottom:0.3em}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){color:#D6002A;font-size:26px;margin-bottom:0.2em}div#\:\$p > svg > foreignObject > section.title{background:#1B1B1B;color:#fff;border-top:8px solid #D6002A}div#\:\$p > svg > foreignObject > section.title :is(h1, marp-h1){color:#fff}div#\:\$p > svg > foreignObject > section table{font-size:18px;width:100%}div#\:\$p > svg > foreignObject > section th{background:#F0F0F0}div#\:\$p > svg > foreignObject > section blockquote{border-left:4px solid #D6002A;color:#2E2E2E;font-size:20px}div#\:\$p > svg > foreignObject > section img{display:block;margin:0 auto;max-height:320px}div#\:\$p > svg > foreignObject > section .badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:14px;font-weight:600}div#\:\$p > svg > foreignObject > section section.badge{--marpit-root-font-size: 14px}div#\:\$p > svg > foreignObject > section .testing{background:#DBEAFE;color:#1E3A5F}div#\:\$p > svg > foreignObject > section .planned{background:#fef3c7;color:#78350f}div#\:\$p > svg > foreignObject > section .agentic{background:#EDE9FE;color:#4C1D95}div#\:\$p > svg > foreignObject > section.title :is(h1, marp-h1){font-size:44px;margin-bottom:0.1em}div#\:\$p > svg > foreignObject > section.title :is(h3, marp-h3){color:#F0F0F0;font-weight:400;font-size:22px;margin-top:0}div#\:\$p > svg > foreignObject > section{font-size:16px}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 16px}div#\:\$p > svg > foreignObject > section td{font-size:15px;vertical-align:top}div#\:\$p > svg > foreignObject > section ul{margin:0;padding-left:1.2em}div#\:\$p > svg > foreignObject > section li{margin-bottom:2px}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::after, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::after{display:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction="vertical"]{flex-direction:column}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split] > div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split, 50%)}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split="right"] > div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure > figcaption{position:absolute;border:0;clip:rect(0, 0, 0, 0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"], div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"]{background:transparent!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"], div#\:\$p > svg[data-marpit-svg] > foreignObject[data-marpit-advanced-background="pseudo"]{pointer-events:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background-split]{width:100%;height:100%}
How The Platform Works
@@ -70,8 +72,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="2" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -89,18 +92,21 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works

The Problem We Solve

Software delivery scales with the coordination surface around it, not the engineering inside it.

-

Two frictions slow every team:

+

Four frictions slow every team:

  • Cognitive load — authoring the infrastructure that runs a service correctly. The long tail of services that are difficult to deploy, inconsistent in security and observability posture.
  • -
  • Operational work — moving a merged change from "merged" to "running in production with policy, observability, and security enforced." Manual work that scales with the system, not with the change.
  • +
  • Operational work — promoting a change from "merged" to "running in production with policy, observability, and security enforced." Manual work that scales with the system, not with the change.
  • +
  • Red tape — every deployment requires tickets, approvals, and manual handoffs that scale with the organization, not with the change. A merged change waits in a queue for someone to press a button.
  • +
  • Scalability without increasing headcount — the platform allows delivery throughput to scale without linearly scaling platform engineers. Today, every new team adds load to the same ticket queue.
-

The platform absorbs both frictions.

+

The platform absorbs all four frictions.

Internal
+.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works

The North Star

@@ -172,8 +180,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="4" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -191,18 +200,23 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

The Contract-Driven Model

-

One small YAML file is all a consumer writes. The platform owns everything else.

-

-

The contract names three things:

+

What This Platform Is — and Isn't

+

What it is:

    -
  • Which module — a catalog of pre-built, security-reviewed building blocks
  • -
  • Which environment — the platform raises the safety bar automatically as sensitivity rises
  • -
  • Which inputs — the handful of values that vary per deployment
  • +
  • A sovereign delivery boundary. The platform governs infrastructure and delivery. It does not penetrate upstream product or software development lifecycles. Integration happens through validated, published contracts.
  • +
  • Infrastructure consumed, not maintained. Compute is abstract, containerized, or serverless. The platform does not manage node, OS, or bare-metal lifecycles. Infrastructure is a utility, not a craft.
  • +
+

What it isn't:

+
    +
  • Not an upstream development platform. No product backlogs, sprint ceremonies, or IDE workflows.
  • +
  • Not a general-purpose AI. Autonomy is narrow, scoped to delivery and infrastructure reconciliation, bounded by strict policy envelopes.
  • +
  • Not a legacy infrastructure bridge. No VMs, bare metal, or OS lifecycles.
  • +
  • Not a permissive delivery highway. No escape hatches to bypass the confidence framework or human attestation requirements.
Internal
@@ -223,8 +237,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="5" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -242,16 +257,19 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

The End-to-End Flow

-

Every deployment runs the same stages, in the same order, with the same checks — no team-specific pipelines, no tribal runbooks.

-

+

The Contract-Driven Model

+

One small YAML file is all a consumer writes. The platform owns everything else.

+

+

The contract names three things:

    -
  • Security and policy checks run before any infrastructure is created
  • -
  • Every stage produces a record that feeds the confidence signal and the evidence stream — there is no "unchecked" path
  • +
  • Which module — a catalog of pre-built, security-reviewed building blocks
  • +
  • Which environment — the platform raises the safety bar automatically as sensitivity rises
  • +
  • Which inputs — the handful of values that vary per deployment
Internal
@@ -272,8 +290,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="6" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -291,22 +310,18 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Zero-Trust by Default

-

Consumer repositories hold no long-lived cloud credentials. Ever.

+

The End-to-End Flow

+

Every deployment runs the same stages, in the same order, with the same checks — no team-specific pipelines, no tribal runbooks.

+

    -
  • Authentication — OIDC federation. Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. Available today (GitHub Actions) Planned: all runners
  • -
  • Authorization — attribute-based (ABAC), not role-based. Two attribute classes scope every action: -
      -
    • Repository identity — the role's trust policy binds to the exact consumer repo + branch
    • -
    • Resource tags — every resource is tagged acdl:owner + acdl:contract; the session policy grants access only to matching tags
    • +
    • Security and policy checks run before any infrastructure is created
    • +
    • Every stage produces a record that feeds the confidence signal and the evidence stream — there is no "unchecked" path
    -
  • -
-

The effect: a consumer can only touch the resources it created. Blast radius is contained. One consumer can never affect another.

Internal
+.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16"> +
How The Platform Works
+

Zero-Trust by Default

+

Consumer repositories hold no long-lived cloud credentials. Ever.

+
    +
  • Authentication — OIDC federation. Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. Testing (GitHub Actions) Planned: all runners
  • +
  • Authorization — attribute-based (ABAC), not role-based. Two attribute classes scope every action: +
      +
    • Repository identity — the role's trust policy binds to the exact consumer repo + branch
    • +
    • Resource tags — every resource is tagged acdl:owner + acdl:contract; the session policy grants access only to matching tags
    • +
    +
  • +
+

The effect: a consumer can only touch the resources it created. Blast radius is contained. One consumer can never affect another.

+
Internal
+
+
How The Platform Works

Safety is Computed, Not Assumed

-

Every delivery action produces a measurable, explainable confidence signal — the platform's certified answer to "is this safe to proceed?"

+

Every delivery action produces a measurable, explainable confidence signal — the platform's certified answer to "is this safe to proceed?" Agentic

  • Six weighted inputs: policy conformance, validation, freshness, source provenance, history, NFRs
  • Per-environment thresholds that rise with sensitivity:
  • @@ -392,56 +465,6 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
How The Platform Works
-

Policy & Security Enforcement

-

Checks run on every deployment, normalized to a single schema regardless of which engine produced them.

-
    -
  • Infrastructure policy (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS references, required tagging standards (acdl:owner, acdl:contract, acdl:environment, acdl:cost-center) Available today
  • -
  • Cloud security posture (Wiz adapter) — translates cloud security findings into the same normalized record Adapter ready
  • -
  • Kubernetes-native policy (Kyverno adapter) — ready for the GitOps reconciler Adapter ready
  • -
-

Every check produces a record with severity, rule ID, pass/fail status, and a human-readable message — consumed uniformly by the confidence signal.

-
Internal
-
+.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Secure by Default

-

Security defaults that do not require a team to opt in. Available today

+

Policy & Security Enforcement

+

Checks run on every deployment, normalized to a single schema regardless of which engine produced them.

    -
  • Encryption on every resource — at-rest encryption on by default for every primitive (S3, RDS, ECR, ECS, and more)
  • -
  • Per-stack customer-managed keys — one key per deployment, 90-day rotation, no shared keys across stacks
  • -
  • Managed-key fallback with a loud warning — silent use of cloud-managed keys is a security gap we refuse to hide
  • -
  • Deletion protection on by defaultprevent_destroy on unless a consumer explicitly disables it via a documented flag
  • -
  • Safe decommission — a 2-step pipeline (disable protection → zero counts → destroy) with two SRE attestation gates and a change-request validated against the CMDB
  • +
  • Infrastructure policy (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS references, required tagging standards (acdl:owner, acdl:contract, acdl:environment, acdl:cost-center) Testing
  • +
  • Cloud security posture (Wiz adapter) — translates cloud security findings into the same normalized record Testing
  • +
  • Kubernetes-native policy (Kyverno adapter) — ready for the GitOps reconciler Testing
+

Every check produces a record with severity, rule ID, pass/fail status, and a human-readable message — consumed uniformly by the confidence signal.

Internal
+.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Immutable Audit & Evidence

-

Version control is a coordination tool, not an evidentiary fortress. True compliance requires an immutable, externally-stored ledger.

+

Secure by Default

+

Security defaults that do not require a team to opt in. Testing

    -
  • Every deployment writes a hash-chained evidence event — each event links to the previous via a cryptographic hash; tampering breaks the chain Available today
  • -
  • Tiered storage: cold, tamper-proof source of truth (S3 Object Lock, 7-year retention) + a hot query index Outbox shipped Full ledger: planned
  • -
  • RPO = 0 — the evidence write is synchronous; a deployment is not acknowledged until the evidence event is durably recorded
  • -
  • Every production change is traceable to a human attestation — approver identities are the only durable record outside the forge's audit log
  • +
  • Encryption on every resource — at-rest encryption on by default for every primitive (S3, RDS, ECR, ECS, and more)
  • +
  • Per-stack customer-managed keys — one key per deployment, 90-day rotation, no shared keys across stacks
  • +
  • Managed-key fallback with a loud warning — silent use of cloud-managed keys is a security gap we refuse to hide
  • +
  • Deletion protection on by defaultprevent_destroy on unless a consumer explicitly disables it via a documented flag
  • +
  • Safe decommission — a 2-step pipeline (disable protection → zero counts → destroy) with two SRE attestation gates and a change-request validated against the CMDB
Internal
@@ -560,8 +587,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="11" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -579,17 +607,18 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Human-in-the-Loop Where It Matters

-

Autonomy and accountability are not in tension — they apply at different environments.

+

Immutable Audit & Evidence

+

Version control is a coordination tool, not an evidentiary fortress. True compliance requires an immutable, externally-stored ledger.

    -
  • Dev is fully autonomous. The confidence signal (≥ 0.50) is the only gate. Queue-based handoffs are eliminated from lower environments.
  • -
  • qa, prod, and dr require deliberate human attestation — not rubber stamps, but policy-mandated acts of accountability via protected deployment approvals.
  • -
  • Separation of duties is enforced — the QA approver cannot be the prod approver. The platform reads both identities from the outbox and blocks on a match. Design shipped Wiring: planned
  • -
  • Timeout discipline — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit
  • +
  • Every deployment writes a hash-chained evidence event — each event links to the previous via a cryptographic hash; tampering breaks the chain Testing
  • +
  • Tiered storage: cold, tamper-proof source of truth (S3 Object Lock, 7-year retention) + a hot query index Outbox tested Full ledger: planned
  • +
  • RPO = 0 — the evidence write is synchronous; a deployment is not acknowledged until the evidence event is durably recorded
  • +
  • Every production change is traceable to a human attestation — approver identities are the only durable record outside the VCS's audit log
Internal
@@ -610,8 +639,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="12" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -629,18 +659,18 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Observability Built In

-

Monitoring is a platform default, not a per-team project. Available today

+

Human-in-the-Loop Where It Matters

+

Autonomy and accountability are not in tension — they apply at different environments.

    -
  • Uptime monitoring deployed automatically with every stack — a dedicated monitoring instance is provisioned after any module deploy, in a separate state, with a feature flag to disable
  • -
  • Monitored endpoints passed from the deployment's own outputs — no manual endpoint registration
  • -
  • Alert channels: Microsoft Teams webhook, email, SMS, and GitHub issues
  • -
  • The uptime URL is published to the developer via a PR comment — they don't hunt for it
  • -
  • Roadmap: deeper observability bootstrap (dashboards, runbooks, on-call bindings) as first-class contract fields
  • +
  • Dev is fully autonomous. The confidence signal (≥ 0.50) is the only gate. Queue-based handoffs are eliminated from lower environments. Agentic
  • +
  • qa, prod, and dr require deliberate human attestation — not rubber stamps, but policy-mandated acts of accountability via protected deployment approvals.
  • +
  • Separation of duties is enforced — the QA approver cannot be the prod approver. The platform reads both identities from the outbox and blocks on a match. Design tested Wiring: planned
  • +
  • Timeout discipline — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit
Internal
@@ -661,8 +691,9 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } +.agentic { background: #EDE9FE; color: #4C1D95; } " lang="C" data-marpit-pagination="13" style="--paginate:true;--header:How The Platform Works;--footer:Internal;--theme:default;--style:section { font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif; font-size: 22px; @@ -680,21 +711,20 @@ img { display: block; margin: 0 auto; max-height: 320px; } display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 14px; font-weight: 600; } -.today { background: #c6f6d5; color: #22543d; } +.testing { background: #DBEAFE; color: #1E3A5F; } .planned { background: #fef3c7; color: #78350f; } -;" data-marpit-pagination-total="15"> +.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Platform-Managed Environments

-

A consumer provides no AWS account, no VPC, no subnet, no state backend, no runner key. The platform owns the blast radius.

-

A named environment is a platform-owned bundle of:

+

Observability Built In

+

Monitoring is a platform default, not a per-team project. Testing

    -
  • An AWS account (or a scoped partition of one)
  • -
  • A network (VPC + subnets)
  • -
  • A state backend (S3 + DynamoDB for state + locking)
  • -
  • An IAM role surfaced via ABAC, scoped to the consumer's identity and resource tags
  • +
  • Uptime monitoring deployed automatically with every stack — a dedicated monitoring instance is provisioned after any module deploy, in a separate state, with a feature flag to disable
  • +
  • Monitored endpoints passed from the deployment's own outputs — no manual endpoint registration
  • +
  • Alert channels: Microsoft Teams webhook, email, SMS, and GitHub issues
  • +
  • The uptime URL is published to the developer via a PR comment — they don't hunt for it
  • +
  • Roadmap: deeper observability bootstrap (dashboards, runbooks, on-call bindings) as first-class contract fields
-

The consumer selects an environment by name in their contract. The platform resolves the name to the underlying resources at run time. The consumer never sees raw credentials.

-

Friendly onboarding: the first run detects no environment and emits a guided prompt (not an opaque failure). Available today Self-service: planned

Internal
+.agentic { background: #EDE9FE; color: #4C1D95; } +;" data-marpit-pagination-total="16">
How The Platform Works
-

Portability & Future-Proofing

-

The platform is opinionated, but not painted into a corner.

+

Platform-Managed Environments

+

A consumer provides no AWS account, no VPC, no subnet, no state backend, no runner key. The platform owns the blast radius.

+

A named environment is a platform-owned bundle of:

    -
  • Substrate-agnostic core. The contract, the resolved stack, the policy results, the confidence signal, and the evidence stream are all defined without reference to any specific infrastructure tool. 1 adapter: Terraform OpenTofu / Pulumi / K8s
  • -
  • Forge-agnostic contract ingestion. The platform Lambda reads a configurable API base for GitHub or Gitea. Available today
  • -
  • Portable contracts. A second forge needs a forge adapter + a workflow translator — no change to modules, contracts, confidence, or audit
  • -
  • Pattern recognition compounds value over time. As the platform observes recurring patterns, it can synthesize reusable modules. Future capability
  • +
  • An AWS account (or a scoped partition of one)
  • +
  • A network (VPC + subnets)
  • +
  • A state backend (S3 + DynamoDB for state + locking)
  • +
  • An IAM role surfaced via ABAC, scoped to the consumer's identity and resource tags
+

The consumer selects an environment by name in their contract. The platform resolves the name to the underlying resources at run time. The consumer never sees raw credentials.

+

Friendly onboarding: the first run detects no environment and emits a guided prompt (not an opaque failure). Testing Self-service: planned

Internal
-
+
How The Platform Works
+

Portability & Future-Proofing

+

The platform is opinionated, but not painted into a corner.

+
    +
  • Engine-agnostic core. The contract, the resolved stack, the policy results, the confidence signal, and the evidence stream are all defined without reference to any specific infrastructure tool. 1 adapter: Terraform OpenTofu / Pulumi / K8s
  • +
  • VCS-agnostic contract ingestion. The platform Lambda reads a configurable API base for GitHub or Gitea. Testing
  • +
  • Portable contracts. A second VCS needs a VCS adapter + a workflow translator — no change to modules, contracts, confidence, or audit
  • +
  • Pattern recognition compounds value over time. As the platform observes recurring patterns, it can synthesize reusable modules. Future capability Agentic
  • +
+
Internal
+
+
How The Platform Works
-

Roadmap: Shipped vs. Planned

- -

Available today

+

Testing vs. Planned

+ + + + + +
+

Testing (works internally, not yet released to consumers)

  • Contract-driven deploys with a versioned reusable workflow
  • Module catalog (primitives + modules) with validated examples
  • Zero-trust OIDC + ABAC on GitHub Actions runners
  • Security + policy checks before infra creation (Checkov; Wiz + Kyverno ready)
  • -
  • Confidence signal (6 inputs, per-env thresholds) gating promotion
  • +
  • Confidence signal (6 inputs, per-env thresholds) gating promotion Agentic
  • Hash-chained, tamper-evident evidence outbox (RPO = 0)
  • Encryption by default + per-stack customer-managed keys
  • Deletion protection by default + safe decommission with SRE gates
  • Uptime monitoring deployed automatically with every stack
  • Platform-managed environments + friendly onboarding
  • -
  • Local reproducibility + forge-agnostic contract ingestion
  • +
  • Local reproducibility + VCS-agnostic contract ingestion
-

Planned (on the roadmap)

+
+

Planned (on the roadmap)

  • Real OIDC federation on all platform runners
  • HITL wiring for qa / prod / dr environments
  • Full regulatory ledger: S3 Object Lock + JWS signatures + daily checkpoints
  • Compliance milestone: GDPR, SOX, SOC2, DORA extension points
  • Environment self-service provisioning
  • -
  • Dynamic module creation from a contract (agentic citizen-developer flow)
  • -
  • Additional substrate adapters (OpenTofu, Pulumi, Kubernetes CRDs)
  • +
  • Dynamic module creation from a contract (agentic citizen-developer flow) Agentic
  • +
  • Additional engine adapters (OpenTofu, Pulumi, Kubernetes CRDs)
-
Internal
+
Internal