diff --git a/src/components/PricingGrid.test.tsx b/src/components/PricingGrid.test.tsx
new file mode 100644
index 0000000..4864942
--- /dev/null
+++ b/src/components/PricingGrid.test.tsx
@@ -0,0 +1,58 @@
+/* PricingGrid.test.tsx — pricing copy regression guards.
+ *
+ * BIZ-3 (2026-05-29): the dashboard in-app pricing tile shipped with copy
+ * inherited from a retired "deployment_size" field on /deploy/new:
+ * - Hobby tile: "1 small deployment"
+ * - Pro tile: "50 GB object storage · 10 medium deployments"
+ *
+ * The backend handler (api/internal/handlers/deploy.go) has no
+ * deployment_size field — there are no small/medium/large pod sizes.
+ * Numbers come from plans.yaml deployments_apps. Marketing PricingPage
+ * (src/pages/PricingPage.tsx) dropped the size adjectives in the
+ * 2026-05-20 DOC-REALITY-DELTA sweep; the dashboard surface lagged.
+ *
+ * This test pins both strings out of the in-app pricing surface so any
+ * future copy edit that re-introduces them fails CI before it ships.
+ */
+
+import { describe, it, expect, afterEach } from 'vitest'
+import { render, cleanup } from '@testing-library/react'
+import { MemoryRouter } from 'react-router-dom'
+import { PricingGrid } from './PricingGrid'
+
+afterEach(() => cleanup())
+
+function renderGrid() {
+ return render(
+
+ {}}
+ onSelectTier={() => {}}
+ />
+ ,
+ )
+}
+
+describe('PricingGrid — BIZ-3 deployment copy regression', () => {
+ it('does not render "small deployment" copy anywhere', () => {
+ renderGrid()
+ expect(document.body.textContent ?? '').not.toMatch(/small deployment/i)
+ })
+
+ it('does not render "medium deployments" copy anywhere', () => {
+ renderGrid()
+ expect(document.body.textContent ?? '').not.toMatch(/medium deployments/i)
+ })
+
+ it('Hobby tile says "1 deployment" (matches plans.yaml deployments_apps=1)', () => {
+ renderGrid()
+ expect(document.body.textContent ?? '').toContain('1 deployment')
+ })
+
+ it('Pro tile says "10 deployments" (matches plans.yaml deployments_apps=10)', () => {
+ renderGrid()
+ expect(document.body.textContent ?? '').toContain('10 deployments')
+ })
+})
diff --git a/src/components/PricingGrid.tsx b/src/components/PricingGrid.tsx
index 320296d..30fc552 100644
--- a/src/components/PricingGrid.tsx
+++ b/src/components/PricingGrid.tsx
@@ -109,7 +109,7 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [
{ text: '1 GB Postgres · 8 conn' },
{ text: '50 MB Redis' },
{ text: '100 MB MongoDB · 5 conn' },
- { text: '1 small deployment' },
+ { text: '1 deployment' },
{ text: '20 vault entries · production env' },
{ text: '1,000 stored webhooks' },
],
@@ -161,7 +161,7 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [
{ text: '10 GB Postgres · 20 conn' },
{ text: '512 MB Redis' },
{ text: '5 GB MongoDB · 20 conn' },
- { text: '50 GB object storage · 10 medium deployments' },
+ { text: '50 GB object storage · 10 deployments' },
{ text: '200 vault entries · multi-env' },
{ text: 'custom domain · 10k stored webhooks' },
],
diff --git a/src/pages/MarketingPage.test.tsx b/src/pages/MarketingPage.test.tsx
index 6082df4..d147ba6 100644
--- a/src/pages/MarketingPage.test.tsx
+++ b/src/pages/MarketingPage.test.tsx
@@ -116,4 +116,21 @@ describe('MarketingPage — claim consistency (T18 P1-4 / P1-6)', () => {
expect(text).not.toMatch(/<10s/)
expect(text).toMatch(/~60s/)
})
+
+ // BIZ-3 (2026-05-29): the landing pricing tile shipped "1 small deployment"
+ // and "10 medium deployments" copy from the days when /deploy/new had a
+ // deployment_size field. The backend dropped that field; marketing
+ // /pricing dropped the size adjectives in the 2026-05-20 sweep; the
+ // landing tile lagged. Pin both strings out so a future copy edit can't
+ // silently re-introduce a contract claim the API doesn't honor.
+ it('landing pricing tile no longer claims "small / medium" deployment sizes', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const text = container.textContent ?? ''
+ expect(text).not.toMatch(/small deployment/i)
+ expect(text).not.toMatch(/medium deployments/i)
+ })
})
diff --git a/src/pages/MarketingPage.tsx b/src/pages/MarketingPage.tsx
index 216aecc..05673ff 100644
--- a/src/pages/MarketingPage.tsx
+++ b/src/pages/MarketingPage.tsx
@@ -164,7 +164,7 @@ const PLANS: Plan[] = [
features: [
'1 GB Postgres · 8 conn',
'50 MB Redis · 100 MB Mongo · 5 conn',
- '1 small deployment · *.deployment.instanode.dev',
+ '1 deployment · *.deployment.instanode.dev',
'20 vault entries · production env',
],
cta: { label: 'Start hobby →', href: ROUTES.signin, variant: 'secondary' },
@@ -186,7 +186,7 @@ const PLANS: Plan[] = [
features: [
'10 GB Postgres · 20 conn',
'512 MB Redis · 5 GB Mongo · 20 conn',
- '50 GB object storage · 10 medium deployments · custom domain',
+ '50 GB object storage · 10 deployments · custom domain',
// BugBash P3-08: kept in sync with PricingPage's "Vault envs" row
// and the multi-env FAQ — Pro's multi-env is dev/staging/prod. The
// earlier "+ custom" claim implied arbitrary named environments the