Skip to content

Preview rollup: full facelift + jsCat stack (for team comments — do not merge) - #623

Draft
mcfrank wants to merge 17 commits into
masterfrom
phase5-jscat
Draft

Preview rollup: full facelift + jsCat stack (for team comments — do not merge)#623
mcfrank wants to merge 17 commits into
masterfrom
phase5-jscat

Conversation

@mcfrank

@mcfrank mcfrank commented Jul 9, 2026

Copy link
Copy Markdown
Member

Do not merge this PR — it exists so the team can comment on the complete diff in one place after clicking around the live preview:

🔗 http://webcdi-preview.us-west-2.elasticbeanstalk.com

(Same logins as the dev site; the preview shares the dev database, so anything you create there is real dev data. The preview also runs the new in-browser CAT — open any CAT study link to try it.)

This is the combined view of the six-PR stack, which merges in order:

  1. 1/6 Tech debt: dev docs, .env template, compose hardening, settings refactor #617 — dev docs, .env template, compose hardening, settings refactor
  2. 2/6 Mobile: viewport meta tags + normalized compensating CSS #618 — mobile viewport + CSS normalization
  3. 3/6 CAT item parameters for all five languages, exported from the R API #619 — CAT item parameters for all five languages
  4. 4/6 Facelift: design-token theme, layered layout, About + Documentation pages #620 — facelift: theme, layout, About + Documentation pages
  5. 5/6 Console dashboard + study page rework; test suite green and 3.6x faster #621 — console dashboard + study page; test suite green and 3.6× faster
  6. 6/6 In-browser CAT via jsCat, behind a CAT_ENGINE flag #622 — in-browser CAT via jsCat (opt-in per environment; production unchanged)

How to comment: big-picture reactions and anything you notice on the preview site → comment here. Specific code concerns → line comments on the numbered PR that owns the change. This draft closes unmerged once the stack lands.

🤖 Generated with Claude Code

mcfrank and others added 17 commits July 9, 2026 11:34
.env.example documents every env var settings.py reads, with values
that work out of the box with docker-compose. DEVELOPMENT.md is the
setup guide (build, migrate, populate, day-to-day commands). The
.gitignore .env* pattern needed an exception so the example can be
tracked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unpinned postgres image began pulling Postgres 18, which changed
its data-directory layout and refuses the volume mount at
/var/lib/postgresql/data. The db healthcheck was a no-op ("exit 0"),
so web could start before the database accepted connections and
crash with a DNS/connection error; depends_on now waits for
pg_isready. Also drops the obsolete compose "version" key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Leftover from the pre-R-API python (catsim) CAT implementation;
nothing references it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ALLOWED_HOSTS, ADMINS, and TRUSTED_ORIGINS shared triplicated
string-mangling; that logic now lives in two documented parser
functions accepting both the quoted-literal and unquoted EB
shorthand formats, with identical results (verified by diffing a
full settings dump before/after — the only change is that the
leaked TEMP_ADMINS/TEMP_ALLOWED_HOSTS intermediates are gone).

DEBUG used bool(os.environ.get(...)), which is True for ANY
non-empty string including "False"; it now uses the existing
is_true() helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…for them

The participant-facing base templates (cdi_base, administration_base,
registration base, home) had no viewport meta tag, so phones rendered
pages in the ~980px fallback viewport scaled down. The small-screen
CSS compensated with huge sizes (40px body text, 46px icons, 60px
datepicker cells); with a real viewport those compensations over-fire,
so this change is necessarily coupled: viewport tags added, font
scale normalized to 16px/18px, form-control and modal/datepicker
compensations removed, checkboxes/radios enlarged to comfortable tap
targets, and a small phone gutter added for pages without a Bootstrap
container.

Both copies of each stylesheet (app source and the tracked
STATIC_ROOT copy) are updated in sync.

Verified with phone- and desktop-size screenshots of the home page,
background-info form, and vocabulary checklist; also fixes desktop
artifacts (truncated item labels, overflowing sidebar buttons).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Exports the 2PL item banks from langcog/cdi-cat-api's
combined_CAT_parms.Rdata into the existing webcdi CSV format
(classic-b difficulty = -d/a1, matching [English_CAT].csv, which
reproduces the R values to 1e-14). Adds the missing Japanese and
Dutch starting-words files and refreshes the stale French one;
instruments.json now points each CAT language at its own item bank
instead of the English placeholder.

Dutch parameters are derived from the model object
(coef(irt_models$NL)) rather than the repo's irt_coefs table, which
comes from a different fit — see
langcog/cdi-cat-api#14.

Every language was validated against freshly generated mirtCAT
ground-truth sequences: theta trajectories match jsCat within 0.0024
at all 256 steps and maximum-information item selection matches
246/246.

These CSVs are data-only today (07_populate_cat_items has been dead
since the InstrumentItem model was removed in migration 0075); they
are the canonical source for the upcoming in-browser jsCat CAT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Design-token layer loaded after Bootstrap in the participant, auth,
home, and researcher base templates. Warm paper ground, deep pine
accent replacing stock Bootstrap blue, green checked-state treatment
that flips the whole checklist card, 44px+ tap targets, keyboard-only
focus rings, and un-underlined <strong>. Also makes the home page
hero responsive (logo max-width, headings allowed to wrap) and drops
hardcoded inline link colors from the login template.

No markup restructuring; the URL smoke baseline is byte-identical.
Verified by screenshot on phone and desktop: home, login, researcher
console, background-info, and vocabulary checklist (checked answers
persist across reload).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The console rendered {% block main %} straight into <main> with no
container, so buttons and text sat flush against the viewport edge;
the theme now centers it at max 1140px with gutters. The navbar was
missing Bootstrap's navbar-light class, leaving the hamburger icon
invisible at narrow widths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ze test runs

The CDI-format download encoded every cell to bytes (a Python-2
relic); pandas 3 str-dtype columns reject bytes, so
download-study-scoring crashed (the two tests tagged @tag('error')).
Cells stay str now, which is also what the replace() value maps
expect.

test_korean_get grabbed [0] from an unordered, unscoped
completed-administrations queryset and never logged in, so it failed
depending on suite order; it now scopes to its own study and logs in
like its sibling test.

test_spanish_seq_1 replays a sequence recorded against a different
parameter set than the currently deployed CAT API (which returns
pre-rename names like "bolsa (household)"), so it is skipped with an
explanation until it is re-recorded or replaced by the offline jsCat
validation harness.

make docker-test now runs without coverage and with --parallel auto;
the sequential coverage run moved to docker-test-coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Palette tokens renamed to semantic names (--wcdi-primary etc.) and
shifted from pine green to a deep harbor blue per team preference;
the green checked-state stays as semantic color. Future palette
changes are now a three-line token edit.

Layout: the researcher navbar becomes sticky and gains Documentation
and About links plus a user avatar chip; a page_header template block
is available for console pages; a shared footer (lab attribution,
Documentation / About the MB-CDI / GitHub / Contact) is included on
researcher, participant, auth, and home pages and pinned to the
bottom of short pages. The login form moves into a centered card
with properly styled fields.

Also adds tblib to test requirements (Django needs it to report
failures under --parallel) and --noinput to the docker-test target
so leftover test databases from interrupted runs don't prompt.

URL smoke baseline byte-identical; verified by screenshot on phone
and desktop: login, console, checklist, home.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rofile

The administrations table becomes a card with a proper header row,
row hover, and a styled search box and pagination; long action-button
labels wrap instead of overlapping, and disabled bulk actions render
quiet until row selections enable them. table.html's embedded
.login-card style block (overflow:scroll, white headings) is
neutralized from the theme. The profile page is rebuilt as two card
panels using new generic .wcdi-card-panel / .wcdi-form-table styles
that any as_table form can adopt.

URL smoke baseline remains byte-identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PDFAdministrationDetailView deliberately redirects Korean
administrations to the HTML view instead of rendering with
WeasyPrint. The test expected 200 and only passed when its unscoped
queryset happened to grab a non-Korean fixture administration; now
that it deterministically tests a Korean administration, it asserts
the redirect the view actually performs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ages

Home: hero with Register + Login buttons and the sponsor/support text
moved into a card at normal weight. Navbar: links left, user chip
flush right, new Instruments item, and Documentation/About now point
at real pages instead of a bare PDF and an external redirect.

New pages: /about/ (what Web-CDI is, support contacts, citations,
links) and /documentation/ — the 16-page PDF manual converted to a
sectioned HTML page with a table of contents, updated for current UI
names, keeping a link to the original PDF. Footer links updated.

Study page: form-inline made the administrations table expand past
the viewport so scrolling dragged the buttons and header along;
min-width:0 confines it and the table now scrolls inside its own
card. Wrapped table headers and tighter padding make the table
~35% narrower. Search input and button render as one row.

Instruments selection is now a single card with a title and helper
text (also fixes a stray unclosed div in that template).

URL smoke diff shows exactly the two new URLs and no other changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s only

console.css loaded Karla through a single-weight 2016-era @font-face,
so every weight on the researcher pages rendered from one heavy cut —
the whole site read as bold with wide spacing. The theme now sets the
system font stack (SF Pro / Segoe UI / Roboto) at weight 400 with
normal letter-spacing for body text, reserving 700 for headings,
matching the typography of the design mocks. Applies to researcher,
participant, auth, and home pages alike since they all load the theme
after their legacy stylesheets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…down

The console now opens on "Your administration groups": one card per
group with instrument, completion progress bar, completed/total
administrations, and unique-children count (annotated in the Console
view queryset). "+ New administration group" moves into the page
header; new users see a three-step getting-started card linking to
Instruments, group setup, and the documentation.

The study page gets a proper header — back link, study name,
instrument and stats line, and a compact group switcher — replacing
the duplicated welcome banner. Its form actions are unchanged and
verified (search posts and filters; buttons post as before). The
white-on-white heading that table.html's embedded styles caused is
overridden.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The action buttons were four col-3 blocks with wrapping centered
labels at four different heights. They are now two flex toolbars with
auto-width, single-line buttons grouped by scope: group actions (Add
Administrations as the primary action, Download All, Update Group,
and a right-aligned Delete Group) and a table toolbar (search, then
"With selected: Re-administer / Download / Delete"). Destructive
buttons get a quiet red danger treatment; the long explainer under
Add Administrations moved into its tooltip; the back link is bigger.
All element ids are unchanged (Selenium tests and researcher_UI.js
target ids), and selection-enabling, search, and dropdowns verified
in the browser.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orm nav

The CAT can now run entirely client-side. A new 08_generate_cat_json
command converts the per-language item CSVs into static JSON banks
(1-based indices matching the R API, so CatResponse data stays
comparable). cdi_forms/cat_forms/jscat/ holds the engine source — a
thin wrapper over @bdelab/jscat (MLE) with the MAP fallback mirtCAT
uses for unmixed patterns and maximum-information selection — plus an
esbuild bundle step and a test that validates the BUILT bundle
against mirtCAT ground-truth sequences committed in jscat/ground_truth/
(all five languages: theta within 0.0024, identical item choices and
stop points, one documented 0.002%-information near-tie).

settings.CAT_ENGINE selects the engine ("remote" default keeps
production on the R API; "browser" serves cat_form_browser.html,
which fetches the bank, runs the engine, and posts each answer to the
new CatAnswerView JSON endpoint — persisting the same CatResponse
fields per answer and applying the same completion rules, with no
page reload per word). The completion page's hardest/easiest words
are computed locally from the bank in browser mode (verified
identical to the R API's output). Four network-free tests cover the
new flow; make docker-test pins CAT_ENGINE=remote so the remote-path
tests stay deterministic, and make docker-test-jscat regenerates the
banks and validates the bundle. Remote-path regression: 15 tests OK.

Also in this change, participant form polish: the shared navigation
include becomes a sticky bottom bar with previous/next arrow buttons,
an inline progress bar, and quiet Save/Background links (all input
names and ids unchanged); the CAT instructions move into a shared
include; and the completion pages (cat_completed,
administration_summary) get the viewport tag, the site theme, a card
layout, and body copy at normal weight.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gitguardian

gitguardian Bot commented Jul 9, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
9415972 Triggered Generic Password 8ba9af7 .env.example View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

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