WHAT the words mean: "merge frequently + auto build + auto test" is exactly the definition of Continuous Integration (CI). Delivery and Deployment are about producing/shipping an artifact, which is not happening here.
Answer: CI (Continuous Integration).
Recall Solution 1.2
GitHub Actions: Workflow ➜ Job ➜ Step.
GitLab CI: Pipeline ➜ Stage ➜ Job.
WHY watch out: the word "Job" sits at different depths in the two systems. In GitLab a Stage groups Jobs; in GitHub a Job groups Steps.
Recall Solution 1.3
WHY this order: cheapest-and-fastest-to-fail goes first so you never pay for slow work when a 2-second check already proves the code is broken (the "shift-left" idea).
Answer: Build → Lint → Test → Package → Deploy.
Mnemonic from the parent note: Be Lazy, Test, Package, Deploy.
WHAT: stages run sequentially — each waits for the previous to pass — so we simply add.
WHY add (not max): they are dependent, so no overlap is possible.
T=4+9+2=15 min.
Recall Solution 2.2
WHY parallel: the 6 shards are independent, so the only limit is runner availability.
Waves:⌈n/m⌉=⌈6/3⌉=2 waves. Each wave costs one t.
Tparallel=t⌈mn⌉=5×2=10 min.
Look at figure s01: 3 runners chew through 3 shards per wave, so 6 shards = exactly 2 clean waves.
Recall Solution 2.3
WHAT: caching swaps the repeated, deterministic install d for a cheap restore c.
(a) Tserial=n⋅t=8×3=24 min.
(b) Waves =⌈8/4⌉=2, so Tparallel=3×2=6 min. Speedup S=24/6=4×.
(c) With m=5: waves =⌈8/5⌉=2 still, so Tparallel=3×2=6 min — no change.
WHY no change:8 jobs on 5 runners is one full wave of 5 plus a leftover wave of 3; that leftover wave still costs a whole t. See figure s02 — the total-time curve is flat until you reach m=n=8.
Recall Solution 3.2
WHAT is the minimum: the fastest you can ever go is one wave, T=t=3 min, reached when ⌈8/m⌉=1, i.e. m≥n=8.
Smallest such m:m=8.
WHY not m=7:⌈8/7⌉=2 waves → 6 min, still not minimal.
So more runners help only up to m=n — the Amdahl-style cap (Amdahl's Law).
Recall Solution 3.3
WHY Test is skipped: stages run sequentially with fail-fast — if an earlier stage fails, later stages are skipped, not run. So Test being "skipped" means an earlier stage went red.
Which stage: the Lint / static-analysis stage (it runs before Test). The fix is to read the earliest red stage, not the most visible one. "Passes on my laptop" is irrelevant because the failing stage isn't Test at all.
Build and Deploy are sequential single-job stages, so they always add: 6+…+3.
(a) Serial Test =10×4=40. Total =6+40+3=49 min.
(b) Parallel Test waves =⌈10/5⌉=2 → 4×2=8 min. Total =6+8+3=17 min.
(c) Fastest Test = one wave, needs m≥n=10. Then Test =4 min. Total =6+4+3=13 min.
WHY the floor is 13, not lower: Build (6) and Deploy (3) are serial and cannot be parallelised here — they set a hard floor of 6+3=9 min plus at least one Test wave of 4.
Recall Solution 4.2
WHAT: each shard saves d−c per run; there are 10 shards and k=12 runs.
Saved=k×10×(d−c)=12×10×(90−15)=120×75=9000 s=150 min.WHY cache: dependency install is repeated, deterministic and large — the textbook memoization candidate (Docker & Containerization caches layers the same way).
WHAT: even with infinite runners, the parallel part shrinks toward 0 but the serial part stays fixed.
(a) Minimum total =serial part=15 min (parallel part →0 in the ideal limit).
(b) Max speedup =T1/Tmin=60/15=4×.
WHY capped: this is Amdahl's Law — the serial fraction 6015=0.25 sets a hard ceiling; speedup can never exceed 1/0.25=4× no matter how many runners you add. Figure s03 shows the curve flattening toward the 15-min floor.
Recall Solution 5.2
Budget for Test:20−9=11 min available. Each wave costs t=2 min, so we may afford at most ⌊11/2⌋=5 waves (5 waves =10≤11; 6 waves =12>11).
Waves needed:⌈30/m⌉≤5⇒30/m≤5⇒m≥6.
Check m=6:⌈30/6⌉=5 waves =10 min. Total =9+10=19≤20. ✓
Check m=5:⌈30/5⌉=6 waves =12 min. Total =9+12=21>20. ✗
Answer: m=6 runners.
Recall Solution 5.3
Why it feels right: the job genuinely needs the value, and the YAML is the config the job reads.
Why it is unsafe: the YAML is committed to the repo, so the secret lives in git history forever, readable by anyone who ever clones — even after you "delete" it.
Fix: store it in the platform secret store (GitHub: ${{ secrets.API_KEY }}; GitLab: masked CI/CD variable). The runner injects it at run time; it never touches version control. See Version Control & Git Branching on why history is immutable.
DevOps Principles & Shift-Left — the philosophy behind "cheapest-fails-first" ordering.
Recall Self-test summary
Serial stages add ::: T=∑ti
Parallel jobs in one stage ::: T=t⌈n/m⌉
Runners stop helping when ::: m≥n (one wave, T=t)
Cache saving per run ::: d−c
Amdahl max speedup ::: 1/(serial fraction), e.g. 1/0.25=4×