Skip to content

Fix Creator and Builder role grants failing since the June onboarding… - #969

Merged
JoaquinBN merged 1 commit into
mainfrom
dev
Aug 5, 2026
Merged

Fix Creator and Builder role grants failing since the June onboarding…#969
JoaquinBN merged 1 commit into
mainfrom
dev

Conversation

@JoaquinBN

Copy link
Copy Markdown
Collaborator

… rework (#968)

  • Surface the real reason when Creator journey completion fails

Users who fail to complete the Creator journey currently hit an opaque HTML 500 that the portal can only render as a generic "try again" dead end, and the reports keep coming with nothing actionable in them. The community completion endpoint now catches unhandled errors the same way the builder endpoint does: the role grant still rolls back, the client receives the actual failure reason as JSON (which the portal already displays verbatim), and the full traceback is written to the logs. Builder journey completion logging now keeps the traceback as well instead of only the exception message.

Claude Implementation Notes

  • backend/users/views.py: Wrapped complete_community_journey's transaction and success response in try/except returning a JSON 500 with the real error, logged via logger.exception (catching suppresses django.request's own 500 traceback logging). Switched complete_builder_journey's logger.error to logger.exception for the same reason.
  • backend/users/tests/test_community_journey.py: New test patches update_user_leaderboard_entries to raise during the POST only (setup-step signals call the same function) and asserts JSON 500 with the reason, an ERROR log, and Creator rollback.
  • Assert the completion failure log carries the traceback

The failure test only proved an ERROR record was emitted, so reverting logger.exception to a bare logger.error(str(e)) would still pass while losing the diagnostic traceback this change exists to keep. The test now captures the log output and requires both the traceback and the original exception text in it.

Claude Implementation Notes

  • backend/users/tests/test_community_journey.py: Capture the assertLogs context in test_complete_failure_returns_json_error_and_rolls_back and assert 'Traceback' and the exception message appear in the joined output.
  • Fix new Creator and Builder role grants failing at the final step

Since the June onboarding rework, every first-time role grant through the Creator and Builder journeys failed in production while all tests passed. The completion endpoints re-fetched the user via type(request.user), and in production request.user is Django's lazy wrapper: every attribute access proxies to the real user, but the wrapper's type has no .objects manager, so the grant crashed and rolled back on the exact line that only runs for genuinely new members. Tests authenticated with a concrete user, which is why the suite never saw it. Both endpoints now resolve the model through get_user_model(), and each journey gains a completion test that runs through the real session authentication chain so the wrapper shape is covered from now on.

Claude Implementation Notes

  • backend/users/views.py: Replace type(user).objects with get_user_model().objects in complete_builder_journey and complete_community_journey; comments explain the SimpleLazyObject trap. Confirmed against the production CloudWatch traceback (AttributeError: type object 'SimpleLazyObject' has no attribute 'objects' at the fresh_user re-fetch).
  • backend/users/tests/test_community_journey.py: test_complete_grants_creator_through_wallet_session_auth completes the journey via login_wallet_session; reproduced the production 500 before the fix.
  • backend/users/tests/test_builder_journey.py: test_complete_grants_role_through_wallet_session_auth, same pattern for the builder grant.
  • backend/CLAUDE.md: New "request.user is a lazy wrapper" section documenting the trap and the wallet-session test guards.
  • Update changelog

  • Keep exception internals out of journey completion error responses

A failed role grant returned str(exception) to the client, and the portal renders those fields verbatim. Database error text can carry table and constraint names or even the conflicting row values, so the client now gets a stable completion_failed code with a friendly message while the full traceback stays in the server logs, which today's diagnosis proved is the channel that matters.

Claude Implementation Notes

  • backend/users/views.py: Both journey completion except blocks return {'error': 'completion_failed', 'message': ...} instead of interpolating str(e); logger.exception unchanged. The frontend completionErrorMessage helpers pick up data.message, so no frontend change is needed.
  • backend/users/tests/test_community_journey.py: The failure test now asserts the stable error code and that the exception text does NOT appear anywhere in the response, while still requiring it in the logged traceback.
  • Show tracebacks in the dev console log format

logger.exception call sites are the only durable traceback source once a view catches an error, and the production JSON formatter already renders them. The human-readable console formatter used in development dropped exc_info entirely, leaving a bare one-line ERROR. It now appends the formatted traceback, and both formatters have a direct test pinning the exception rendering.

Claude Implementation Notes

  • backend/tally/middleware/logging_utils.py: LayeredFormatter.format appends self.formatException(record.exc_info) when present, matching LayeredJSONFormatter's behavior.
  • backend/tally/tests/test_logging_formatters.py: New direct tests asserting both formatters include the traceback and exception text.

… rework (#968)

* Surface the real reason when Creator journey completion fails

Users who fail to complete the Creator journey currently hit an opaque
HTML 500 that the portal can only render as a generic "try again" dead
end, and the reports keep coming with nothing actionable in them. The
community completion endpoint now catches unhandled errors the same way
the builder endpoint does: the role grant still rolls back, the client
receives the actual failure reason as JSON (which the portal already
displays verbatim), and the full traceback is written to the logs.
Builder journey completion logging now keeps the traceback as well
instead of only the exception message.

## Claude Implementation Notes
- backend/users/views.py: Wrapped complete_community_journey's transaction and success response in try/except returning a JSON 500 with the real error, logged via logger.exception (catching suppresses django.request's own 500 traceback logging). Switched complete_builder_journey's logger.error to logger.exception for the same reason.
- backend/users/tests/test_community_journey.py: New test patches update_user_leaderboard_entries to raise during the POST only (setup-step signals call the same function) and asserts JSON 500 with the reason, an ERROR log, and Creator rollback.

* Assert the completion failure log carries the traceback

The failure test only proved an ERROR record was emitted, so reverting
logger.exception to a bare logger.error(str(e)) would still pass while
losing the diagnostic traceback this change exists to keep. The test now
captures the log output and requires both the traceback and the original
exception text in it.

## Claude Implementation Notes
- backend/users/tests/test_community_journey.py: Capture the assertLogs context in test_complete_failure_returns_json_error_and_rolls_back and assert 'Traceback' and the exception message appear in the joined output.

* Fix new Creator and Builder role grants failing at the final step

Since the June onboarding rework, every first-time role grant through the
Creator and Builder journeys failed in production while all tests passed.
The completion endpoints re-fetched the user via type(request.user), and
in production request.user is Django's lazy wrapper: every attribute
access proxies to the real user, but the wrapper's type has no .objects
manager, so the grant crashed and rolled back on the exact line that only
runs for genuinely new members. Tests authenticated with a concrete user,
which is why the suite never saw it. Both endpoints now resolve the model
through get_user_model(), and each journey gains a completion test that
runs through the real session authentication chain so the wrapper shape
is covered from now on.

## Claude Implementation Notes
- backend/users/views.py: Replace type(user).objects with get_user_model().objects in complete_builder_journey and complete_community_journey; comments explain the SimpleLazyObject trap. Confirmed against the production CloudWatch traceback (AttributeError: type object 'SimpleLazyObject' has no attribute 'objects' at the fresh_user re-fetch).
- backend/users/tests/test_community_journey.py: test_complete_grants_creator_through_wallet_session_auth completes the journey via login_wallet_session; reproduced the production 500 before the fix.
- backend/users/tests/test_builder_journey.py: test_complete_grants_role_through_wallet_session_auth, same pattern for the builder grant.
- backend/CLAUDE.md: New "request.user is a lazy wrapper" section documenting the trap and the wallet-session test guards.

* Update changelog

* Keep exception internals out of journey completion error responses

A failed role grant returned str(exception) to the client, and the
portal renders those fields verbatim. Database error text can carry
table and constraint names or even the conflicting row values, so the
client now gets a stable completion_failed code with a friendly message
while the full traceback stays in the server logs, which today's
diagnosis proved is the channel that matters.

## Claude Implementation Notes
- backend/users/views.py: Both journey completion except blocks return {'error': 'completion_failed', 'message': ...} instead of interpolating str(e); logger.exception unchanged. The frontend completionErrorMessage helpers pick up data.message, so no frontend change is needed.
- backend/users/tests/test_community_journey.py: The failure test now asserts the stable error code and that the exception text does NOT appear anywhere in the response, while still requiring it in the logged traceback.

* Show tracebacks in the dev console log format

logger.exception call sites are the only durable traceback source once a
view catches an error, and the production JSON formatter already renders
them. The human-readable console formatter used in development dropped
exc_info entirely, leaving a bare one-line ERROR. It now appends the
formatted traceback, and both formatters have a direct test pinning the
exception rendering.

## Claude Implementation Notes
- backend/tally/middleware/logging_utils.py: LayeredFormatter.format appends self.formatException(record.exc_info) when present, matching LayeredJSONFormatter's behavior.
- backend/tally/tests/test_logging_formatters.py: New direct tests asserting both formatters include the traceback and exception text.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e0afd88f-5238-4a32-8482-aed592065615

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@JoaquinBN
JoaquinBN merged commit 1ae0af0 into main Aug 5, 2026
61 checks passed
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.

2 participants