Parent runbook: docs/slo/completed/RUNBOOK-hulumi-operations.md. Read Carmack-Style Best Practices, the Global Execution Rules (especially Rule 0 + Rules 11–14) + the Global Entry Rules + docs/slo/lessons/hulumi-operations-m{1,2,3}.md before starting.
Goal: After M4, @hulumi/policies.HulumiOperationsHardeningPack ships as a CrossGuard policy pack mirroring the existing HulumiHardeningPack (H_*) and HulumiGithubHardeningPack (G_*) shape. Five rules under prefix O_, tier-aware (Sandbox: advisory; StartupHardened: mandatory) where appropriate. Plus the existing Suppression API extends to accept the new IDs. Plus a tier-monotonicity meta-test (H4-shape) that asserts Sandbox emits ≤ controls than StartupHardened across the new pack. Plus license-boundary mappings in docs/mappings/ for CIS / NIST / PCI-DSS — IDs only.
Context: The design record docs/slo/design/hulumi-for-operations.md § Decision: HulumiOperationsHardeningPack shape commits the five rule IDs and their tier-aware levels. The threat model rows tm-hulumi-ops-abuse-raw-ec2-rejected, tm-hulumi-ops-abuse-scanonpush-false-rejected, tm-hulumi-ops-abuse-tier-monotonicity-violation, tm-hulumi-ops-abuse-license-boundary, tm-hulumi-ops-abuse-suppression-without-reason are the abuse-case surface. The five rules:
O_PATCH_1: everyaws.ec2.Instancemust have aPatch:Group ∈ {dev, staging, production}tag (Sandbox: advisory; StartupHardened: mandatory). Updated 2026-05-01 per Flaw 2 — tightened from free-form value to enum check.O_PATCH_2: everyaws.ssm.PatchBaselinemust associate to aMaintenanceWindow(both: mandatory).O_DETECT_1: account-level stack with EC2 / ECR resources but noDetectiveServicesEnable(Sandbox: advisory; StartupHardened: mandatory).O_AUDIT_1: account-level stack without anAuditTrail(Sandbox: advisory; StartupHardened: mandatory).O_INSPECTOR_1: everyaws.ecr.RepositorywithimageScanningConfiguration.scanOnPush != true(both: mandatory).
Carmack-style reliability goal: Strengthen Rule 5 — invalid-states-unrepresentable at the policy-pack layer (rules express what cannot exist in the consumer's stack), and Rule 4 — bounded resources via the Operations-pack-cap (max 10 distinct rule IDs in the pack, refuse to register an 11th — see top-level runbook Rule 12).
Important design rule: O_* rule IDs follow the existing prefix convention (H_*, G_*, now O_*). The Suppression API accepts rule IDs from any pack indifferently — no per-pack suppression scoping, mirroring the existing behavior. Every O_* rule's metadata controls field cites framework IDs (CIS / NIST / PCI-DSS) but NEVER verbatim text — license-boundary-lint extension covers the new pack.
Refactor budget: Surgical addition only. New files under packages/policies/src/aws/operations-pack/ and matching tests + mappings docs. One existing file modified: packages/policies/src/index.ts (re-exports). The Suppression API itself is unchanged — accepting new IDs is data, not code change. The license-boundary lint is extended additively to glob-cover the new mappings doc.
| Field | Value |
|---|---|
| Inputs | The HulumiOperationsHardeningPack PolicyPack ctor accepts args: { tier: Tier; suppressions?: Suppression[] } — same shape as existing HulumiHardeningPack. The five rule functions are not exported individually; they're attached to the pack. |
| Outputs | The pack instance, ready to pass to Pulumi CrossGuard. Same output shape as existing packs. |
| Interfaces touched | New stable surface: @hulumi/policies#{HulumiOperationsHardeningPack}. New rule IDs accepted by the existing Suppression API: O_PATCH_1, O_PATCH_2, O_DETECT_1, O_AUDIT_1, O_INSPECTOR_1. License-boundary mapping doc: docs/mappings/operations.md (NEW). |
| Data classification | Public. Policy rules + their CIS / NIST / PCI-DSS mappings are public framework references. The pack does not handle consumer data. |
| Proactive controls in play | (a) C1 Define Security Requirements — O_* rules ARE the requirements at the IaC-policy layer. (b) @hulumi/policies.HulumiHardeningPack (existing) — pattern precedent. (c) Suppression API (existing) — accepts new IDs without code change; reason field already mandatory. (d) license-boundary-lint — extended additively. (e) tier-monotonicity meta-test (H4-shape) — extended. |
| Abuse acceptance scenarios | Five BDD rows below cite tm-hulumi-ops-abuse-N: tm-hulumi-ops-abuse-raw-ec2-rejected (O_PATCH_1 rejects aws.ec2.Instance without Patch:Group=* tag at StartupHardened), tm-hulumi-ops-abuse-scanonpush-false-rejected (O_INSPECTOR_1 rejects ECR repo with scanOnPush: false), tm-hulumi-ops-abuse-tier-monotonicity-violation (meta-test asserts count(Sandbox-mandatory rules) ≤ count(StartupHardened-mandatory rules)), tm-hulumi-ops-abuse-license-boundary (license-boundary-lint extends to cover operations.md mapping doc; verbatim CIS / NIST / PCI-DSS text in the pack source rejected at lint), tm-hulumi-ops-abuse-suppression-without-reason (existing compliance-justified-suppressions meta-test extends to cover O_* IDs; suppression without reason field rejected). |
| Files allowed to change | NEW: packages/policies/src/aws/operations-pack/{index.ts,o-patch-1.ts,o-patch-2.ts,o-detect-1.ts,o-audit-1.ts,o-inspector-1.ts,operations-pack.ts}, packages/policies/tests/aws/operations-pack/{o-patch-1.test.ts,o-patch-2.test.ts,o-detect-1.test.ts,o-audit-1.test.ts,o-inspector-1.test.ts,tier-monotonicity.test.ts,suppression-discipline.test.ts}, docs/mappings/operations.md, docs/components/hulumi-operations-hardening-pack.md (one-line stub), docs/slo/lessons/hulumi-operations-m4.md, docs/slo/completion/hulumi-operations-m4.md. MODIFIED: packages/policies/src/index.ts (re-export HulumiOperationsHardeningPack), scripts/license-boundary-lint.mjs (additive glob — covers docs/mappings/operations.md + the new pack source dir; the lint logic itself is unchanged), docs/slo/completed/RUNBOOK-hulumi-operations.md Milestone Tracker, docs/slo/runbook-milestones/hulumi-operations-m4.md (this file — Evidence Log only), docs/ARCHITECTURE.md (one paragraph), docs/mappings/README.md (index entry for the new mappings doc). REFUSE TO TOUCH: any packages/baseline/, packages/drift/, packages/k8s-baseline/. |
| Files to read before changing anything | docs/slo/completed/RUNBOOK-hulumi-operations.md; docs/slo/design/hulumi-for-operations.md § Decision: HulumiOperationsHardeningPack; docs/slo/design/hulumi-for-operations-threat-model.md HulumiOperationsHardeningPack STRIDE rows + Compliance mapping table; docs/slo/lessons/hulumi-operations-m{1,2,3}.md; packages/policies/src/aws/hardening-pack/ (the existing H_* pack — pattern precedent); packages/policies/src/aws/cis-v5-pack/ (the existing CIS pack — mapping precedent); packages/policies/tests/aws/hardening-pack/tier-monotonicity.test.ts (the existing meta-test we mirror); scripts/license-boundary-lint.mjs; docs/mappings/README.md; docs/mappings/aws.md (existing mapping doc — shape precedent). |
| New files allowed | All NEW entries above. |
| New dependencies allowed | none. Pulumi CrossGuard is already a peer dep of @hulumi/policies. |
| Migration allowed | no — additive only. Suppression API accepts new IDs as data, not as code change. |
| Compatibility commitments | The five O_* rule IDs are stable from M4 — renaming O_PATCH_1 to O_PATCH_BASELINE_REQUIRED_TAG would be a major-version bump. The Suppression API shape unchanged. The pack ships in @hulumi/policies@1.2.0 (M5 release). |
| Resource bounds introduced/changed (v4 Rule 4) | (a) HulumiOperationsHardeningPack rule count: 5 in M4, hard cap of 10 (per top-level Rule 12); refusing to register an 11th rule is encoded as a runtime check + a meta-test. (b) Per-rule severity-level cardinality: each rule emits exactly one severity per evaluation (no fan-out within a single rule). |
| Invariants/assertions required (v4 Rule 3) | (i) Each rule's name field starts with O_ and ends with a digit. (ii) Each rule has a description, a severity (advisory or mandatory per tier), and a controls array of framework IDs (no verbatim text). (iii) Tier monotonicity: for each rule, severity_at_StartupHardened ≥ severity_at_Sandbox (where mandatory > advisory). Asserted in tier-monotonicity.test.ts. (iv) Every Suppression for an O_* ID has a non-empty reason field. Asserted in suppression-discipline.test.ts. (v) The pack instance count of distinct rule IDs is ≤ 10 (the bound); attempting to register an 11th throws. |
| Debugger / inspection expectation (v4 Rule 1) | Pulumi CrossGuard policy violations are observable via pulumi preview output. If a rule fires unexpectedly, the agent runs pulumi preview --policy-pack <path> against a synthetic stack to inspect the violation message before speculating about rule logic. Pulumi mock-runtime supports introspecting args.props inside the rule function — same debugger pattern as M1/M2/M3. |
| Static analysis gates (v4 Rule 2) | Same as M1/M2/M3 — formatter, typecheck, lint, license-boundary, exact-pin guard. License-boundary lint is the gate that protects this milestone the most because it catches verbatim CIS/NIST/PCI-DSS text in any new file. |
| Forbidden shortcuts | (a) NEVER ship verbatim CIS / NIST / PCI-DSS control text in any rule's description or controls metadata — IDs only, framework URLs at the file level. (b) NEVER rename an existing rule ID. (c) NEVER make O_PATCH_2 / O_INSPECTOR_1 advisory at any tier — both are mandatory per design record. (d) NEVER add a sixth rule in M4 — five rules ship; if a sixth is needed, defer to v1.3 with a fresh contract block. (e) NEVER allow a Suppression for an O_* ID without a reason — meta-test catches this. (f) NEVER widen the license-boundary glob beyond what's needed (additive only — covers operations.md and the new pack source dir, not anything else). (g) NEVER rely on O_DETECT_1 / O_AUDIT_1 being able to detect the absence of a component without explicit hint — these rules look for a stack-level marker tag (hulumi:detective-services-enable: present or hulumi:audit-trail: present) emitted by the M2/M3 components; the rule fails closed if the marker is missing AND the stack has the gating resource type. |
- No skill scenarios — those are M5.
- No additional rules beyond the five committed.
- No CIS v8 mappings — v5 is the canonical set; v8 deferred.
- No
SuppressionAPI changes — accepts new IDs as data. - No
HulumiHardeningPack(H_*) orHulumiGithubHardeningPack(G_*) modifications. - No skill-side wiring of the pack — skills don't declare CrossGuard dependencies.
- Complete Global Entry Rules.
- Read lessons-m1, lessons-m2, lessons-m3 — apply corrections.
- Read the design record's
HulumiOperationsHardeningPackdecision + the threat-model compliance-mapping table. - Read the existing
HulumiHardeningPacksource end-to-end as the pattern precedent. - Re-state load-bearing constraints: (i) IDs only (no verbatim framework text); (ii) tier monotonicity; (iii)
O_DETECT_1/O_AUDIT_1rely on M2/M3 marker tags emitted by the components; (iv) hard cap of 10 rules in pack. - Verify the existing
tier-monotonicity.test.tsandcompliance-justified-suppressions.test.tstests pass at baseline.
| File | Planned Change |
|---|---|
packages/policies/src/aws/operations-pack/index.ts |
NEW: re-export HulumiOperationsHardeningPack |
packages/policies/src/aws/operations-pack/operations-pack.ts |
NEW: HulumiOperationsHardeningPack ctor |
packages/policies/src/aws/operations-pack/{o-patch-1,o-patch-2,o-detect-1,o-audit-1,o-inspector-1}.ts |
NEW: per-rule logic |
packages/policies/src/index.ts |
MODIFY: re-export HulumiOperationsHardeningPack |
packages/policies/tests/aws/operations-pack/{o-*.test.ts,tier-monotonicity.test.ts,suppression-discipline.test.ts} |
NEW: tests |
docs/mappings/operations.md |
NEW: CIS / NIST / PCI-DSS / SOC 2 / ISO 27001 mappings — IDs only (per design record's compliance table) |
docs/mappings/README.md |
MODIFY: add index entry pointing at operations.md |
scripts/license-boundary-lint.mjs |
MODIFY: additive glob extension (covers docs/mappings/operations.md and packages/policies/src/aws/operations-pack/); lint logic unchanged |
docs/components/hulumi-operations-hardening-pack.md |
NEW (one-line stub) |
docs/slo/completed/RUNBOOK-hulumi-operations.md Milestone Tracker |
MODIFY |
docs/slo/runbook-milestones/hulumi-operations-m4.md |
MODIFY: Evidence Log fill-in |
docs/slo/lessons/hulumi-operations-m4.md |
NEW per v4 lessons template |
docs/slo/completion/hulumi-operations-m4.md |
NEW per v4 completion template |
docs/ARCHITECTURE.md |
MODIFY: one paragraph |
- Pre-flight + re-state constraints.
- Write per-rule BDD tests (
o-*.test.ts) covering happy-path-stack, violation-stack, suppression-with-reason, suppression-without-reason. Run — expect failures. - Implement
o-patch-1.ts: walks everyaws.ec2.Instanceresource in the stack, checkstags["Patch:Group"]is set AND its value is one of{"dev", "staging", "production"}(tightened 2026-05-01 per Flaw 2); tier-aware severity. Each rule file ~30 lines. - Implement
o-patch-2.ts: walks everyaws.ssm.PatchBaseline, checks for an associatedMaintenanceWindowTargetreferencing it; mandatory both tiers. - Implement
o-detect-1.ts: walks the stack foraws.ec2.Instance,aws.ecr.Repository,aws.lambda.Functionresources; if any present AND no resource emits the marker taghulumi:component=DetectiveServicesEnable, fail tier-aware. - Implement
o-audit-1.ts: walks the stack for anyaws.cloudtrail.Trail-eligible state; if nohulumi:component=AuditTrailmarker present, fail tier-aware. - Implement
o-inspector-1.ts: walks everyaws.ecr.Repository, checksimageScanningConfiguration.scanOnPush === true; mandatory both tiers. - Implement
operations-pack.ts: registers all five rules under theHulumiOperationsHardeningPackPolicyPack class; tier-aware via the existingTier-resolved-severity helper fromHulumiHardeningPack. - Re-export from
packages/policies/src/index.ts. - Write
tier-monotonicity.test.ts(asserts every rule's StartupHardened severity ≥ Sandbox severity) andsuppression-discipline.test.ts(asserts everyO_*suppression in fixture stacks has a non-emptyreason). - Write
docs/mappings/operations.md(IDs only — copy table from threat-model compliance-mapping section verbatim, add framework URLs). - Extend
scripts/license-boundary-lint.mjsglob list. Run — verify it catches a synthetic verbatim-text fixture before final commit. - Run full repo suite. Self-Review Gate. Update Tracker, write lessons + completion files.
Feature: @hulumi/policies.HulumiOperationsHardeningPack — five O_* rules with tier-aware severity, license-boundary-clean, suppression-disciplined
| Scenario | Category | Given | When | Then | Threat-model row | Control |
|---|---|---|---|---|---|---|
| Happy path — all rules satisfied at StartupHardened | happy path | synthetic stack: 1 EC2 with Patch:Group=production tag, 1 PatchBaseline + MW, DetectiveServicesEnable + AuditTrail markers, ECR with scanOnPush:true |
pulumi preview with the pack |
zero violations across all five rules | n/a | n/a |
O_PATCH_1 mandatory at StartupHardened — raw EC2 rejected |
abuse case | synthetic stack: 1 aws.ec2.Instance with no Patch:Group=* tag |
pulumi preview at tier: StartupHardened |
O_PATCH_1 violation; severity mandatory; message contains "Patch:Group" + the resource URN |
tm-hulumi-ops-abuse-raw-ec2-rejected |
C5 + Forbidden (b) |
O_PATCH_1 advisory at Sandbox — raw EC2 warning, not blocking |
tier ladder | same synthetic stack | pulumi preview at tier: Sandbox |
O_PATCH_1 violation; severity advisory; preview proceeds |
n/a | tier discipline |
O_PATCH_1 rejects tag value outside enum (NEW 2026-05-01 per Flaw 2) |
abuse case | synthetic stack: 1 aws.ec2.Instance with Patch:Group=experiment (free-form value) |
pulumi preview at tier: StartupHardened |
O_PATCH_1 violation; severity mandatory; message contains "must be one of [dev, staging, production]" + the resource URN; the prior pattern (any value present) is no longer sufficient |
tm-hulumi-ops-abuse-tag-outside-enum |
invariant + Forbidden (l) |
O_PATCH_2 mandatory at both tiers — orphan PatchBaseline |
violation | synthetic stack: 1 PatchBaseline with no MaintenanceWindowTarget |
pulumi preview at either tier |
O_PATCH_2 violation; severity mandatory |
n/a | n/a |
O_DETECT_1 — ECR resource present, no DetectiveServicesEnable marker |
violation | synthetic stack: 1 ECR repo, no marker | pulumi preview at StartupHardened |
O_DETECT_1 violation; mandatory |
n/a (data-flow check; abuse covered in M2) | C9 |
O_AUDIT_1 — account-level resources present, no AuditTrail marker |
violation | synthetic stack: 1 EC2, 1 ECR, no hulumi:component=AuditTrail marker tag |
pulumi preview at StartupHardened |
O_AUDIT_1 violation; mandatory |
n/a | C9 |
O_INSPECTOR_1 mandatory both tiers — ECR with scanOnPush: false |
abuse case | synthetic stack: 1 ECR with imageScanningConfiguration.scanOnPush: false |
pulumi preview at either tier |
O_INSPECTOR_1 violation; mandatory; message contains "scanOnPush" |
tm-hulumi-ops-abuse-scanonpush-false-rejected |
C5 + Forbidden (c) |
| Suppression with reason accepted | happy path (suppression) | synthetic stack with O_INSPECTOR_1 violation; pack instantiated with suppressions: [{ id: "O_INSPECTOR_1", reason: "Legacy registry; replacing in Q3 2026" }] |
pulumi preview |
violation suppressed; preview proceeds; suppression recorded in suppression-audit.log (existing pattern) |
n/a | C9 + Suppression API |
Abuse case — Suppression without reason rejected |
abuse case | suppressions: [{ id: "O_INSPECTOR_1" } as any] (cast through any to bypass TS) |
Suppression API construction |
the existing Suppression ctor's runtime check throws Error('Suppression: reason is required') |
tm-hulumi-ops-abuse-suppression-without-reason |
Forbidden (e) |
| Abuse case — verbatim CIS / NIST text in rule source rejected by lint | abuse case | synthetic source file with verbatim CIS control description embedded in a rule's description |
pnpm run lint:license-boundary |
lint exits non-zero; specific file:line of the verbatim text reported | tm-hulumi-ops-abuse-license-boundary |
Forbidden (a) + (f) |
| Abuse case — tier monotonicity violation rejected by meta-test | abuse case | synthetic rule definition with Sandbox: mandatory AND StartupHardened: advisory |
pnpm --filter @hulumi/policies test -- tier-monotonicity |
meta-test fails; specific rule ID called out | tm-hulumi-ops-abuse-tier-monotonicity-violation |
Rule 11 + invariant (iii) |
| Resource bound — pack with 11 distinct rule IDs rejected | resource bound | synthetic pack with 11 O_* rules registered |
HulumiOperationsHardeningPack constructor |
throws Error('HulumiOperationsHardeningPack: rule count exceeds hard cap of 10') |
n/a | Rule 4 + invariant (v) |
Compatibility — existing H_* and G_* packs unchanged |
compatibility | HulumiHardeningPack + HulumiGithubHardeningPack packs in the consumer stack |
pulumi preview with all three packs |
all three packs run independently; no rule-ID collision; no false-positive cross-pack effect | n/a | additive |
- All M1 + M2 + M3 BDD continue to pass.
- All existing AWS / GitHub / K8s BDD continue to pass.
- Existing
HulumiHardeningPack/CisV5Pack/HulumiGithubHardeningPackrule tests unchanged — re-run, all green. - Existing
tier-monotonicity.test.tsforH_*rules unchanged. - Existing
compliance-justified-suppressions.test.tsforH_*andG_*IDs unchanged; the new test file is forO_*IDs. - License-boundary lint: re-run on existing source — no false positives.
-
HulumiOperationsHardeningPackre-exported from@hulumi/policies. - No new dependencies.
- Static-analysis gates green.
- License-boundary lint catches verbatim text in synthetic fixture (fixture committed under tests, NOT in production source).
- License header on every new
.tsfile. - DCO sign-off carried over.
- All M1 + M2 + M3 + existing AWS / GitHub / K8s BDD scenarios produce valid output unchanged.
- Existing
SuppressionAPI call sites unchanged. - Existing
H_*/G_*rule pack tests unchanged.
Policy packs do not have a "runtime" the way components do — they execute at pulumi preview. The E2E equivalents are end-to-end policy-pack integration tests:
File: packages/policies/tests/aws/operations-pack/e2e-policy-pack.test.ts.
| E2E Test | What It Proves | Pass Criteria |
|---|---|---|
policy_pack_runs_against_synthetic_stack_with_violations |
The pack actually fires when expected | Test constructs an in-memory policy-pack instance + synthetic Pulumi stack with each violation type; asserts each rule fires exactly once with the correct severity. |
policy_pack_runs_clean_against_compliant_stack |
The pack doesn't false-positive | Test constructs a happy-path stack (M1+M2+M3 components present, all marker tags emitted, ECR with scanOnPush, EC2 with Patch:Group); asserts zero violations. |
combined_packs_no_collision |
H_*, G_*, O_* coexist |
Test loads all three packs together against a stack that has both AWS account-level + GitHub + Operations resources; asserts each pack's rules fire on their own resources only, no cross-pack interference. |
license_boundary_catches_verbatim_in_synthetic_fixture |
The lint extension is wired | Synthetic test fixture file under tests/fixtures/license-boundary-violations/operations-verbatim.ts containing a CIS verbatim sentence; run pnpm run lint:license-boundary --include-fixtures; assert non-zero exit + specific file:line flagged. |
- Full static-analysis suite green.
- Mock-runtime BDD green.
- In a Pulumi program with
HulumiOperationsHardeningPackenabled attier: StartupHardened:new aws.ec2.Instance("foo", { ... no Patch:Group tag ... })causespulumi previewto emitO_PATCH_1violation. - In a Pulumi program:
new aws.ecr.Repository("bar", { imageScanningConfiguration: { scanOnPush: false } })causespulumi previewto emitO_INSPECTOR_1violation. -
git statusclean. -
.gitignorecovers any new generated files.
| Step | Command / Check | Expected Result | Actual Result | Pass/Fail | Notes |
|---|---|---|---|---|---|
| Baseline tests | pnpm -r build && pnpm -r test |
green | filled during execution | pending | |
| BDD tests created (per rule) | pnpm --filter @hulumi/policies test -- operations-pack |
fail for expected reason | filled during execution | pending | |
| Tier-monotonicity meta-test | pnpm --filter @hulumi/policies test -- tier-monotonicity |
initially fails (no rules registered yet) | filled during execution | pending | |
| Implementation | filesystem | source files + re-exports | filled during execution | pending | |
| Mappings doc | cat docs/mappings/operations.md |
IDs only; framework URLs at file level | filled during execution | pending | |
| License-boundary glob extension | cat scripts/license-boundary-lint.mjs |
additive glob covers new files | filled during execution | pending | |
| Formatter | pnpm -r format:check |
clean | filled during execution | pending | |
| Typecheck | pnpm -r typecheck |
clean | filled during execution | pending | |
| Static analyzer | pnpm -r lint |
clean | filled during execution | pending | |
| License-boundary lint | pnpm run lint:license-boundary |
OK on new files; catches synthetic fixture | filled during execution | pending | |
| Exact-pin guard | pnpm run lint:exact-pin-guard |
OK | filled during execution | pending | |
| Per-rule BDD | pnpm --filter @hulumi/policies test -- operations-pack |
all rows pass | filled during execution | pending | |
| Tier-monotonicity meta-test | pnpm --filter @hulumi/policies test -- tier-monotonicity |
green for all five O_* rules |
filled during execution | pending | |
| Suppression-discipline meta-test | pnpm --filter @hulumi/policies test -- suppression-discipline |
green; rejects reason: "" |
filled during execution | pending | |
| Combined packs no-collision test | pnpm --filter @hulumi/policies test -- e2e-policy-pack |
green | filled during execution | pending | |
| Build/boot | pnpm -r build |
builds cleanly | filled during execution | pending | |
| Resource-bound verification | mock-runtime: 11-rule pack rejected | bound = 10; over-cap rejected | filled during execution | pending | |
| Invariant verification | tier-monotonicity meta-test | invariant (iii) holds for all five rules | filled during execution | pending | |
| Debugger / state inspection | pulumi preview --policy-pack against synthetic stack if a rule fires unexpectedly |
rule logic confirmed before code change | filled during execution | pending | |
| Smoke tests | (manual list) | all checked | filled during execution | pending | |
| Test artifact cleanup | git status --short |
only intentional files | filled during execution | pending | |
| .gitignore review | review | current | filled during execution | pending | |
| Compatibility checks | (manual list) | no regressions | filled during execution | pending |
- All BDD scenarios pass.
- Tier-monotonicity meta-test green for all five
O_*rules. - Suppression-discipline meta-test green.
- License-boundary lint green; the synthetic-fixture test confirms the lint catches verbatim text.
- Static-analysis gates green.
- Smoke tests checked off.
- Compatibility checklist complete.
- Resource bounds (Rule 4: max 10 rules) and invariants (Rule 3: all five enumerated) encoded + tested.
- No forbidden shortcuts.
git statusclean.- All M1 + M2 + M3 + existing surfaces unchanged.
- Self-Review Gate answered with
yes. - Lessons + completion files written.
- Mappings doc
docs/mappings/operations.mdwritten, IDs only. - Milestone Tracker updated to
done.
docs/slo/completed/RUNBOOK-hulumi-operations.mdMilestone Tracker → M4done.docs/components/hulumi-operations-hardening-pack.md— one-line stub.docs/ARCHITECTURE.md— one paragraph.docs/mappings/README.md— index entry pointing atoperations.md.
- The M2/M3-marker-tag pattern (
hulumi:component=DetectiveServicesEnable,hulumi:component=AuditTrail) is the load-bearing data-flow link between the M2/M3 components and theO_DETECT_1/O_AUDIT_1rules. If the marker tag is missed in M2/M3 implementation, the rules can't fire correctly. The lessons file should call this out as the cross-milestone dependency that the reader should verify when reading M4 lessons against M2/M3 source. - Five rules is the deliberate ceiling for v1.2. If consumer demand surfaces additional Operations-pack rules (e.g., GuardDuty-Master-Account-required, Cost-Anomaly-Threshold-min), they're v1.3 work — not M4 scope creep.