Risks & Improvements
The platform is intentionally ambitious — one shell, many independent teams, two integration paths, a dynamic registry, a self-service deployment pipeline, AI-first tooling. This is an honest catalogue of where it’s brittle today and what’s prioritized to fix next.
Out of scope: the local link: workspace dependency issue (tracked
separately). The Artifactory publishing pipeline itself — an auto-opened
“Version Packages” PR (.github/workflows/version-packages.yml) followed by
each package’s own Jenkins pipeline (nodeLibraryPipeline) publishing on
main — isn’t listed as a risk below because merging that PR is the only
manual step left; see whisker-platform/README.md (“How deployments work”)
for the full flow.
Where the platform is fragile today
Section titled “Where the platform is fragile today”1. The manifest schema can’t validate everything
Section titled “1. The manifest schema can’t validate everything”It catches structural errors (required fields, enums, mutual exclusivity of
integration kinds, name uniqueness) but can’t catch a componentPath that
doesn’t resolve to an actual export in the deployed bundle, a dead iframe
URL, or a Slack channel nobody’s in. These fail only at runtime — the
nightly Playwright run is the only systemic catch today.
Improvement: a CI “dry-load” step that verifies every componentPath
against the freshly-built remoteEntry.js before publishing.
2. Async gap between merge and visibility
Section titled “2. Async gap between merge and visibility”merge → CI build → S3 upload → Lambda → DynamoDB → next page load — each
hop is normally seconds but can stall, and there’s no “published
successfully” notification back to the developer.
Improvement: wire the publisher Lambda to post to
manifest.notifications.slack.channel on success and on DLQ rejection —
the schema slot already exists.
3. pinnedHostContractVersion is informational only
Section titled “3. pinnedHostContractVersion is informational only”The host publishes a live, queryable whisker-contract.json, so the diff
path is real — but the host doesn’t yet refuse to mount a module whose
pinned contract is older than its declared minimum. Also: contract
regeneration is a husky pre-commit hook, so git commit --no-verify can
land drift that only PR review catches today.
Improvement: make the host refuse to mount an out-of-date module with a
clear upgrade message; ship thundercats update --contract; add a host CI
step that re-runs the generator and fails the build on unexpected diff.
4. Iframe postMessage protocol has no compile-time surface
Section titled “4. Iframe postMessage protocol has no compile-time surface”Hand-coded on both sides — renaming a message or changing a payload shape
is a silent break with no shared type either side can import.
Improvement: a @nike/whisker-iframe-protocol types-only package
consumed by both the host and the kit’s iframe-consumer template.
5. Module Federation runtime coupling
Section titled “5. Module Federation runtime coupling”Federation modules load a host-provided React, MUI, and react-router at
runtime. A host major bump (React 19, MUI v6) can break a module that
hasn’t rebuilt against the new peer set. The host now publishes
sharedPackages in its contract, so the input data for a drift check
already exists — it’s just not wired into doctor yet.
Improvement: a whisker doctor check that fetches
<host>/whisker-contract.json#sharedPackages and warns on a major-version
mismatch against the module’s own package.json.
6. Host port 3001 is load-bearing
Section titled “6. Host port 3001 is load-bearing”Okta + BERM auth is registered to this origin; changing it invalidates
every developer session. Enforced today only by convention (strictPort: true in Vite config + doctor checks) — a stray vite.config edit could
still land in a release.
Improvement: a runtime assertion in whisker-host that throws on boot
if the resolved port is ever anything other than 3001.
7. Admin-aware merge is correct only if name is stable
Section titled “7. Admin-aware merge is correct only if name is stable”mergeManifestForUpsert matches components by name; a rename is a
delete+add, which loses any admin-controlled enabled/allowedPersonas state
for that component with no “renamed” diagnostic.
Improvement: an optional id on component buckets, preferred over
name when present.
8. whisker-bff is not yet extracted
Section titled “8. whisker-bff is not yet extracted”whisker-host still calls sim-bff for GET /manifests/v1 and the
legacy BERM login/refresh routes — platform concerns that don’t belong in
an inventory BFF. See
Manifest pipeline & deployment
for the extraction plan. The manifest endpoint’s public-read posture will
carry forward unchanged, so no new local-dev auth setup is needed either
before or after the migration.
9. whisker-config-panel doesn’t exist yet
Section titled “9. whisker-config-panel doesn’t exist yet”The Lambda merge preserves admin-edited enabled/allowedPersonas, but the
admin UI that lets a human set them isn’t built. Today the only way to
flip those values in production is a direct DynamoDB write — unsafe and
unmonitored.
10. No per-athlete feature overrides
Section titled “10. No per-athlete feature overrides”NikeStoreProvider.config is store-level only; rwe-core’s per-athlete
deledge flags have no whisker-host equivalent yet. Needs a decision
(manifest userOverrides, a flags service, or a BFF proxy) before a full
rwe-core migration.
11. The devkit panel and its 8 compliance checks are design-only
Section titled “11. The devkit panel and its 8 compliance checks are design-only”whisker doctor runs real checks today; the eight-check live panel on port
3009 is fully speculative — no server, no UI, nothing running on a
developer’s machine. See
Automation, devkit & E2E.
Even once it ships, checks stay advisory by design (self-service over
gating), which is an accepted long-term cost.
12. Thundercats Phase 2D is still pending, plus two untracked deviations
Section titled “12. Thundercats Phase 2D is still pending, plus two untracked deviations”The orchestrator + three specialists ship at platform-docs depth;
@nike/create-whisker writes the agent-context files itself as the last
scaffold step (so create no longer needs to chain a separate init call —
init is reserved for onboarding a pre-existing repo). Pending: the
external-skills pipeline, multi-repo scope, and --contract. Two smaller
deviations from the original plan, discovered during a docs cleanup and now
tracked in whisker-platform/DEFERRED.md:
- The
tcshort binary alias was decided but never shipped —binonly exposesthundercats. thundercats updatewas supposed to self-update by default; today only the separatethundercats upgradecommand does.
13. Service-kit publish gap during the pilot window
Section titled “13. Service-kit publish gap during the pilot window”thundercats create service writes a working template that depends on
@nike/whisker-service-kit — but the kit itself is deliberately excluded
from the first Artifactory pilot (.changeset/config.json#ignore) since
the pilot’s dependency graph doesn’t reach it. Between the pilot ship date
and the follow-up release, a scaffolded service can’t pnpm install
outside this workspace. Short-lived by design —
RELEASE_RUNBOOK.md’s “post-pilot tidy-up” lifts the ignore immediately
after.
14. The sync workflow depends on /manifests/v1 staying public
Section titled “14. The sync workflow depends on /manifests/v1 staying public”sync-deployed-registry.yml calls the BFF from a GitHub-hosted runner with
no Nike credentials — this works only because the endpoint is designed to
be public. If it were ever put behind auth, the sync workflow, local
whisker dev against remote BFFs, and the “no local credential setup”
promise all break at once.
Improvement: when whisker-bff ships, codify the public-read contract
in its README and add an integration test asserting GET /manifests/v1
returns 200 with no auth header.
Planned / proposed — prioritized
Section titled “Planned / proposed — prioritized”- Validate the v0.1.0 pilot publish + install on a clean machine, then
lift
@nike/whisker-service-kitout of the changesets ignore list (closes #13). - Complete the
whisker-bffextraction (#8), carrying forward the public-read posture of/manifests/v1with a locking integration test (#14). - Build
whisker-config-panel(#9). - Wire the publisher Lambda → Slack notifications (#2).
- Ship the
whiskerTestfixture +./e2ekit export (see Automation, devkit & E2E). - Implement the devkit panel server + UI (#11) — the highest-leverage automation piece still on the board.
pinnedHostContractVersionenforcement +thundercats update --contract- a host CI drift check (#3).
- Host shared-deps drift check in
whisker doctor/thundercats audit(#5). - Dry-load CI step for
componentPathvalidation (#1). @nike/whisker-iframe-protocoltypes package (#4).- Per-athlete feature overrides decision (#10).
- Optional
idon component buckets (#7).
- Thundercats Phase 2D as one slice — external-skills pipeline, cache,
quality gates, multi-repo fan-out,
add-skill/diff, plus the two small deviations in #12 (tcalias, self-update-on-update). - WCL AGENTS.md hierarchy polish, so the Tier 1 specialist registry can
flip its WCL entry from
placeholder: true. - Scaffolder version-parity for service + iframe-consumer scaffolds.
- Widget lifecycle convention in WCL (per-operator dismiss persistence — see rwe-core vs whisker-host for the prior art).
whisker-lambda-kitfor serverless workloads.- Virtual store engine for QA session simulation.
Maintenance upkeep
Section titled “Maintenance upkeep”| Owner | Cadence | Cost |
|---|---|---|
| Platform team | Every host release | Confirm schemaVersion/moduleKitMinVersion reflect real breaking changes; confirm nightly is green |
| Platform team | Every kit release | Dry-run the changeset payload; regression-test against ≥1 federation module and ≥1 iframe consumer |
| Platform team | Every Lambda change | Re-verify DLQ replay + admin-merge invariants |
| Platform team | Monthly / Quarterly | Audit orphan DynamoDB rows; review the compliance-check inventory |
| Module teams | Continuously | thundercats upgrade (then install-skill) for CLI/skill updates; thundercats audit/update for a repo’s .cursor/ |
| Module teams | Weekly | pnpm update @nike/whisker-module-kit if update-check flags one |
| Module teams | On host shared-dep bumps | Rebuild + redeploy against the new peer set |
| End users | — | Effectively zero — dashboard layout, dark mode, language, and inventory cache all persist and survive refresh automatically |
What we should keep doing
Section titled “What we should keep doing”- One Zod schema, imported by everything that touches a manifest — the reason “valid locally” really does mean “valid at ingest.”
whisker-contract.jsonas a versioned, queryable artifact.- Admin-editable fields preserved across redeploys.
- Tiny
remoteSafeSelectorssurface — resist expanding it casually. - Manifest endpoint stays publicly readable.
- Host port 3001 is sacred.
- Dynamic origin allow-list from the registry — no hand-maintained CORS lists.
- Doctor prints exact remediation commands.
