chore: merge develop into hare/develop

This commit is contained in:
2026-10-07 18:03:33 +09:00
117 changed files with 27801 additions and 10459 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
"dev": "deno run -A npm:vite@8.3.2 dev",
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787",
"check": "deno run -A npm:@sveltejs/kit@3.0.0 sync && deno run -A npm:svelte-check@4.7.6 --tsconfig ./tsconfig.json",
"test": "deno test --allow-read=src,test,tests,../../docs --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/repository-api.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts tests/skill-api.test.ts tests/tooltip-contract.test.ts tests/bevel-contract.test.ts tests/bevel-line-contract.test.ts tests/typography-contract.test.ts src/lib/workspace/auth/model.test.ts src/lib/workspace/protocol-validator.test.ts tests/auth-api.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/api/workers.test.ts src/lib/workspace/api/ticket-browser.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-delivery.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/composer-invocation.test.ts src/lib/workspace/console/file-completions.test.ts test/console/ansi.test.ts src/lib/workspace/console/history.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/turn-navigation.test.ts src/lib/workspace/console/run-status.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts tests/workdir-permissions.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/spa-shell.test.ts test/objective-pages.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts tests/runtime-connection.test.ts tests/runtime-management.test.ts tests/runtime-management-source.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/route-ownership.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-workdir-meta.test.ts src/lib/workspace/sidebar/worker-launch.test.ts tests/runtime-workers.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/config-source/api.test.ts tests/memory-api.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/model.test.ts test/repository-access/structure.test.ts test/repository-ssh-connection-ui.test.ts",
"test": "deno test --allow-read=src,test,tests,../../docs,../../resources/config-schema --allow-env=LOG,VSCODE_TEXTMATE_DEBUG,NODE_ENV tests/workspace-model.test.ts tests/repository-api.test.ts tests/workspace-catalog.test.ts tests/profile-api.test.ts tests/skill-api.test.ts tests/tooltip-contract.test.ts tests/bevel-contract.test.ts tests/bevel-line-contract.test.ts tests/typography-contract.test.ts src/lib/workspace/auth/model.test.ts src/lib/workspace/protocol-validator.test.ts tests/auth-api.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/api/workers.test.ts src/lib/workspace/api/ticket-browser.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-delivery.test.ts test/composer-history.test.ts tests/composer-paste.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-draft.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/composer-invocation.test.ts src/lib/workspace/console/file-completions.test.ts test/console/ansi.test.ts src/lib/workspace/console/history.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/turn-navigation.test.ts src/lib/workspace/console/run-status.test.ts src/lib/workspace/companion/api.test.ts tests/workdir-api.test.ts tests/workdir-permissions.test.ts src/lib/workspace/console/tasks.test.ts test/ticket-detail-route-reuse.test.ts test/spa-shell.test.ts test/objective-pages.test.ts test/repositories/ui.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts tests/runtime-connection.test.ts tests/runtime-management.test.ts tests/runtime-management-source.test.ts src/lib/workspace/sidebar/override-stack.test.ts src/lib/workspace/sidebar/route-ownership.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/workspace-switcher.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-workdir-meta.test.ts src/lib/workspace/sidebar/worker-launch.test.ts tests/runtime-workers.test.ts test/sidebar/worker-actions.test.ts src/lib/workspace/tickets/merge-request-resources.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/merge-request-status.test.ts test/config-source/decodal-grammar.test.ts test/config-source/editor-state.test.ts test/config-source/fixed-schema-wrapper.test.ts test/config-source/toolchain.test.ts test/config-source/wasm-parity.test.ts test/config-source/api.test.ts tests/memory-api.test.ts test/repository-access/api.test.ts test/repository-access/loader.test.ts test/repository-access/model.test.ts test/repository-access/structure.test.ts test/repository-ssh-connection-ui.test.ts",
"test:component": "deno run -A npm:vitest@5.0.3 run --config vitest.config.ts",
"build": "deno run -A npm:vite@8.3.2 build",
"preview": "deno run -A npm:vite@8.3.2 preview",
@@ -1,6 +1,6 @@
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:fd06f382c6d33a5c3cc98ef9e264545923c53fa95a9be555a85680f98c6065da)
// Input contract: 0.1.0 (sha256:a6a7147c9a2f465a5da044e9ba21947cb3d86eacbfe3905696483917e794d5cf)
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/companion-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
@@ -237,6 +237,10 @@ export type ConfigSchemaContribution = {
version: string;
source: string;
projection_validator?: ConfigProjectionValidator;
/**
* Completion-only shape for partial values; never materialized as defaults.
*/
authoring_source?: string;
source_digest: string;
};
@@ -1,6 +1,6 @@
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:fd06f382c6d33a5c3cc98ef9e264545923c53fa95a9be555a85680f98c6065da)
// Input contract: 0.1.0 (sha256:a6a7147c9a2f465a5da044e9ba21947cb3d86eacbfe3905696483917e794d5cf)
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
// Output: web/workspace/src/lib/generated/repository-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:fd06f382c6d33a5c3cc98ef9e264545923c53fa95a9be555a85680f98c6065da)
// Input contract: 0.1.0 (sha256:a6a7147c9a2f465a5da044e9ba21947cb3d86eacbfe3905696483917e794d5cf)
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/runtime-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:fd06f382c6d33a5c3cc98ef9e264545923c53fa95a9be555a85680f98c6065da)
// Input contract: 0.1.0 (sha256:a6a7147c9a2f465a5da044e9ba21947cb3d86eacbfe3905696483917e794d5cf)
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/ticket-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:fd06f382c6d33a5c3cc98ef9e264545923c53fa95a9be555a85680f98c6065da)
// Input contract: 0.1.0 (sha256:a6a7147c9a2f465a5da044e9ba21947cb3d86eacbfe3905696483917e794d5cf)
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
@@ -216,6 +216,51 @@ test("unmount during schema setup closes the toolchain", async () => {
expect(toolchain.close).toHaveBeenCalledOnce();
});
test("builtin diagnostics show read-only paths without adding editable workspace files", async () => {
toolchain.analyze.mockResolvedValue([{
path: "$builtin/profiles/companion.dcdl",
revision: 7,
tree_digest: "sha256:tree",
kind: "constraint_violation",
span: { start_byte: 1, end_byte: 4 },
message: "Imported value does not match the requested schema",
labels: [],
notes: [],
}]);
const view = renderEditor();
await expectReady(view);
await waitFor(() => {
const diagnostic = view.container.querySelector(".config-source-diagnostics");
expect(diagnostic?.textContent).toContain("$builtin/profiles/companion.dcdl (read-only builtin source)");
expect(diagnostic?.textContent).toContain("bytes 1–4");
});
const paths = view.getByRole("navigation", { name: "Virtual configuration paths" });
expect(paths.textContent).not.toContain("$builtin/");
expect(paths.querySelectorAll("button")).toHaveLength(1);
expect(view.container.querySelector('.cm-content[contenteditable="true"]')).not.toBeNull();
});
test("unknown builtin diagnostics retain the workspace importer path", async () => {
toolchain.analyze.mockResolvedValue([{
path: "main.dcdl",
revision: 7,
tree_digest: "sha256:tree",
kind: "import",
span: { start_byte: 8, end_byte: 40 },
message: "unknown or non-public read-only builtin source: $builtin/profiles/missing.dcdl",
labels: [],
notes: [],
}]);
const view = renderEditor();
await expectReady(view);
await waitFor(() => {
const diagnostic = view.container.querySelector(".config-source-diagnostics");
expect(diagnostic?.textContent).toContain("main.dcdl · bytes 8–40");
expect(diagnostic?.textContent).toContain("unknown or non-public read-only builtin source");
});
expect(view.getByRole("navigation", { name: "Virtual configuration paths" }).textContent).not.toContain("$builtin/");
});
test("unmount during fetch does not start a toolchain", async () => {
let finishFetch!: (response: Response) => void;
fetcher.mockReturnValueOnce(
@@ -377,7 +377,7 @@
<li>
<strong>{diagnostic.kind}</strong>
<span>{diagnostic.message}</span>
<small>bytes {diagnostic.span.start_byte}–{diagnostic.span.end_byte}</small>
<small>{diagnostic.path}{diagnostic.path.startsWith("$builtin/") ? " (read-only builtin source)" : ""} · bytes {diagnostic.span.start_byte}–{diagnostic.span.end_byte}</small>
</li>
{/each}
</ol>
@@ -187,7 +187,7 @@ function parseContribution(value: unknown): ConfigSchemaContribution {
const item = record(
value,
["provider_id", "namespace", "version", "source", "source_digest"],
["projection_validator"],
["projection_validator", "authoring_source"],
);
const projection = item.projection_validator === undefined
? undefined
@@ -197,6 +197,12 @@ function parseContribution(value: unknown): ConfigSchemaContribution {
namespace: boundedString(item.namespace),
version: boundedString(item.version),
source: boundedString(item.source, MAX_SCHEMA_SOURCE_BYTES),
...(item.authoring_source === undefined ? {} : {
authoring_source: boundedString(
item.authoring_source,
MAX_SCHEMA_SOURCE_BYTES,
),
}),
...(projection === undefined ? {} : { projection_validator: projection }),
source_digest: boundedString(item.source_digest, MAX_DIGEST_BYTES),
};
@@ -1,4 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ConfigProjectionValidator } from "./ConfigProjectionValidator";
export type ConfigSchemaContribution = { provider_id: string, namespace: string, version: string, source: string, projection_validator?: ConfigProjectionValidator | null, source_digest: string, };
export type ConfigSchemaContribution = { provider_id: string, namespace: string, version: string, source: string, authoring_source?: string | null, projection_validator?: ConfigProjectionValidator | null, source_digest: string, };
@@ -226,6 +226,62 @@ Deno.test("config source API rejects unsafe revisions and oversized entry conten
);
});
Deno.test("config source API does not materialize imported builtins in the workspace file list", async () => {
const body = {
...tree,
snapshot: {
...snapshot,
entries: {
"profiles/main.dcdl": {
...entry,
content: 'import "$builtin/profiles/companion.dcdl"',
},
},
},
};
const fetcher = (() => Promise.resolve(response(body))) as typeof fetch;
const result = await fetchConfigTree("w", fetcher);
assertEquals(Object.keys(result.snapshot.entries), ["profiles/main.dcdl"]);
assertEquals(
result.snapshot.entries["profiles/main.dcdl"].content,
body.snapshot.entries["profiles/main.dcdl"].content,
);
});
Deno.test("config source API preserves unknown read-only builtin diagnostics without fallback requests", async () => {
const diagnostic = {
path: "main.dcdl",
revision: 7,
tree_digest: "sha256:tree",
kind: "import",
span: { start_byte: 8, end_byte: 40 },
message:
"unknown or non-public read-only builtin source: $builtin/profiles/missing.dcdl",
labels: [],
notes: [],
};
const calls: string[] = [];
const fetcher = ((input: string | URL | Request) => {
calls.push(String(input));
return Promise.resolve(
response({ error: JSON.stringify([diagnostic]) }, 400),
);
}) as typeof fetch;
const error = await assertRejects(
() =>
commitConfigTree("w", {
base_revision: 7,
base_digest: "sha256:tree",
changes: [],
entrypoints: ["main.dcdl"],
}, fetcher),
ConfigSourceApiError,
diagnostic.message,
);
assert(String(error).includes("main.dcdl"));
assertEquals(calls, ["/api/w/w/config/source-tree/commit"]);
});
Deno.test("config source API surfaces bounded failed evaluation details", async () => {
const fetcher = (() =>
Promise.resolve(
@@ -244,3 +300,41 @@ Deno.test("config source API surfaces bounded failed evaluation details", async
}
assert(message.includes("structured diagnostics"));
});
Deno.test("config source API carries bounded optional authoring schemas without changing validation source", () => {
const body = withSchema("validation");
const authoringSource = "shape\n".repeat(6000);
const contribution = {
...body.contract.schema_bundle.contributions[0],
authoring_source: authoringSource,
};
const withAuthoring = {
...body,
contract: {
...body.contract,
schema_bundle: {
...body.contract.schema_bundle,
contributions: [contribution],
},
},
};
const parsed = parseWorkspaceConfigTreeResponse(withAuthoring);
assertEquals(
parsed.contract.schema_bundle.contributions[0].authoring_source,
authoringSource,
);
assertEquals(parsed.contract.schema_bundle.source, "validation");
for (const invalid of [null, 42, {}, "é".repeat(4 * 1024 * 1024) + "x"]) {
assertThrows(() =>
parseWorkspaceConfigTreeResponse({
...withAuthoring,
contract: {
...body.contract,
schema_bundle: {
...body.contract.schema_bundle,
contributions: [{ ...contribution, authoring_source: invalid }],
},
},
}), ConfigSourceApiError);
}
});
@@ -89,6 +89,31 @@ Deno.test("completion starts only after non-whitespace typing", () => {
);
});
Deno.test("toolchain preserves read-only builtin import completion detail", () => {
const result = toCodeMirrorCompletion({
from: 8,
items: [{
label: "$builtin/profiles/companion.dcdl",
kind: "file",
detail: "read-only builtin Decodal source",
priority: 0,
}],
});
assert(result !== null, "builtin completion should be available");
assert(
result.options[0].label === "$builtin/profiles/companion.dcdl",
"builtin namespace must not become a workspace path",
);
assert(
result.options[0].detail === "read-only builtin Decodal source",
"CodeMirror must display the read-only completion detail",
);
assert(
result.options[0].type === "file",
"builtin imports remain file completions",
);
});
Deno.test("toolchain preserves WASM UTF-16 completion ranges for CodeMirror", () => {
const result = toCodeMirrorCompletion({
from: "let 名 = ".length,
@@ -299,6 +299,150 @@ Deno.test("generated WASM returns completion items for the editor adapter", () =
assertEquals(result.items[0].kind, "file");
});
Deno.test("generated WASM exposes read-only builtin completions without editable builtin entries", () => {
const tree = schemaSnapshot("{}");
set_snapshot(tree);
set_schema_bundle(emptySchemaBundle);
const source = 'let 名 = 1; import "$builtin/profiles/comp"';
const result = complete_current(
"main.dcdl",
source,
source.length - 1,
true,
) as {
from: number;
items: Array<{ label: string; kind: string; detail: string }>;
};
const companion = result.items.find((item) =>
item.label === "$builtin/profiles/companion.dcdl"
);
assertEquals(result.from, 'let 名 = 1; import "'.length);
assertEquals(companion?.kind, "file");
assertEquals(companion?.detail, "read-only builtin Decodal source");
assertEquals(Object.keys(tree.entries), ["main.dcdl"]);
const evaluated = evaluate_snapshot(
schemaSnapshot('import "$builtin/profiles/companion.dcdl"'),
mainEntrypointContract,
) as {
projections: Array<{ data_json: { slug: string } }>;
};
assertEquals(evaluated.projections[0].data_json.slug, "companion");
});
Deno.test("generated WASM rejects unknown builtin imports without same-suffix workspace fallback", () => {
const tree = schemaSnapshot('import "$builtin/profiles/missing.dcdl"');
tree.entries["profiles/missing.dcdl"] = {
path: "profiles/missing.dcdl",
content_type: "decodal",
content: "{}",
content_digest: "sha256:workspace-fallback",
};
set_schema_bundle(emptySchemaBundle);
const diagnostics = analyze_snapshot(tree, "main.dcdl", undefined) as Array<{
path: string;
revision: number;
tree_digest: string;
message: string;
}>;
assertEquals(diagnostics.length > 0, true);
assertEquals(diagnostics[0].path, "main.dcdl");
assertEquals(diagnostics[0].revision, tree.revision);
assertEquals(diagnostics[0].tree_digest, tree.digest);
assertEquals(
diagnostics[0].message.includes(
"unknown or non-public read-only builtin source",
),
true,
);
assertEquals(
diagnostics[0].message.includes("$builtin/profiles/missing.dcdl"),
true,
);
let failed = false;
try {
evaluate_snapshot(tree, mainEntrypointContract);
} catch (error) {
failed = true;
assertEquals(
(error as Array<{ message: string }>)[0].message.includes(
"unknown or non-public read-only builtin source",
),
true,
);
}
assertEquals(failed, true);
assertEquals(
analyze_snapshot(tree, "main.dcdl", 'import "./profiles/missing.dcdl"'),
[],
);
});
function importFailure(tree: ConfigTreeSnapshot): ProjectedDiagnostic[] {
try {
evaluate_snapshot(tree, mainEntrypointContract);
} catch (error) {
// A WASM trap/stack overflow must not count as a structured import failure.
assertEquals(Array.isArray(error), true);
const diagnostics = error as Array<
ProjectedDiagnostic & {
revision: number;
tree_digest: string;
}
>;
assertEquals(diagnostics.length > 0, true);
assertEquals(diagnostics[0].revision, tree.revision);
assertEquals(diagnostics[0].tree_digest, tree.digest);
return diagnostics;
}
throw new Error("expected a structured import diagnostic");
}
Deno.test("generated WASM rejects nested lazy-object import cycles without a stack overflow", () => {
const tree = schemaSnapshot('{ nested = import "./b.dcdl"; }');
tree.entries["b.dcdl"] = {
path: "b.dcdl",
content_type: "decodal",
content: '{ nested = import "./main.dcdl"; }',
content_digest: "sha256:nested-cycle-b",
};
const diagnostics = importFailure(tree);
assertEquals(diagnostics[0].kind, "cycle");
assertEquals(diagnostics[0].message.includes("import cycle"), true);
});
Deno.test("generated WASM enforces the import depth budget on a real 33-deep chain", () => {
function chain(depth: number): ConfigTreeSnapshot {
const tree = schemaSnapshot('import "./chain/1.dcdl"');
for (let index = 1; index <= depth; index++) {
const path = `chain/${index}.dcdl`;
tree.entries[path] = {
path,
content_type: "decodal",
content: index === depth
? "{ answer = 42; }"
: `import "./${index + 1}.dcdl"`,
content_digest: `sha256:chain-${depth}-${index}`,
};
}
return tree;
}
// The synthetic evaluation-wrapper import consumes one of the 32 edges.
const accepted = evaluate_snapshot(chain(31), mainEntrypointContract) as {
projections: Array<{ data_json: { answer: number } }>;
};
assertEquals(accepted.projections[0].data_json, { answer: 42 });
for (const depth of [32, 33]) {
const diagnostics = importFailure(chain(depth));
assertEquals(diagnostics[0].kind, "import");
assertEquals(
diagnostics.some((diagnostic) =>
diagnostic.message.includes("import depth")
),
true,
);
}
});
Deno.test("generated WASM completes blank nested schema positions after Unicode", () => {
const source =
'{ description = "日本語"; profile = { }\n} as WorkspaceConfigSchema';
@@ -381,3 +525,376 @@ Deno.test("generated WASM completes asserted WorkspaceConfigSchema keys", () =>
assertEquals(result.from, 2);
assertEquals(result.items.some((item) => item.label === "profile"), true);
});
function fixtureDecodal(value: unknown): string {
if (Array.isArray(value)) return `[${value.map(fixtureDecodal).join(", ")}]`;
if (value !== null && typeof value === "object") {
return `{ ${
Object.entries(value).map(([key, value]) =>
`${key} = ${fixtureDecodal(value)};`
).join(" ")
} }`;
}
if (
typeof value === "string" || typeof value === "number" ||
typeof value === "boolean"
) return JSON.stringify(value);
throw new Error("fixture omission must not be represented as null/undefined");
}
Deno.test("generated WASM authors value-based Profiles using the Backend schema without materializing authoring fields", async () => {
const source = await Deno.readTextFile(
new URL(
"../../../../resources/config-schema/profile.dcdl",
import.meta.url,
),
);
const authoring_source = await Deno.readTextFile(
new URL(
"../../../../resources/config-schema/profile-authoring.dcdl",
import.meta.url,
),
);
const schema = compose_schema_bundle([{
provider_id: "builtin:profile",
namespace: "profile",
version: "2",
source,
source_digest: await digestText(source),
authoring_source,
}]) as WorkspaceConfigSchemaBundle;
const content =
'{ profile = { entries = [{ selector = "project:alpha"; profile = {}; }]; }; } as WorkspaceConfigSchema';
const tree: ConfigTreeSnapshot = {
revision: 8,
digest: "sha256:value-profile-tree",
entries: {
"main.dcdl": {
path: "main.dcdl",
content_type: "decodal",
content,
content_digest: await digestText(content),
},
},
};
const valueContract = {
...contract,
entrypoints: ["main.dcdl"],
schema_bundle: schema,
fingerprint: await toolchainFingerprint(["main.dcdl"], schema),
};
set_snapshot(tree);
set_schema_bundle(schema);
const evaluated = evaluate_snapshot(tree, valueContract) as {
projections: Array<
{ data_json: { profile: { entries: Array<{ profile: unknown }> } } }
>;
};
assertEquals(
evaluated.projections[0].data_json.profile.entries[0].profile,
{},
);
for (
const [body, token, label] of [
[
"{ profile = { entries = [{ sel }] } } as WorkspaceConfigSchema",
"sel",
"selector",
],
[
"{ profile = { entries = [{ pro }] } } as WorkspaceConfigSchema",
"pro",
"profile",
],
[
"{ profile = { entries = [{ profile = { wor } }] } } as WorkspaceConfigSchema",
"wor",
"worker",
],
[
"{ profile = { entries = [{ profile = { worker = { mo } } }] } } as WorkspaceConfigSchema",
"mo",
"mode",
],
[
"{ profile = { entries = [{ profile = { feature = { ta } } }] } } as WorkspaceConfigSchema",
"ta",
"task",
],
]
) {
const cursor = body.lastIndexOf(token) + token.length;
const result = complete_current("main.dcdl", body, cursor, true) as {
from: number;
items: Array<{ label: string }>;
};
assertEquals(
result.items.some((item) => item.label === label),
true,
label,
);
assertEquals(result.from, cursor - token.length);
}
for (
const value of [
"{}",
"{ worker = {}; }",
'{ worker = { mode = "wip"; }; }',
"{ feature = { task = {}; }; }",
]
) {
const partialContent = content.replace(
"profile = {};",
`profile = ${value};`,
);
assertEquals(
analyze_snapshot(tree, "main.dcdl", partialContent),
[],
value,
);
}
const recipe = "{ worker = { mode = 42; }; }";
const analysisTree = {
...tree,
entries: {
...tree.entries,
"recipe.dcdl": {
path: "recipe.dcdl",
content_type: "decodal",
content: recipe,
content_digest: await digestText(recipe),
},
},
};
for (
const [value, field, expectedPath] of [
["42", "profile", "main.dcdl"],
["{ worker = 42; }", "worker", "main.dcdl"],
["{ worker = { mode = 42; }; }", "mode", "main.dcdl"],
["{ feature = { task = { enabled = 42; }; }; }", "enabled", "main.dcdl"],
['{ worker = { typo = "wip"; }; }', "typo", "main.dcdl"],
['import "./recipe.dcdl"', "mode", "recipe.dcdl"],
[
'(import "./recipe.dcdl") // { worker = { mode = 42; }; }',
"mode",
"main.dcdl",
],
]
) {
const invalidContent = content.replace(
"profile = {};",
`profile = ${value};`,
);
const diagnostics = analyze_snapshot(
analysisTree,
"main.dcdl",
invalidContent,
) as Array<{
path: string;
revision: number;
kind: string;
span: { start_byte: number; end_byte: number };
message: string;
labels: Array<
{ span: { start_byte: number; end_byte: number }; message: string }
>;
}>;
assertEquals(diagnostics.length > 0, true, value);
const diagnostic = diagnostics[0];
assertEquals(diagnostic.path, expectedPath);
assertEquals(diagnostic.revision, tree.revision);
assertEquals(
["constraint_violation", "type_mismatch"].includes(diagnostic.kind),
true,
);
assertEquals(
diagnostic.message.includes(field) ||
diagnostic.labels.some((label) => label.message.includes(field)),
true,
);
// New authoring failures must be anchored in the supplied value, not the
// much longer schema source, including relative imported recipes.
if (value !== "42") {
const length = new TextEncoder().encode(
expectedPath === "main.dcdl" ? invalidContent : recipe,
).length;
assertEquals(
diagnostic.span.end_byte > diagnostic.span.start_byte &&
diagnostic.span.end_byte <= length,
true,
);
assertEquals(
diagnostic.labels.every((label) => label.span.end_byte <= length),
true,
);
}
}
for (const field of ["scope", "delegation_scope"]) {
for (
const [prefix, label] of [["int", "intent"], ["deny", "deny_write"], [
"sym",
"symlink_policy",
]]
) {
const body =
`{ profile.entries = [{ profile.${field} = { ${prefix} } }]; } as WorkspaceConfigSchema`;
const cursor = body.lastIndexOf(prefix) + prefix.length;
const result = complete_current("main.dcdl", body, cursor, true) as {
items: Array<{ label: string }>;
};
assertEquals(
result.items.some((item) => item.label === label),
true,
`${field}.${label}`,
);
}
}
for (
const [recipe, expected] of [
['{ scope = "workspace_read"; delegation_scope = "workspace_write"; }', {
scope: "workspace_read",
delegation_scope: "workspace_write",
}],
['{ scope = "workspace_write"; delegation_scope = "workspace_read"; }', {
scope: "workspace_write",
delegation_scope: "workspace_read",
}],
[
'{ scope = { intent = "workspace_read"; }; delegation_scope = { intent = "workspace_write"; deny_write = ["private"]; symlink_policy = "resolved"; }; }',
{
scope: { intent: "workspace_read" },
delegation_scope: {
intent: "workspace_write",
deny_write: ["private"],
symlink_policy: "resolved",
},
},
],
] as const
) {
for (
const form of [
recipe,
'import "./scoped.dcdl"',
'(import "./scoped.dcdl") // { description = "patched"; }',
]
) {
const scopedContent = content.replace(
"profile = {};",
`profile = ${form};`,
);
const scopedTree = {
...tree,
entries: {
"main.dcdl": {
...tree.entries["main.dcdl"],
content: scopedContent,
content_digest: await digestText(scopedContent),
},
"scoped.dcdl": {
path: "scoped.dcdl",
content_type: "decodal",
content: recipe,
content_digest: await digestText(recipe),
},
},
};
assertEquals(
analyze_snapshot(scopedTree, "main.dcdl", undefined),
[],
form,
);
const result = evaluate_snapshot(
scopedTree,
valueContract,
) as typeof evaluated;
assertEquals(
result.projections[0].data_json.profile.entries[0].profile,
form.includes("patched")
? { ...expected, description: "patched" }
: expected,
);
}
}
const cases = JSON.parse(
await Deno.readTextFile(
new URL(
"../../../../resources/config-schema/profile-authoring-values.json",
import.meta.url,
),
),
) as Array<{ name: string; profile: Record<string, unknown> }>;
for (const fixture of cases) {
const recipe = fixtureDecodal(fixture.profile);
for (
const [form, patched] of [[recipe, false], [
'import "./recipe.dcdl"',
false,
], [
'(import "./recipe.dcdl") // { description = "patched"; }',
true,
]] as const
) {
const fixtureContent = content.replace(
"profile = {};",
`profile = ${form};`,
);
const fixtureTree = {
...tree,
entries: {
"main.dcdl": {
...tree.entries["main.dcdl"],
content: fixtureContent,
content_digest: await digestText(fixtureContent),
},
"recipe.dcdl": {
path: "recipe.dcdl",
content_type: "decodal",
content: recipe,
content_digest: await digestText(recipe),
},
},
};
assertEquals(
analyze_snapshot(fixtureTree, "main.dcdl", undefined),
[],
`${fixture.name}: ${form}`,
);
const result = evaluate_snapshot(
fixtureTree,
valueContract,
) as typeof evaluated;
assertEquals(
result.projections[0].data_json.profile.entries[0].profile,
patched
? { ...fixture.profile, description: "patched" }
: fixture.profile,
);
}
}
for (
const [path, prefix, label] of [
["compaction", "reta", "retained_tokens"],
["compaction", "prune_min", "prune_min_savings"],
["compaction", "req", "request"],
["compaction", "wor", "worker"],
["compaction", "compact_ret", "compact_retained_tokens"],
["feature.memory.extraction", "reas", "reasoning"],
["feature.subjektiv.extraction", "reas", "reasoning"],
]
) {
const body =
`{ profile.entries = [{ profile.${path} = { ${prefix} } }]; } as WorkspaceConfigSchema`;
const cursor = body.lastIndexOf(prefix) + prefix.length;
const result = complete_current("main.dcdl", body, cursor, true) as {
items: Array<{ label: string }>;
};
assertEquals(
result.items.some((item) => item.label === label),
true,
`${path}.${label}`,
);
}
// Neither completion nor diagnostic shape checking changes the saved value.
assertEquals(evaluate_snapshot(tree, valueContract), evaluated);
});