Conversation
Wrapped the decorative × entity in the onboarding banner close button inside an element with aria-hidden="true". This prevents screen readers from announcing "multiplication sign" or "times" redundantly alongside the existing aria-label. Also recorded this learning in .Jules/palette.md for future reference. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added `@ratelimit(key="ip", rate="10/m", method=["GET", "POST"], block=True)` decorator to `invite_accept` to prevent brute force and DoS attacks. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added dynamic, descriptive `aria-label`s to the "Approve" and "Dismiss" buttons within the pending surveys table (`templates/surveys/client_surveys.html`). Previously, screen readers iterating through the table read "Approve, button" and "Dismiss, button" consecutively without indicating which survey the action applied to. Using Django's `blocktrans` block, the labels now include the corresponding survey name directly (e.g. "Approve Initial Intake Survey"), providing clarity and fulfilling WCAG guidelines on providing context for interactive elements. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…you. I implemented a global listener in `static/js/app.js` to automatically set `aria-busy="true"` and temporarily disable pointer events on form buttons when they are clicked. This ensures users get immediate visual feedback (a loading spinner provided by Pico CSS) and prevents duplicate requests. Additionally, I included a safety check for `event.defaultPrevented` to avoid breaking forms that handle their own client-side validation logic, along with an event listener on `pageshow` to remove the loading state if the user navigates back to the page using the browser's Back/Forward Cache (BFCache). Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Add `content: "\1F4CB" / "";` to `.empty-state::before` so screen readers ignore the decorative clipboard icon instead of announcing "clipboard". - Added a fallback `content: "\1F4CB";` declaration for older browsers. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…aries 🚨 Severity: HIGH 💡 Vulnerability: Missing rate limiting on `accept_invite` and `staff_assisted_login` (apps/portal/views.py) and `public_registration_form` (apps/registration/views.py). 🎯 Impact: This exposes the application to brute-force or Denial-of-Service (DoS) attacks on authentication-related endpoints that consume one-time tokens or handle user registrations. 🔧 Fix: Added `@ratelimit` decorator with `block=True` to the affected endpoints to enforce rate limits and protect against abuse. ✅ Verification: Ran `python -m pytest tests/test_security.py` successfully. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
**Severity:** HIGH **Vulnerability:** The `accept_invite` and `staff_assisted_login` endpoints in `apps/portal/views.py` handle authentication logic and token validation but were missing rate limiting. **Impact:** Attackers could attempt brute-force or Denial-of-Service (DoS) attacks on these sensitive endpoints. **Fix:** Added the `@ratelimit(key="ip", rate="10/m", method=["GET", "POST"], block=True)` decorator to both functions, standardizing them with other authentication boundaries. **Verification:** Ran `python -m pytest tests/test_security.py` to ensure existing behavior is preserved and syntax compiled properly. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…eview Reviewed the old OpenWebUI transcript structuring prompt that preceded KoNote's qualitative analysis features. Three ideas worth preserving: data quality transparency panel, language-aware quote collection, and graduated confidence on theme auto-links. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DQ1 — Data quality transparency (practice signal):
- Enhanced summary bar with month count for temporal context
- Added contextual sentence above Participant Voice section when
voice coverage is below 30% ("Participant reflections were recorded
in X of Y sessions")
- Added raw counts (with_voice, total_full) to practice_health dict
CONF1 — Raised auto-link threshold from 2 to 3 words:
- Reduces false positives in theme auto-linking without creating
a review queue for program managers
LANG1 — Language-aware quote collection (Phase 1):
- Added detect_language() heuristic (FR/EN) using French function
words — no external dependencies
- Each quote now carries a "lang" field from collect_quotes()
- AI prompt in generate_outcome_insights() includes language
distribution and instructions to analyse French quotes in French
- Templates show FR pill on quotes only when mixed-language content
is detected (invisible for monolingual programs)
- Added lang="fr" attribute to French blockquotes for accessibility
Tests: 31 pass (6 new — language detection + 2-word rejection)
French translations added for new blocktrans strings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The contextual sentence about participant reflections was rendered twice — the second copy also used a different blocktrans variable name (voice vs with_voice), so it wouldn't match the French .po entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove redundant re.IGNORECASE from _WORD_SPLIT_RE (text is already lowered before matching) - Fix double blank line in AI prompt when lang_line is non-empty Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…point Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added rate limiting to the `accept_invite` and `staff_assisted_login` views in `apps/portal/views.py`. These endpoints handle authentication and registration actions using one-time tokens, making them sensitive to brute-force and DoS attacks. Applying `@ratelimit` with `block=True` ensures they are protected consistently with other auth endpoints in the application. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Wrap decorative HTML entities (×, ←, →) in `<span aria-hidden="true">` across templates so that screen readers ignore them, improving accessibility.
Carefully places the spans OUTSIDE of Django `{% trans %}` and `{% blocktrans %}` translation tags to avoid invalidating existing translations or causing template syntax errors.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…ata export New export tier for external program evaluators: de-identified participant-level CSV with k-anonymity enforcement, pseudonymous IDs, and generalised demographics. Designed through expert panel (evaluator, privacy, nonprofit PM, health informatics). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…a-export-drr Add DRR for de-identified evaluation microdata export
Session kickoff prompt for implementing EVAL-EXPORT1 (de-identified microdata export). Added to Parking Lot: Ready to Build in TODO.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…session-prompt Add session prompt and TODO for evaluation microdata export
…microdata exports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10-step pipeline: extract → decrypt → consent filter → strip PII → generalise QIs → k-anonymity → resolve violations → population gate → generate CSV → suppression report. Enforces k=5 anonymity, population thresholds, and 15% suppression ceiling per DRR. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two-step flow: form → preview (shows pipeline results, population summary, generalisations, suppression) → generate (creates SecureExportLink, audit log, encrypted linkage). View enforces can_create_evaluation_export() permission check. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add evaluation_microdata to SecureExportLink.EXPORT_TYPE_CHOICES. Add permission-gated nav link in Reports dropdown. Linkage key stored in filters_json (no migration needed). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Admins can mark non-sensitive field groups as available for evaluation export QI columns. Validation blocks marking groups with sensitive fields. Shown in Django admin list and agency admin form. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bulk-fetch ProgressNote stats, MetricValues, and ClientDetailValues in Step 2 (was ~2800 queries for 200 clients, now ~4) - Remove unused _suppressed_records list and SMALL_CELL_THRESHOLD import - Extract _active_records property to replace 7 repeated list filters - Move inline `import re` to module level - Use ProgramSelectionMixin for clean_program() RBAC validation - Remove duplicate audit log entry (pipeline already logs the export) - Use settings.SECURE_EXPORT_DIR directly (no fallback) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add clean_program override to reject __all__ sentinel (crash fix) - Fix broken blocktrans with inline filter in preview template - Filter pipeline custom fields by is_evaluation_exportable (data leak fix) - Remove dead duplicate ProgressNote query - Remove unused imports (field, PlanTarget) - Fix stale link object — refresh_from_db + single update Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Hand-written migration 0043 for CustomFieldGroup.is_evaluation_exportable (makemigrations cannot run locally — no Django env) - Add metric slug collision detection with warning log in Step 1 - Deduplicate metric slugs with _2, _3 suffix in bulk metric fetch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…a-export Add de-identified evaluation microdata export
Gives Claude Code Review KoNote-specific rules to check: PHIPA consent, encrypted fields, form validation, template conventions, accessibility, translations, and design rationale. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused namedtuple import - Fix name uniqueness check: was querying encrypted field values and comparing to plaintext tuples (would never match). Replaced with a within-batch uniqueness tracker - Make consent flag assignment deterministic: use record_id order instead of random so repeated runs produce consistent results Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ixes Fix review issues in eval export seed command
Session review panel flagged that the boolean field should clearly indicate it's a stopgap, with a pointer to the full grant model design in tasks/eval-export-governance.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ment Add TODO comment on evaluation_export_granted field
Differentiates from standard reports in the menu. Makes it clear this export is for an external evaluator and contains sensitive de-identified data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename Evaluation Export to Evaluator Export (Confidential)
…8-162435 Add REVIEW.md for Claude Code Review
…o seed Closes the admin bypass in the Evaluator Export (Confidential) flow and restores the governance model from tasks/eval-export-governance.md: the report.evaluation_export permission is DENY for all roles by default and must be explicitly granted per-user. Admins are the granters, not the operators, so they no longer auto-hold the permission. Fixes: - apps/reports/utils.py: remove is_admin bypass in can_create_evaluation_export so an admin without an explicit grant gets 403 at the view layer (previously 200). - templates/base.html: remove `or user.is_admin` from the Evaluator Export nav visibility so the link no longer appears for admins unless they have been explicitly granted the permission. - templates/base.html: add missing "Team Members" link to the admin dropdown (admin_users:user_list). Previously the admin menu only had "User Invites", giving admins no way to view or edit existing users. - apps/auth_app/permissions.py: update stale comment on the four DENY entries to reflect that admins are NOT auto-granted. Demo seed: - apps/reports/management/commands/seed_eval_export_demo.py: extend the permission grant to cover Casey Worker (demo-worker-1, PM in the Supported Employment program the demo export is wired up against) in addition to Morgan Manager and Eva Executive. - apps/admin_settings/management/commands/seed.py: wire seed_eval_export_demo into the main seed orchestrator so the full Evaluator Export demo (extra participants, demographics, consent flags, discharges, plans, notes, permission grants) runs automatically on container startup when DEMO_MODE is on. Non-fatal on failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pass Enforce per-user grant for Evaluator Export, add Team Members link, wire demo seed
…mmary, and improve UI elements - Updated metrics application to support configuration of cadence sessions. - Enhanced custom fields management with updates for existing fields. - Introduced financial coaching summary feature with toggle. - Improved UI for survey progress and timeline events. - Added action steps to plan targets and updated related forms. - Enhanced CSS for better visual differentiation of goals and timeline events.
Enhance metrics and custom fields handling, add financial coaching summary, and improve UI elements
Enhance accessibility and security with ARIA labels and rate limiting
.Jules/ was added to .gitignore (line 37) but palette.md and sentinel.md were already tracked, so git kept watching them. Removing from the index stops tracking without deleting the files from disk. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…9-112619 Untrack .Jules/ files so .gitignore rule takes effect
Follow-up to 546cda4 cleaning up findings from /simplify review. - apps/reports/utils.py: delete the dead role-loop fallback in can_create_evaluation_export. All four roles have DENY for this permission in apps/auth_app/permissions.py, so the loop could never return True — and worse, it would have silently bypassed the per-user governance if a role were ever flipped to ALLOW. The function is now a one-line attribute read, matching the template tag's fast path. Also collapses the 8-line docstring that was narrating the governance doc. - apps/auth_app/templatetags/permissions_tags.py: add a comment noting that the per-user evaluation_export_granted check mirrors the helper in reports.utils, so future changes keep both sites in sync. - apps/reports/management/commands/seed_eval_export_demo.py: add a fast-path short-circuit at the top of _run(). The seed runs on every container startup (wired via the main seed orchestrator) and previously did ~1-5s of read + unconditional-write DB work even when the demo was already fully seeded. Two cheap indexed queries now let us skip the whole sweep when enrolments are at target and all grantees already hold the permission. Hoists the grantee list to a module-level EVAL_EXPORT_GRANTEES constant shared with _grant_permission so the fast-path check and the grant step can't drift. - apps/admin_settings/management/commands/seed.py: drop the 5-line "Step 3" narration comment. The method name self-documents and the comment just restated the sub-command's docstring. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pass Simplify eval export check and short-circuit demo seed
Follow-up to #617 / #622 addressing the "Fix soon" items from the /review-session expert panel. 1. tests/test_export_permissions.py: add EvaluatorExportPermissionTest with three tests against /reports/evaluation-export/: - admin without the per-user grant → 403 (regression guard for the is_admin bypass that PRs #617 / #622 removed; if anyone ever adds `or user.is_admin` back to can_create_evaluation_export or the nav check, this test fails) - non-admin with evaluation_export_granted=True → 200 - anonymous → 302 login redirect (confirms @login_required runs before the permission check so the 403 path isn't reachable without a session) Uses the existing test_export_permissions.py fixture style (direct User.create_user with TEST_KEY Fernet, Client().force_login, no PM role needed because the permission is per-user not per-role). 2. apps/reports/management/commands/seed_eval_export_demo.py: extend the fast-path comment block noting that the short-circuit's correctness depends on handle() wrapping _run() in transaction.atomic() — so a future refactor that relaxes atomicity must re-audit the check or risk skipping a partially-seeded state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Splits EvaluatorExportPermissionTest into two layers: - 3 helper-level unit tests of can_create_evaluation_export (pure function, no view/template rendering — robust against unrelated template context issues): admin without grant → False, granted non-admin → True, plain user without flag → False. - 2 view-level tests: admin without grant → 403 (the actual regression guard), anonymous → 302 login redirect. Removed the earlier "granted user → 200" view test: that path renders the full evaluation_export.html template which pulls in terminology and feature context processors — a single-purpose permission test shouldn't be fragile to unrelated template changes. The helper unit test covers the positive path more cleanly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…egression Add regression test and atomicity comment for Evaluator Export
Detailed prompt for a future session to build the admin UI for granting report.evaluation_export (with mandatory reason field, audit trail, and revoke flow). Covers: data model, signal-based cache sync, form validation, view + URL + template scaffolding, demo seed update, test expectations, acceptance criteria, and a list of explicit anti-patterns from the governance doc. Closes the policy hole flagged by the /review-session expert panel: the bug-fix PRs (#617, #622, #623) closed the technical hole (admin bypass + regression tests) but without EVAL-GOV1 the governance model is only half-enforced because there is still no reason field on grants and the only way to grant is via Django admin. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add EVAL-GOV1 implementation prompt
- Recently Done: add EVAL-GOV-BYPASS1 entry bundling PRs #617, #622, #623, #624 (governance fix + simplify + regression test + EVAL-GOV1 prompt). - EVAL-GOV1: add pointer to tasks/phase-eval-gov1-prompt.md so the next session doesn't have to re-derive the implementation plan. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ss-done TODO: record Evaluator Export bypass fix and link EVAL-GOV1 prompt
…xport to perm map ProgressNote.created_at uses auto_now_add=True which ignores values passed in create(). Now that today (2026-04-09) is past the hardcoded fiscal year end (2026-03-31), notes were invisible to date-filtered queries. Switch to backdate which the filter already checks first. Also adds the missing report.evaluation_export entry to PERMISSION_URL_MAP. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd-perm-map fix: test date filters and perm map entry
chore: promote develop to staging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces several important enhancements and fixes across accessibility, security, admin tooling, and evaluation export governance. The most significant changes include new accessibility guidelines, improved rate limiting for invite endpoints, expanded admin setup automation, and the introduction of a new evaluation export permission for users. Additionally, supporting documentation and review processes have been updated to reflect these changes.
Accessibility Improvements:
<span aria-hidden="true">for better screen reader support, and clarified the use of contextualaria-labels for action buttons in lists to improve accessibility for users with assistive technology (.Jules/palette.md, .jules/palette.md) [1] [2].Security Enhancements:
invite_acceptendpoint to prevent brute-force and DoS attacks, including the necessary import and decorator application (apps/auth_app/invite_views.py, .jules/sentinel.md) [1] [2] [3].Evaluation Export Governance:
evaluation_export_grantedBoolean field to theUsermodel, with corresponding admin UI and migration, to support permission-gated de-identified evaluation exports (apps/auth_app/migrations/0011_user_evaluation_export_granted.py, apps/auth_app/admin.py) [1] [2].Admin Tooling and Automation:
apply_setup.pyto support updating and configuring metrics and custom fields, including updating existing records when config changes, and improved logging/return values (apps/admin_settings/management/commands/apply_setup.py) [1] [2].Documentation and Review Process:
These changes collectively improve the system's accessibility, security, governance, and maintainability.