Skip to main content

RFC Review: Centralized Web Session — Launchpad FE Integration

Executive Summary

Addendum (2026-07-02, latest review): This review scored the RFC's SDK contract (D5/D6, CNT, DEP) as validated but pending — treating "npm vs CDN" and the _mekari_account-based server_down predicate as open alternatives rather than checking them against the real SDK (mekari-account-web-sdk v0.3.0, session.ts/README.md). Neither the RFC nor this review consulted the SDK source. Both alternatives were wrong: the SDK is a bundled git dependency (no CDN ever existed) and it owns the server_down fallback (msli) internally, so no consumer predicate is possible or needed. A wrong SDK contract validated as a strength (see "Best dimension of the RFC" and the CNT row, below) is a correctness blocker, not a pending dependency — this addendum re-rates accordingly. Scores, verdicts, and the priority-action list below have been updated in place; struck-through content marks what the latest review reconciliation removed.

  • Overall Score: 7.0/10 (was 6.5/10 — see addendum)
  • Rating: Needs Work
  • RFC Type: frontend
  • Sub-Type: new-feature
  • Assessment Confidence: Medium
  • Applied Caps/Gates: None triggered as hard caps. NFS=4.0 (no quantified non-functionals) is the lone sub-5.0 category. Previously 3 critical open questions (Q1, Q2, Q3) were treated as blocking chunks 2/4/6; Q1 and Q2 are now RESOLVED by real-SDK verification (they were never genuinely open — the RFC's contract was simply wrong). Only Q3 (current-company endpoint, a genuine cross-layer BE dependency) still blocks.
  • Implementation Readiness Verdict: HOLD — Q3 (current-company endpoint) blocks agentic execution of chunk 4. Q1 (SDK distribution) and Q2 (server_down predicate) are RESOLVED — they were correctness errors in the RFC's SDK contract, not pending decisions; see latest review.
  • Report Path: /Users/mekari/Documents/qontak-launchpad-fe/rfc-review-report.md
  • RFC Author: Account & Launchpad team | Reviewed: 2026-06-28 | Re-rated: 2026-07-02 (latest review)

This RFC is unusually well-grounded for agentic execution on its closed parts: it cites real files with line numbers (authenticated.global.ts:80, useToggleQontakOne.ts:11, SwitchAccountContent.vue:117), names every file to create/modify, supplies a reading order, four ADRs, and (post-correction) a 6-chunk execution plan with per-chunk acceptance criteria. The biggest gap is that three explicitly-flagged critical decisions remain open and they gate the SDK loader, the current-company sync, and the server_down fallback — roughly half the feature. Corrected: two of those three "critical decisions" were never real decisions — they were fabricated SDK contract details (@mekari/sdk npm-vs-CDN; an _mekari_account-based server_down predicate) that the real SDK, mekari-account-web-sdk v0.3.0, simply does not have. Only current-company endpoint ownership (Q3) remains a genuine open cross-layer dependency. The one thing that must still change before full agentic execution: close Q3 with a concrete host/schema/failure contract. The now-deleted switch_user chunk (~2.5 FE days) is removed entirely — the real SDK has no such event; an account switch surfaces as logged_out.


Quick Verdict

Why this RFC can be implemented agentically:

  • Every file is named with grounding line numbers; reading order + patterns-to-follow tables remove codebase guessing (§2.0).
  • Chunks 1 (toggle), 3 (logged_out, now also covering account switches), 6 (middleware) reuse existing builders (authenticated.global.ts:80, clearTokenLaunchpad, resetAuth) and have verifiable acceptance criteria. (The former chunk 5, switch_user re-auth + toast, is deleted — no such SDK event exists.)

Why this RFC will cause agent guessing or rework:

  • Q1/Q2/Q3 are critical and unresolved — chunks 2, 4, 6 are explicitly "blocked". Corrected: only Q3 (current-company endpoint) is a genuine blocker (chunk 4). Q1 (SDK distribution) and Q2 (server_down predicate) are resolved by consulting the real SDK — an agent would not have had to invent the import path or a fallback predicate; those were review/RFC gaps, not RFC-external unknowns.
  • No error-message catalog and no quantified non-functionals — agent would ship without perf/a11y targets. (The "account changed" toast copy gap no longer applies — that toast is deleted along with switch_user.)

PRD → RFC Traceability Matrix

PRD is a Confluence link (not fetchable in this review); scored against the RFC's own §1.A coverage table, which is bidirectional and explicit.

Standard format (PRD exists)

PRD ElementRFC SectionCoverage
Overview / known issues§1.0, §1.1Full
Success Criteria (FE portion)§1.1, §2.xFull
Out of Scope§1.2Full
Dependencies (SDK, service, Redis)§2.1 (upstream, read-only)Full (referenced as upstream contracts)
Technical Design — Proposal§2.2–§2.6Full (FE portion)
SDK contract / events§2.3Full
FE Product Integration Flows§2.4–§2.6Full
Web Session Flow§2.5n/a — Launchpad uses OAuth2 authz-code, not Rails web session (justified)
OAuth2 Authorization Code Flow§2.5, ADR-1Full
User Logout From Product§2.6Full
User Switch Account§2.3/§2.4 (surfaces as logged_out, no dedicated event)Full — corrected: the real SDK has no switch_user event; an account switch runs the normal logged_out sign-out flow, so the "account changed" toast requirement and its missing copy/i18n gap no longer apply (latest review)
Database Modeln/a — no DB (FE)
HA & Security§3Partial — FE subset; perf/a11y not quantified
Rollout Plan§4Full (Launchpad = step 4)
Open Questions§5Full (7 questions, severity-tagged)

Summary: ~13 of 14 PRD elements fully covered (was 12; the "User Switch Account" row moved from Partial to Full once the fictional switch_user toast requirement was corrected away — latest review), 1 partial (non-functionals), 0 missing. No RFC decisions lack PRD justification. PRT = 8.0 (unchanged — the correction did not add or remove PRD coverage, it fixed a wrong toast requirement).


Scorecard

Frontend Scorecard (11 categories)

CategoryScoreEvidence-Based Rationale
PRT — PRD Traceability8.0§1.A coverage table is bidirectional and marks n/a items with justification (e.g. "Web Session Flow → Launchpad uses OAuth2"). PRD not fetchable, capping confidence.
TDC — Technical Decisions7.5 (was 6.0)D1, D2, D4 resolved as full ADRs with options + rationale. D3 partial (source unresolved, Q4). D5 and D6 are now Resolved, not dangling — real-SDK verification shows mekari-account-web-sdk is a bundled git dependency (no npm-vs-CDN decision to make) and the server_down fallback is SDK-internal (no FE predicate to define). D7 (current-company) remains genuinely Dangling. latest review.
CNT — Contract Specificity7.0 (was 6.5)SDK contract specified (new Session({current_user}), .on, .refresh; §2.1). Corrected: that contract was wrong on every point — real constructor option is currentUser (camelCase), the only valid event name is the literal "event" with a single-arg callback, and there is no .refresh(). The RFC (post-correction) now matches the real SDK. State Surface Contract table present (§2.3). /users/me/current_company still has no request/response schema; msli is no longer FE-surfaced at all (it's SDK-internal, R7), which removes the earlier "loosely specified" msli format complaint entirely.
SCB — Scope Boundaries8.5Repo Map + Existing Code Anchors + every new/modified file named (§2.0); non-goals explicit (§1.2). Agent can produce file-by-file plan from RFC alone.
DEP — Dependencies7.5 (was 6.5)Deps named with status: mekari-account-web-sdk "NOT installed" — now correctly resolved to a git-dependency install (Q1, no longer blocked); current-company host still unresolved (Q3, genuinely blocked); toggle new. Only one key dependency remains blocked, down from two.
FMC — Failure Mode Coverage6.5 (was 5.5)All 3 real events (logged_in, logged_out, server_down) have a reaction; hard client-side timeout noted (§3.1). server_down predicate is broken (Q2)corrected: server_down is now specified as fail-open per PRD 6.10 (no predicate needed, no consumer msli to evaluate). Still missing: an error-message catalog, current_company fetch-failure definition. Cap "FMC<7.0 needs error catalog" still applies — held below 7.
NFS — Non-Functional Specificity4.0Security/OWASP present (§3.2) and good. But no LCP/INP/CLS/bundle budget, no a11y spec, no browser matrix, no i18n. Service-side RPS deferred upstream (correct), FE targets absent.
TPS — Test Plan Specificity7.0Each chunk (§4.C) has a pnpm run test -- <spec> command + "red first" + concrete accept criteria (e.g. "toggle off → returns false"). Missing: enumerated failure-path tests per story.
ROL — Rollout & Rollback7.0Toggle-gated; rollout stages (§4.E) with go/no-go evidence; rollback recipe = flip toggle (§4.D); verification commands (§4.B). Config contract incomplete — toggle source/env name unresolved (Q4).
OBS — Observability5.5server_down fallback counter proposed; console.error/warn + useErrorHandler routing (§3.3). But telemetry sink [REQUIRED], no metric/dashboard names finalized.
CPA — Pattern Alignment8.5Patterns-to-Follow table maps each concern to a reference file (Pinia setup store, useToggleQontakOne:11, useClient:43, toast.notify:117). Reuses existing redirect/sign-out builders; introduces only new composables.

Decision Closure Assessment

Decision Index

#DecisionStatusCritical Gaps
D1Auth model = OAuth2 authz-codeResolved
D2SDK load = *.client.ts pluginResolved
D3Toggle = mirror useToggleQontakOnePartialtoggle source (env vs backend) unresolved — Q4
D4Event wiring = plugin→composable→mw/storeResolvedtouches shared middleware (medium reversibility)
D5SDK distributionResolved (was Dangling)none — bundled git dependency (mekari-account-web-sdk v0.3.0), no CDN alternative ever existed. latest review/Q1.
D6server_down fallbackResolved (was Dangling)none — the SDK owns the msli fallback internally; no consumer predicate exists to define. latest review/Q2.
D7Current-company endpoint host/schemaDanglinghost/owner unknown, no schema — Q3 (genuine, unaffected by the SDK correction)

Aggregate: 5 Resolved, 1 Partial, 1 Dangling (of 7) — was 3 Resolved, 1 Partial, 3 Dangling; D5/D6 moved to Resolved via real-SDK verification (latest review).


Decision: D1 — Auth model variant: OAuth2 Authorization Code

Status: Resolved

What was decided

"(b) OAuth2 authz-code flow with bearer tokens." (ADR-1, §2.3.1)

Alternatives considered

(a) web-session + client_credentials + Rails cookie — rejected: "no Rails session in this SPA." Grounded in ssoCallbackStore.ts:53 grantType: authorization_code.

Grounding in existing code

ssoCallbackStore.ts:53, global_sso_* cookies (useAuthCookies.ts:5-7). Fully grounded.

Interface specification

Variant isolates event handlers to token-revocation semantics. Sufficient.

Failure handling

Specified downstream in §2.4 handlers.

Challenge results

  • Scale: N/A (per-user auth).
  • Reversibility: High — "variant isolated to event handlers."
  • Consistency: Consistent with D2/D4.
  • Agent implementability: Yes.

Gaps and suggestions

None. Strong ADR.


Decision: D2 — SDK load location: client plugin

Status: Resolved

What was decided

"(b) app/plugins/mekariSession.client.ts." (ADR-2)

Alternatives considered

(a) app.vue useHead, (c) per-page import — rejected for single-init + browser-context guarantee. Grounded in plugins/auth.ts.

Interface specification

Init must be idempotent + toggle-gated (stated consequence).

Failure handling

Idempotency required but idempotency mechanism not specified (how is double-init prevented?). Update (latest review, R11): the real SDK is itself a singleton — a second new Session() call anywhere returns the first instance and silently ignores new options. This makes a bespoke idempotency guard largely unnecessary for preventing duplicate Session construction; the remaining concern is narrower — ensure session.destroy() (not just off()) is called before any re-init (e.g. on toggle flip), since off() alone leaves the iframe + window listener attached.

Challenge results

  • Reversibility: High — delete plugin / flip toggle.
  • Consistency: Consistent.
  • Agent implementability: Yes (was "Mostly") — the SDK's own singleton behavior removes most of the guesswork; the agent only needs to call destroy() on teardown, not invent a module-level guard from scratch.

Gaps and suggestions

Missing (reduced scope, latest review): explicit session.destroy() call on teardown/toggle-flip; the module-singleton guard against duplicate construction is no longer needed since the SDK enforces it. Open questions: none blocking.


Decision: D3 — Toggle mechanism

Status: Partial

What was decided

Mirror useToggleQontakOne TOGGLE_SOURCE switch; "default source unresolved — Q4 (env var preferred)." (ADR-3)

Alternatives considered

(a) hardcoded const, (b) runtimeConfig env var, (c) backend per-company — all listed; final source not picked.

Grounding in existing code

useToggleQontakOne.ts:11. Grounded.

Interface specification

Incomplete: env var name, type, default value not given (config contract gap).

Failure handling

Toggle off → no side effects (testable). Adequate.

Challenge results

  • Reversibility: High.
  • Agent implementability: Partial — agent must guess env var name + default.

Gaps and suggestions

Missing: env var name + default; whether pilot uses env or backend. Suggested resolution: pilot uses runtimeConfig.public.CENTRALIZED_SESSION (boolean, default false), mirroring existing public config keys in nuxt.config.ts. Flip to backend at PRD step 5. Open questions: Q4 — confirm source + key name with AL.


Decision: D4 — Event wiring point

Status: Resolved

What was decided

"(b) Plugin forwards events to useCentralizedSession; middleware awaits initial resolution; store actions perform token/company changes." (ADR-4)

Grounding in existing code

authenticated.global.ts single gate. Grounded.

Interface specification

Middleware gains toggle-gated await with timeout (§3.1). Timeout value not numerically specified.

Failure handling

Slow /current → falls to server_down, which (post-correction, D6) is now a well-defined fail-open path with no broken predicate.

Challenge results

  • Reversibility: Medium — "touches the shared middleware" (regression surface).
  • Consistency: Consistent.
  • Agent implementability: Mostly — agent must pick the timeout number.

Gaps and suggestions

Missing: concrete await timeout (ms). Suggested resolution: 3000ms client-side timeout → emit synthetic server_down; assert existing authenticated.global.spec stays green when toggle off. Open questions: none blocking.


Decision: D5 — SDK distribution

Status: Resolved (was Dangling — corrected 2026-07-02, latest review)

What was decided

NOT DECIDED — "unresolved — see Open Question Q1." Two upstream contracts both listed (§2.1): npm @mekari/sdk and CDN https://account.mekari.com/sm/sdk.js. Corrected: there was never a real "npm vs CDN" decision to make — no CDN for this SDK has ever existed. The real package is mekari-account-web-sdk v0.3.0, installed as a bundled git dependency (npm install git+https://<user>:<pass>@bitbucket.org/mid-kelola-indonesia/mekari-account-web-sdk#<version>) and imported via import { Session } from "mekari-account-web-sdk". This finding came from reading the real SDK's README.md/src/index.ts (latest review), which neither the original RFC nor this review consulted.

Alternatives considered

Both named, neither rejected. Corrected: there was no genuine alternative; "CDN" was a fabricated option.

Grounding in existing code

package.jsonmekari-account-web-sdk absent (§2.0.1), to be added via the git-dependency install above.

Interface specification

SDK shape verified against real source (session.ts): new Session({ currentUser, sessionUrl?, interval?, checkTimeout?, includeSessionId? }), session.on("event", (data) => {}), session.off(), session.destroy() — no .refresh().

Failure handling

No CDN script-load path exists or is needed — the SDK is bundled at build time. server_down (SDK-internal fallback exhausted) is the only runtime failure mode; see D6.

Challenge results

  • Reversibility: N/A — single supported distribution mechanism, not a reversible choice.
  • Agent implementability: Yes (was "No") — the import path is now fully specified.

Gaps and suggestions

None remaining. The original review's "prefer npm, CDN as fallback" suggestion is now moot and removed — the fallback branch it recommended was never real. Open questions: none — Q1 resolved.


Decision: D6 — server_down fallback predicate

Status: Resolved (was Dangling — corrected 2026-07-02, latest review)

What was decided

Predicate: "msli < 2h AND _mekari_account valid" — but RFC itself marks the second clause "[UNREADABLE cross-domain — Q2]" in the failure sequence diagram (§2.4). Corrected: there is no consumer-side predicate to define. The real SDK owns the msli localStorage key (2h expiry) internally — it sets it on logged_in, clears it on logged_out, and uses it itself to decide whether a checkTimeout lapse should emit logged_in (fresh msli) or server_down (stale/absent). Launchpad only ever receives the final logged_in/logged_out/server_down status; it must NOT read or write the msli key itself (doing so would collide with the SDK's own bookkeeping and corrupt its fallback — R7). On server_down, the product-level contract is simply fail-open per PRD 6.10: take no destructive action, do not force sign-out.

Alternatives considered

None needed — there is nothing left for a consumer predicate to decide.

Grounding in existing code

useAuthCookies.ts has no _mekari_account (§2.0.1, §3.2 — the old A01 finding is now moot, since the premise that Launchpad needed to read it was itself wrong). Real SDK: session.tsmsli read/write confined to SDK internals.

Interface specification

server_down is a terminal, fully-specified status: FE fail-open, log/observe only.

Failure handling

No longer "the failure-handling path itself unimplementable" — it is now a one-line no-op-plus-log branch.

Challenge results

  • Scale: N/A.
  • Reversibility: High — fail-open is a single, easily-reversible branch.
  • Consistency: No longer conflicts with anything — the removed _mekari_account premise was the source of the prior contradiction.
  • Agent implementability: Yes (was "No") — an agent can implement fail-open trivially; there is no predicate to invent.

Gaps and suggestions

None remaining. The original review's suggested resolution — now - msli < 2h && global_sso_valid_until > now, i.e. a consumer-side msli read/write — is itself now known to be WRONG and must NOT be implemented: the SDK owns the msli key, and a consumer localStorage.setItem("msli", …) would collide with and corrupt the SDK's own fallback bookkeeping. This suggestion is struck from the priority-action list below. Open questions: none — Q2 resolved.


Decision: D7 — Current-company endpoint host/schema

Status: Dangling

What was decided

New useCurrentCompany.ts calls /users/me/current_company via useClient, but "endpoint owner/host is an Open Question (Q3) — do not hardcode api.mekari.com." (§2.5)

Alternatives considered

Kong route vs BE proxy vs direct api.mekari.com — listed, unresolved.

Grounding in existing code

grep current_company → no matches (§2.0.1). Existing profile via authStore.ts:81 (/users/me) through Kong.

Interface specification

Missing: host, CORS/Kong routing, response schema (company id/name/fields).

Failure handling

Fetch failure (CORS reject, 4xx/5xx) behavior undefined.

Challenge results

  • Reversibility: Medium.
  • Agent implementability: No — agent must guess host and response shape; per RFC's own warning, hardcoding api.mekari.com is wrong.

Gaps and suggestions

Missing: host, schema, failure behavior. Suggested resolution: route through existing Kong base (apiBaseUrl, as authStore.ts:81 does) via a Launchpad BE proxy; define response { data: { current_company: { id, name } } } read at data.value.data per repo convention; on failure route through useErrorHandler and keep prior company. Open questions: Q3 — Launchpad BE to own/confirm host + schema.


UI State Audit

5 states per data-driven surface.

SurfaceLoadingEmptyErrorPartialSuccessAssessment
Session gate (middleware await)partial (await + timeout, no spinner spec — §1.3 marked [REQUIRED])n/adefined (→server_down, fail-open)n/adefined (allow nav)2.5/5
Current-company fetchmissingmissing (no company?)missingmissingdefined (set on store)1/5

Removed: the "Account changed" toast row — the real SDK has no switch_user event, so this surface no longer exists (latest review, R5).

Summary: 0 of 2 remaining surfaces have all states (was 0 of 3). Loading visual is [REQUIRED] (open); current-company fetch states entirely absent — agent will build happy-path only.


Performance Budget Check

MetricTargetCurrent BaselineSourceAssessment
LCPnot statednot statedmissing
INPnot statednot statedmissing
CLSnot statednot statedmissing
Bundle size delta (SDK)not statednot statedmissing — distribution is now known (git dependency, Q1 resolved), but the delta itself is still unmeasured
Middleware await timeout"hard client-side timeout" (§3.1), no numberRFC prosevague

NO QUANTIFIED PERFORMANCE BUDGET — agent cannot optimize against targets; SDK bundle delta unmeasured (distribution mechanism is resolved, Q1, but no size measurement exists yet).


Accessibility Review

AspectSpecified?DetailsAssessment
Keyboard navigation flownomissing
Focus managementnoloading-gate focus undefined (the "account changed" toast surface no longer exists — R5)missing
ARIA labelsnomissing
Heading hierarchynomissing
Color contrastn/ano toast surface remains in scope (removed with switch_user, R5)n/a
Motion sensitivitynomissing
Screen reader behaviorn/ano toast surface remains in scopen/a

A11y is largely unaddressed for the one remaining FE-visible surface (the loading gate, [REQUIRED] — no focus/announce spec). The "account changed" toast that previously anchored several rows here is removed: its trigger (switch_user) does not exist in the real SDK (R5).


Pattern Alignment Check

PatternRFC ApproachAssessment
State management (Pinia setup store)follows (authStore.ts)strong
Feature toggleextends (useToggleQontakOne.ts:11)strong — but source unresolved (Q4)
API call (useClient)follows (useClient.ts:43, body at data.value.data)strong
Auth cookiesreuse (useAuthCookies.ts)strong
SSO re-auth / sign-out redirectreuse (authenticated.global.ts:80, SwitchAccountContent.vue:117)strong
Toast notification@mekari/pixel3 toast.notify (authStore.ts:117) remains available as a patternn/a for this RFC — its only proposed trigger (switch_user) does not exist in the real SDK, so no toast is wired by this feature (R5)
Error normalizefollows (useErrorHandler)strong (per AGENTS.md)

Best dimension of the RFC — no parallel systems introduced; new composables only.


Agentic Readiness Deep-Dive

Vague Word Audit

#Word/PhraseLocationImpactConcrete Replacement
1"hard client-side timeout"§3.1agent guesses ms"3000ms then synthetic server_down"
2"non-blocking when toggle off"§3.1OK but unverifiedassert existing middleware spec green with toggle off
3"account changed" toast (no exact copy)§2.4, §1.3removed — no longer applicable: the toast and its switch_user trigger do not exist in the real SDK (R5)n/a
4"msli=now"§2.3removed — no longer applicable: msli is SDK-internal; Launchpad never writes it (R7)n/a
5"idempotent" initADR-2narrowed impact — the SDK's own singleton behavior (R11) covers duplicate-construction; only session.destroy() on teardown is still unstatedexplicit session.destroy() call on toggle-flip/unmount

Total vague words in spec sections: 2 (was 5 — two items were struck because they described features that don't exist in the real SDK, one narrowed by the SDK's singleton behavior)

Dangling Alternatives

#AlternativesLocationImpact
1npm vs CDN SDK§1.B D5 / §2.1 / Q1resolved — no CDN exists; bundled git dependency (latest review)
2env var vs backend toggle sourceADR-3 / Q4agent guesses config key/default
3Kong vs api.mekari.com vs BE proxy§2.5 / Q3agent guesses host (chunk 4)
4/sm/current vs /sessionmanager/current§2.1 / Q5resolved — https://sm.mekari.com/current (SDK's sessionUrl default, latest review)

Total dangling alternatives: 2 (was 4 — #1 and #4 resolved by real-SDK verification, not by a product decision)

Task Decomposition Assessment

ChunkAcceptance CriteriaAssessment
1 toggletoggle off→false, on→true; red firstverifiable (blocked Q4 for source)
2 SDK loadernew Session({currentUser}) with launchpad.sso_id (mock)verifiable — not blocked (Q1, Q5 resolved)
3 logged_outclearTokenLaunchpad+resetAuth+sign_out redirect; also fires for account switches (R5)verifiable
4 logged_in+companycompany fetched/set (no msli write — that's SDK-internal, R7)verifiable but blocked Q3
5 switch_usertokens cleared→authz redirect→toast on returndeleted — no such SDK event exists (R5); ~2.5 FE days removed from scope
5 server_down (renumbered from 6)fail-open (PRD 6.10): no destructive action, log/observe onlyverifiable — not blocked (Q2 resolved; no predicate to build)
6 middleware (renumbered from 7)toggle on→await+timeout; off→specs greenverifiable; timeout number missing

Order is sound (toggle→loader→handlers→middleware). 1 of 6 chunks blocked (was 3 of 7) — only chunk 4 (current-company) remains blocked, on Q3.


Strengths

  • Scope grounding (§2.0, SCB 8.5): Repo Map + Existing Code Anchors + Reading Order with real line numbers (authenticated.global.ts:80, useToggleQontakOne.ts:11) — agent skips codebase discovery entirely.
  • Pattern alignment (§2.0 Patterns-to-Follow, CPA 8.5): every concern mapped to a reference file; reuses existing redirect/sign-out builders; introduces only new composables — generated code will look native. (The toast-notification pattern was previously listed here too, but its only proposed trigger, switch_user, does not exist in the real SDK — R5 — so it is no longer part of this RFC's scope.)
  • Honest decision tracking (§1.B, §5, §7): ADR index, severity-tagged open questions, and a Ready: no gate. Two of the three originally-cited blockers (Q1, Q2) turned out to be correctness errors in a fabricated SDK contract rather than genuine open decisions — the gate should have needed only Q3 all along, once the real SDK is consulted. Source Verification table (§2.0.1) backs claims with greps, but did not extend to the SDK's own source, which is what let the wrong Q1/Q2 framing stand.

Biggest Gaps

  • Three critical dangling decisions (Q1/D5, Q2/D6, Q3/D7): block chunks 2, 4, 6corrected: only one genuine dangling decision remains, Q3/D7 (current-company endpoint), blocking chunk 4. Q1/D5 and Q2/D6 were not real product decisions — the real SDK is a bundled git dependency (no CDN choice) and owns its server_down fallback internally (no predicate to define). The original review's belief that D6 was "a logic contradiction" was correct in diagnosis but wrong in remedy — the fix is not a redefined predicate, it's removing the predicate concept entirely.
  • No error-message catalog + no current_company schema (CNT 7.0, FMC 6.5 — both improved from 6.5/5.5): toast copy/i18n gap no longer applies (toast removed with switch_user, R5); current_company still has no response shape or fetch-failure behavior — agent still invents this part.
  • No quantified non-functionals (NFS 4.0, unchanged): no LCP/INP/CLS/bundle budget, no a11y spec, no browser matrix, no timeout number — agent ships unmeasured. Unaffected by the SDK correction.

Priority Actions

Do these before handing to an AI agent.

  1. Q1 / D5 (SDK distribution) — pick npm @mekari/sdk ... or CDN ... RESOLVED (latest review): mekari-account-web-sdk v0.3.0, bundled git dependency; no action needed.
  2. Q2 / D6 (server_down predicate) — redefine FE-readable: now - msli < 2h && global_sso_valid_until > now (drop _mekari_account). RESOLVED (latest review) — and the suggested predicate above must NOT be built: the SDK owns msli internally; a consumer write to that key collides with and corrupts the SDK's own fallback bookkeeping. Implement server_down as fail-open (PRD 6.10) instead.
  3. Q3 / D7 (current-company endpoint) — name host (prefer Kong apiBaseUrl proxy as authStore.ts:81), give request/response schema (read at data.value.data), and fetch-failure behavior via useErrorHandler. Unblocks chunk 4. Still open.
  4. Non-functionals — add the middleware await timeout (ms) and minimal perf/a11y targets (SDK bundle delta, loading-gate focus/announce spec). Lifts NFS above gate. (The former "toast i18n key" item is removed — no toast remains in scope.)

Implementation Readiness Checklist

Unblocked (agent can proceed)

All types:

  • PRD → RFC traceability matrix complete (§1.A)
  • All technical decisions resolved (1 dangling: D7 — was 3: D5/D6/D7; D5/D6 resolved latest review)
  • All failure modes handled with error message catalog (no catalog; server_down is now well-defined fail-open, no longer broken)
  • Configuration contract (toggle source/env key unresolved — Q4)
  • Pattern alignment verified (§2.0)
  • Rollout plan with flag + rollback (§4.D/§4.E)
  • Observability metrics/alerts defined (sink [REQUIRED])
  • Task decomposition with acceptance criteria per chunk (§4.C)
  • Zero vague words in spec sections (2 found, was 5)

Frontend:

  • All interfaces/prop types specified (current_company schema missing)
  • All UI states defined (0/2 remaining surfaces complete, was 0/3 — toast surface removed)
  • Performance budget quantified
  • Accessibility requirements specified
  • Browser support matrix defined

Blocked (must fix first)

  • Q1 — SDK distribution mechanism (chunk 2) RESOLVED (latest review): bundled git dependency.
  • Q2 — FE-readable server_down predicate (chunk 6) RESOLVED (latest review): no predicate — SDK owns msli internally; FE fails open.
  • Q3 — current-company endpoint host + schema (chunk 4)

Verdict: Fix 1 blocker first (was "Fix 3 blockers first") — chunks 1, 2, 3, 5, 6 are agent-ready today; only chunk 4 (current-company) is blocked, on Q3.


Task Manifest

Verified against RFC §4.C; ordering retained; chunk 5 (switch_user) deleted and subsequent chunks renumbered to match the corrected RFC (latest review). Blocked chunks flagged.

OrderChunkFiles to Create/ModifyAcceptance CriteriaDependencies
1centralized_session toggleapp/common/composables/useCentralizedSessionToggle.ts + specoff→false, on→true; spec red firstQ4 (source/key)
2SDK loader pluginapp/plugins/mekariSession.client.ts + spectoggle on + launchpad.sso_idnew Session({currentUser}) (mock); off → not loadednone — Q1, Q5 resolved
3logged_out handlerapp/common/composables/useCentralizedSession.ts + specdata.status === "logged_out"clearTokenLaunchpad+resetAuth+SSO_URL/sign_out redirect; also fires for account switches (R5)Chunk 1
4logged_in + company syncapp/common/composables/useCurrentCompany.ts + spec; extend useCentralizedSession.tscompany fetched via useClient, set on store (no msli write — SDK-internal, R7)Q3, Chunk 3
5switch_user re-auth + toastextend useCentralizedSession.ts; modify authenticated.global.tsDELETED (R5) — no such SDK event exists; ~2.5 FE days removed
5 (was 6)server_down fallbackextend useCentralizedSession.ts + specdata.status === "server_down" → fail-open (PRD 6.10), log/observe onlynone — Q2 resolved, Chunk 4
6 (was 7)middleware integrationapp/middleware/authenticated.global.tson → await + timeout; off → existing specs greenChunks 1–5; timeout value

RFC specified this decomposition; reviewer confirms ordering and dependencies. Author must close Q3 before chunk 4 executes (Q1, Q2 resolved latest review; the former chunk 5 is deleted, not blocked).


Dangling Decisions Log

#DecisionLocationOwnerDeadline
1SDK distribution (npm vs CDN)§1.B D5 / §2.1 / Q1RESOLVED (latest review) — bundled git dependency, no CDN
2server_down FE-readable predicate§2.4 / §3.2 A01 / Q2RESOLVED (latest review) — SDK owns msli internally; FE fails open
3Current-company endpoint host/schema§2.5 / Q3Launchpad BEunset — genuinely open
4Toggle source (env vs backend) + key/defaultADR-3 / Q4ALunset
5Session Manager path /sm/current vs /sessionmanager/current§2.1 / Q5RESOLVED (latest review)https://sm.mekari.com/current
6CSP / SDK iframe hardening (whitelist sm.mekari.com, not account.mekari.com)§3.2 / Q6infosecunset
7 (new)SDK does not validate event.origin — upstream infosec finding, not a decision to make§3.2 A08/A07 (R9)infosec + SDK ownersunset

Open Questions

#QuestionCategorySeverity
1npm @mekari/sdk or CDN sdk.js?TDC/DEPRESOLVEDmekari-account-web-sdk v0.3.0, bundled git dependency; no CDN exists (latest review)
2FE-readable server_down predicate (drop _mekari_account)?FMCRESOLVED — no predicate; SDK owns msli internally, FE fails open per PRD 6.10 (latest review)
3Current-company endpoint host + response schema + failure behavior?CNT/DEPBlocking (unchanged — genuine cross-layer dependency)
4Toggle source + env key + default for pilot?TDC/ROLImportant
5Canonical Session Manager path?TDCRESOLVEDhttps://sm.mekari.com/current (latest review)
6Launchpad CSP vs SDK iframe; whitelist sm.mekari.com via frame-src/child-srcNFS (security)Important
7Visible loading state while SDK resolves?UI StateNice-to-have
8Exact "account changed" toast i18n key + strings?CNT/FMCREMOVED — no toast remains in scope; its trigger (switch_user) does not exist in the real SDK (R5)
9Middleware await timeout value (ms)?TDC/NFSImportant
10 (new)SDK's message listener does not validate event.origin — track as an open upstream infosec finding for the SDK owners, not a question the RFC author can answerNFS (security), OWASP A08/A07Important

Evidence Notes

  • §2.0 Repo Reading Guide + §2.0.1 Source Verification — strong evidence via repo greps (mekari-account-web-sdk absent, current_company no matches), but this table did not extend to consulting the real SDK's own source, which is what let the fabricated npm-vs-CDN and _mekari_account predicate stand as "dangling decisions" instead of being identified as wrong contract claims. latest review closed that gap by reading mekari-account-web-sdk v0.3.0's session.ts/README.md directly.
  • §1.B Decisions + §5 Open Questions — originally 3 critical dangling decisions held TDC to 6.0 and overall to 6.5; now 1 genuine dangling decision (D7/Q3) with TDC at 7.5 and overall at 7.0 (latest review).
  • §3 HA & Security — OWASP-aligned (A02/A05/A07) but no quantified FE perf/a11y → NFS 4.0 (unchanged). New: an A08/A07 finding that the SDK does not validate event.origin (R9), which no FE-side fix can address — tracked as an open upstream item, not a scoring factor for this RFC.
  • §4.C Agent Execution Plan — per-chunk test commands + accept criteria gave TPS 7.0; originally 3 of 7 chunks self-flagged blocked, now 1 of 6 (chunk 4, Q3) after chunk 5 (switch_user) was deleted and Q1/Q2 resolved.
  • Absence: error-message catalog + current_company schema + UI states — previously capped FMC at 5.5 and CNT at 6.5; now FMC 6.5 / CNT 7.0 since the server_down predicate and SDK contract are no longer broken, though the current_company schema gap persists.