diff --git a/package.json b/package.json
index 686b5d29..d15811e0 100644
--- a/package.json
+++ b/package.json
@@ -94,9 +94,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/test-operator-check-strictness.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-theme-color.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && node scripts/test-pr-duplicates.mjs && node scripts/test-public-support-contact-voice.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/test-operator-check-strictness.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-theme-color.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && node scripts/test-pr-duplicates.mjs && node scripts/test-public-support-contact-voice.mjs && node scripts/test-public-app-copy-voice.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/test-operator-check-strictness.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-theme-color.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && node scripts/test-pr-duplicates.mjs && node scripts/test-public-support-contact-voice.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/test-operator-check-strictness.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-theme-color.mjs && node scripts/test-public-soft-404.mjs && node scripts/test-public-deploy-bundle.mjs && node scripts/test-deploy-public-site-workflow.mjs && node scripts/test-pages-release.mjs && node scripts/test-pr-duplicates.mjs && node scripts/test-public-support-contact-voice.mjs && node scripts/test-public-app-copy-voice.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/public/drishti/index.html b/public/drishti/index.html
index c822db69..8088542f 100644
--- a/public/drishti/index.html
+++ b/public/drishti/index.html
@@ -189,7 +189,7 @@
Built around rituals, streaks, and compassion.
- Where to go next
+ Help and next steps
- Drishti support
- Drishti privacy
diff --git a/public/promptly/index.html b/public/promptly/index.html
index 19acdc78..4d87487e 100644
--- a/public/promptly/index.html
+++ b/public/promptly/index.html
@@ -190,7 +190,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 f941ba7e..09e00b09 100644
--- a/public/promptly/privacy/index.html
+++ b/public/promptly/privacy/index.html
@@ -152,7 +152,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.
diff --git a/scripts/test-public-app-copy-voice.mjs b/scripts/test-public-app-copy-voice.mjs
new file mode 100644
index 00000000..9c97b68f
--- /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)