You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by as...@apache.org on 2026/09/05 06:55:25 UTC

(maka) branch main updated: chore(desktop): stop pricing sanctioned imports in the renderer ratchet (#4823)

This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/maka.git


The following commit(s) were added to refs/heads/main by this push:
     new 21702c85cf chore(desktop): stop pricing sanctioned imports in the renderer ratchet (#4823)
21702c85cf is described below

commit 21702c85cf9f1387dd8792fbdb2a05f56341baf7
Author: NekoPunch <95...@users.noreply.github.com>
AuthorDate: Fri Sep 4 23:55:20 2026 -0700

    chore(desktop): stop pricing sanctioned imports in the renderer ratchet (#4823)
    
    The renderer architecture ratchet admitted a legacy file's dependency on a validated copy catalog, a shell module or a public application contract, but still counted the importDeclarations / importSpecifiers of those edges as debt. Replacing eight inlined lines with one import from application/contracts failed with "importSpecifiers debt increased", so the incentive ran backwards: copy the helper rather than import it. Copy catalogs hit the same inconsistency: validateCopyCatalog perm [...]
    
    Import debt is now computed per source and excludes the sources isSanctionedDependencyTarget already exempts for that section; a validated catalog's bare package runtime imports are exempt from closure debt, matching catalog validation. The ledger is regenerated: every changed entry is lower, so the one-way ratchet holds. Two fixture tests pin the sanctioned edge as free and a private application/sessions import as still priced.
    
    No product behavior change. Ledger entries now depend on other files' zones, so a later move into shell/ or a public surface should regenerate the ledger rather than edit counts by hand.
    
    Generated-by: Claude Code
---
 apps/desktop/renderer-architecture.json            | 60 +++++++++----------
 .../scripts/check-renderer-architecture.mjs        | 67 ++++++++++++++++------
 .../scripts/check-renderer-architecture.test.mjs   | 62 +++++++++++++++++++-
 3 files changed, 139 insertions(+), 50 deletions(-)

diff --git a/apps/desktop/renderer-architecture.json b/apps/desktop/renderer-architecture.json
index f6cd35fd2c..c4724663db 100644
--- a/apps/desktop/renderer-architecture.json
+++ b/apps/desktop/renderer-architecture.json
@@ -311,7 +311,7 @@
         "nonTriviaTokens": 92
       },
       "src/renderer/app-shell-chat-actions.ts": {
-        "importDeclarations": 9,
+        "importDeclarations": 8,
         "bridgePaths": {
           "window.maka.newTasks.create": 1,
           "window.maka.sessions.remove": 1,
@@ -337,11 +337,11 @@
           "@maka/core/session-name": 1,
           "@maka/ui": 1
         },
-        "importSpecifiers": 16,
+        "importSpecifiers": 14,
         "nonTriviaTokens": 4086
       },
       "src/renderer/app-shell-chrome-actions.tsx": {
-        "importDeclarations": 5,
+        "importDeclarations": 4,
         "bridgePaths": {},
         "environmentCapabilities": {},
         "hookCalls": {
@@ -357,11 +357,11 @@
           "@maka/ui": 1,
           "@maka/ui/icons": 1
         },
-        "importSpecifiers": 8,
+        "importSpecifiers": 7,
         "nonTriviaTokens": 408
       },
       "src/renderer/app-shell-command-actions.ts": {
-        "importDeclarations": 7,
+        "importDeclarations": 5,
         "bridgePaths": {
           "window.maka.connections.setDefault": 1,
           "window.maka.connections.test": 1,
@@ -388,11 +388,11 @@
           "./locales/shell-copy.js": 1,
           "react": 1
         },
-        "importSpecifiers": 11,
+        "importSpecifiers": 9,
         "nonTriviaTokens": 2307
       },
       "src/renderer/app-shell-context-compaction.ts": {
-        "importDeclarations": 1,
+        "importDeclarations": 0,
         "bridgePaths": {},
         "environmentCapabilities": {},
         "hookCalls": {},
@@ -402,11 +402,11 @@
         "dependencyPaths": {
           "./locales/shell-copy.js": 1
         },
-        "importSpecifiers": 1,
+        "importSpecifiers": 0,
         "nonTriviaTokens": 610
       },
       "src/renderer/app-shell-copy.ts": {
-        "importDeclarations": 2,
+        "importDeclarations": 1,
         "bridgePaths": {},
         "environmentCapabilities": {},
         "hookCalls": {},
@@ -417,7 +417,7 @@
           "./locales/shell-copy.js": 1,
           "@maka/core/redaction": 1
         },
-        "importSpecifiers": 2,
+        "importSpecifiers": 1,
         "nonTriviaTokens": 504
       },
       "src/renderer/app-shell-detail-panel.tsx": {
@@ -453,7 +453,7 @@
         "nonTriviaTokens": 666
       },
       "src/renderer/app-shell-effects.ts": {
-        "importDeclarations": 12,
+        "importDeclarations": 11,
         "bridgePaths": {
           "window.maka.app.info": 1,
           "window.maka.appWindow.subscribeCommand": 1,
@@ -502,11 +502,11 @@
           "@maka/core/session-event-health": 1,
           "react": 1
         },
-        "importSpecifiers": 20,
+        "importSpecifiers": 19,
         "nonTriviaTokens": 3816
       },
       "src/renderer/app-shell-overlays.tsx": {
-        "importDeclarations": 8,
+        "importDeclarations": 7,
         "bridgePaths": {},
         "environmentCapabilities": {
           "window": 2,
@@ -534,11 +534,11 @@
           "@maka/ui": 1,
           "react": 1
         },
-        "importSpecifiers": 12,
+        "importSpecifiers": 11,
         "nonTriviaTokens": 977
       },
       "src/renderer/app-shell-project-actions.ts": {
-        "importDeclarations": 5,
+        "importDeclarations": 4,
         "bridgePaths": {
           "window.maka.app.openPath": 4,
           "window.maka.app.resolveProjectGitInfo": 1,
@@ -564,11 +564,11 @@
           "./open-path": 1,
           "./session-workspace-errors": 1
         },
-        "importSpecifiers": 9,
+        "importSpecifiers": 7,
         "nonTriviaTokens": 2284
       },
       "src/renderer/app-shell-revision-actions.ts": {
-        "importDeclarations": 6,
+        "importDeclarations": 4,
         "bridgePaths": {
           "window.maka.sessions.abandonSessionCopy": 2,
           "window.maka.sessions.reviseBeforeTurn": 1
@@ -588,11 +588,11 @@
           "./session-workspace-errors.js": 1,
           "@maka/core/session": 1
         },
-        "importSpecifiers": 10,
+        "importSpecifiers": 8,
         "nonTriviaTokens": 2316
       },
       "src/renderer/app-shell-session-events.ts": {
-        "importDeclarations": 3,
+        "importDeclarations": 2,
         "bridgePaths": {},
         "environmentCapabilities": {
           "requestAnimationFrame": 1,
@@ -610,11 +610,11 @@
           "./model-connection-errors.js": 1,
           "@maka/ui": 1
         },
-        "importSpecifiers": 12,
+        "importSpecifiers": 11,
         "nonTriviaTokens": 2974
       },
       "src/renderer/app-shell-session-start-actions.ts": {
-        "importDeclarations": 3,
+        "importDeclarations": 2,
         "bridgePaths": {
           "window.maka.newTasks.create": 1,
           "window.maka.onboarding.setMilestone": 1
@@ -631,7 +631,7 @@
           "./model-connection-errors.js": 1,
           "./session-workspace-errors.js": 1
         },
-        "importSpecifiers": 7,
+        "importSpecifiers": 5,
         "nonTriviaTokens": 650
       },
       "src/renderer/app-shell-session-ui-state.ts": {
@@ -649,7 +649,7 @@
         "nonTriviaTokens": 7
       },
       "src/renderer/app-shell-stop-action.ts": {
-        "importDeclarations": 2,
+        "importDeclarations": 0,
         "bridgePaths": {
           "window.maka.sessions.stop": 1
         },
@@ -664,11 +664,11 @@
           "./locales/conversation-copy.js": 1,
           "./locales/shell-copy.js": 1
         },
-        "importSpecifiers": 2,
+        "importSpecifiers": 0,
         "nonTriviaTokens": 302
       },
       "src/renderer/app-shell-turn-actions.ts": {
-        "importDeclarations": 4,
+        "importDeclarations": 2,
         "bridgePaths": {
           "window.maka.sessions.branchFromTurn": 1,
           "window.maka.sessions.regenerateTurn": 1
@@ -686,7 +686,7 @@
           "./session-copy-attempt.js": 1,
           "./session-workspace-errors.js": 1
         },
-        "importSpecifiers": 5,
+        "importSpecifiers": 3,
         "nonTriviaTokens": 650
       },
       "src/renderer/app-shell-turn-view-model.ts": {
@@ -713,7 +713,7 @@
         "nonTriviaTokens": 1408
       },
       "src/renderer/app-shell.tsx": {
-        "importDeclarations": 92,
+        "importDeclarations": 81,
         "bridgePaths": {
           "window.maka.app.installUpdate": 1,
           "window.maka.app.retryUpdateDownload": 1,
@@ -895,7 +895,7 @@
           "@maka/ui/icons": 1,
           "react": 1
         },
-        "importSpecifiers": 147,
+        "importSpecifiers": 124,
         "nonTriviaTokens": 15588
       },
       "src/renderer/use-app-shell-composer-quotes.ts": {
@@ -916,7 +916,7 @@
         "nonTriviaTokens": 360
       },
       "src/renderer/use-app-shell-session-list.ts": {
-        "importDeclarations": 10,
+        "importDeclarations": 8,
         "bridgePaths": {
           "window.maka.sessions.list": 1
         },
@@ -941,7 +941,7 @@
           "@maka/ui": 1,
           "react": 1
         },
-        "importSpecifiers": 13,
+        "importSpecifiers": 11,
         "nonTriviaTokens": 581
       },
       "src/renderer/use-app-shell-session-ui-reads.ts": {
diff --git a/apps/desktop/scripts/check-renderer-architecture.mjs b/apps/desktop/scripts/check-renderer-architecture.mjs
index 606952781f..e522c6901c 100644
--- a/apps/desktop/scripts/check-renderer-architecture.mjs
+++ b/apps/desktop/scripts/check-renderer-architecture.mjs
@@ -1249,6 +1249,8 @@ export function analyzeRendererSource(source, file = 'fixture.ts') {
   const moduleReexports = [];
   let importDeclarations = 0;
   let importSpecifiers = 0;
+  const importDeclarationsBySource = {};
+  const importSpecifiersBySource = {};
   let unresolvedDependencies = 0;
 
   function recordBridgePath(path) {
@@ -1261,9 +1263,14 @@ export function analyzeRendererSource(source, file = 'fixture.ts') {
 
   function visit(node, parent) {
     if (node.type === 'ImportDeclaration' && !typeOnlySourceDependency(node)) {
+      const specifierCount = node.specifiers.filter((specifier) => specifier.importKind !== 'type').length;
       importDeclarations += 1;
-      importSpecifiers += node.specifiers.filter((specifier) => specifier.importKind !== 'type').length;
+      importSpecifiers += specifierCount;
       const source = staticString(node.source);
+      if (source !== undefined) {
+        importDeclarationsBySource[source] = (importDeclarationsBySource[source] ?? 0) + 1;
+        importSpecifiersBySource[source] = (importSpecifiersBySource[source] ?? 0) + specifierCount;
+      }
       if (source !== undefined && node.importKind !== 'type') {
         for (const specifier of node.specifiers) {
           if (specifier.importKind === 'type') continue;
@@ -1544,7 +1551,9 @@ export function analyzeRendererSource(source, file = 'fixture.ts') {
     environmentCapabilities: sortedObject(environmentCapabilities),
     hookCalls: sortedObject(hookCalls),
     importDeclarations,
+    importDeclarationsBySource: sortedObject(importDeclarationsBySource),
     importSpecifiers,
+    importSpecifiersBySource: sortedObject(importSpecifiersBySource),
     lifecycleMethods: sortedObject(lifecycleMethods),
     moduleImports: moduleImports.map((entry, index) => ({
       ...entry,
@@ -1651,11 +1660,20 @@ function capabilityDebtMetrics(analysis) {
   };
 }
 
-function debtMetrics(analysis) {
+// Imports from a sanctioned target (a validated copy catalog, or for AppShell
+// files a shell / public application / public feature module) are the edges
+// the migration wants a legacy file to take on; they cost no import debt, so
+// a legacy file is never pushed to inline a helper it could import.
+function debtMetrics(analysis, isSanctionedSource) {
+  const unsanctioned = (bySource) =>
+    Object.entries(bySource).reduce(
+      (total, [source, count]) => (isSanctionedSource(source) ? total : total + count),
+      0,
+    );
   return {
-    importDeclarations: analysis.importDeclarations,
+    importDeclarations: unsanctioned(analysis.importDeclarationsBySource),
     ...capabilityDebtMetrics(analysis),
-    importSpecifiers: analysis.importSpecifiers,
+    importSpecifiers: unsanctioned(analysis.importSpecifiersBySource),
     nonTriviaTokens: analysis.nonTriviaTokens,
   };
 }
@@ -2247,15 +2265,15 @@ function validateMetric(path, metric, actual, expected, violations) {
   }
 }
 
-function validateDebtFile(desktopRoot, path, expected, violations, metrics = ROOT_DEBT_METRICS) {
-  const absolutePath = resolve(desktopRoot, path);
-  if (!existsSync(absolutePath)) {
+function validateDebtFile(desktopRoot, path, expected, violations, section) {
+  if (!existsSync(resolve(desktopRoot, path))) {
     violations.push(`${path}: debt ledger entry points to a missing file`);
     return;
   }
-  const analysis = analyzeRendererSource(readFileSync(absolutePath, 'utf8'), path);
-  for (const metric of metrics) {
-    validateMetric(path, metric, analysis[metric], expected[metric], violations);
+  const rootSection = section === 'legacyAppShell' || section === 'rootDebt';
+  const actual = rootSection ? debtForPath(desktopRoot, path, section) : capabilityDebtForPath(desktopRoot, path);
+  for (const metric of rootSection ? ROOT_DEBT_METRICS : CAPABILITY_DEBT_METRICS) {
+    validateMetric(path, metric, actual[metric], expected[metric], violations);
   }
 }
 
@@ -2282,7 +2300,7 @@ function validateLegacyLedger(desktopRoot, config, violations) {
   }
 
   for (const [path, expected] of Object.entries(config.legacyAppShell.files)) {
-    validateDebtFile(desktopRoot, path, expected, violations);
+    validateDebtFile(desktopRoot, path, expected, violations, 'legacyAppShell');
   }
   const actualClosure = collectRootDependencyClosure(desktopRoot, expectedFiles, violations, 'AppShell');
   const expectedClosure = Object.keys(config.legacyAppShell.closure).sort();
@@ -2299,10 +2317,10 @@ function validateLegacyLedger(desktopRoot, config, violations) {
     if (!isRootClosureDebtSource(path) || DECLARATION_FILE.test(path)) {
       violations.push(`${path}: AppShell closure debt must point to a non-owner Desktop source`);
     }
-    validateDebtFile(desktopRoot, path, expected, violations, CAPABILITY_DEBT_METRICS);
+    validateDebtFile(desktopRoot, path, expected, violations, 'legacyAppShellClosure');
   }
   for (const [path, expected] of Object.entries(config.rootDebt)) {
-    validateDebtFile(desktopRoot, path, expected, violations);
+    validateDebtFile(desktopRoot, path, expected, violations, 'rootDebt');
   }
   const appShellDebtPaths = new Set([...expectedFiles, ...expectedClosure]);
   const rootDebtPaths = Object.keys(config.rootDebt).sort();
@@ -2322,7 +2340,7 @@ function validateLegacyLedger(desktopRoot, config, violations) {
     if (!isRootClosureDebtSource(path) || DECLARATION_FILE.test(path)) {
       violations.push(`${path}: renderer root closure debt must point to a non-owner Desktop source`);
     }
-    validateDebtFile(desktopRoot, path, expected, violations, CAPABILITY_DEBT_METRICS);
+    validateDebtFile(desktopRoot, path, expected, violations, 'rootDebtClosure');
   }
 
   const ownedPaths = new Map();
@@ -2981,7 +2999,7 @@ function validateCopyCatalog(desktopRoot, relativePath) {
     if (metricTotal(value) > 0) return `catalog carries ${metric} (${describeMetric(value)})`;
   }
   const forbidden = inspection.runtimeDependencies.find(
-    (dependency) => dependency.startsWith('.') || dependency.startsWith(DESKTOP_SELF_PREFIX),
+    (dependency) => !isBarePackageSpecifier(dependency),
   );
   if (forbidden !== undefined) {
     return `runtime import ${forbidden} is not a bare package specifier`;
@@ -3008,9 +3026,17 @@ function validateCopyCatalogFiles(desktopRoot, violations) {
   }
 }
 
+function isBarePackageSpecifier(dependency) {
+  return !dependency.startsWith('.') && !dependency.startsWith(DESKTOP_SELF_PREFIX);
+}
+
 function withoutSanctionedDependencies(desktopRoot, section, importerPath, dependencyPaths) {
+  // A validated catalog is already restricted to bare package runtime imports;
+  // pricing them again would push copy helpers back inline into the catalog.
+  const importerIsCatalog = isValidatedCopyCatalog(desktopRoot, importerPath);
   const filtered = {};
   for (const [dependency, count] of Object.entries(dependencyPaths)) {
+    if (importerIsCatalog && isBarePackageSpecifier(dependency)) continue;
     if (isSanctionedDependencyTarget(desktopRoot, section, importerPath, dependency)) continue;
     filtered[dependency] = count;
   }
@@ -3043,8 +3069,11 @@ function allowsMigrationDependency({ base, current, dependency, desktopRoot, pat
   return swapZones.includes(zoneFor(normalizePath(relative(desktopRoot, target))).kind);
 }
 
-function debtForPath(desktopRoot, path) {
-  return debtMetrics(analyzeRendererSource(readFileSync(resolve(desktopRoot, path), 'utf8'), path));
+function debtForPath(desktopRoot, path, section) {
+  return debtMetrics(
+    analyzeRendererSource(readFileSync(resolve(desktopRoot, path), 'utf8'), path),
+    (source) => isSanctionedDependencyTarget(desktopRoot, section, path, source),
+  );
 }
 
 function capabilityDebtForPath(desktopRoot, path) {
@@ -3091,7 +3120,7 @@ export function generateArchitectureConfig(desktopRoot, config) {
   const imports = collectLegacyImportEdges(desktopRoot);
   const rootDebt = {};
   for (const path of Object.keys(config.rootDebt ?? {}).sort()) {
-    if (existsSync(resolve(desktopRoot, path))) rootDebt[path] = debtForPath(desktopRoot, path);
+    if (existsSync(resolve(desktopRoot, path))) rootDebt[path] = debtForPath(desktopRoot, path, 'rootDebt');
   }
   const appShellDebtPaths = new Set([...appShellFiles, ...closureFiles]);
   const rootDebtClosureFiles = collectRootDependencyClosure(
@@ -3111,7 +3140,7 @@ export function generateArchitectureConfig(desktopRoot, config) {
     legacyPlatformImports: imports.platform,
     controllerOwners: controllerOwnersOf(config),
     legacyAppShell: {
-      files: Object.fromEntries(appShellFiles.map((path) => [path, debtForPath(desktopRoot, path)])),
+      files: Object.fromEntries(appShellFiles.map((path) => [path, debtForPath(desktopRoot, path, 'legacyAppShell')])),
       closure: Object.fromEntries(closureFiles.map((path) => [path, capabilityDebtForPath(desktopRoot, path)])),
     },
     rootDebt,
diff --git a/apps/desktop/scripts/check-renderer-architecture.test.mjs b/apps/desktop/scripts/check-renderer-architecture.test.mjs
index 46d6e81b7c..db2c11d8cf 100644
--- a/apps/desktop/scripts/check-renderer-architecture.test.mjs
+++ b/apps/desktop/scripts/check-renderer-architecture.test.mjs
@@ -2229,9 +2229,15 @@ describe('renderer architecture checker fixtures', () => {
         return <AlphaHost scope={defaultSessionScope} />;
       }
     `;
-    const currentDebt = debtForSource(appShellSource, appShellPath);
+    const currentDebt = {
+      ...debtForSource(appShellSource, appShellPath),
+      importDeclarations: 0,
+      importSpecifiers: 0,
+    };
     const baseDebt = {
       ...currentDebt,
+      importDeclarations: 2,
+      importSpecifiers: 2,
       dependencyPaths: {
         './legacy-alpha-owner.js': 1,
         './legacy-session-owner.js': 1,
@@ -2271,6 +2277,37 @@ describe('renderer architecture checker fixtures', () => {
     );
   });
 
+  for (const [targetPath, pricing] of [
+    ['src/renderer/application/contracts/fixture-diagnostics.ts', 'free'],
+    ['src/renderer/application/sessions/fixture-service.ts', 'priced'],
+  ]) {
+    it(`${pricing === 'free' ? 'exempts' : 'prices'} AppShell import specifiers from ${targetPath}`, async () => {
+      const specifier = `./${targetPath.slice('src/renderer/'.length).replace(/\.ts$/u, '.js')}`;
+      await withDesktopFixture(
+        {
+          [TRANSITIVE_APP_SHELL_PATH]: `
+            import { reportFixture } from '${specifier}';
+            export const AppShell = reportFixture('shell');
+          `,
+          [targetPath]: `export function reportFixture(scope: string): string { return scope; }`,
+        },
+        (desktopRoot) => {
+          const currentConfig = generateArchitectureConfig(desktopRoot, transitiveAppShellSeedConfig());
+          const baseConfig = structuredClone(currentConfig);
+          Object.assign(baseConfig.legacyAppShell.files[TRANSITIVE_APP_SHELL_PATH], {
+            importDeclarations: 0,
+            importSpecifiers: 0,
+            dependencyPaths: {},
+          });
+          const priced = violationsFor(desktopRoot, currentConfig, baseConfig).some((violation) =>
+            violation.startsWith(`${TRANSITIVE_APP_SHELL_PATH}: importSpecifiers debt increased`),
+          );
+          assert.equal(priced, pricing === 'priced');
+        },
+      );
+    });
+  }
+
   it('rejects replacing legacy AppShell debt with a feature private import', async () => {
     const appShellPath = 'src/renderer/app-shell.tsx';
     const appShellSource = `
@@ -2831,6 +2868,29 @@ describe('validated copy catalog dependencies', () => {
     );
   });
 
+  it('does not price a catalog\'s own bare package runtime import', async () => {
+    await withDesktopFixture(
+      transitiveAppShellFiles(
+        `
+          import { FIXTURE_COPY } from './locales/fixture-copy.js';
+          export const legacySessionHelper = FIXTURE_COPY.en.notice;
+        `,
+        {
+          [CATALOG_PATH]: catalogSource(`
+            import { lookupCopy } from '@maka/core/ui-locale';
+            export const noticeFor = (code: string) => lookupCopy(FIXTURE_COPY.en, code);
+          `),
+        },
+      ),
+      (desktopRoot) => {
+        const currentConfig = generateArchitectureConfig(desktopRoot, catalogSeedConfig());
+        const baseConfig = structuredClone(currentConfig);
+        baseConfig.legacyAppShell.closure[CATALOG_PATH].dependencyPaths = {};
+        assert.deepEqual(violationsFor(desktopRoot, currentConfig, baseConfig), []);
+      },
+    );
+  });
+
   const INVALID_CATALOGS = [
     ['a hook call', catalogSource(`
       import { useState } from 'react';


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org