@interf/compiler 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +6 -7
  2. package/dist/commands/compile-controller.js +3 -3
  3. package/dist/commands/test-flow.js +5 -16
  4. package/dist/lib/agent-shells.js +1 -1
  5. package/dist/lib/{workflow-abi.d.ts → builtin-compiled-workflow.d.ts} +2 -2
  6. package/dist/lib/{workflow-abi.js → builtin-compiled-workflow.js} +2 -5
  7. package/dist/lib/compiled-compile.js +2 -2
  8. package/dist/lib/compiled-paths.d.ts +0 -2
  9. package/dist/lib/compiled-paths.js +5 -13
  10. package/dist/lib/compiled-raw.d.ts +2 -2
  11. package/dist/lib/compiled-schema.d.ts +2 -2
  12. package/dist/lib/compiled-schema.js +2 -2
  13. package/dist/lib/interf-detect.d.ts +0 -1
  14. package/dist/lib/interf-detect.js +7 -18
  15. package/dist/lib/interf.d.ts +1 -1
  16. package/dist/lib/interf.js +1 -1
  17. package/dist/lib/local-workflows.js +1 -1
  18. package/dist/lib/project-paths.d.ts +2 -4
  19. package/dist/lib/project-paths.js +13 -10
  20. package/dist/lib/runtime-prompt.js +1 -3
  21. package/dist/lib/runtime-reconcile.js +3 -14
  22. package/dist/lib/runtime-runs.js +2 -87
  23. package/dist/lib/schema.d.ts +33 -40
  24. package/dist/lib/schema.js +17 -104
  25. package/dist/lib/source-config.js +21 -22
  26. package/dist/lib/state-health.js +4 -2
  27. package/dist/lib/state-io.js +2 -110
  28. package/dist/lib/state-view.js +2 -2
  29. package/dist/lib/summarize-plan.js +1 -5
  30. package/dist/lib/test-paths.js +12 -3
  31. package/dist/lib/test-sandbox.js +4 -17
  32. package/dist/lib/test-specs.js +1 -1
  33. package/dist/lib/validate-compiled.js +4 -2
  34. package/dist/lib/validate.d.ts +2 -0
  35. package/dist/lib/validate.js +27 -12
  36. package/dist/lib/workflow-definitions.d.ts +3 -2
  37. package/dist/lib/workflow-definitions.js +9 -2
  38. package/dist/lib/workflow-primitives.d.ts +2 -0
  39. package/dist/lib/workflow-primitives.js +5 -0
  40. package/package.json +6 -6
  41. package/dist/lib/compiled-layout.d.ts +0 -2
  42. package/dist/lib/compiled-layout.js +0 -60
package/README.md CHANGED
@@ -31,7 +31,6 @@ A maintained public test run in this repo uses checks like this:
31
31
  "datasets": [
32
32
  {
33
33
  "name": "cbre-chart-sanity",
34
- "path": ".",
35
34
  "about": "Bristol historical take-up and availability chart lookup.",
36
35
  "checks": [
37
36
  {
@@ -65,7 +64,7 @@ A recent maintained internal run on the CBRE chart sanity dataset produced:
65
64
 
66
65
  Use `interf test` on your own dataset to measure files as-is versus the compiled dataset on the same checks.
67
66
 
68
- Each dataset keeps one latest comparison under `interf/<dataset>/tests/latest.json`. Target-specific runs stay under `interf/<dataset>/tests/file-as-is/runs/` and `interf/<dataset>/tests/compiled/runs/`.
67
+ Each dataset keeps one latest comparison under `interf/tests/<dataset>/latest.json`. Target-specific runs stay under `interf/tests/<dataset>/file-as-is/runs/` and `interf/tests/<dataset>/compiled/runs/`.
69
68
 
70
69
  ## Quick Start
71
70
 
@@ -104,8 +103,8 @@ After setup, the project root stays simple:
104
103
 
105
104
  - `interf.json` at the root holds your saved dataset entries and truth checks
106
105
  - `interf/` is created only when Interf has artifacts to save
107
- - `interf/<dataset>/compiled/` is the compiled dataset
108
- - `interf/<dataset>/tests/` is the saved comparison history for that dataset
106
+ - `interf/<dataset>/` is the compiled dataset
107
+ - `interf/tests/<dataset>/` is the saved comparison history for that dataset
109
108
 
110
109
  A compiled dataset is a folder on top of your dataset. It includes:
111
110
 
@@ -143,7 +142,7 @@ interf doctor
143
142
 
144
143
  ## What `interf test` Does
145
144
 
146
- By default, if a compiled dataset exists, it runs both sides and saves one latest comparison under `interf/<dataset>/tests/latest.json`.
145
+ By default, if a compiled dataset exists, it runs both sides and saves one latest comparison under `interf/tests/<dataset>/latest.json`.
147
146
 
148
147
  You can also select one or more detected local agents in the CLI and compare them in one table.
149
148
 
@@ -153,7 +152,7 @@ For live runs:
153
152
  - compiled-dataset tests execute from a copied compiled sandbox with embedded sanitized `raw/`
154
153
  - both sides use the same saved truth checks from `interf.json`
155
154
  - neither sandbox includes the project control plane
156
- - detailed dataset-visible runs are kept under `interf/<dataset>/tests/file-as-is/runs/` and `interf/<dataset>/tests/compiled/runs/`
155
+ - detailed dataset-visible runs are kept under `interf/tests/<dataset>/file-as-is/runs/` and `interf/tests/<dataset>/compiled/runs/`
157
156
  - local detailed target runs and preserved sandboxes stay under `.interf/tests/targets/`
158
157
  - failed test sandboxes are kept automatically
159
158
  - `interf test --keep-sandboxes` keeps every sandbox, even successful ones
@@ -176,7 +175,7 @@ Add another only when you want a different dataset folder, focus, or set of trut
176
175
  Why add another:
177
176
 
178
177
  - it keeps a separate set of truth checks
179
- - it gives that dataset its own compiled output under `interf/<dataset>/compiled/`
178
+ - it gives that dataset its own compiled output under `interf/<dataset>/`
180
179
  - it lets you test that dataset separately
181
180
 
182
181
  ## Advanced: Compile Loops
@@ -4,7 +4,7 @@ import { dirname, join } from "node:path";
4
4
  import chalk from "chalk";
5
5
  import { readInterfConfig } from "../lib/interf.js";
6
6
  import { resetCompiledGeneratedState } from "../lib/compiled-reset.js";
7
- import { formatActiveCompiledWorkflowStageStep, resolveCompiledWorkflowFromConfig, } from "../lib/workflow-definitions.js";
7
+ import { formatActiveCompiledWorkflowStageStep, resolveRequiredCompiledWorkflowFromConfig, } from "../lib/workflow-definitions.js";
8
8
  import { resolveDatasetCompileMaxAttempts, resolveDatasetCompileMaxLoops, } from "../lib/source-config.js";
9
9
  import { runWorkflowImprovementLoop } from "../lib/workflow-improvement.js";
10
10
  import { stageExecutionShellsRoot, workflowPackagePathForCompiled, } from "../lib/compiled-paths.js";
@@ -12,7 +12,7 @@ import { readCompiledSchemaFile } from "../lib/compiled-schema.js";
12
12
  import { compileCompiledWithReporter } from "./compiled-flow.js";
13
13
  import { printSavedTestOutcome, questionPassRate, runSavedCompiledTest, } from "./test-flow.js";
14
14
  function printCompileFailure(compiledPath, failedStage) {
15
- const workflowId = resolveCompiledWorkflowFromConfig(readInterfConfig(compiledPath));
15
+ const workflowId = resolveRequiredCompiledWorkflowFromConfig(readInterfConfig(compiledPath), `.interf/interf.json for ${compiledPath}`);
16
16
  const failedStageLabel = formatActiveCompiledWorkflowStageStep(compiledPath, workflowId, failedStage ?? "compile");
17
17
  console.log(chalk.red(` ${failedStageLabel} failed.`));
18
18
  }
@@ -362,7 +362,7 @@ export async function runConfiguredCompiledCompile(options) {
362
362
  const improvement = await runWorkflowImprovementLoop({
363
363
  executor: options.executor,
364
364
  compiledPath: options.compiledPath,
365
- workflowId: resolveCompiledWorkflowFromConfig(readInterfConfig(options.compiledPath)),
365
+ workflowId: resolveRequiredCompiledWorkflowFromConfig(readInterfConfig(options.compiledPath), `.interf/interf.json for ${options.compiledPath}`),
366
366
  compiledConfig,
367
367
  runId: improvementRunId,
368
368
  loopIndex,
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { createRawTestTarget, createCompiledTestTarget, runTargetTestsAuto, saveTargetTestRun, } from "../lib/test.js";
5
5
  import { buildTestSpecFromSourceFolderConfig, buildTestSpecFromCompiledDatasetConfig, resolveSourceDatasetPath, } from "../lib/source-config.js";
6
- import { datasetArtifactRoot, datasetLatestTestStatePath, datasetLatestTestSummaryPath, datasetTestRunsRoot, } from "../lib/project-paths.js";
6
+ import { datasetLatestTestStatePath, datasetLatestTestSummaryPath, normalizeDatasetTestRunId, datasetTestRunPath, datasetTestRunsRoot, datasetTestsRoot, } from "../lib/project-paths.js";
7
7
  import { testRootForCompiled } from "../lib/compiled-paths.js";
8
8
  import { readJsonFileWithSchema } from "../lib/parse.js";
9
9
  import { TestRunComparisonSchema } from "../lib/schema.js";
@@ -29,21 +29,10 @@ function summarizeSavedTestOutcome(label, outcome) {
29
29
  target: outcome.target,
30
30
  };
31
31
  }
32
- function normalizeTestRunId(input) {
33
- return input
34
- .toLowerCase()
35
- .trim()
36
- .replace(/[^a-z0-9]+/g, "-")
37
- .replace(/^-+|-+$/g, "")
38
- .slice(0, 80);
39
- }
40
- function datasetRunPathForTarget(projectPath, datasetName, target, generatedAt, runId, runSuffix) {
41
- return join(datasetTestRunsRoot(projectPath, datasetName, target), `${generatedAt.replace(/[:.]/g, "-")}-${runId}${runSuffix ? `-${normalizeTestRunId(runSuffix)}` : ""}.json`);
42
- }
43
32
  function writeDatasetTargetRun(options) {
44
33
  const dirPath = datasetTestRunsRoot(options.projectPath, options.datasetName, options.target);
45
34
  mkdirSync(dirPath, { recursive: true });
46
- const runPath = datasetRunPathForTarget(options.projectPath, options.datasetName, options.target, options.generatedAt, options.runId, options.runSuffix);
35
+ const runPath = datasetTestRunPath(options.projectPath, options.datasetName, options.target, options.generatedAt, options.runId, options.runSuffix);
47
36
  writeFileSync(runPath, `${JSON.stringify(options.payload, null, 2)}\n`);
48
37
  return runPath;
49
38
  }
@@ -354,7 +343,7 @@ export async function runSavedRawTest(options) {
354
343
  const run = await runTargetTestsAuto(datasetSourcePath, spec, [target], {
355
344
  executor,
356
345
  preserveSandboxes: options.preserveSandboxes ?? "on-failure",
357
- artifactRootPath: datasetArtifactRoot(options.sourcePath, options.datasetConfig.name),
346
+ artifactRootPath: datasetTestsRoot(options.sourcePath, options.datasetConfig.name),
358
347
  });
359
348
  const result = run.results[0];
360
349
  if (!result)
@@ -364,7 +353,7 @@ export async function runSavedRawTest(options) {
364
353
  datasetName: options.datasetConfig.name,
365
354
  target: "file-as-is",
366
355
  generatedAt: run.generated_at,
367
- runId: normalizeTestRunId(spec.id),
356
+ runId: normalizeDatasetTestRunId(spec.id),
368
357
  runSuffix: options.runSuffix,
369
358
  payload: run,
370
359
  });
@@ -413,7 +402,7 @@ export async function runSavedCompiledTest(options) {
413
402
  datasetName: options.datasetConfig.name,
414
403
  target: "compiled",
415
404
  generatedAt: run.generated_at,
416
- runId: normalizeTestRunId(spec.id),
405
+ runId: normalizeDatasetTestRunId(spec.id),
417
406
  runSuffix: options.runSuffix,
418
407
  payload: run,
419
408
  });
@@ -70,7 +70,7 @@ export function renderCompiledAgents(compiledPath, name, workflowId, about, opti
70
70
  "- Compiled output zones are declared in `.interf/workflow/compiled.schema.json`.",
71
71
  ...zoneLines,
72
72
  "- `.interf/runtime/` holds CLI-owned runtime artifacts.",
73
- "- `.interf/tests/` holds saved raw-vs-compiled test comparisons for this compiled dataset.",
73
+ "- `.interf/tests/` mirrors the latest dataset-level comparison and keeps detailed target runs plus preserved sandboxes.",
74
74
  "- `.interf/tests/targets/` holds detailed raw and compiled target runs plus preserved test sandboxes.",
75
75
  "",
76
76
  "## Manual query rules",
@@ -1,7 +1,6 @@
1
+ import { COMPILED_ZONE_KINDS, type CompiledZoneKind } from "./workflow-primitives.js";
1
2
  export declare const COMPILED_CONTRACT_TYPES: readonly ["compiled-file-evidence", "compiled-knowledge-structure", "compiled-query-shape"];
2
3
  export type CompiledContractType = typeof COMPILED_CONTRACT_TYPES[number];
3
- export declare const COMPILED_ZONE_KINDS: readonly ["directory", "file", "runtime"];
4
- export type CompiledZoneKind = typeof COMPILED_ZONE_KINDS[number];
5
4
  export declare const COMPILED_CONTRACT_FAMILY_METADATA: {
6
5
  readonly "compiled-file-evidence": {
7
6
  readonly order: 0;
@@ -127,3 +126,4 @@ export declare function requiredCompiledZoneOwners<TStage extends {
127
126
  id: string;
128
127
  writes: readonly string[];
129
128
  }>(stages: readonly TStage[], zoneId: BuiltinCompiledZoneId): string[];
129
+ export { COMPILED_ZONE_KINDS };
@@ -1,13 +1,9 @@
1
+ import { COMPILED_ZONE_KINDS } from "./workflow-primitives.js";
1
2
  export const COMPILED_CONTRACT_TYPES = [
2
3
  "compiled-file-evidence",
3
4
  "compiled-knowledge-structure",
4
5
  "compiled-query-shape",
5
6
  ];
6
- export const COMPILED_ZONE_KINDS = [
7
- "directory",
8
- "file",
9
- "runtime",
10
- ];
11
7
  export const COMPILED_CONTRACT_FAMILY_METADATA = {
12
8
  "compiled-file-evidence": {
13
9
  order: 0,
@@ -154,3 +150,4 @@ export function requiredCompiledZoneOwners(stages, zoneId) {
154
150
  .filter((stage) => stage.writes.includes(zoneId))
155
151
  .map((stage) => stage.id)));
156
152
  }
153
+ export { COMPILED_ZONE_KINDS };
@@ -5,7 +5,7 @@ import { reconcileCompiledStageRun, } from "./runtime-reconcile.js";
5
5
  import { refreshCompiledArtifacts, } from "./state.js";
6
6
  import { buildRuntimeStageContract, } from "./runtime.js";
7
7
  import { validateWorkflowPackage } from "./local-workflows.js";
8
- import { formatActiveCompiledWorkflowStageStep, getActiveCompiledStagePolicyNotes, getActiveCompiledWorkflow, resolveCompiledWorkflowFromConfig, resolveActiveCompiledStageAcceptance, } from "./workflow-definitions.js";
8
+ import { formatActiveCompiledWorkflowStageStep, getActiveCompiledStagePolicyNotes, getActiveCompiledWorkflow, resolveRequiredCompiledWorkflowFromConfig, resolveActiveCompiledStageAcceptance, } from "./workflow-definitions.js";
9
9
  import { validateCompiledStage, validateCompiledWorkflow, } from "./validate.js";
10
10
  import { buildLocalSkillContractExtension, buildStageInstructions, reportBlankLine, reportLine, reportValidationFailure, workflowCompileStageDirectory, } from "./workflow-helpers.js";
11
11
  import { executeValidatedStage, } from "./workflow-stage-runner.js";
@@ -16,7 +16,7 @@ import { discoverSourceFiles } from "./discovery.js";
16
16
  import { listFilesRecursive } from "./filesystem.js";
17
17
  export function resolveCompiledContext(compiledPath) {
18
18
  const config = readInterfConfig(compiledPath);
19
- const workflowId = resolveCompiledWorkflowFromConfig(config);
19
+ const workflowId = resolveRequiredCompiledWorkflowFromConfig(config, `.interf/interf.json for ${compiledPath}`);
20
20
  return {
21
21
  compiledName: config?.name ?? "compiled",
22
22
  sourcePath: resolveSourceFolderPath(compiledPath, config),
@@ -18,9 +18,7 @@ export declare function compiledInterfRoot(compiledPath: string): string;
18
18
  export declare function compiledInterfConfigPath(compiledPath: string): string;
19
19
  export declare function workflowPackagePathForCompiled(compiledPath: string): string;
20
20
  export declare function testRootForCompiled(compiledPath: string): string;
21
- export declare function testRunsRootForCompiled(compiledPath: string): string;
22
21
  export declare function testTargetsRootForCompiled(compiledPath: string): string;
23
- export declare function latestTestComparisonPathForCompiled(compiledPath: string): string;
24
22
  export declare function stageExecutionShellsRoot(compiledPath: string): string;
25
23
  export declare function workflowImprovementLoopsRoot(compiledPath: string): string;
26
24
  export declare function workflowImprovementRunRoot(compiledPath: string, runId: string): string;
@@ -31,15 +31,9 @@ export function workflowPackagePathForCompiled(compiledPath) {
31
31
  export function testRootForCompiled(compiledPath) {
32
32
  return join(compiledInterfRoot(compiledPath), COMPILED_TEST_DIR);
33
33
  }
34
- export function testRunsRootForCompiled(compiledPath) {
35
- return join(testRootForCompiled(compiledPath), "runs");
36
- }
37
34
  export function testTargetsRootForCompiled(compiledPath) {
38
35
  return join(testRootForCompiled(compiledPath), COMPILED_TEST_TARGETS_DIR);
39
36
  }
40
- export function latestTestComparisonPathForCompiled(compiledPath) {
41
- return join(testRootForCompiled(compiledPath), "latest.json");
42
- }
43
37
  export function stageExecutionShellsRoot(compiledPath) {
44
38
  return join(compiledRuntimeRoot(compiledPath), "execution-shells");
45
39
  }
@@ -91,14 +85,12 @@ export function compiledRuntimeStageContractPath(compiledPath) {
91
85
  export function resolveSourceControlPathForCompiled(compiledPath) {
92
86
  let cursor = resolve(compiledPath);
93
87
  while (true) {
94
- if (basename(cursor) === "compiled") {
95
- const datasetRoot = dirname(cursor);
96
- const interfRoot = dirname(datasetRoot);
97
- if (basename(interfRoot) === "interf") {
98
- return dirname(interfRoot);
99
- }
100
- }
101
88
  const parent = dirname(cursor);
89
+ if (basename(parent) === "interf" &&
90
+ basename(cursor) !== "tests" &&
91
+ basename(cursor) !== "workflows") {
92
+ return dirname(parent);
93
+ }
102
94
  if (parent === cursor)
103
95
  break;
104
96
  cursor = parent;
@@ -9,6 +9,7 @@ export declare function resolveCompiledRawPath(compiledPath: string, config?: {
9
9
  [x: string]: unknown;
10
10
  type: "compiled";
11
11
  name: string;
12
+ workflow: string;
12
13
  checks: {
13
14
  question: string;
14
15
  id?: string | undefined;
@@ -24,11 +25,10 @@ export declare function resolveCompiledRawPath(compiledPath: string, config?: {
24
25
  }[];
25
26
  source: {
26
27
  path: string;
28
+ dataset_path: string;
27
29
  control_path?: string | undefined;
28
- dataset_path?: string | undefined;
29
30
  };
30
31
  about?: string | undefined;
31
- workflow?: string | undefined;
32
32
  max_attempts?: number | undefined;
33
33
  max_loops?: number | undefined;
34
34
  workflow_origin?: {
@@ -1,10 +1,10 @@
1
- import { type BuiltinCompiledZoneId } from "./workflow-abi.js";
1
+ import { type BuiltinCompiledZoneId } from "./builtin-compiled-workflow.js";
2
2
  import { type WorkflowCompiledSchema, type WorkflowCompiledZone, type WorkflowZoneId } from "./schema.js";
3
3
  export interface WorkflowSchemaStageLike {
4
4
  id: string;
5
5
  writes: readonly string[];
6
6
  }
7
- export { BUILTIN_COMPILED_ZONE_IDS } from "./workflow-abi.js";
7
+ export { BUILTIN_COMPILED_ZONE_IDS } from "./builtin-compiled-workflow.js";
8
8
  export declare const COMPILED_SCHEMA_FILE = "compiled.schema.json";
9
9
  export declare function compiledSchemaFilePath(rootPath: string): string;
10
10
  export declare function compiledSchemaRelativePath(): string;
@@ -1,9 +1,9 @@
1
1
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { readJsonFileWithSchema } from "./parse.js";
4
- import { BUILTIN_COMPILED_ZONE_IDS, listBuiltinCompiledZoneSpecs, requiredCompiledZoneOwners, } from "./workflow-abi.js";
4
+ import { BUILTIN_COMPILED_ZONE_IDS, listBuiltinCompiledZoneSpecs, requiredCompiledZoneOwners, } from "./builtin-compiled-workflow.js";
5
5
  import { WorkflowCompiledSchemaSchema, } from "./schema.js";
6
- export { BUILTIN_COMPILED_ZONE_IDS } from "./workflow-abi.js";
6
+ export { BUILTIN_COMPILED_ZONE_IDS } from "./builtin-compiled-workflow.js";
7
7
  export const COMPILED_SCHEMA_FILE = "compiled.schema.json";
8
8
  const BUILTIN_COMPILED_ZONE_SPEC_BY_ID = new Map(listBuiltinCompiledZoneSpecs().map((zone) => [zone.id, zone]));
9
9
  export function compiledSchemaFilePath(rootPath) {
@@ -10,7 +10,6 @@ export declare const WORKFLOW_CONTAINER_NAME = "workflows";
10
10
  export declare const TEST_CONTAINER_NAME = "tests";
11
11
  export declare const INTERF_CONFIG_FILE = "interf.json";
12
12
  export declare const WORKFLOW_PACKAGE_DIR = "workflow";
13
- export declare function prepareCompiledLayout(dirPath: string): boolean;
14
13
  export declare function readInterfConfig(dirPath: string): InterfConfig | null;
15
14
  export declare function hasSourceFolderInput(config: InterfConfig | null | undefined): config is InterfConfig & {
16
15
  source: {
@@ -4,7 +4,6 @@ import { warnInterf } from "./logger.js";
4
4
  import { readJsonFileUnchecked } from "./parse.js";
5
5
  import { compiledCompiledPathForDataset, projectInterfRoot, } from "./project-paths.js";
6
6
  import { resolveSourceControlPathForCompiled, compiledInterfConfigPath, } from "./compiled-paths.js";
7
- import { normalizeLegacyCompiledLayout, compiledNeedsLegacyLayoutNormalization, } from "./compiled-layout.js";
8
7
  import { InterfConfigSchema, } from "./schema.js";
9
8
  import { assertPathWithinRoot } from "./util.js";
10
9
  export const INTERF_CONTAINER_NAME = "interf";
@@ -12,12 +11,6 @@ export const WORKFLOW_CONTAINER_NAME = "workflows";
12
11
  export const TEST_CONTAINER_NAME = "tests";
13
12
  export const INTERF_CONFIG_FILE = "interf.json";
14
13
  export const WORKFLOW_PACKAGE_DIR = "workflow";
15
- export function prepareCompiledLayout(dirPath) {
16
- if (!compiledNeedsLegacyLayoutNormalization(dirPath)) {
17
- return false;
18
- }
19
- return normalizeLegacyCompiledLayout(dirPath);
20
- }
21
14
  export function readInterfConfig(dirPath) {
22
15
  const configPath = compiledInterfConfigPath(dirPath);
23
16
  if (!existsSync(configPath))
@@ -41,7 +34,6 @@ export function hasSourceFolderInput(config) {
41
34
  return typeof config?.source?.path === "string" && config.source.path.length > 0;
42
35
  }
43
36
  export function detectInterf(cwd) {
44
- prepareCompiledLayout(cwd);
45
37
  const config = readInterfConfig(cwd);
46
38
  if (config)
47
39
  return { path: cwd, config };
@@ -58,7 +50,6 @@ export function resolveCompiled(cwd) {
58
50
  };
59
51
  }
60
52
  export function resolveSourceFolderPath(compiledPath, config = null) {
61
- prepareCompiledLayout(compiledPath);
62
53
  const resolvedConfig = config ?? readInterfConfig(compiledPath);
63
54
  if (hasSourceFolderInput(resolvedConfig)) {
64
55
  return assertPathWithinRoot(compiledPath, resolve(compiledPath, resolvedConfig.source.path), "Compiled raw source path");
@@ -66,17 +57,15 @@ export function resolveSourceFolderPath(compiledPath, config = null) {
66
57
  return resolve(compiledPath, "raw");
67
58
  }
68
59
  export function resolveSourceControlPath(compiledPath) {
69
- prepareCompiledLayout(compiledPath);
70
60
  return resolveSourceControlPathForCompiled(compiledPath);
71
61
  }
72
62
  export function resolveSourceInputPath(compiledPath) {
73
- prepareCompiledLayout(compiledPath);
74
- const projectPath = resolveSourceControlPathForCompiled(compiledPath);
75
63
  const config = readInterfConfig(compiledPath);
76
64
  if (typeof config?.source?.dataset_path === "string" && config.source.dataset_path.length > 0) {
65
+ const projectPath = resolveSourceControlPathForCompiled(compiledPath);
77
66
  return assertPathWithinRoot(projectPath, resolve(compiledPath, config.source.dataset_path), "Dataset source path");
78
67
  }
79
- return projectPath;
68
+ throw new Error(`Compiled dataset is missing source.dataset_path in ${compiledInterfConfigPath(compiledPath)}.`);
80
69
  }
81
70
  export function listCompiledDatasetsForSourceFolder(sourcePath) {
82
71
  const interfRoot = projectInterfRoot(sourcePath);
@@ -91,11 +80,12 @@ export function listCompiledDatasetsForSourceFolder(sourcePath) {
91
80
  return [];
92
81
  }
93
82
  return readdirSync(interfRoot)
94
- .filter((entry) => !entry.startsWith(".") && entry !== WORKFLOW_CONTAINER_NAME)
83
+ .filter((entry) => !entry.startsWith(".") &&
84
+ entry !== WORKFLOW_CONTAINER_NAME &&
85
+ entry !== TEST_CONTAINER_NAME)
95
86
  .map((entry) => compiledCompiledPathForDataset(sourcePath, entry))
96
87
  .filter((compiledPath) => existsSync(compiledPath))
97
88
  .map((compiledPath) => {
98
- prepareCompiledLayout(compiledPath);
99
89
  const config = readInterfConfig(compiledPath);
100
90
  return config ? { path: compiledPath, config } : null;
101
91
  })
@@ -112,7 +102,7 @@ export function assertCompiledContainer(sourcePath) {
112
102
  if (entry.startsWith("."))
113
103
  return false;
114
104
  const entryPath = join(interfRoot, entry);
115
- if (entry === WORKFLOW_CONTAINER_NAME) {
105
+ if (entry === WORKFLOW_CONTAINER_NAME || entry === TEST_CONTAINER_NAME) {
116
106
  try {
117
107
  return !statSync(entryPath).isDirectory();
118
108
  }
@@ -146,7 +136,7 @@ export function assertCompiledContainer(sourcePath) {
146
136
  const unexpectedEntries = readdirSync(containerPath).filter((entry) => {
147
137
  if (entry.startsWith("."))
148
138
  return false;
149
- if (entry === WORKFLOW_CONTAINER_NAME)
139
+ if (entry === WORKFLOW_CONTAINER_NAME || entry === TEST_CONTAINER_NAME)
150
140
  return false;
151
141
  const entryPath = join(containerPath, entry);
152
142
  try {
@@ -161,7 +151,6 @@ export function assertCompiledContainer(sourcePath) {
161
151
  if (!existsSync(compiledPath)) {
162
152
  return false;
163
153
  }
164
- prepareCompiledLayout(compiledPath);
165
154
  return !readInterfConfig(compiledPath);
166
155
  });
167
156
  if (unexpectedEntries.length > 0) {
@@ -1,4 +1,4 @@
1
- export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, INTERF_CONFIG_FILE, WORKFLOW_PACKAGE_DIR, prepareCompiledLayout, readInterfConfig, detectInterf, resolveCompiled, resolveSourceFolderPath, resolveSourceControlPath, resolveSourceInputPath, listCompiledDatasetsForSourceFolder, hasSourceFolderInput, assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
1
+ export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, INTERF_CONFIG_FILE, WORKFLOW_PACKAGE_DIR, readInterfConfig, detectInterf, resolveCompiled, resolveSourceFolderPath, resolveSourceControlPath, resolveSourceInputPath, listCompiledDatasetsForSourceFolder, hasSourceFolderInput, assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
2
2
  export type { InterfConfig, ResolvedCompiled } from "./interf-detect.js";
3
3
  export { ensureCompiledRawBinding, resolveCompiledRawPath, syncCompiledRawSnapshot, } from "./compiled-raw.js";
4
4
  export { refreshCompiledBootstrapGuidance, renderClaudeBootstrap, } from "./interf-bootstrap.js";
@@ -1,4 +1,4 @@
1
- export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, INTERF_CONFIG_FILE, WORKFLOW_PACKAGE_DIR, prepareCompiledLayout, readInterfConfig, detectInterf, resolveCompiled, resolveSourceFolderPath, resolveSourceControlPath, resolveSourceInputPath, listCompiledDatasetsForSourceFolder, hasSourceFolderInput, assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
1
+ export { INTERF_CONTAINER_NAME, WORKFLOW_CONTAINER_NAME, TEST_CONTAINER_NAME, INTERF_CONFIG_FILE, WORKFLOW_PACKAGE_DIR, readInterfConfig, detectInterf, resolveCompiled, resolveSourceFolderPath, resolveSourceControlPath, resolveSourceInputPath, listCompiledDatasetsForSourceFolder, hasSourceFolderInput, assertCompiledContainer, assertWritableTargetDir, assertCompiledName, } from "./interf-detect.js";
2
2
  export { ensureCompiledRawBinding, resolveCompiledRawPath, syncCompiledRawSnapshot, } from "./compiled-raw.js";
3
3
  export { refreshCompiledBootstrapGuidance, renderClaudeBootstrap, } from "./interf-bootstrap.js";
4
4
  export { createCompiled, defaultCompiledNameForSource, } from "./interf-scaffold.js";
@@ -6,7 +6,7 @@ import { isMarkdownFile } from "./util.js";
6
6
  import { listFilesRecursive } from "./filesystem.js";
7
7
  import { warnInterf } from "./logger.js";
8
8
  import { readJsonFileUnchecked, readJsonFileWithSchema } from "./parse.js";
9
- import { listBuiltinCompiledZoneSpecs, } from "./workflow-abi.js";
9
+ import { listBuiltinCompiledZoneSpecs, } from "./builtin-compiled-workflow.js";
10
10
  import { WorkflowCompilerApiSchema, RuntimeContractTypeSchema, RuntimeStageAcceptanceSchema, WorkflowStageZoneAccessSchema, WorkflowCompiledSchemaSchema, WorkflowIdPattern, } from "./schema.js";
11
11
  import { writeCompiledSchemaFile, compiledSchemaFilePath } from "./compiled-schema.js";
12
12
  const LocalWorkflowStageDefinitionSchema = z.object({
@@ -1,13 +1,11 @@
1
1
  export declare const PROJECT_INTERF_DIR = "interf";
2
- export declare const PROJECT_WORKFLOW_DIR = "workflows";
3
- export declare const PROJECT_COMPILED_DIR = "compiled";
4
2
  export declare const PROJECT_TESTS_DIR = "tests";
5
3
  export declare function projectInterfRoot(projectPath: string): string;
6
- export declare function projectWorkflowRoot(projectPath: string): string;
7
- export declare function datasetArtifactRoot(projectPath: string, datasetName: string): string;
8
4
  export declare function compiledCompiledPathForDataset(projectPath: string, datasetName: string): string;
9
5
  export declare function datasetTestsRoot(projectPath: string, datasetName: string): string;
10
6
  export type DatasetTestTargetLabel = "file-as-is" | "compiled";
11
7
  export declare function datasetTestRunsRoot(projectPath: string, datasetName: string, target: DatasetTestTargetLabel): string;
12
8
  export declare function datasetLatestTestStatePath(projectPath: string, datasetName: string): string;
13
9
  export declare function datasetLatestTestSummaryPath(projectPath: string, datasetName: string): string;
10
+ export declare function normalizeDatasetTestRunId(input: string): string;
11
+ export declare function datasetTestRunPath(projectPath: string, datasetName: string, target: DatasetTestTargetLabel, generatedAt: string, runId: string, runSuffix?: string | null): string;
@@ -1,22 +1,14 @@
1
1
  import { join } from "node:path";
2
2
  export const PROJECT_INTERF_DIR = "interf";
3
- export const PROJECT_WORKFLOW_DIR = "workflows";
4
- export const PROJECT_COMPILED_DIR = "compiled";
5
3
  export const PROJECT_TESTS_DIR = "tests";
6
4
  export function projectInterfRoot(projectPath) {
7
5
  return join(projectPath, PROJECT_INTERF_DIR);
8
6
  }
9
- export function projectWorkflowRoot(projectPath) {
10
- return join(projectInterfRoot(projectPath), PROJECT_WORKFLOW_DIR);
11
- }
12
- export function datasetArtifactRoot(projectPath, datasetName) {
13
- return join(projectInterfRoot(projectPath), datasetName);
14
- }
15
7
  export function compiledCompiledPathForDataset(projectPath, datasetName) {
16
- return join(datasetArtifactRoot(projectPath, datasetName), PROJECT_COMPILED_DIR);
8
+ return join(projectInterfRoot(projectPath), datasetName);
17
9
  }
18
10
  export function datasetTestsRoot(projectPath, datasetName) {
19
- return join(datasetArtifactRoot(projectPath, datasetName), PROJECT_TESTS_DIR);
11
+ return join(projectInterfRoot(projectPath), PROJECT_TESTS_DIR, datasetName);
20
12
  }
21
13
  export function datasetTestRunsRoot(projectPath, datasetName, target) {
22
14
  return join(datasetTestsRoot(projectPath, datasetName), target, "runs");
@@ -27,3 +19,14 @@ export function datasetLatestTestStatePath(projectPath, datasetName) {
27
19
  export function datasetLatestTestSummaryPath(projectPath, datasetName) {
28
20
  return join(datasetTestsRoot(projectPath, datasetName), "latest.md");
29
21
  }
22
+ export function normalizeDatasetTestRunId(input) {
23
+ return input
24
+ .toLowerCase()
25
+ .trim()
26
+ .replace(/[^a-z0-9]+/g, "-")
27
+ .replace(/^-+|-+$/g, "")
28
+ .slice(0, 80);
29
+ }
30
+ export function datasetTestRunPath(projectPath, datasetName, target, generatedAt, runId, runSuffix) {
31
+ return join(datasetTestRunsRoot(projectPath, datasetName, target), `${generatedAt.replace(/[:.]/g, "-")}-${runId}${runSuffix ? `-${normalizeDatasetTestRunId(runSuffix)}` : ""}.json`);
32
+ }
@@ -1,7 +1,5 @@
1
1
  export function buildStagePrompt(instructions, contractPath, statusLines) {
2
- const stageSkillDir = instructions.stage_skill_dir ||
3
- (instructions.bundled_skill?.split(/[\\/]/).filter(Boolean).pop()) ||
4
- "stage";
2
+ const stageSkillDir = instructions.stage_skill_dir || "stage";
5
3
  const modeNotes = instructions.effective_mode === "override"
6
4
  ? [
7
5
  "Local stage instruction docs are authoritative for this run.",
@@ -7,7 +7,7 @@ import { loadRuntimeRun } from "./runtime.js";
7
7
  import { initCompiledState, loadState, refreshCompiledArtifacts, saveState, } from "./state.js";
8
8
  import { compiledInventoryFromEntries } from "./runtime-inventory.js";
9
9
  import { compiledRuntimeRoot } from "./compiled-paths.js";
10
- import { isOutputMarkdownFile } from "./validate.js";
10
+ import { extractSynthAbstract, isOutputMarkdownFile } from "./validate.js";
11
11
  function readActiveRunStartedAtMs(dirPath) {
12
12
  const run = loadRuntimeRun(dirPath);
13
13
  if (!run)
@@ -49,14 +49,7 @@ function summaryAbstract(content) {
49
49
  const parsed = parseJsonFrontmatter(content);
50
50
  if (!parsed)
51
51
  return null;
52
- const frontmatterAbstract = typeof parsed.frontmatter.abstract === "string"
53
- ? parsed.frontmatter.abstract.trim()
54
- : "";
55
- if (frontmatterAbstract.length > 0)
56
- return frontmatterAbstract;
57
- const match = parsed.body.match(/^## Abstract\s+([\s\S]*?)(?:\n## |\n# |$)/m);
58
- const bodyAbstract = match?.[1]?.trim() ?? "";
59
- return bodyAbstract.length > 0 ? bodyAbstract : null;
52
+ return extractSynthAbstract(parsed.frontmatter, parsed.body);
60
53
  }
61
54
  function buildStageInventoryEntries(dirPath, stage) {
62
55
  const schema = readCompiledSchemaFile(join(dirPath, ".interf", "workflow"));
@@ -81,11 +74,7 @@ function buildStageInventoryEntries(dirPath, stage) {
81
74
  return null;
82
75
  const inputPath = typeof parsed.frontmatter.source === "string"
83
76
  ? parsed.frontmatter.source.trim()
84
- : typeof parsed.frontmatter.source_file === "string"
85
- ? parsed.frontmatter.source_file.trim()
86
- : typeof parsed.frontmatter.raw === "string"
87
- ? parsed.frontmatter.raw.trim()
88
- : "";
77
+ : "";
89
78
  if (inputPath.length === 0)
90
79
  return null;
91
80
  const abstract = summaryAbstract(content);
@@ -16,7 +16,8 @@ export function loadRuntimeRun(dirPath) {
16
16
  const parsed = RuntimeRunSchema.safeParse(raw);
17
17
  if (parsed.success)
18
18
  return parsed.data;
19
- return normalizeRuntimeRunRecord(raw);
19
+ warnInterf(`Warning: failed to validate runtime run at ${path}: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
20
+ return null;
20
21
  }
21
22
  catch (error) {
22
23
  warnInterf(`Warning: failed to read runtime run at ${path}: ${error instanceof Error ? error.message : String(error)}`);
@@ -221,92 +222,6 @@ function writeRuntimeRunPrompt(dirPath, runId, prompt) {
221
222
  function createRunId() {
222
223
  return `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
223
224
  }
224
- function normalizeRuntimeRunRecord(raw) {
225
- if (!raw || typeof raw !== "object")
226
- return null;
227
- const record = raw;
228
- const executor = record.executor;
229
- if (record.kind !== "interf-run" ||
230
- typeof record.version !== "number" ||
231
- typeof record.run_id !== "string" ||
232
- typeof record.target_name !== "string" ||
233
- typeof record.workflow !== "string" ||
234
- typeof record.stage !== "string" ||
235
- !executor ||
236
- typeof executor !== "object" ||
237
- typeof record.started_at !== "string" ||
238
- typeof record.updated_at !== "string" ||
239
- typeof record.contract_path !== "string" ||
240
- typeof record.summary !== "string") {
241
- return null;
242
- }
243
- const normalizedTargetType = inferRuntimeTargetType(record.target_type);
244
- if (!normalizedTargetType)
245
- return null;
246
- const executorRecord = executor;
247
- const normalized = {
248
- kind: "interf-run",
249
- version: record.version,
250
- run_id: record.run_id,
251
- target_type: normalizedTargetType,
252
- target_name: record.target_name,
253
- workflow: record.workflow,
254
- stage: record.stage,
255
- stage_label: typeof record.stage_label === "string" ? record.stage_label : record.stage,
256
- contract_type: typeof record.contract_type === "string"
257
- ? inferRuntimeContractType(record.contract_type, record.stage)
258
- : inferRuntimeContractType(record.target_type, record.stage),
259
- status: normalizeRuntimeRunStatus(record),
260
- executor: {
261
- kind: executorRecord.kind,
262
- name: executorRecord.name,
263
- display_name: executorRecord.display_name,
264
- command: typeof executorRecord.command === "string" ? executorRecord.command : null,
265
- model: typeof executorRecord.model === "string" ? executorRecord.model : null,
266
- effort: typeof executorRecord.effort === "string" ? executorRecord.effort : null,
267
- profile: typeof executorRecord.profile === "string" ? executorRecord.profile : null,
268
- timeout_ms: typeof executorRecord.timeout_ms === "number" ? executorRecord.timeout_ms : null,
269
- },
270
- started_at: record.started_at,
271
- updated_at: record.updated_at,
272
- finished_at: typeof record.finished_at === "string" ? record.finished_at : null,
273
- contract_path: record.contract_path,
274
- execution_path: typeof record.execution_path === "string" ? record.execution_path : undefined,
275
- counts: record.counts && typeof record.counts === "object" ? record.counts : {},
276
- output_artifacts: Array.isArray(record.output_artifacts) ? record.output_artifacts : [],
277
- logs: record.logs && typeof record.logs === "object" ? record.logs : undefined,
278
- summary: record.summary,
279
- exit_code: typeof record.exit_code === "number" ? record.exit_code : null,
280
- error: typeof record.error === "string" ? record.error : null,
281
- };
282
- const parsed = RuntimeRunSchema.safeParse(normalized);
283
- return parsed.success ? parsed.data : null;
284
- }
285
- function normalizeRuntimeRunStatus(record) {
286
- const status = record.status;
287
- if (status === "running" || status === "succeeded" || status === "failed")
288
- return status;
289
- if (typeof record.exit_code === "number")
290
- return record.exit_code === 0 ? "succeeded" : "failed";
291
- if (typeof record.error === "string" && record.error.length > 0)
292
- return "failed";
293
- return "running";
294
- }
295
- function inferRuntimeTargetType(targetType) {
296
- if (targetType === "compiled") {
297
- return "compiled";
298
- }
299
- return null;
300
- }
301
- function inferRuntimeContractType(contractType, stage) {
302
- if (typeof contractType === "string" && /^[a-z0-9][a-z0-9-]{0,79}$/.test(contractType)) {
303
- return contractType;
304
- }
305
- if (typeof stage === "string" && /^[a-z0-9][a-z0-9-]{0,79}$/.test(stage)) {
306
- return stage;
307
- }
308
- return "compiled";
309
- }
310
225
  function replaceOrAppendRunHistoryEntry(dirPath, run) {
311
226
  const historyPath = runHistoryPath(dirPath);
312
227
  if (!existsSync(historyPath)) {