OpenIssues.md
Auto-synced mirror · last updated 2026-06-12
# ŚUBHAKĀLA — OPEN ISSUES
**Purpose.** Living register of known inconsistencies and defects across the live site,
focused (for now) on the Pañcāṅga surface. Each session: read this file, fix what you can,
and delete rows that are resolved. **Goal: keep this file empty.**
Mirror: /openissues-md/ (auto-synced by sync_context.py). Canonical copy on GitHub.
_Last audit: 2026-06-06 (read-only consistency audit, 7 representative pages)._
> **SCOPE WIDENING (2026-06-06):** the consistency pass must cover **all front-door pages**
> — homepage `/`, About, stotrams index, Join (membership) — not just Pañcāṅga. ISS-11 shows the
> same "uncommitted generator → cron reverts nightly" drift hits the homepage too; the others
> (stotrams index, Join) are not yet audited and likely share copy/brand drift. Audit them next.
_2026-06-06: added ISS-08 (calculator location selector — browser→Nominatim geocode 403/throttle; diagnose-only)._
---
## SCOPE OF THIS AUDIT
Pages sampled (rendered HTML, fetched as a guest via the origin-IP bypass):
| # | Page | URL | HTTP | Notes |
|---|------|-----|------|-------|
| 1 | Oldest static date | /panchanga-bengaluru-2026-05-17/ | 200 | range start |
| 2 | Mid-range past | /panchanga-bengaluru-2026-05-22/ | 200 | |
| 3 | **Today** | /panchanga-bengaluru-2026-06-06/ | 200 | **~124 KB vs ~161 KB — degraded** |
| 4 | Tomorrow | /panchanga-bengaluru-2026-06-07/ | 200 | full template |
| 5 | Far future in-range | /panchanga-bengaluru-2027-04-15/ | 200 | full template |
| 6 | Pañcāṅga index | /panchanga/ | 200 | calendar surface |
| 7 | Calculator | /panchanga/panchanga-calculator/?date=… | 200 | dynamic surface |
Routing checks (separate from the matrix):
- `/panchanga-calculator/?date=…` → **301** → `/panchanga/panchanga-calculator/?date=…` ✓ (canonical alias works).
- Calculator with an **out-of-range** date (`?date=2030-01-01`) → **200**, renders client-side (any date OK). ✓
- Direct **static** URL for an out-of-range date (`/panchanga-bengaluru-2030-01-01/`) → **404** (no graceful fallback — see ISS-04).
- Static range is 2026-05-17 → 2027-05-16 (365 pages).
---
## PRESENCE MATRIX
Legend: ✓ present · `—` absent · (rt) runtime-injected · (baked) in saved page HTML.
Columns: 1=oldest 2=midpast 3=**today** 4=tmrw 5=future 6=index 7=calc.
| Element | Delivery | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---------|----------|---|---|---|---|---|---|---|
| Top nav: logo + menu | (rt) theme | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Day-nav prev / next arrows | (baked) _s1 | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| **'Today' button** | (baked) _s1 | ✓ | ✓ | **—** | ✓ | ✓ | — | — |
| Page header / title | (baked) _s1 | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| Calculator form / banner | (baked) calc page | — | — | — | — | — | ✓ | ✓ |
| Five Elements (Tithi/Nakṣ/Yoga/Karaṇa) | (baked) _s2 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Karaṇa panel | (baked) _s2 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Sunrise / Sunset | (baked) _s5 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Rāhu Kāla | (baked) _s3/_s4 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Gulika | (baked) _s3/_s4 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Yamāghanda (timeline + list) | (baked) _s3/_s4 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Chandrabalam + Tarabalam | (baked) _s_cb_tb + JS | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| **Today's Sky chart** | (baked) _s_sky + JS | ✓ | ✓ | **—** | ✓ | ✓ | — | — |
| └ N / S Indian toggle | (baked) _s_sky | ✓ | ✓ | **—** | ✓ | ✓ | — | — |
| └ Planetary positions table | (rt) JS → /api/kundli | ✓ | ✓ | **—** | ✓ | ✓ | — | — |
| Upcoming Transitions | (baked) _s7 | ✓ | ✓ | ✓ | ✓ | ✓ | — | — |
| **'Today for you' strip** | (baked) _s_tfy + (rt) SK_USER | ✓ | ✓ | **—** | ✓ | ✓ | — | — |
| Footer (template _s8) | (baked) _s8 | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| └ contains "Swiss Ephemeris" | (baked) _s8 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
### Divergences flagged
- **Today (col 3) is missing 'Today's Sky' chart, N/S toggle, planetary table, 'Today for you' strip, AND the 'Today' button** — every other daily page has them. Page is ~124 KB vs ~161 KB. → ISS-01.
- **Calculator (col 7) is missing 'Today's Sky' chart, 'Upcoming Transitions', and 'Today for you' strip** that the static daily pages have. → ISS-05.
- **"Swiss Ephemeris" appears in the footer on every page** (forbidden by DESIGN.md). → ISS-02.
- Index (col 6) intentionally lacks daily-detail sections (different surface) — not a defect.
- Calculator/index intentionally lack the day-nav arrows/header (different surface) — not a defect.
### Non-issues confirmed (so we don't re-chase them)
- Yamāghanda **is** rendered on all daily pages (timeline `tl-seg` tooltip **and** the Inauspicious Timings list row) — present, not missing.
- Tithi / Nakṣatra / Yoga / Karaṇa panels present and structurally identical across all daily pages.
- Chandrabalam + Tarabalam present on all daily pages + calculator.
- 'Today for you' SK_USER personalisation fixed last session (no-store hydrator) — works where the strip exists.
---
## OPEN ISSUES
| ID | Issue | Affected | Sev | Suspected root cause | Status |
|----|-------|----------|-----|----------------------|--------|
| ISS-08 | **Calculator location selector has no effect — Pañcāṅga always computes Bengaluru.** | /panchanga-calculator/ (page 7712, /panchanga/panchanga-calculator/) | **P0** | **CAPTURE layer (client-side geocoding), not request/compute/render.** The form geocodes the typed city by calling the public OSM endpoint `nominatim.openstreetmap.org/search` **directly from the browser**. OSM throttles/blocks this (observed **HTTP 403**, 5/5 rapid requests; 403 even with a generic UA — only a full real-browser UA+Referer got 200). On a non-2xx/empty geocode the submit handler hits its `.catch`/empty branch and **returns without navigating** (`panchanga_calculator.html` submit handler, lines ~436–445), so `state.lat/lon` stay at the Bengaluru `DEF` and the page recomputes Bengaluru — only a small form-hint changes, which users miss. **Verified working when coords ARE supplied:** end-to-end headless run typed "Mumbai" → geocoded 19.055/72.869 → navigated `?lat=19.0550&lon=72.8692` → API `…&lat=19.055&lon=72.8692` → rendered Mumbai (sunrise 06:00 vs Bengaluru 05:53). API itself is correct (returns Mumbai times for Mumbai lat+lon; the `lng`-only path is wrong but the page sends `lon`). So request/compute/render are sound; the break is the unreliable browser→Nominatim geocode. _One-line fix (not applied): geocode via our own backend — add a server-side `/api/geocode?q=` proxy (Railway/Flask) that calls Nominatim with a compliant identifying User-Agent + caching, and point the calculator at it instead of calling nominatim.openstreetmap.org from the browser._ | **RESOLVED — Pañcāṅga pages now location-aware (2026-06-12).** Runtime snippet **`sk-location` (id 74, front-end, `code_error=None`; source `location_snippet.php`)**. **INDEX** (/panchanga/): re-wires the existing `#pi-city-search` (clone-drops the baked "coming soon" handler) to a **curated local city list** (~55 major IN + diaspora cities, instant, diacritic-insensitive) — made PRIMARY because **`/api/geocode` is currently DOWN** (hangs ~30 s → HTTP 500; Nominatim now throttles the *server*, i.e. ISS-08 moved server-side); `/api/geocode` kept as a 6 s-timeout fallback. Selecting a city stores `localStorage.sk_loc={name,lat,lon}`, updates `.pi-city-chip`, shows `#pi-city-note` ("Calendar overview shows Bengaluru; open any date for <city> timings"), and the stale "Calculated with Lahiri ayanāṃśa and Swiss Ephemeris" attribution is removed. **DAILY** pages: on load read `sk_loc`; if not Bengaluru, fetch **`/api/panchanga` (live, correct)** for the page's date (from the URL slug / `#pr-hdr-title`) + city and re-render every LOCATION-DEPENDENT value — sun/moon times, day/night length, Rāhu/Gulika/Yamagaṇḍa + Brahma/Abhijit/Durmuhūrtam in both the list **and** the rebuilt day-timeline, plus the header location pill; shows a loading bar; on API failure falls back to the printed Bengaluru data **with a visible "Showing Bengaluru timings" warning** (never silent wrong-city data). The five limbs are location-independent in IST (transition instants identical) so they're touched only if the API value differs. **Accuracy gate (2026-06-12, for manual DrikPanchang check):** Delhi 05:23/19:19/Rāhu 10:36–12:21 · Mumbai 06:00/19:16/10:59–12:38 · Kolkata 04:51/18:21/09:55–11:36 · Bengaluru 05:53/18:46/10:43–12:19; Tithi-end 19:38 + Nakṣatra-end 06:29 identical across cities (correct — single-instant transitions). **Verified live (Endurance purged, headless CDP):** daily Mumbai → all values switch to API-Mumbai + pill + note; daily Bengaluru → unchanged; persistence + revert work; index search selects→stores→chip→note; Swiss attribution gone; no wrong-city silent data. **Accepted gaps (logged):** (a) URLs stay `/panchanga-bengaluru-*` (cosmetic — recompute is by coords, not slug); (b) index calendar-grid Tithi cells stay Bengaluru-printed (note added; per-cell recompute deferred); (c) the "Today's Sky" transit chart + CB/TB strip keep Bengaluru sunrise (secondary, not a Pañcāṅga timing). **Remaining server-side follow-up:** fix `/api/geocode` on Railway (cache + short upstream timeout/retry so it can't 30 s-hang→500); until then the local city list is the search source. |
| ISS-06 | **Daily-page CHROME is still baked into 365 saved pages** (full runtime-chrome refactor not done). The *acute* drift (ISS-01) is fixed — the cron now ships the current template + JS, so cron output == bulk output — but a future template change still needs a 365-page re-push to propagate; chrome is not yet a single runtime source. | All 365 daily pages + calc | **P1** | No single runtime renderer; chrome is baked. Acute symptom removed (cron consistent); architectural refactor (global `sk-panchanga-chrome` snippet injecting chrome into placeholder containers) **deferred** — high blast radius on a live revenue site, warrants a reviewed staged rollout (build → one-page proof → bulk). **UPDATE 2026-06-07 — STAGED TEST DONE, GATE STOPPED BEFORE BULK:** built snippet `sk-panchanga-chrome` (id 47, now **deactivated**) that injects shared chrome into `.pr[data-sk-date]` placeholders, scoped so non-converted pages are untouched. Single-page test on page 1885 (2026-05-20): moved the **date-independent** chrome (day-nav incl. Today button on all pages, + footer) to the snippet, removed them from the baked HTML — verified live (headless via Cloudflare): converted page rendered **identical** to a normal page (nav injected w/ correct prev/next/Today, footer injected, all baked data sections intact). **MECHANISM PROVEN.** BUT the **full** chrome move is blocked: CB/TB and Today-for-you bake **date-specific values into their inline JS** (`var CUR_NK`, `var CUR_MOON` @template ln1032-33; `var MOON` @1258), and the shared CSS/JS bundles are large — these must be refactored to read date values from `data-*` attributes before they can move to a shared snippet. So "ALL chrome via snippet" is NOT yet achievable → per the gate, **did NOT bulk-apply**; reverted test page 1885 to baked (site uniform) and deactivated the snippet. **PLAN:** (1) refactor CB/TB + TFY + sky to read all date values from a single baked `#sk-panchanga-data` JSON/attrs; (2) move CSS + all JS + nav + footer + those containers into `sk-panchanga-chrome`; (3) re-run single-page gate; (4) bulk 365 + calc parity (ISS-05). **UPDATE 2026-06-07 #2 — STEP 1 (DATE-DECOUPLE) DONE + COMMITTED:** added `_s_data()` → bakes `<div id="sk-panchanga-data" data-date/-sunrise/-lat/-lng/-cur-nk/-cur-moon>` as the first child of `.pr`; refactored CB/TB + Today-for-you inline JS to read `CUR_NK`/`CUR_MOON`/`MOON` from that block — **zero hardcoded date literals remain in the JS** (verified by render). Functionally verified on one live page (1885 pushed decoupled, headless): CB/TB computed **Strong/Favourable** from the block, sky chart rendered, TFY present, no NEW JS errors (a pre-existing SyntaxError exists on normal pages too → ISS-14). Committed `29af6db` (cron-safe; cron migrates pages to the decoupled structure over time). Test page reverted to baked. **STILL PENDING (Step 2/3):** the large faithful port of CB/TB + TFY + sky + transitions HTML/JS *into* `sk-panchanga-chrome` (~560 lines) + the all-chrome single-page gate — NOT done this run; did NOT bulk. The date-decouple now unblocks it. | Open (decouple done; full unify + gate pending) |
| ISS-05 | **Calculator ≠ static-page parity**: dynamic calculator omits 'Today's Sky' chart, 'Upcoming Transitions', and 'Today for you' strip that static daily pages show. | /panchanga/panchanga-calculator/ | **P2** | Calculator is a separate artifact (`panchanga_calculator.html`) not in feature parity. Bundled with the deferred ISS-06 runtime-chrome refactor (the shared snippet would render the same chrome on the calculator too). | Open (deferred w/ ISS-06) |
| ISS-12 | **Stotrams index (/stotrams/) has a per-page EN/HI language toggle** (`.si-lang-btn` EN/हिन्दी buttons; `lang-btn`×7, `data-lang`×2) — DESIGN.md forbids per-page toggles (a global toggle is the planned approach). | /stotrams/ index (page 1636) | **P2** | Baked by `stotrams_index_rebuild.py` (`build_html`, lines ~299-300). Same brand-drift family as the homepage toggle (now removed). Generator is NOT cron-run (so no nightly auto-revert) but is uncommitted, so the committed copy differs. Fits **Cluster B** (copy/brand not aligned to DESIGN.md). | **Resolved (2026-06-09)** — toggle removed in the /stotrams/ deity-grouping rebuild; both scripts now shown statically. See **FEAT-STOTRAMS-DEITY**. |
| ISS-13 | **Uncommitted page generators = latent revert risk** — `stotrams_index_rebuild.py` and `panchanga_index_rebuild.py` are modified-but-uncommitted. Not currently in the nightly cron (so no active revert), but if either is ever added to cron — or the stale committed copy is run — it would overwrite live pages with old output (the ISS-01/ISS-11 disease). | stotrams index, Pañcāṅga index generators | **P3** | Working copies ahead of committed; no single source of truth. Fits **Cluster A**. _Fix: commit both (after review) so committed == live-producing source._ | Open |
| ISS-09 | **No automated cache purge (Cloudflare + Bluehost) — fixes stay invisible until a manual purge; blocks the consistency pass.** Edits made via WP REST only purge the *edited page's* Endurance cache; CSS/snippet/theme changes that affect many URLs (or pages not re-saved) keep serving stale HTML for up to `max-age=7200`. This is why the /about/ white-strip fix appeared to "fail" twice. | Site-wide infra | **P1 · NEAR-TERM** | No purge automation. Endurance Page Cache (`X-Endurance-Cache-Level:2`, 2h TTL) only auto-purges a URL on that page's own save. No Cloudflare API token in `.env` to purge the edge (CF currently isn't caching HTML, but could). **AGREED FIX:** a **Claude Code hook that auto-purges Cloudflare + Bluehost cache after every publish** — deterministic, fires automatically (not model-dependent), so a fix is never hidden by stale cache again. The hook calls `POST /client/v4/zones/{zone}/purge_cache` (full or per-URL) for Cloudflare and triggers the Endurance/Bluehost purge for the affected URLs. **PREREQUISITE:** add a **Cloudflare API token (+ zone id)** to `~/Claude/shubhakala/.env` first — without it the hook can only do the Bluehost side. **Priority: NEAR-TERM / high** — until this lands, every CSS/snippet/theme fix looks broken until a manual purge. **UPDATE 2026-06-06 — BROWSER-CACHE FACET ADDRESSED:** the worst contributor was the HTML browser TTL of `max-age=7200` (2h) — root cause was Endurance Page Cache's `text/html` expiry (option `epc_filetype_expirations` unset → 2h default; it also writes the mod_expires block and reconciles `.htaccess`, so manual `.htaccess`/`mod_headers` edits were overridden). Fixed durably by setting `epc_filetype_expirations['text/html'] = '5 minutes'` → live `Cache-Control: max-age=300` (verified via Cloudflare). Browser-side staleness now ≤5 min instead of 2 h. **STILL PENDING:** the active server-side auto-purge hook (Cloudflare edge + Endurance) needs the **Cloudflare API token + zone id in `.env`** — not yet added; CF currently shows `cf-cache-status: BYPASS` (not edge-caching HTML), and Bluehost per-URL purge still relies on a page re-save. | Open (browser-cache facet done; auto-purge + CF token pending) |
---
## ROOT-CAUSE CLUSTERS
Fix the cluster, not the symptom.
> **Status 2026-06-06:** Cluster B ✅ resolved (copy fixed in source + backfilled to all 366 pages).
> Cluster C ✅ resolved (redirect snippet id 35). Cluster A ◑ partial — the acute drift (ISS-01) is
> fixed by committing the template+JS so the cron is consistent; the full runtime-chrome refactor
> (ISS-06/05) is deferred for a reviewed staged rollout.
### Cluster A — Baked-template drift · (ISS-01 ✅, ISS-06 ◑, ISS-05 ☐)
**One cause:** daily Pañcāṅga content is *statically baked* — 365 saved pages from
`panchanga_template.py`, plus a *separate* `panchanga_calculator.html` for the dynamic view —
with no single runtime render. So (a) the nightly cron can re-bake today's page from an older
template (ISS-01), (b) every template change silently drifts until a 365-page re-push (ISS-06),
and (c) the calculator falls out of parity (ISS-05).
**Cluster fix options:** either (1) move daily rendering to a runtime shortcode/snippet that
renders from `panchanga.compute()` on request (kills the drift surface entirely), **or**
(2) make the cron import the *current* `panchanga_template.py` and trigger a full re-push on any
template change + bring the calculator to parity. Immediate stop-gap for ISS-01: re-push today's
page with the current template (and fix the cron's template source).
### Cluster B — Copy not aligned to DESIGN.md · (ISS-02, ISS-07)
**One cause:** `_s8` footer text and some labels predate DESIGN.md's language rules
("no Swiss Ephemeris", consistent IAST). **Cluster fix:** update the strings in
`panchanga_template.py` (`_s8` + Yamāghanda→Yamagaṇḍa) and re-push — folds into the same
re-push that fixes Cluster A.
### Cluster D — Browser→Nominatim geocoding is unreliable · (ISS-08)
**One cause:** the site geocodes city names by calling the public OSM Nominatim endpoint
*directly from the browser*, which OSM rate-limits/blocks (HTTP 403/429). When it fails, the
calculator's submit handler aborts without navigating, so the city silently has no effect.
**Note:** the same browser→Nominatim pattern is also used by the checkout (snippet 13) and
Muhūrta (snippet 31) place fields — they share this fragility. **Cluster fix:** one server-side
`/api/geocode` proxy (compliant User-Agent + caching) used by the calculator, checkout, and Muhūrta.
### Cluster C — No out-of-range fallback routing · (ISS-04)
**Standalone.** Add a catch-all redirect (snippet/`template_redirect`) mapping unmatched
`/panchanga-bengaluru-YYYY-MM-DD/` slugs to `/panchanga/panchanga-calculator/?date=YYYY-MM-DD`,
mirroring what the index month-picker already does for out-of-range months.
---
## ROADMAP (structural / tooling — prevent whole classes of issues)
| ID | Item | Why | Status |
|----|------|-----|--------|
| RM-01 | **Site-QA subagent** — a saved Claude Code subagent that audits all pages (pre-login + post-login) against DESIGN.md on a single command. | Audits currently need a fresh long prompt each time; a saved subagent makes "audit the whole site vs DESIGN.md" a one-liner and keeps coverage consistent (homepage, About, stotrams index, Join, Pañcāṅga, account/checkout — logged-out AND logged-in). | Planned |
| RM-02 | **Move colours + fonts to Kadence Global Styles** — define design tokens (the DESIGN.md palette + type scale) ONCE in the theme so every page inherits them. | Structural fix for design drift — the WordPress equivalent of the single-source-of-truth chrome snippet (ISS-06). Stops per-page/per-snippet colour hardcoding; new pages are on-brand by default. | Planned |
| RM-05 | **`/kundli/` follow-ups — D9 (Navāṃśa) chart + aesthetic overhaul.** Build the real **D9 divisional chart** (currently "coming soon" for Sādhaka+; locked for Śubha) reusing the chart renderer + `navamsa_sign` already in `kundli.py`/`/api/kundli`. Then a **visual/UX overhaul** of `/kundli/` (deferred from the FEAT-KUNDLI-PAGE build, which intentionally matched the existing chart style with no redesign). | `/kundli/` was shipped functionally (transit + natal + navigable Vimśottarī daśā, tier-gated) with D9 stubbed and styling kept minimal per scope. D9 data is already computable; the page just needs the D9 render + a polished layout. Also: server-side gating hides natal/daśā HTML from free users, but `/api/kundli` itself is public (CORS `*`) — if true data-gating is wanted later, proxy it server-side. | Planned |
---
## OPEN (additional)
| ID | Issue | Affected | Sev | Suspected root cause | Status |
|----|-------|----------|-----|----------------------|--------|
| ISS-14 | **Pre-existing JS `SyntaxError: Invalid or unexpected token` on daily Pañcāṅga pages** — one inline script fails to parse (discovered while testing ISS-06; present on normal pages too, so NOT caused by the decouple). CB/TB, sky, TFY, Today all still work, so the broken script is a minor/other one — but a parse error means *some* inline JS is dead. | All daily pages | **P2** | Likely a smart-quote / unescaped char in an inline script (CONTEXT notes a prior panchanga.js smart-quote fix; another instance remains). Source TBD — capture the failing line via DevTools. | Open |
| ISS-18 | **Razorpay→tier webhook does NOT exist** (CONTEXT claims "POST /webhook/razorpay deployed"). The route is absent from `app.py` and the live Railway API returns **404** for `POST /webhook/razorpay`; the root endpoint list omits it. So there is **no server-side, signature-verified amount→tier automation**; `RAZORPAY_WEBHOOK_SECRET` (per CONTEXT in Railway env) is unused. Membership grant depends entirely on Knit Pay→PMP. **Silent-failure risk:** the standalone Razorpay payment-button links (rzp.io/…) on /support/ are donation links **not wired to any membership grant** — a visitor paying via those gets no tier and nothing records it. | Railway Flask API (`app.py`), /support/ rzp.io links | **P0** | Webhook never implemented/deployed (CONTEXT overstated). Decide: (a) rely solely on Knit Pay→PMP for tier grants (then remove the webhook claim + don't use rzp.io links for tiers), or (b) actually build a signed `/webhook/razorpay` (HMAC-SHA256 over raw body using `RAZORPAY_WEBHOOK_SECRET`, urllib WP REST grant). NOTE: with Knit Pay "Razorpay – Easy Connect" (OAuth), the connected app handles payment verification on return; a separate webhook secret only applies if you configure a Razorpay webhook in the dashboard. | Open |
| ISS-22 | **Jetpack Protect math-captcha appears on the branded `/login/` flow and re-prompts ("solve to prove you're not a bot, then log in again"), creating a perceived login loop after repeated failed attempts from an IP.** Jetpack's brute-force gate runs on the `wp-login.php` interstitial *before* authentication; the branded `
Login · लॉग इन
Śubhakāla · शुभकाल
` form (`wp_login_form()`) carries no Jetpack math fields, so once an IP is flagged the math challenge can keep re-showing through the custom login page. Jetpack does **not** destroy the auth cookie — it gates before auth — so it is friction, not session-breaking. (Diagnosed 2026-06-08; the immediate trigger in the reported case was a stale/throwaway password causing repeated failures.) | `/login/` (branded) + `wp-login.php` interstitial; Jetpack Protect | **P2** | Jetpack Protect (brute-force protection) flagged-IP math gate + a custom login form that can't satisfy/clear it cleanly. **DEFERRED to post-launch as a known issue** (per owner, 2026-06-08). Options when addressed: allow-list trusted IPs in Jetpack → Protect, integrate Jetpack's captcha into the branded form, or disable brute-force protection in favour of another limiter. Do **not** change Jetpack now. | Open (deferred — post-launch) |
## PAYMENT / MEMBERSHIP / LOGIN AUDIT — 2026-06-07 (trace only, no config changed)
> **POST-FIX UPDATE (2026-06-07, later same day):** the BROKEN items below were then fixed (membership level
> config only, gateway untouched) — see RESOLVED ISS-16/17/19/20. Live levels table is now:
> Śubha(4)=₹101 · Sādhaka(5)=₹501 · Jyotiṣa(7)=₹2,501 · Lifetime(11)=₹11,001 — all **one-time**, billing 0,
> cycle none; 4/5/7 expire 1 Year, 11 never. Monthly(6,8,12)+Kula(9)+Praśna(10) `allow_signups=0` (hidden).
> Early Access(3)=free, 10-day expiry, + new snippet `sk-early-access-downgrade` → Śiṣya(2) on expiry.
> **Displayed price == charged price** for every listed tier (verified live). Gateway = Knit Pay **Test**.
> The original audit trace is kept below for history.
**Method:** read live Flask routes (Railway), live `9d9_pmpro_membership_levels` (read-only temp route, removed after),
sk-core (snippet 23) login/checkout/level logic, page HTTP statuses through Cloudflare, and a **real wp-login.php login**
with test user `vyasa_muni`. No test payment attempted. No payment config changed.
**Flow map — (a) brand-new visitor:**
/join/ **OK** → choose tier (`/membership-checkout/?level=N`, `?level=` is the standard PMP selector, not PII) **OK** →
/membership-checkout/ renders **OK** → ⚠ **for tiers 4–10,12 the price is ₹0 (ISS-16)** so Razorpay/Knit Pay is **never invoked** →
Razorpay (Easy Connect) **UNVERIFIED** (no test payment) → return/confirmation **UNVERIFIED** → tier granted **UNVERIFIED/BROKEN**
(₹0 levels would grant free; real charge path only exists for Lifetime, which is mispriced — ISS-17) → log back in **OK**.
**Flow map — (b) existing logged-in user upgrading:** login **OK** → /join/ or /membership-account/ → `/membership-checkout/?level=N`
**OK** → same Razorpay/return/grant steps **UNVERIFIED** (+ blocked by ISS-16/17). Account page `/membership-account/` renders for a
logged-in user **OK**.
**Amount→tier table (intended vs DB) — `gateway=knit_pay`, `pmpro_gateway_environment=live`:**
| Level id | Tier | Intended price | DB initial_payment | DB billing | Status |
|---|---|---|---|---|---|
| 2 | Śiṣya | Free | 0 | 0 | OK (free) |
| 3 | Early Access | Free (10-day) | 0 | 0 | OK (free, expires 10/Day) |
| 4 | Śubha (annual) | ₹101/yr | **0** | 0 | **BROKEN (ISS-16)** |
| 5 | Sādhaka (annual) | ₹501/yr | **0** | 0 | **BROKEN (ISS-16)** |
| 6 | Sādhaka (monthly) | ₹51/mo | **0** | 0 | **BROKEN (ISS-16)** |
| 7 | Jyotiṣa (annual) | ₹1,001/yr | **0** | 0 | **BROKEN (ISS-16)** |
| 8 | Jyotiṣa (monthly) | ₹101/mo | **0** | 0 | **BROKEN (ISS-16)** |
| 9 | Kula Jyotiṣa | ₹2,001/yr | **0** | 0 | **BROKEN (ISS-16)** |
| 10 | Praśna Retainer | ₹5,001/yr | **0** | 0 | **BROKEN (ISS-16)** |
| 11 | Lifetime | ₹11,001 once | **4999** | 0 | **MISMATCH (ISS-17)** |
| 12 | Śubha (monthly) | ₹21/mo | **0** | 0 | **BROKEN (ISS-16)** |
There is **no `/webhook/razorpay`** to map amounts → tiers (ISS-18); grants rely on Knit Pay→PMP only.
**Login flow — OK (verified live):** real wp-login.php POST as `vyasa_muni` → authenticated (`wordpress_logged_in` cookie set),
landed on **/welcome/** (HTTP 200, first-time onboarding; no 404), `/membership-account/` renders for the session (no bounce to
login). `logout_redirect`→ home, `login_redirect`→ /welcome/ (new) or today's Pañcāṅga (returning), same-site `redirect_to` honoured.
`/account/` 404s **by design** — nav + redirects correctly use `/membership-account/`. (A throwaway password was set on the test
account `vyasa_muni` for this check; reset in WP Admin if needed.)
**Security checklist:** HTTPS site-wide **OK** · login + checkout submit via **POST**, not GET **OK** · no password/PII in any
URL/query string (only `?level=` selector and same-site `?redirect_to=`) **OK** · passwords hashed by WP (phpass; REST set-password
is hashed, no plaintext stored) **OK** · webhook unsigned-request rejection **N/A — no webhook exists (ISS-18)** · secrets not
printed **OK**. (Could not inspect Railway env values directly; `WP_URL`/`WP_USER`/`WP_PASS` are clearly present since WP REST writes
work — `RAZORPAY_WEBHOOK_SECRET` presence **UNVERIFIED** and moot until a webhook exists.)
**Post-payment:** confirmation page `/membership-confirmation/` exists (guest → login, expected) **OK (page)** / real-order render
**UNVERIFIED** · granted-tier unlock of gated features **UNVERIFIED** (no real grant performed).
**Ranked fix-list before a Test-mode end-to-end run:**
1. **ISS-16 (P0)** — set real `initial_payment` on levels 4,5,6,7,8,9,10,12 (else everything is free).
2. **ISS-17 (P0)** — reconcile Lifetime price (DB 4999 vs shown 11,001).
3. **ISS-20 (P1)** — confirm Knit Pay Easy Connect is in Test mode (PMP env shows `live`).
4. **ISS-19 (P1)** — decide one-time vs recurring; fix cycle/trial fields + copy to match.
5. **ISS-18 (P0 for rzp.io path)** — either stop using rzp.io donation links for tiers, or build a signed webhook; confirm Knit Pay→PMP is the sole grant path.
_(Side note: `/api/geocode` proxy now EXISTS + works on Railway — the server-side fix for ISS-08; front-end wiring still to confirm.)_
## RESOLVED
| ID | Issue | Sev | Resolution (2026-06-07) |
|----|-------|-----|--------------------------|
| FIX-GRAHA-CLOCK-LABELS | Homepage Graha Ghaṭī dial (snippet 63): at the larger nakṣatra font several outer-ring labels rendered **crowded/touching** — worst on the left arc (Śravaṇa/Dhaniṣṭhā/Śatabhiṣā/P.Bhādra/U.Bhādra + the Āṣāḍha pair). Also: add per-boundary degree readouts so users can correlate the hand-tip degrees with nakṣatra positions. | P2 | **FIXED (2026-06-11) — snippet 63 + `graha_clock_snippet.php` in sync; astronomy/JS computation, hand-tip degree labels, and injection logic untouched; `code_error=None`.** **Root cause of the obscuring:** at SVG font 13 the long nakṣatra names (the 9-char single words + the P./U. compounds) spanned almost the entire 13° text-arc of each 13.33° segment, leaving ~0 gap between adjacent labels → crowding/touching, worst where several long names cluster on the left arc; the flip logic itself was correct (no true inversion — the "badly rotated" look was the crowding). **Fix:** nakṣatra SVG font **13→12**, text arc widened **±6.5°→±6.6°** (near the full segment), and the last over-long compounds shortened **P.Āṣāḍha→P.Āṣā, U.Āṣāḍha→U.Āṣā** (diacritics kept; P.Bhādra/U.Bhādra/P.Phalgu/U.Phalgu already shortened previously). **Boundary degrees (new):** at each of the 27 nakṣatra boundary spokes, a small dim-gold (opacity .55) label of the boundary's **degrees-within-rāśi** — computed by **exact arcminute math** (`(i*800)%1800` → no float drift, so 13°20′/26°40′/10°00′/23°20′/6°40′/20°00′/3°20′/16°40′/0°00′…), placed at the **inner edge of the nakṣatra ring (r=R_NAK_B+7) just outside the rāśi ring**, tangential + upright (same flip as the ring labels), 60% of the nakṣatra font (7.2), dark halo; **never collides** with nakṣatra/rāśi names (distinct radius). **Dropped on mobile** (`.skgc-bdeg{display:none}` ≤600px) since at 390px they'd be near-illegible — collision-free either way. **Verified live (Endurance purged) at true viewports via Chrome DevTools Protocol:** desktop **1440 → no h-scroll, 27 boundary labels all visible** (samples 0°00′/13°20′/26°40′/10°00′/23°20′), **all 27 nakṣatra + 12 rāśi names fully legible, zero overlap** (zoom-verified left arc + full ring), 0 overflowers; mobile **390 → no h-scroll, 27 boundary labels present but 0 visible (hidden)**, nakṣatra labels legible, chips stacked, 0 overflowers. Rollback unchanged: deactivate snippet **63**. _(Clipping item remains resolved — see also FEAT-GRAHA-CLOCK-INSTRUMENT / FIX-GRAHA-CLOCK-POLISH.)_ **Boundary-degree legibility refinement (2026-06-11, same day):** the first cut of the boundary degrees was too small/dim/radially-rotated to read, so they were reworked — now **curved ALONG the arc** (textPath + the same upper/lower-half flip as the names, upright-readable), enlarged to **9.4 (~78% of the 12 name font)**, brighter **#E3B84C at opacity .85**, placed **just clockwise of each boundary** (arc centre a0+4.2, r=R_NAK_B+9) in the clear band below the names (kept full degrees°minutes′ form). Re-verified via CDP: 1440 → all 27 legible, curved, collision-free with names/tick-ring/rāśi; 390 → still hidden, no overflow. **Full-name restoration + auto-fit (2026-06-11, same day):** the earlier truncations read as broken names, so **all 27 nakṣatras now render their COMPLETE name** (P.Phalgunī, U.Phalgunī, P.Āṣāḍhā, U.Āṣāḍhā, P.Bhādrapadā, U.Bhādrapadā — P./U. prefix kept). Each label **auto-fits to its arc**: it measures `getComputedTextLength()`, and if it exceeds the available arc (≈60 SVG units) shrinks the font to fit down to a **~70% legibility floor (8.4 of 12)**; if even the floor can't fit, the full name stays on desktop and an abbreviated form is swapped in **on mobile only** (`.skgc-nak-full`/`.skgc-nak-abbr`). **Measured result (CDP, identical at 1440 & 390 since it's SVG-relative):** only **P.Bhādrapadā → 80% (font 9.59)** and **U.Bhādrapadā → 78% (font 9.37)** were condensed (both above the floor); the other 4 long names fit full at 100%; **no mobile fallback triggered** (all fit above the floor → full names on mobile too); 0 overflow at either width. Zoom-verified all 6 long names render complete and legible at 1440. |
| FEAT-GRAHA-CLOCK-INSTRUMENT | Homepage Graha Ghaṭī dial (snippet 63): make it larger + more instrument-like (degree tick ring, hand-tip degree readouts) and re-confirm the P.Bhādrapadā/U.Bhādrapadā label clipping (OpenIssues P2) stays fixed at the new font size. | Feature | **DELIVERED (2026-06-11) — snippet 63 + `graha_clock_snippet.php` in sync; astronomy/JS computation + injection logic untouched; `code_error=None`.** **Size:** dial max-width 680→**760px** (container 720→800); `width:100%` so it still fits 360px with no horizontal scroll. **Fonts ~+25%:** heading clamp 30–42→**37–52px**, subtitle 16→20, chip label 13→16, **chip value 21→26** (mobile 19→23), chip detail 15→18, civil-time 16→20, note 13→16; SVG nakṣatra 12→13, rāśi 16→18 (these also scale with the bigger dial). **NEW degree tick ring** just inside the rāśi ring (`R_TICK_OUT=R_RAS_B-2`): 360 ticks — 1° thin/short (opacity .35), 5° longer (.45), 10° longest (.6), gold, **no numerals** (subtle but visible). **NEW hand-tip degree labels:** small upright readouts of degrees-in-rāśi at each hand — **gold for Sūrya, cream for Candra**, dark halo for legibility, **counter-rotated/absolute-positioned so they stay upright at any hand angle**, refreshed by the same 60s tick that moves the hands. Because the tips fall inside the tick/rāśi rings, they're placed in the **clear zone between the Ṣaḍkoṇa hub and the rāśi ring** (Sūrya r=120, Candra r=92 — different radii so they never collide with each other or the ring labels). **Conjunction stagger (2026-06-11):** when the two hands are **within 12°** (Amāvasyā, e.g. the new moon at 2026-06-15 03:00 UTC), the radial stagger widens — **Sūrya label moves outer (r=136), Candra inner (r=78)** — so the readouts never overlap when the bodies coincide; reverts to 120/92 otherwise. Verified live via CDP with the clock faked to the conjunction: at sep≈0.04° the labels sit at r136/78, **59px apart, no overlap** (Sun "29°50′" gold outer / Moon "29°52′" cream inner); within-12° (Tithi=Kṛṣṇa Amāvasyā) same stagger; a normal far-apart time keeps r120/92. **Label clipping stays fixed** (shortened compounds P.Bhādra/U.Bhādra/P.Phalgu/U.Phalgu/P.Āṣāḍha/U.Āṣāḍha) — verified at the new font 13. **Verified live (Endurance purged) at true viewports via Chrome DevTools Protocol Emulation:** desktop **1440 → dial 760px, no h-scroll, 409 SVG lines (= 360 ticks + 39 spokes + hands → tick ring present), 41 texts (27+12+2 degree labels)**, sun "25°59′"/moon "29°51′" labels upright at r≈120/92 (collision-free), **all 27 nakṣatra + 12 rāśi labels render fully** (zoom-verified incl. P.Bhādra/U.Bhādra/P.Phalgu/Anurādhā/Jyeṣṭha); mobile **390 → clientW 390 = scrollW 390 (no horizontal scroll)**, dial fits 326px, chips stacked & centered, 0 overflowers. Rollback unchanged: deactivate snippet **63**. _(Supersedes/extends FIX-GRAHA-CLOCK-POLISH; clipping item remains resolved.)_ |
| FIX-GRAHA-CLOCK-POLISH | Homepage Graha Ghaṭī dial (snippet 63, `sk-graha-clock`): long nakṣatra labels **P.Bhādrapadā / U.Bhādrapadā clipped** to ".Bhādrapad" on their arcs (known clipping issue from the Jun-10 build, not previously logged here); also requested bigger dial + bigger fonts. | P2 | **FIXED + POLISHED (2026-06-10) — snippet 63 + source `graha_clock_snippet.php` kept in sync; astronomy/JS computation + injection logic untouched.** **Bigger dial:** `.skgc-dialwrap` max-width **560→680px** (container 600→720); SVG is `width:100%` so it still fits a 360px screen with no horizontal scroll. **Bigger fonts:** heading clamp 24–34→**30–42px**, subtitle 13→16, chip label 11→13, **chip value 17→21**, chip detail 12→15, civil-time 13→16, note 11→13; SVG ring fonts nakṣatra 11.5→12 and rāśi 15→16 (these also scale ~+21% on-screen from the larger dial), nakṣatra label arc widened ±6→±6.5°. Net dial text ~+20–26%. **Label clipping fixed:** shortened the six long compound labels — P.Phalgunī→**P.Phalgu**, U.Phalgunī→**U.Phalgu**, P.Āṣāḍhā→**P.Āṣāḍha**, U.Āṣāḍhā→**U.Āṣāḍha**, P.Bhādrapadā→**P.Bhādra**, U.Bhādrapadā→**U.Bhādra** (single-word names kept full; all ≤9 chars fit the widened arc at font 12). **Mobile fix:** the larger chip fonts made the 2-up chip row overflow at ≤390px → chips now **stack vertically (1-col, max 300px centered)** at ≤600px. `code_error=None`. **Verified live (Cloudflare-fresh, Endurance purged) at true viewports via Chrome DevTools Protocol (CLI `--window-size` was unreliable — forced a 485px layout; used Emulation.setDeviceMetricsOverride instead):** desktop 1440 — dial visibly larger, **all 27 nakṣatra + 12 rāśi labels render fully, zero clipping** (zoom-verified incl. P.Bhādra/U.Bhādra/P.Āṣāḍha/U.Āṣāḍha/P.Phalgu/U.Phalgu); mobile **360px → clientW 360 = docScrollW 360 (no horizontal scroll)**, widget l32→r328 fits, 3 chips stacked & centered, 0 overflowers; 390px likewise no scroll. Rollback unchanged: deactivate snippet **63**. |
| FEAT-KUNDLI-PAGE | **Build a real `/kundli/` page** (was a 404) showing D1 natal chart + sunrise transit chart + navigable Vimśottarī daśā, tier-gated. Done in 2 phases with a human accuracy gate after Phase 1. | Feature | **Delivered (2026-06-09), two phases. No prices/gateway/Jetpack touched; existing daily Pañcāṅga Kundlī (#sk-sky) unchanged; reused its renderer + the live `/api/kundli` engine. No Flask/Railway change — the daśā engine already existed in `kundli.py`.** **Phase 1 (daśā accuracy gate):** confirmed `kundli.py`'s existing Vimśottarī engine (ephem, Lāhirī; 9 lords summing to 120y; 1 daśā-yr = 365.25d; balance-at-birth; Mahā→Antar→Pratyantar active chain) and generated 3 fixed sample births; **owner verified the daśā against a known chart before Phase 2.** **Phase 2:** new snippet **`sk-kundli` (id 61, global, active, `code_error=None`)** registers `
Janma Kuṇḍalī · जन्म कुण्डली
Your Vedic birth chart, today’s sky & running daśā
Today’s Sky · आज का ग्रह चित्र
Planetary positions at today’s sunrise (Bengaluru) — transit chart.
Loading sky chart…
Natal Chart & Vimśottarī Daśā
🔒
Unlock your personal birth chart & daśā
Your natal D1 chart and your running Vimśottarī Mahā → Antar → Pratyantar daśā unlock with Śubha (₹101). The sunrise transit chart above stays free for everyone.
Unlock with Śubha (₹101) →
`; new WP page **`/kundli/` (id 10011, published)** renders it. Sections: **(1) Sunrise TRANSIT D1** (free, all users) — fetches today's sunrise from `/api/panchanga` then `/api/kundli`, drawn with the **reused `panchanga_sky.js` builders** (North/South toggle + planetary table); **(2) NATAL D1** — birth form **prefilled from PMP profile** (`date_of_birth`/`time_of_birth`/`place_of_birth`) with on-page override, geocoded via the server-side **`/api/geocode`** proxy (avoids ISS-08 browser-Nominatim), rendered with the same builders; **(3) Vimśottarī DAŚĀ** — **navigable** Mahādaśā → tap → Antardaśā → tap → Pratyantardaśā (pratyantar subdivided client-side in Vimśottarī order; running Mahā auto-opens; running Mahā/Antar/Pratyantar **highlighted** from the API's `current`); **(4) D9** placeholder. **Read-only tier gating** (reads `pmpro_getMembershipLevelForUser`, writes nothing): logged-out/Śiṣya(2)/Early-Access(3) → transit only, natal+daśā **server-side withheld** (form/daśā HTML not emitted) behind an "Unlock with Śubha (₹101) →" `/join/` card; Śubha(4/12)+ → full transit+natal+daśā; Sādhaka(5/6)/Jyotiṣa(7/8)/Kula(9)/Praśna(10)/Lifetime(11) → additionally a "**D9 — coming soon**" card; Śubha (below ₹501) → D9 **locked** ("Upgrade to Sādhaka"). Styled to DESIGN.md (dark #2c1000, gold #c8960c, cream; scoped `body.sk-kundli-page` container-darkening like login/welcome) — **no aesthetic overhaul (deferred, RM-05)**. **Daily-strip link repointed:** the prior interim `sk-dasha-link-fix` (id 59, which rewrote the daśā link to `#sk-sky`) is **retired** (deactivated + code-emptied + renamed); the baked daily-page daśā href is already `https://shubhakala.com/kundli/` (template `panchanga_template.py` ln~1471 already correct — no template change/bake needed), so retiring 59 restores the link to the now-live `/kundli/`. **Verified live via Cloudflare (purged):** `/kundli/` **HTTP 200**; **guest** (headless screenshot) → transit chart renders + natal/daśā locked + Unlock prompt, `SK_K.paid=false`, no natal form/daśā in HTML; **Sādhaka `karna108`** (authenticated fetch) → `paid=true`,`d9=true`, natal form + daśā container present, "D9 coming soon", no free/Śubha-lock leakage; **rendered the real deployed paid page** (its HTML + live APIs, CORS `*`) with sample birth details → natal D1 chart (Moon Meṣa/Bharaṇī ✓) + 3-level navigable daśā with running **Rāhu** highlighted + Pratyantar expansion + "D9 coming soon"; daily page daśā href = `/kundli/` (snippet 59 retired). Sources: `kundli_snippet.php` + `_deploy_kundli.py`. ⚠ Could not live-test a **Śubha**-tier account (only have Sādhaka `karna108` + guest) — Śubha's "D9 locked" path is code-verified, not screenshotted. ⚠ Temp purge helper `sk-tmp-purge3` (REST DELETE 500s on this install) left disabled+flagged "safe to delete". See **RM-05** for deferred D9 + aesthetic overhaul. |
| FIX-DASHA-KUNDLI-LINK | **Dead link:** the logged-in 'Today for You' strip line "Your active daśā: **calculate in your Kundlī →**" (baked into all 365 daily Pañcāṅga pages via `panchanga_template.py`, the `#sk-tfy-dasha` row) pointed to `https://shubhakala.com/kundli/`, which **404s** (no `/kundli/` page is built yet). | P2 | **FIXED (2026-06-09) — this one link target only; nothing else touched. No `/kundli/` page built, Kundlī unchanged, no tiers/prices/gating touched.** **Where the basic Kundlī actually lives:** there is no `/kundli/` URL; a working **basic Kundlī already renders on every daily Pañcāṅga page** as the **"Today's Sky · आज का ग्रह चित्र"** section — a **sunrise Kundlī chart** (D1, North/South Indian toggle + planetary-positions table) drawn client-side from `/api/kundli`. Its on-page anchor is **`#sk-sky`** (`panchanga_template.py` ~ln1589–1612; the wrapping `.ps` panel's chart container `id="sk-sky"`). **New link target:** **`#sk-sky`** (on-page anchor → scrolls to the sunrise Kundlī on the same page), replacing the 404 `/kundli/`. **How:** the link is baked into 365 pages, so — matching the established `sk-today-fix`/**ISS-15** pattern (fix baked cross-page elements at runtime, no re-bake) — added a tiny front-end snippet **`sk-dasha-link-fix` (id 59, active, `code_error=None`)** that rewrites `#sk-tfy-dasha a[href*="/kundli/"]` → `#sk-sky` on load. Corrects all existing pages **and** future cron bakes at runtime. Source of truth in repo: `dasha_link_fix_snippet.php`. **Verified live via Cloudflare (headless Chrome, JS run) on `/panchanga-bengaluru-2026-06-09/` (HTTP 200):** daśā anchor href is now **`#sk-sky`**, **0** remaining `/kundli/` hrefs in the rendered DOM, and the `#sk-sky` "Today's Sky" section (with N/S toggle) is present on the page → the link resolves to working on-page content, no 404. Endurance purged (best-effort) after deploy. ⚠ **Follow-ups (not done, by design):** (a) `panchanga_template.py` ln~1471 still hard-codes the `/kundli/` href in the baked source — the runtime snippet overrides it everywhere, but update that line (and commit) when the full page is built; (b) **full `/kundli/` natal-chart page deferred post-launch** (then re-point this link to it and retire the snippet); (c) semantic note: `#sk-sky` is the *sunrise/transit* sky chart, not the user's *natal* daśā — acceptable interim per task, to be superseded by the real Kundlī page. |
| FEAT-POSTLOGIN-UX | 8 post-login UX defects: (1) logged-in name showed email-derived display name ('Akhilesh C') not the username; (2) top-bar **Edit Profile** was a dead link (→ /membership-account/, just reloaded); (3) **Log Out** not visually distinct; (4) /welcome/ onboarding had a white theme frame + no Rāśi calculator; (5) wp-login / reset pages were vanilla WP (grey logo, blue buttons); (6) 30-min session timeout unverified; (7) post-login links unaudited. | Feature | **Delivered (2026-06-09) — snippets `sk-core` (id 23), `sk-account-page` (id 32), new `sk-login-branding` (id 56) only; all `code_error=None`; pristine timestamped backups in `~/Claude/shubhakala/snippet_backups/`. No prices/tiers/gateway/Jetpack touched.** **(1) Username everywhere** — added a non-destructive `set_current_user` filter in sk-core that overrides the in-memory current-user `display_name` → `user_login` on the front end only (DB untouched; wp-admin "Howdy" unaffected); SK_USER builders (wp_head + REST hydrator) also switched to `user_login`. Live-verified logged in as `karna108`: hero "**Namaste, karna108**", PMP card "**Welcome, karna108**", `SK_USER.display_name="karna108"` (nav indicator reads it). **(2) Edit Profile fixed** — hero link → `/membership-account/your-profile/`; live-verified it now matches the working card link (both resolve to the same profile page). **(3) Log Out red** — added class `sk-acct-logout` to the hero link + CSS (`#b82105` outline → red fill on hover) that also matches the PMP card's Log Out via `a[href*="action=logout"]`; live-verified class + CSS present on both. **(4) Welcome page** — expanded the welcome CSS to darken EVERY Kadence container (`#primary, article, .content-bg, .entry-content-wrap, .wp-block-post-content, .wp-site-blocks>*`) mirroring the login/join approach → white frame gone; **reused the existing birth-detail Rāśi calculator** (same Railway `/api/birthchart` engine as account/checkout) inline below the Janma Rāśi dropdown (link `#sk-w-calc-toggle` → DOB/TOB/POB → Nominatim geocode → moon_rashi → auto-selects the dropdown). The calculator already existed → reused, NOT a placeholder. Live-verified via DOM (toggled `karna108` onboarding flag off through a secret-gated temp snippet to render the form, then restored to 1 — restore confirmed): `sk-welcome-body` body class + full container CSS + Rāśi link/panel/select-id/wiring-script all present. **(5) Login branding** — new `sk-login-branding` snippet via `login_enqueue_scripts` (+ `login_headerurl`/`login_headertext`): dark-brown bg, Ṣaḍkoṇa gold logo, cream fields, gold buttons, gold links. **Headless-screenshot-verified** on `wp-login.php` (login) and `?action=lostpassword`; `action=rp/resetpass` uses the same chrome. **Captcha reach:** the Jetpack Protect math-captcha interstitial renders inside the same wp-login chrome, so bg + logo + gold links + the math input (cream field) + submit (gold button) carry; could NOT screenshot it because triggering it requires deliberately failing logins / a flagged IP, which I won't induce on production (ties to **ISS-22**, deferred). No Jetpack settings touched. **(6) Session timeout CONFIRMED active** — snippet 33 caps `auth_cookie_expiration=1800`; decoded the live `wordpress_logged_in` cookie → lifetime **1789 s (≈30 min)**; idle-modal JS present in logged-in pages. Not weakened. **(7) Link audit CLEAN** — every post-login link (account hero, PMP card, footer, nav) status-checked live: all 200 (the `your-profile`/`change-password`/`cancel` 302→login are guest-gating only; `/membership-levels/` 200; no 404s/misdirects). **Verification login:** test user `karna108` (provided), used in-session only, not persisted. ⚠ Two verification helper snippets (`sk-tmp-purge` id 57, `sk-tmp-onboard` id 58) could not be REST-deleted (this install returns 500 on snippet DELETE — same reason ids 50/51 linger) → left **deactivated + code-emptied + renamed "(DISABLED — safe to delete)"**; delete in wp-admin when convenient. Endurance purged (best-effort) after deploy. |
| FEAT-STOTRAMS-DEITY | /stotrams/ index showed a flat grid bucketed only by colour (2 groups). Requested: group by DEITY into 7 sections, shortest-first within each, on the dark/gold theme, all 23 free. | Feature | **Delivered (2026-06-09) — `stotrams_index_rebuild.py` only (dynamic, parent 1636); no individual stotram page / price / tier / colour touched.** Replaced the flat grid with **7 deity sections in fixed order: Śiva · Viṣṇu · Gaṇeśa · Devī · Hanumān · Sūrya · Navagraha.** Grouping is an explicit `STOTRAM_MAP` (page_id → (deity, paid)); **paywall hook left** (`paid` flag + a documented "to add a new stotram" block) but **no paywall built** — all 23 are `paid=False` / free / visible to logged-out visitors. **Within each section: SHORTEST-FIRST by verse word count**, computed from each page's actual body via `verse_word_count()` (counts Devanāgarī tokens in `॥`-verse paragraphs; excludes single-`।` prose). Order verified live — Śiva: Mahāmṛtyuñjaya 46 · Liṅgāṣṭakam 52 · Pañcākṣara 64 · Bilvāṣṭakam 77 · Kālabhairavāṣṭakam 88 · Ardhanārīśvara 94 · Rudrāṣṭakam 196 · Śiva Tāṇḍava 201 · Mahimnaḥ 773; Viṣṇu: Nārāyaṇa 114 · Veṅkateśa 124 · Puruṣa 189 · Bhaja Govindam 317 · Viṣṇu Sahasranāma 1643; Devī: Gāyatrī 10 · Śrī Sūktam 165 · Kanakādhārā 222 · Mahiṣāsura Mardanī 308 · Saundaryalaharī 1519; singletons Gaṇeśa/Hanumān/Sūrya/Navagraha. **Per-stotram accent colour preserved** from each page's own H1 palette (green palette-11 / red palette-13) — independent of group: 4 green cards (Śrī Sūktam, Kanakādhārā, Mahiṣāsura Mardanī, Saundaryalaharī), 19 red incl. **Gāyatrī (red card inside the Devī group)** and **Ardhanārīśvara (red card inside Śiva)**. Styling = DESIGN.md dark brown #2c1000 page (scoped `body.page-id-1636`, mirrors sk-home/about-darkbg, lives in the page's own content — no new snippet) + gold #c8960c deity headings; existing cream stotram-card style kept; no images. **Fixed a stale id:** Ardhanārīśvara was deleted+recreated → new id **6522** (old 1685 retired) — title maps + STOTRAM_MAP updated. Removed the per-page EN/HI toggle (DESIGN.md forbids per-page toggles → resolves **ISS-12**); both scripts now shown statically. Backup of prior page at `/tmp/stotrams_index_1636.backup.html`. **Verified live via Cloudflare (HTTP 200, cf BYPASS, max-age=300) + headless desktop 1280 & mobile 390:** all 23 present, 7 headings in the exact order, shortest-first within each, correct colours, dark+gold, responsive. Endurance purged via the page PUT. ⚠ generator still uncommitted (ISS-13) but is not cron-run. |
| ISS-23 | **10 of 23 stotram pages rendered their देवनागरी/IAST tabs as a plain unstyled bulleted list** (raw WordPress) instead of styled Kadence tabs; both tabs' text stacked. Affected: rudrashtakam, aditya-hridayam, shiva-mahimna-stotram, shiva-panchakshara-stotram, sri-shiva-tandava-stotram, bilvashtakam, kalabhairavashtakam, sri-mahamrityunjaya-mantra, sri-vishnu-sahasranama, lingashtakam. | P2 | **FIXED (2026-06-08) — reference-match to /stotrams/bhaja-govindam/ (option A); prose/verses untouched.** **Root cause:** these 10 pages stored the *complete* Kadence-tab HTML (correct `kt-tabs` classes, `theme-palette-13` red text, both panes) but trapped inside a single **`<!-- wp:html -->` raw block** with a baked inline `<style>`. With no genuine `wp:kadence/tabs` block, Kadence Blocks never ran `has_block('kadence/tabs')` → **never enqueued its frontend tab CSS/JS** (`kt-tabs.min.js` + `kadence-blocks-tabs-css`), so the `<ul class="kt-tabs-title-list">` fell back to a bulleted list and both panes showed. The 13 working pages store the same structure as real `wp:kadence/tabs`+`wp:kadence/tab` blocks. **Fix:** for each page, converted the `wp:html` wrapper into genuine `wp:kadence/tabs`+`wp:kadence/tab` block delimiters (JSON copied from bhaja-govindam, each page's own `uniqueID` kept; clean title-list from the working page), keeping **each tab's inner verse/prose HTML byte-for-byte** and the page's red `theme-palette-13` colour. Idempotent script `~/Claude/shubhakala/fix_stotram_tabs.py` (`--check`/`--page`/`--all-broken`); per-page backups in `~/Claude/shubhakala/stotram_tab_backups/`. **Phase 1 (rudrashtakam) verified first** (headless: styled tab bar, देवनागरी active + IAST hidden, switching live, red preserved), then **Phase 2 (other 9)**. **All 10 verified live via Cloudflare (HTTP 200):** `kt-tabs.min.js` + `kadence-blocks-tabs-css` now enqueued, `data-tab` switch handles present, both `kt-inner-tab-1/2` panes present, `theme-palette-13` preserved (28–416 per page); headless screenshots of rudrashtakam, sri-vishnu-sahasranama, shiva-panchakshara-stotram show styled switchable tabs with red Devanāgarī. All 10 are red/Deva (Śiva/Viṣṇu/Bhairava) — correct. **Touched only the 10 listed pages**; the 13 working pages, cron (does not touch stotrams), Pañcāṅga pages, and snippets were not modified. Endurance purged via each page's re-save; CF BYPASS (not edge-caching HTML). |
| MAINT-PASSWORDLESS | Passwordless Login plugin left **active** despite no longer providing the login form (only enqueued `style-front-end.css`); flagged in CONTEXT as "deactivate to fully remove magic-link — not yet done", and a candidate interferer in the ISS-22 login-loop diagnosis. | Maint | **DEACTIVATED (2026-06-08) — only change this task; not deleted.** `passwordless-login/passwordless_login` v1.1.4 set **inactive** via WP plugins REST (`status: inactive`). Confirmed: active plugin count 11→10, only Passwordless removed; **Jetpack, PMP, Knit Pay and all others untouched** (no prices/tiers/config changed). **Verified live via Cloudflare:** `/login/` → HTTP **200**, branded login form + password field present, correct `redirect_to=/membership-account/`, the passwordless stylesheet is **no longer referenced**, 0 PHP fatals; `wp-login.php?action=lostpassword` → HTTP **200** (full browser headers; a bare-curl 403 is just CF's bot-block), standard reset form intact (`user_login` + "Get New Password"), 0 fatals, 0 passwordless refs (origin cross-check also 200, no fatals). The Jetpack captcha-on-branded-login friction is **deferred to post-launch** as a known issue → see **ISS-22**. |
| ISS-21 | **Logged-in account area near-invisible (dark-on-dark text + white Order History table).** /membership-account/ (My Account, My Memberships, Order History) rendered dark text on the dark-brown cards ('Sādhaka', 'Expires June 8 2027', Welcome/Username/Email) and washed-out light text on a white Order History table — low-contrast, looked broken though data was correct. | P1 | **FIXED (2026-06-08), styling only — snippet `sk-account-css` (id 25); no membership logic/prices/tiers/data touched.** **Root cause:** the old contrast rules targeted a `.pmpro_account` wrapper that **PMP 3.7.3 does not output**. The live markup is `<div class="pmpro">` › `<section class="pmpro_section" id="pmpro_account-profile\|-membership\|-orders">` › `.pmpro_card` › `.pmpro_card_title` / `.pmpro_card_content` / `.pmpro_list`+`.pmpro_list_item`(`.pmpro_list_item_label`/`_value`) / `.pmpro_card_actions`+`.pmpro_card_action a`, and Order History is a `<table class="pmpro_table pmpro_table_orders">` with `<span class="pmpro_tag pmpro_tag-success">Paid</span>` — **no `.pmpro_account` element and no table the old CSS knew about**, so every colour rule missed and text fell back to PMP's `pmpro-variation_1` light theme. **Fix:** rewrote sk-account-css to target the REAL PMP 3.7.3 classes with `!important`, scoped to `body.sk-account-page` AND `body.page-id-7645` (confirmation): section titles + card titles + labels → gold #c8960c; card body + list values → cream #FDF6EC; cards → #3d1a00 w/ gold border; action links (Renew/Change/Cancel, Edit Profile/Change Password/Log Out) → gold; **Order History table → dark theme** (gold header row w/ dark text, #3d1a00 cells w/ cream text, gold row separators, gold date link); **'Paid' badge → green #13612e + cream** (`.pmpro_tag-success`); edit-profile form fields cream/dark; mobile padding tuned (PMP's responsive stacked table verified legible). Theme title/breadcrumbs hidden on the account page only (its custom hero replaces them); confirmation keeps its heading. The top action-button hero (snippet `sk-account-page` id 32) was left untouched and the new scheme matches it. **Verified headless (Chrome screenshots, desktop 1280 + mobile 390) on the live authenticated render (test acct aesshu, Sādhaka, Expires June 8 2027, one Paid ₹501 order):** every element legible against its background — gold headings/labels, cream values, fully-dark orders table (no white strip), green Paid badge — at both widths. Source of truth: `~/Claude/shubhakala/account_css_snippet.php` (deploys to snippet 25, `<?php` stripped). Endurance purged via re-save of pages 7641 + 7645; CF still BYPASS (not edge-caching HTML — ISS-09). _Note: throwaway passwords were set on test accounts vyasa_muni (id14) + aesshu (id15) to log in for verification — rotate in WP Admin if desired._ |
| FEAT-JOIN-BADGES | /join/ Coming-Soon badges out of sync with feature reality on 3 rows (Śubha tier) | Feature | **Delivered (2026-06-08), sk-join id 54 only — no prices/levels/gateway/other badges touched.** Three feature-badge corrections in `join_snippet.php`, verified against live behaviour: **(1) Abhijit + Brahma Muhūrta (Śubha):** REMOVED the Coming-Soon badge (`live`→true) — it is LIVE (real times now render on the daily Pañcāṅga pages). **(2) Lalitā Sahasranāma (Śubha intermediate stotrams):** ADDED an inline prominent `.skj-cs` Coming-Soon badge after just that title (bullet stays `live` because Viṣṇu Sahasranāma + Āditya Hṛdayam ARE published; Lalitā returns 404 / still in the queue per CONTEXT). **(3) Ad-free browsing (Śubha):** ADDED a Coming-Soon badge (`live`→false) — AdSense still under review, so ad-free is not yet a live differentiator. Pushed via `_deploy_join_only.py` (snippet 54 only, `code_error=None`), /join/ page 7701 re-saved for Endurance per-URL purge. **Verified live (Cloudflare normal path, HTTP 200, `cf-cache-status: BYPASS`, `max-age=300`) AND headless Chrome:** 5 cards render, no console errors; Abhijit row has NO badge, Lalitā bullet carries the inline badge (Viṣṇu/Āditya unbadged), Ad-free carries the badge; total feature Coming-Soon badges 22→23. All other Coming-Soon badges left exactly as they were. CF edge still not caching HTML (no CF API token — ISS-09); Endurance purged via page re-save. |
| FEAT-JOIN-POLISH | /join/ tooltips were slow (native title delay), feature reality unclear, jargon-heavy; no inaugural framing; Lifetime/Jyotiṣa feature mismatch; /about/ roadmap out of sync | Feature | **Delivered (2026-06-07), sk-join id 54 + redesign_about.py — no prices/levels/gateway touched.** (1) **Instant tooltips:** replaced all native `title=""` with custom CSS tooltips (`.skj-tip`/`.skj-tt`, shown on hover+focus, `transition:none` → zero delay, dark-brown/cream/gold per DESIGN.md). (2) **Feature verification + 'Coming Soon':** audited every bullet vs CONTEXT, defaulted unconfirmed to **Coming Soon** (22 items); replaced all 'Soon' with a **prominent filled-gold** 'Coming Soon' badge (same fill as Most Popular). LIVE: Daily Pañcāṅga, 8 foundational + intermediate + advanced stotrams, CB/TB manual, Gulika+Yamagaṇḍa, ad-free, 9 Graha positions, Pañcāṅga date-picker, Muhūrta finder. COMING SOON: CB/TB auto-from-profile, Choghaḍiyā+Horā, Chandrāṣṭama, Sāde Sāti (tracker+detail), Abhijit/Brahma Muhūrta, Auspicious Yogas, Gochara Guru detail, Janma Kuṇḍalī PDF, Transit calendar, Plan Your Week, Daily Briefing, Pañcāṅga Śuddhi, Kuṇḍlī Milan, Eclipse calendar, divisional charts D10/D9/D7, Monthly Horā consult, Praśna, Gemstone+Mantra, WhatsApp, AI Agent, Hall of Patrons, Early beta. (3) **De-jargon:** 'CB/TB' → 'Chandrabalam + Tārābalam (your Moon & birth-star strength for the day)'; plain-English gloss added after every Sanskrit term. (4) **Refund block** now two bullets (all-except-Lifetime / Lifetime) + policy link. (5) **Inaugural Price** pill on all 4 paid cards + footnote 'Inaugural pricing — rates increase soon.' (6) **One trial banner** below the subtitle (no per-card trial note); Śiṣya 'Join Free' → `?level=3`. (7) **Jyotiṣa↔Lifetime parity:** moved Eclipse calendar, divisional charts, WhatsApp (+all) into Jyotiṣa; Lifetime differentiators reduced to Hall of Patrons + Early beta + inherent (pay once / no renewals / all future features / Retiring after 12 months / Non-refundable). (8) **About sync:** added 'See everything that's coming →' CTA to /join/ + a T&C line linking /about/; added a 'More Premium Tools in Development' card to the About 'On the Horizon' section listing every Coming-Soon item so both pages agree. **Verified live (Cloudflare + headless):** instant tooltips (no `title=`), 22 gold Coming-Soon badges, 4 Inaugural pills, banner, two-bullet refund, parity, About CTA, About roadmap updated. **All CSS lives in the snippet — no Customizer paste needed.** |
| FEAT-JOIN-REVAMP | /join/ page crowded, had Annual/Monthly toggle + stale "10-day free trial" copy; no refund page; no checkout consent | Feature | **Delivered (2026-06-07).** New snippet **`sk-join`** (id 54, priority 11 → overrides sk-core's old `shubhakala_join`) renders a cleaner /join/: **5 cards only** (Śiṣya·Free → `?level=3`, Śubha ₹101, Sādhaka ₹501 *Most Popular* single badge, Jyotiṣa ₹2,501, Lifetime ₹11,001 once), **no Annual/Monthly toggle**, **no 'Early Access' wording**, **progressive disclosure** via native `<details>/<summary>` (top 3–4 features + "See all features ▾", no JS), subtle `title=""` `?` tooltips, larger type/line-height/padding. Śiṣya headline "10 days full access, then free basics forever", button **Join Free → /membership-checkout/?level=3** (delivers the trial that auto-downgrades to Śiṣya via `sk-early-access-downgrade`). Jyotiṣa: 'Praśna queries' + 'Monthly Horā consult' (+AI agent) tagged **Soon**. Lifetime: 'Retiring after 12 months' + **Non-refundable** tag. Refund summary block links to /refund-policy/; footer line "One-time annual payment · Secure checkout · 256-bit encrypted". All CSS lives **inside the snippet** (Code Snippet, not Customizer) — no manual paste needed. **New page /refund-policy/** (id 9981, snippet **`sk-refund`** id 55, dark per DESIGN.md): annual = full refund <30d, pro-rated after; Lifetime = full refund <30d, non-refundable after; how-to-cancel (account → Cancel → free Śiṣya); contact. Footer link added site-wide (sk-footer-feedback now adds Feedback + Refund Policy to theme_mod `footer_html_content`). **Checkout consent:** PMP native TOS enabled (`pmpro_tospage` → /refund-policy/) so a required "I agree to the Refund & Cancellation Policy" checkbox shows at checkout (PMP records acceptance); **Lifetime (level 11)** also shows a non-refundable notice + a required second-confirmation checkbox gated server-side via `pmpro_registration_checks`. **Verified live (Cloudflare + headless):** /join/ renders (5 cards, badges, expanders, dark), Śiṣya→level=3 (no level=2), paid→4/5/7/11, no toggle/no-trial copy, refund block; /refund-policy/ dark + correct; checkout L4 & L11 show the TOS checkbox linking refund-policy; L11 shows the lifetime ack; footer shows Refund Policy. No prices or gateway mode touched. |
| ISS-16 | All paid PMP tiers were ₹0 in the DB (checkout would charge nothing / grant free) | P0 | **FIXED (2026-06-07).** Wrote real `initial_payment` to `9d9_pmpro_membership_levels`: Śubha(4)=₹101, Sādhaka(5)=₹501, Jyotiṣa(7)=₹2,501, Lifetime(11)=₹11,001. Also set the sk-core `pmpro_level_cost_text` map + /join/ display to the same figures, so **displayed price == charged price** (verified live on /join/ and /membership-checkout/?level=4/5/7/11). Monthly levels (6,8,12) and Kula(9)/Praśna(10) set `allow_signups=0` (hidden from the flow, kept in DB). |
| ISS-17 | Lifetime showed ₹11,001 but DB charged ₹4,999 | P0 | **FIXED (2026-06-07).** Level 11 `initial_payment` set to **11001**; cost text → "One-time payment of ₹11,001 — lifetime access". Display now equals charge. |
| ISS-19 | Recurring/one-time conflict + phantom "10-day free trial" copy | P1 | **RESOLVED as one-time annual (2026-06-07).** On all listed paid levels (4,5,7,11): `billing_amount=0`, `cycle_number=0`, `cycle_period=''` (no recurring), `trial_limit=0`/`trial_amount=0` (no trial). Annual tiers (4,5,7) carry `expiration=1 Year` (one-time payment → 1 year access, re-purchase, **no auto-rebill**); Lifetime(11) never expires. Removed all "free trial / then ₹X per period" copy from the cost-text filter, the Śiṣya "10-day free trial" benefit, the Annual/Monthly toggle, and the join-note (now "One-time annual payment"). _Decision logged: annual tiers expire after 1 year — flagged for owner review._ |
| ISS-20 | Gateway-environment ambiguity (PMP said `live`) | P1 | **REPORTED (2026-06-07, no change made).** Knit Pay "Razorpay – Easy Connect" config (gateway post **7653**, `_pronamic_gateway_mode = test`) is in **TEST** mode — matches owner intent; payments route to Razorpay Test. PMP's separate `pmpro_gateway_environment` option still reads `live` but Knit Pay uses its own config mode, so it does not route real charges. _Recommendation (not done per instructions): align the PMP flag to test to avoid confusion._ |
| FEAT-FEEDBACK | **No site-wide feedback / testimonial capture.** Visitors had no on-brand way to send feedback or consent to a public testimonial; no owner-gated approval workflow. | Feature | **Delivered (2026-06-07).** New page **/feedback/** (id 9972) rendering `
Share Your Feedback
Your experience helps Śubhakāla grow. Tell us what's working, what isn't, or share how a consultation went. We read every message.
` from a single revert-safe snippet **`sk-feedback`** (Code Snippets id 49, global, active, `code_error: None`). Source of truth in repo: `feedback_snippet.php` + `deploy_feedback.py` (idempotent deployer). On-brand per DESIGN.md (dark #2c1000, gold #c8960c, cream #FDF6EC cards). Category-first form (8 categories) that **reveals consultation fields** (session date / mode / remedies) only for *Consultation / Session*; optional contact + 1–5★ rating; optional testimonial-consent checkbox; **required** Terms checkbox with an in-page expander holding the full Feedback & Testimonial Terms; **guest-accessible, no login**. Submit → guest **POST** REST `/wp-json/shk/v1/feedback` (honeypot-gated, required-terms-gated, all inputs sanitised, never any value in a URL) which **(a)** `wp_mail`s [email protected] (category in subject, consent noted) and **(b)** stores a **private CPT `sk_feedback`** record (category, name, contact, rating, message, consultation fields, `consent_to_publish`, `testimonial_status=pending`). Admin meta box gives an **Approve/Decline** control + list columns. **``** renders ONLY `consent_to_publish=yes` AND `testimonial_status=approved` (not placed on any live page yet). **'Feedback' added to the footer 'Useful Links' menu** (menu 84, item 9973). **Live-verified through Cloudflare (normal UA):** page on-brand; consultation fields reveal on category; honeypot→400, terms-unticked→422, missing-required→422; a consent-ticked submission emailed (`_sk_mail_sent=1`) + stored (id, `consent_to_publish=yes`, `testimonial_status=pending`); `` empty while pending → shows name+text+stars after Approve → hidden again on Decline. Verification used a TEMP admin-only snippet (id 50) now **disabled + emptied** (its routes 404); test entry trashed. |
| ISS-01 | Today's page rendered from a stale template (missing sky chart / tfy strip / Today button; ~37 KB smaller) | P0 | **Root cause:** the committed `panchanga_template.py` predated the sky/tfy sections AND `panchanga.js`/`panchanga_sky.js` were *untracked* — so the GitHub-Actions cron rendered today from a stale template with empty inline JS. **Fix:** committed the current template + both JS assets to `shubhakala-api` (commit `e54209a`; cron triggers are schedule/dispatch only, so the push didn't fire it) → future cron output now equals bulk output. Re-rendered today's live page (1915) with the current template: **35 KB → 156 KB**, now has sky chart + N/S toggle + planetary table + Upcoming Transitions + 'Today for you' + 'Today' button, at parity with future pages. Verified live. |
| ISS-02 | Footer said "Swiss Ephemeris" (DESIGN.md violation) | P2 | Removed from `panchanga_template.py` `_s8` (→ "Classical Vedic methods · Lāhirī Ayanāṃśa") and backfilled across **all 365 daily pages + calculator** (changed 365, err 0; verification pass: 0 pages still containing the string). |
| ISS-04 | Out-of-range `/panchanga-bengaluru-DATE/` hard-404'd instead of redirecting | P2 | Added snippet **`sk-panchanga-oor-redirect`** (id 35, front-end, `template_redirect` prio 1, scoped to 404 + exact slug regex). Verified: valid date → 200, OOR date → **302 → /panchanga/panchanga-calculator/?date=DATE**, unrelated 404 → still 404. |
| ISS-07 | "Yamāghanda" / "यमघण्ट" not canonical IAST | P2 | Standardised to **Yamagaṇḍa / यमगण्ड** in template source (display only; engine data key `yamaaghanda` untouched) and backfilled across all 366 pages (verification: 0 old labels remaining). |
| ISS-10 | **Light "white strip" between the top nav and the About content on /about/** (had appeared to "fail" twice — a stale cache hid a working fix) | P2 | **Real cause:** the `<body>` background is light `rgb(237,239,243)` and Kadence's `.content-area`/`#primary` carry `margin-top:32px` beneath the *transparent header*, so that 32 px gap (above the dark `#2c1000` `article`) revealed the light body bg. **Fix:** snippet **`sk-about-darkbg` (id 36)**, scoped `is_page(6544)`, sets `body.page-id-6544` + `#inner-wrap`/`.content-area`/`#primary` background to `#2c1000`. **Cache:** purged Bluehost Endurance for the URL by re-saving page 6544 (next fetch `x-proxy-cache: MISS`, regenerated with the snippet). **Verified fresh (headless, cache-busted AND plain):** `body` bg = `rgb(44,16,0)`, the entire former-gap region y=121→169 is continuous `#2c1000`, no white strip. Cloudflare not caching this HTML (`cf-cache-status: none`). |
| ISS-11 | Homepage stale + off-brand (old 'An authentic guide' tagline, EN/HI toggle in hero, 'Swiss Ephemeris' in body, 'Free to access', light/white sections) — highest-traffic page | P1 | **Root cause (same as ISS-01):** the June-4 redesign in `update_homepage.py` was **uncommitted**, so the nightly cron republished the OLD committed version over it. **Fix:** committed the redesigned `update_homepage.py` to `shubhakala-api` (commit `94c4932`) → cron no longer reverts; ran it to publish page 1768 (WP 200). Added snippet **`sk-home-darkbg` (id 37)** to force the front page's body + boxed `article.content-bg` + wrappers to `#2c1000` (Kadence boxed style was painting them light). Purged via re-save. **Verified fresh (headless, cache-busted):** new शुभकाल/italic Śubhakāla hero, tagline **'Free to start. No compromise on accuracy.'**, **0** 'Swiss Ephemeris', **0** lang-btn/skApplyLang, body+article = `rgb(44,16,0)`, bg histogram = ONLY `#2c1000` (×14), **0 light sections**. |
| ISS-15 | "Today" button on daily pages linked to a stale date (e.g. → 2026-06-04 instead of real IST today) — the ISS-06 disease: the dynamic-Today fix existed in `panchanga.js` but is BAKED per page, so pages rendered before the fix kept stale JS | P1 | Runtime fix snippet **`sk-today-fix` (id 48)**: site-wide, sets `#pr-today-day` to the real IST today (clones the node to strip stale baked handlers). Verified live (headless via Cloudflare): old page 1885 AND a future page now both → **2026-06-07** (real today). Fixes all 365 pages with no re-render. |
_Open: 7 (ISS-18 P0, ISS-06 P1, ISS-09 P1, ISS-05 P2, ISS-14 P2, ISS-22 P2 (deferred — post-launch), ISS-13 P3) · Resolved: 21 (ISS-01, ISS-02, ISS-04, ISS-07, ISS-08, ISS-10, ISS-11, ISS-12, ISS-15, ISS-16, ISS-17, ISS-19, ISS-20, ISS-21, ISS-23, + FEAT-POSTLOGIN-UX, + FIX-DASHA-KUNDLI-LINK, + FEAT-KUNDLI-PAGE, + FIX-GRAHA-CLOCK-POLISH, + FEAT-GRAHA-CLOCK-INSTRUMENT, + FIX-GRAHA-CLOCK-LABELS) · Roadmap: 3 (RM-01, RM-02, RM-05)._
_ISS-08 location-awareness wiring done 2026-06-12 (snippet sk-location); remaining server-side follow-up: /api/geocode currently 500s (Nominatim throttles the Railway server) — search uses a curated local city list meanwhile._
_Payment config 2026-06-07: ISS-16/17/19 FIXED (real one-time annual prices, displayed==charged), ISS-20 reported (Knit Pay = **Test**). Pricing is now Test-run-ready. **Still blocking a full revenue path: ISS-18** (no Razorpay→tier webhook; rzp.io donation links not wired to tiers — Knit Pay→PMP is the only grant path)._
_When every Open row above is gone, this file should contain only the header + RESOLVED log + "No open issues."_