@interf/compiler 0.16.0 → 0.18.0
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.
- package/LICENSE.md +1 -0
- package/README.md +10 -7
- package/TRADEMARKS.md +4 -4
- package/builtin-methods/interf-default/README.md +6 -7
- package/builtin-methods/interf-default/method.json +7 -68
- package/builtin-methods/interf-default/method.schema.json +52 -50
- package/dist/cli/commands/prep.js +58 -2
- package/dist/cli/commands/verify.d.ts +2 -0
- package/dist/cli/commands/verify.js +17 -8
- package/dist/cli/commands/wizard.js +122 -14
- package/dist/compiler-ui/404.html +1 -1
- package/dist/compiler-ui/__next.__PAGE__.txt +2 -2
- package/dist/compiler-ui/__next._full.txt +3 -3
- package/dist/compiler-ui/__next._head.txt +1 -1
- package/dist/compiler-ui/__next._index.txt +2 -2
- package/dist/compiler-ui/__next._tree.txt +2 -2
- package/dist/compiler-ui/_next/static/chunks/{13awzu4tooflw.css → 0_c_tvh-cukjz.css} +1 -1
- package/dist/compiler-ui/_next/static/chunks/{0jipmpez3_ehh.js → 0f_geuwdesg_c.js} +42 -17
- package/dist/compiler-ui/_not-found/__next._full.txt +2 -2
- package/dist/compiler-ui/_not-found/__next._head.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._index.txt +2 -2
- package/dist/compiler-ui/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._not-found.txt +1 -1
- package/dist/compiler-ui/_not-found/__next._tree.txt +2 -2
- package/dist/compiler-ui/_not-found.html +1 -1
- package/dist/compiler-ui/_not-found.txt +2 -2
- package/dist/compiler-ui/index.html +1 -1
- package/dist/compiler-ui/index.txt +3 -3
- package/dist/packages/contracts/index.d.ts +2 -2
- package/dist/packages/contracts/index.js +1 -1
- package/dist/packages/contracts/lib/schema.d.ts +271 -72
- package/dist/packages/contracts/lib/schema.js +243 -83
- package/dist/packages/engine/action-definitions.js +1 -1
- package/dist/packages/engine/agents/lib/shells.d.ts +12 -4
- package/dist/packages/engine/agents/lib/shells.js +127 -120
- package/dist/packages/engine/cloud-seams.d.ts +115 -0
- package/dist/packages/engine/cloud-seams.js +84 -0
- package/dist/packages/engine/compile/artifact-counts.d.ts +1 -1
- package/dist/packages/engine/compile/artifact-counts.js +3 -3
- package/dist/packages/engine/compile/artifact-status.d.ts +41 -0
- package/dist/packages/engine/compile/artifact-status.js +166 -0
- package/dist/packages/engine/compile/billing-events.d.ts +89 -0
- package/dist/packages/engine/compile/billing-events.js +74 -0
- package/dist/packages/engine/compile/check-evaluator.d.ts +66 -0
- package/dist/packages/engine/compile/check-evaluator.js +298 -0
- package/dist/packages/engine/compile/compiled-schema.d.ts +7 -17
- package/dist/packages/engine/compile/compiled-schema.js +55 -70
- package/dist/packages/engine/compile/compiled-stage-plan.d.ts +1 -0
- package/dist/packages/engine/compile/compiled-stage-plan.js +32 -15
- package/dist/packages/engine/compile/compiled-stage-runner.js +1 -1
- package/dist/packages/engine/compile/index.d.ts +0 -1
- package/dist/packages/engine/compile/index.js +0 -1
- package/dist/packages/engine/compile/lib/schema.d.ts +111 -92
- package/dist/packages/engine/compile/lib/schema.js +35 -39
- package/dist/packages/engine/compile/method-primitives.d.ts +2 -2
- package/dist/packages/engine/compile/method-primitives.js +1 -1
- package/dist/packages/engine/compile/reset.js +4 -4
- package/dist/packages/engine/compile/runtime-contracts.js +2 -1
- package/dist/packages/engine/compile/runtime-prompt.js +3 -2
- package/dist/packages/engine/compile/runtime-reconcile.js +35 -35
- package/dist/packages/engine/compile/runtime-runs.js +0 -1
- package/dist/packages/engine/compile/runtime-types.d.ts +7 -8
- package/dist/packages/engine/compile/runtime.d.ts +1 -2
- package/dist/packages/engine/compile/runtime.js +0 -1
- package/dist/packages/engine/compile/state-health.js +6 -6
- package/dist/packages/engine/compile/state-view.js +7 -6
- package/dist/packages/engine/compile/validate-compiled.js +61 -30
- package/dist/packages/engine/compile/validate.js +26 -24
- package/dist/packages/engine/execution/lib/schema.d.ts +79 -33
- package/dist/packages/engine/execution/lib/schema.js +13 -5
- package/dist/packages/engine/index.d.ts +2 -2
- package/dist/packages/engine/index.js +1 -1
- package/dist/packages/engine/lib/schema.d.ts +551 -242
- package/dist/packages/engine/lib/schema.js +53 -17
- package/dist/packages/engine/native-run-handlers.js +15 -7
- package/dist/packages/engine/preparation-store.d.ts +6 -0
- package/dist/packages/engine/preparation-store.js +8 -0
- package/dist/packages/engine/routes.d.ts +6 -0
- package/dist/packages/engine/routes.js +6 -0
- package/dist/packages/engine/run-observability.js +1 -2
- package/dist/packages/engine/runtime-event-applier.js +7 -0
- package/dist/packages/engine/runtime-proposal-helpers.js +1 -1
- package/dist/packages/engine/runtime-resource-builders.d.ts +6 -6
- package/dist/packages/engine/runtime-resource-builders.js +5 -4
- package/dist/packages/engine/runtime.d.ts +67 -7
- package/dist/packages/engine/runtime.js +159 -29
- package/dist/packages/engine/server.d.ts +25 -0
- package/dist/packages/engine/server.js +62 -3
- package/dist/packages/engine/verify/index.d.ts +10 -10
- package/dist/packages/engine/verify/index.js +8 -8
- package/dist/packages/engine/verify/readiness-check-run.d.ts +27 -4
- package/dist/packages/engine/verify/readiness-check-run.js +92 -24
- package/dist/packages/engine/verify/{test-execution.d.ts → verify-execution.d.ts} +2 -2
- package/dist/packages/engine/verify/{test-execution.js → verify-execution.js} +2 -2
- package/dist/packages/engine/verify/{test-paths.d.ts → verify-paths.d.ts} +1 -1
- package/dist/packages/engine/verify/{test-sandbox.d.ts → verify-sandbox.d.ts} +1 -1
- package/dist/packages/engine/verify/{test-specs.d.ts → verify-specs.d.ts} +1 -1
- package/dist/packages/engine/verify/{test-specs.js → verify-specs.js} +1 -1
- package/dist/packages/engine/verify/{test-targets.d.ts → verify-targets.d.ts} +1 -1
- package/dist/packages/engine/verify/{test.d.ts → verify.d.ts} +4 -4
- package/dist/packages/engine/verify/{test.js → verify.js} +3 -3
- package/dist/packages/engine/wire-schemas.d.ts +545 -0
- package/dist/packages/engine/wire-schemas.js +59 -0
- package/dist/packages/methods/authoring/method-authoring.d.ts +2 -0
- package/dist/packages/methods/authoring/method-authoring.js +99 -18
- package/dist/packages/methods/authoring/method-edit-session.js +5 -5
- package/dist/packages/methods/authoring/method-improvement.js +1 -1
- package/dist/packages/methods/package/builtin-compiled-method.d.ts +12 -12
- package/dist/packages/methods/package/builtin-compiled-method.js +25 -22
- package/dist/packages/methods/package/context-interface.d.ts +39 -26
- package/dist/packages/methods/package/context-interface.js +48 -39
- package/dist/packages/methods/package/interf-method-package.js +28 -47
- package/dist/packages/methods/package/local-methods.d.ts +3 -4
- package/dist/packages/methods/package/local-methods.js +34 -62
- package/dist/packages/methods/package/method-definitions.d.ts +4 -6
- package/dist/packages/methods/package/method-definitions.js +0 -4
- package/dist/packages/methods/package/method-helpers.d.ts +0 -2
- package/dist/packages/methods/package/method-helpers.js +0 -4
- package/dist/packages/project/interf-scaffold.js +12 -12
- package/dist/packages/project/source-config.js +2 -1
- package/package.json +6 -16
- package/dist/packages/engine/compile/runtime-acceptance.d.ts +0 -9
- package/dist/packages/engine/compile/runtime-acceptance.js +0 -265
- /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_buildManifest.js +0 -0
- /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_clientMiddlewareManifest.js +0 -0
- /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → 6qyE1u9m_oBUkvAhhoCmO}/_ssgManifest.js +0 -0
- /package/dist/packages/engine/verify/{test-paths.js → verify-paths.js} +0 -0
- /package/dist/packages/engine/verify/{test-profile-presets.d.ts → verify-profile-presets.d.ts} +0 -0
- /package/dist/packages/engine/verify/{test-profile-presets.js → verify-profile-presets.js} +0 -0
- /package/dist/packages/engine/verify/{test-sandbox.js → verify-sandbox.js} +0 -0
- /package/dist/packages/engine/verify/{test-targets.js → verify-targets.js} +0 -0
- /package/dist/packages/engine/verify/{test-types.d.ts → verify-types.d.ts} +0 -0
- /package/dist/packages/engine/verify/{test-types.js → verify-types.js} +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.17 — interface seams for the future cloud variant.
|
|
3
|
+
*
|
|
4
|
+
* These types document the injection points a cloud variant of the
|
|
5
|
+
* engine slots into without forking. The local binary keeps its
|
|
6
|
+
* in-process implementations (private `Map` fields on the runtime,
|
|
7
|
+
* the per-instance bearer-token check in `server.ts`); cloud variants
|
|
8
|
+
* provide their own implementations and pass them through
|
|
9
|
+
* `startLocalService` / `LocalServiceRuntimeOptions`.
|
|
10
|
+
*
|
|
11
|
+
* Each seam below is paired with a `TODO(cloud)` marker at the
|
|
12
|
+
* concrete call site so the cloud variant has a clear "wire this
|
|
13
|
+
* through" landing pad. Local default behavior is unchanged in 0.17.
|
|
14
|
+
*/
|
|
15
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Local default implementations
|
|
17
|
+
//
|
|
18
|
+
// These wrap in-process Maps and satisfy the interfaces above so the
|
|
19
|
+
// runtime can inject either a local default (current behavior) or a
|
|
20
|
+
// cloud override (Redis-shaped store, shared lease, etc) without
|
|
21
|
+
// branching on the deployment.
|
|
22
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
23
|
+
export class InMemoryIdempotencyStore {
|
|
24
|
+
buckets = new Map();
|
|
25
|
+
get(scope, key) {
|
|
26
|
+
return this.buckets.get(scope)?.get(key) ?? null;
|
|
27
|
+
}
|
|
28
|
+
set(scope, key, value) {
|
|
29
|
+
let bucket = this.buckets.get(scope);
|
|
30
|
+
if (!bucket) {
|
|
31
|
+
bucket = new Map();
|
|
32
|
+
this.buckets.set(scope, bucket);
|
|
33
|
+
}
|
|
34
|
+
bucket.set(key, value);
|
|
35
|
+
}
|
|
36
|
+
delete(scope, key) {
|
|
37
|
+
const bucket = this.buckets.get(scope);
|
|
38
|
+
if (!bucket)
|
|
39
|
+
return;
|
|
40
|
+
bucket.delete(key);
|
|
41
|
+
if (bucket.size === 0)
|
|
42
|
+
this.buckets.delete(scope);
|
|
43
|
+
}
|
|
44
|
+
prune(now) {
|
|
45
|
+
for (const [scope, bucket] of this.buckets) {
|
|
46
|
+
for (const [key, value] of bucket) {
|
|
47
|
+
if (value.expiresAt < now)
|
|
48
|
+
bucket.delete(key);
|
|
49
|
+
}
|
|
50
|
+
if (bucket.size === 0)
|
|
51
|
+
this.buckets.delete(scope);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
size() {
|
|
55
|
+
let total = 0;
|
|
56
|
+
for (const bucket of this.buckets.values())
|
|
57
|
+
total += bucket.size;
|
|
58
|
+
return total;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export class InMemoryRunLeaseStore {
|
|
62
|
+
leases = new Map();
|
|
63
|
+
acquire(runId, lease) {
|
|
64
|
+
this.leases.set(runId, lease);
|
|
65
|
+
}
|
|
66
|
+
release(runId) {
|
|
67
|
+
this.leases.delete(runId);
|
|
68
|
+
}
|
|
69
|
+
get(runId) {
|
|
70
|
+
return this.leases.get(runId) ?? null;
|
|
71
|
+
}
|
|
72
|
+
markCancelled(runId) {
|
|
73
|
+
const lease = this.leases.get(runId);
|
|
74
|
+
if (!lease)
|
|
75
|
+
return;
|
|
76
|
+
lease.cancelled = true;
|
|
77
|
+
lease.cancelledAt = new Date().toISOString();
|
|
78
|
+
}
|
|
79
|
+
*listActive() {
|
|
80
|
+
for (const [runId, lease] of this.leases) {
|
|
81
|
+
yield { runId, lease };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function countCompiledArtifactsAtPath(compiledPath: string, artifactPath: string, kind: "directory" | "file" | "runtime"): number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { listFilesRecursive } from "../../contracts/utils/filesystem.js";
|
|
3
|
-
import {
|
|
3
|
+
import { compiledArtifactAbsolutePath } from "./compiled-schema.js";
|
|
4
4
|
const SCAFFOLD_PLACEHOLDER_SNIPPETS = [
|
|
5
5
|
"Not yet compiled. Run `interf compile` to build the portable context.",
|
|
6
6
|
"Not yet compiled. Run `interf compile` to build this portable context.",
|
|
@@ -16,8 +16,8 @@ function isScaffoldPlaceholderFile(filePath) {
|
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
export function
|
|
20
|
-
const absolutePath =
|
|
19
|
+
export function countCompiledArtifactsAtPath(compiledPath, artifactPath, kind) {
|
|
20
|
+
const absolutePath = compiledArtifactAbsolutePath(compiledPath, { path: artifactPath });
|
|
21
21
|
if (!existsSync(absolutePath))
|
|
22
22
|
return 0;
|
|
23
23
|
if (kind === "file")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ArtifactStatus } from "../../contracts/lib/schema.js";
|
|
2
|
+
import type { MethodDefinition } from "../../methods/package/method-definitions.js";
|
|
3
|
+
import type { StageRun } from "../execution/lib/schema.js";
|
|
4
|
+
/**
|
|
5
|
+
* 0.17 — compute per-Artifact status for a compile run.
|
|
6
|
+
*
|
|
7
|
+
* Walks the Method's declared `artifacts[]` and decides
|
|
8
|
+
* `ready | not_ready | failed | skipped` for each.
|
|
9
|
+
*
|
|
10
|
+
* Mapping rules:
|
|
11
|
+
* - **shape kind = "path"**: the artifact is `ready` when the declared
|
|
12
|
+
* path exists inside `compiledPath` with the declared artifact kind,
|
|
13
|
+
* `not_ready` otherwise. Future shape kinds (value, remote-handle,
|
|
14
|
+
* confirmation) slot in here.
|
|
15
|
+
* - **`built_by_stages`** is preserved from the Method declaration when
|
|
16
|
+
* present, otherwise inferred from stage `writes` that match the
|
|
17
|
+
* artifact's path.
|
|
18
|
+
* - **proofs** carries structured evidence from the shared check
|
|
19
|
+
* evaluator.
|
|
20
|
+
*
|
|
21
|
+
* Stage-failure short-circuit: if any stage has `status: "failed"`, all
|
|
22
|
+
* non-existent artifacts are marked `failed` instead of `not_ready` so
|
|
23
|
+
* the run record carries the real causal signal.
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeArtifactStatuses(options: {
|
|
26
|
+
method: Pick<MethodDefinition<string>, "stages" | "contextInterface" | "schema">;
|
|
27
|
+
compiledPath: string;
|
|
28
|
+
stageRuns: StageRun[];
|
|
29
|
+
/**
|
|
30
|
+
* Optional runtime counts (e.g. `source_total`) passed to checks
|
|
31
|
+
* that compare against source. Threaded through from the compile
|
|
32
|
+
* runtime; absent for ad-hoc evaluations.
|
|
33
|
+
*/
|
|
34
|
+
counts?: Record<string, number>;
|
|
35
|
+
}): ArtifactStatus[];
|
|
36
|
+
/**
|
|
37
|
+
* Aggregate verdict: any artifact in `not_ready | failed | skipped`
|
|
38
|
+
* makes the preparation `not_ready`. Used by the readiness state view
|
|
39
|
+
* once Phase D lights up the per-artifact UI.
|
|
40
|
+
*/
|
|
41
|
+
export declare function aggregateArtifactVerdict(statuses: readonly ArtifactStatus[]): "ready" | "not_ready";
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { evaluateChecks } from "./check-evaluator.js";
|
|
4
|
+
/**
|
|
5
|
+
* 0.17 — compute per-Artifact status for a compile run.
|
|
6
|
+
*
|
|
7
|
+
* Walks the Method's declared `artifacts[]` and decides
|
|
8
|
+
* `ready | not_ready | failed | skipped` for each.
|
|
9
|
+
*
|
|
10
|
+
* Mapping rules:
|
|
11
|
+
* - **shape kind = "path"**: the artifact is `ready` when the declared
|
|
12
|
+
* path exists inside `compiledPath` with the declared artifact kind,
|
|
13
|
+
* `not_ready` otherwise. Future shape kinds (value, remote-handle,
|
|
14
|
+
* confirmation) slot in here.
|
|
15
|
+
* - **`built_by_stages`** is preserved from the Method declaration when
|
|
16
|
+
* present, otherwise inferred from stage `writes` that match the
|
|
17
|
+
* artifact's path.
|
|
18
|
+
* - **proofs** carries structured evidence from the shared check
|
|
19
|
+
* evaluator.
|
|
20
|
+
*
|
|
21
|
+
* Stage-failure short-circuit: if any stage has `status: "failed"`, all
|
|
22
|
+
* non-existent artifacts are marked `failed` instead of `not_ready` so
|
|
23
|
+
* the run record carries the real causal signal.
|
|
24
|
+
*/
|
|
25
|
+
export function computeArtifactStatuses(options) {
|
|
26
|
+
const schema = pickContextInterface(options.method);
|
|
27
|
+
const artifacts = schema?.artifacts ?? [];
|
|
28
|
+
if (artifacts.length === 0)
|
|
29
|
+
return [];
|
|
30
|
+
const stageWriteIndex = buildStageWriteIndex(options.method.stages);
|
|
31
|
+
const anyStageFailed = options.stageRuns.some((stage) => stage.status === "failed");
|
|
32
|
+
return artifacts.map((artifact) => buildArtifactStatus({
|
|
33
|
+
artifact,
|
|
34
|
+
compiledPath: options.compiledPath,
|
|
35
|
+
stageWriteIndex,
|
|
36
|
+
anyStageFailed,
|
|
37
|
+
counts: options.counts,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
function pickContextInterface(method) {
|
|
41
|
+
return method.contextInterface ?? method.schema;
|
|
42
|
+
}
|
|
43
|
+
function buildStageWriteIndex(stages) {
|
|
44
|
+
const index = new Map();
|
|
45
|
+
for (const stage of stages) {
|
|
46
|
+
for (const write of stage.writes ?? []) {
|
|
47
|
+
const owners = index.get(write) ?? [];
|
|
48
|
+
if (!owners.includes(stage.id))
|
|
49
|
+
owners.push(stage.id);
|
|
50
|
+
index.set(write, owners);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return index;
|
|
54
|
+
}
|
|
55
|
+
function buildArtifactStatus(options) {
|
|
56
|
+
const { artifact, compiledPath, stageWriteIndex, anyStageFailed, counts } = options;
|
|
57
|
+
const builtBy = artifact.built_by_stages.length > 0
|
|
58
|
+
? artifact.built_by_stages
|
|
59
|
+
: inferBuiltByStages(artifact, stageWriteIndex);
|
|
60
|
+
const shapeStatus = resolveStatusValue({
|
|
61
|
+
artifact,
|
|
62
|
+
compiledPath,
|
|
63
|
+
anyStageFailed,
|
|
64
|
+
});
|
|
65
|
+
// Run the locked CheckKind evaluator against artifact.checks. Proofs
|
|
66
|
+
// are surfaced for each declared check; if any required check fails,
|
|
67
|
+
// the artifact's status is forced to failed (or not_ready if the
|
|
68
|
+
// shape itself isn't built yet).
|
|
69
|
+
const targetPath = artifact.shape.kind === "path" ? artifact.shape.path : undefined;
|
|
70
|
+
// `artifact.checks` is `default([])` in the schema, but raw objects
|
|
71
|
+
// (test fixtures, hand-edited Methods loaded without parsing) may
|
|
72
|
+
// omit the field entirely.
|
|
73
|
+
const declaredChecks = artifact.checks ?? [];
|
|
74
|
+
const checkResult = declaredChecks.length > 0
|
|
75
|
+
? evaluateChecks(declaredChecks, {
|
|
76
|
+
rootPath: compiledPath,
|
|
77
|
+
targetPath,
|
|
78
|
+
counts,
|
|
79
|
+
})
|
|
80
|
+
: { proofs: [], ready: true, failures: [] };
|
|
81
|
+
const status = (() => {
|
|
82
|
+
if (shapeStatus !== "ready")
|
|
83
|
+
return shapeStatus;
|
|
84
|
+
if (checkResult.failures.length > 0)
|
|
85
|
+
return "failed";
|
|
86
|
+
return "ready";
|
|
87
|
+
})();
|
|
88
|
+
return {
|
|
89
|
+
artifact_id: artifact.id,
|
|
90
|
+
status,
|
|
91
|
+
built_by_stages: builtBy,
|
|
92
|
+
proofs: checkResult.proofs,
|
|
93
|
+
...(buildSummary(artifact, status, checkResult.failures.length)),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function buildSummary(artifact, status, failedRequiredCount) {
|
|
97
|
+
if (status === "ready")
|
|
98
|
+
return { summary: `Artifact ${artifact.id} is ready.` };
|
|
99
|
+
if (status === "failed") {
|
|
100
|
+
if (failedRequiredCount > 0) {
|
|
101
|
+
return { summary: `Artifact ${artifact.id}: ${failedRequiredCount} required check(s) failed.` };
|
|
102
|
+
}
|
|
103
|
+
return { summary: `Artifact ${artifact.id} did not produce ${describeShape(artifact)}.` };
|
|
104
|
+
}
|
|
105
|
+
if (status === "not_ready")
|
|
106
|
+
return { summary: `Artifact ${artifact.id} has not been produced yet.` };
|
|
107
|
+
return { summary: `Artifact ${artifact.id} was skipped.` };
|
|
108
|
+
}
|
|
109
|
+
function inferBuiltByStages(artifact, stageWriteIndex) {
|
|
110
|
+
if (artifact.shape.kind !== "path")
|
|
111
|
+
return [];
|
|
112
|
+
const directOwners = stageWriteIndex.get(artifact.id);
|
|
113
|
+
if (directOwners && directOwners.length > 0)
|
|
114
|
+
return directOwners;
|
|
115
|
+
const pathOwners = stageWriteIndex.get(artifact.shape.path);
|
|
116
|
+
return pathOwners ?? [];
|
|
117
|
+
}
|
|
118
|
+
function resolveStatusValue(options) {
|
|
119
|
+
const { artifact, compiledPath, anyStageFailed } = options;
|
|
120
|
+
if (artifact.shape.kind !== "path")
|
|
121
|
+
return "skipped";
|
|
122
|
+
const compiledRoot = resolve(compiledPath);
|
|
123
|
+
const absolutePath = resolve(compiledRoot, artifact.shape.path);
|
|
124
|
+
// Defense in depth: the schema-level `isInterfRelativePath` refine
|
|
125
|
+
// already rejects `..` and absolute paths in `ArtifactPathShape.path`,
|
|
126
|
+
// but Method packages can land on disk before the schema validates
|
|
127
|
+
// (hand-edited drafts can still bypass normal package validation).
|
|
128
|
+
// Reject any resolved path that escapes the portable-context root.
|
|
129
|
+
if (absolutePath !== compiledRoot && !absolutePath.startsWith(`${compiledRoot}/`)) {
|
|
130
|
+
return "failed";
|
|
131
|
+
}
|
|
132
|
+
if (!existsSync(absolutePath)) {
|
|
133
|
+
return anyStageFailed ? "failed" : "not_ready";
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const info = statSync(absolutePath);
|
|
137
|
+
// For directory artifacts, ready means the directory exists; the
|
|
138
|
+
// directory may be empty during early stages, but content-shape
|
|
139
|
+
// checks live in artifact `checks[]`, not here. For file artifacts,
|
|
140
|
+
// the file must have non-zero bytes —
|
|
141
|
+
// an empty placeholder is not_ready.
|
|
142
|
+
if (artifact.shape.artifact_kind === "directory" && info.isDirectory())
|
|
143
|
+
return "ready";
|
|
144
|
+
if (artifact.shape.artifact_kind === "file" && info.isFile() && info.size > 0)
|
|
145
|
+
return "ready";
|
|
146
|
+
return anyStageFailed ? "failed" : "not_ready";
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return anyStageFailed ? "failed" : "not_ready";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function describeShape(artifact) {
|
|
153
|
+
if (artifact.shape.kind === "path")
|
|
154
|
+
return `\`${artifact.shape.path}\``;
|
|
155
|
+
return `(${artifact.shape.kind})`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Aggregate verdict: any artifact in `not_ready | failed | skipped`
|
|
159
|
+
* makes the preparation `not_ready`. Used by the readiness state view
|
|
160
|
+
* once Phase D lights up the per-artifact UI.
|
|
161
|
+
*/
|
|
162
|
+
export function aggregateArtifactVerdict(statuses) {
|
|
163
|
+
if (statuses.length === 0)
|
|
164
|
+
return "not_ready";
|
|
165
|
+
return statuses.every((status) => status.status === "ready") ? "ready" : "not_ready";
|
|
166
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ArtifactStatus } from "../../contracts/lib/schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* 0.17 — per-Artifact billing event record.
|
|
5
|
+
*
|
|
6
|
+
* Emitted once per Artifact each time a compile run produces it.
|
|
7
|
+
* `account_id` is `null` for loopback (no auth); the cloud variant
|
|
8
|
+
* fills it from the `tokenValidator` (B4.3) result.
|
|
9
|
+
*
|
|
10
|
+
* `event_kind`:
|
|
11
|
+
* - `fresh` — first-time build of this Artifact in this run
|
|
12
|
+
* - `resync` — incremental rebuild (deferred to 0.18+; not emitted in 0.17)
|
|
13
|
+
*/
|
|
14
|
+
export declare const BillingEventKindSchema: z.ZodEnum<{
|
|
15
|
+
fresh: "fresh";
|
|
16
|
+
resync: "resync";
|
|
17
|
+
}>;
|
|
18
|
+
export declare const CompilationEventSchema: z.ZodObject<{
|
|
19
|
+
kind: z.ZodLiteral<"interf-compilation-event">;
|
|
20
|
+
version: z.ZodLiteral<1>;
|
|
21
|
+
timestamp: z.ZodString;
|
|
22
|
+
run_id: z.ZodString;
|
|
23
|
+
preparation: z.ZodString;
|
|
24
|
+
artifact_id: z.ZodString;
|
|
25
|
+
method_id: z.ZodString;
|
|
26
|
+
account_id: z.ZodNullable<z.ZodString>;
|
|
27
|
+
event_kind: z.ZodEnum<{
|
|
28
|
+
fresh: "fresh";
|
|
29
|
+
resync: "resync";
|
|
30
|
+
}>;
|
|
31
|
+
size_class: z.ZodOptional<z.ZodEnum<{
|
|
32
|
+
small: "small";
|
|
33
|
+
medium: "medium";
|
|
34
|
+
large: "large";
|
|
35
|
+
}>>;
|
|
36
|
+
duration_ms: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
}, z.core.$strict>;
|
|
38
|
+
export type CompilationEvent = z.infer<typeof CompilationEventSchema>;
|
|
39
|
+
export type BillingEventKind = z.infer<typeof BillingEventKindSchema>;
|
|
40
|
+
/**
|
|
41
|
+
* Sink for billing events.
|
|
42
|
+
*
|
|
43
|
+
* **STUB FOR 0.17 — JSONL local default.** Production sink (Metronome
|
|
44
|
+
* HTTP) wires in 0.18+ once the Stripe + Metronome accounts are
|
|
45
|
+
* provisioned. The `<prep>/runs/<run-id>/billing-events.jsonl` file is
|
|
46
|
+
* an **observability / dev fixture, NOT production billing data**.
|
|
47
|
+
* Future readers must not treat it as authoritative — Stripe Billing
|
|
48
|
+
* holds the books once 0.18 ships the HTTP sink.
|
|
49
|
+
*
|
|
50
|
+
* Cloud variants inject a remote sink via `startLocalService` options
|
|
51
|
+
* (paired with the `BillingEventSink` injection point in B4-style
|
|
52
|
+
* dependency injection); the engine treats either implementation
|
|
53
|
+
* identically.
|
|
54
|
+
*/
|
|
55
|
+
export interface BillingEventSink {
|
|
56
|
+
emit(event: CompilationEvent): void;
|
|
57
|
+
}
|
|
58
|
+
export declare class JsonlBillingEventSink implements BillingEventSink {
|
|
59
|
+
private readonly logPath;
|
|
60
|
+
constructor(logPath: string);
|
|
61
|
+
emit(event: CompilationEvent): void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Default sink path for a run. Each compile run gets its own JSONL
|
|
65
|
+
* file alongside its other on-disk artifacts.
|
|
66
|
+
*/
|
|
67
|
+
export declare function defaultBillingEventLogPath(options: {
|
|
68
|
+
preparationDataDir: string;
|
|
69
|
+
preparationName: string;
|
|
70
|
+
runId: string;
|
|
71
|
+
}): string;
|
|
72
|
+
/**
|
|
73
|
+
* Convert a list of per-Artifact statuses into compilation events for
|
|
74
|
+
* the run. Only `ready` and `failed` artifacts emit events — `skipped`
|
|
75
|
+
* and `not_ready` represent work that didn't happen and shouldn't bill.
|
|
76
|
+
*
|
|
77
|
+
* 0.17 ships `event_kind: "fresh"` only. The resync optimization that
|
|
78
|
+
* differentiates cached-vs-rebuilt artifacts lands in 0.18+.
|
|
79
|
+
*/
|
|
80
|
+
export declare function buildCompilationEventsForRun(options: {
|
|
81
|
+
runId: string;
|
|
82
|
+
preparation: string;
|
|
83
|
+
methodId: string;
|
|
84
|
+
accountId: string | null;
|
|
85
|
+
artifacts: readonly ArtifactStatus[];
|
|
86
|
+
startedAt?: string | null;
|
|
87
|
+
finishedAt?: string | null;
|
|
88
|
+
timestamp?: string;
|
|
89
|
+
}): CompilationEvent[];
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* 0.17 — per-Artifact billing event record.
|
|
6
|
+
*
|
|
7
|
+
* Emitted once per Artifact each time a compile run produces it.
|
|
8
|
+
* `account_id` is `null` for loopback (no auth); the cloud variant
|
|
9
|
+
* fills it from the `tokenValidator` (B4.3) result.
|
|
10
|
+
*
|
|
11
|
+
* `event_kind`:
|
|
12
|
+
* - `fresh` — first-time build of this Artifact in this run
|
|
13
|
+
* - `resync` — incremental rebuild (deferred to 0.18+; not emitted in 0.17)
|
|
14
|
+
*/
|
|
15
|
+
export const BillingEventKindSchema = z.enum(["fresh", "resync"]);
|
|
16
|
+
export const CompilationEventSchema = z.object({
|
|
17
|
+
kind: z.literal("interf-compilation-event"),
|
|
18
|
+
version: z.literal(1),
|
|
19
|
+
timestamp: z.string().min(1),
|
|
20
|
+
run_id: z.string().min(1),
|
|
21
|
+
preparation: z.string().min(1),
|
|
22
|
+
artifact_id: z.string().min(1),
|
|
23
|
+
method_id: z.string().min(1),
|
|
24
|
+
account_id: z.string().min(1).nullable(),
|
|
25
|
+
event_kind: BillingEventKindSchema,
|
|
26
|
+
size_class: z.enum(["small", "medium", "large"]).optional(),
|
|
27
|
+
duration_ms: z.number().nonnegative().optional(),
|
|
28
|
+
}).strict();
|
|
29
|
+
export class JsonlBillingEventSink {
|
|
30
|
+
logPath;
|
|
31
|
+
constructor(logPath) {
|
|
32
|
+
this.logPath = logPath;
|
|
33
|
+
}
|
|
34
|
+
emit(event) {
|
|
35
|
+
const validated = CompilationEventSchema.parse(event);
|
|
36
|
+
mkdirSync(dirname(this.logPath), { recursive: true });
|
|
37
|
+
appendFileSync(this.logPath, `${JSON.stringify(validated)}\n`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Default sink path for a run. Each compile run gets its own JSONL
|
|
42
|
+
* file alongside its other on-disk artifacts.
|
|
43
|
+
*/
|
|
44
|
+
export function defaultBillingEventLogPath(options) {
|
|
45
|
+
return join(options.preparationDataDir, options.preparationName, "runs", options.runId, "billing-events.jsonl");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Convert a list of per-Artifact statuses into compilation events for
|
|
49
|
+
* the run. Only `ready` and `failed` artifacts emit events — `skipped`
|
|
50
|
+
* and `not_ready` represent work that didn't happen and shouldn't bill.
|
|
51
|
+
*
|
|
52
|
+
* 0.17 ships `event_kind: "fresh"` only. The resync optimization that
|
|
53
|
+
* differentiates cached-vs-rebuilt artifacts lands in 0.18+.
|
|
54
|
+
*/
|
|
55
|
+
export function buildCompilationEventsForRun(options) {
|
|
56
|
+
const timestamp = options.timestamp ?? new Date().toISOString();
|
|
57
|
+
const durationMs = options.startedAt && options.finishedAt
|
|
58
|
+
? Math.max(0, new Date(options.finishedAt).getTime() - new Date(options.startedAt).getTime())
|
|
59
|
+
: undefined;
|
|
60
|
+
return options.artifacts
|
|
61
|
+
.filter((status) => status.status === "ready" || status.status === "failed")
|
|
62
|
+
.map((status) => ({
|
|
63
|
+
kind: "interf-compilation-event",
|
|
64
|
+
version: 1,
|
|
65
|
+
timestamp,
|
|
66
|
+
run_id: options.runId,
|
|
67
|
+
preparation: options.preparation,
|
|
68
|
+
artifact_id: status.artifact_id,
|
|
69
|
+
method_id: options.methodId,
|
|
70
|
+
account_id: options.accountId,
|
|
71
|
+
event_kind: "fresh",
|
|
72
|
+
...(durationMs !== undefined ? { duration_ms: durationMs } : {}),
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type Check, type CheckKind, type Proof } from "../../contracts/lib/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* 0.17 — Check evaluator for the locked verification vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* One evaluator per `CheckKind` from `CHECK_KINDS`. The evaluator is
|
|
6
|
+
* scope-agnostic: it takes a Check, a target path, and optional
|
|
7
|
+
* runtime context (counts, source-file totals); it returns a Proof.
|
|
8
|
+
*
|
|
9
|
+
* The same evaluator serves stage-level checks, artifact-level checks,
|
|
10
|
+
* and (for `qa_match`) user-level checks. Methods and user-defined
|
|
11
|
+
* verification declare `Check[]`; the runtime invokes this evaluator
|
|
12
|
+
* to produce `Proof[]`.
|
|
13
|
+
*
|
|
14
|
+
* This evaluator is the source of truth for declared verification
|
|
15
|
+
* checks. Legacy stage-acceptance rules were retired after the
|
|
16
|
+
* artifact-first migration.
|
|
17
|
+
*/
|
|
18
|
+
export interface CheckEvaluationContext {
|
|
19
|
+
/**
|
|
20
|
+
* Filesystem root the check evaluates against. For artifact checks
|
|
21
|
+
* this is the portable-context root; the artifact's path is
|
|
22
|
+
* resolved relative to it. For stage checks this can be the same
|
|
23
|
+
* root or a stage-output sub-directory.
|
|
24
|
+
*/
|
|
25
|
+
rootPath: string;
|
|
26
|
+
/**
|
|
27
|
+
* Optional: the path the check targets. For artifact-scoped checks
|
|
28
|
+
* this is the artifact's `shape.path`; for stage-scoped checks
|
|
29
|
+
* this is the stage's writes path. Some kinds (qa_match) ignore
|
|
30
|
+
* targetPath because they operate on agent answers, not files.
|
|
31
|
+
*/
|
|
32
|
+
targetPath?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Optional runtime-derived counts used by `min_file_count_matches_source`
|
|
35
|
+
* and similar rules. `source_total` is the canonical key for "how
|
|
36
|
+
* many source files were processed." Methods reference it in check
|
|
37
|
+
* params via `{ match: "source_total" }`.
|
|
38
|
+
*/
|
|
39
|
+
counts?: Record<string, number>;
|
|
40
|
+
/**
|
|
41
|
+
* Optional: the agent's answer for a `qa_match` check. Provided by
|
|
42
|
+
* the verify-run flow, not relevant for compile-time evaluation.
|
|
43
|
+
*/
|
|
44
|
+
agentAnswer?: string;
|
|
45
|
+
}
|
|
46
|
+
export type CheckEvaluator = (check: Check, context: CheckEvaluationContext) => Proof;
|
|
47
|
+
/**
|
|
48
|
+
* Evaluate a single Check against a context, returning a Proof.
|
|
49
|
+
*/
|
|
50
|
+
export declare function evaluateCheck(check: Check, context: CheckEvaluationContext): Proof;
|
|
51
|
+
/**
|
|
52
|
+
* Evaluate a list of checks. Aggregate ready/not_ready verdict over
|
|
53
|
+
* the proofs: `ready` if every required check passed, otherwise
|
|
54
|
+
* `not_ready`. Soft checks (required: false) that fail produce a
|
|
55
|
+
* proof but don't change the verdict.
|
|
56
|
+
*/
|
|
57
|
+
export declare function evaluateChecks(checks: readonly Check[], context: CheckEvaluationContext): {
|
|
58
|
+
proofs: Proof[];
|
|
59
|
+
ready: boolean;
|
|
60
|
+
failures: Proof[];
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Type guard for the canonical CheckKinds. Useful at parse boundaries
|
|
64
|
+
* where a string came from on-disk JSON.
|
|
65
|
+
*/
|
|
66
|
+
export declare function isCheckKind(value: unknown): value is CheckKind;
|