|
| 1 | +# SPC Extraction Playbook (Shadow Repo ➜ Canonical) |
| 2 | + |
| 3 | +End‑to‑end guidance for spinning up a shadow repository for `@nhs-fdp/spc`, validating it in parallel with the monorepo, and promoting it to the canonical source once readiness gates are met. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## 1. Objectives |
| 8 | + |
| 9 | +| Goal | Why it matters | |
| 10 | +|------|----------------| |
| 11 | +| Isolate SPC release cadence | Ship SPC fixes/features without full design-system release overhead | |
| 12 | +| Maintain reversibility | Shadow phase keeps monorepo as source of truth until adoption proves value | |
| 13 | +| Enforce quality gates | Prevent silent export breaks and bundle bloat pre‑extraction | |
| 14 | +| Provide clean history | Optional subtree split for auditable evolution | |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## 2. Readiness Prerequisites (Monorepo) |
| 19 | + |
| 20 | +All should be green/stable before starting the shadow repo: |
| 21 | + |
| 22 | +- `npm run spc:validate` PASS (build, SSR, export diff, size, CSS artifact) |
| 23 | +- Export surface snapshot established |
| 24 | +- Bundle gzip baseline recorded (`index.esm.js` & `spc.css`) |
| 25 | +- Alias convergence complete (only root `@/` in barrels) |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## 3. Phase 1 – Shadow Repo Creation (Now) |
| 30 | + |
| 31 | +1. Create new private repo: `nhs-fdp-spc` (enterprise template: CODEOWNERS, Dependabot, branch protection). |
| 32 | +2. Choose content import strategy: |
| 33 | + - Simple copy (fast): copy `packages/nhs-fdp-spc/` plus LICENSE & README. |
| 34 | + - History preserving: subtree split (see Appendix A) of `packages/nhs-fdp-spc` (+ optionally SPC source directories once internalised). |
| 35 | +3. Add minimal files (if copy strategy): |
| 36 | + - `package.json` (scoped name, repository, bugs, homepage, exports, types) |
| 37 | + - `README.md`, `CHANGELOG.md`, `LICENSE`, `CODE_OF_CONDUCT.md` (if needed) |
| 38 | +4. Set version to `0.0.0-alpha.0` (pre‑release tag only). |
| 39 | +5. Configure `.npmrc` (GitHub Packages) & add publish tokens as repo secrets. |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +## 4. Phase 2 – Shadow CI Workflows |
| 44 | + |
| 45 | +Recommended single workflow (or split): |
| 46 | + |
| 47 | +| Job | Scripts | Purpose | |
| 48 | +|-----|---------|---------| |
| 49 | +| install | `npm ci` | Deterministic dependencies | |
| 50 | +| build | `npm run build:spc` | JS + CSS integrity | |
| 51 | +| validate | `npm run spc:validate` | Gates: size, SSR, exports, CSS | |
| 52 | +| exports-check | `npm run spc:exports:check` | Prevent accidental removals | |
| 53 | +| adoption-report (optional early) | (n/a – runs only in monorepo) | Not needed once extracted | |
| 54 | +| test (optional) | `npm test` (if unit subset copied) | Lock behaviour early | |
| 55 | +| publish (manual dispatch) | `npm publish --tag alpha` | Dry-run releases | |
| 56 | + |
| 57 | +Artifacts / outputs: |
| 58 | + |
| 59 | +- Upload dist (optional) for inspection. |
| 60 | +- Generate summary with gzip sizes & export delta count. |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +## 5. Phase 3 – Ongoing Sync (Until Flip) |
| 65 | + |
| 66 | +During shadow phase the monorepo stays authoritative. Keep the shadow repo updated by either: |
| 67 | + |
| 68 | +1. Manual PRs: Periodically re-copy changes from monorepo SPC package. |
| 69 | +2. Automation: A monorepo workflow triggered on `packages/nhs-fdp-spc/**` changes pushing to shadow (PAT secret). Ensure generated commits are labelled (e.g. `chore(shadow-sync): …`). |
| 70 | + |
| 71 | +Release strategy: publish only `alpha` / `beta` tags; do not mark `latest`. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## 6. Phase 4 – Readiness Gates |
| 76 | + |
| 77 | +Flip to canonical only when ALL pass: |
| 78 | + |
| 79 | +| Gate | Target | Source | |
| 80 | +|------|--------|--------| |
| 81 | +| Adoption | ≥70% of SPC import lines use `@nhs-fdp/spc` | `npm run spc:adoption` (monorepo) | |
| 82 | +| Export stability | 2 consecutive minor cycles with no breaking removals | export snapshot checks | |
| 83 | +| CI health | 100% green on build + validate + parity | shadow repo CI | |
| 84 | +| Parity completeness | Canonical numeric fixtures (XmR, T, G) unskipped | parity tests | |
| 85 | +| Size budget | gzipped ESM bundle < target (e.g. 120KB tightened) | validate output | |
| 86 | +| Documentation | Migration guide & external README finalised | docs | |
| 87 | + |
| 88 | +--- |
| 89 | + |
| 90 | +## 7. Phase 5 – Canonical Flip |
| 91 | + |
| 92 | +1. Final announcement & migration window (e.g. 4–6 weeks) posted in internal comms & CHANGELOG. |
| 93 | +2. Shadow repo publishes first stable version (e.g. `0.1.0`). |
| 94 | +3. Monorepo updates: |
| 95 | + - Replace legacy re-exports with a thin dependency on `@nhs-fdp/spc` OR mark as deprecated with console warning. |
| 96 | + - Update internal documentation to point to new repo. |
| 97 | +4. Monitor for regressions (error rate, bundle size changes in consumers). |
| 98 | +5. After window expires, remove deprecated legacy exports. |
| 99 | + |
| 100 | +Rollback (if needed): |
| 101 | + |
| 102 | +- Re-point consumers back to monorepo package version; publish patch release from monorepo including latest shadow code (subtree re-import if required). |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +## 8. Phase 6 – Post-Flip Hardening |
| 107 | + |
| 108 | +- Introduce semantic release or conventional-changelog action for automated versioning. |
| 109 | +- Tighten size budgets; track delta per PR. |
| 110 | +- Add provenance: SBOM generation & license scan (if mandated by org policy). |
| 111 | +- Consider splitting engine & UI sub-entries if adoption for pure logic emerges. |
| 112 | + |
| 113 | +--- |
| 114 | + |
| 115 | +## 9. Metrics & Reporting |
| 116 | + |
| 117 | +| Metric | Source | Action Threshold | |
| 118 | +|--------|--------|------------------| |
| 119 | +| Adoption % | `spc:adoption` | <70% → extend migration support | |
| 120 | +| Bundle size delta | CI summary | >5% increase → require justification | |
| 121 | +| Export churn | `spc:exports:check` diff count | >0 unintended → block merge | |
| 122 | +| Parity failures | parity job | Any → block release | |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +## 10. Risks & Mitigations |
| 127 | + |
| 128 | +| Risk | Mitigation | |
| 129 | +|------|-----------| |
| 130 | +| Divergent code between monorepo & shadow | Automate sync; diff on each PR | |
| 131 | +| Hidden deep imports bypassing public API | Export snapshot + codemod enforcement | |
| 132 | +| Size creep after extraction | CI size budget & trend report | |
| 133 | +| Consumer lag on migration | Early comms + codemods + adoption dashboard | |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +## Appendix A – Subtree Split (History Preservation) |
| 138 | + |
| 139 | +```bash |
| 140 | +# From monorepo root (ensure clean working tree) |
| 141 | +git checkout master |
| 142 | +git pull |
| 143 | + |
| 144 | +# 1. Create subtree branch for SPC package history only |
| 145 | +git subtree split --prefix=packages/nhs-fdp-spc -b spc-package-history |
| 146 | + |
| 147 | +# 2. (Optional) Add additional SPC source paths once isolated |
| 148 | +# Repeat subtree split for each additional path if needed |
| 149 | + |
| 150 | +# 3. Push to new (empty) shadow repo |
| 151 | +git remote add spc-origin [email protected]: <org >/nhs-fdp-spc.git |
| 152 | +git push spc-origin spc-package-history:main |
| 153 | +``` |
| 154 | + |
| 155 | +If you also want engine source history that still lives outside the package, migrate those files physically into the package in the monorepo first, then repeat the split to ensure continuity. |
| 156 | + |
| 157 | +--- |
| 158 | + |
| 159 | +## Appendix B – Minimal Shadow CI Workflow (Conceptual) |
| 160 | + |
| 161 | +```yaml |
| 162 | +name: spc-ci |
| 163 | +on: |
| 164 | + push: |
| 165 | + branches: [ main ] |
| 166 | + pull_request: |
| 167 | + branches: [ main ] |
| 168 | + |
| 169 | +jobs: |
| 170 | + build-validate: |
| 171 | + runs-on: ubuntu-latest |
| 172 | + steps: |
| 173 | + - uses: actions/checkout@v4 |
| 174 | + - uses: actions/setup-node@v4 |
| 175 | + with: |
| 176 | + node-version: 22 |
| 177 | + cache: npm |
| 178 | + - run: npm ci |
| 179 | + - run: npm run build:spc |
| 180 | + - run: npm run spc:validate |
| 181 | + - run: npm run spc:exports:check |
| 182 | + - name: Bundle summary |
| 183 | + run: | |
| 184 | + echo 'Bundle sizes:' >> $GITHUB_STEP_SUMMARY |
| 185 | + npx gzip-size-cli packages/nhs-fdp-spc/dist/index.esm.js >> $GITHUB_STEP_SUMMARY || true |
| 186 | +``` |
| 187 | +
|
| 188 | +--- |
| 189 | +
|
| 190 | +## Appendix C – Migration Communication Template |
| 191 | +
|
| 192 | +> We are promoting `@nhs-fdp/spc` to its own repository. Legacy imports via `@nhs-fdp/design-system` will remain for a deprecation window of 6 weeks. Please run `npm run spc:codemod:imports` to migrate. Track progress with `npm run spc:adoption`. Report issues in #spc-migration. |
| 193 | + |
| 194 | +--- |
| 195 | + |
| 196 | +## Change Log (Playbook) |
| 197 | + |
| 198 | +| Date | Change | |
| 199 | +|------|--------| |
| 200 | +| 2025-11-10 | Initial version added alongside adoption metrics script | |
0 commit comments