From a0dcf4f2f8980c9393a33ac702f6568fe4a31a8a Mon Sep 17 00:00:00 2001 From: Nish <257724087+nish3451@users.noreply.github.com> Date: Wed, 12 Aug 2026 04:42:11 +0530 Subject: [PATCH 1/3] fix(public): replace residual editorial and submission-prep copy on the four app pages The Drishti and Promptly product pages still carried the editor-facing 'Where to go next' eyebrow (residual from PR #28), and both app privacy pages still carried submission-prep copy as visible hero/body copy: H1s spoke to the launch calendar ('already in place before launch', 'already public ahead of release'), the leads referenced the 'current planned launch scope' and 'final App Store privacy disclosures before release', the aside was labeled 'Current release scope' with 'not publicly released yet', the first card was headed 'At launch', and the 'Important note' told readers both the page and the App Store privacy answers should be updated before the next submission. Rewrite those passages as visitor-facing copy that describes what each page covers and the choices available, without referencing the submission process. Heading levels, links, meta tags, chips, and JSON-LD are unchanged. --- public/drishti/index.html | 2 +- public/drishti/privacy/index.html | 32 ++++++++++++++--------------- public/promptly/index.html | 2 +- public/promptly/privacy/index.html | 33 +++++++++++++++--------------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/public/drishti/index.html b/public/drishti/index.html index 9ef4bf15..16757bbe 100644 --- a/public/drishti/index.html +++ b/public/drishti/index.html @@ -187,7 +187,7 @@

Built around rituals, streaks, and compassion.

-

Where to go next

+

Help and next steps

  • Drishti support
  • Drishti privacy
  • diff --git a/public/drishti/privacy/index.html b/public/drishti/privacy/index.html index 3917f378..eccbad3a 100644 --- a/public/drishti/privacy/index.html +++ b/public/drishti/privacy/index.html @@ -83,11 +83,12 @@

    Drishti privacy

    -

    Drishti’s privacy page is already in place before launch.

    +

    Drishti privacy for mindful screen time.

    - This is the app-specific privacy destination for Drishti. It - reflects the current planned launch scope and should stay aligned - with the final App Store privacy disclosures before release. + This page explains what information Tiny Studio may receive + through Drishti, how it is used, and the choices you have. Drishti + is Tiny Studio’s mindful screen time app for interrupting the + scroll reflex.

    Effective date: March 14, 2026 @@ -96,10 +97,10 @@

    Drishti’s privacy page is already in place before launch.

    @@ -107,12 +108,12 @@

    Drishti’s privacy page is already in place before launch.

    -

    At launch

    -

    No third-party advertising or cross-app tracking is disclosed here.

    +

    Advertising and tracking

    +

    No third-party advertising or cross-app tracking.

    - This page does not currently describe targeted advertising, - cross-app tracking, a public sign-in system, or website payments - for Drishti. + This page does not describe targeted advertising, cross-app + tracking, a public sign-in system, or website payments for + Drishti.

    @@ -149,10 +150,9 @@

    To respond, improve, and keep records when necessary.

    Important note

    - If Drishti launches with analytics, crash reporting, accounts, - sync, or another external service not described here, both this - page and the App Store privacy answers should be updated before - that version is submitted. + If Drishti adds analytics, crash reporting, accounts, sync, or + another external service not described here, this page will be + updated to describe it.

    diff --git a/public/promptly/index.html b/public/promptly/index.html index c151f290..2743ea11 100644 --- a/public/promptly/index.html +++ b/public/promptly/index.html @@ -188,7 +188,7 @@

    Reminders, proof, and calendar clarity.

    -

    Where to go next

    +

    Help and next steps

    • Promptly support
    • Promptly privacy
    • diff --git a/public/promptly/privacy/index.html b/public/promptly/privacy/index.html index 41e3e4a0..7e55571f 100644 --- a/public/promptly/privacy/index.html +++ b/public/promptly/privacy/index.html @@ -83,11 +83,11 @@

      Promptly privacy

      -

      Promptly’s privacy page is already public ahead of release.

      +

      Promptly privacy for bookings, reminders, and client data.

      - This is the app-specific privacy destination for Promptly. It - reflects the current planned launch scope and should stay aligned - with the final App Store privacy disclosures before release. + This page explains what data Promptly handles, how it is used, and + the choices you have. Promptly is Tiny Studio’s booking and + no-show prevention app for solo professionals.

      Effective date: March 14, 2026 @@ -96,10 +96,10 @@

      Promptly’s privacy page is already public ahead of release.

      @@ -107,12 +107,12 @@

      Promptly’s privacy page is already public ahead of release.

      -

      At launch

      -

      No third-party advertising or cross-app tracking is planned.

      +

      Advertising and tracking

      +

      No third-party advertising or cross-app tracking.

      - Promptly is described as a booking workflow for solo professionals. - This policy does not describe targeted advertising, cross-app - tracking, or selling personal information. + Promptly is a booking workflow for solo professionals. This policy + does not describe targeted advertising, cross-app tracking, or + selling personal information.

      @@ -150,7 +150,7 @@

      Booking links, notes, payment proof, and support records.

      support, security, legal, or accounting reasons. Service providers may support hosting, storage, authentication or OTP delivery, notifications, calendar connectivity, support, and payment-proof - handling. Promptly should not receive full payment-card numbers. + handling. Promptly does not receive full payment-card numbers.

    @@ -170,10 +170,9 @@

    Booking links, notes, payment proof, and support records.

    Important note

    - If Promptly launches with analytics, crash reporting, new payment - processors, expanded account sync, or another external service not - described here, both this page and the App Store privacy answers - should be updated before that version is submitted. + If Promptly adds analytics, crash reporting, new payment + processors, expanded account sync, or another external service + not described here, this page will be updated to describe it.

    From 3f3221910654dc6f59655734e8a4feda24f56c55 Mon Sep 17 00:00:00 2001 From: Nish <257724087+nish3451@users.noreply.github.com> Date: Wed, 12 Aug 2026 04:49:01 +0530 Subject: [PATCH 2/3] test(public): guard the four app pages against editorial and submission-prep copy The residual editorial copy on the app product and privacy pages was cleaned up without a regression guard (the earlier footer-copy guard proposal never merged). Add test-public-app-copy-voice.mjs, wired into npm test and npm run ci, which fails if any of the four app pages re-introduces the editorial/submission-prep phrasing (launch-calendar H1s, planned-scope leads, release-scope asides, at-launch cards, 'Where to go next' eyebrows, submission notes) or drops the visitor-facing product identity and public support route. --- package.json | 4 +- scripts/test-public-app-copy-voice.mjs | 96 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 scripts/test-public-app-copy-voice.mjs diff --git a/package.json b/package.json index 6c96a39a..5733d834 100644 --- a/package.json +++ b/package.json @@ -86,9 +86,9 @@ "product:truth": "node scripts/check-product-truth.mjs", "mobbin:run": "node scripts/run-design-system-proving-lab.mjs", "mobbin:check": "node scripts/run-design-system-proving-lab.mjs --dry-run", - "ci": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", + "ci": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-app-copy-voice.mjs && node scripts/test-public-deploy-bundle.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", "check": "npm test", - "test": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", + "test": "node scripts/test-service-engine.mjs && node scripts/test-sales-intake-contract.mjs && node scripts/test-active-offer-projection.mjs && node scripts/test-active-operator-surfaces.mjs && node scripts/test-direction-proof-gate.mjs && node scripts/test-client-readiness-contract.mjs && node scripts/test-validated-service-client.mjs && node scripts/test-client-acceptance-gates.mjs && node scripts/check-product-truth.mjs && node scripts/check-human-service-kit.mjs && node scripts/test-design-system-proving-lab.mjs && node scripts/check-retention-automation.mjs && node scripts/test-retention-automation.mjs && node scripts/check-agency-defaults.mjs && node scripts/check-outbound-claim-safety.mjs && node scripts/check-outbound-send-readiness.mjs && node scripts/test-outbound-send-readiness.mjs && node scripts/test-public-conversion-signal.mjs && node scripts/test-public-structured-data.mjs && node scripts/test-public-brand-disambiguation.mjs && node scripts/test-public-heading-hierarchy.mjs && node scripts/test-public-link-targets.mjs && node scripts/test-public-social-preview.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-app-copy-voice.mjs && node scripts/test-public-deploy-bundle.mjs && find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check", "site:publish": "node scripts/publish-public-site.mjs", "site:publish:check": "node scripts/publish-public-site.mjs --prepare-only" }, diff --git a/scripts/test-public-app-copy-voice.mjs b/scripts/test-public-app-copy-voice.mjs new file mode 100644 index 00000000..2abf3f5f --- /dev/null +++ b/scripts/test-public-app-copy-voice.mjs @@ -0,0 +1,96 @@ +import { readFileSync } from "node:fs" +import { fileURLToPath } from "node:url" +import { dirname, join } from "node:path" + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..") +const read = (p) => readFileSync(join(ROOT, p), "utf8") + +let failures = 0 +let checks = 0 +const ok = (cond, msg) => { + checks++ + if (cond) console.log(` ok ${msg}`) + else { + failures++ + console.error(` FAIL ${msg}`) + } +} + +// The four public app pages (Promptly and Drishti product + privacy pages). +// PR #28 cleaned the product and support pages and this change cleans the +// residual product-page eyebrows and the app privacy pages; kept as an +// explicit list so a new app page with the old editorial voice fails CI +// instead of being silently missed. +const APP_PAGES = [ + "public/drishti/index.html", + "public/drishti/privacy/index.html", + "public/promptly/index.html", + "public/promptly/privacy/index.html" +] + +// The old copy spoke to Tiny Studio's own team or Apple's reviewer instead of +// visitors: H1s on the launch calendar ("already in place before launch", +// "already public ahead of release"), leads about the "current planned launch +// scope" and "final App Store privacy disclosures", a "Current release scope" +// aside ("not publicly released yet"), "At launch" cards, editor-facing +// "Where to go next" eyebrows, and notes that the page and App Store privacy +// answers should be updated before the next submission. Any of these +// fragments anywhere on an app page means the visitor-facing rewrite has +// regressed. +const EDITORIAL_FRAGMENTS = [ + "Where to go next", + "already", + "launch", + "planned", + "not publicly released", + "App Store", + "submission", + "in the meantime", + "current build", + "should stay aligned", + "should be updated before", + "before that version is submitted", + "Current release scope" +] + +// The replacement copy names the actual app and keeps the public support +// route. Each page must keep both so an over-aggressive rewrite that deletes +// product identity or the support path fails CI. +const PAGE_REQUIREMENTS = { + "public/drishti/index.html": ["Drishti", "support@tinystudio.in"], + "public/drishti/privacy/index.html": ["Drishti", "support@tinystudio.in"], + "public/promptly/index.html": ["Promptly", "support@tinystudio.in"], + "public/promptly/privacy/index.html": ["Promptly", "support@tinystudio.in"] +} + +console.log("test-public-app-copy-voice: the four public app pages carry only visitor-facing copy") + +console.log("A. every app page keeps visitor-facing product and support copy") +for (const page of APP_PAGES) { + const html = read(page) + for (const fragment of PAGE_REQUIREMENTS[page]) { + ok(html.includes(fragment), `${page} names ${fragment}`) + } +} + +console.log("B. no app page carries editorial or submission-prep phrasing") +for (const page of APP_PAGES) { + const html = read(page) + for (const fragment of EDITORIAL_FRAGMENTS) { + ok(!html.includes(fragment), `${page} avoids "${fragment}"`) + } +} + +console.log("C. npm test/ci wiring") +const pkg = JSON.parse(read("package.json")) +ok( + pkg.scripts.test.includes("test-public-app-copy-voice.mjs"), + "npm test runs the public app copy voice test" +) +ok( + pkg.scripts.ci.includes("test-public-app-copy-voice.mjs"), + "npm run ci runs the public app copy voice test" +) + +console.log(`\n${checks} checks, ${failures} failures`) +process.exit(failures === 0 ? 0 : 1) From c9d06f0840e8f5b1fe72fe487c78e65ceff620b6 Mon Sep 17 00:00:00 2001 From: Nish <257724087+nish3451@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:06:54 +0530 Subject: [PATCH 3/3] Assert the entity-encoded support address, not the plaintext one PR #123 replaced the literal support@tinystudio.in in the public HTML with support@tinystudio.in so Cloudflare Email Address Obfuscation cannot rewrite it into a [email protected] placeholder, and its live check now asserts the plaintext form is absent. This guard still required the plaintext form, so the two contradicted each other. Updated to match the landed encoding. --- scripts/test-public-app-copy-voice.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/test-public-app-copy-voice.mjs b/scripts/test-public-app-copy-voice.mjs index 2abf3f5f..9c97b68f 100644 --- a/scripts/test-public-app-copy-voice.mjs +++ b/scripts/test-public-app-copy-voice.mjs @@ -57,10 +57,10 @@ const EDITORIAL_FRAGMENTS = [ // route. Each page must keep both so an over-aggressive rewrite that deletes // product identity or the support path fails CI. const PAGE_REQUIREMENTS = { - "public/drishti/index.html": ["Drishti", "support@tinystudio.in"], - "public/drishti/privacy/index.html": ["Drishti", "support@tinystudio.in"], - "public/promptly/index.html": ["Promptly", "support@tinystudio.in"], - "public/promptly/privacy/index.html": ["Promptly", "support@tinystudio.in"] + "public/drishti/index.html": ["Drishti", "support@tinystudio.in"], + "public/drishti/privacy/index.html": ["Drishti", "support@tinystudio.in"], + "public/promptly/index.html": ["Promptly", "support@tinystudio.in"], + "public/promptly/privacy/index.html": ["Promptly", "support@tinystudio.in"] } console.log("test-public-app-copy-voice: the four public app pages carry only visitor-facing copy")