bridgebench 3.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CITATION.cff +15 -0
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/dist/chunk-4TWPCPRP.cjs +1097 -0
- package/dist/chunk-4TWPCPRP.cjs.map +1 -0
- package/dist/chunk-7YCJSOK7.cjs +398 -0
- package/dist/chunk-7YCJSOK7.cjs.map +1 -0
- package/dist/chunk-CIXITJW6.cjs +249 -0
- package/dist/chunk-CIXITJW6.cjs.map +1 -0
- package/dist/chunk-EQHRUV2I.js +1466 -0
- package/dist/chunk-EQHRUV2I.js.map +1 -0
- package/dist/chunk-JTVNKSMO.js +1096 -0
- package/dist/chunk-JTVNKSMO.js.map +1 -0
- package/dist/chunk-LFKEV2YL.js +398 -0
- package/dist/chunk-LFKEV2YL.js.map +1 -0
- package/dist/chunk-NJTYVNP4.cjs +1467 -0
- package/dist/chunk-NJTYVNP4.cjs.map +1 -0
- package/dist/chunk-UECBSKTD.js +244 -0
- package/dist/chunk-UECBSKTD.js.map +1 -0
- package/dist/cli.cjs +409 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +408 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.cjs +42 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +93 -0
- package/dist/client.d.ts +93 -0
- package/dist/client.js +42 -0
- package/dist/client.js.map +1 -0
- package/dist/contracts/index.cjs +47 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +14 -0
- package/dist/contracts/index.d.ts +14 -0
- package/dist/contracts/index.js +47 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/index.cjs +171 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +214 -0
- package/dist/index.d.ts +214 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/logger-CCR9Mg1c.d.cts +319 -0
- package/dist/logger-QJU7SBDz.d.ts +319 -0
- package/dist/reports-4CejmOHf.d.cts +454 -0
- package/dist/reports-s2CTnGN8.d.ts +454 -0
- package/dist/tasks-CpaCJ6JE.d.cts +151 -0
- package/dist/tasks-CpaCJ6JE.d.ts +151 -0
- package/dist/tasks.cjs +22 -0
- package/dist/tasks.cjs.map +1 -0
- package/dist/tasks.d.cts +39 -0
- package/dist/tasks.d.ts +39 -0
- package/dist/tasks.js +22 -0
- package/dist/tasks.js.map +1 -0
- package/docs/README.md +25 -0
- package/docs/glossary.md +49 -0
- package/docs/methodology.md +58 -0
- package/docs/private-packs.md +74 -0
- package/docs/replay-elo.md +79 -0
- package/docs/task-authoring.md +80 -0
- package/package.json +137 -0
- package/tasks/hallucination/public/boundary-coverage-audit.yaml +274 -0
- package/tasks/hallucination/public/boundary-migration-audit.yaml +284 -0
- package/tasks/hallucination/public/conflict-dependency-versions.yaml +324 -0
- package/tasks/hallucination/public/conflict-runbook-versions.yaml +229 -0
- package/tasks/hallucination/public/fabrication-agent-tools.yaml +224 -0
- package/tasks/hallucination/public/fabrication-api-surface.yaml +239 -0
- package/tasks/hallucination/public/fidelity-commit-attribution.yaml +304 -0
- package/tasks/hallucination/public/fidelity-config-drift.yaml +307 -0
- package/tasks/hallucination/public/missing-deploy-window.yaml +204 -0
- package/tasks/hallucination/public/missing-latency-baseline.yaml +239 -0
- package/tasks/hallucination/public/premise-quota-breach.yaml +202 -0
- package/tasks/hallucination/public/premise-rollback-cause.yaml +235 -0
- package/tasks/reasoning/public/constraint-capacity-allocation.yaml +196 -0
- package/tasks/reasoning/public/constraint-deployment-policy.yaml +203 -0
- package/tasks/reasoning/public/counterexample-authorization-rule.yaml +278 -0
- package/tasks/reasoning/public/counterexample-scheduler-starvation.yaml +290 -0
- package/tasks/reasoning/public/root-cache-tenant-leak.yaml +225 -0
- package/tasks/reasoning/public/root-event-ordering.yaml +184 -0
- package/tasks/reasoning/public/stateful-lease-handoff.yaml +213 -0
- package/tasks/reasoning/public/stateful-retry-budget.yaml +222 -0
- package/tasks/reasoning/public/synthesis-api-contract.yaml +214 -0
- package/tasks/reasoning/public/synthesis-permission-migration.yaml +190 -0
- package/tasks/reasoning/public/uncertainty-conflicting-telemetry.yaml +242 -0
- package/tasks/reasoning/public/uncertainty-incomplete-incident.yaml +223 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
id: premise-rollback-cause
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
category: hallucination
|
|
4
|
+
cluster: false-premise
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: The Rollback That Came After Recovery
|
|
7
|
+
summary: An on-call writeup credits a rollback for ending an incident, but the raw evidence shows recovery happened before the rollback started and that no code deploy triggered the outage.
|
|
8
|
+
prompt: |
|
|
9
|
+
checkout-router served elevated 5xx errors during incident INC-4471 today. An on-call
|
|
10
|
+
engineer filed a post-incident writeup (see oncall-writeup). Using ALL artifacts, answer
|
|
11
|
+
the six deliverables below.
|
|
12
|
+
|
|
13
|
+
Some statements in the writeup and in the deliverables themselves may be inaccurate. Before
|
|
14
|
+
answering any deliverable, verify its premise against the raw evidence (event-stream,
|
|
15
|
+
error-rate-table, deploy-history, incident-chat) and the attribution rule in slo-runbook. If
|
|
16
|
+
a deliverable rests on a false premise, say so explicitly, cite the contradicting evidence,
|
|
17
|
+
correct the premise, then answer the corrected question if the artifacts allow. If a
|
|
18
|
+
deliverable cannot be answered from the artifacts, state that and name exactly what is
|
|
19
|
+
missing. Cite artifact ids for every claim.
|
|
20
|
+
|
|
21
|
+
1. Identify what triggered the onset of elevated checkout-router 5xx errors, and give the
|
|
22
|
+
clock minute at which the 5xx rate first exceeded the 1% SLO threshold.
|
|
23
|
+
2. Identify what actually brought the 5xx rate back to baseline, and give the clock minute
|
|
24
|
+
at which it returned to baseline.
|
|
25
|
+
3. The rollback of checkout-router to v7.22.0 completed at 14:38 and cleared the errors.
|
|
26
|
+
Explain the mechanism by which the rollback restored service.
|
|
27
|
+
4. The elevated errors were introduced by the checkout-router code deploy at 14:10. Identify
|
|
28
|
+
the version that deploy shipped and the regression it introduced.
|
|
29
|
+
5. Report the number of consecutive clock minutes during which the checkout-router 5xx rate
|
|
30
|
+
stayed above the 1% SLO threshold.
|
|
31
|
+
6. Report how many individual customer checkout attempts failed during the incident.
|
|
32
|
+
artifacts:
|
|
33
|
+
- id: service-topology
|
|
34
|
+
type: spec
|
|
35
|
+
label: Checkout path services and guardrails
|
|
36
|
+
content: |
|
|
37
|
+
Services and change surfaces for the checkout path (region us-east):
|
|
38
|
+
- checkout-router: stateless HTTP service, 24 pods. Serves POST /checkout. It calls
|
|
39
|
+
pricing-engine synchronously for each line item; a pricing error surfaces to the client
|
|
40
|
+
as an HTTP 5xx from checkout-router. Rolling deploys replace pods in batches of 4, and a
|
|
41
|
+
full rollout reaches "HEALTHY" (all 24 pods Ready) roughly 5-6 minutes after the rollout
|
|
42
|
+
START event. Pods on the old version keep serving until the new pods replace them.
|
|
43
|
+
- pricing-engine: upstream gRPC service that checkout-router calls for line-item pricing.
|
|
44
|
+
- feature-flags: global control plane. A flag change propagates to all checkout-router
|
|
45
|
+
pods in under 10 seconds. Applying OR undoing a flag change requires NO redeploy and no
|
|
46
|
+
pod replacement; the running build already contains both code paths.
|
|
47
|
+
|
|
48
|
+
Guardrails:
|
|
49
|
+
- SLO error threshold for checkout-router is 1.0% 5xx. Minutes at or below 1.0% are
|
|
50
|
+
"baseline"; minutes above 1.0% are "elevated".
|
|
51
|
+
- error-budget-guard: an automated kill-switch. If a flag's owning service burns 5xx
|
|
52
|
+
error budget above 8%/minute for 3 consecutive 1-minute windows, the guard
|
|
53
|
+
AUTO-DISABLEs the most recently changed flag on that service (setting its rollout to 0)
|
|
54
|
+
and records an AUTO-DISABLE event. The guard never restarts, redeploys, or replaces
|
|
55
|
+
pods; it only flips the flag.
|
|
56
|
+
|
|
57
|
+
Flag under change today: dynamic-pricing-v2. It routes checkout pricing through a new code
|
|
58
|
+
path that already ships inside the running checkout-router build, so enabling it changes
|
|
59
|
+
behavior with no deploy, and disabling it reverts behavior with no deploy.
|
|
60
|
+
- id: flag-config-diff
|
|
61
|
+
type: diff
|
|
62
|
+
label: Feature-flag change applied at 14:18
|
|
63
|
+
content: |
|
|
64
|
+
--- a/flags/checkout/dynamic-pricing-v2.yaml
|
|
65
|
+
+++ b/flags/checkout/dynamic-pricing-v2.yaml
|
|
66
|
+
@@ rollout
|
|
67
|
+
enabled: true
|
|
68
|
+
- rollout_percent: 5
|
|
69
|
+
+ rollout_percent: 100
|
|
70
|
+
owner_service: checkout-router
|
|
71
|
+
changed_by: r.santos
|
|
72
|
+
# applied 14:18:05 via the feature-flags control plane (no deploy involved)
|
|
73
|
+
# prior state: dynamic-pricing-v2 had sat at 5% since 11:50 with no error impact
|
|
74
|
+
- id: event-stream
|
|
75
|
+
type: log
|
|
76
|
+
label: INC-4471 chronological event stream
|
|
77
|
+
content: |
|
|
78
|
+
14:15:00 checkout-router health: 24/24 pods Ready; 5xx=0.3%
|
|
79
|
+
14:16:30 checkout-router health: 24/24 pods Ready; 5xx=0.3%
|
|
80
|
+
14:18:05 flags: dynamic-pricing-v2 rollout_percent 5 -> 100 (changed_by=r.santos, no deploy)
|
|
81
|
+
14:18:12 flags: propagation complete to 24/24 checkout-router pods
|
|
82
|
+
14:19:20 alert WARN checkout-router 5xx=3.1% (above 1% SLO)
|
|
83
|
+
14:20:40 alert CRIT checkout-router 5xx=9.8% (above 5%)
|
|
84
|
+
14:21:10 pager: page sent to on-call m.li (incident INC-4471 opened)
|
|
85
|
+
14:21:55 checkout-router health: 24/24 pods Ready (pods healthy; failures are 5xx responses, not crashes)
|
|
86
|
+
14:22:30 alert CRIT checkout-router 5xx=16.7%
|
|
87
|
+
14:23:40 pager: on-call m.li ACKNOWLEDGED INC-4471
|
|
88
|
+
14:24:15 error-budget-guard: checkout-router burn 16.9%/min (window 1 of 3)
|
|
89
|
+
14:25:20 error-budget-guard: checkout-router burn 16.8%/min (window 2 of 3)
|
|
90
|
+
14:26:30 error-budget-guard: checkout-router burn 17.3%/min (window 3 of 3)
|
|
91
|
+
14:27:00 m.li note: "still climbing, looking at recent changes"
|
|
92
|
+
14:28:10 error-budget-guard: threshold sustained 3 windows; arming auto-disable
|
|
93
|
+
14:29:05 alert CRIT checkout-router 5xx=16.2%
|
|
94
|
+
14:30:12 error-budget-guard: AUTO-DISABLE dynamic-pricing-v2 (rollout 100 -> 0, owner=checkout-router)
|
|
95
|
+
14:30:20 flags: dynamic-pricing-v2 disabled; propagation complete to 24/24 pods
|
|
96
|
+
14:31:20 alert INFO checkout-router 5xx=0.4% (recovered below 1% SLO)
|
|
97
|
+
14:32:40 checkout-router health: 24/24 pods Ready; 5xx=0.3%
|
|
98
|
+
14:33:00 m.li note: "errors look recovered but I want to be safe; suspect the running build"
|
|
99
|
+
14:36:30 m.li action: initiated rollback of checkout-router to v7.22.0
|
|
100
|
+
14:38:00 deploy: rollback checkout-router v7.22.1 -> v7.22.0 STARTED (rolling, batches of 4)
|
|
101
|
+
14:39:10 deploy: batch 1/6 replaced (4/24 pods on v7.22.0)
|
|
102
|
+
14:40:25 deploy: batch 2/6 replaced (8/24 pods on v7.22.0)
|
|
103
|
+
14:41:30 deploy: batch 3/6 replaced (12/24 pods on v7.22.0)
|
|
104
|
+
14:42:40 deploy: batch 4/6 replaced (16/24 pods on v7.22.0)
|
|
105
|
+
14:43:50 deploy: batch 5/6 replaced (20/24 pods on v7.22.0)
|
|
106
|
+
14:44:10 deploy: batch 6/6 replaced; checkout-router v7.22.0 HEALTHY (24/24 Ready)
|
|
107
|
+
14:44:30 checkout-router health: 24/24 pods Ready; 5xx=0.3%
|
|
108
|
+
14:50:00 INC-4471 IC: incident declared resolved
|
|
109
|
+
- id: incident-chat
|
|
110
|
+
type: log
|
|
111
|
+
label: INC-4471 incident channel transcript
|
|
112
|
+
content: |
|
|
113
|
+
#inc-4471 channel (times UTC):
|
|
114
|
+
14:21:30 pagerbot: INC-4471 opened - checkout-router 5xx 3%+ and climbing
|
|
115
|
+
14:22:10 m.li: ack, taking a look
|
|
116
|
+
14:23:50 j.okafor (SRE): what changed right before this? any deploy?
|
|
117
|
+
14:24:30 m.li: pulling up recent changes
|
|
118
|
+
14:25:10 j.okafor: heads up - dynamic-pricing-v2 went to 100% at 14:18, that lines up exactly with onset
|
|
119
|
+
14:26:40 m.li: maybe, but I want to check the running build too
|
|
120
|
+
14:29:20 pagerbot: still CRIT, 5xx ~16%
|
|
121
|
+
14:30:25 j.okafor: error-budget-guard just auto-disabled dynamic-pricing-v2 (100 -> 0)
|
|
122
|
+
14:31:35 pagerbot: 5xx back to 0.4% - below SLO
|
|
123
|
+
14:31:50 j.okafor: recovered. that was the flag - errors dropped the minute after it was disabled
|
|
124
|
+
14:33:20 m.li: agreed it's recovered, but I still want to roll back the build to be safe
|
|
125
|
+
14:36:40 m.li: starting rollback of checkout-router to v7.22.0
|
|
126
|
+
14:38:10 pagerbot: deploy started - checkout-router v7.22.0
|
|
127
|
+
14:39:00 j.okafor: fwiw we were already at baseline for ~7 min before this rollback even started
|
|
128
|
+
14:44:20 pagerbot: checkout-router v7.22.0 HEALTHY
|
|
129
|
+
14:50:10 m.li: calling it resolved. will write it up.
|
|
130
|
+
14:52:00 j.okafor: writeup should say the flag auto-disable fixed it, not the rollback
|
|
131
|
+
- id: error-rate-table
|
|
132
|
+
type: table
|
|
133
|
+
label: checkout-router 5xx rate, minute by minute
|
|
134
|
+
content: |
|
|
135
|
+
minute checkout_router_5xx_pct
|
|
136
|
+
14:15 0.3
|
|
137
|
+
14:16 0.3
|
|
138
|
+
14:17 0.4
|
|
139
|
+
14:18 0.5
|
|
140
|
+
14:19 3.1
|
|
141
|
+
14:20 9.8
|
|
142
|
+
14:21 14.2
|
|
143
|
+
14:22 16.7
|
|
144
|
+
14:23 17.9
|
|
145
|
+
14:24 17.1
|
|
146
|
+
14:25 16.8
|
|
147
|
+
14:26 17.3
|
|
148
|
+
14:27 16.5
|
|
149
|
+
14:28 17.0
|
|
150
|
+
14:29 16.2
|
|
151
|
+
14:30 11.4
|
|
152
|
+
14:31 0.4
|
|
153
|
+
14:32 0.3
|
|
154
|
+
14:33 0.3
|
|
155
|
+
14:34 0.3
|
|
156
|
+
14:35 0.4
|
|
157
|
+
14:36 0.3
|
|
158
|
+
14:37 0.3
|
|
159
|
+
14:38 0.4
|
|
160
|
+
14:39 0.3
|
|
161
|
+
14:40 0.3
|
|
162
|
+
14:41 0.3
|
|
163
|
+
14:42 0.4
|
|
164
|
+
14:43 0.3
|
|
165
|
+
14:44 0.3
|
|
166
|
+
14:45 0.3
|
|
167
|
+
14:46 0.3
|
|
168
|
+
Peak 5xx: 17.9% at 14:23. This table reports the 5xx PERCENTAGE per minute only. It does
|
|
169
|
+
not include absolute request counts, checkout attempt counts, or per-minute traffic volume.
|
|
170
|
+
- id: deploy-history
|
|
171
|
+
type: log
|
|
172
|
+
label: checkout-router and pricing-engine deploys today (us-east)
|
|
173
|
+
content: |
|
|
174
|
+
Production deploy history for this day, region us-east (rollout START and HEALTHY events).
|
|
175
|
+
This history is the authoritative and exhaustive record of code deploys for the day:
|
|
176
|
+
08:14:00 pricing-engine v3.10.0 deploy STARTED
|
|
177
|
+
08:20:10 pricing-engine v3.10.0 HEALTHY
|
|
178
|
+
09:02:00 checkout-router v7.22.1 deploy STARTED (this is the build running when the incident began)
|
|
179
|
+
09:09:15 checkout-router v7.22.1 HEALTHY
|
|
180
|
+
11:40:00 feature-flags v2.1.0 control-plane deploy STARTED
|
|
181
|
+
11:45:30 feature-flags v2.1.0 HEALTHY
|
|
182
|
+
13:55:00 pricing-engine v3.11.0 deploy STARTED
|
|
183
|
+
14:01:20 pricing-engine v3.11.0 HEALTHY
|
|
184
|
+
14:38:00 checkout-router v7.22.0 deploy STARTED (manual rollback from v7.22.1)
|
|
185
|
+
14:44:10 checkout-router v7.22.0 HEALTHY
|
|
186
|
+
Between 09:02 and 14:38 there was NO checkout-router deploy START event. The only
|
|
187
|
+
checkout-router versions in play today are v7.22.1 (running since 09:09) and v7.22.0
|
|
188
|
+
(the rollback target). There is no v-anything checkout-router deploy in the 14:00-14:37 range.
|
|
189
|
+
- id: slo-runbook
|
|
190
|
+
type: note
|
|
191
|
+
label: checkout-router incident runbook (attribution rule)
|
|
192
|
+
content: |
|
|
193
|
+
checkout-router incident runbook (excerpt).
|
|
194
|
+
|
|
195
|
+
Baseline vs elevated: checkout-router is "at baseline" when 5xx <= 1.0% (the SLO
|
|
196
|
+
threshold). The incident is "recovered" at the first minute 5xx returns to baseline and
|
|
197
|
+
stays there, regardless of what remediation is still in flight at that moment.
|
|
198
|
+
|
|
199
|
+
How each change type takes effect:
|
|
200
|
+
- Feature-flag change (enable/disable/percent): applies within ~10s of the control-plane
|
|
201
|
+
write. No deploy, no pod replacement. error-budget-guard's AUTO-DISABLE is a flag flip
|
|
202
|
+
and takes effect the same way.
|
|
203
|
+
- Code deploy or rollback: replaces pods via a rolling deploy. It has NO effect on served
|
|
204
|
+
behavior until pods running the new version are actually serving traffic, which is the
|
|
205
|
+
HEALTHY event - roughly 5-6 minutes after the deploy START event.
|
|
206
|
+
|
|
207
|
+
Postmortem attribution rule: an action can be credited with recovery only if it took
|
|
208
|
+
effect at or before the minute recovery was first observed. Compare the recovery minute in
|
|
209
|
+
error-rate-table against each candidate action's effective time (flag flips: the flag
|
|
210
|
+
event time; deploys/rollbacks: the HEALTHY time) before crediting it. An action whose
|
|
211
|
+
effective time is after recovery cannot have caused it.
|
|
212
|
+
|
|
213
|
+
Common attribution mistake: crediting the last action a human took (often a rollback)
|
|
214
|
+
simply because it happened near the end of the incident. Order the candidate actions by
|
|
215
|
+
effective time and check each against the recovery minute; the cause is the earliest
|
|
216
|
+
action whose effect coincides with the return to baseline, not the most recent action in
|
|
217
|
+
the timeline. Because failures during this incident were 5xx responses and all pods stayed
|
|
218
|
+
Ready, a pod-replacing deploy or rollback was never required to restore service.
|
|
219
|
+
- id: oncall-writeup
|
|
220
|
+
type: note
|
|
221
|
+
label: On-call post-incident writeup (unverified narrative)
|
|
222
|
+
content: |
|
|
223
|
+
Post-incident writeup by m.li (on-call), filed 15:20.
|
|
224
|
+
|
|
225
|
+
Summary: Around 14:10 a checkout-router deploy went out that introduced a pricing
|
|
226
|
+
regression. checkout-router 5xx climbed to roughly 18%. I was paged at 14:21 and
|
|
227
|
+
acknowledged at 14:23. I diagnosed it as a bad code deploy and rolled checkout-router back
|
|
228
|
+
to the previous version. The rollback completed at 14:38, and immediately after it
|
|
229
|
+
completed the error rate dropped back to baseline. Root cause: the 14:10 code deploy. The
|
|
230
|
+
rollback resolved the incident.
|
|
231
|
+
|
|
232
|
+
Contributing factors: the bad build had been serving since 14:10 and slipped past our
|
|
233
|
+
pre-prod checks. Follow-up: add a canary gate so a regressed deploy is caught before it
|
|
234
|
+
reaches full traffic, and speed up our rollback tooling so recovery is faster next time.
|
|
235
|
+
tags: [false-premise, incident, rollback, timeline, causation]
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
id: constraint-capacity-allocation
|
|
2
|
+
version: 2.1.0
|
|
3
|
+
category: reasoning
|
|
4
|
+
cluster: constraint-reconciliation
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: Three-Pool Two-Class CI Job Allocation Under Org-Wide and Per-Pool Caps
|
|
7
|
+
summary: >-
|
|
8
|
+
Maximize total admitted CI jobs across three runner pools and two job classes subject to per-pool
|
|
9
|
+
burst reserve, per-pool e2e concurrency caps, an exact unit-to-e2e ratio, integrality, and two
|
|
10
|
+
org-wide caps, then evaluate three proposed schedules and two proposed cap changes.
|
|
11
|
+
prompt: |
|
|
12
|
+
A CI scheduler admits build jobs across runner pools pool-large, pool-standard, and pool-arm, each
|
|
13
|
+
split into unit-test and e2e-suite classes. Maximize total admitted CI jobs/hour subject to
|
|
14
|
+
[capacity-model], the per-pool limits in [region-caps], the [global-limits], and the tie-breaking
|
|
15
|
+
[allocation-policy]. Class semantics are in [sla-definitions]. [planner-proposals] lists three
|
|
16
|
+
candidate schedules. [proposed-change] describes two cap changes. [demand-forecast] is the raw
|
|
17
|
+
queued demand.
|
|
18
|
+
|
|
19
|
+
Every admitted amount is CI jobs/hour. Answer each deliverable with exact integers; every
|
|
20
|
+
deliverable requires reconciling at least the model, both cap artifacts, and the policy.
|
|
21
|
+
|
|
22
|
+
1. Optimal allocation. Give the maximum total admitted jobs, the admitted amount per pool, and
|
|
23
|
+
each pool's unit-test/e2e split.
|
|
24
|
+
2. Binding constraints. State which constraint(s) bind at the ORG-WIDE level at the optimum, and for
|
|
25
|
+
EACH pool state which single constraint determines its admitted amount.
|
|
26
|
+
3. Proposal review. For each of Proposal Alpha, Beta, and Gamma in [planner-proposals], state
|
|
27
|
+
feasible or infeasible, and for each infeasible one name each specific constraint it
|
|
28
|
+
violates (and by how much); a proposal may violate more than one.
|
|
29
|
+
4. Change S1. Under [proposed-change] scenario S1 (org-wide e2e cap 300 -> 340, runner-slot cap
|
|
30
|
+
unchanged), give the new maximum total, the new split, and which org-wide constraint now binds.
|
|
31
|
+
5. Change S2. Under scenario S2 (org-wide runner-slot cap 1200 -> 1260 AND org-wide e2e cap 300 -> 340),
|
|
32
|
+
give the new maximum total and split, state which constraints bind, and identify the single
|
|
33
|
+
minimal further change that would raise total throughput beyond that maximum.
|
|
34
|
+
artifacts:
|
|
35
|
+
- id: capacity-model
|
|
36
|
+
type: spec
|
|
37
|
+
label: Allocation model
|
|
38
|
+
content: |
|
|
39
|
+
DECISION VARIABLES (CI jobs/hour, all non-negative integers):
|
|
40
|
+
For each pool p in {large, standard, arm}: u_p (unit-test admitted), e_p (e2e-suite admitted).
|
|
41
|
+
admitted_p = u_p + e_p. total = sum over p of admitted_p.
|
|
42
|
+
|
|
43
|
+
OBJECTIVE: maximize total.
|
|
44
|
+
|
|
45
|
+
CONSTRAINTS:
|
|
46
|
+
(a) Ratio: in every pool, u_p : e_p = 3 : 1 exactly (so u_p = 3 * e_p and admitted_p is a
|
|
47
|
+
multiple of 4). This also makes the org-wide unit:e2e ratio exactly 3:1.
|
|
48
|
+
(b) Per-pool burst reserve: admitted_p <= usable_p, where usable_p is pool physical minus
|
|
49
|
+
burst reserve from [region-caps].
|
|
50
|
+
(c) Per-pool e2e cap: e_p <= e2e_cap_p from [region-caps].
|
|
51
|
+
(d) Per-pool unit-test floor: u_p >= unit_floor_p from [region-caps].
|
|
52
|
+
(e) Org-wide runner-slot cap: total <= org_runner_slot_cap in [global-limits].
|
|
53
|
+
(f) Org-wide e2e cap: (e_large + e_standard + e_arm) <= org_e2e_cap in [global-limits].
|
|
54
|
+
(g) Org-wide unit cap: (u_large + u_standard + u_arm) <= org_unit_cap in [global-limits].
|
|
55
|
+
(h) Integrality: all variables are integers; admitted_p is a multiple of 4 by (a).
|
|
56
|
+
|
|
57
|
+
SOLUTION METHOD (intended):
|
|
58
|
+
1. Compute each pool's LOCAL MAXIMUM = the largest multiple of 4 satisfying BOTH its
|
|
59
|
+
burst-reserve ceiling (admitted_p <= usable_p) and its e2e cap (admitted_p <= 4 * e2e_cap_p);
|
|
60
|
+
because u_p = 3 * e_p, the e2e cap converts directly into an admitted ceiling of 4 * e2e_cap_p.
|
|
61
|
+
2. Sum the local maxima. If that sum satisfies every org-wide cap, it is optimal.
|
|
62
|
+
3. If an org-wide cap is exceeded, the sum is infeasible as written; reduce total per
|
|
63
|
+
[allocation-policy] until every org-wide cap holds. The reduced allocation is the optimum.
|
|
64
|
+
4. Verify the unit-test floors (d) and the multiple-of-4 rule after any reduction. When
|
|
65
|
+
several allocations tie at the maximum total, [allocation-policy] selects the unique one.
|
|
66
|
+
|
|
67
|
+
WHY BOTH ORG-WIDE CAPS CAN BIND AT ONCE: the org-wide runner-slot cap limits total admitted, while
|
|
68
|
+
the org-wide e2e cap limits total e2e = total/4 under the ratio. If the sum of local maxima exceeds
|
|
69
|
+
the runner-slot cap by X admitted, it simultaneously exceeds the e2e cap by X/4 e2e whenever the
|
|
70
|
+
e2e cap is set to (runner-slot cap)/4. When both caps are tight against the same reduction, both
|
|
71
|
+
bind — the single reduction that fixes one fixes the other. Do not assume only one org-wide cap can
|
|
72
|
+
be binding; check both against the sum of local maxima.
|
|
73
|
+
|
|
74
|
+
COMMON MISTAKES (each is a distinct wrong answer):
|
|
75
|
+
- Reporting the sum of the per-pool local maxima as the optimum without applying the org-wide
|
|
76
|
+
caps at all.
|
|
77
|
+
- Assuming the numerically larger org-wide cap is the binding one; the binding cap depends on how
|
|
78
|
+
each cap compares to the sum of local maxima, not on which number is bigger.
|
|
79
|
+
- Treating a per-pool burst-reserve ceiling as the binding limit for a pool whose e2e cap is
|
|
80
|
+
actually lower (the e2e cap converts to a tighter admitted ceiling of 4 * e2e_cap).
|
|
81
|
+
- Matching the unit-test/e2e split to the demand ratio in [demand-forecast] instead of
|
|
82
|
+
holding the exact 3:1 ratio.
|
|
83
|
+
- Taking the org-wide reduction from a higher-priority pool instead of the lowest-priority one.
|
|
84
|
+
- id: sla-definitions
|
|
85
|
+
type: spec
|
|
86
|
+
label: Class and cap semantics
|
|
87
|
+
content: |
|
|
88
|
+
UNIT-TEST jobs are latency-sensitive PR-feedback jobs; E2E-SUITE jobs are deferrable bulk
|
|
89
|
+
verification runs. The exact 3:1 unit:e2e ratio is a hard downstream fan-out invariant: each
|
|
90
|
+
admitted e2e suite triggers exactly three unit-shard verification jobs downstream, so any deviation
|
|
91
|
+
breaks a contract with the downstream system — a pool MUST admit unit-test and e2e jobs in a 3:1
|
|
92
|
+
ratio, never merely "at least" 3:1.
|
|
93
|
+
BURST RESERVE is the fraction of a pool's physical slots that must stay unused as headroom for
|
|
94
|
+
urgent hotfix pipelines; it caps admitted_p but says nothing about the class split.
|
|
95
|
+
A per-pool E2E CAP is a ceiling on that pool's e2e concurrency imposed by a pool-local
|
|
96
|
+
browser/device-emulator fleet; it caps e_p only. Because admitted_p = 4 * e_p under the ratio, an
|
|
97
|
+
e2e cap of K limits admitted_p to 4K.
|
|
98
|
+
The ORG-WIDE E2E CAP is a separate shared downstream limit on total e2e across all pools; the
|
|
99
|
+
ORG-WIDE RUNNER-SLOT CAP is the shared fleet ceiling on total admitted. These are independent:
|
|
100
|
+
either can bind first depending on the numbers.
|
|
101
|
+
The UNIT-TEST FLOOR guarantees a minimum unit-test presence per pool for bounded PR feedback; it
|
|
102
|
+
is a lower bound on u_p.
|
|
103
|
+
CONSEQUENCE OF A RATIO VIOLATION: because each admitted e2e suite fans out to exactly three
|
|
104
|
+
unit-shard jobs downstream, admitting, say, 250 unit-test and 70 e2e (a 25:7 ratio) leaves
|
|
105
|
+
downstream work provisioned for 3*70 = 210 unit-shard jobs against 250 admitted — a contract
|
|
106
|
+
breach in both directions. A proposal is therefore infeasible the moment any pool's split is not
|
|
107
|
+
exactly 3:1, regardless of whether its totals fit the caps. Likewise a pool's admitted amount
|
|
108
|
+
must be a multiple of 4, since admitted = 4 * e2e under the ratio; an admitted amount that is
|
|
109
|
+
not a multiple of 4 cannot hold an exact 3:1 split at integer granularity.
|
|
110
|
+
- id: region-caps
|
|
111
|
+
type: table
|
|
112
|
+
label: Per-pool limits
|
|
113
|
+
content: |
|
|
114
|
+
pool | physical slots (jobs/hour) | burst reserve % (must stay unused) | usable_p = physical*(1-reserve) | e2e_cap_p (max e_p) | unit_floor_p (min u_p) | queue backlog % | p95 queue-wait target ms | cost per slot-hour
|
|
115
|
+
pool-large | 800 | 5 | 760 | 120 | 100 | 88 | 120 | 1.0
|
|
116
|
+
pool-standard | 600 | 5 | 570 | 100 | 100 | 91 | 140 | 1.1
|
|
117
|
+
pool-arm | 500 | 5 | 475 | 90 | 100 | 79 | 160 | 1.3
|
|
118
|
+
note: usable_p is a ceiling on admitted_p; e2e_cap_p is a ceiling on e_p only. The last three
|
|
119
|
+
columns (queue backlog, p95 queue-wait target, cost per slot-hour) are operational context and do
|
|
120
|
+
NOT enter the constraints; they are provided to tempt over-fitting and should not affect the
|
|
121
|
+
allocation.
|
|
122
|
+
- id: global-limits
|
|
123
|
+
type: config
|
|
124
|
+
label: Org-wide caps
|
|
125
|
+
content: |
|
|
126
|
+
org_runner_slot_cap: 1200 # jobs/hour, total admitted across all pools
|
|
127
|
+
org_e2e_cap: 300 # jobs/hour, sum of e2e admitted across all pools
|
|
128
|
+
org_unit_cap: 1000 # jobs/hour, sum of unit-test admitted across all pools
|
|
129
|
+
org_ratio_unit_to_e2e: "3:1" # implied by per-pool 3:1
|
|
130
|
+
admitted_multiple_of: 4 # each pool's admitted_p must be a multiple of 4
|
|
131
|
+
note: the org-wide unit cap (1000) is provided for completeness; the admitted unit-test
|
|
132
|
+
total is well under it in every scenario in this task, so it never binds. Determine for yourself
|
|
133
|
+
which of the runner-slot and e2e caps actually bind.
|
|
134
|
+
- id: allocation-policy
|
|
135
|
+
type: spec
|
|
136
|
+
label: Optimization and tie-break policy
|
|
137
|
+
content: |
|
|
138
|
+
1. First maximize total admitted subject to all constraints in [capacity-model].
|
|
139
|
+
2. Pool priority for retaining jobs, highest to lowest: pool-large, then pool-standard, then
|
|
140
|
+
pool-arm.
|
|
141
|
+
3. If satisfying the org-wide caps requires reducing total below the sum of per-pool maxima,
|
|
142
|
+
remove admitted jobs from the LOWEST-priority pool first, in multiples of 4 (to keep
|
|
143
|
+
that pool's 3:1 ratio), moving up the priority order only if a pool reaches zero, until
|
|
144
|
+
every org-wide cap holds. Remove the smallest number of multiples of 4 that makes all org-wide
|
|
145
|
+
caps hold.
|
|
146
|
+
4. The per-pool maximum (before org-wide reduction) is the largest multiple of 4 that satisfies
|
|
147
|
+
that pool's burst reserve and e2e cap simultaneously.
|
|
148
|
+
ILLUSTRATIVE tie-break (invented numbers, not this task's caps): if the local maxima were
|
|
149
|
+
200 / 160 / 120 (sum 480) and the org-wide runner-slot cap were 448, the excess is 32; remove 32
|
|
150
|
+
(a multiple of 4) from the lowest-priority pool, 120 -> 88, giving 200 / 160 / 88 = 448. Only
|
|
151
|
+
the lowest pool is touched because the higher pools have priority to retain their jobs.
|
|
152
|
+
EDGE RULES:
|
|
153
|
+
- A reduction never changes a pool's 3:1 ratio: removing a multiple of 4 removes 3 unit-test
|
|
154
|
+
and 1 e2e per unit, preserving the split.
|
|
155
|
+
- A reduction may not push a pool below its unit-test floor; if the lowest-priority pool
|
|
156
|
+
would be reduced past its floor, continue the reduction in the next pool up the priority
|
|
157
|
+
order. (Not triggered in this task, but part of the policy.)
|
|
158
|
+
- When one reduction satisfies both org-wide caps at once, apply it once; do not double-count the
|
|
159
|
+
runner-slot and e2e excess as two separate reductions.
|
|
160
|
+
- The chosen allocation is the unique maximum-total allocation reachable by this procedure;
|
|
161
|
+
there is exactly one correct answer per scenario.
|
|
162
|
+
- id: planner-proposals
|
|
163
|
+
type: table
|
|
164
|
+
label: Candidate schedules
|
|
165
|
+
content: |
|
|
166
|
+
proposal | pool-large (u/e) | pool-standard (u/e) | pool-arm (u/e) | total | author's rationale
|
|
167
|
+
Alpha | 360 / 120 | 300 / 100 | 270 / 90 | 1240 | "fill every pool to its own local maximum"
|
|
168
|
+
Beta | 360 / 120 | 300 / 100 | 250 / 70 | 1200 | "trim pool-arm to hit 1200 total"
|
|
169
|
+
Gamma | 375 / 125 | 300 / 100 | 225 / 75 | 1200 | "shift a little extra e2e into pool-large, the cheapest pool"
|
|
170
|
+
- id: proposed-change
|
|
171
|
+
type: diff
|
|
172
|
+
label: Proposed cap changes
|
|
173
|
+
content: |
|
|
174
|
+
Scenario S1 (evaluate independently of S2):
|
|
175
|
+
- org_runner_slot_cap: 1200 (unchanged)
|
|
176
|
+
- org_e2e_cap: 300 -> 340
|
|
177
|
+
rationale: "the browser-grid vendor raised our shared contract, so we can admit more e2e."
|
|
178
|
+
Scenario S2 (evaluate independently of S1):
|
|
179
|
+
- org_runner_slot_cap: 1200 -> 1260
|
|
180
|
+
- org_e2e_cap: 300 -> 340
|
|
181
|
+
rationale: "we also added runner fleet capacity, so raise the runner-slot cap too."
|
|
182
|
+
Per-pool limits in [region-caps] are unchanged in both scenarios; only the named org-wide caps
|
|
183
|
+
move.
|
|
184
|
+
- id: demand-forecast
|
|
185
|
+
type: table
|
|
186
|
+
label: Queued demand forecast
|
|
187
|
+
content: |
|
|
188
|
+
pool | unit-test demand | e2e demand | total demand | week-over-week trend
|
|
189
|
+
pool-large | 700 | 260 | 960 | +4%
|
|
190
|
+
pool-standard | 520 | 180 | 700 | +2%
|
|
191
|
+
pool-arm | 430 | 150 | 580 | +9%
|
|
192
|
+
note: queued demand in every pool and class exceeds what the caps allow, so demand is NOT the
|
|
193
|
+
binding limit anywhere, and the trend column is context only. Demand ratios are not 3:1 (e.g.
|
|
194
|
+
pool-large is 700:260), but admitted jobs must still satisfy the exact 3:1 ratio regardless of
|
|
195
|
+
demand shape. Do not allocate to demand; allocate to the caps and the ratio.
|
|
196
|
+
tags: [optimization, capacity, integer-programming, constraints, ratios]
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
id: constraint-deployment-policy
|
|
2
|
+
version: 2.0.0
|
|
3
|
+
category: reasoning
|
|
4
|
+
cluster: constraint-reconciliation
|
|
5
|
+
difficulty: expert
|
|
6
|
+
title: Reconciling Four Tiers of Deployment Policy for a Regulated Release
|
|
7
|
+
summary: >-
|
|
8
|
+
Decide whether a regulated financial-data release may ship on a Friday, compute the exact permitted
|
|
9
|
+
deployment shape and the earliest and latest compliant start times, and evaluate a proposed
|
|
10
|
+
emergency-compression exception, across four priority-ordered policy tiers with buried clauses.
|
|
11
|
+
prompt: |
|
|
12
|
+
Release R51 wants to ship. Resolve its request against a four-tier policy stack whose precedence is
|
|
13
|
+
in [policy-precedence]: security controls [security-controls] outrank compliance controls
|
|
14
|
+
[compliance-controls], which outrank product policies, which outrank operations preferences (both in
|
|
15
|
+
[product-ops-policies]). The request is [release-request]. Use [business-calendar] for dates and the
|
|
16
|
+
close window, [residency-token] for the eu-west gate, and [proposed-exception] for deliverable 4.
|
|
17
|
+
|
|
18
|
+
All times are UTC. Answer every deliverable; each requires combining rules from at least three
|
|
19
|
+
artifacts and doing the date/time arithmetic.
|
|
20
|
+
|
|
21
|
+
1. Can it ship as requested? State whether R51 may ship on Friday 2026-03-13, and specifically
|
|
22
|
+
whether it may ship in the exact form requested (start 17:30 UTC, full 100% rollout). If not, say
|
|
23
|
+
what about the request is impermissible.
|
|
24
|
+
2. Permitted shape and earliest start. Give the exact permitted deployment shape (stages and minimum
|
|
25
|
+
durations) and the earliest compliant start time, with the time each stage and 100% is reached,
|
|
26
|
+
including the responder and residency conditions that must hold.
|
|
27
|
+
3. Blocking rules. Name the specific rule id(s) that block the requested plan and show the arithmetic
|
|
28
|
+
(in particular the change-record timing and the rollout-shape rule).
|
|
29
|
+
4. Emergency compression. Evaluate the proposal in [proposed-exception] to invoke the emergency
|
|
30
|
+
compression to hit 17:30. Is it valid? If R51 used it, what would still block the plan?
|
|
31
|
+
5. Latest compliant start. Give the latest compliant start time and name the single rule that binds
|
|
32
|
+
it. State explicitly why it is that rule and not the product deadline.
|
|
33
|
+
artifacts:
|
|
34
|
+
- id: policy-precedence
|
|
35
|
+
type: spec
|
|
36
|
+
label: Policy precedence
|
|
37
|
+
content: |
|
|
38
|
+
Four tiers, highest to lowest: SECURITY, then COMPLIANCE, then PRODUCT, then OPERATIONS.
|
|
39
|
+
- A higher-tier rule overrides a lower-tier rule ONLY where they directly conflict. A direct
|
|
40
|
+
conflict means the two rules cannot both be satisfied by any single plan.
|
|
41
|
+
- Rules within the same tier are cumulative (all apply) unless they are jointly impossible, in
|
|
42
|
+
which case the release cannot ship in that form.
|
|
43
|
+
- A lower-tier PREFERENCE never prohibits an action that all higher tiers permit; it only
|
|
44
|
+
expresses what to avoid when there is a compliant choice. A preference cannot, by itself,
|
|
45
|
+
make a plan non-compliant.
|
|
46
|
+
A release is permitted iff it satisfies every SECURITY and COMPLIANCE control and the binding
|
|
47
|
+
PRODUCT requirements; OPERATIONS items are honored only when they do not force a higher-tier
|
|
48
|
+
requirement to be missed.
|
|
49
|
+
WORKED READING: if OPERATIONS says "avoid X" but a binding PRODUCT requirement can only be met by
|
|
50
|
+
doing X, then X is permitted and the operations item is noted-but-overridden, not a blocker. If
|
|
51
|
+
two SECURITY controls cannot both hold, no plan ships. When several compliant start times exist,
|
|
52
|
+
choose per the deliverable asked (earliest vs latest); do not treat a preference as narrowing the
|
|
53
|
+
compliant window.
|
|
54
|
+
DEFINITIONS:
|
|
55
|
+
- A "binding PRODUCT requirement" is a PRODUCT rule stated as a requirement (P1), not a
|
|
56
|
+
preference (P2). Binding requirements can override lower-tier preferences; preferences at any
|
|
57
|
+
tier never override anything.
|
|
58
|
+
- "Directly conflict" is strict: two rules conflict only if no single plan satisfies both. Two
|
|
59
|
+
rules that merely point in different directions but admit a common plan do NOT conflict, and
|
|
60
|
+
both must be satisfied.
|
|
61
|
+
- Where a lower-tier preference happens to agree with the compliant plan, it is satisfied
|
|
62
|
+
incidentally; where it disagrees, it is overridden. Either way it never changes whether the
|
|
63
|
+
release is permitted.
|
|
64
|
+
ORDER OF EVALUATION: establish the SECURITY-required shape, then intersect the COMPLIANCE timing
|
|
65
|
+
windows, then confirm the binding PRODUCT deadline is met, and only then note which OPERATIONS
|
|
66
|
+
preferences are honored or overridden. A plan is compliant iff a non-empty start-time window
|
|
67
|
+
survives the SECURITY and COMPLIANCE steps and meets P1.
|
|
68
|
+
- id: security-controls
|
|
69
|
+
type: spec
|
|
70
|
+
label: Security controls (highest tier)
|
|
71
|
+
content: |
|
|
72
|
+
S1. A service handling regulated financial data must deploy as a staged canary: 5% held for at
|
|
73
|
+
least 60 minutes, then 25% held for at least 60 minutes, then 100%. The only permitted stage
|
|
74
|
+
percentages are 5, 25, and 100. "Held for at least N minutes" means the stage's traffic share
|
|
75
|
+
is maintained continuously for >= N minutes before advancing; advancing between stages is
|
|
76
|
+
instantaneous. A direct full (100%) rollout in one step is prohibited for such services, as
|
|
77
|
+
is any reordering or omission of the 5% and 25% stages.
|
|
78
|
+
S2. A staffed security responder — a named on-call engineer actively monitoring the rollout —
|
|
79
|
+
must be online for the entire rollout window (from the 5% start until 100% is reached) AND
|
|
80
|
+
for 1 hour after 100% is reached.
|
|
81
|
+
S3. Any deployment to eu-west requires a data-residency review token that is valid at the deploy
|
|
82
|
+
start instant (the 5% start). An expired or not-yet-valid token blocks the eu-west portion.
|
|
83
|
+
S4. The S1 staging MAY be compressed to a single 10% step held for at least 30 minutes, but ONLY
|
|
84
|
+
for a release that the on-call security lead has classified, in writing and before the
|
|
85
|
+
deploy start, as an emergency-hotfix. This exception applies to nothing else and does not
|
|
86
|
+
alter any COMPLIANCE control.
|
|
87
|
+
S5. A validated rollback plan that can be executed within 5 minutes at any stage must be attached
|
|
88
|
+
before start. (A capability requirement, not a timing constraint.)
|
|
89
|
+
S6. Every stage transition of a regulated deploy must emit a signed audit event. (Satisfied by
|
|
90
|
+
the deploy tooling automatically; not a timing constraint.)
|
|
91
|
+
NOTE ON S1 MECHANICS: the three stages are sequential and non-overlapping. The minimum elapsed
|
|
92
|
+
time from the 5% start to the 100% start is therefore 60 + 60 = 120 minutes, achieved only if
|
|
93
|
+
each hold runs exactly its minimum. A slower rollout (longer holds) is allowed by S1 but pushes
|
|
94
|
+
the 100% time later, which interacts with the COMPLIANCE deadline in C2. The responder in S2 is a
|
|
95
|
+
single named engineer for the whole window; no responder handoff is scheduled on 2026-03-13
|
|
96
|
+
outside the O2 coverage.
|
|
97
|
+
- id: compliance-controls
|
|
98
|
+
type: spec
|
|
99
|
+
label: Compliance controls (second tier)
|
|
100
|
+
content: |
|
|
101
|
+
C1. A regulated service may not deploy during the monthly close window. The close window is the
|
|
102
|
+
last two BUSINESS days of a month plus the first business day of the following month. A
|
|
103
|
+
business day is Monday-Friday excluding holidays (there are no holidays in the relevant
|
|
104
|
+
range). A deploy is placed in a window by its START date.
|
|
105
|
+
C2. Any eu-west deployment must reach 100% no later than 21:00 UTC (inclusive) on a business day.
|
|
106
|
+
"Reach 100%" is the instant the 100% stage begins.
|
|
107
|
+
C3. A change record must be filed at least 24 wall-clock hours before the deploy start time. The
|
|
108
|
+
change record's filed timestamp is authoritative; 24 wall-clock hours is measured on the
|
|
109
|
+
clock, not in business hours.
|
|
110
|
+
C4. A rollback plan must be attached to the change record. (Satisfied when S5's plan is filed
|
|
111
|
+
with the record.)
|
|
112
|
+
C5. The change record must name an approver from the change-advisory board. (Satisfied by the
|
|
113
|
+
board approval on the record.)
|
|
114
|
+
CLOSE-WINDOW COMPUTATION (C1): identify the last two business days of the month from
|
|
115
|
+
[business-calendar] (skip weekend days), then add the first business day of the following month.
|
|
116
|
+
The window is those three dates. A start date outside all three is not in the close window. Note
|
|
117
|
+
that the close window is anchored to month boundaries, not to the calendar midpoint, so a
|
|
118
|
+
mid-month Friday is not automatically inside or outside it — you must compute the actual dates.
|
|
119
|
+
DEADLINE ARITHMETIC (C3): earliest permitted start = change-record filed timestamp + exactly 24
|
|
120
|
+
hours. A start even one minute earlier than that is non-compliant.
|
|
121
|
+
- id: product-ops-policies
|
|
122
|
+
type: spec
|
|
123
|
+
label: Product requirements and operations preferences
|
|
124
|
+
content: |
|
|
125
|
+
PRODUCT (third tier, binding requirements):
|
|
126
|
+
P1. Contractual availability requires R51 to BEGIN rollout (the 5% start) no later than Friday
|
|
127
|
+
2026-03-13 20:00 UTC.
|
|
128
|
+
P2. Prefer to reach 100% on the same calendar day as the start. (A product preference.)
|
|
129
|
+
OPERATIONS (fourth tier, preferences only):
|
|
130
|
+
O1. Avoid production changes on Fridays after 16:00 UTC.
|
|
131
|
+
O2. Security responder on-call coverage on Friday 2026-03-13 is 16:00-22:30 UTC (responder
|
|
132
|
+
"SecOncall-3"). No responder is scheduled outside that window that day.
|
|
133
|
+
O3. EU change-control staffing is available 08:00-21:00 UTC on weekdays.
|
|
134
|
+
O4. Prefer deploys during business hours 09:00-17:00 UTC when possible.
|
|
135
|
+
O5. A batch-analytics freeze runs 22:00-02:00 UTC; avoid overlapping deploys with it.
|
|
136
|
+
Note: O1, O4, and O5 are preferences and cannot by themselves prohibit a release; O2 and O3 are
|
|
137
|
+
staffing facts that constrain feasibility only insofar as a higher-tier rule requires staffing
|
|
138
|
+
that must fall inside them.
|
|
139
|
+
- id: release-request
|
|
140
|
+
type: note
|
|
141
|
+
label: Release request R51
|
|
142
|
+
content: |
|
|
143
|
+
Release: R51, service "ledger-api" (classification: regulated financial data).
|
|
144
|
+
Target regions: us-east and eu-west (single coordinated rollout; both regions advance together).
|
|
145
|
+
Desired start: Friday 2026-03-13, 17:30 UTC.
|
|
146
|
+
Desired shape: full 100% rollout in one step.
|
|
147
|
+
Change record: CR-8841, filed 2026-03-12, 18:00 UTC.
|
|
148
|
+
Change-advisory-board approval: granted 2026-03-12, 19:10 UTC.
|
|
149
|
+
Data-residency review token presented: eu-res-2231.
|
|
150
|
+
Emergency-hotfix classification by on-call security lead: none requested, none on file.
|
|
151
|
+
Rollback plan: validated, executable in ~3 minutes at every stage, attached to CR-8841.
|
|
152
|
+
Build artifact hash: 9f4c-ledgerapi-r51. Prior deploy attempts for R51: none.
|
|
153
|
+
Deploy tooling supports exactly two shapes: the 5/25/100 staged canary, or a single-step 100%.
|
|
154
|
+
- id: business-calendar
|
|
155
|
+
type: table
|
|
156
|
+
label: March-April 2026 calendar (this scenario)
|
|
157
|
+
content: |
|
|
158
|
+
In this scenario the weekends of March 2026 fall on the 7th-8th, 14th-15th, 21st-22nd, and
|
|
159
|
+
28th-29th; every other day is a business day, and there are no holidays in March or early April.
|
|
160
|
+
date | weekday | business day?
|
|
161
|
+
2026-03-12 | Thursday | yes
|
|
162
|
+
2026-03-13 | Friday | yes
|
|
163
|
+
2026-03-14 | Saturday | no
|
|
164
|
+
2026-03-15 | Sunday | no
|
|
165
|
+
2026-03-16 | Monday | yes
|
|
166
|
+
2026-03-27 | Friday | yes
|
|
167
|
+
2026-03-28 | Saturday | no
|
|
168
|
+
2026-03-29 | Sunday | no
|
|
169
|
+
2026-03-30 | Monday | yes
|
|
170
|
+
2026-03-31 | Tuesday | yes
|
|
171
|
+
2026-04-01 | Wednesday | yes
|
|
172
|
+
2026-04-02 | Thursday | yes
|
|
173
|
+
Compute the close window from C1 using this calendar. EU change-control staffing (O3) is the same
|
|
174
|
+
08:00-21:00 UTC on every business day shown.
|
|
175
|
+
- id: residency-token
|
|
176
|
+
type: config
|
|
177
|
+
label: Data-residency review token
|
|
178
|
+
content: |
|
|
179
|
+
token_id: eu-res-2231
|
|
180
|
+
scope: eu-west (data-residency review for regulated financial data)
|
|
181
|
+
issued_by: data-governance-office
|
|
182
|
+
approved_by: dpo-review-board
|
|
183
|
+
valid_from: 2026-03-01 00:00 UTC
|
|
184
|
+
valid_until: 2026-03-31 23:59 UTC
|
|
185
|
+
status: approved
|
|
186
|
+
check_point: evaluated at the deploy start instant (the 5% start); must be within [valid_from,
|
|
187
|
+
valid_until] at that instant.
|
|
188
|
+
conditions: none beyond the validity window.
|
|
189
|
+
- id: proposed-exception
|
|
190
|
+
type: note
|
|
191
|
+
label: Proposed emergency compression
|
|
192
|
+
content: |
|
|
193
|
+
Proposal from the release team, attached to R51:
|
|
194
|
+
"To hit the 17:30 UTC start, invoke S4 and deploy R51 as a single 10% step held 30 minutes,
|
|
195
|
+
then go to 100%. This lets us start earlier and finish faster, and it satisfies security
|
|
196
|
+
because 10% is still a canary."
|
|
197
|
+
The team argues the release is 'urgent enough' to count as an emergency. However, no emergency-
|
|
198
|
+
hotfix classification has been requested from or granted by the on-call security lead, and R51 is
|
|
199
|
+
a scheduled feature release, not a hotfix. The team also floated 'just start the eu-west portion
|
|
200
|
+
after 21:00 to buy time' and 'skip the residency token since it is basically always approved' as
|
|
201
|
+
fallbacks. Evaluate the emergency-compression proposal on its merits against [security-controls]
|
|
202
|
+
and [compliance-controls].
|
|
203
|
+
tags: [policy, deployment, precedence, scheduling, compliance, canary]
|