Skip to content

Trust pages answer the buyer first: /about, /security, /trust - #335

Merged
Apolloccrypt merged 1 commit into
mainfrom
feat/fe-vertrouwen
Sep 2, 2026
Merged

Trust pages answer the buyer first: /about, /security, /trust#335
Apolloccrypt merged 1 commit into
mainfrom
feat/fe-vertrouwen

Conversation

@Apolloccrypt

@Apolloccrypt Apolloccrypt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Rewrites the three pages a buyer reaches after the homepage, in the order
docs/brand/messaging.md fixes (merged as #331): what this is, who it is for,
who is behind it, a next step, then the proof including the honest limits.
Copy, hierarchy and order only. No restyle.

frontend/index.html, frontend/apply-nav.py and frontend/js/nav-auth.js
are untouched. Scope is five files: the three pages and the two test files
that pin them.

Third round. The second was rejected on a stale base plus twelve findings
across two reviews. Every one is answered below, with the pin that now fails
when it comes back.

Rebased, and main's corrections kept

Base is current main (56694a1, #362). Since the previous head the branch
has picked up #327, #328, #331, #332, #333, #334, #336, #337, #339, #340,
#342, #352 to #359 and #362, plus the dependency bumps. What main fixed on these pages survives:

What main fixed State here
ships 3 KEMs and 17 signature schemes plus the core/extended caveat kept
the account-lockout promise the code does not implement stays removed
the IP-logging row citing access_log off in deploy/nginx-paramant-live.conf kept, and carried into the moved-up jurisdiction table
the /trust audit link pointing at /docs#audits kept
Cloudflare gone from the out-of-scope list (Resend, Hetzner, Bunny, Mollie) kept, and the CLOUD Act card no longer names Cloudflare either
the free plan renamed Community followed on all three pages, and now enforced sitewide
#332's give-back paragraph on /about (about.html r.169) taken verbatim, moved with the section into the top half

Two files conflicted. In tests/ui-truthfulness.test.mjs main's block is kept
whole; this branch's block is appended after it and reuses main's about and
pricing handles instead of redeclaring them. In frontend/about.html the
conflict is the section this branch moves out of position 03 and #332 edits in
place: main's three paragraphs win word for word, including both sentences
#332 added, and they travel with the section into the top half. The section
appears once, at 02, and the numbering below it is consecutive.

The blocking findings

1. "The audit reports themselves are not published" was untrue, and pinned.
docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup and
it ships in the site tree as frontend/docs/security-audit-2026-04.md. Only
the raw pentest output is missing, which is what that document itself calls
the raw report. Both pages now say what /docs#audits adds up to: three
audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart Cyber
Solutions, forty findings, four of them critical, resolving commits in the
table. The published report is linked. The false sentence is now forbidden by
assertion on both pages.

2. The absolute promise above the fold was contradicted lower down. The
hero read "Even if our own server is broken into, nobody can read your
documents" flat out, while the page says ten screens lower that the Chromium
and Outlook extensions take a server-side encryption path. The exception now
travels with the promise: it holds for the web app, ParaShare and the official
SDKs, and the extensions are named in the same paragraph.

3. /trust called itself two different things. <title> and <h1> said
Trust & Verification; og:title, twitter:title and the JSON-LD WebPage
name still said Trust & Transparency. #334 has since rewritten every head on
the site, so the literal strings belong there and tests/seo-contract.test.mjs
pins them in its PINNED table. On rebase the head of all three pages was
resolved in main's favour, without exception, and
python3 bron-seo/apply_seo_head.py --check reports would change: 0 pages.

What this branch pins instead is the relation, which no test in tests/
covered and which #334 does not cover either: <title>, og:title,
twitter:title and the JSON-LD name must name the page the same, and that name
must contain the words the <h1> uses. Punctuation and case are normalised
away; Transparency versus Verification was the defect.

4. The auditor names were pinned on /trust only. Replacing them on
/security with "an independent firm" left the suite green. Pinned on both.

/about

  • The lede no longer ends on "the cryptography is post-quantum, which is the
    proof that it still holds up in ten years". That is not a proof and not
    checkable, on the page whose whole argument is that everything on it is
    checkable.
  • The founder paragraph carries Signed in, the free plan is called Community, and the page answers what a buyer asks #332's give-back paragraph verbatim: "The
    Community plan is his way of giving something back to society; the business
    plans pay for it. That is the whole arrangement, and it is why the Community
    plan is not a trial and has no end date." It replaces a version that
    explained the free plan with a jurisdiction claim ("should not depend on a
    US subscription"), which the guide forbids beside his name because the
    jurisdiction claim needs its Resend exception with it. The pin is exact, so
    the copy here and the copy Signed in, the free plan is called Community, and the page answers what a buyer asks #332 landed cannot drift.
  • The free plan is Community, as /pricing prints it on the card.
  • Measured at 390x844: the founder name at y=463, the title at y=493, "See
    pricing" at y=549, "See the evidence" at y=608. The stray 00 under the H1
    is hidden by #main-content .sec-head .num{display:none}, confirmed in the
    browser as display: none, not merely reordered.

/security

  • The first screen now carries the bounded promise, who is behind the page
    (Paramantis Solutions B.V. in Harderwijk, KvK 42115132, and the founder
    line) and both next steps. The buttons used to sit at roughly y=11400, some
    fourteen phone screens down. Measured: "See pricing" y=629, "Verify a
    document" y=689.
  • The CLOUD Act row and the EU-law card move to the data-path wording that
    section 9.2 of the guide requires: no US provider in the data path, with
    Resend named as the one exception in the same breath. The old row, "Not
    applicable: no US infrastructure, no US company", is broader than /privacy
    allows. The pin measures the exception as a window of 420 characters around
    the claim, not as "somewhere on the page", after a first version of that
    check let a card drop Resend while the table lower down still carried the
    word.
  • The eyebrow stays EVIDENCE, not DEFENSE IN DEPTH, and the word relay does
    not appear above the fold undefined.

/trust

  • The hero addresses organisations that run their own server and anyone
    checking a supplier, and gives that reader two buttons instead of one text
    link mid-paragraph (y=416 and y=476).
  • "the operator who runs the relay" is gone from the first screen. Relay is
    not a word a supplier reviewer knows.
  • The plan sentence named two of the three paid ParaSign tiers. It names all
    three, and both free tiers as Community.

The fourth-round finding

security.html r.448 still read "ParaSign Free and ParaSend Free cost
€0" after three rounds. The reason is worth writing down: the check this
branch added forbidding the old plan name was scoped to /about, so the page
that repeated it was never looked at. Two changes, not one:

  • the site-claims assertion now runs over about, security and trust;
  • TIER_NAME_SHAPES in ui-truthfulness gains /\bPara(Sign|Send) Free\b/,
    so the sitewide sweep over every frontend/**/*.html catches it on any page,
    including pages no round of this work touches. Sabotage on pricing.html
    confirms that.

Two more in the same round:

  • The hero said "treat those uploads as relay-side". Relay is the word this
    branch removed from the /trust hero, and it tells a reader who does not know
    what a relay is nothing at all. It now says what the exception costs them:
    the extensions encrypt on our server, which means we can read what you
    upload through them until that is changed. Neither hero uses the word relay
    now, and a test says so on both pages. The /security meta description, which
    sold "relay architecture" in the one line a search result shows, was rewritten
    with it.
  • Three paid ParaSign tiers plus Community, not four paid ones. Corrected in
    the test message and the commit.

Tests

tests/ui-truthfulness.test.mjs gains a block for the findings above.
tests/site-claims.test.mjs block 11 reads each number out of the /pricing
tier card that owns it and requires /about to repeat it; it follows the
Community rename and now also forbids ParaSign Free on /about.

Twenty-seven sabotages were applied in place and reverted, one per new pin: the
ten-year promise, the give-back sentence, the US-subscription framing, the
Community rename, the CLOUD Act row, the Resend exception dropped from the
card, the finding counts on each page, the "reports not published" sentence,
the auditor names on /security, the hero buttons on all three pages, the
who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
name, the jargon in each hero, the plan name on each of the three pages plus
one page outside this PR, the "relay" word in both heroes, the /trust head naming the page differently from its own H1, and the paid tiers.
Twenty-seven red, no gaps.

Following main through parallel merges

main moved nine times while this branch was in review. Three things came out
of that and are worth naming:

Two assertions #339 added were adjusted rather than kept, and both are
deliberate:

  • security.html must keep its Jurisdiction and privacy table matched
    <h2>Jurisdiction. This branch gives that heading an id so the EU-law card
    can link to #jurisdiction, so the selector became <h2[^>]*>. The check
    itself (Bunny is not in that table) is unchanged.
  • security.html must keep the US CLOUD Act row that proof 1 is measured against pinned Not applicable: no US infrastructure, no US company.
    Section 9.2 of the guide names that row as the one that has to move to the
    data-path wording "in its own PR with its own test". This is that PR, so the
    assertion now requires the data-path wording and forbids no US company.

Green locally

node --test over the CI glob (.github/workflows/test.yml r.200): 173
pass, 0 fail
, including links, seo-contract, site-claims,
ui-truthfulness, frontend-loading-contract, navigation-shell,
code-manifest, version-consistency, env-documented.
scripts/check-csp-inline.sh and scripts/check-cache-bust.sh exit 0.
eslint@9 exits 0 over the whole repository, and tests/static-sanity.sh is
PASS on all eleven checks, check 10 (commit style) and #362's new check 11
(test scope) included. scripts/check-commit-style.sh is clean.

At 390x844, scrollWidth === clientWidth === 390 on all three pages.

Still open, deliberately

The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
real contradiction and needs a decision, not a copy edit. This branch stops it
spreading and pins that it stays on the one page that has always carried it.

The three pages a buyer reaches after the homepage were written for someone
who already believes the product. /about opened on the mission and put the
founder in section 03, below the cryptography. /security opened on defence in
depth and kept the one row a buyer came for, the jurisdiction table, seven
screens down. /trust never said who it was for.

They now run the order docs/brand/messaging.md fixes: what this is, who it is
for, who is behind it, a next step, then the proof including the honest
limits. Copy, hierarchy and order only. No restyle. index.html, apply-nav.py
and js/nav-auth.js are untouched.

/about is the founder page.

  The lede is plain language: sign and send documents so only you and the
  recipient can read them, so anyone can check later that the document is
  genuine, on servers in Germany under EU law. Under it, in the first phone
  screen, who it is for, then Mick Beer with the title the guide fixes, then
  two buttons. Measured at 390x844: the founder sits at y=463 and the second
  button at y=608. The section number "00" is hidden in the mobile override
  instead of landing under the H1 as a stray number.

  Two sentences are gone. "The cryptography is post-quantum, which is the
  proof that it still holds up in ten years" was not a proof and not
  checkable, on the page whose argument is that everything on it is
  checkable. The founder paragraph explained the free plan with a
  jurisdiction claim ("should not depend on a US subscription"), which the
  guide forbids beside his name. In its place stands the paragraph #332
  landed on main while this branch was in review: the Community plan is his
  way of giving something back to society, the business plans pay for it,
  that is the whole arrangement, and it is why the Community plan is not a
  trial and has no end date. Taken from main verbatim, moved with the section
  into the top half, and pinned so the two copies cannot drift.

  The tier block names the free plan Community, which is what /pricing prints
  on the card since #328.

/security answers "why would I trust you" before it answers "how it works".

  The promise carries its own scope. It read "even if our own server is
  broken into, nobody can read your documents" flat out, while ten screens
  lower the page says the Chromium and Outlook extensions take a server-side
  encryption path. For an extension user the flat version is untrue today, so
  the exception now travels with the promise, in the hero.

  It also says what that exception costs the reader, in words rather than in
  ours: the extensions encrypt on our server, which means we can read what
  you upload through them until that is changed. "Treat those uploads as
  relay-side" was the internal phrasing, and relay is exactly the word this
  branch removed from the /trust hero. Neither hero uses it now, and a test
  says so.

  The first screen also carries who is behind the page (Paramantis Solutions
  B.V., Harderwijk, KvK 42115132, and the founder line) and the next step.
  The buttons used to sit at roughly y=11400 on a phone; "See pricing" is now
  at y=656 and "Verify a document" at y=716.

  The free plan is Community here too. A first version of this branch left
  "ParaSign Free and ParaSend Free cost EUR 0" standing at r.448, because the
  only check that forbade the old name was scoped to /about. That check now
  covers all three pages, and the sitewide sweep in ui-truthfulness gained the
  shape it was missing, so any page using it fails. The page description no
  longer sells "relay architecture" either.

  The audit block says what /docs#audits actually adds up to: three external
  audits in April 2026, two by R. Zwarts and one by Ryan Williams of Smart
  Cyber Solutions, forty findings, four of them critical, with the resolving
  commits in the table. The previous round claimed "the audit reports
  themselves are not published" and pinned it. That was false:
  docs/security-audit-2026-04.md is the full Smart Cyber Solutions writeup
  and it ships in the site tree. Only the raw pentest output is missing,
  which is what that document itself calls the raw report. Both pages now say
  that, and link the report.

  The CLOUD Act row and the EU-law card move to the data-path wording, as
  section 9.2 of the guide requires: no US provider in the data path, with
  Resend named as the one exception in the same breath. The old row read "not
  applicable: no US infrastructure, no US company", which is broader than
  /privacy allows.

/trust names its reader, then gives that reader somewhere to go.

  The hero addresses organisations running their own relay and anyone
  checking a supplier, and now offers them two buttons instead of one text
  link mid-paragraph (y=416 and y=476). The first sentence under the hero no
  longer says "the operator who runs the relay": relay is not a word a
  supplier reviewer knows.

  The page called itself Trust & Verification in its title and H1 while the
  social card and the structured data still said Trust & Transparency. #334
  then rewrote every head on the site, so the literal strings belong there and
  tests/seo-contract.test.mjs pins them. What this branch pins is the
  relation: the title, og:title, twitter:title and the JSON-LD name must name
  the page the same, and that name must contain the words the H1 uses.
  Punctuation and case are not the point; Transparency versus Verification
  was. Its plan sentence named two of the three paid
  ParaSign tiers; it names all three, and both free tiers as Community.

Tests

  tests/ui-truthfulness.test.mjs pins each of the above, and each one was
  sabotaged in place to confirm it goes red: the ten-year promise, the
  give-back sentence, the US-subscription framing, the Community rename, the
  CLOUD Act row, the Resend exception dropped from the card, the finding
  counts, the "reports not published" sentence, the auditor names on
  /security as well as /trust, the two hero buttons on each page, the
  who-is-behind line, the bounded promise, the /trust og:title and JSON-LD
  name, the jargon in the first screen, and the paid tiers. Twenty-seven
  sabotages, twenty-seven red, no gaps.

  tests/site-claims.test.mjs block 11 reads the numbers out of the /pricing
  tier card that owns them and requires /about to repeat them; it follows the
  Community rename and now also forbids "ParaSign Free" on /about.

  node --test over the CI glob: 173 pass, 0 fail. check-csp-inline,
  check-cache-bust and eslint exit 0, bron-seo/apply_seo_head.py --check
  reports 0 pages, and tests/static-sanity.sh is PASS on all eleven checks,
  including #362's new test-scope guard. At 390px all three pages have
  scrollWidth === clientWidth === 390.

Following main through four parallel merges

  #359 landed the deduplication this branch was carrying (the second const
  tiers in relay/test/pricing-page.test.js, and pricingVisible renamed to
  pricingText), so both local fixes are dropped in favour of main's.

  This branch's own block in tests/ui-truthfulness.test.mjs now sits inside a
  bare block scope and declares nothing at module level. Four PRs merged into
  that file in parallel on 2 September and two of them collided on a top-level
  const, which is a SyntaxError: not one assertion in the file runs, on any
  branch. A block that declares nothing at module level cannot do that to the
  next branch.

  tests/site-claims.test.mjs block 12 stopped spelling the units itself. #336
  renamed both /pricing section headings and put ParaSign first, and #359
  reworded "2 signatures per month" to "2 signatures a month". The block now
  finds the headings by product prefix, orders them by position, and lifts each
  fact out of the card as a whole phrase, so /about repeats what /pricing says
  rather than what this file guesses /pricing says. /about follows the new
  wording: "2 signatures a month", "24 hour link expiry", "up to 10 reads per
  link".

Still open, deliberately

  The eIDAS level (SES on /about, advanced (AES) in the /pricing FAQ) is a
  real contradiction and needs a decision, not a copy edit. This branch stops
  it spreading and pins that it stays on the one page that has always carried
  it.
@Apolloccrypt
Apolloccrypt merged commit e627576 into main Sep 2, 2026
9 of 10 checks passed
@Apolloccrypt
Apolloccrypt deleted the feat/fe-vertrouwen branch September 5, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant