diff --git a/.lane/reports/fix-lane1-public-footer-copy-regression-guard.md b/.lane/reports/fix-lane1-public-footer-copy-regression-guard.md new file mode 100644 index 00000000..c7658da6 --- /dev/null +++ b/.lane/reports/fix-lane1-public-footer-copy-regression-guard.md @@ -0,0 +1,63 @@ +# Lane report: fix/lane1-public-footer-copy-regression-guard + +## Item + +- [ ] [unreviewed-by-opus] Eleven public pages still end with launch-prep footer copy ("clean public foundation before l + +## What was wrong + +PR #35 (`fix(public): replace launch-prep footer copy on all public pages`) +replaced the eleven shared-footer pages' footer copy +("Tiny Studio builds independent iPhone apps and gives each product a +clean public foundation before launch.") with visitor-facing copy that +names the actual products and what they do. The replacement shipped +without a regression test, so adding a new public page or accidentally +editing the footer would not fail CI. + +The original follow-up test (commit `26c7e35` on +`fix/public-footer-copy-regression-guard`) was created on 2026-08-11 but +never merged to `main`. Without the test wired in, every PR that touches +`public/*.html` carries the same risk that motivated PR #35 in the first +place. + +## What I changed + +- `scripts/test-public-footer-copy.mjs` (new, 98 lines): explicit + FOOTER_PAGES list of the 12 shared-footer pages (the eleven + studio/product/support/legal pages plus the 404 page); fails CI if any + footer block re-introduces `clean public foundation`, `foundation + before launch`, `gives each product`, or `before launch`, or drops the + visitor-facing `Promptly`/`Drishti` product names. +- `package.json`: wired the new test into both `npm test` and `npm run ci` + in the natural position between the soft-404 and deploy-bundle public + tests (matches the existing sibling layout). + +Branch: `fix/lane1-public-footer-copy-regression-guard` (fresh from +`origin/main@377c27e`, single commit `f2ca885`). +PR: https://github.com/nish3451/tinystudio-in/pull/151 + +## Verification + +- `node scripts/test-public-footer-copy.mjs` -> **146 checks, 0 failures** + (Section A: 60 footer-copy/visitor-name checks; Section B: 48 + block-fragment checks; Section C: 2 npm wiring checks; 36 footer-block + presence checks). +- `find scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check` -> clean. +- `git push` succeeded to + `fix/lane1-public-footer-copy-regression-guard`; `gh pr create` opened + PR #151 against `main`. + +## What this lane deliberately did NOT do + +- Did not modify any `public/*.html` file. The 12 footers are already + fixed by PR #35; this lane adds the regression guard so they stay + fixed. +- Did not touch the body copy on + `public/promptly/privacy/index.html`, + `public/drishti/privacy/index.html`, `public/privacy/index.html`, or + `public/terms/index.html`, which still carry internal submission-prep + copy (tracked by separate lanes under + `fix/remove-submission-prep-copy-privacy-pages` and friends). +- Did not touch the homepage (`public/index.html`), which has a distinct + footer block ("Small studio. Clear lanes. Better signal.") and is not + on the FOOTER_PAGES list. diff --git a/package.json b/package.json index 94972244..002ab480 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 && node scripts/test-public-app-copy-voice.mjs && node scripts/test-public-meta-descriptions.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 && node scripts/test-public-meta-descriptions.mjs && node scripts/test-public-footer-copy.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 && node scripts/test-public-app-copy-voice.mjs && node scripts/test-public-meta-descriptions.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 && node scripts/test-public-meta-descriptions.mjs && node scripts/test-public-footer-copy.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-footer-copy.mjs b/scripts/test-public-footer-copy.mjs new file mode 100644 index 00000000..afb18acb --- /dev/null +++ b/scripts/test-public-footer-copy.mjs @@ -0,0 +1,98 @@ +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}`) + } +} + +// Every public page that carries the shared footer block. Kept as an explicit +// list so adding a new page with the old launch-prep footer copy fails CI +// instead of being silently missed. +const FOOTER_PAGES = [ + "public/404.html", + "public/contact/index.html", + "public/drishti/index.html", + "public/drishti/privacy/index.html", + "public/drishti/support/index.html", + "public/privacy-choices/index.html", + "public/privacy/index.html", + "public/promptly/index.html", + "public/promptly/privacy/index.html", + "public/promptly/support/index.html", + "public/support/index.html", + "public/terms/index.html" +] + +// The old footer line described the internal launch-prep process ("gives each +// product a clean public foundation before launch"). Any of these fragments +// in a footer block means the visitor-facing rewrite has regressed. +const LAUNCH_PREP_FRAGMENTS = [ + "clean public foundation", + "foundation before launch", + "gives each product", + "before launch" +] + +// The replacement footer line names the actual products and what they do. +const VISITOR_FACING_FRAGMENTS = ["Promptly", "Drishti"] + +const footerBlockOf = (html) => { + const start = html.indexOf("") + return start >= 0 && end > start ? html.slice(start, end) : "" +} + +console.log("test-public-footer-copy: no public page ends with launch-prep footer copy") + +console.log("A. every page with the shared footer block has visitor-facing footer copy") +for (const page of FOOTER_PAGES) { + const html = read(page) + const footer = footerBlockOf(html) + ok(footer.length > 0, `${page} has a footer block`) + if (footer.length === 0) continue + + const copyBlock = footer.match(/