[CompatGuard] RISKY: Env.SENDGRID_API_KEY removed from .env.example — coordinate migration before MR !4 merges
## CompatGuard Owner Issue — Contract 3
**Severity:** 🟠 RISKY (breaking for active consumers)
**MR:** [!4 — Proof: dynamic OSS contract gate](https://gitlab.com/gitlab-ai-hackathon/transcend/34816704/-/merge_requests/4)
**Pipeline:** [#2623964361](https://gitlab.com/gitlab-ai-hackathon/transcend/34816704/-/pipelines/2623964361)
**Owners notified:** `@notifications`, `@platform`
---
### What broke
`samples/shopstack/head/.env.example` removes `SENDGRID_API_KEY` with no migration comment and no replacement key. Two consumers fail:
| Consumer | Owner | Kind | Failure mode |
|---|---|---|---|
| `api/emailService.ts` | `@notifications` | runtime | `process.env.SENDGRID_API_KEY` → `undefined`; SendGrid client broken; all transactional email fails silently or at startup |
| `.gitlab-ci.yml` | `@platform` | pipeline | Notification smoke test runs with undefined key (false-negative pass) or fails if operators follow updated `.env.example` |
> **Env contract semantics:** `.env.example` is the deployment-time contract. Removing a key signals to operators and deployment tooling that the variable is no longer required. Any environment that follows the example and removes the key will break the runtime service. Any environment that does not remove it will have a dangling variable. Neither outcome is safe without explicit migration coordination.
### Prior incident
> 🟠 **Pipeline `#5521`** — *Notification smoke tests failed after SendGrid env rename* — MEDIUM severity
> This project's deployment tooling does not handle silent env key removal gracefully. The prior failure shows both the CI smoke test and the runtime service broke when this key was renamed without coordination.
> Prior pipeline URL: `https://gitlab.example/shopstack/-/pipelines/5521`
### Dynamic replay result
Both probes **FAILED**:
- Probe 3-A: `SENDGRID_API_KEY` not in `{ DATABASE_URL, BILLING_WEBHOOK_SECRET }` → ❌ (runtime email broken)
- Probe 3-B: Same → ❌ (CI smoke test fails or false-negative pass)
### Required actions (P1 — must complete before MR !4 merges)
- [ ] `@notifications` — Restore `SENDGRID_API_KEY` in `.env.example` with a migration comment (e.g., `# Coordinate removal with @notifications and @platform before deleting`); add startup/config validation that fails fast if the key is absent
- [ ] `@platform` — Confirm CI variable `SENDGRID_API_KEY` is retained in pipeline settings until `@notifications` completes migration; agree on a coordinated removal date
### Suggested tests
```bash
# One-liner gate (run in CI before merge):
grep -q "^SENDGRID_API_KEY=" samples/shopstack/head/.env.example \
&& echo "PASS" || { echo "FAIL — pipeline #5521 repeat risk"; exit 1; }
# CI config reference check:
grep -q "SENDGRID_API_KEY" .gitlab-ci.yml \
&& echo "PASS" || { echo "FAIL — CI variable reference missing"; exit 1; }
npx jest tests/compat/env.sendgrid.test.ts tests/compat/ci.sendgrid.test.ts --no-coverage
```
Minimum assertions:
```ts
it("SENDGRID_API_KEY is present and uncommented in .env.example", () => {
const lines = envExample.split("\n").filter(l => !l.startsWith("#"));
expect(lines.some(l => l.startsWith("SENDGRID_API_KEY="))).toBe(true);
});
it("SENDGRID_API_KEY has a non-empty example value", () => {
const line = lines.find(l => l.startsWith("SENDGRID_API_KEY="));
expect(line.split("=")[1].trim()).not.toBe("");
});
```
### Orbit graph gaps (follow-up)
- `api/emailService.ts` and `.gitlab-ci.yml` are absent from the Orbit `owners` flat dict — add owner annotations for `@notifications` and `@platform`
- No pipeline entries for `api/emailService.ts` in the Orbit `pipelines` dict — index against integration/smoke test pipeline
---
*Auto-created by CompatGuard MR Gatekeeper · Pipeline #2623964361 · Commit 84728869*
issue