Instrument and improve incremental workspace checks
Profile source capture, Nix evaluation/realization, resource/query checking, and implementation builds without putting timings into immutable outputs. Keep modular repositories; bound independent capture work, snapshot jj once per observation, and retain final concurrent-edit and Git completeness checks. Compose exact resource/closure/frontend/toolchain checks as memoized Nix derivations. Preserve whole-workspace validation and the full compiler path when no checked dependency is supplied. Share canonical Nixpkgs by content, index workspace build contexts once, and narrow lock/driver/compiler inputs with conservative complete-source fallback. Batch React witness checks only when distinct source closures cannot share ambient declarations; otherwise run the original independent TypeScript checks. Seed local authoring toolchains with exact canonical fetch identities when they match the selected inputs; retain store-path inputs for overrides. Add generic correctness checks rather than permanent Reader timing/content fixtures. Verify actual Reader edits and rejection/recovery in a private workbench, preserving the original user's workbench and runtime. Query checking currently caches at resource/closure boundaries, not individual query semantic dependency boundaries. Template helper pins and reproducible fixture snapshots follow in a separate publication change.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { readFile, realpath } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { profile } from "./profile.js";
|
||||
import { loadQxSources, resolveQxSources } from "./source-loader.js";
|
||||
import { compileQuery, compileRepositoryQuery } from "../query/compile.js";
|
||||
import type { QueryDeclaration } from "../query/types.js";
|
||||
@@ -43,6 +44,15 @@ export type CapabilityRepositoryResolver = (
|
||||
kind: LockedResource["kind"],
|
||||
) => Promise<CapabilityRepositorySnapshot>;
|
||||
|
||||
/** Already checked outputs of this compiler, composed by the Nix build DAG.
|
||||
* Source capture/check reports never grant this authority. */
|
||||
export type CheckedResourceResolver = (
|
||||
kind: LockedResource["kind"],
|
||||
source: GitSource,
|
||||
lock: QuixosRepositoryLock,
|
||||
dependencies: ReadonlyMap<string, ResolvedCapabilityResource>,
|
||||
) => Promise<CapabilityResource | undefined>;
|
||||
|
||||
/** An explicitly selected build frontend supplies ordinary query sources. The
|
||||
* assembler never chooses a frontend by inspecting an interface/contract ID.
|
||||
* Generated sources go through the same query and imported-fragment checks. */
|
||||
@@ -221,7 +231,12 @@ const createResourceGraphResolver = (
|
||||
quixosCommit: string,
|
||||
resolveResource: CapabilityRepositoryResolver,
|
||||
generateQueries?: PackageQueryGenerator,
|
||||
checkedResource?: CheckedResourceResolver,
|
||||
) => {
|
||||
const graphStarted = performance.now();
|
||||
let checkedResources = 0,
|
||||
reusedResources = 0,
|
||||
checkedQueries = 0;
|
||||
const resolved = new Map<string, Promise<ResolvedCapabilityResource>>();
|
||||
const active: string[] = [];
|
||||
|
||||
@@ -275,6 +290,30 @@ const createResourceGraphResolver = (
|
||||
};
|
||||
}
|
||||
const dependencyClosure = resourceClosure(directPairs.map(([, node]) => node));
|
||||
const dependencies = new Map(
|
||||
directPairs.map(([dependency, node]) => [bindingKey(dependency.kind, dependency.binding), node]),
|
||||
);
|
||||
const checked = await checkedResource?.(locked.kind, locked.source, lockResult.lock, dependencies);
|
||||
if (checked) {
|
||||
if (
|
||||
checked.kind !== locked.kind ||
|
||||
checked.revision.source.repository !== locked.source.repository ||
|
||||
checked.revision.source.commit !== locked.source.commit
|
||||
)
|
||||
throw new Error("Checked resource identity mismatch");
|
||||
assertImportsMatchLock("Checked resource", checked.imports, lockResult.lock.resources);
|
||||
reusedResources++;
|
||||
return {
|
||||
key,
|
||||
kind: locked.kind,
|
||||
source: locked.source,
|
||||
directory: snapshot.directory,
|
||||
lock: lockResult.lock,
|
||||
resource: structuredClone(checked),
|
||||
dependencies,
|
||||
};
|
||||
}
|
||||
const checkStarted = performance.now();
|
||||
const environment = environmentFor(directPairs, dependencyClosure);
|
||||
const manifestName = locked.kind === "interface" ? "interface.qx" : "package.qx";
|
||||
const manifestPath = path.join(snapshot.directory, manifestName);
|
||||
@@ -399,6 +438,15 @@ const createResourceGraphResolver = (
|
||||
compiled.resource.revision.migrationCatalog = catalog;
|
||||
}
|
||||
}
|
||||
checkedResources++;
|
||||
const queries =
|
||||
compiled.resource.kind === "package" ? (compiled.resource.revision.checkedQueries?.length ?? 0) : 0;
|
||||
checkedQueries += queries;
|
||||
profile("resource-check", checkStarted, {
|
||||
kind: locked.kind,
|
||||
resource: compiled.resource.revision.displayName,
|
||||
queries,
|
||||
});
|
||||
return {
|
||||
key,
|
||||
kind: locked.kind,
|
||||
@@ -420,7 +468,11 @@ const createResourceGraphResolver = (
|
||||
|
||||
return {
|
||||
visit,
|
||||
nodes: async () => await Promise.all(resolved.values()),
|
||||
nodes: async () => {
|
||||
const nodes = await Promise.all(resolved.values());
|
||||
profile("resource-graph", graphStarted, { checkedResources, reusedResources, checkedQueries });
|
||||
return nodes;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -430,6 +482,7 @@ export const compileCapabilityResourceRepository = async (options: {
|
||||
source: GitSource;
|
||||
resolveResource: CapabilityRepositoryResolver;
|
||||
generateQueries?: PackageQueryGenerator;
|
||||
checkedResource?: CheckedResourceResolver;
|
||||
}): Promise<CompiledCapabilityResourceRepository> => {
|
||||
const lockResult = await loadQuixosLock(path.join(options.rootDirectory, "quixos.lock"));
|
||||
if (!lockResult.ok) {
|
||||
@@ -439,6 +492,7 @@ export const compileCapabilityResourceRepository = async (options: {
|
||||
lockResult.lock.quixos.commit,
|
||||
options.resolveResource,
|
||||
options.generateQueries,
|
||||
options.checkedResource,
|
||||
);
|
||||
const root = await resolver.visit(
|
||||
{
|
||||
@@ -466,6 +520,7 @@ export const compileWorkspaceRepository = async (options: {
|
||||
/** An editor's proposed source snapshot; locks and dependency revisions remain exact. */
|
||||
readSource?: (name: string) => Promise<string>;
|
||||
generateQueries?: PackageQueryGenerator;
|
||||
checkedResource?: CheckedResourceResolver;
|
||||
}): Promise<CompiledWorkspaceRepository> => {
|
||||
const rootLockResult = await loadQuixosLock(path.join(options.rootDirectory, "quixos.lock"));
|
||||
if (!rootLockResult.ok) {
|
||||
@@ -476,6 +531,7 @@ export const compileWorkspaceRepository = async (options: {
|
||||
rootLock.quixos.commit,
|
||||
options.resolveResource,
|
||||
options.generateQueries,
|
||||
options.checkedResource,
|
||||
);
|
||||
|
||||
const directPairs: Array<[LockedResource, ResolvedCapabilityResource]> = [];
|
||||
|
||||
Reference in New Issue
Block a user