diff --git a/README.md b/README.md index 83b0bae..c1baf6f 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Planned future features (no dates; tracked in the internal roadmap): consumer creates a module directly from the contract file (the "composition" mechanism, redesigned). - **Compliance milestone** — per-module compliance extension points (GDPR, - SOX, SOC2, HIPAA, DORA) wired into the pipeline. + SOX, SOC2, DORA) wired into the pipeline. - **Additional substrate 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 diff --git a/docs/consumer-guide.md b/docs/consumer-guide.md index 1967a66..80d6508 100644 --- a/docs/consumer-guide.md +++ b/docs/consumer-guide.md @@ -292,7 +292,7 @@ for the full table. ## Step 9 — Compliance extensions Each module lists compliance extension points for the future compliance -milestone (GDPR, SOX, SOC2, HIPAA, DORA). See each module's README under +milestone (GDPR, SOX, SOC2, DORA). See each module's README under `modules/l1//README.md` or `modules/l2//README.md` for the per-module extension points. Common examples: diff --git a/docs/index.md b/docs/index.md index f0594ed..405fc19 100644 --- a/docs/index.md +++ b/docs/index.md @@ -63,7 +63,7 @@ Planned future features (no dates; tracked in the internal roadmap): consumer creates a module directly from the contract file (the "composition" mechanism, redesigned). - **Compliance milestone** — per-module compliance extension points (GDPR, - SOX, SOC2, HIPAA, DORA) wired into the pipeline. + SOX, SOC2, DORA) wired into the pipeline. - **Additional substrate adapters** — beyond the Terraform adapter. - **Environment self-service** — a consumer-facing flow to request and provision a new platform-managed environment. diff --git a/docs/presentations/how-the-platform-works-marp.md b/docs/presentations/how-the-platform-works-marp.md index ccea780..5f84efb 100644 --- a/docs/presentations/how-the-platform-works-marp.md +++ b/docs/presentations/how-the-platform-works-marp.md @@ -3,7 +3,7 @@ marp: true theme: default paginate: true size: 16x9 -header: "Agentic Cloud Delivery Platform — How The Platform Works" +header: "How The Platform Works" footer: "Internal" style: | section { @@ -30,10 +30,13 @@ style: | -# Agentic Cloud Delivery Platform — How The Platform Works +# How The Platform Works + +### Agentic Cloud Delivery Platform --- @@ -234,7 +237,7 @@ section { font-size: 20px; } - 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, HIPAA, DORA extension points +- 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 diff --git a/docs/presentations/how-the-platform-works.html b/docs/presentations/how-the-platform-works.html index 81b0951..5982e2d 100644 --- a/docs/presentations/how-the-platform-works.html +++ b/docs/presentations/how-the-platform-works.html @@ -1,4 +1,4 @@ -Agentic Cloud Delivery Platform — How The Platform Works
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%} +
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works
-

Agentic Cloud Delivery Platform — How The Platform Works

+

How The Platform Works

+

Agentic Cloud Delivery Platform

Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
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:

@@ -102,7 +103,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }

The platform absorbs both frictions.

Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

The North Star

Consumers declare intent; the platform delivers safe production deployment — automatically, safely, and with a complete audit trail.

@@ -154,7 +155,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

The Contract-Driven Model

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

@@ -205,7 +206,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
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.

@@ -254,7 +255,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Zero-Trust by Default

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

    @@ -308,7 +309,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }

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

    Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
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?"

    @@ -391,7 +392,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Policy & Security Enforcement

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

    @@ -441,7 +442,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }

    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 Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Secure by Default

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

    @@ -492,7 +493,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
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.

    @@ -542,7 +543,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Human-in-the-Loop Where It Matters

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

    @@ -592,7 +593,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Observability Built In

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

    @@ -643,7 +644,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
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:

@@ -696,7 +697,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }

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

Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Portability & Future-Proofing

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

    @@ -746,7 +747,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
Internal
-
-
Agentic Cloud Delivery Platform — How The Platform Works
+
How The Platform Works

Roadmap: Shipped vs. Planned

@@ -808,7 +809,7 @@ img { display: block; margin: 0 auto; max-height: 320px; }
  • 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, HIPAA, DORA extension points
  • +
  • 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)
  • diff --git a/docs/presentations/how-the-platform-works.md b/docs/presentations/how-the-platform-works.md index 3f2bf90..c774973 100644 --- a/docs/presentations/how-the-platform-works.md +++ b/docs/presentations/how-the-platform-works.md @@ -1,5 +1,6 @@ -# How the Platform Works +# How The Platform Works +> **Subtitle:** Agentic Cloud Delivery Platform > **Audience:** Senior Leadership, CTO, Head of Cloud, Head of Infrastructure, Head of DevOps > **Length:** ~15 minutes · 14 slides > **Purpose:** Sell the platform's value to tech leadership — zero-trust, security, observability, auditability, and the shift from "operators guess" to "the platform computes safety." @@ -239,7 +240,7 @@ The platform is **opinionated, but not painted into a corner.** - Real OIDC federation on all platform runners (Gitea Actions OIDC pending an upstream merge). - HITL wiring for qa / prod / dr environments (design shipped; wiring is next). - Full regulatory ledger: S3 Object Lock (7-yr compliance mode) + JWS detached signatures + daily checkpoints. -- Compliance milestone: per-module extension points for GDPR, SOX, SOC2, HIPAA, DORA. +- Compliance milestone: per-module extension points for GDPR, SOX, SOC2, DORA. - Environment self-service (a consumer-facing flow to request and provision a new environment). - Dynamic module creation from a contract (the agentic "citizen developer" composition mechanism). - Additional substrate adapters (OpenTofu, Pulumi, Kubernetes CRDs). diff --git a/docs/presentations/the-developer-experience-marp.md b/docs/presentations/the-developer-experience-marp.md index 5b63650..34ecbab 100644 --- a/docs/presentations/the-developer-experience-marp.md +++ b/docs/presentations/the-developer-experience-marp.md @@ -3,7 +3,7 @@ marp: true theme: default paginate: true size: 16x9 -header: "Agentic Cloud Delivery Platform — The Developer Experience" +header: "The Developer Experience" footer: "Internal" style: | section { @@ -32,10 +32,13 @@ style: | -# Agentic Cloud Delivery Platform — The Developer Experience +# The Developer Experience + +### Agentic Cloud Delivery Platform --- @@ -47,7 +50,7 @@ The platform serves **two kinds of consumer** through two coordinated interfaces ![w:1000](assets/png/developer-experience-01-two-surfaces.png) - **Technical developer** — owns app code + a contract + a thin CI definition -- **Citizen developer** — declares intent in plain language; an agent produces a contract that passes the **same** safety envelope +- **Citizen developer** — declares intent in plain language; an AI agent produces a contract that passes the **same** safety envelope The platform is **opinionated in what it accepts, regardless of who is declaring.** There is no "citizen developer mode" with weaker checks. @@ -57,7 +60,7 @@ The platform is **opinionated in what it accepts, regardless of who is declaring Three things. That is the entire consumer-side surface. -![w:900](assets/png/developer-experience-02-what-dev-does.png) + The developer does **not**: @@ -74,7 +77,7 @@ The developer does **not**: A non-technical consumer ships a production deployment **by declaring intent** — without authoring a workflow, a configuration file, or an infrastructure module. - The consumer opens an issue describing what they need (e.g. "a web API for the pricing service") -- An agent maps the intent to a contract referencing a module from the **reviewed skill catalog** +- An AI agent maps the intent to a contract referencing a module from the **reviewed skill catalog** - The contract enters the **same pipeline** and must clear the **same confidence gate** before promotion **Guardrails that make this safe:** @@ -162,17 +165,6 @@ After a successful deploy, the developer gets their connection information **wit --- -# Local Reproducibility - -The entire CI pipeline runs **from the shell**, not just in CI. Available today - -- `scripts/run_ci.sh` mirrors the CI pipeline locally — the same three stages (lint → test → check-only) in sequence -- `scripts/run_platform.sh --check-only` runs the platform **offline** — no AWS, no policy engine, no outbox required. Validates a contract end-to-end before pushing -- `--plan-only` runs through the infrastructure plan without applying -- The CI and deploy pipelines are defined by **declarative contracts** (YAML instances validated against JSON Schemas) — a single source of truth that both workflows implement. A test asserts conformance - ---- - # Friendly Onboarding First impressions of a platform are made **when it fails for the first time.** The platform fails gracefully. Available today @@ -196,7 +188,11 @@ Both onboarding paths end in a **sandbox dev submission that must pass the confi The contract is environment-agnostic by design. Promotion is **a workflow choice, not a contract edit** — the platform raises the bar automatically. -**Approach A — One contract, one job per environment.** A single contract is referenced by multiple jobs; the environment is passed by each job and interpolated at runtime. The contract never changes. + + + + + +
    + +**Approach A — One contract, one job per environment.** The environment is passed by each job and interpolated at runtime. The contract never changes. ```yaml jobs: @@ -209,7 +205,10 @@ jobs: with: { contract: .acdl/contract.yaml, environment: qa } ``` -**Approach B — One job per environment, environment-specific contracts.** When inputs genuinely differ per environment, each job points at its own contract file. + + +**Approach B — Environment-specific contracts.** When inputs genuinely differ per environment, each job points at its own contract file. ```yaml jobs: @@ -222,10 +221,15 @@ jobs: with: { contract: .acdl/contract-qa.yaml } ``` +
    + --- @@ -280,7 +284,7 @@ Developers pick from **pre-built, security-reviewed building blocks** — they d - **Modules** — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + load balancer + registry) - **Validated examples per module** — `simple.yaml` + `complex.yaml` + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently - **Auto-promotion of patterns** — a thin-composition layer is auto-promoted to the catalog after 3 observed usages Planned -- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, HIPAA, DORA controls will wire in Planned +- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, DORA controls will wire in Planned --- diff --git a/docs/presentations/the-developer-experience.html b/docs/presentations/the-developer-experience.html index ae687ca..d4b79f5 100644 --- a/docs/presentations/the-developer-experience.html +++ b/docs/presentations/the-developer-experience.html @@ -1,4 +1,4 @@ -Agentic Cloud Delivery Platform — The Developer Experience
    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 :is(pre, marp-pre){font-size:16px;line-height:1.3}div#\:\$p > svg > foreignObject > section code{font-size:16px}div#\:\$p > svg > foreignObject > section img{display:block;margin:0 auto;max-height:300px}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:18px}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 18px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){font-size:11px;line-height:1.2}div#\:\$p > svg > foreignObject > section code{font-size:11px}div#\:\$p > svg > foreignObject > section td{font-size:16px}div#\:\$p > svg > foreignObject > section{font-size:22px}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size: 22px}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%} +
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +
    The Developer Experience
    -

    Agentic Cloud Delivery Platform — The Developer Experience

    +

    The Developer Experience

    +

    Agentic Cloud Delivery Platform

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Two Consumer Surfaces, One Platform

    The platform serves two kinds of consumer through two coordinated interfaces — both converge on the same contract, the same policy envelope, and the same evidence stream.

    • Technical developer — owns app code + a contract + a thin CI definition
    • -
    • Citizen developer — declares intent in plain language; an agent produces a contract that passes the same safety envelope
    • +
    • Citizen developer — declares intent in plain language; an AI agent produces a contract that passes the same safety envelope

    The platform is opinionated in what it accepts, regardless of who is declaring. There is no "citizen developer mode" with weaker checks.

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    What a Developer Actually Does

    Three things. That is the entire consumer-side surface.

    -

    +

    The developer does not:

    • Write infrastructure modules
    • @@ -167,7 +168,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    The Citizen Developer Experience

    A non-technical consumer ships a production deployment by declaring intent — without authoring a workflow, a configuration file, or an infrastructure module.

    • The consumer opens an issue describing what they need (e.g. "a web API for the pricing service")
    • -
    • An agent maps the intent to a contract referencing a module from the reviewed skill catalog
    • +
    • An AI agent maps the intent to a contract referencing a module from the reviewed skill catalog
    • The contract enters the same pipeline and must clear the same confidence gate before promotion

    Guardrails that make this safe:

    @@ -227,7 +228,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }

    Skill catalog + real agent runtime: planned

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    The Contract

    A 5-line YAML file. This is the entire consumer-facing interface to production.

    # .acdl/contract.yaml — a static site
    @@ -292,7 +293,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
     

    An invalid contract fails fast at validation with a clear error — not an opaque failure three stages in.

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    No Platform Code, No Cloning

    Consumers uses: a versioned central workflow. The platform fetches itself at run time. The consumer never touches platform internals.

    @@ -347,7 +348,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Versioned, Predictable Releases

    Consumers control when they absorb platform improvements.

      @@ -402,7 +403,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Instant Feedback

    Developers see what the platform is doing, in real time, in their own run logs. Available today

      @@ -456,7 +457,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Deploy Outputs That Just Work

    After a successful deploy, the developer gets their connection information without hunting for it — and without secrets leaking into logs. Available today

      @@ -510,7 +511,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    -

    Local Reproducibility

    -

    The entire CI pipeline runs from the shell, not just in CI. Available today

    -
      -
    • scripts/run_ci.sh mirrors the CI pipeline locally — the same three stages (lint → test → check-only) in sequence
    • -
    • scripts/run_platform.sh --check-only runs the platform offline — no AWS, no policy engine, no outbox required. Validates a contract end-to-end before pushing
    • -
    • --plan-only runs through the infrastructure plan without applying
    • -
    • The CI and deploy pipelines are defined by declarative contracts (YAML instances validated against JSON Schemas) — a single source of truth that both workflows implement. A test asserts conformance
    • -
    -
    Internal
    -
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Friendly Onboarding

    First impressions of a platform are made when it fails for the first time. The platform fails gracefully. Available today

    When no environment is bound, the platform emits a user-friendly onboarding prompt instead of failing opaquely:

    @@ -622,7 +569,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }

    Citizen developer onboarding path: planned

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Safe Promotion Path

    The contract is environment-agnostic by design. Promotion is a workflow choice, not a contract edit — the platform raises the bar automatically.

    -

    Approach A — One contract, one job per environment. A single contract is referenced by multiple jobs; the environment is passed by each job and interpolated at runtime. The contract never changes.

    + + + + + +
    +

    Approach A — One contract, one job per environment. The environment is passed by each job and interpolated at runtime. The contract never changes.

    jobs:
       dev:
         uses: acdl/.github/workflows/deploy.yml@v1.6
    @@ -678,7 +628,9 @@ img { display: block; margin: 0 auto; max-height: 300px; }
         uses: acdl/.github/workflows/deploy.yml@v1.6
         with: { contract: .acdl/contract.yaml, environment: qa }
     
    -

    Approach B — One job per environment, environment-specific contracts. When inputs genuinely differ per environment, each job points at its own contract file.

    +
    +

    Approach B — Environment-specific contracts. When inputs genuinely differ per environment, each job points at its own contract file.

    jobs:
       dev:
         uses: acdl/.github/workflows/deploy.yml@v1.6
    @@ -688,9 +640,12 @@ img { display: block; margin: 0 auto; max-height: 300px; }
         uses: acdl/.github/workflows/deploy.yml@v1.6
         with: { contract: .acdl/contract-qa.yaml }
     
    +
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Safe Promotion Path — The Rising Bar

    Whichever approach a team picks, the platform applies the same rising bar:

    @@ -770,7 +725,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }

    The DX win: the contract stays stable across environments. The safety win: the platform raises the threshold and attestation bar automatically based on the job's declared environment.

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Safe Decommission

    Tearing down a stack is as deliberate as deploying one — and just as gated. Available today

    uses: acdl/.github/workflows/deploy.yml@v1.8
    @@ -832,7 +787,7 @@ img { display: block; margin: 0 auto; max-height: 300px; }
     

    The per-stack encryption key enters a grace window (default 30 days) so encrypted data remains recoverable.

    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +;" data-marpit-pagination-total="15"> +
    The Developer Experience

    Self-Service Module Catalog

    Developers pick from pre-built, security-reviewed building blocks — they don't author infrastructure from scratch. Available today

      @@ -883,11 +838,11 @@ img { display: block; margin: 0 auto; max-height: 300px; }
    • Modules — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + load balancer + registry)
    • Validated examples per modulesimple.yaml + complex.yaml + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently
    • Auto-promotion of patterns — a thin-composition layer is auto-promoted to the catalog after 3 observed usages Planned
    • -
    • Compliance extension points — each module lists where GDPR, SOX, SOC2, HIPAA, DORA controls will wire in Planned
    • +
    • Compliance extension points — each module lists where GDPR, SOX, SOC2, DORA controls will wire in Planned
    Internal
    -
    -
    Agentic Cloud Delivery Platform — The Developer Experience
    +
    The Developer Experience

    The Desired Outcomes

    diff --git a/docs/presentations/the-developer-experience.md b/docs/presentations/the-developer-experience.md index 605ed02..32c43cd 100644 --- a/docs/presentations/the-developer-experience.md +++ b/docs/presentations/the-developer-experience.md @@ -1,7 +1,8 @@ # The Developer Experience +> **Subtitle:** Agentic Cloud Delivery Platform > **Audience:** Senior Leadership, CTO, Head of Cloud, Head of Infrastructure, Head of DevOps -> **Length:** ~15 minutes · 14 slides +> **Length:** ~15 minutes · 13 slides > **Purpose:** Sell the developer experience and the citizen developer experience to tech leadership — velocity without sacrificing safety, and security/observability/compliance as platform defaults rather than per-team effort. > **Maturity framing:** "Available today" = shipped and verified. "Planned" = on the roadmap, not yet shipped. @@ -22,7 +23,7 @@ flowchart TD ``` - **Technical developer** — owns app code + a contract + a thin CI definition. Uses the full module catalog and inputs. -- **Citizen developer** — declares intent in plain language; an agent produces a contract that passes the **same** safety envelope as a senior engineer's. +- **Citizen developer** — declares intent in plain language; an AI agent produces a contract that passes the **same** safety envelope as a senior engineer's. The platform is **opinionated in what it accepts, regardless of who is declaring.** There is no "citizen developer mode" with weaker checks. @@ -59,7 +60,7 @@ The developer does **not**: A non-technical consumer ships a production deployment **by declaring intent** — without authoring a workflow, a configuration file, or an infrastructure module. - The consumer opens an issue describing what they need (e.g. "a web API for the pricing service"). -- An agent maps the intent to a contract referencing a module from the **reviewed skill catalog.** +- An AI agent maps the intent to a contract referencing a module from the **reviewed skill catalog.** - The contract enters the **same pipeline** and must clear the **same confidence gate** before promotion. **Guardrails that make this safe:** @@ -176,20 +177,7 @@ After a successful deploy, the developer gets their connection information **wit --- -## Slide 9 — Local Reproducibility - -The entire CI pipeline runs **from the shell**, not just in CI. - -- `scripts/run_ci.sh` mirrors the CI pipeline locally — the same three stages (lint → test → check-only) in sequence. Exits 0 with "CI PIPELINE OK." *(Available today.)* -- `scripts/run_platform.sh --check-only` runs the platform offline — **no AWS, no policy engine, no outbox required.** Validates a contract end-to-end before pushing. *(Available today.)* -- `--plan-only` runs through the infrastructure plan without applying. -- The CI and deploy pipelines are defined by **declarative contracts** (YAML instances validated against JSON Schemas) — a single source of truth that both the GitHub and Gitea workflows implement. A test asserts conformance. - -> **Speaker notes:** This is the "no 'works on my machine' for CI" slide. A developer can reproduce the exact CI behavior locally before pushing. For the Head of Engineering: this shrinks the PR-cycle time because failures are caught pre-push, and it makes the pipeline itself a reviewable artifact (the YAML contract), not tribal workflow code. - ---- - -## Slide 10 — Friendly Onboarding +## Slide 9 — Friendly Onboarding First impressions of a platform are made **when it fails for the first time.** The platform fails gracefully. @@ -308,7 +296,7 @@ Developers pick from **pre-built, security-reviewed building blocks** — they d - **Modules** — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + load balancer + registry). *(Available today.)* - **Validated examples per module** — every module ships `simple.yaml` + `complex.yaml` + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently. *(Available today.)* - **Auto-promotion of patterns** — a thin-composition layer is auto-promoted to the catalog after 3 observed usages. *(Mechanism planned.)* -- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, HIPAA, DORA controls will wire in. *(Compliance milestone is planned.)* +- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, DORA controls will wire in. *(Compliance milestone is planned.)* > **Speaker notes:** The catalog is what makes "declare intent" practical — you can only declare a module that exists. For leadership: the catalog is the leverage. One well-reviewed module serves every consumer; a fix to the module serves every consumer on the next run. This is the compounding asset. diff --git a/modules/README-TEMPLATE.md b/modules/README-TEMPLATE.md index 7df1372..76c540a 100644 --- a/modules/README-TEMPLATE.md +++ b/modules/README-TEMPLATE.md @@ -50,7 +50,7 @@ L1 primitive MUST declare `deletion_protection` and `encryption_enabled` ## Compliance extension points Resources this module could be extended with for the future compliance -milestone (GDPR, SOX, SOC2, HIPAA, DORA). Not implemented yet — listed +milestone (GDPR, SOX, SOC2, DORA). Not implemented yet — listed so the redesign can plan for them. - **<area>** — <what could be added, e.g. KMS key for encryption> diff --git a/modules/STANDARDS.md b/modules/STANDARDS.md index e4a3c93..7c3cc3a 100644 --- a/modules/STANDARDS.md +++ b/modules/STANDARDS.md @@ -431,7 +431,7 @@ Every module README MUST follow the structure of 7. `## Usage` — a concrete snippet showing how a consumer references the module in a contract. 8. `## Compliance extension points` — resources or behaviors that could - be added for the future compliance milestone (GDPR, SOX, SOC2, HIPAA, + be added for the future compliance milestone (GDPR, SOX, SOC2, DORA). Not implemented yet; listed so the redesign can plan for them. 9. `## Examples` — links to `examples/simple.yaml` and `examples/complex.yaml` with a one-line description of each. diff --git a/modules/l1/alb/README.md b/modules/l1/alb/README.md index d7677fd..1d7e755 100644 --- a/modules/l1/alb/README.md +++ b/modules/l1/alb/README.md @@ -57,7 +57,7 @@ The `target_group_arn` output is referenced by `ecs-service` as its ## Compliance extension points -- **TLS / HTTPS listener** — add `aws_acm_certificate` + `ssl_policy` + `certificate_arn` for encryption in transit (SOC2 CC6.1, PCI-DSS 4.1, HIPAA §164.312(e)(1), GDPR Art.32). +- **TLS / HTTPS listener** — add `aws_acm_certificate` + `ssl_policy` + `certificate_arn` for encryption in transit (SOC2 CC6.1, PCI-DSS 4.1, GDPR Art.32). - **Access logs** — add `access_logs { bucket = ..., prefix = ... }` to the load balancer (SOX, SOC2 CC7.2, DORA ICT audit trail). - **Security group rules** — add ingress/egress rules restricting traffic to known sources (SOC2 CC6.6, PCI-DSS 1.2). - **Health check** — add a `health_check` block to the target group (SOC2 CC7.3 monitoring, DORA operational resilience). diff --git a/modules/l1/cloudfront/README.md b/modules/l1/cloudfront/README.md index 5991654..bffe040 100644 --- a/modules/l1/cloudfront/README.md +++ b/modules/l1/cloudfront/README.md @@ -69,7 +69,7 @@ inside a module composition (see `modules/l2/static-assets`). - **Logging** — CloudFront access logs to an S3 bucket for auditability (SOC2 CC7.2, DORA audit trail). - **Field-level encryption** — add field-level encryption for PII fields - in POST bodies (HIPAA §164.312(a)(2)(iv), GDPR Art.32). + in POST bodies (GDPR Art.32). ## Examples diff --git a/modules/l1/ecr/README.md b/modules/l1/ecr/README.md index 64dd4b2..52c810d 100644 --- a/modules/l1/ecr/README.md +++ b/modules/l1/ecr/README.md @@ -45,11 +45,11 @@ The `repository_url` output is used to build the `image` input for ## Compliance extension points -- **Image scanning** — add `image_scanning_configuration { scan_on_push = true }` for vulnerability scanning (SOC2 CC7.6, DORA ICT risk testing, HIPAA security monitoring). -- **Encryption** — add `encryption_configuration { encryption_type = "KMS", kms_key = ... }` with a customer-managed key (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32). +- **Image scanning** — add `image_scanning_configuration { scan_on_push = true }` for vulnerability scanning (SOC2 CC7.6, DORA ICT risk testing, security monitoring). +- **Encryption** — add `encryption_configuration { encryption_type = "KMS", kms_key = ... }` with a customer-managed key (SOC2 CC6.1, GDPR Art.32). - **Image tag immutability** — add `image_tag_mutability = "IMMUTABLE"` to prevent tag overwriting (SOX §802, SOC2 CC6.1 integrity, DORA audit integrity). - **Lifecycle policy** — add `aws_ecr_lifecycle_policy` to enforce image retention / cleanup (GDPR Art.5(2) data minimization, SOC2 CC5.2). -- **Access policy** — add a repository policy restricting pull/push to known roles (SOC2 CC6.1, HIPAA §164.308(a)(4)). +- **Access policy** — add a repository policy restricting pull/push to known roles (SOC2 CC6.1. ## Examples diff --git a/modules/l1/ecs-cluster/README.md b/modules/l1/ecs-cluster/README.md index 7e5bc0b..574a1fd 100644 --- a/modules/l1/ecs-cluster/README.md +++ b/modules/l1/ecs-cluster/README.md @@ -46,8 +46,8 @@ The `cluster_arn` output is referenced by `ecs-service` as its ## Compliance extension points - **Container Insights** — add `configuration { container_insights = "enabled" }` for observability (SOC2 CC7.3, DORA ICT risk monitoring). -- **CloudWatch Logs** — add a log group with retention policy for cluster-level audit logs (SOX, SOC2 CC7.2, HIPAA §164.312(b)). -- **Encryption** — add `settings { name = "containerInsights", value = "enabled" }` and KMS-based encryption for container data (HIPAA §164.312(a)(2)(iv), GDPR Art.32). +- **CloudWatch Logs** — add a log group with retention policy for cluster-level audit logs (SOX, SOC2 CC7.2. +- **Encryption** — add `settings { name = "containerInsights", value = "enabled" }` and KMS-based encryption for container data (GDPR Art.32). ## Examples diff --git a/modules/l1/ecs-service/README.md b/modules/l1/ecs-service/README.md index d9fa1ca..1f50368 100644 --- a/modules/l1/ecs-service/README.md +++ b/modules/l1/ecs-service/README.md @@ -64,9 +64,9 @@ provided. ## Compliance extension points -- **CloudWatch Logs** — add `logConfiguration` to the container definition with a log group + retention policy (SOX, SOC2 CC7.2, HIPAA §164.312(b), DORA ICT incident logging). +- **CloudWatch Logs** — add `logConfiguration` to the container definition with a log group + retention policy (SOX, SOC2 CC7.2, DORA ICT incident logging). - **Task execution role separation** — add a separate `aws_iam_role` for execution vs. the task role (SOC2 CC6.3 segregation of duties at runtime). -- **Secrets injection** — add `secrets` block referencing AWS Secrets Manager / SSM Parameter Store with KMS encryption (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv)). +- **Secrets injection** — add `secrets` block referencing AWS Secrets Manager / SSM Parameter Store with KMS encryption (SOC2 CC6.1. - **Execute command** — add `enable_execute_command` with KMS encryption for session audit (SOC2 CC7.2). - **Deployment circuit breaker** — add `deployment_circuit_breaker` block for resilience (SOC2 CC9.1, DORA operational resilience). - **Health check** — add a `health_check` block to the target group (currently missing despite the contract schema having a healthcheck field). diff --git a/modules/l1/iam-role/README.md b/modules/l1/iam-role/README.md index c28d5dc..78056a7 100644 --- a/modules/l1/iam-role/README.md +++ b/modules/l1/iam-role/README.md @@ -51,8 +51,8 @@ into the Terraform `assume_role_policy` argument. The ## Compliance extension points - **Permissions boundary** — add `permissions_boundary` to enforce least-privilege guardrails (SOC2 CC6.1, SOX ITGC, DORA ICT access control). -- **Inline policy** — add `aws_iam_role_policy` for fine-grained least-privilege instead of broad managed policies (SOC2 CC6.1, HIPAA §164.308(a)(4)). -- **MFA conditions** — add `condition` blocks requiring MFA for assume-role (SOC2 CC6.1, HIPAA §164.312(d)). +- **Inline policy** — add `aws_iam_role_policy` for fine-grained least-privilege instead of broad managed policies (SOC2 CC6.1. +- **MFA conditions** — add `condition` blocks requiring MFA for assume-role (SOC2 CC6.1. - **Source IP / region conditions** — add `aws:SourceIp` / `aws:RequestedRegion` conditions for data residency enforcement (GDPR Art.44-49, DORA ICT third-party risk). - **Access Analyzer** — add `aws_accessanalyzer_analyzer` to verify least-privilege (SOC2 CC6.1, GDPR Art.32). - **Role separation** — add a separate task role vs. execution role (SOC2 CC6.3 segregation of duties). diff --git a/modules/l1/kms-key/README.md b/modules/l1/kms-key/README.md index 291dd0c..40a6174 100644 --- a/modules/l1/kms-key/README.md +++ b/modules/l1/kms-key/README.md @@ -53,7 +53,7 @@ pipeline as the regression baseline). ## Compliance extension points -- **Key rotation** — automatic key rotation enabled by default (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32). +- **Key rotation** — automatic key rotation enabled by default (SOC2 CC6.1, GDPR Art.32). - **Deletion protection** — pending deletion window prevents accidental destruction (SOC2 CC7.2). - **Key policy** — restrict key usage to the stack's IAM roles (SOC2 CC6.1, GDPR Art.32). - **Audit logging** — CloudTrail logs all KMS API calls (SOC2 CC7.2, DORA audit trail). diff --git a/modules/l1/rds/README.md b/modules/l1/rds/README.md index cd1f976..879284c 100644 --- a/modules/l1/rds/README.md +++ b/modules/l1/rds/README.md @@ -72,18 +72,17 @@ as the regression baseline). ## Compliance extension points - **KMS encryption** — add a customer-managed KMS key for storage - encryption (`kms_key_id` argument) (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), + encryption (`kms_key_id` argument) (SOC2 CC6.1, GDPR Art.32). - **Automated backups** — the `backup_retention_period` NFR controls automated backup retention; extend with backup windows + copy tags to another region for DR (SOX ITGC, DORA operational resilience). - **Audit logging via CloudTrail** — RDS does not emit CloudTrail events for data-plane access; add `aws_db_instance_automated_backups_replication` - + CloudWatch Logs for database audit (SOX, SOC2 CC7.2, HIPAA - §164.312(b)). + + CloudWatch Logs for database audit (SOX, SOC2 CC7.2). - **IAM database authentication** — add `iam_database_authentication_enabled = true` so IAM users/roles can authenticate to the database without - long-lived passwords (SOC2 CC6.1, HIPAA §164.308(a)(4)). + long-lived passwords (SOC2 CC6.1). - **Read replicas** — add `aws_db_instance` with `replicate_source_db` for read scaling and DR failover (SOC2 CC9.1, DORA operational resilience). diff --git a/modules/l1/s3/README.md b/modules/l1/s3/README.md index 46cff13..3c46745 100644 --- a/modules/l1/s3/README.md +++ b/modules/l1/s3/README.md @@ -50,11 +50,11 @@ pipeline as the regression baseline). ## Compliance extension points -- **Encryption at rest** — add `aws_s3_bucket_server_side_encryption_configuration` with a customer-managed KMS key (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32). +- **Encryption at rest** — add `aws_s3_bucket_server_side_encryption_configuration` with a customer-managed KMS key (SOC2 CC6.1, GDPR Art.32). - **Object Lock** — add `aws_s3_bucket_object_lock_configuration` in compliance mode with 7-year retention for immutable evidence (SOX §802, DORA audit trail). - **Access logging** — add `aws_s3_bucket_logging` to a target logging bucket (SOC2 CC7.2). - **Public access block** — add `aws_s3_bucket_public_access_block` to prevent data exfiltration (SOC2 CC6.1, GDPR Art.32). -- **Lifecycle policy** — add `aws_s3_bucket_lifecycle_configuration` for retention enforcement (GDPR Art.5(2), HIPAA §164.530(j)). +- **Lifecycle policy** — add `aws_s3_bucket_lifecycle_configuration` for retention enforcement (GDPR Art.5(2). ## Examples diff --git a/modules/l1/uptime/README.md b/modules/l1/uptime/README.md index 31913d4..b868e0b 100644 --- a/modules/l1/uptime/README.md +++ b/modules/l1/uptime/README.md @@ -72,7 +72,7 @@ pipeline as the regression baseline). ## Compliance extension points -- **KMS encryption for EFS** — encrypt the EFS volume that persists uptime-kuma state with a customer-managed KMS key (SOC2 CC6.1, HIPAA §164.312(a)(2)(iv), GDPR Art.32). +- **KMS encryption for EFS** — encrypt the EFS volume that persists uptime-kuma state with a customer-managed KMS key (SOC2 CC6.1, GDPR Art.32). - **HTTPS/TLS for the ALB** — attach an ACM certificate and HTTPS listener to the ALB so the dashboard is served over TLS (SOC2 CC6.1, GDPR Art.32). - **WAF in front of uptime dashboard** — place a WAF web ACL in front of the ALB to protect the dashboard from common exploits (SOC2 CC7.2). - **Secrets Manager for alert webhook URLs** — store Teams webhook URLs and other credentials in AWS Secrets Manager rather than plaintext inputs (SOC2 CC6.1, GDPR Art.32). diff --git a/modules/l1/vpc/README.md b/modules/l1/vpc/README.md index 56c5020..3b663f2 100644 --- a/modules/l1/vpc/README.md +++ b/modules/l1/vpc/README.md @@ -54,8 +54,8 @@ modules reference `subnet_ids` for their network placement. ## Compliance extension points -- **VPC Flow Logs** — add `aws_flow_log` + CloudWatch Logs group / S3 destination (SOX ITGC, SOC2 CC7.2, HIPAA §164.312(b), DORA ICT risk logging). -- **Private subnets + NAT gateway** — add private subnets with a NAT gateway so ECS tasks don't need public IPs (SOC2 CC6.6, PCI-DSS 1.3, HIPAA network isolation). +- **VPC Flow Logs** — add `aws_flow_log` + CloudWatch Logs group / S3 destination (SOX ITGC, SOC2 CC7.2, DORA ICT risk logging). +- **Private subnets + NAT gateway** — add private subnets with a NAT gateway so ECS tasks don't need public IPs (SOC2 CC6.6, PCI-DSS 1.3, network isolation). - **VPC endpoints** — add S3, ECR, KMS, DynamoDB, CloudWatch interface/gateway endpoints to keep traffic off the public internet (SOC2 CC6.7, GDPR Art.32(1)(a), DORA ICT third-party risk). - **Security groups** — add `aws_security_group` as a first-class sub-resource (currently missing; needed for all regulated deployments) (SOC2 CC6.6, PCI-DSS 1.2). - **Network ACLs** — add `aws_network_acl` for subnet-level segmentation (PCI-DSS 1.3). diff --git a/modules/l2/microservice/README.md b/modules/l2/microservice/README.md index 6eaac3b..3c64698 100644 --- a/modules/l2/microservice/README.md +++ b/modules/l2/microservice/README.md @@ -53,7 +53,7 @@ inputs: ## Compliance extension points The pattern can wire compliance resources across primitives when the -compliance milestone (GDPR, SOX, SOC2, HIPAA, DORA) lands: +compliance milestone (GDPR, SOX, SOC2, DORA) lands: - **KMS key** — shared encryption key referenced by S3, ECR, CloudWatch Logs, and Secrets Manager. - **CloudTrail** — management-plane audit trail for the entire stack. diff --git a/modules/l2/static-assets/README.md b/modules/l2/static-assets/README.md index 2606f28..6d7b3b7 100644 --- a/modules/l2/static-assets/README.md +++ b/modules/l2/static-assets/README.md @@ -75,7 +75,7 @@ READMEs for the underlying primitives. ## Compliance extension points The pattern can wire compliance resources when the compliance -milestone (GDPR, SOX, SOC2, HIPAA, DORA) lands: +milestone (GDPR, SOX, SOC2, DORA) lands: - **KMS key** — shared encryption key for S3 SSE. - **S3 access logs** — access logging to a separate audit bucket.