MIP-0054 tasks¶
Ordered delivery of MIP-0054 as stacked PRs
(.claude/skills/mip-tasks/SKILL.md, scripts/stack.sh). Branch mip-0054/<k>-<slug>, each based
on the previous; merge bottom-up, scripts/stack.sh restack after each squash-merge.
This round is the site's half and the codes that close it. Tasks 1 and 2 are the page; task 3
is the Scala change that lets the page translate the scoring notes. The summary, the corpus and the
guard are listed under "Later" and stay unfiled. File MIP-0044's and MIP-0046's tasks first:
tasks 1 and 2 depend on them, and just tasks-to-issues refuses an unfiled cross-MIP edge.
| # | slug | delivers | tests (must exist before the PR) | depends on |
|---|---|---|---|---|
| 1 | i18n-chrome | §5.1's site half as amended at acceptance, and §5.5's language half. In site/static/ui.js: I18N = {'pt-BR': {…}, en: {…}} with every static string of index.html, about.html and chat.js (nav, controls, hour label, legend, day labels, status, footer blurb, chat, noscript); t(key, args) falling back to English, then the key; the §5.5 resolver (?lang=, then localStorage['marola.lang'] inside try/catch, then navigator.languages, then pt-BR); applyLang() over data-i18n, data-i18n-title, data-i18n-aria-label and data-i18n-placeholder, plus document.title and <html lang>; #lang, two <button aria-pressed> in MIP-0044's menu-prefs, writing the store and ?lang= through setParam, which moves from app.js into ui.js. Both HTML files' source text becomes pt-BR, and about.html's article carries both languages as two article[lang] blocks shown by :lang() CSS |
scripts/site_check.js: <html lang="pt-BR"> in both files; a default run (empty search, navigator: {}, a localStorage that throws) resolves pt-BR; ?lang=en resolves en; a stored en with ?lang=pt-BR resolves pt-BR; navigator.languages = ['en-US'] resolves en; #lang is two <button>s with aria-pressed and no href="#", and a click flips them and writes both the store and the URL; the two catalogs have identical keys and no empty value; every data-i18n* key in both HTML files exists; values are lowercase except an allowlist (°C, UV, km/h, PRÓPRIA, IMPRÓPRIA, GitHub, Open-Meteo, IMA/SC). Screenshots at 390 px and 1280 px in both languages |
0044-T1 |
| 2 | i18n-app | Every string app.js builds goes through t(): tooltip and card cells, the list, the hour label, status and fail(), the footer, the near-me notices. renderDays is split out of selectArea, so a language flip relabels the days without a fetch, and an onLang hook re-renders in place. wind_level, jellyfish and whales values render through lvl.* and wind.* keys, unknown values passed through. noteText() renders t('note.' + code, args) when the board carries note_codes and the English notes string otherwise, with the sixteen note.* keys task 3 will emit, in both languages |
scripts/site_check.js, per language: the default run shows hour-label = "melhor hora por praia", a tooltip with "água-viva" and "ondas … a cada", and 1/1 PRÓPRIA (25 Aug) untouched (the board's own month, until later); a ?lang=en run shows today's English needles; a synthetic board with note_codes renders note.choppy in both languages; the real fixture, without codes, shows notes verbatim; the marker-path and band-class assertions unchanged. Screenshots of the tooltip and the card in both languages |
1, 0046-T1 |
| 3 | note-codes | §5.1's board half, Scala, verified only in CI (no JDK on the machine this was planned on). Swimability returns Note(code: NoteCode, args) instead of String; Board writes hours[].note_codes and best.note_codes next to notes, which stay; board.schema.json's schema enum becomes [1, 2]; Report's English wording is unchanged; site/fixtures/board.json gains codes |
SwimabilitySpec asserts on NoteCodes, not English strings. BoardSpec: note_codes present, schema 2, and a schema-1 fixture still validates. scripts/site_check.js: the fixture validates against the schema, and task 2's hook renders its real codes in both languages. just quality green in CI |
2 |
Later (not filed)¶
- messages-report:
marola.i18n.Messages,Reportin pt-BR,--langandMAROLA_LANG, andwater.summary's month per language (§5.1, §3's CLI block). Decides which catalog is canonical for thenote.*overlap (§11). Depends on 3. - prompts-pt: the pt-BR DSPy recompile of both prompts (§5.2). Depends on messages-report.
- corpus-pt:
knowledge/pt-BR/, sourced line by line (§5.3). - language-guard:
LanguageGuardand the benchmark's pt-BR arm (§5.4, §7). Depends on messages-report and corpus-pt. - area-default: §5.5's location half on the site: a stored area, the nearest area on "near me", the timezone hint, and §3's outside-coverage line. Client-only, and the natural next task to file.
Decisions¶
- The site's catalog is a JS object in
ui.js, notdata/i18n/*.jsonfetched at load. No request before the first render, no flash of the wrong language, works fromfile://, and no Scala in the site's half. Recorded in §5.1. pt-BRis the last fallback, as §5.5 says. In practicenavigator.languagesdecides for almost every visitor, and the constant only matters to a browser that exposes no language.- Mixed language between tasks 1 and 3 is accepted. The chrome turns Portuguese while the notes, the water summary's month and the lore stay English (§8). Task 3 closes the notes.
- The release blocker is unchanged. Release 0 still waits for the whole MIP, later tasks included; this round does not make the release shippable on its own.
- A native-speaker pass gates the release, not task 1's merge (§11), since the page is English only today.