Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); refactor(desktop): enforce a metadata-free renderer startup boundary by Colafornia · Pull Request #2176 · apache/maka · GitHub
Skip to content

refactor(desktop): enforce a metadata-free renderer startup boundary - #2176

Merged
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen
Aug 6, 2026
Merged

refactor(desktop): enforce a metadata-free renderer startup boundary#2176
Astro-Han merged 2 commits into
apache:mainfrom
Colafornia:perf/model-metadata-firstscreen

Conversation

@Colafornia

@ColaforniaColafornia commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep full model metadata behind the main-process and lazy Settings boundaries
  • reuse onboarding:getSnapshot to project only first-screen model choices, thinking levels, provider labels, and session send outcomes
  • remove provider registry, model catalog, model thinking, and generated metadata from the renderer startup graph without adding another IPC channel
  • align the session health notice with the main-process send projection and self-heal legacy connection locks at the storage summary boundary

Closes#2063
Relates to #2084

 sequenceDiagram
participant R as Renderer Main Thread
participant IPC as IPC Bridge
participant M as Main Process
participant MM as model-metadata 520KB
Note over R,MM: BEFORE
R->>MM: parse + eval 520 KB (5 import paths)
Note right of R: BLOCKED — not needed for first screen
R->>R: build choices / thinking / menu / display / hero
R->>IPC: hasSecret per connection
IPC-->>R: secret presence
R->>R: re-derive projection
Note over R: first screen ready
Note over R,MM: AFTER
M->>MM: parse 520 KB (already loaded)
M->>M: buildChatModelChoices + projectSessionSendOutcome
M->>IPC: onboarding:getSnapshot (existing channel)
IPC-->>R: chatModelChoices + sessionSendOutcomes
R->>R: render first screen (snapshot + local + constant)
Note over R: no metadata on main thread
Note over M: SettingsModal lazy-loads on user click
Loading

Measured result

MetricBaselineOptimizedChange
Static startup JS1,951,976 B1,339,905 B-31.4%
Startup metadata-name matches2660-100%
Fresh-V8 startup-module read + parse median25.35 ms18.59 ms-26.7%
Cold-start median to mounted AppFrame1,045.6 ms1,049.0 ms+0.3%
Chromium ScriptDuration median433.0 ms432.5 ms-0.1%

The artifact and isolated parse cost improved materially. End-to-end cold start and Chromium script duration were unchanged within run-to-run noise, so this PR does not claim a user-visible wall-clock startup improvement.

Architecture boundary

The main process remains the metadata authority. The renderer startup path consumes a lightweight projection; full catalog data remains available only to main-process code and lazy-loaded Settings paths. Explicit core subpaths make that boundary independent of barrel reachability, with sideEffects: false and tree-shaking as a second defense.

FIRST_RUN_PROVIDER_TYPES is intentionally a metadata-free product constant. A contract test keeps it aligned with the first four recommended providers at test time rather than reintroducing a runtime registry dependency.

Review follow-up

  • enforce the real Vite startup chunk closure and metadata markers in a build-backed contract test
  • pin the complete renderer snapshot projection and every physical session outcome
  • keep first-run providers aligned with the recommended provider order
  • lock sessions in the message append transaction and migrate legacy unlocked user sessions once in schema v22; read paths remain pure
  • document conservative credential-read failures and event-triggered snapshot timing; remove the dead connection revision
  • preserve the existing Codex empty-inventory fallback, which remains covered by its legacy compatibility test

Verification

  • npm --workspace @maka/desktop run typecheck — passed
  • npm --workspace @maka/desktop test — 1,751 passed
  • npm --workspace @maka/storage test — passed
  • targeted UI contract tests — 12 passed
  • npm --workspace @maka/desktop run build:renderer — passed, including third-party notice verification
  • git diff --check — passed

@Colafornia
Colafornia marked this pull request as draft August 4, 2026 15:57
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 3 times, most recently from d197de3 to 2fcb7e0CompareAugust 4, 2026 17:00
@Colafornia
Colafornia marked this pull request as ready for review August 4, 2026 17:08
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for this — I verified the headline claims by rebuilding both trees: the startup JS drops ~32% (1,974KB → 1,339KB on my fresh build), the metadata-name markers go from 266 matches to 0 across all 27 startup chunks, EmptyState shrinks 812KB → 135KB, and the boundary is real (all five metadata import paths are cut; what remains sits behind the lazy SettingsModal). The moved computations check out line-by-line against the pre-PR versions — same filters, ordering, labels, and OAuth redaction — and the honest framing ("no user-visible wall-clock improvement claimed") is appreciated. Three things to handle before merge, none questioning the design:

Merge blocker — the branch conflicts with main on general-settings-page.tsx (main's #2216 reformatted it). Resolution is mechanical (re-apply the buildChatModelChoices swap on main's version), just needs a rebase.

P2 — the claimed contract test for the startup boundary doesn't exist. The PR body says "A contract test keeps it aligned with the first four recommended providers at test time", but provider-firstscreen-contract.test.ts only asserts the providerDisplay fallback for an unknown type — it doesn't scan the startup graph or the built chunks. Your own docs/model-metadata-firstscreen-optimization.md lists "startup chunks contain zero metadata markers" as an acceptance criterion, and nothing enforces it: a later refactor re-importing the metadata into any startup-reachable module ships green, silently returning the 520KB to the first screen — the exact regression this PR exists to prevent. The repo already has the pattern (dependency-boundary.test.ts import-closure assertions, or a chunk-marker grep in CI) — worth adding, since the perf claim is otherwise unverifiable.

P2 — the snapshot payload has no runtime contract pin. The renderer consumes chatModelChoices (8 fields) and sessionSendOutcomes[sessionId] with only two spot checks in onboarding-service.test.ts; thinkingLevels dropping off the wire, outcomes keyed by the wrong id, or a session missing from the map all pass CI while the UI silently loses thinking chips or the health notice. A deepEqual of one real snapshot's full shape plus a "every session has an outcome" assertion would pin it.

P3 (optional): the FIRST_RUN_PROVIDER_TYPES constant duplicates RECOMMENDED_PROVIDER_TYPES.slice(0,4) with no correspondence test (same "claimed contract" gap); the list() self-heal is a write in a read path whose cost scales with unhealed sessions (assistant-only previews never heal and pay a full message read forever); the health notice now lags one snapshot pull (deliberate, worth a comment); the codex zero-entry retry and the hasSecret error semantics are deliberate behavior changes worth a sentence each in the body; connectionsRevision is now dead state with a stale comment.

The design and the refactor itself are sound — happy to approve once rebased and the boundary test lands (or is explicitly deferred).

@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch 2 times, most recently from cd30b8c to 59be1c6CompareAugust 6, 2026 02:48
Keep full model metadata behind the main-process and lazy-settings boundaries, and project only first-screen data through onboarding snapshots.
Refs apache#2063
Relates to apache#2084
Lock sessions when user messages are appended and migrate legacy unlocked sessions once, keeping read paths pure.
@Colafornia
Colaforniaforce-pushed the perf/model-metadata-firstscreen branch from 59be1c6 to 30c68c9CompareAugust 6, 2026 06:18
@Astro-Han

Copy link
Copy Markdown
Contributor

Thanks for the follow-up — both P2s are closed with verified enforcement, and I confirmed by mutation rather than inference:

  • Boundary contract test: the new provider-firstscreen-contract.test.ts runs a real Vite build and BFS-walks the startup chunk graph — I injected import { lookupModelMetadata } with a real call into a startup-reachable module and the test fails, listing the exact modules (model-metadata.generated.js, model-metadata.js). A static re-import can no longer ship green; the FIRST_RUN_PROVIDER_TYPES correspondence is pinned too (order, not just membership).
  • Snapshot contract: the onboarding test deep-equals the complete chatModelChoices[0] (all 8 fields incl. providerLabel, connectionName, isDefault, thinkingLevels) and both sessions' sessionSendOutcomes, plus the Object.keys(sessionSendOutcomes) ≡ session ids invariant.
  • The storage change is safe: the migration is pure SQL (v22, gated on connectionLocked = 0 AND EXISTS(user message)), atomic + idempotent in the version-bumped transaction; the append-time lock lives inside the one and only INSERT INTO session_messages site, so no bypass path exists; read paths are now genuinely pure (the self-heal is gone entirely); new sessions are born unlocked and lock on first user append; rename/archive/hasSecret are unaffected; runtime-host converges to the same state a few ms earlier. The renamed storage test fails on the pre-commit head (pins the eager lock) and the migration test is real (downgrades to v21, reopens, asserts the WHERE semantics). The rebase is clean — 10/11 jointly-touched files are byte-identical to a 3-way merge and the general-settings-page.tsx resolution keeps both sides (main's feat(desktop): complete Runtime Host opt-in parity #2216 reformatting + the buildChatModelChoices swap, zero remaining callers of the old function).

Five optional notes, none blocking:

  • Docs acceptance criterion 2 (model-catalog-choices.ts / chat-model-selection.ts statically absent) is only enforced transitively today (those modules import a forbidden one); adding both names to FORBIDDEN_STARTUP_MODULES would pin it directly.
  • A dynamic import() executed at mount from a startup-reachable module would ship green — inherent to the static-BFS mechanism; a doc sentence noting the boundary is static-only would keep expectations honest.
  • apps/desktop/e2e/session-health-notice.spec.ts:9 still describes the old read-path self-heal; the behavior is identical but the comment describes removed code.
  • No negative test for the eager lock (assistant-only append must not lock) — the old test had the same blind spot, so nothing was weakened, but a regression to "lock on any append" would currently pass.
  • Interaction with fix(storage): import legacy JSONL session transcripts into SQLite (#2260) #2263 (still open): its importer restores connectionLockedafter appending messages, so an imported session with connectionLocked: false + user messages would stay unlocked (the migration only covers pre-upgrade rows) — worth re-checking the restore order there before that PR lands.

Merging now — the boundary finally has teeth.

@Astro-Han
Astro-Han merged commit c1ee5c0 into apache:mainAug 6, 2026
12 checks passed
@Colafornia
Colafornia deleted the perf/model-metadata-firstscreen branch August 13, 2026 06:51
Sign up for freeto 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.

perf(desktop): remove models.dev metadata from the renderer startup path

2 participants

@Colafornia@Astro-Han