Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions scripts/check_growth_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
CATALOG_MIN_ITEMS = 92
FEATURED_SLUGS = ("debate-me", "tappitsu-battle", "future-me", "twotaku")
GROWTH_RELEASE_ID = "growth-20261106-wave2"
GROWTH_LASTMOD_BASELINE = "2026-11-07"
GROWTH_UPDATED_PATHS = (
"/", "/apps",
"/support/taletime/", "/support/debate-me/",
"/support/dog-breeds-encyclopedia/", "/support/face-reaction-battle/",
"/guides/quick-games/", "/guides/daily-habits/",
"/guides/decision-helpers/", "/guides/ai-tools/",
)
PATHS = ("/", "/apps", "/robots.txt", "/sitemap.xml") + tuple(
f"/support/{slug}/" for slug in SLUGS
)
Expand Down Expand Up @@ -154,6 +162,18 @@ def check(path, key, valid):
loc = "https://appdevelopsk.com" + path
check("/sitemap.xml", f"listed_{path}", f"<loc>{loc}</loc>" in sitemap)

# Recent content changes must be discoverable through a current sitemap.
# Dates later than the baseline are valid when the page changes again.
for path in GROWTH_UPDATED_PATHS:
canonical = "https://appdevelopsk.com" + path
match = re.search(
r"<loc>" + re.escape(canonical) +
r"</loc>\s*<lastmod>(\d{4}-\d{2}-\d{2})</lastmod>",
sitemap,
)
check("/sitemap.xml", f"fresh_lastmod_{path}",
bool(match and match.group(1) >= GROWTH_LASTMOD_BASELINE))

return {"passed": all(item["passed"] for item in findings),
"passedChecks": sum(item["passed"] for item in findings),
"totalChecks": len(findings), "checks": findings,
Expand Down
32 changes: 28 additions & 4 deletions scripts/test_growth_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
import unittest

from check_growth_live import FEATURED_SLUGS, GROWTH_RELEASE_ID, PATHS, SLUGS, inspect
from check_growth_live import FEATURED_SLUGS, GROWTH_RELEASE_ID, GROWTH_UPDATED_PATHS, PATHS, SLUGS, inspect


def valid_pages():
Expand Down Expand Up @@ -59,9 +59,17 @@ def valid_pages():
f'<a href="{play}&amp;utm_source=test" data-position="details">' +
" ".join(f'<a href="/support/{x}/" data-related-app="{x}">' for x in other))
pages["/robots.txt"] = "User-agent: *\\nAllow: /icons/\\n"
pages["/sitemap.xml"] = "".join(
f"<loc>https://appdevelopsk.com{p}</loc>"
for p in ("/", "/apps") + tuple(f"/support/{s}/" for s in SLUGS))
pages["/sitemap.xml"] = (
"".join(
f"<loc>https://appdevelopsk.com{p}</loc><lastmod>2026-11-07</lastmod>"
for p in GROWTH_UPDATED_PATHS
) +
"".join(
f"<loc>https://appdevelopsk.com/support/{slug}/</loc>"
for slug in SLUGS
if f"/support/{slug}/" not in GROWTH_UPDATED_PATHS
)
)
for path in ("/", "/apps") + tuple(f"/support/{slug}/" for slug in SLUGS):
pages[path] = (f'<meta name="sk-growth-release" '
f'content="{GROWTH_RELEASE_ID}">' + pages[path])
Expand All @@ -74,6 +82,22 @@ def test_valid_source_fixture_passes(self):
self.assertTrue(report["passed"])
self.assertEqual(report["passedChecks"], report["totalChecks"])

def test_recent_sitemap_timestamp_regression_fails(self):
data = valid_pages()
data["/sitemap.xml"] = data["/sitemap.xml"].replace(
"<loc>https://appdevelopsk.com/apps</loc><lastmod>2026-11-07</lastmod>",
"<loc>https://appdevelopsk.com/apps</loc><lastmod>2026-11-06</lastmod>",
)
self.assertFalse(inspect(data)["passed"])

def test_missing_recent_sitemap_page_fails(self):
data = valid_pages()
data["/sitemap.xml"] = data["/sitemap.xml"].replace(
"<loc>https://appdevelopsk.com/guides/ai-tools/</loc><lastmod>2026-11-07</lastmod>",
"",
)
self.assertFalse(inspect(data)["passed"])

def test_missing_related_link_fails(self):
data = valid_pages()
data["/support/future-me/"] = data["/support/future-me/"].replace(
Expand Down
61 changes: 61 additions & 0 deletions scripts/test_sitemap_growth_freshness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Validate catalog and recently revised support/guide sitemap dates.

Run with: python3 -m unittest discover -s scripts -p 'test_sitemap_growth_freshness.py' -v
"""
from datetime import date
from pathlib import Path
import unittest
import xml.etree.ElementTree as ET

ROOT = Path(__file__).resolve().parent.parent
NS = "{http://www.sitemaps.org/schemas/sitemap/0.9}"
BASE = "https://appdevelopsk.com"
CHANGED_2026_11_07 = (
"/", "/apps",
"/support/taletime/", "/support/debate-me/",
"/support/dog-breeds-encyclopedia/", "/support/face-reaction-battle/",
"/guides/quick-games/", "/guides/daily-habits/",
"/guides/decision-helpers/", "/guides/ai-tools/",
)


def entries():
root = ET.parse(ROOT / "sitemap.xml").getroot()
if root.tag != NS + "urlset":
raise ValueError("unexpected sitemap XML root")
records = []
for item in root.findall(NS + "url"):
url = item.findtext(NS + "loc")
lastmod = item.findtext(NS + "lastmod")
records.append((url, lastmod))
return records


class GrowthSitemapFreshnessTests(unittest.TestCase):
def test_sitemap_canonical_urls_are_unique(self):
records = entries()
urls = [url for url, _ in records]
self.assertEqual(len(urls), len(set(urls)))
self.assertGreaterEqual(len(urls), 319)
self.assertTrue(all(url.startswith(BASE + "/") for url in urls))
self.assertNotIn(BASE + "/apps.html", urls)

def test_changed_pages_have_accurate_nov_7_date(self):
pages = dict(entries())
for path in CHANGED_2026_11_07:
with self.subTest(path=path):
self.assertEqual(pages.get(BASE + path), "2026-11-07")

def test_sitemap_dates_are_valid_and_not_future(self):
for url, stamp in entries():
with self.subTest(url=url):
parsed = date.fromisoformat(stamp)
self.assertLessEqual(parsed, date.today())

def test_filtered_catalog_urls_are_not_indexed_separately(self):
urls = [url for url, _ in entries()]
self.assertFalse(any("?goal=" in url for url in urls))


if __name__ == "__main__":
unittest.main()
20 changes: 10 additions & 10 deletions sitemap.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://appdevelopsk.com/</loc><lastmod>2026-11-05</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>
<url><loc>https://appdevelopsk.com/</loc><lastmod>2026-11-07</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>
<url><loc>https://appdevelopsk.com/about</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.4</priority></url>
<url><loc>https://appdevelopsk.com/contact</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.4</priority></url>
<url><loc>https://appdevelopsk.com/privacy</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.4</priority></url>
<url><loc>https://appdevelopsk.com/terms</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.4</priority></url>
<url><loc>https://appdevelopsk.com/apps</loc><lastmod>2026-11-06</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://appdevelopsk.com/apps</loc><lastmod>2026-11-07</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>
<url><loc>https://appdevelopsk.com/support/</loc><lastmod>2026-08-18</lastmod><changefreq>weekly</changefreq><priority>0.6</priority></url>
<url><loc>https://appdevelopsk.com/privacy-policy/</loc><lastmod>2026-08-18</lastmod><changefreq>weekly</changefreq><priority>0.3</priority></url>
<url><loc>https://appdevelopsk.com/support/30sec-challenge/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
Expand All @@ -27,16 +27,16 @@
<url><loc>https://appdevelopsk.com/support/daily-duel/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/date-pilot/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/date-roulette/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/debate-me/</loc><lastmod>2026-11-05</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/debate-me/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/debrief/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/dinner-home-roulette/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/dinosaur-encyclopedia/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/dog-breeds-encyclopedia/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/dog-breeds-encyclopedia/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/dream-log/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/drift/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/earsense/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/eye-break/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/face-reaction-battle/</loc><lastmod>2026-10-27</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/face-reaction-battle/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/face-symmetry/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/face-vibe/</loc><lastmod>2026-11-04</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/fileforce/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
Expand Down Expand Up @@ -112,7 +112,7 @@
<url><loc>https://appdevelopsk.com/support/study-roulette/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/sub-tracker/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/take-sides/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/taletime/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/taletime/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/tappitsu-battle/</loc><lastmod>2026-11-05</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/tier-rank-me/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://appdevelopsk.com/support/tracepedia/</loc><lastmod>2026-08-18</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>
Expand Down Expand Up @@ -315,8 +315,8 @@
<url><loc>https://appdevelopsk.com/terms/smile-score/</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.3</priority></url>
<url><loc>https://appdevelopsk.com/terms/idea-market/</loc><lastmod>2026-11-04</lastmod><changefreq>yearly</changefreq><priority>0.3</priority></url>
<url><loc>https://appdevelopsk.com/csae-standards/</loc><lastmod>2026-08-18</lastmod><changefreq>yearly</changefreq><priority>0.3</priority></url>
<url><loc>https://appdevelopsk.com/guides/quick-games/</loc><lastmod>2026-10-30</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/daily-habits/</loc><lastmod>2026-10-27</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/decision-helpers/</loc><lastmod>2026-10-27</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/ai-tools/</loc><lastmod>2026-10-27</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/quick-games/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/daily-habits/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/decision-helpers/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
<url><loc>https://appdevelopsk.com/guides/ai-tools/</loc><lastmod>2026-11-07</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url>
</urlset>
Loading