Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f2ca885
test(public): guard public pages against launch-prep footer copy regr…
nish3451 Aug 14, 2026
ce85a55
docs(lane): add lane1 public footer copy regression guard report
nish3451 Aug 14, 2026
4928da8
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
7442d98
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
a85393c
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
a5ec2d1
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
6bcaf26
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
46827f4
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
03a0ec2
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
e86de34
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
e86d315
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
bfcd1b7
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 14, 2026
d958872
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
f7ab93b
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
4e08b2d
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
29fdf04
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
4cca3af
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
cdc03f7
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
0b5fefc
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
08ebe81
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
59747ee
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
e014741
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
5154669
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
272fe5b
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
240f395
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
a856402
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 15, 2026
5926d09
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
bd119b4
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
88c5aa4
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
9974188
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
c33a938
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
32e500b
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
45f448c
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 17, 2026
abbb417
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 18, 2026
bad65ca
Merge branch 'main' into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 19, 2026
2b51796
Merge origin/main into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 19, 2026
d83c8df
Merge origin/main into fix/lane1-public-footer-copy-regression-guard
nish3451 Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .lane/reports/fix-lane1-public-footer-copy-regression-guard.md
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
98 changes: 98 additions & 0 deletions scripts/test-public-footer-copy.mjs
Original file line number Diff line number Diff line change
@@ -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("<footer")
const end = html.indexOf("</footer>")
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(/<p class="footer-copy"[^>]*>([\s\S]*?)<\/p>/)
ok(copyBlock !== null, `${page} has a .footer-copy paragraph`)
if (!copyBlock) continue

const copy = copyBlock[1]
for (const fragment of VISITOR_FACING_FRAGMENTS) {
ok(copy.includes(fragment), `${page} footer copy names ${fragment}`)
}
for (const fragment of LAUNCH_PREP_FRAGMENTS) {
ok(!copy.includes(fragment), `${page} footer copy avoids "${fragment}"`)
}
}

console.log("B. no launch-prep phrasing survives anywhere in any footer block")
for (const page of FOOTER_PAGES) {
const footer = footerBlockOf(read(page))
for (const fragment of LAUNCH_PREP_FRAGMENTS) {
ok(!footer.includes(fragment), `${page} footer has no "${fragment}"`)
}
}

console.log("C. npm test/ci wiring")
const pkg = JSON.parse(read("package.json"))
ok(
pkg.scripts.test.includes("test-public-footer-copy.mjs"),
"npm test runs the public footer copy test"
)
ok(
pkg.scripts.ci.includes("test-public-footer-copy.mjs"),
"npm run ci runs the public footer copy test"
)

console.log(`\n${checks} checks, ${failures} failures`)
process.exit(failures === 0 ? 0 : 1)