FN-8463: cover root-level File Scope files
Extend File Scope regression coverage for root-level configuration and solution files. - Cover .NET and ecosystem-neutral root-level file entries - Verify task-store and public store validation exports share classification - Add a patch changeset for the File Scope validation fix Files changed: .changeset/fn-8463-file-scope-root-extensions.md | 7 +++ .../__tests__/file-scope-classification.test.ts | 64 +++++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-8463 Fusion-Task-Lineage: 149f0066-8ec5-4f9d-b5be-29f158a274cc Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-8463-file-scope-root-extensions.md
Normal file
7
.changeset/fn-8463-file-scope-root-extensions.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Accept root-level File Scope files with extensions such as global.json and solution files.
|
||||
category: fix
|
||||
dev: isValidFileScopeEntry no longer requires a slash; letter-leading final extensions share create/update validation with classification. Regression coverage tracks GitHub #2389.
|
||||
@@ -9,6 +9,11 @@
|
||||
* FNXC:FileScopeClassification 2026-07-21-18:05:
|
||||
* Also covers fenced repro snippets (GitHub #2389) whose escaped backticks produced
|
||||
* tokens like `global.json\` and blocked import via InvalidFileScopeError.
|
||||
*
|
||||
* FNXC:FileScopeClassification 2026-07-21-19:00:
|
||||
* The regression invariant covers ecosystem-neutral root files, not only the four-path
|
||||
* .NET repro. Classification, create/update validation, and the public store re-export
|
||||
* must agree while duplicate, read-only, and invalid tokens remain excluded from writes.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
@@ -17,18 +22,27 @@ import {
|
||||
isValidFileScopeEntry,
|
||||
} from "../file-scope-classification.js";
|
||||
import {
|
||||
isValidFileScopeEntry as storeIsValidFileScopeEntry,
|
||||
isValidFileScopeEntry as storeFileScopeIsValidFileScopeEntry,
|
||||
validateFileScopeInPromptContent,
|
||||
} from "../task-store/file-scope.js";
|
||||
import { isValidFileScopeEntry as storeIsValidFileScopeEntry } from "../store.js";
|
||||
import { buildBootstrapPrompt } from "../mesh-task-replication.js";
|
||||
|
||||
describe("isValidFileScopeEntry", () => {
|
||||
it("accepts root-level repo files with letter-leading extensions", () => {
|
||||
const roots = [
|
||||
"global.json",
|
||||
"Directory.Build.props",
|
||||
"Directory.Build.targets",
|
||||
"Directory.Packages.props",
|
||||
"nuget.config",
|
||||
"NuGet.config",
|
||||
".editorconfig",
|
||||
"MyApp.slnx",
|
||||
"MyApp.sln",
|
||||
"Cargo.toml",
|
||||
"go.mod",
|
||||
"pyproject.toml",
|
||||
"tsconfig.json",
|
||||
"package.json",
|
||||
"pnpm-lock.yaml",
|
||||
@@ -38,6 +52,7 @@ describe("isValidFileScopeEntry", () => {
|
||||
];
|
||||
for (const path of roots) {
|
||||
expect(isValidFileScopeEntry(path), path).toBe(true);
|
||||
expect(storeFileScopeIsValidFileScopeEntry(path), `task-store:${path}`).toBe(true);
|
||||
expect(storeIsValidFileScopeEntry(path), `store:${path}`).toBe(true);
|
||||
}
|
||||
});
|
||||
@@ -82,7 +97,8 @@ describe("isValidFileScopeEntry", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps create/update validation and classification on the same function", () => {
|
||||
it("keeps create/update validation and store exports on the same function", () => {
|
||||
expect(storeFileScopeIsValidFileScopeEntry).toBe(isValidFileScopeEntry);
|
||||
expect(storeIsValidFileScopeEntry).toBe(isValidFileScopeEntry);
|
||||
});
|
||||
});
|
||||
@@ -109,6 +125,28 @@ describe("extractEffectiveWriteScopeFromPrompt / validateFileScopeInPromptConten
|
||||
]);
|
||||
});
|
||||
|
||||
it("retains the broader .NET root set in effective scope", () => {
|
||||
const rootPaths = [
|
||||
".editorconfig",
|
||||
"Directory.Build.props",
|
||||
"Directory.Build.targets",
|
||||
"Directory.Packages.props",
|
||||
"global.json",
|
||||
"nuget.config",
|
||||
"MyApp.slnx",
|
||||
];
|
||||
const broaderPrompt = `## File Scope
|
||||
${rootPaths.map((path) => `- \`${path}\` (new)`).join("\n")}
|
||||
- \`src/MyApp/Program.cs\` (new)
|
||||
`;
|
||||
|
||||
expect(extractEffectiveWriteScopeFromPrompt(broaderPrompt)).toEqual([
|
||||
...rootPaths,
|
||||
"src/MyApp/Program.cs",
|
||||
]);
|
||||
expect(validateFileScopeInPromptContent(broaderPrompt).invalid).toEqual([]);
|
||||
});
|
||||
|
||||
it("passes create/update File Scope validation for root-level extension paths", () => {
|
||||
const { valid, invalid } = validateFileScopeInPromptContent(prompt);
|
||||
expect(invalid).toEqual([]);
|
||||
@@ -120,6 +158,28 @@ describe("extractEffectiveWriteScopeFromPrompt / validateFileScopeInPromptConten
|
||||
]);
|
||||
});
|
||||
|
||||
it("omits duplicate, read-only, conditional, and invalid tokens from write scope", () => {
|
||||
const classified = `## File Scope
|
||||
- \`global.json\`
|
||||
- \`global.json\`
|
||||
|
||||
Read-only context:
|
||||
- \`Directory.Build.props\`
|
||||
|
||||
Files changed:
|
||||
- \`src/MyApp/Program.cs\`
|
||||
|
||||
Only if changed:
|
||||
- \`.changeset/fix.md\`
|
||||
|
||||
## Steps
|
||||
`;
|
||||
expect(extractEffectiveWriteScopeFromPrompt(classified)).toEqual([
|
||||
"global.json",
|
||||
"src/MyApp/Program.cs",
|
||||
]);
|
||||
});
|
||||
|
||||
it("still rejects git-ref tokens inside File Scope on create/update validation", () => {
|
||||
const bad = `## File Scope
|
||||
- \`packages/core/src/store.ts\`
|
||||
|
||||
Reference in New Issue
Block a user