/docs and /help answer a buyer before they answer a developer - #333
Conversation
|
Follow-up commit The test asserts the rendered text of The lede now reads "Every ParaSign API endpoint is in the API reference". Same meaning, and the phrase is back where the test can see it. The test itself is unchanged — it caught a real thinning of the page's own name, which is exactly the job. The browser suites were run locally this time (all 18 subtests across the playwright-importing files in |
Second pass on the review of PR #333, rebased on main (#324, #327, #328, #331, #342). /docs - The buyer line is pinned to the visible paragraph. The old assertion matched the same words in four meta tags, so deleting the paragraph left the test green. Proven by sabotage, both ways. - The buyer gets a real button to /pricing beside Quick start, same size, same row. Quick start stays the primary CTA the messaging guide asks for; the pricing button is the outlined one. - Two sentences that ran on double colons now read as sentences, and the ADR range no longer uses an en-dash. /help - "What does it cost?" names the numbers /pricing prints: ParaSign Community free forever, no card, 2 signatures per month, and ParaSign Pro at 49 euro a month excl. btw (59.29 incl.) with 100 signatures. Each half is pinned to the card it was quoted from. - "Pay for volume, never for security" is off the support page. The fact behind it stays, quoted from /pricing: every plan gets the same encryption, the same post-quantum signatures and the same public proof log. A test now fails if the sales line comes back. - "Where does my data live?" is three readable sentences instead of a flattened compliance table: Hetzner Nuremberg, EU law and the GDPR, no US provider in the data path, and email via Resend as /privacy sets out. Scoped to the data path per proof 1 of the messaging guide, so the unqualified "no US company" row from /security is not repeated here while that contradiction is open (guide section 9). - The em-dash sweep on api-key-vs-totp and lost-authenticator now covers the H1, the tab title, the meta description and the body, not only the lede. A test pins all three help pages. /developer - The page is noindex and only reachable once signed in, so the lede addresses the developer reading it, not the buyer who sent them. The plan boundary for API access stays, and a test forbids the buyer phrasing coming back. Tests: links, seo-contract, ui-truthfulness, site-claims, frontend-loading-contract, navigation-shell, csp-inline, cache-bust, eslint and static-sanity all pass. Every new pin was sabotaged one at a time and went red.
1611bc3 to
5516c9a
Compare
Second pass on the review of PR #333, rebased on main (#324, #327, #328, #331, #342). /docs - The buyer line is pinned to the visible paragraph. The old assertion matched the same words in four meta tags, so deleting the paragraph left the test green. Proven by sabotage, both ways. - The buyer gets a real button to /pricing beside Quick start, same size, same row. Quick start stays the primary CTA the messaging guide asks for; the pricing button is the outlined one. - Two sentences that ran on double colons now read as sentences, and the ADR range no longer uses an en-dash. /help - "What does it cost?" names the numbers /pricing prints: ParaSign Community free forever, no card, 2 signatures per month, and ParaSign Pro at 49 euro a month excl. btw (59.29 incl.) with 100 signatures. Each half is pinned to the card it was quoted from. - "Pay for volume, never for security" is off the support page. The fact behind it stays, quoted from /pricing: every plan gets the same encryption, the same post-quantum signatures and the same public proof log. A test now fails if the sales line comes back. - "Where does my data live?" is three readable sentences instead of a flattened compliance table: Hetzner Nuremberg, EU law and the GDPR, no US provider in the data path, and email via Resend as /privacy sets out. Scoped to the data path per proof 1 of the messaging guide, so the unqualified "no US company" row from /security is not repeated here while that contradiction is open (guide section 9). - The em-dash sweep on api-key-vs-totp and lost-authenticator now covers the H1, the tab title, the meta description and the body, not only the lede. A test pins all three help pages. /developer - The page is noindex and only reachable once signed in, so the lede addresses the developer reading it, not the buyer who sent them. The plan boundary for API access stays, and a test forbids the buyer phrasing coming back. Tests: links, seo-contract, ui-truthfulness, site-claims, frontend-loading-contract, navigation-shell, csp-inline, cache-bust, eslint and static-sanity all pass. Every new pin was sabotaged one at a time and went red.
5516c9a to
ff838a6
Compare
Third pass on the review of PR #333. Blocker. The data-location answer said "Your documents and keys live on servers at Hetzner Nuremberg, Germany". The keys do not. Five places on the site promise the opposite: "Generated on your device, never sent" (index.html), "relay holds only ciphertext, never keys" and "No plaintext, no keys" (security.html), "we never hold decryption keys, anywhere" (trust.html), "The relay never sees plaintext and never holds a private key" (docs.html). Flattening a table into prose is how the word "keys" got in there, and it is the sentence a security reviewer would quote back at us. The answer now says the documents are there and that they are ciphertext, and it quotes docs.html for where the keys are not: Your documents live on servers at Hetzner Nuremberg, Germany, and they sit there as ciphertext. The relay never sees plaintext and never holds a private key. Your files stay under EU law and the GDPR, and no US provider is in the data path. Email goes out via Resend, as /privacy sets out. Pinned in both directions. The positive half is a pair, the quote and docs.html. The negative half is a loop over every sentence in the /help body: a sentence that mentions a key and a piece of infrastructure in the same breath must be denying it, and may never use a locative verb between the two. Sabotage: putting "and keys" back is red, "your keys are stored on the relay" is red, and "Your keys are kept on servers at Hetzner Nuremberg, and there is no US provider" is red as well, so a stray "no" elsewhere in the sentence does not buy a pass. Also in this commit, from the same review: - The gate against the pricing slogan and the one against sales vocabulary ran on the three answers only. Both now run on the whole /help body below </head>, so the line cannot come back through the lede, an article card or the footer. Sabotage on both: red. - Rebased on main for #332, which added two console.log lines at the end of tests/ui-truthfulness.test.mjs. No name collision; both sides kept. Tests: links, seo-contract, ui-truthfulness, site-claims, frontend-loading-contract, navigation-shell, csp-inline, cache-bust, eslint, static-sanity. All pass. 37 sabotage mutations, one at a time, all red.
/docs is busier than /pricing. That is not an accident: it was the page a
navigation of forty links pointed at, and it opens on pip install. Someone
evaluating Paramant lands there because their IT asked to see the API, and
the page never says what it is for or where the price boundary sits.
The messaging guide (docs/brand/messaging.md, section 8) settles the order:
one line for the buyer, then the developer entry, and no marketing beyond
one line naming which plan the API needs.
What changed, per page.
/docs
A single buyer line above the lede: "Evaluating Paramant? Your IT can
check everything here. Plans and prices are on Pricing." The existing
lede is unchanged and gains one sentence: the ParaSign API is available
from ParaSign Pro, with a link to /pricing. The hero CTA is now Quick
start, with Create account beside it, because a developer who arrives
here wants the first request, not a signup form.
The meta description said "PARAMANT Ghost Pipe v2" while the page body
describes 3.0.0. It now matches the page and says what the page is for.
/developer
Same shape for the person already signed in. The lede loses "Everything
needed to connect and operate the ParaSign API is here", which said
nothing, and gains a link to the API reference and the plan line: API
access is included from ParaSign Pro. Quick start joins the Build and
operate links.
/help
The three questions a buyer asks, at the top, above the article grid,
each answered in the words the source page already uses and each linking
to that page:
Can I sign without an account? -> /sign
What does it cost? -> /pricing
Where does my data live? -> /security
H1 and lead are unchanged, the support voice is unchanged, and nothing
is sold. The meta description now names those three answers instead of
repeating the h1.
Two article ledes lost an em-dash (api-key-vs-totp, lost-authenticator).
A mobile fix that /docs needed to be readable at all: .content is a flex
item, so its default min-width:auto let the widest table (first column is
white-space:nowrap) push it to 840px inside a 390px viewport. The body
clipped the overflow with no scrollbar, so the documentation text simply
ran off the right of the screen on a phone. min-width:0 plus scrollable
tables below 900px. No other styling changed; the palette and the mono
labels are untouched.
Tests. The guide's rule is that a sentence may only ship when a test fails
if it stops shipping, and a quote is worse than a paraphrase if it can
drift from its source in silence. So tests/ui-truthfulness.test.mjs now
asserts each new sentence AND the page it was quoted from, as a pair:
"Pay for volume, never for security" on /help and on /pricing, the two
jurisdiction rows on /help and on /security, the account requirement on
/help and on /sign, and "API access" on the ParaSign Pro tier, which is
what makes the /docs and /developer plan line true. Plus: no sales
vocabulary on /help.
Not touched: index.html, apply-nav.py, js/nav-auth.js, the API reference
itself, and the two open contradictions the guide names in section 9.
Green locally: seo-contract, ui-truthfulness, links,
frontend-loading-contract, navigation-shell (24 checks),
check-csp-inline.sh, check-cache-bust.sh, eslint.
tests/developer-parasign-dashboard.test.mjs asserts that the rendered text of the developer page contains "ParaSign API", which is how it proves the page is the ParaSign surface and not the old transfer tool catalogue. The eyebrow above the h1 is text-transform:uppercase, so innerText renders it as "PARASIGN API" and never satisfies that check. The only lowercase occurrence sat in the sentence this branch rewrote. The lede now reads "Every ParaSign API endpoint is in the API reference", which says the same thing and puts the phrase back where the test can see it. The test is unchanged: it was right, and it caught a real thinning of the page's own name. Ran locally this time: all 18 browser subtests in tests/*.mjs that import playwright, plus the 110 non-browser subtests.
Second pass on the review of PR #333, rebased on main (#324, #327, #328, #331, #342). /docs - The buyer line is pinned to the visible paragraph. The old assertion matched the same words in four meta tags, so deleting the paragraph left the test green. Proven by sabotage, both ways. - The buyer gets a real button to /pricing beside Quick start, same size, same row. Quick start stays the primary CTA the messaging guide asks for; the pricing button is the outlined one. - Two sentences that ran on double colons now read as sentences, and the ADR range no longer uses an en-dash. /help - "What does it cost?" names the numbers /pricing prints: ParaSign Community free forever, no card, 2 signatures per month, and ParaSign Pro at 49 euro a month excl. btw (59.29 incl.) with 100 signatures. Each half is pinned to the card it was quoted from. - "Pay for volume, never for security" is off the support page. The fact behind it stays, quoted from /pricing: every plan gets the same encryption, the same post-quantum signatures and the same public proof log. A test now fails if the sales line comes back. - "Where does my data live?" is three readable sentences instead of a flattened compliance table: Hetzner Nuremberg, EU law and the GDPR, no US provider in the data path, and email via Resend as /privacy sets out. Scoped to the data path per proof 1 of the messaging guide, so the unqualified "no US company" row from /security is not repeated here while that contradiction is open (guide section 9). - The em-dash sweep on api-key-vs-totp and lost-authenticator now covers the H1, the tab title, the meta description and the body, not only the lede. A test pins all three help pages. /developer - The page is noindex and only reachable once signed in, so the lede addresses the developer reading it, not the buyer who sent them. The plan boundary for API access stays, and a test forbids the buyer phrasing coming back. Tests: links, seo-contract, ui-truthfulness, site-claims, frontend-loading-contract, navigation-shell, csp-inline, cache-bust, eslint and static-sanity all pass. Every new pin was sabotaged one at a time and went red.
Third pass on the review of PR #333. Blocker. The data-location answer said "Your documents and keys live on servers at Hetzner Nuremberg, Germany". The keys do not. Five places on the site promise the opposite: "Generated on your device, never sent" (index.html), "relay holds only ciphertext, never keys" and "No plaintext, no keys" (security.html), "we never hold decryption keys, anywhere" (trust.html), "The relay never sees plaintext and never holds a private key" (docs.html). Flattening a table into prose is how the word "keys" got in there, and it is the sentence a security reviewer would quote back at us. The answer now says the documents are there and that they are ciphertext, and it quotes docs.html for where the keys are not: Your documents live on servers at Hetzner Nuremberg, Germany, and they sit there as ciphertext. The relay never sees plaintext and never holds a private key. Your files stay under EU law and the GDPR, and no US provider is in the data path. Email goes out via Resend, as /privacy sets out. Pinned in both directions. The positive half is a pair, the quote and docs.html. The negative half is a loop over every sentence in the /help body: a sentence that mentions a key and a piece of infrastructure in the same breath must be denying it, and may never use a locative verb between the two. Sabotage: putting "and keys" back is red, "your keys are stored on the relay" is red, and "Your keys are kept on servers at Hetzner Nuremberg, and there is no US provider" is red as well, so a stray "no" elsewhere in the sentence does not buy a pass. Also in this commit, from the same review: - The gate against the pricing slogan and the one against sales vocabulary ran on the three answers only. Both now run on the whole /help body below </head>, so the line cannot come back through the lede, an article card or the footer. Sabotage on both: red. - Rebased on main for #332, which added two console.log lines at the end of tests/ui-truthfulness.test.mjs. No name collision; both sides kept. Tests: links, seo-contract, ui-truthfulness, site-claims, frontend-loading-contract, navigation-shell, csp-inline, cache-bust, eslint, static-sanity. All pass. 37 sabotage mutations, one at a time, all red.
ff838a6 to
7c4e36f
Compare
What this does
/docs, /developer and /help, rebased on main and reworked after two rounds of review. The rule from
docs/brand/messaging.md: a sentence ships only when it already ships somewhere else and a test fails the moment it stops shipping. Every claim below is quoted from the page that owns it, and every quote is pinned to the markup a visitor actually sees.The review points, one by one
1. The buyer line on /docs was not pinned. The old assertion matched
Your IT can check everything hereagainst the whole file, and the same words sit in four meta tags. Deleting the visible paragraph left the test green. The assertion is now anchored to<p class="docs-buyer">Evaluating Paramant? .... Sabotaged both ways: removing the paragraph is red, and leaving it while breaking only the meta copy is red too.2. The buyer had no button on /docs. Quick start was the only real action and Pricing was a text link. There are now two buttons of the same size in the same row: Quick start (filled, still the primary CTA the guide asks for) and See plans and prices (outlined, straight to /pricing). Create account stays as a text link below them. On 390px both buttons go full width and stack. Pinned on both
hrefand class, so demoting either one back to a text link fails.3. "What does it cost?" on /help named no amount. It now names what /pricing prints: ParaSign Community is free, forever, no card required, 2 signatures per month; the first paid plan is ParaSign Pro at €49 a month excl. btw (€59.29 incl.) with 100 signatures a month. Each half is pinned against the card it came from, and the Community pin is scoped to the ParaSign grid because /pricing carries a second Community card for ParaSend.
4. "Pay for volume, never for security" was a sales line on a support page. It is gone from /help and stays on /pricing, which is the page that sells. The fact behind it is quoted instead, word for word: "Every plan gets the same encryption, the same post-quantum signatures and the same public proof log." A
doesNotMatchfails if the slogan comes back. That gate, and the sales-vocabulary gate beside it, run on the whole /help body below</head>, not on the three answers alone, so the line cannot return through the lede, an article card or the footer.5. "Where does my data live?" was a compliance table flattened into prose, with two colons in one sentence. It is four short sentences now, and the second round of review caught a real error in the first draft of them: it said the documents and keys live on servers at Hetzner. The keys do not. Five places on the site promise the opposite: "Generated on your device, never sent" (index.html), "relay holds only ciphertext, never keys" and "No plaintext, no keys" (security.html), "we never hold decryption keys, anywhere" (trust.html), "The relay never sees plaintext and never holds a private key" (docs.html). The answer now reads:
That is proof 1 of the messaging guide, scoped to the data path and naming the Resend exception in the same breath, plus the key sentence quoted from docs.html. The unqualified "no US company" row on /security is an open contradiction (guide section 9) and is deliberately not repeated here; a test fails if it appears.
Pinned in both directions. The positive half is a pair, the quote and docs.html. The negative half is a loop over every sentence in the /help body: a sentence naming a key and a piece of infrastructure in the same breath must be denying it, and may never put a locative verb between the two. Sabotage: putting "and keys" back is red, "your keys are stored on the relay" is red, and "Your keys are kept on servers at Hetzner Nuremberg, and there is no US provider" is red as well, so a stray "no" elsewhere in the sentence buys no pass.
6. The em-dash sweep stopped at the lede. The H1, the tab title, the meta description and the body of /help/api-key-vs-totp and /help/lost-authenticator still had them: eleven and six. All gone, plus an en-dash range in each of the two pages and one on /docs. A loop over the three help pages and /docs pins it.
7. /developer spoke to the wrong audience. The page is noindex and only reachable once signed in, so "so your IT can check everything before you connect anything" was addressing someone who is not there. It now reads "so you can read the whole surface before you connect anything." The plan boundary for API access stays, and a test forbids the buyer phrasing from returning.
Also fixed while here: two sentences on /docs that ran on double colons (the "Version 3.0.0 keeps ..." lede and the ADR line) now read as sentences.
Rebase
Rebased onto main twice. The first pass resolved a conflict in
tests/ui-truthfulness.test.mjswhere main's homepage, dashboard and Community-rename assertions (#327, #328) landed in the same place; both sides kept, the duplicatepricing.htmlread folded into the existing one. main's rename of the free tier to Community also changed the source sentence on /sign, so the /help quote follows it. The second pass took #332, which appends twoconsole.loglines at the end of the same file: no name collision, both sides kept. Now current with #352 and #353.frontend/apply-nav.pyran after each rebase and produced no further changes.Proof
Green:
links,seo-contract,ui-truthfulness,site-claims,frontend-loading-contract,navigation-shell,check-csp-inline.sh,check-cache-bust.sh,eslint@9 .,tests/static-sanity.sh(PASS, all hard checks clear, 10/10),scripts/check-commit-style.shover the whole range.Sabotage: 37 mutations, one at a time, each reverted after the run. Every new pin went red, including the ones on the source pages (
pricing.html,security.html,index.html,docs.html) and the four negative pins. Screenshots at 390x844: no horizontal scroll on either page, scrollWidth 390 = clientWidth 390, and all three /help answers still fit one screen.Known gap, outside this PR: renaming the ParaSend Community card on /pricing stays green, because main's assertion from #328 is satisfied by the remaining ParaSign card. This branch's own pin is scoped and does catch the ParaSign one. That is a pin on main, not a regression here.
Scope: six files, all /docs, /developer, /help and their test.
frontend/apply-nav.py,frontend/js/nav-auth.jsandfrontend/index.htmlare not edited.