Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/demo-runtime-rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ never issued one, so it is skipped with the reason `check` already gives.
Running it uses the documented `--dangerously-run-scripts`. The `sg` and `vale`
samples are inert data and run under `check` like any other rule.

The same three rules are published as `@taskless/cli/demo-reference.json`, as a
The same three rules are published as `@taskless/cli/reference.json`, as a
conformance corpus rather than a pile of examples. Each entry carries the
generation prompt it answers, the rule itself, and the held-out cases — kept
apart, because the useful comparison is the cross: run a generated rule against
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"prebuild": "tsx scripts/fetch-rule-hash-vectors.ts",
"test": "vitest run",
"typecheck": "tsc --noEmit",
"demo:reference": "tsx scripts/write-demo-reference.ts",
"demo:manifests": "tsx scripts/print-demo-manifests.ts"
"demo:manifests": "tsx scripts/print-demo-manifests.ts",
"reference": "tsx scripts/write-reference.ts"
},
"type": "module",
"module": "./dist/index.js",
Expand All @@ -41,11 +41,11 @@
"types": "./dist/node/runtimes/index.d.ts",
"import": "./dist/node/runtimes.js"
},
"./demo-reference.json": "./assets/demo-reference.json"
"./reference.json": "./assets/reference.json"
},
"files": [
"dist",
"assets/demo-reference.json"
"assets/reference.json"
],
"engines": {
"node": ">=22.22.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
/**
* Regenerate `assets/demo-reference.json` from the shipped rules.
* Regenerate `assets/reference.json` from the shipped rules.
*
* The corpus is every demonstration rule with the prompt it answers, the rule
* itself, and the held-out cases — separately, so another team can run their
* rule against our cases and ours against theirs.
*
* Reads the asset files directly rather than importing `rule.ts`, whose `?raw`
* specifiers only resolve under a vite transform. Both read `DEMO_MANIFESTS`,
* and `test/demo-reference.test.ts` asserts they agree.
* and `test/reference.test.ts` asserts they agree.
*
* Run: pnpm --filter @taskless/cli demo:reference
* Run: pnpm --filter @taskless/cli reference
*/

import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";

import { buildDemoReference } from "../src/rules/demo/reference";
import { buildReference } from "../src/rules/reference";
import { DEMO_MANIFESTS } from "../src/rules/demo/manifest";

const packageRoot = join(import.meta.dirname, "..");
Expand Down Expand Up @@ -45,10 +45,10 @@ const rules = await Promise.all(
}))
);

const target = join(packageRoot, "assets", "demo-reference.json");
const target = join(packageRoot, "assets", "reference.json");
await writeFile(
target,
`${JSON.stringify(buildDemoReference(rules), undefined, 2)}\n`,
`${JSON.stringify(buildReference(rules), undefined, 2)}\n`,
"utf8"
);
console.log(`Wrote ${target}`);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EngineName } from "../layout";
import type { EngineName } from "./layout";

/**
* What `verify` enforces beyond the engine's own schema.
Expand All @@ -19,7 +19,7 @@ import type { EngineName } from "../layout";
* "`verify` never reads `language`", which stopped being true when
* `validateLanguage` landed. Nothing failed, because prose has no test.
*
* `test/rule-constraints.test.ts` builds a rule that violates each entry and
* `test/constraints.test.ts` builds a rule that violates each entry and
* asserts `verify` rejects it, keyed on `id`. An entry describing a check that
* no longer fires fails the suite; a check with no entry is invisible to that
* test and is the gap this list is trying to close, so add one when you add a
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/rules/demo/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* The paths therefore live here, stated once. `rule.ts` embeds exactly these
* lists, the generator reads exactly these lists off disk, and
* `test/demo-reference.test.ts` asserts the two agree — so the rules the CLI
* `test/reference.test.ts` asserts the two agree — so the rules the CLI
* writes and the payload handed to other teams cannot come to describe
* different things.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { DeliveredFile } from "../deliver";
import type { EngineName } from "../layout";
import type { DeliveredFile } from "./deliver";
import type { EngineName } from "./layout";
import { RULE_CONSTRAINTS, type RuleConstraint } from "./constraints";

/**
Expand All @@ -21,10 +21,10 @@ import { RULE_CONSTRAINTS, type RuleConstraint } from "./constraints";
* and both tiers are inert, so a signature on them would imply a gate that does
* not exist.
*/
export const DEMO_REFERENCE_SIGNATURE = `1;h=sha-256;d=${"0".repeat(64)}`;
export const REFERENCE_SIGNATURE = `1;h=sha-256;d=${"0".repeat(64)}`;

/** Bumped when a consumer would have to change code to keep reading this. */
export const DEMO_REFERENCE_VERSION = 1;
export const REFERENCE_VERSION = 1;

/**
* The check this corpus exists to make possible, stated in the artifact itself.
Expand All @@ -44,7 +44,7 @@ export const DEMO_REFERENCE_VERSION = 1;
* disagreement about our validator. Any consumer would have hit it on their
* first run.
*/
export const DEMO_REFERENCE_PROTOCOL = [
export const REFERENCE_PROTOCOL = [
"Generate a rule from `prompt`, using your own pipeline.",
"Run `taskless verify` over what you generated. It enforces constraints beyond the engine's own schema, listed in `constraints` below, so a rule the engine executes correctly can still be refused. A rule that fails here is not deliverable however well it behaves, and every later step would be measuring the wrong thing. Check `enforcedBy` before concluding anything: some constraints are only decided once the fixtures run.",
"Run your generated rule against your own cases. It should pass; if it does not, the disagreement is inside your pipeline and nothing below will be informative.",
Expand All @@ -53,7 +53,7 @@ export const DEMO_REFERENCE_PROTOCOL = [
];

/** One rule as this corpus carries it. */
export interface DemoReferenceRule {
export interface ReferenceRule {
engine: EngineName;
id: string;
/** The generation request, as a caller would phrase it. */
Expand All @@ -66,7 +66,7 @@ export interface DemoReferenceRule {
signature?: string;
}

export interface DemoReference {
export interface Reference {
version: number;
protocol: string[];
/**
Expand All @@ -78,11 +78,11 @@ export interface DemoReference {
* enforces it, which decides the order an eval has to run in.
*/
constraints: RuleConstraint[];
rules: DemoReferenceRule[];
rules: ReferenceRule[];
}

/** The input shape `buildDemoReference` reads, satisfied by both callers. */
export interface DemoReferenceInput {
/** The input shape `buildReference` reads, satisfied by both callers. */
export interface ReferenceInput {
engine: EngineName;
ruleId: string;
prompt: string;
Expand All @@ -106,22 +106,18 @@ const plain = (files: readonly DeliveredFile[]) =>
* Built from the rules rather than restating them, so the corpus and what the
* CLI writes cannot describe different things.
*/
export function buildDemoReference(
rules: readonly DemoReferenceInput[]
): DemoReference {
export function buildReference(rules: readonly ReferenceInput[]): Reference {
return {
version: DEMO_REFERENCE_VERSION,
protocol: DEMO_REFERENCE_PROTOCOL,
version: REFERENCE_VERSION,
protocol: REFERENCE_PROTOCOL,
constraints: [...RULE_CONSTRAINTS],
rules: rules.map((rule) => ({
engine: rule.engine,
id: rule.ruleId,
prompt: rule.prompt,
rule: plain(rule.ruleFiles),
tests: plain(rule.testFiles),
...(rule.engine === "runtime"
? { signature: DEMO_REFERENCE_SIGNATURE }
: {}),
...(rule.engine === "runtime" ? { signature: REFERENCE_SIGNATURE } : {}),
})),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { stringify } from "yaml";

import { RULE_CONSTRAINTS } from "../src/rules/demo/constraints";
import { RULE_CONSTRAINTS } from "../src/rules/constraints";
import { testOneRule, verifyOneRule } from "../src/rules/inspect";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import { join } from "node:path";
import { describe, expect, it } from "vitest";

import { parseSignature } from "../src/rules/rule-hash";
import {
buildDemoReference,
type DemoReference,
} from "../src/rules/demo/reference";
import { RULE_CONSTRAINTS } from "../src/rules/demo/constraints";
import { buildReference, type Reference } from "../src/rules/reference";
import { RULE_CONSTRAINTS } from "../src/rules/constraints";
import { DEMO_MANIFESTS, writtenPaths } from "../src/rules/demo/manifest";
import { DEMO_RULES } from "../src/rules/demo/rule";

Expand All @@ -25,22 +22,22 @@ const referencePath = join(
import.meta.dirname,
"..",
"assets",
"demo-reference.json"
"reference.json"
);

async function readReference(): Promise<DemoReference> {
return JSON.parse(await readFile(referencePath, "utf8")) as DemoReference;
async function readReference(): Promise<Reference> {
return JSON.parse(await readFile(referencePath, "utf8")) as Reference;
}

function ruleFor(reference: DemoReference, engine: string) {
function ruleFor(reference: Reference, engine: string) {
const rule = reference.rules.find((entry) => entry.engine === engine);
if (rule === undefined) throw new Error(`reference has no ${engine} rule`);
return rule;
}

describe("the demo reference payload", () => {
it("is current — regenerate with `pnpm --filter @taskless/cli demo:reference`", async () => {
expect(await readReference()).toEqual(buildDemoReference(DEMO_RULES));
it("is current — regenerate with `pnpm --filter @taskless/cli reference`", async () => {
expect(await readReference()).toEqual(buildReference(DEMO_RULES));
});

it("embeds exactly the files each manifest lists", () => {
Expand Down Expand Up @@ -177,9 +174,9 @@ describe("the reference payload is reachable by another team", () => {
// Both halves are needed and neither implies the other: `exports` without
// `files` names a path npm does not ship, and `files` without `exports` is
// unreachable under this package's strict export map.
expect(manifest.files).toContain("assets/demo-reference.json");
expect(manifest.exports["./demo-reference.json"]).toBe(
"./assets/demo-reference.json"
expect(manifest.files).toContain("assets/reference.json");
expect(manifest.exports["./reference.json"]).toBe(
"./assets/reference.json"
);
});
});
2 changes: 1 addition & 1 deletion packages/cli/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const HOST_BOUND_ENTRIES = [NODE_RUNTIMES_ENTRY];
* it. An `exports` entry npm does not publish resolves for nobody.
*/
const ASSET_EXPORTS: Record<string, string> = {
"./demo-reference.json": "./assets/demo-reference.json",
"./reference.json": "./assets/reference.json",
};

/**
Expand Down
Loading