FN-7093: tighten lazy-view inventory guard

Keep the lazy-loaded views documentation guard aligned with every curated chunk source.

- Expand AGENTS guidance to name the plugin and agent detail lazy-import sources.
- Teach the dashboard docs test to scan feature-owned lazy declarations in PluginsSection and AgentsView.
- Assert explicit exclusions for embedded views, terminal/onboarding internals, and duplicate overflow imports.

Files changed:
 AGENTS.md                                          |   4 +-
 .../app/__tests__/lazy-loaded-views-docs.test.ts   | 113 +++++++++++++++++++--
 2 files changed, 108 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7093

Fusion-Task-Lineage: 25bbe920-529d-4f2b-95d4-4c17b682dc49

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-06-26 22:01:36 -07:00
parent b4b9db12a4
commit dbe1e2e39f
2 changed files with 108 additions and 9 deletions

View File

@@ -259,7 +259,7 @@ Scoped exception (FN-5819): shared-branch-group members (`branchContext.assignme
### Lazy-Loaded Heavy Views
These 20 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null}>`.
Keep this AGENTS inventory in sync with App lazy imports, AppModals lazy modal imports (`SettingsModal`, `WorkflowNodeEditor`, `SetupWizardModal`), and `packages/dashboard/app/__tests__/lazy-loaded-views-docs.test.ts`.
Keep this AGENTS inventory in sync with App lazy imports, AppModals lazy modal imports (`SettingsModal`, `WorkflowNodeEditor`, `SetupWizardModal`), plugin settings lazy imports (`PluginManager`, `PiExtensionsManager`), AgentsView lazy imports (`AgentDetailView`), and `packages/dashboard/app/__tests__/lazy-loaded-views-docs.test.ts`.
- `AgentsView`
- `ChatView`
@@ -282,7 +282,7 @@ Keep this AGENTS inventory in sync with App lazy imports, AppModals lazy modal i
- `PiExtensionsManager`
- `AgentDetailView`
Note: the embedded main-content views Workflows (`_WorkflowEditorView`), Import Tasks (`_ImportTasksView`), Automations (`_AutomationsView`), and Settings (`_SettingsView`) in App.tsx are `_`-prefixed lazy splits that reuse already-documented chunks. They are intentionally excluded from the curated list above and from the count; `lazy-loaded-views-docs.test.ts` filters out `_`-prefixed lazy consts (`extractAppLazyViews`), so do not add them as bullets.
Note: the embedded main-content views Workflows (`_WorkflowEditorView`), Import Tasks (`_ImportTasksView`), Automations (`_AutomationsView`), and Settings (`_SettingsView`) in App.tsx are `_`-prefixed lazy splits that reuse already-documented chunks. Task session terminals, onboarding-internal modals, duplicate `AgentDetailView` imports, and right-dock overflow re-imports of already-counted views are also intentionally excluded. These exclusions stay out of the curated list and count; `lazy-loaded-views-docs.test.ts` asserts them explicitly, so do not add them as bullets.
## FNXC_LOG comments:
- Please whenever you're working on a codebase. I want you to add comments describing the date of the change (must be in this format yyyy-MM-dd-hh:mm) and describing the requirements or the change in requirements that made you implement certain functionality.

View File

@@ -17,6 +17,12 @@ FN-6881 removes StashRecoveryView from the App-level lazy inventory because Stas
FNXC:DashboardLazyViews 2026-06-22-00:00:
The navigation reshuffle promotes Workflows, Import Tasks, Automations, and Settings as embedded views that reuse existing lazy chunks. Their underscore-prefixed App consts stay out of the curated inventory so the docs count each heavy chunk once.
FNXC:DashboardLazyViews 2026-06-26-00:00:
Curated chunks declared outside App.tsx/AppModals.tsx (Plugins settings section, AgentsView) must be scanned at their real call sites so the inventory cannot drift while this guard stays green.
FNXC:DashboardLazyViews 2026-06-26-00:00:
Session terminals, onboarding internals, and overflow re-imports of already-counted chunks are explicit exclusions because they are not new heavy top-level views or modals for the AGENTS inventory.
*/
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
@@ -72,6 +78,57 @@ const EXPECTED_APP_MODALS_LAZY_VIEWS = new Set([
"WorkflowNodeEditor",
]);
const EXPECTED_PLUGINS_SECTION_LAZY_VIEWS = new Set([
"PluginManager",
"PiExtensionsManager",
]);
const EXPECTED_AGENTS_VIEW_LAZY_VIEWS = new Set([
"AgentDetailView",
]);
const EXPECTED_EXCLUDED_LAZY = [
{
file: "../App.tsx",
symbols: ["_WorkflowEditorView", "_ImportTasksView", "_AutomationsView", "_SettingsView"],
reason: "embedded App presentations reuse already-documented modal/import chunks",
},
{
file: "../components/TaskDetailModal.tsx",
symbols: ["LazySessionTerminal"],
reason: "task session terminal, not a top-level heavy view or modal",
},
{
file: "../components/TaskDetailModal.tsx",
symbols: ["AgentDetailView"],
reason: "re-import of the same AgentDetailView chunk curated from AgentsView.tsx",
countedBy: "../components/AgentsView.tsx",
},
{
file: "../components/ModelOnboardingModal.tsx",
symbols: ["ExperimentalAgentOnboardingModal"],
reason: "onboarding internal loaded inside the existing model onboarding flow",
},
{
file: "../components/SetupWizardModal.tsx",
symbols: ["ExperimentalAgentOnboardingModal"],
reason: "onboarding internal loaded inside the existing setup wizard flow",
},
{
file: "../components/overflowViewRegistry.tsx",
symbols: ["DevServerView", "SecretsView", "TodoView", "PullRequestView"],
reason: "right-dock overflow re-imports of App-level chunks already counted once",
countedBy: "../App.tsx",
},
] as const;
const EXPECTED_CURATED_LAZY_SOURCES = [
{ file: "../App.tsx", symbols: EXPECTED_APP_LEVEL_VIEWS },
{ file: "../components/AppModals.tsx", symbols: EXPECTED_APP_MODALS_LAZY_VIEWS },
{ file: "../components/settings/sections/PluginsSection.tsx", symbols: EXPECTED_PLUGINS_SECTION_LAZY_VIEWS },
{ file: "../components/AgentsView.tsx", symbols: EXPECTED_AGENTS_VIEW_LAZY_VIEWS },
] as const;
function extractLazyLoadedSection(agentsDoc: string): string {
const match = agentsDoc.match(/### Lazy-Loaded Heavy Views[\s\S]*?(?=\n### |\n---|$)/);
if (!match) {
@@ -102,11 +159,20 @@ function extractAppModalsLazyViews(appModalsSource: string): Set<string> {
return new Set(extractConstLazyViews(appModalsSource));
}
function expectDocumentedViews(include: Iterable<string>, section: string): void {
for (const view of include) {
expect(EXPECTED_DOCUMENTED_VIEWS.has(view)).toBe(true);
expect(section).toContain(`\`${view}\``);
}
}
describe("AGENTS lazy-loaded views inventory", () => {
it("documents the App-level and AppModals lazy views accurately and keeps the curated 20-view list in sync", () => {
const agentsDoc = readFileSync(resolve(__dirname, "../../../../AGENTS.md"), "utf-8");
const appSource = readFileSync(resolve(__dirname, "../App.tsx"), "utf-8");
const appModalsSource = readFileSync(resolve(__dirname, "../components/AppModals.tsx"), "utf-8");
const pluginsSectionSource = readFileSync(resolve(__dirname, "../components/settings/sections/PluginsSection.tsx"), "utf-8");
const agentsViewSource = readFileSync(resolve(__dirname, "../components/AgentsView.tsx"), "utf-8");
const section = extractLazyLoadedSection(agentsDoc);
const countMatch = section.match(/These\s+(\d+)\s+views\s+are lazy-loaded/);
@@ -123,21 +189,54 @@ describe("AGENTS lazy-loaded views inventory", () => {
expect(section).toContain("`WorkflowNodeEditor`");
expect(section).toContain("`_ImportTasksView`");
expect(section).toContain("`_AutomationsView`");
expect((section.match(/`AgentDetailView`/g) ?? []).length).toBe(1);
expect(documentedViews.filter((view) => view === "AgentDetailView")).toHaveLength(1);
const appLevelViews = extractAppLazyViews(appSource);
expect(appLevelViews).toEqual(EXPECTED_APP_LEVEL_VIEWS);
for (const view of appLevelViews) {
expect(EXPECTED_DOCUMENTED_VIEWS.has(view)).toBe(true);
}
expectDocumentedViews(appLevelViews, section);
const appModalsLazyViews = extractAppModalsLazyViews(appModalsSource);
expect(appModalsLazyViews).toEqual(EXPECTED_APP_MODALS_LAZY_VIEWS);
expectDocumentedViews(appModalsLazyViews, section);
for (const view of appModalsLazyViews) {
expect(EXPECTED_DOCUMENTED_VIEWS.has(view)).toBe(true);
expect(section).toContain(`\`${view}\``);
/*
* FNXC:DashboardLazyViews 2026-06-26-00:00:
* Plugin manager chunks and the agent detail chunk are curated AGENTS entries, but their lazy declarations live in feature-owned source files rather than App.tsx/AppModals.tsx. Scan those real call sites so removing or renaming one of these declarations fails this inventory guard.
*/
const pluginsSectionLazyViews = new Set(extractConstLazyViews(pluginsSectionSource));
expect(pluginsSectionLazyViews).toEqual(EXPECTED_PLUGINS_SECTION_LAZY_VIEWS);
expectDocumentedViews(pluginsSectionLazyViews, section);
const agentsViewLazyViews = new Set(extractConstLazyViews(agentsViewSource));
expect(agentsViewLazyViews).toEqual(EXPECTED_AGENTS_VIEW_LAZY_VIEWS);
expectDocumentedViews(agentsViewLazyViews, section);
/*
* FNXC:DashboardLazyViews 2026-06-26-00:00:
* These lazy consts are intentionally outside the curated 20: task session terminals, onboarding internals, duplicate AgentDetail/overflow imports, and underscore-prefixed embedded views do not create additional top-level heavy inventory entries.
*/
for (const exclusion of EXPECTED_EXCLUDED_LAZY) {
const excludedSource = readFileSync(resolve(__dirname, exclusion.file), "utf-8");
const excludedLazyViews = new Set(extractConstLazyViews(excludedSource));
for (const symbol of exclusion.symbols) {
expect(excludedLazyViews.has(symbol), exclusion.reason).toBe(true);
}
}
const curatedSourceKeys = new Set(
EXPECTED_CURATED_LAZY_SOURCES.flatMap((source) => [...source.symbols].map((symbol) => `${source.file}:${symbol}`)),
);
for (const exclusion of EXPECTED_EXCLUDED_LAZY) {
for (const symbol of exclusion.symbols) {
expect(curatedSourceKeys.has(`${exclusion.file}:${symbol}`), exclusion.reason).toBe(false);
if ("countedBy" in exclusion) {
expect(curatedSourceKeys.has(`${exclusion.countedBy}:${symbol}`), exclusion.reason).toBe(true);
expect(documentedViews.filter((view) => view === symbol), exclusion.reason).toHaveLength(1);
} else {
expect(EXPECTED_DOCUMENTED_VIEWS.has(symbol), exclusion.reason).toBe(false);
}
}
}
});
});