Skip to content

Commit cc788f2

Browse files
fix(copy): correct fabricated/stale details found in display-accuracy audit (#218)
Display-detail accuracy sweep against prod reality (plans.yaml, live /openapi.json, prod k8s config, provisioner naming, GitHub/npm): - MarketingPage mock provision visual: region "iad-1 · us-east" was a fabricated region we never ran in — prod is DigitalOcean nyc3 (US-East). "postgres 16.2" → "postgres 16" (prod image is pgvector pg16; the patch level was invented). STEP-01 "202 accepted" → "201 created" (/db/new provisions synchronously and returns 201 per openapi.json; 202 belongs to /deploy/new + /stacks/new). - MarketingPage service-count copy: "Seven services" headline sat above EIGHT rendered cards and "Seven provisioning tools" omitted vector — both stale since /vector/new + mcp create_vector shipped 2026-05-20. Test now derives the expected count word from the rendered cards (rule 18: registry-iterating, not hand-typed). - MarketingPage claim-card sample URL: u_/d_ prefixes → the provisioner's canonical usr_/db_ scheme. - ForAgentsPage playground response ("what hits the wire — no mocks"): host "shared-1.instanode.dev" never existed → pg.instanode.dev (POSTGRES_PUBLIC_HOST); token "res_…" → UUID (openapi format:uuid); u_ → usr_; response meta "200" → "201". - StatusPage: github.com/instanode is an unrelated third-party org → github.com/InstaNode-dev. Verified accurate (no change needed): all tier prices/limits on Marketing/Pricing/Billing/PricingGrid vs plans.yaml; Team = contact-sales only; cancel/downgrade = support-only copy; *.deployment.instanode.dev; pg.instanode.dev terminal sample; nyc3 changelog entry. Known gap reported separately (not fixable here): `instanode-mcp` is not published on npm (404) while /for-agents + homepage instruct `npx -y instanode-mcp` — operator must publish mcp v0.12.0. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 967a889 commit cc788f2

5 files changed

Lines changed: 105 additions & 27 deletions

File tree

src/pages/ForAgentsPage.test.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ describe('ForAgentsPage', () => {
4242
expect(cta).toBeTruthy()
4343
})
4444

45+
it('playground response sample matches the real /db/new wire shape (2026-06-11 display-detail audit)', () => {
46+
renderPage()
47+
const text = document.body.textContent ?? ''
48+
// The page promises "what hits the wire — no mocks": the public host is
49+
// pg.instanode.dev (POSTGRES_PUBLIC_HOST) — "shared-1.instanode.dev"
50+
// never existed — and role/db names use the provisioner's canonical
51+
// usr_/db_ prefixes. /db/new returns 201 (synchronous), not 200.
52+
expect(text).toContain('@pg.instanode.dev:5432')
53+
expect(text).not.toContain('shared-1.instanode.dev')
54+
expect(text).toContain('postgres://usr_')
55+
expect(text).not.toContain('"res_')
56+
expect(text).toContain('201 · 1.4s · application/json')
57+
})
58+
4559
it('copies the command and flips the button label to "copied"', async () => {
4660
copyMock.mockResolvedValue(true)
4761
renderPage()

src/pages/ForAgentsPage.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,16 @@ const PLAYGROUND_CURL = `curl -X POST https://api.instanode.dev/db/new \\
6767
// provisioning response (CLAUDE.md convention #11) — a caller that omits
6868
// `env` lands in `development`, the lowest-stakes bucket. The earlier
6969
// sample dropped it, so the page misrepresented the wire shape.
70+
// Display-detail accuracy (2026-06-11): the page promises "what hits the
71+
// wire — no mocks", so the shapes must match prod: `token` is a UUID
72+
// (openapi DBProvisionResponse format:uuid, not the old fabricated
73+
// "res_…"), the public host is pg.instanode.dev (POSTGRES_PUBLIC_HOST;
74+
// "shared-1.instanode.dev" never existed), and role/db names follow the
75+
// provisioner's canonical usr_{token[:12]}/db_{token[:12]} scheme.
7076
const PLAYGROUND_RESPONSE = `{
7177
"ok": true,
72-
"token": "res_2RtL9k4mP",
73-
"connection_url": "postgres://u_3jX:••••@shared-1.instanode.dev:5432/db_2rtL9k4mp",
78+
"token": "9b2f61ce-4a3d-4e8b-b150-7c2f0a4d9e21",
79+
"connection_url": "postgres://usr_9b2f61ce4a3d:••••@pg.instanode.dev:5432/db_9b2f61ce4a3d",
7480
"tier": "anonymous",
7581
"env": "development",
7682
"limits": { "storage_mb": 10, "connections": 2 },
@@ -172,7 +178,9 @@ export function ForAgentsPage() {
172178
<div className="fa-play-head">
173179
<span className="fa-play-dot fa-play-dot--res" />
174180
response
175-
<span className="fa-play-meta">200 · 1.4s · application/json</span>
181+
{/* Display-detail accuracy (2026-06-11): /db/new returns
182+
201 Created (synchronous provisioning), not 200. */}
183+
<span className="fa-play-meta">201 · 1.4s · application/json</span>
176184
</div>
177185
<pre className="public-code"><code>{highlightJson(PLAYGROUND_RESPONSE)}</code></pre>
178186
</div>

src/pages/MarketingPage.test.tsx

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,60 @@ describe('MarketingPage — homepage nav drift (T18 P1-2)', () => {
8888
})
8989

9090
describe('MarketingPage — claim consistency (T18 P1-4 / P1-6)', () => {
91-
it("'Seven services' headline matches the MCP tools card (both say seven, listing webhook)", () => {
91+
it('services headline + MCP tools card count match the rendered SERVICES cards (registry-derived, not hand-typed)', () => {
9292
const { container } = render(
9393
<MemoryRouter initialEntries={['/']}>
9494
<MarketingPage />
9595
</MemoryRouter>,
9696
)
9797
const text = container.textContent ?? ''
98-
// Headline says "Seven services. One bundle."
99-
expect(text).toMatch(/Seven services\. One bundle\./)
100-
// MCP tools card lists the seven provisioning tools (must still list
101-
// webhook — anti-regression for the dropped-webhook bug) AND, per the
102-
// 2026-06-03 gap fix, also surfaces the stack/deployment management tools
103-
// (the MCP server registers more than seven; "Seven tools registered" was
104-
// an understatement).
105-
expect(text).not.toMatch(/Six provisioning tools/)
106-
expect(text).toMatch(/Seven provisioning tools/)
107-
expect(text).toMatch(/webhook/)
98+
// 2026-06-11 display-detail audit: the headline said "Seven services"
99+
// above EIGHT rendered cards (vector joined SERVICES on 2026-05-20 but
100+
// the count copy was never bumped), and the MCP card said "Seven
101+
// provisioning tools" while omitting `vector` (mcp registers
102+
// create_vector). Per rule 18, derive the expected count from the live
103+
// registry (the rendered service cards) instead of a hand-typed word so
104+
// adding service #9 without bumping the copy fails this test.
105+
const cardCount = container.querySelectorAll('.mkt-service-card').length
106+
expect(cardCount).toBeGreaterThan(0)
107+
const COUNT_WORDS = [
108+
'Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight',
109+
'Nine', 'Ten', 'Eleven', 'Twelve',
110+
]
111+
const word = COUNT_WORDS[cardCount]
112+
expect(word).toBeDefined()
113+
expect(text).toContain(`${word} services. One bundle.`)
114+
expect(text).toContain(`${word} provisioning tools`)
115+
// The MCP tools card must list every provisioning service shown in the
116+
// cards row — anti-regression for the dropped-webhook (T18 P1-4) and
117+
// dropped-vector (2026-06-11) bugs — plus the management tools.
118+
for (const svc of ['postgres', 'vector', 'redis', 'mongo', 'queue', 'storage', 'webhook', 'deploy']) {
119+
expect(text).toContain(svc)
120+
}
108121
expect(text).toMatch(/list_deployments/)
109122
})
110123

124+
it('mock provision visual shows real prod facts: nyc3 region, 201 for /db/new, usr_/db_ name prefixes', () => {
125+
const { container } = render(
126+
<MemoryRouter initialEntries={['/']}>
127+
<MarketingPage />
128+
</MemoryRouter>,
129+
)
130+
const html = container.innerHTML
131+
// 2026-06-11 display-detail audit: prod runs on DigitalOcean nyc3 —
132+
// "iad-1" was a fabricated region we never ran in.
133+
expect(html).toContain('nyc3 · us-east')
134+
expect(html).not.toContain('iad-1')
135+
// POST /db/new provisions synchronously → 201 Created (openapi.json);
136+
// "202 accepted" belongs to /deploy/new + /stacks/new only.
137+
expect(html).toContain('201 created')
138+
expect(html).not.toContain('202 accepted')
139+
// Claim-card sample URL uses the provisioner's canonical usr_/db_
140+
// prefixes, not the fabricated u_/d_ ones.
141+
expect(html).toContain('usr_xY9')
142+
expect(html).not.toContain('postgres://u_xY9')
143+
})
144+
111145
it("Deploy service card claims a build window consistent with content/llms.txt (~60s, not '<10s')", () => {
112146
const { container } = render(
113147
<MemoryRouter initialEntries={['/']}>

src/pages/MarketingPage.tsx

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,15 @@ export function MarketingPage() {
383383
</div>
384384
</header>
385385

386-
{/* ---------- seven services row ---------- */}
386+
{/* ---------- eight services row ---------- */}
387387
<section className="mkt-section" id="services">
388388
<div className="mkt-wrap">
389389
<div className="mkt-section-head">
390-
<div className="mkt-section-tag">Seven services. One bundle.</div>
390+
{/* Display-detail accuracy (2026-06-11): Vector (pgvector, /vector/new)
391+
joined the SERVICES array on 2026-05-20 but this headline kept
392+
saying "Seven" above eight rendered cards. The count below is
393+
asserted against SERVICES.length in MarketingPage.test.tsx. */}
394+
<div className="mkt-section-tag">Eight services. One bundle.</div>
391395
<h2 className="mkt-section-title">
392396
The whole stack, <span className="mkt-accent">not the pieces.</span>
393397
</h2>
@@ -447,7 +451,11 @@ export function MarketingPage() {
447451
<div className="r"><span className="k">auth</span><span className="v dim">none — fingerprinted</span></div>
448452
<div className="r"><span className="k">body</span><span className="v dim">{'{}'}</span></div>
449453
<div className="r" style={{ marginTop: 8 }}>
450-
<span className="k">status</span><span className="v ok">202 accepted</span>
454+
{/* Display-detail accuracy (2026-06-11): POST /db/new provisions
455+
synchronously and returns 201 Created (see /openapi.json) —
456+
the old "202 accepted" implied an async contract the db
457+
endpoint does not have (202 is /deploy/new + /stacks/new). */}
458+
<span className="k">status</span><span className="v ok">201 created</span>
451459
</div>
452460
</div>
453461
</article>
@@ -460,8 +468,14 @@ export function MarketingPage() {
460468
stored credentials, a connection string in 1.4 s. 24 h TTL on the free tier.
461469
</p>
462470
<div className="mkt-how-visual" aria-hidden="true">
463-
<div className="r"><span className="k">service</span><span className="v">postgres 16.2</span></div>
464-
<div className="r"><span className="k">region</span><span className="v dim">iad-1 · us-east</span></div>
471+
{/* Display-detail accuracy (2026-06-11): prod customer Postgres runs
472+
the pgvector pg16 image (major version is the honest claim — the
473+
patch level tracks the image) in DigitalOcean nyc3, not the old
474+
fabricated "iad-1" (a region we never ran in). nyc3 is US-East
475+
(NYC) — matches the Changelog's nyc3 cutover entry and the
476+
Privacy page's "US-region cloud infrastructure". */}
477+
<div className="r"><span className="k">service</span><span className="v">postgres 16</span></div>
478+
<div className="r"><span className="k">region</span><span className="v dim">nyc3 · us-east</span></div>
465479
<div className="r"><span className="k">size</span><span className="v">10 MB / 2 conn</span></div>
466480
<div className="r"><span className="k">expires</span><span className="v dim">in 24h</span></div>
467481
<div className="r" style={{ marginTop: 8 }}>
@@ -493,8 +507,8 @@ export function MarketingPage() {
493507
Obfuscation" feature scans every served HTML response
494508
and replaces any string that looks like name@domain.tld
495509
with a "[email protected]" placeholder + JS-decode shim.
496-
The sample URL below has `u_xY9...@pg.instanode.dev`,
497-
which matches CF's regex (the `u_xY9` part is a valid
510+
The sample URL below has `usr_xY9...@pg.instanode.dev`,
511+
which matches CF's regex (the `usr_xY9` part is a valid
498512
email local-part), so the live homepage rendered
499513
"postgres://[email protected]:5432/d_..." — confusing
500514
for visitors and broken for the hero claim card.
@@ -507,7 +521,11 @@ export function MarketingPage() {
507521
className="url"
508522
dangerouslySetInnerHTML={{
509523
__html:
510-
'<!--email_off-->postgres://u_xY9...@pg.instanode.dev:5432/d_...<!--/email_off-->',
524+
// Display-detail accuracy (2026-06-11): the provisioner's
525+
// canonical naming is usr_{token}/db_{token} (see
526+
// provisioner internal/backend/postgres/backend.go) — the
527+
// old `u_…`/`d_…` prefixes were fabricated.
528+
'<!--email_off-->postgres://usr_xY9...@pg.instanode.dev:5432/db_...<!--/email_off-->',
511529
}}
512530
/>
513531
<div className="claim-btn">Claim these resources →</div>
@@ -701,12 +719,14 @@ export function MarketingPage() {
701719
{'\n '}{'}'}
702720
{'\n'}{'}'}
703721
</div>
704-
{/* T18 P1-4 (2026-05-20): list the same seven tools as
705-
the "Seven services. One bundle." headline (and the
722+
{/* T18 P1-4 (2026-05-20): list the same tools as the
723+
"Eight services. One bundle." headline (and the
706724
SERVICES array). The earlier "Six tools" copy dropped
707725
webhook — a real MCP tool — and contradicted the same
708-
page. */}
709-
<p>Seven provisioning tools: <code>postgres</code>, <code>redis</code>, <code>mongo</code>, <code>queue</code>, <code>storage</code>, <code>webhook</code>, <code>deploy</code> — plus stack &amp; deployment management (<code>create_stack</code>, <code>list_stacks</code>, <code>update_stack_env</code>, <code>list_deployments</code>, <code>get_deployment</code>, <code>redeploy</code>, <code>delete_deployment</code>, …).</p>
726+
page. 2026-06-11: count bumped seven → eight and
727+
`vector` added — mcp registers create_vector (shipped
728+
with /vector/new) but this card still omitted it. */}
729+
<p>Eight provisioning tools: <code>postgres</code>, <code>vector</code>, <code>redis</code>, <code>mongo</code>, <code>queue</code>, <code>storage</code>, <code>webhook</code>, <code>deploy</code> — plus stack &amp; deployment management (<code>create_stack</code>, <code>list_stacks</code>, <code>update_stack_env</code>, <code>list_deployments</code>, <code>get_deployment</code>, <code>redeploy</code>, <code>delete_deployment</code>, …).</p>
710730
</div>
711731
</div>
712732

src/pages/StatusPage.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ export function StatusPage() {
136136
{/* FIX-G (2026-05-14): "Subscribe via RSS" link removed — /status.rss
137137
404s on the API. See IncidentsPage for the matching cleanup. */}
138138
<section className="public-section status-links">
139-
<a href="https://github.com/instanode" className="status-link">GitHub status</a>
139+
{/* Display-detail accuracy (2026-06-11): github.com/instanode is an
140+
unrelated third-party org — ours is InstaNode-dev. */}
141+
<a href="https://github.com/InstaNode-dev" className="status-link">GitHub status</a>
140142
<span className="status-link-sep">·</span>
141143
<a href="/incidents" className="status-link">Incident log</a>
142144
</section>

0 commit comments

Comments
 (0)