From 9d81706c7b2a47d40ce9591fe23eea7c04859d59 Mon Sep 17 00:00:00 2001 From: anikamw <147226875+anikamw@users.noreply.github.com> Date: Sun, 14 Jun 2026 12:58:07 -0700 Subject: [PATCH 1/2] feat(plan): note cantonal/institution-set fees & timelines where no federal figure exists 12 us-ch steps have no single federal fee or processing-time figure - the canton sets them (work, family-reunification, retirement and study permits), or the institution does (study admission). They previously showed nothing. They now carry a user-facing note that the fee/timing is set locally and to confirm with the cantonal authorities (or the institution), so the plan is honest about cantonal variability instead of silently blank. - schema: optional presentation hint localCostTimeline: 'canton'|'institution' on TaskSchema (asserts no fact, carries no provenance; ADR-0007/ADR-0021). - content: flag the 12 silent us-ch tasks (11 canton, 1 institution). - frontend: render a 'Fees & processing time' note in the plan + static guide only when the flag is set AND the task has no cost/timeline claim; plus a 'varies by canton' caveat now always shown in the 'Your canton' panel. No invented numbers, no new sourced claims. Verified: astro check 0 errors, build + provenance gate pass (15 pages), 277/277 tests; fact-verifier confirmed scope, honesty (no hidden federal figure) and no overstatement across all 12. Co-Authored-By: Claude Opus 4.8 (1M context) --- FOUNDER-TLDR.md | 12 ++++++++++++ ROADMAP.md | 4 ++-- src/components/CorridorApp.tsx | 19 ++++++++++++++++++- src/content/corridors/us-ch.yaml | 12 ++++++++++++ src/content/schema.ts | 14 ++++++++++++++ src/pages/[origin]/[destination]/index.astro | 9 +++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) diff --git a/FOUNDER-TLDR.md b/FOUNDER-TLDR.md index 7b70bc0..90465c5 100644 --- a/FOUNDER-TLDR.md +++ b/FOUNDER-TLDR.md @@ -10,6 +10,18 @@ coming next. Newest updates are at the top. --- +## 2026-06-14 — Swiss plans now say *when* a fee or timeline is set by your canton + +**What changed.** Many Swiss steps have no single nationwide fee or processing time — the **canton** sets them (and for getting into a school, the **institution** does). Until now those steps simply showed *nothing*, which can read as "free/instant" or leave people guessing. Now each such step carries a plain note: *"Fees & processing time: set by your canton, not federally — confirm the exact amount and timing with your cantonal authorities"* (study admission says "the institution"). The "Your canton" box also now reminds you these vary by canton. Importantly, **we invented no numbers** — we only made the plan honest about where the real figures come from and who to ask. Covers 11 steps (the family-reunification routes, the retirement permit, and the study permits/sub-steps). + +**Why it matters.** For legal/financial decisions, silence misleads. This sets honest expectations and points people to the right desk for the real figure — without us publishing a number we can't verify. + +**What you'd notice today.** On a Swiss plan, steps like family reunification, the retirement permit and study permits now show a "fees & processing time are cantonal — confirm locally" line instead of nothing. + +**What's next.** If/when we source the actual per-canton fee and timeline figures (currently paused), these notes can become specific numbers. + +--- + ## 2026-06-14 — Swiss plan steps now link to *your* canton's office, not a list of all 26 **What changed.** You pointed out that for an unmarried partner moving to Switzerland the rules really do hinge on the canton — and they do. Until now, the steps that say "contact the migration office of the canton where your partner lives" sent everyone to one big federal list of all 26 cantonal offices, even after they'd already told us their canton. Now, if you've picked a canton we've fact-checked (Zürich, Geneva, Vaud, Zug, Basel-Stadt), those steps link **straight to that canton's own migration office** (e.g. Zürich's Migrationsamt, Geneva's OCPM). Pick any other canton and it still falls back to the federal list — so no one ever hits a dead end. This covers every "apply at your cantonal office" step: all the family-reunification routes, the unmarried-partner case, retirement, and study. It's now passed our automatic safety checks and an independent accuracy review, I've confirmed it working in a live preview (Zürich and Geneva point to their own offices; an un-sourced canton like Bern still gets the safe federal list), and it's bundled into the batch of changes waiting for your approval — **not live yet; it goes live the moment you approve that batch.** diff --git a/ROADMAP.md b/ROADMAP.md index 410bf2e..caeafd8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,7 +6,7 @@ > > Legend: ✅ done · 🚧 in progress · ⏳ planned · 🔁 ongoing · 🗓️ backlog -Last updated: 2026-06-14 (Canton-aware plan-step links: the six "apply at / contact your cantonal authority of the canton where you live/study" steps (family reunification ×3, unmarried-partner concubinage, retirement, study) now deep-link the user's *selected* canton's own migration office (ZH Migrationsamt, GE OCPM, VD SPOP, ZG, BS) instead of the federal SEM directory of all 26 — falling back to that directory for not-yet-sourced cantons, so no dead ends. A `StepLinkSchema.cantonOffice` rendering hint (asserts no fact, no provenance) drives a frontend-only swap to the already-VERIFIED canton migrationOffice claim; static SSR full-guide stays federal (can't know the canton). Build/gate/`astro check`/277 tests green; fact-verifier (accurate, no overreach) + provenance-integrity verified; ADR-0021. Outbound links: the written-guide's 109 external source links now open in a new tab (target=_blank + rel=noopener noreferrer), matching the planner — readers don't lose their place. Plan UI: the desktop plan sidebar (progress / answers / journey) is now collapsible (Hide/Show), giving the task panel full width; mobile already had this. Canton dimension for Switzerland (ADR-0021): corridor-embedded `cantons` schema + provenance gate; CH-only "which canton?" intake step (searchable combobox over 26 cantons, optional) + `cn` share-param + "Your canton" plan panel with a verified SEM-directory fallback; per-canton sourced detail for ZH/GE/VD/ZG/BS in the two-agent pipeline. Earlier: Link audit: all 950 source links render-checked — 147 good, 23 Fedlex "under preparation" links flagged + the us-ch fix applied (79 occurrences → static-HTML, independently fact-verifier re-verified; re-audit now 0 suspect / 170 good). The weekly link-auditor now also checks anchor-reach — a `#article` link that loads but whose section never renders (SPA shell) goes RED on SPA domains (fedlex-class regressions); france-visas added to manual-check (403s the bot, fine for users). Live run: 0 errors / 142 URLs. Plan-personalisation correctness: "Who's joining you?" companion multi-select (partner/children/"It's just me") replaces the children yes/no; family/dependant steps gated to who is actually coming; full-guide route labels; cross-corridor plan-correctness regression suite — ADR-0020. UI/UX "Trust & Authority" design system adopted — audit fixes 1–10: AA-contrast CTAs, 44px touch targets, readable legal text, EB Garamond + Lato self-hosted fonts, brand tokens, consent-overlap fix, home/wizard trust framing, plus polish 11–13 (SVG icons, consistent focus rings, tighter line-length); ADR-0019. Earlier: 8 corridors published + intake availability dots, ADR-0018; source-snapshot cache, ADR-0017; corridor production via agent teams in two runs, ADR-0016; all-routes intake + launch waitlist, ADR-0015; launch-readiness drafts, og:image, dormant consent+analytics, ADR-0013; us-ch founder approval, ADR-0014; go-live blocked on domain + lawyer review) +Last updated: 2026-06-14 (Cantonal fee/timeline transparency: 11 us-ch steps that have no single federal fee/processing-time figure (the family-reunification routes, the retirement permit, the study permits/sub-steps) now show a user-facing "Fees & processing time" note that these are set by the canton — or, for study admission, the institution — and to confirm locally; driven by a presentation-only `localCostTimeline` task hint (no invented numbers, no new sourced claims, ADR-0007/ADR-0021), plus a "varies by canton" caveat now always shown in the "Your canton" panel. Canton-aware plan-step links: the six "apply at / contact your cantonal authority of the canton where you live/study" steps (family reunification ×3, unmarried-partner concubinage, retirement, study) now deep-link the user's *selected* canton's own migration office (ZH Migrationsamt, GE OCPM, VD SPOP, ZG, BS) instead of the federal SEM directory of all 26 — falling back to that directory for not-yet-sourced cantons, so no dead ends. A `StepLinkSchema.cantonOffice` rendering hint (asserts no fact, no provenance) drives a frontend-only swap to the already-VERIFIED canton migrationOffice claim; static SSR full-guide stays federal (can't know the canton). Build/gate/`astro check`/277 tests green; fact-verifier (accurate, no overreach) + provenance-integrity verified; ADR-0021. Outbound links: the written-guide's 109 external source links now open in a new tab (target=_blank + rel=noopener noreferrer), matching the planner — readers don't lose their place. Plan UI: the desktop plan sidebar (progress / answers / journey) is now collapsible (Hide/Show), giving the task panel full width; mobile already had this. Canton dimension for Switzerland (ADR-0021): corridor-embedded `cantons` schema + provenance gate; CH-only "which canton?" intake step (searchable combobox over 26 cantons, optional) + `cn` share-param + "Your canton" plan panel with a verified SEM-directory fallback; per-canton sourced detail for ZH/GE/VD/ZG/BS in the two-agent pipeline. Earlier: Link audit: all 950 source links render-checked — 147 good, 23 Fedlex "under preparation" links flagged + the us-ch fix applied (79 occurrences → static-HTML, independently fact-verifier re-verified; re-audit now 0 suspect / 170 good). The weekly link-auditor now also checks anchor-reach — a `#article` link that loads but whose section never renders (SPA shell) goes RED on SPA domains (fedlex-class regressions); france-visas added to manual-check (403s the bot, fine for users). Live run: 0 errors / 142 URLs. Plan-personalisation correctness: "Who's joining you?" companion multi-select (partner/children/"It's just me") replaces the children yes/no; family/dependant steps gated to who is actually coming; full-guide route labels; cross-corridor plan-correctness regression suite — ADR-0020. UI/UX "Trust & Authority" design system adopted — audit fixes 1–10: AA-contrast CTAs, 44px touch targets, readable legal text, EB Garamond + Lato self-hosted fonts, brand tokens, consent-overlap fix, home/wizard trust framing, plus polish 11–13 (SVG icons, consistent focus rings, tighter line-length); ADR-0019. Earlier: 8 corridors published + intake availability dots, ADR-0018; source-snapshot cache, ADR-0017; corridor production via agent teams in two runs, ADR-0016; all-routes intake + launch waitlist, ADR-0015; launch-readiness drafts, og:image, dormant consent+analytics, ADR-0013; us-ch founder approval, ADR-0014; go-live blocked on domain + lawyer review) > **Current focus:** USA → Switzerland (`us-ch`) **only**, until it is perfected end-to-end. > All other corridors are deferred (see DECISIONS.md **ADR-0006**). India → Germany (`in-de`) @@ -72,7 +72,7 @@ _Founder direction: drop the visual flowchart from the UI; make the whole produc - self-employment / starting a business - lump-sum taxation ("forfait fiscal") / wealth-based residence - study-adjacent stays (language stay, sabbatical, internship/trainee agreements with the US) -- [~] **Canton-aware path shaping (Switzerland)**: replace the free-text "canton or city" intake field with a canton picker, and let the chosen canton shape next steps — link the exact cantonal migration office, and (longer-term) reinstate the 5 cantonal-variable fee/timeline fields omitted under ADR-0007 as per-canton verified claims. _Content-heavy: every per-canton fact needs the full two-agent pipeline (26 cantons), so machinery first, cantons added incrementally starting with Zürich/Geneva/Vaud/Basel-Stadt/Zug._ **Done (ADR-0021):** canton picker + intake `cn` param + "Your canton" panel; and the exact cantonal migration office is now deep-linked both in that panel **and** in the plan's "contact your cantonal authority" steps (`StepLinkSchema.cantonOffice`, 2026-06-14). Sourced cantons: ZH/GE/VD/ZG/BS (others fall back to the federal SEM directory). **Still pending:** reinstate the per-canton fee/timeline claims, and expand canton coverage beyond the first five. +- [~] **Canton-aware path shaping (Switzerland)**: replace the free-text "canton or city" intake field with a canton picker, and let the chosen canton shape next steps — link the exact cantonal migration office, and (longer-term) reinstate the 5 cantonal-variable fee/timeline fields omitted under ADR-0007 as per-canton verified claims. _Content-heavy: every per-canton fact needs the full two-agent pipeline (26 cantons), so machinery first, cantons added incrementally starting with Zürich/Geneva/Vaud/Basel-Stadt/Zug._ **Done (ADR-0021):** canton picker + intake `cn` param + "Your canton" panel; and the exact cantonal migration office is now deep-linked both in that panel **and** in the plan's "contact your cantonal authority" steps (`StepLinkSchema.cantonOffice`, 2026-06-14). Sourced cantons: ZH/GE/VD/ZG/BS (others fall back to the federal SEM directory). Where no federal fee/processing-time figure exists, the plan now **notes** that these are set by the canton (or, for study admission, the institution) and to confirm locally (`localCostTimeline` hint, 2026-06-14) — transparency without invented numbers. **Still pending:** source the actual per-canton fee/timeline figures, and expand canton coverage beyond the first five. - [ ] **EU/EFTA passport branching**: switch the path on a free-movement passport (deferred to capture-only for now — ADR-0008) - [x] **F-08** URL state encoding (2026-06-12): plan-affecting answers encoded in the URL **fragment** (`/us/ch/#pp=us&m=work&ws=has-offer&dur=long&kids=0`) for shareable/bookmarkable profiles. Fragment, not search params, per the compliance share-link ruling — the fragment is never sent in HTTP requests, so answers can't land in server/CDN logs or analytics; free-text answers are never encoded. Restore precedence: URL > localStorage > defaults; a URL with intake params fully determines the plan (codec: `src/utils/urlState.ts`, 15 tests) - [x] **F-08 follow-up** (2026-06-12): "Copy link to this plan" button in the plan sidebar with the compliance-required pre-share warning ("This link contains your answers…"); clipboard-API failure falls back to a URL prompt diff --git a/src/components/CorridorApp.tsx b/src/components/CorridorApp.tsx index d5eeb14..8ec4458 100644 --- a/src/components/CorridorApp.tsx +++ b/src/components/CorridorApp.tsx @@ -115,6 +115,10 @@ export interface TaskData { documents: (string | TaskDocumentData)[]; timeline?: ClaimData; cost?: ClaimData; + /** Presentation hint (ADR-0021/ADR-0007): this step's fee + processing time are set + * locally — by the canton or, for study admission, the institution — with no federal + * figure. Renders a "confirm locally" note only when no cost/timeline claim exists. */ + localCostTimeline?: 'canton' | 'institution'; warning?: string; dependsOn: string[]; appliesIf?: string; @@ -1053,6 +1057,9 @@ function CantonPanel({ canton, data }: { canton: string; data: CantonData | unde

{note.text}

))} +

+ Exact fees, processing times and some procedures are set by {name} and vary across Switzerland — confirm them with the office above. +

) : (
@@ -1241,7 +1248,7 @@ function TaskCard({ {/* Key facts: scannable grid. keyFacts come from the content pipeline; the verified timeline/cost claims are appended automatically (the researcher does not duplicate them in keyFacts). */} - {(task.keyFacts?.length || task.timeline || task.cost) && ( + {(task.keyFacts?.length || task.timeline || task.cost || task.localCostTimeline) && (

Key facts

@@ -1263,6 +1270,16 @@ function TaskCard({
{task.cost.text}
)} + {task.localCostTimeline && !task.cost && !task.timeline && ( +
+
Fees & processing time
+
+ {task.localCostTimeline === 'institution' + ? 'Set by the educational institution, not at the federal level. Confirm the exact application fee and timing directly with the institution.' + : 'Set by your canton, not at the federal level — there is no single national figure, and it varies across Switzerland. Confirm the exact amount and timing with your cantonal authorities (see “Your canton”).'} +
+
+ )}
)} diff --git a/src/content/corridors/us-ch.yaml b/src/content/corridors/us-ch.yaml index 2bdc0b7..3d66957 100644 --- a/src/content/corridors/us-ch.yaml +++ b/src/content/corridors/us-ch.yaml @@ -13,6 +13,7 @@ coversMotivations: [work, family, retirement, study] tasks: # --------------------------------------------------------------------------- - id: work-residence-permit + localCostTimeline: canton title: "Secure an employer-sponsored work and residence permit" category: visa-permit summary: @@ -999,6 +1000,7 @@ tasks: # --------------------------------------------------------------------------- - id: family-permit-spouse-swiss + localCostTimeline: canton title: "Family reunification as the spouse or registered partner of a Swiss citizen" category: family-dependents appliesIf: "motivation == 'family' && familyJoineeStatus == 'citizen' && familyRelationship != 'unmarried-partner' && familyRelationship != 'parent'" @@ -1168,6 +1170,7 @@ tasks: # --------------------------------------------------------------------------- - id: family-permit-spouse-settled + localCostTimeline: canton title: "Family reunification as the spouse or registered partner of a settled person (C permit)" category: family-dependents appliesIf: "motivation == 'family' && familyJoineeStatus == 'settled' && familyRelationship != 'unmarried-partner' && familyRelationship != 'parent'" @@ -1323,6 +1326,7 @@ tasks: # --------------------------------------------------------------------------- - id: family-permit-spouse-b-holder + localCostTimeline: canton title: "Family reunification as the spouse or registered partner of a residence (B) permit holder" category: family-dependents appliesIf: "motivation == 'family' && familyJoineeStatus == 'permit-holder' && familyRelationship != 'unmarried-partner' && familyRelationship != 'parent'" @@ -1479,6 +1483,7 @@ tasks: # --------------------------------------------------------------------------- - id: family-permit-unmarried-partner + localCostTimeline: canton title: "Joining an unmarried partner (concubinage): no general right — cantonal discretion" category: family-dependents appliesIf: "motivation == 'family' && familyRelationship == 'unmarried-partner'" @@ -1619,6 +1624,7 @@ tasks: # --------------------------------------------------------------------------- - id: family-permit-children + localCostTimeline: canton title: "Family reunification for minor children" category: family-dependents # Deliberately motivation-independent: children also accompany work-route @@ -1994,6 +2000,7 @@ tasks: # --------------------------------------------------------------------------- - id: retirement-residence-permit + localCostTimeline: canton title: "Apply for a retired person's residence permit (residence without gainful employment, Art. 28 FNIA)" category: visa-permit # appliesIf APPROVED 2026-06-12 (fact-verifier, ADR-0009 §4): correct. @@ -2615,6 +2622,7 @@ tasks: # --------------------------------------------------------------------------- - id: study-admission + localCostTimeline: institution title: "Get admitted: secure the confirmation of a Swiss educational institution first" category: education # appliesIf (content-researcher, 2026-06-12, PENDING fact-verifier approval @@ -2745,6 +2753,7 @@ tasks: # --------------------------------------------------------------------------- - id: study-residence-permit + localCostTimeline: canton title: "Apply for a residence permit for education purposes (Art. 27 FNIA)" category: visa-permit # appliesIf (content-researcher, 2026-06-12, PENDING fact-verifier approval @@ -3100,6 +3109,7 @@ tasks: # --------------------------------------------------------------------------- - id: study-work-alongside + localCostTimeline: canton title: "Working alongside your studies: waiting period, hour limit and employer permit" category: employment # appliesIf (content-researcher, 2026-06-12, PENDING fact-verifier approval @@ -3272,6 +3282,7 @@ tasks: # --------------------------------------------------------------------------- - id: study-health-insurance-exemption + localCostTimeline: canton title: "Check the student exemption from Swiss compulsory health insurance" category: healthcare-insurance # appliesIf (content-researcher, 2026-06-12, PENDING fact-verifier approval @@ -3407,6 +3418,7 @@ tasks: # --------------------------------------------------------------------------- - id: study-after-graduation + localCostTimeline: canton title: "After graduation: the six-month stay to look for qualified work" category: employment # appliesIf (content-researcher, 2026-06-12, PENDING fact-verifier approval diff --git a/src/content/schema.ts b/src/content/schema.ts index 4a6604d..6ea39e3 100644 --- a/src/content/schema.ts +++ b/src/content/schema.ts @@ -168,6 +168,20 @@ export const TaskSchema = z.object({ documents: z.array(z.union([z.string(), TaskDocumentSchema])), timeline: ClaimSchema.optional(), cost: ClaimSchema.optional(), + /** + * Presentation hint (asserts no new fact, carries no provenance): for a + * cantonally-administered destination (Switzerland — ADR-0021), this step's + * fee and processing time are set locally — by the canton (`'canton'`) or, + * for study admission, the educational institution (`'institution'`) — with + * no single federal figure. ADR-0007 omits a numeric `cost`/`timeline` here + * because none exists federally; rather than leave the plan silently blank, + * this flag surfaces a user-facing "Fees & processing time" note telling the + * user the figures are set locally and to confirm them with the competent + * authority. It restates the established cantonal-administration principle — + * not a new sourced claim — so it needs no source of its own, and it is only + * meaningful when the task carries no `cost`/`timeline` claim. + */ + localCostTimeline: z.enum(['canton', 'institution']).optional(), warning: z.string().optional(), dependsOn: z.array(z.string()).default([]), appliesIf: z.string().optional(), // Expression evaluated at runtime diff --git a/src/pages/[origin]/[destination]/index.astro b/src/pages/[origin]/[destination]/index.astro index 953e8d5..ede128c 100644 --- a/src/pages/[origin]/[destination]/index.astro +++ b/src/pages/[origin]/[destination]/index.astro @@ -47,6 +47,7 @@ const appTasks: TaskData[] = corridor.tasks.map((t) => ({ ), timeline: t.timeline ? { text: t.timeline.text, sourceUrl: t.timeline.sourceUrl, sourceName: t.timeline.sourceName } : undefined, cost: t.cost ? { text: t.cost.text, sourceUrl: t.cost.sourceUrl, sourceName: t.cost.sourceName } : undefined, + localCostTimeline: t.localCostTimeline, warning: t.warning, dependsOn: t.dependsOn, appliesIf: t.appliesIf, @@ -280,6 +281,14 @@ const planScope = (appliesIf?: string): string => { ({task.cost.sourceName})

)} + {task.localCostTimeline && !task.cost && !task.timeline && ( +

+ Fees & processing time:{' '} + {task.localCostTimeline === 'institution' + ? 'set by the educational institution, not at the federal level — confirm the exact application fee and timing directly with the institution.' + : 'set by your canton, not at the federal level (no single national figure; it varies across Switzerland) — confirm the exact amount and timing with your cantonal authorities.'} +

+ )}

Source: {task.summary.sourceName} From 2acc562589dc8f79d06ec4f9bb1a77a25fd4692e Mon Sep 17 00:00:00 2001 From: anikamw <147226875+anikamw@users.noreply.github.com> Date: Sun, 14 Jun 2026 13:00:21 -0700 Subject: [PATCH 2/2] docs: correct cantonal-note count to 12 (adds work-residence-permit) Co-Authored-By: Claude Opus 4.8 (1M context) --- FOUNDER-TLDR.md | 2 +- ROADMAP.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FOUNDER-TLDR.md b/FOUNDER-TLDR.md index 90465c5..dc84623 100644 --- a/FOUNDER-TLDR.md +++ b/FOUNDER-TLDR.md @@ -12,7 +12,7 @@ coming next. Newest updates are at the top. ## 2026-06-14 — Swiss plans now say *when* a fee or timeline is set by your canton -**What changed.** Many Swiss steps have no single nationwide fee or processing time — the **canton** sets them (and for getting into a school, the **institution** does). Until now those steps simply showed *nothing*, which can read as "free/instant" or leave people guessing. Now each such step carries a plain note: *"Fees & processing time: set by your canton, not federally — confirm the exact amount and timing with your cantonal authorities"* (study admission says "the institution"). The "Your canton" box also now reminds you these vary by canton. Importantly, **we invented no numbers** — we only made the plan honest about where the real figures come from and who to ask. Covers 11 steps (the family-reunification routes, the retirement permit, and the study permits/sub-steps). +**What changed.** Many Swiss steps have no single nationwide fee or processing time — the **canton** sets them (and for getting into a school, the **institution** does). Until now those steps simply showed *nothing*, which can read as "free/instant" or leave people guessing. Now each such step carries a plain note: *"Fees & processing time: set by your canton, not federally — confirm the exact amount and timing with your cantonal authorities"* (study admission says "the institution"). The "Your canton" box also now reminds you these vary by canton. Importantly, **we invented no numbers** — we only made the plan honest about where the real figures come from and who to ask. Covers 12 steps (the employer-sponsored work permit, the family-reunification routes, the retirement permit, and the study permits/sub-steps). **Why it matters.** For legal/financial decisions, silence misleads. This sets honest expectations and points people to the right desk for the real figure — without us publishing a number we can't verify. diff --git a/ROADMAP.md b/ROADMAP.md index caeafd8..e99631c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,7 +6,7 @@ > > Legend: ✅ done · 🚧 in progress · ⏳ planned · 🔁 ongoing · 🗓️ backlog -Last updated: 2026-06-14 (Cantonal fee/timeline transparency: 11 us-ch steps that have no single federal fee/processing-time figure (the family-reunification routes, the retirement permit, the study permits/sub-steps) now show a user-facing "Fees & processing time" note that these are set by the canton — or, for study admission, the institution — and to confirm locally; driven by a presentation-only `localCostTimeline` task hint (no invented numbers, no new sourced claims, ADR-0007/ADR-0021), plus a "varies by canton" caveat now always shown in the "Your canton" panel. Canton-aware plan-step links: the six "apply at / contact your cantonal authority of the canton where you live/study" steps (family reunification ×3, unmarried-partner concubinage, retirement, study) now deep-link the user's *selected* canton's own migration office (ZH Migrationsamt, GE OCPM, VD SPOP, ZG, BS) instead of the federal SEM directory of all 26 — falling back to that directory for not-yet-sourced cantons, so no dead ends. A `StepLinkSchema.cantonOffice` rendering hint (asserts no fact, no provenance) drives a frontend-only swap to the already-VERIFIED canton migrationOffice claim; static SSR full-guide stays federal (can't know the canton). Build/gate/`astro check`/277 tests green; fact-verifier (accurate, no overreach) + provenance-integrity verified; ADR-0021. Outbound links: the written-guide's 109 external source links now open in a new tab (target=_blank + rel=noopener noreferrer), matching the planner — readers don't lose their place. Plan UI: the desktop plan sidebar (progress / answers / journey) is now collapsible (Hide/Show), giving the task panel full width; mobile already had this. Canton dimension for Switzerland (ADR-0021): corridor-embedded `cantons` schema + provenance gate; CH-only "which canton?" intake step (searchable combobox over 26 cantons, optional) + `cn` share-param + "Your canton" plan panel with a verified SEM-directory fallback; per-canton sourced detail for ZH/GE/VD/ZG/BS in the two-agent pipeline. Earlier: Link audit: all 950 source links render-checked — 147 good, 23 Fedlex "under preparation" links flagged + the us-ch fix applied (79 occurrences → static-HTML, independently fact-verifier re-verified; re-audit now 0 suspect / 170 good). The weekly link-auditor now also checks anchor-reach — a `#article` link that loads but whose section never renders (SPA shell) goes RED on SPA domains (fedlex-class regressions); france-visas added to manual-check (403s the bot, fine for users). Live run: 0 errors / 142 URLs. Plan-personalisation correctness: "Who's joining you?" companion multi-select (partner/children/"It's just me") replaces the children yes/no; family/dependant steps gated to who is actually coming; full-guide route labels; cross-corridor plan-correctness regression suite — ADR-0020. UI/UX "Trust & Authority" design system adopted — audit fixes 1–10: AA-contrast CTAs, 44px touch targets, readable legal text, EB Garamond + Lato self-hosted fonts, brand tokens, consent-overlap fix, home/wizard trust framing, plus polish 11–13 (SVG icons, consistent focus rings, tighter line-length); ADR-0019. Earlier: 8 corridors published + intake availability dots, ADR-0018; source-snapshot cache, ADR-0017; corridor production via agent teams in two runs, ADR-0016; all-routes intake + launch waitlist, ADR-0015; launch-readiness drafts, og:image, dormant consent+analytics, ADR-0013; us-ch founder approval, ADR-0014; go-live blocked on domain + lawyer review) +Last updated: 2026-06-14 (Cantonal fee/timeline transparency: 12 us-ch steps that have no single federal fee/processing-time figure (the employer-sponsored work permit, the family-reunification routes, the retirement permit, the study permits/sub-steps) now show a user-facing "Fees & processing time" note that these are set by the canton — or, for study admission, the institution — and to confirm locally; driven by a presentation-only `localCostTimeline` task hint (no invented numbers, no new sourced claims, ADR-0007/ADR-0021), plus a "varies by canton" caveat now always shown in the "Your canton" panel. Canton-aware plan-step links: the six "apply at / contact your cantonal authority of the canton where you live/study" steps (family reunification ×3, unmarried-partner concubinage, retirement, study) now deep-link the user's *selected* canton's own migration office (ZH Migrationsamt, GE OCPM, VD SPOP, ZG, BS) instead of the federal SEM directory of all 26 — falling back to that directory for not-yet-sourced cantons, so no dead ends. A `StepLinkSchema.cantonOffice` rendering hint (asserts no fact, no provenance) drives a frontend-only swap to the already-VERIFIED canton migrationOffice claim; static SSR full-guide stays federal (can't know the canton). Build/gate/`astro check`/277 tests green; fact-verifier (accurate, no overreach) + provenance-integrity verified; ADR-0021. Outbound links: the written-guide's 109 external source links now open in a new tab (target=_blank + rel=noopener noreferrer), matching the planner — readers don't lose their place. Plan UI: the desktop plan sidebar (progress / answers / journey) is now collapsible (Hide/Show), giving the task panel full width; mobile already had this. Canton dimension for Switzerland (ADR-0021): corridor-embedded `cantons` schema + provenance gate; CH-only "which canton?" intake step (searchable combobox over 26 cantons, optional) + `cn` share-param + "Your canton" plan panel with a verified SEM-directory fallback; per-canton sourced detail for ZH/GE/VD/ZG/BS in the two-agent pipeline. Earlier: Link audit: all 950 source links render-checked — 147 good, 23 Fedlex "under preparation" links flagged + the us-ch fix applied (79 occurrences → static-HTML, independently fact-verifier re-verified; re-audit now 0 suspect / 170 good). The weekly link-auditor now also checks anchor-reach — a `#article` link that loads but whose section never renders (SPA shell) goes RED on SPA domains (fedlex-class regressions); france-visas added to manual-check (403s the bot, fine for users). Live run: 0 errors / 142 URLs. Plan-personalisation correctness: "Who's joining you?" companion multi-select (partner/children/"It's just me") replaces the children yes/no; family/dependant steps gated to who is actually coming; full-guide route labels; cross-corridor plan-correctness regression suite — ADR-0020. UI/UX "Trust & Authority" design system adopted — audit fixes 1–10: AA-contrast CTAs, 44px touch targets, readable legal text, EB Garamond + Lato self-hosted fonts, brand tokens, consent-overlap fix, home/wizard trust framing, plus polish 11–13 (SVG icons, consistent focus rings, tighter line-length); ADR-0019. Earlier: 8 corridors published + intake availability dots, ADR-0018; source-snapshot cache, ADR-0017; corridor production via agent teams in two runs, ADR-0016; all-routes intake + launch waitlist, ADR-0015; launch-readiness drafts, og:image, dormant consent+analytics, ADR-0013; us-ch founder approval, ADR-0014; go-live blocked on domain + lawyer review) > **Current focus:** USA → Switzerland (`us-ch`) **only**, until it is perfected end-to-end. > All other corridors are deferred (see DECISIONS.md **ADR-0006**). India → Germany (`in-de`)