Skip to content

SSR default classifier pages with loader fallback#12

Open
DmitryMatv wants to merge 3 commits intomainfrom
t3code/ssr-default-classification
Open

SSR default classifier pages with loader fallback#12
DmitryMatv wants to merge 3 commits intomainfrom
t3code/ssr-default-classification

Conversation

@DmitryMatv
Copy link
Owner

@DmitryMatv DmitryMatv commented Mar 23, 2026

Summary

  • Server-rendered default classifier pages now inline initial results when SSR succeeds, reducing the need for client-side loading on base classifier URLs.
  • Added a shared classification results context builder so the fragment route and page route use the same classification path and template data.
  • Search-query pages still use the initial results loader, while SSR failures on base pages fall back to the existing loader behavior.
  • Added tests covering UNSPSC and NAICS SSR rendering, search-page loader behavior, and fallback when classification SSR fails.

Testing

  • Not run in this environment.
  • Covered by new unit tests in tests/test_web_helpers.py for SSR success and fallback cases.
  • Covered by updated metadata behavior test in tests/test_request_validation_and_metadata.py for base-page loader fallback.

Summary by CodeRabbit

  • Refactor

    • Simplified server-side classification flow and tightened initial-results rendering so results are inlined only when appropriate.
  • Bug Fixes

    • Improved error handling: when server-side classification fails, the page falls back to client-driven loading.
  • Tests

    • Added tests covering SSR success, SSR failure fallback, and client-side loading behavior.
  • Chores

    • Increased HTML page cache max-age for longer CDN caching.

- Render base classifier pages with server-side example results
- Keep the client loader for search pages or SSR failures
- Add coverage for SSR success and fallback behavior
@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

Adds a centralized helper to build classification results context, refactors server-side rendering flow to optionally SSR results with a client-side fallback, tightens the template conditional so the HTMX initial-results-loader mounts only when both trigger_search_on_load and needs_initial_results_loader are true, and adjusts cache TTL.

Changes

Cohort / File(s) Summary
Template conditional
app/templates/classifier_page.html
Tightened HTMX initial-results-loader condition to require both trigger_search_on_load and needs_initial_results_loader, preventing automatic client fetch unless both flags are set.
Web handlers & helper
app/web.py
Added build_classification_results_context(request, classifier_type, query, version, top_k) to normalize/short-circuit queries, measure total request time, and return standardized context; refactored get_classification_fragment() and updated show_classifier_page_with_query() to set needs_initial_results_loader and handle SSR-with-fallback on errors.
Tests — behavior & SSR
tests/test_request_validation_and_metadata.py, tests/test_web_helpers.py
Renamed base-page test to reflect fallback behavior; added BaseClassifierPageSSRTests to verify SSR success/failure, loader presence, usage-tracking suppression, and correct perform_classification calls for UNSPSC/NAICS.
Cache profile
app/cache_profiles.py
Increased HTML_PAGE.cloudflare_cache_control max-age from 7200 to 21600 (stale-while-revalidate unchanged).

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Server as Server (app/web)
    participant Classifier as Classifier Service
    participant Template as Template Renderer

    Client->>Server: GET /<classifier>[/query]
    alt URL contains search query or example-query SSR path
        Server->>Classifier: perform_classification(query, version, top_k)
        Classifier-->>Server: results
        Server->>Server: build_classification_results_context(...)
        Server->>Template: render page with inlined results (needs_initial_results_loader=false)
        Template-->>Client: HTML (results inlined)
    else SSR disabled or classification raises error
        Server->>Server: set trigger_search_on_load=true, needs_initial_results_loader=true
        Server->>Template: render page with `initial-results-loader` (HX loader)
        Template-->>Client: HTML (client will fetch results)
        Client->>Server: HX request for classification fragment (on load)
        Server->>Classifier: perform_classification(...)
        Classifier-->>Server: results fragment
        Server-->>Client: results fragment (replace loader)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code to tidy the flow,
SSR tries first, then the loaders will know,
A helper compacts timing, queries, and more,
Flags tuck the fetch till the server is sure,
Tests nod and the cache stretches aloft — hooray, encore!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: server-side rendering (SSR) of default classifier pages with client-side loader fallback when SSR fails.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/ssr-default-classification

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/web.py (1)

576-592: The broad Exception catch is acceptable for SSR fallback, but consider logging at warning level.

The static analysis flags catching bare Exception, but this is a valid pattern for optional SSR with graceful degradation. The current implementation correctly:

  1. Logs the error
  2. Falls back to client-side loading

However, since perform_classification converts most errors to HTTPException, you're also catching HTTP 5xx errors (e.g., backend unavailable). For operational visibility, consider using logger.warning instead of logger.error to distinguish "expected fallback" from "unexpected failure," or log the exception type:

♻️ Optional: Add exception type for debugging
             except Exception as e:
                 logger.error(
-                    "Error during '%s' page SSR classification: %s",
+                    "Error during '%s' page SSR classification (%s): %s",
                     effective_classifier_type,
+                    type(e).__name__,
                     e,
                 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/web.py` around lines 576 - 592, Change the error-level logging to a
warning and include the exception type/message when the SSR classification
fallback occurs: inside the except block that surrounds
build_classification_results_context (referencing
build_classification_results_context, effective_classifier_type,
trigger_search_on_load, and needs_initial_results_loader), replace the
logger.error call with logger.warning and format the log to include both the
exception type and the exception instance so the fallback remains quiet but
still records useful operational context.
tests/test_web_helpers.py (1)

326-344: Consider making the example query assertion more robust.

Line 340 asserts "Apple MacBook Air (13-inch, M3, 2024)" appears in the response, which depends on the current value of CLASSIFIER_CONFIG["UNSPSC"]["example"]. If this config value changes, the test will fail for reasons unrelated to the SSR fallback behavior being tested.

Consider deriving the expected text from the config:

expected_example = CLASSIFIER_CONFIG["UNSPSC"]["example"].replace("Example:", "").strip()
self.assertIn(expected_example, response.text)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_web_helpers.py` around lines 326 - 344, The hard-coded example
string in test_base_page_ssr_failure_falls_back_to_loader makes the test
brittle; instead derive the expected text from CLASSIFIER_CONFIG to match
whatever the config currently contains. Replace the literal assertion that
checks for "Apple MacBook Air (13-inch, M3, 2024)" with code that reads
CLASSIFIER_CONFIG["UNSPSC"]["example"], strips any leading "Example:" and
whitespace (e.g., .replace("Example:", "").strip()), then assert that this
expected_example is in response.text; keep the other assertions and mocks
(perform_classification_mock, check_usage_mock, increment_usage_mock) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/web.py`:
- Line 584: Remove the unused variable has_server_rendered_results: locate and
delete its assignments (the occurrences that set has_server_rendered_results =
True) and any standalone declaration; ensure no other code (template context
construction or conditionals) references has_server_rendered_results and, if it
does, either remove that reference or replace it with the appropriate used
variable. Confirm imports or lints are clean after removal.

---

Nitpick comments:
In `@app/web.py`:
- Around line 576-592: Change the error-level logging to a warning and include
the exception type/message when the SSR classification fallback occurs: inside
the except block that surrounds build_classification_results_context
(referencing build_classification_results_context, effective_classifier_type,
trigger_search_on_load, and needs_initial_results_loader), replace the
logger.error call with logger.warning and format the log to include both the
exception type and the exception instance so the fallback remains quiet but
still records useful operational context.

In `@tests/test_web_helpers.py`:
- Around line 326-344: The hard-coded example string in
test_base_page_ssr_failure_falls_back_to_loader makes the test brittle; instead
derive the expected text from CLASSIFIER_CONFIG to match whatever the config
currently contains. Replace the literal assertion that checks for "Apple MacBook
Air (13-inch, M3, 2024)" with code that reads
CLASSIFIER_CONFIG["UNSPSC"]["example"], strips any leading "Example:" and
whitespace (e.g., .replace("Example:", "").strip()), then assert that this
expected_example is in response.text; keep the other assertions and mocks
(perform_classification_mock, check_usage_mock, increment_usage_mock) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5cccd0db-9ac1-4b7c-b0ba-264f65f03a4c

📥 Commits

Reviewing files that changed from the base of the PR and between 6688451 and b5b84cb.

📒 Files selected for processing (4)
  • app/templates/classifier_page.html
  • app/web.py
  • tests/test_request_validation_and_metadata.py
  • tests/test_web_helpers.py

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b5b84cb552

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Extend Cloudflare cache TTL for HTML pages
- Log SSR classification failures as warnings and fall back to client load
- Update test to assert the configured example is rendered
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/web.py (1)

584-589: Include traceback in SSR fallback warning logs.

Fallback is correct, but logging only the exception message makes production debugging harder. Keep fallback behavior and include stack traces.

Suggested patch
-                logger.warning(
-                    "SSR fallback for '%s' page classification due to %s: %s",
-                    effective_classifier_type,
-                    type(e).__name__,
-                    e,
-                )
+                logger.warning(
+                    "SSR fallback for '%s' page classification due to %s: %s",
+                    effective_classifier_type,
+                    type(e).__name__,
+                    e,
+                    exc_info=True,
+                )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/web.py` around lines 584 - 589, The SSR fallback warning currently logs
only the exception type and message in the logger.warning call around SSR
fallback for effective_classifier_type; change the log call to include the
traceback (e.g., add exc_info=True to the existing logger.warning invocation or
use logger.exception if you want an ERROR-level stack trace) so the same message
is emitted but with full stack trace for debugging; keep the fallback behavior
unchanged and only modify the logger.warning(...) line that references
effective_classifier_type, type(e).__name__, and e to include exc_info=True.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/web.py`:
- Around line 584-589: The SSR fallback warning currently logs only the
exception type and message in the logger.warning call around SSR fallback for
effective_classifier_type; change the log call to include the traceback (e.g.,
add exc_info=True to the existing logger.warning invocation or use
logger.exception if you want an ERROR-level stack trace) so the same message is
emitted but with full stack trace for debugging; keep the fallback behavior
unchanged and only modify the logger.warning(...) line that references
effective_classifier_type, type(e).__name__, and e to include exc_info=True.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a7d45b9-4d97-44a1-aca8-c741f11989f9

📥 Commits

Reviewing files that changed from the base of the PR and between b5b84cb and c4cd5f6.

📒 Files selected for processing (3)
  • app/cache_profiles.py
  • app/web.py
  • tests/test_web_helpers.py
✅ Files skipped from review due to trivial changes (1)
  • app/cache_profiles.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant