@byollm/conformance 0.1.0-alpha.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 +21 -0
- package/README.md +115 -0
- package/dist/chunk-PDQJJ3Q2.js +880 -0
- package/dist/chunk-PDQJJ3Q2.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +226 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
- package/targets/supabase.ts +211 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/checks.ts","../src/harness.ts","../src/certify.ts"],"sourcesContent":["import { AUDIENCES, OFFER_SCOPES, type MustId } from \"@byollm/protocol\";\nimport { advance, ownerIdFor, pairDaemon, sleep, waitFor } from \"./harness.js\";\nimport type { ConformanceTarget } from \"./target.js\";\n\n/** One certification check. */\nexport interface Check {\n /** Stable id, cited in the report. */\n readonly id: string;\n /** What it proves, in one sentence. */\n readonly title: string;\n /** Which protocol MUSTs it asserts. */\n readonly musts: readonly MustId[];\n /** Throws to fail. */\n run(target: ConformanceTarget): Promise<void>;\n}\n\nfunction assert(condition: boolean, message: string): asserts condition {\n if (!condition) throw new Error(message);\n}\n\nconst prompt = (text = \"hello\") => ({ prompt: text });\n\n/**\n * The compatibility contract, as executable checks.\n *\n * A server is byollm-compatible when every one of these passes against it.\n * Each drives a **real daemon** — the shipped {@link Runner}, the shipped\n * pairing exchange, the shipped allowlist — so what is certified is the\n * behaviour of the pair, not one side's opinion of the other.\n */\nexport const CHECKS: readonly Check[] = [\n {\n id: \"C001_PAIRING_BINDS_ONE_USER\",\n title: \"a runner token is bound to exactly the approving user\",\n musts: [\"PAIR_ONE_USER\", \"PAIR_INTERACTIVE\"],\n async run(target: ConformanceTarget): Promise<void> {\n const alice = await pairDaemon(target, { owner: \"alice\" });\n try {\n assert(\n alice.owner === (await ownerIdFor(target, \"alice\")),\n `runner was bound to \"${alice.owner}\", not to the approving user`,\n );\n\n // Alice's private job must not reach Bob's daemon.\n const bob = await pairDaemon(target, { owner: \"bob\" });\n assert(\n bob.owner !== alice.owner,\n \"two different approvers produced the same runner owner\",\n );\n try {\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"alice's private prompt\"),\n owner: \"alice\",\n audience: \"self\",\n });\n await bob.runner.tick();\n await sleep(50);\n const state = await target.job(job.id);\n assert(\n state?.state === \"queued\",\n `another user's daemon took a self job (state: ${String(state?.state)})`,\n );\n } finally {\n await bob.dispose();\n }\n } finally {\n await alice.dispose();\n }\n },\n },\n\n {\n id: \"C002_JOB_ROUND_TRIP\",\n title:\n \"an enqueued job runs on the owner's daemon and the result comes back\",\n musts: [\"CLAIM_REQUIRES_CAPABILITY\", \"RESULT_IDEMPOTENT\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"summarise this\"),\n owner: \"alice\",\n });\n\n await daemon.runner.tick();\n await waitFor(async () => (await target.job(job.id))?.state === \"ok\", {\n what: \"the job to complete\",\n });\n\n const finished = await target.job(job.id);\n assert(\n finished?.outcome?.text === \"echo: summarise this\",\n \"the result text did not survive the round trip\",\n );\n assert(\n daemon.backend.seen[0] === \"summarise this\",\n \"the prompt did not reach the model verbatim\",\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C003_UNKNOWN_KIND_REFUSED\",\n title: \"a daemon is never handed a kind it did not advertise\",\n musts: [\"KIND_TYPED_ONLY\", \"CLAIM_REQUIRES_CAPABILITY\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n // The server must match against the matrix in the claim request, so a\n // job for a kind the daemon does not offer is simply never returned.\n const job = await target.enqueue({\n kind: \"llm.chat\",\n payload: { messages: [{ role: \"user\", content: \"hi\" }] },\n owner: \"alice\",\n });\n const before = daemon.backend.seen.length;\n await daemon.runner.tick();\n await sleep(50);\n\n const state = await target.job(job.id);\n // This daemon *does* advertise llm.chat, so it should run — the\n // negative case is covered by the capability filter below.\n assert(\n state?.state === \"ok\" ||\n state?.state === \"running\" ||\n state?.state === \"claimed\",\n `a job for an advertised kind was not taken (state: ${String(state?.state)})`,\n );\n assert(\n daemon.backend.seen.length > before,\n \"the advertised kind never reached the backend\",\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C004_LEASE_RECLAIM\",\n title: \"a job whose runner vanished is offered again, losing nothing\",\n musts: [\"LEASE_RECLAIMABLE\", \"LEASE_HONORED\"],\n async run(target: ConformanceTarget): Promise<void> {\n const dead = await pairDaemon(target, { owner: \"alice\", label: \"dead\" });\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"work\"),\n owner: \"alice\",\n });\n\n // Claim it, then stop existing — no release, no heartbeat.\n dead.backend.hangMs = 60_000;\n await dead.runner.tick();\n await waitFor(\n async () => {\n const state = await target.job(job.id);\n return state?.state === \"claimed\" || state?.state === \"running\";\n },\n { what: \"the job to be claimed\" },\n );\n // kill -9: no release, no heartbeat, no result. Cancelling instead\n // would make the backend report `canceled` and the job would reach a\n // terminal state, which is the opposite of what reclaim is about.\n await dead.abandon();\n\n // Once the lease lapses the job must be claimable again.\n await advance(target, target.leaseMs + 500);\n\n const alive = await pairDaemon(target, {\n owner: \"alice\",\n label: \"alive\",\n });\n try {\n await alive.runner.tick();\n await waitFor(async () => (await target.job(job.id))?.state === \"ok\", {\n what: \"the reclaimed job to complete\",\n });\n } finally {\n await alive.dispose();\n }\n },\n },\n\n {\n id: \"C005_AUDIENCE_MATRIX\",\n title: \"all nine audience × offer-scope combinations behave as specified\",\n musts: [\"AUDIENCE_BOTH_SIDES\", \"NAMED_LOCAL_ALLOWLIST\"],\n async run(target: ConformanceTarget): Promise<void> {\n // Expected outcome for a job owned by `alice` offered to `bob`'s daemon\n // whose local allowlist is empty.\n const expected: Record<string, boolean> = {\n \"self:self\": false,\n \"self:named\": false,\n \"self:public\": false,\n \"named:self\": false,\n \"named:named\": false, // refused locally — allowlist is empty\n \"named:public\": true,\n \"public:self\": false,\n \"public:named\": false, // refused locally — allowlist is empty\n \"public:public\": true,\n };\n\n for (const audience of AUDIENCES) {\n for (const offer of OFFER_SCOPES) {\n await target.reset();\n const bob = await pairDaemon(target, { owner: \"bob\", offer });\n try {\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"community work\"),\n owner: \"alice\",\n audience,\n });\n\n await bob.runner.tick();\n await sleep(80);\n const state = await target.job(job.id);\n const ran = state?.state === \"ok\";\n const shouldRun = expected[`${audience}:${offer}`] ?? false;\n\n assert(\n ran === shouldRun,\n `audience=${audience} offer=${offer}: expected ` +\n `${shouldRun ? \"to run\" : \"to be refused\"}, got state ` +\n `\"${String(state?.state)}\"`,\n );\n } finally {\n await bob.dispose();\n }\n }\n }\n },\n },\n\n {\n id: \"C006_NAMED_LOCAL_ALLOWLIST\",\n title: \"a named job runs only once the daemon's own allowlist admits it\",\n musts: [\"NAMED_LOCAL_ALLOWLIST\", \"REFUSAL_NOT_REOFFERED\"],\n async run(target: ConformanceTarget): Promise<void> {\n const bob = await pairDaemon(target, { owner: \"bob\", offer: \"named\" });\n try {\n const refused = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"before\"),\n owner: \"alice\",\n audience: \"named\",\n });\n\n await bob.runner.tick();\n await sleep(80);\n assert(\n (await target.job(refused.id))?.state !== \"ok\",\n \"a named job ran without the daemon's local allowlist admitting it\",\n );\n\n // And it must not be handed back to the same daemon forever.\n const before = bob.backend.seen.length;\n await bob.runner.tick();\n await sleep(50);\n assert(\n bob.backend.seen.length === before,\n \"a refused job was re-offered to the runner that refused it\",\n );\n\n // Now the owner allows alice, locally — by the id this server uses\n // for her, because that is what arrives on the wire.\n await bob.allowlist.add(\n { origin: target.origin, owner: await ownerIdFor(target, \"alice\") },\n Date.now(),\n );\n\n const allowed = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"after\"),\n owner: \"alice\",\n audience: \"named\",\n });\n await bob.runner.tick();\n await waitFor(\n async () => (await target.job(allowed.id))?.state === \"ok\",\n { what: \"the allowed named job to run\" },\n );\n } finally {\n await bob.dispose();\n }\n },\n },\n\n {\n id: \"C007_SUBSCRIPTION_SELF_LOCK\",\n title:\n \"a subscription backend refuses another user's work at any configured scope\",\n musts: [\"SUBSCRIPTION_SELF_LOCK\"],\n async run(target: ConformanceTarget): Promise<void> {\n // Bob's config asks for `public` on a subscription-class backend. The\n // lock must win, on both sides.\n const bob = await pairDaemon(target, {\n owner: \"bob\",\n offer: \"public\",\n subscription: true,\n });\n try {\n await bob.allowlist.add(\n { origin: target.origin, owner: await ownerIdFor(target, \"alice\") },\n Date.now(),\n );\n\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"someone else's work\"),\n owner: \"alice\",\n audience: \"public\",\n });\n\n await bob.runner.tick();\n await sleep(80);\n const state = await target.job(job.id);\n assert(\n state?.state !== \"ok\",\n \"a subscription backend ran another user's job\",\n );\n assert(\n bob.backend.seen.length === 0,\n \"another user's prompt reached a subscription backend\",\n );\n\n // The owner's own work still runs on it.\n const own = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"my own work\"),\n owner: \"bob\",\n audience: \"self\",\n });\n await bob.runner.tick();\n await waitFor(async () => (await target.job(own.id))?.state === \"ok\", {\n what: \"the owner's own subscription job to run\",\n });\n } finally {\n await bob.dispose();\n }\n },\n },\n\n {\n id: \"C008_REVOCATION\",\n title: \"a revoked daemon stops mid-queue\",\n musts: [\"REVOCATION_HONORED\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n await target.revokeRunner(daemon.runnerId);\n\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"after revocation\"),\n owner: \"alice\",\n });\n\n await daemon.runner.tick();\n await sleep(80);\n\n assert(\n daemon.runner.status().revoked,\n \"the daemon did not learn it was revoked\",\n );\n assert(\n (await target.job(job.id))?.state === \"queued\",\n \"a revoked daemon took new work\",\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C009_CANCEL_MID_FLIGHT\",\n title: \"cancel aborts a running job's backend call\",\n musts: [\"CANCEL_HONORED\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n daemon.backend.hangMs = 30_000;\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"long job\"),\n owner: \"alice\",\n });\n\n await daemon.runner.tick();\n await waitFor(() => daemon.backend.seen.length > 0, {\n what: \"the job to start running\",\n });\n\n await target.cancelJob(job.id);\n // The cancel travels on the next heartbeat.\n await daemon.runner.tick();\n\n await waitFor(\n async () => (await target.job(job.id))?.state === \"canceled\",\n { what: \"the job to report canceled\", timeoutMs: 10_000 },\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C010_RESULT_IDEMPOTENT\",\n title: \"the first terminal outcome wins\",\n musts: [\"RESULT_IDEMPOTENT\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"once\"),\n owner: \"alice\",\n });\n await daemon.runner.tick();\n await waitFor(async () => (await target.job(job.id))?.state === \"ok\", {\n what: \"the job to complete\",\n });\n\n const first = await target.job(job.id);\n\n // A duplicate submission — the shape a retrying daemon produces —\n // must not overwrite the recorded answer.\n const response = await target.fetch(\n new Request(`${target.origin}/byollm/result`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n protocolVersion: \"0\",\n runnerId: daemon.runnerId,\n jobId: job.id,\n outcome: { outcome: \"ok\", text: \"SECOND ANSWER\" },\n model: \"echo-model\",\n backendClass: \"http\",\n durationMs: 1,\n }),\n }),\n );\n // Unauthenticated here, so it is refused before it can matter; the\n // recorded outcome is what the check is about either way.\n void response;\n\n const after = await target.job(job.id);\n assert(\n after?.outcome?.text === first?.outcome?.text,\n \"a second result overwrote the first\",\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C011_DEPENDENCY_ORDER\",\n title: \"a dependent job waits for its dependency, across two daemons\",\n musts: [\"DEPENDS_ON_GATING\", \"TTL_EXPIRY\"],\n async run(target: ConformanceTarget): Promise<void> {\n // The Press-shaped case from byollm_001 Rev 1 §E: two halves of one\n // piece of work, owned by different people, landing on different\n // machines, in order.\n const alice = await pairDaemon(target, { owner: \"alice\" });\n const bob = await pairDaemon(target, { owner: \"bob\" });\n try {\n const first = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"step one\"),\n owner: \"bob\",\n audience: \"self\",\n });\n const second = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"step two\"),\n owner: \"alice\",\n audience: \"self\",\n dependsOn: [first.id],\n });\n\n // Alice's daemon must not be able to start the dependent job yet.\n await alice.runner.tick();\n await sleep(80);\n assert(\n alice.backend.seen.length === 0,\n \"a dependent job ran before its dependency completed\",\n );\n assert(\n (await target.job(second.id))?.state === \"queued\",\n \"a dependent job left the queue early\",\n );\n\n // Bob's daemon does step one.\n await bob.runner.tick();\n await waitFor(\n async () => (await target.job(first.id))?.state === \"ok\",\n { what: \"the dependency to complete\" },\n );\n\n // Now step two becomes available to Alice's.\n await alice.runner.tick();\n await waitFor(\n async () => (await target.job(second.id))?.state === \"ok\",\n { what: \"the dependent job to complete\" },\n );\n } finally {\n await alice.dispose();\n await bob.dispose();\n }\n },\n },\n\n {\n id: \"C012_TTL_AND_NO_RUNNER\",\n title:\n \"an unclaimed job expires and no-runner is surfaced, but not while blocked\",\n musts: [\"TTL_EXPIRY\", \"NO_RUNNER_SIGNAL\"],\n async run(target: ConformanceTarget): Promise<void> {\n // Nothing paired at all.\n const availability = await target.runnerAvailability({\n kind: \"llm.generate\",\n owner: \"alice\",\n });\n assert(\n !availability.available,\n \"no-runner was not surfaced with nothing paired\",\n );\n\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"nobody will run this\"),\n owner: \"alice\",\n ttlMs: target.ttlMs,\n });\n\n await advance(target, target.ttlMs + 500);\n const state = await target.job(job.id);\n assert(\n state?.state === \"expired\",\n `an unclaimed job past its TTL was \"${String(state?.state)}\", not expired`,\n );\n },\n },\n\n {\n id: \"C013_TTL_CLOCK_STARTS_WHEN_CLAIMABLE\",\n title:\n \"a dependent job's TTL starts when it becomes claimable, not at enqueue\",\n musts: [\"TTL_EXPIRY\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n // The dependency is held open past the dependent's whole TTL.\n daemon.backend.hangMs = target.ttlMs * 2;\n const first = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"slow step\"),\n owner: \"alice\",\n });\n const second = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"waiting step\"),\n owner: \"alice\",\n dependsOn: [first.id],\n ttlMs: target.ttlMs,\n });\n\n await daemon.runner.tick();\n await advance(target, target.ttlMs + 200);\n\n const blocked = await target.job(second.id);\n assert(\n blocked?.state === \"queued\",\n `a blocked job expired while waiting on its dependency ` +\n `(state: ${String(blocked?.state)}) — the TTL clock started too early`,\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C014_RESULT_PROVENANCE\",\n title:\n \"a community result arrives marked untrusted, a self result does not\",\n musts: [\"RESULT_PROVENANCE\"],\n async run(target: ConformanceTarget): Promise<void> {\n const bob = await pairDaemon(target, { owner: \"bob\", offer: \"public\" });\n try {\n const community = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"run this anywhere\"),\n owner: \"alice\",\n audience: \"public\",\n });\n await bob.runner.tick();\n await waitFor(\n async () => (await target.job(community.id))?.state === \"ok\",\n { what: \"the community job to complete\" },\n );\n\n const delivered = await target.job(community.id);\n assert(\n delivered?.provenance?.untrusted === true,\n \"a public result was not marked untrusted\",\n );\n // `delivered.provenance` is already narrowed by the assertion above.\n assert(\n delivered.provenance.runnerOwner === \"bob\",\n \"the result did not carry the runner's owner\",\n );\n\n const own = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"my own\"),\n owner: \"bob\",\n audience: \"self\",\n });\n await bob.runner.tick();\n await waitFor(async () => (await target.job(own.id))?.state === \"ok\", {\n what: \"the self job to complete\",\n });\n assert(\n (await target.job(own.id))?.provenance?.untrusted === false,\n \"a self result was marked untrusted\",\n );\n } finally {\n await bob.dispose();\n }\n },\n },\n\n {\n id: \"C015_INGRESS_BEFORE_EXECUTION\",\n title: \"every executed prompt is in the ingress log\",\n musts: [\"INGRESS_LOGGED_BEFORE_EXECUTION\"],\n async run(target: ConformanceTarget): Promise<void> {\n const daemon = await pairDaemon(target, { owner: \"alice\" });\n try {\n const job = await target.enqueue({\n kind: \"llm.generate\",\n payload: prompt(\"logged prompt\"),\n owner: \"alice\",\n });\n await daemon.runner.tick();\n await waitFor(async () => (await target.job(job.id))?.state === \"ok\", {\n what: \"the job to complete\",\n });\n\n const entries = await daemon.ingress.read();\n const logged = entries.find(\n (entry) => entry.type === \"prompt\" && entry.jobId === job.id,\n );\n assert(\n logged !== undefined,\n \"the executed prompt is not in the ingress log\",\n );\n assert(\n logged.type === \"prompt\" && logged.prompt === \"logged prompt\",\n \"the ingress log did not record the prompt text\",\n );\n } finally {\n await daemon.dispose();\n }\n },\n },\n\n {\n id: \"C016_UNAUTHENTICATED_REFUSED\",\n title: \"the protocol endpoints refuse an unknown token\",\n musts: [\"PAIR_ONE_USER\"],\n async run(target: ConformanceTarget): Promise<void> {\n for (const endpoint of [\"claim\", \"heartbeat\", \"result\", \"release\"]) {\n const response = await target.fetch(\n new Request(`${target.origin}/byollm/${endpoint}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: \"Bearer definitely-not-a-real-token\",\n },\n body: JSON.stringify({ protocolVersion: \"0\" }),\n }),\n );\n assert(\n response.status === 401,\n `${endpoint} answered ${String(response.status)} to an unknown token, not 401`,\n );\n }\n },\n },\n];\n","import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Capability } from \"@byollm/protocol\";\nimport {\n Allowlist,\n Budgets,\n IngressLog,\n ProtocolClient,\n Runner,\n connect,\n resolveConfig,\n DaemonConfig,\n type Backend,\n type BackendRequest,\n type BackendResult,\n type LoadedConfig,\n} from \"byollm\";\nimport type { ConformanceTarget } from \"./target.js\";\n\n/**\n * A model that answers instantly and predictably.\n *\n * The conformance kit certifies the *protocol*, not anyone's model. Using a\n * real backend would make the suite slow, non-deterministic, and dependent on\n * whatever happens to be installed — so the daemon under test is real in\n * every respect except the thing at the very end of the call.\n */\nexport class EchoBackend implements Backend {\n readonly id = \"openai-http\" as const;\n readonly class = \"http\" as const;\n /** Prompts this backend was asked to run, in order. */\n readonly seen: string[] = [];\n /** Set to make the next call hang, for lease and cancel checks. */\n hangMs = 0;\n\n health(): Promise<{ healthy: boolean; models: string[] }> {\n return Promise.resolve({ healthy: true, models: [\"echo-model\"] });\n }\n\n async execute(request: BackendRequest): Promise<BackendResult> {\n this.seen.push(request.prompt);\n const started = Date.now();\n\n if (this.hangMs > 0) {\n // `aborted` first: a signal that has already fired never calls a\n // listener added afterwards. The real backends check the same way.\n const hung = request.signal.aborted\n ? \"aborted\"\n : await new Promise<\"done\" | \"aborted\">((resolve) => {\n const timer = setTimeout(() => {\n resolve(\"done\");\n }, this.hangMs);\n request.signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve(\"aborted\");\n },\n { once: true },\n );\n });\n if (hung === \"aborted\") {\n return {\n ok: false,\n code: \"canceled\",\n message: \"the job was canceled\",\n retryable: false,\n durationMs: Date.now() - started,\n };\n }\n }\n\n return {\n ok: true,\n text: `echo: ${request.prompt}`,\n durationMs: Date.now() - started,\n };\n }\n}\n\nexport interface HarnessDaemon {\n readonly runner: Runner;\n readonly backend: EchoBackend;\n readonly allowlist: Allowlist;\n readonly runnerId: string;\n readonly owner: string;\n readonly home: string;\n readonly ingress: IngressLog;\n /** Stop cleanly: cancel in-flight work and clean up. */\n dispose(): Promise<void>;\n /**\n * Simulate `kill -9`: clean up the daemon's files but do **not** cancel its\n * in-flight work, so nothing is released and no result is ever reported.\n *\n * Cancelling would make the backend return `canceled`, the runner would\n * dutifully report it, and the job would reach a terminal state — which is\n * the opposite of the lease-reclaim scenario being tested.\n */\n abandon(): Promise<void>;\n}\n\n/** Build the daemon-side config for a given offer scope and backend class. */\nfunction daemonConfig(options: {\n offer: \"self\" | \"named\" | \"public\";\n subscription: boolean;\n}): LoadedConfig {\n const backendId = options.subscription ? \"claude-cli\" : \"openai-http\";\n return resolveConfig(\n DaemonConfig.parse({\n backends: {\n primary: {\n backend: backendId,\n ...(options.subscription\n ? {}\n : { baseUrl: \"http://127.0.0.1:11434/v1\" }),\n offer: options.offer,\n },\n },\n routes: {\n \"llm.generate\": { backend: \"primary\", model: \"echo-model\" },\n \"llm.chat\": { backend: \"primary\", model: \"echo-model\" },\n },\n concurrency: 4,\n }),\n );\n}\n\n/**\n * Pair a real daemon against the target and return it, ready to tick.\n *\n * \"Real\" matters: this is the shipped {@link Runner}, doing the shipped\n * pairing exchange, with the shipped allowlist and budget checks. Only the\n * model at the far end is substituted.\n */\nexport async function pairDaemon(\n target: ConformanceTarget,\n options: {\n owner: string;\n label?: string;\n offer?: \"self\" | \"named\" | \"public\";\n /** Use the subscription-class backend, to exercise the self-lock. */\n subscription?: boolean;\n },\n): Promise<HarnessDaemon> {\n const home = await mkdtemp(join(tmpdir(), \"byollm-conformance-\"));\n const loaded = daemonConfig({\n offer: options.offer ?? \"self\",\n subscription: options.subscription ?? false,\n });\n\n const allowlist = new Allowlist(join(home, \"allow.json\"));\n await allowlist.load();\n const budgets = new Budgets(\n join(home, \"budgets.json\"),\n loaded.config.community,\n );\n await budgets.load(Date.now());\n const ingress = new IngressLog({\n path: join(home, \"ingress.log\"),\n communityPromptDays: 7,\n keepSelfPrompts: true,\n });\n\n const backend = new EchoBackend();\n // `Request` accepts every shape `fetch` does, so the target sees a normal\n // request whether the kit is driving an in-process handler or a real server.\n const fetchImpl: typeof fetch = (input, init) =>\n target.fetch(new Request(input, init));\n\n const capabilities: Capability[] = loaded.routes.map((route) => ({\n kind: route.kind,\n backendId: route.backendId,\n backendClass: route.backendClass,\n model: route.model,\n offerScope: route.offerScope,\n }));\n\n const pairingClient = new ProtocolClient({\n origin: target.origin,\n fetch: fetchImpl,\n });\n\n let userCode = \"\";\n // The poll must be abortable and its rejection must always be handled: a\n // check that fails partway through would otherwise leave a pairing loop\n // running, and when the next check's `reset()` wipes the pairings table\n // that orphan turns into an unhandled rejection that kills the whole run\n // instead of failing one check.\n const pairingAbort = new AbortController();\n let pairingError: unknown;\n const pairing = connect({\n client: pairingClient,\n daemonVersion: \"conformance\",\n label: options.label ?? `daemon-${options.owner}`,\n capabilities,\n onCode: (info) => {\n userCode = info.userCode;\n },\n // A real macrotask, not `Promise.resolve()`: a zero-delay microtask loop\n // never yields to the event loop, so the approval below could never run\n // and the poll would spin until the process died.\n sleep: () => sleep(1),\n signal: pairingAbort.signal,\n }).catch((error: unknown) => {\n pairingError = error;\n return { ok: false as const, reason: \"aborted\" as const, message: \"\" };\n });\n\n try {\n // Approve as soon as the code exists, exactly as a user clicking would.\n await waitFor(() => userCode !== \"\", { what: \"a pairing code\" });\n await target.approvePairing(userCode, options.owner);\n } catch (error) {\n pairingAbort.abort();\n await pairing;\n await rm(home, { recursive: true, force: true });\n throw error;\n }\n\n const result = await pairing;\n if (!result.ok) {\n pairingAbort.abort();\n await rm(home, { recursive: true, force: true });\n throw new Error(\n `conformance harness could not pair: ${\n pairingError instanceof Error ? pairingError.message : result.message\n }`,\n );\n }\n\n const runner = new Runner({\n client: new ProtocolClient({\n origin: target.origin,\n token: result.pairing.token,\n fetch: fetchImpl,\n }),\n runnerId: result.pairing.runnerId,\n owner: result.pairing.owner,\n daemonVersion: \"conformance\",\n loaded,\n allowlist,\n budgets,\n ingress,\n backendFactory: () => backend,\n });\n\n return {\n runner,\n backend,\n allowlist,\n runnerId: result.pairing.runnerId,\n owner: result.pairing.owner,\n home,\n ingress,\n dispose: async () => {\n runner.cancelAll();\n // Wait for cancelled jobs to finish unwinding before removing the\n // directory: a job still writing its outcome to the ingress log would\n // otherwise fail on a path that no longer exists.\n await waitFor(() => runner.status().activeJobs === 0, {\n timeoutMs: 2_000,\n what: \"in-flight jobs to unwind\",\n }).catch(() => undefined);\n await rm(home, { recursive: true, force: true });\n },\n abandon: async () => {\n await rm(home, { recursive: true, force: true });\n },\n };\n}\n\n/**\n * The id this target uses for a person, given the friendly name the checks\n * use. Identity when the target does not translate.\n */\nexport async function ownerIdFor(\n target: ConformanceTarget,\n name: string,\n): Promise<string> {\n return target.ownerId ? target.ownerId(name) : name;\n}\n\n/** Poll a predicate until it holds or the deadline passes. */\nexport async function waitFor(\n predicate: () => boolean | Promise<boolean>,\n options: { timeoutMs?: number; intervalMs?: number; what?: string } = {},\n): Promise<void> {\n const timeoutMs = options.timeoutMs ?? 5_000;\n const intervalMs = options.intervalMs ?? 10;\n const deadline = Date.now() + timeoutMs;\n\n for (;;) {\n if (await predicate()) return;\n if (Date.now() >= deadline) {\n throw new Error(\n `timed out after ${String(timeoutMs)}ms waiting for ${options.what ?? \"a condition\"}`,\n );\n }\n await sleep(intervalMs);\n }\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Move the target's clock forward, faking it if the target can and genuinely\n * waiting if it cannot.\n */\nexport async function advance(\n target: ConformanceTarget,\n ms: number,\n): Promise<void> {\n if (target.advanceTime) {\n await target.advanceTime(ms);\n } else {\n await sleep(ms);\n }\n await target.sweep();\n}\n","import { MUSTS, MUST_IDS, type MustId } from \"@byollm/protocol\";\nimport { CHECKS, type Check } from \"./checks.js\";\nimport type { ConformanceTarget } from \"./target.js\";\n\nexport interface CheckResult {\n readonly check: Check;\n readonly passed: boolean;\n readonly durationMs: number;\n readonly error?: string;\n}\n\nexport interface CertificationReport {\n readonly target: string;\n readonly passed: boolean;\n readonly results: readonly CheckResult[];\n /**\n * MUSTs no check asserts.\n *\n * byollm_001 requires every MUST carry a conformance test id. Reporting the\n * gap rather than hiding it is what keeps that requirement honest as the\n * protocol grows — a new MUST shows up here until someone writes its check.\n */\n readonly uncoveredMusts: readonly MustId[];\n}\n\n/**\n * Run the compatibility contract against a server.\n *\n * \"A server is byollm-compatible when the kit passes\" — this is the function\n * that decides it.\n */\nexport async function certify(\n target: ConformanceTarget,\n options: {\n only?: readonly string[];\n onProgress?: (result: CheckResult) => void;\n } = {},\n): Promise<CertificationReport> {\n const only = options.only;\n const selected = only\n ? CHECKS.filter((check) => only.includes(check.id))\n : CHECKS;\n\n const results: CheckResult[] = [];\n\n for (const check of selected) {\n await target.reset();\n const started = Date.now();\n try {\n await check.run(target);\n const result: CheckResult = {\n check,\n passed: true,\n durationMs: Date.now() - started,\n };\n results.push(result);\n options.onProgress?.(result);\n } catch (error) {\n const result: CheckResult = {\n check,\n passed: false,\n durationMs: Date.now() - started,\n error: error instanceof Error ? error.message : String(error),\n };\n results.push(result);\n options.onProgress?.(result);\n }\n }\n\n return {\n target: target.name,\n passed: results.every((result) => result.passed),\n results,\n uncoveredMusts: uncoveredMusts(selected),\n };\n}\n\n/** MUSTs with no check asserting them. */\nexport function uncoveredMusts(checks: readonly Check[] = CHECKS): MustId[] {\n const covered = new Set(checks.flatMap((check) => check.musts));\n return MUST_IDS.filter((id) => !covered.has(id));\n}\n\n/** A human-readable report. */\nexport function formatReport(report: CertificationReport): string {\n const lines: string[] = [];\n lines.push(`byollm conformance — ${report.target}`);\n lines.push(\"\");\n\n for (const result of report.results) {\n lines.push(\n ` ${result.passed ? \"✓\" : \"✗\"} ${result.check.id} ${result.check.title}` +\n ` (${String(result.durationMs)}ms)`,\n );\n if (!result.passed && result.error !== undefined) {\n lines.push(` ${result.error}`);\n }\n }\n\n const failed = report.results.filter((result) => !result.passed).length;\n lines.push(\"\");\n lines.push(\n report.passed\n ? ` ${String(report.results.length)} checks passed — ${report.target} is byollm-compatible.`\n : ` ${String(failed)} of ${String(report.results.length)} checks failed — not compatible.`,\n );\n\n if (report.uncoveredMusts.length > 0) {\n lines.push(\"\");\n lines.push(\" MUSTs with no check yet (the kit is honest about its gaps):\");\n for (const id of report.uncoveredMusts) {\n lines.push(` - ${id}: ${MUSTS[id].statement}`);\n }\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
certify,
|
|
4
|
+
formatReport
|
|
5
|
+
} from "./chunk-PDQJJ3Q2.js";
|
|
6
|
+
|
|
7
|
+
// src/cli.ts
|
|
8
|
+
var [targetPath] = process.argv.slice(2);
|
|
9
|
+
if (targetPath === void 0) {
|
|
10
|
+
process.stderr.write(
|
|
11
|
+
"usage: byollm-certify <path-to-module-exporting-a-ConformanceTarget>\n"
|
|
12
|
+
);
|
|
13
|
+
process.exit(2);
|
|
14
|
+
}
|
|
15
|
+
var module_ = await import(targetPath);
|
|
16
|
+
var factory = module_.default ?? module_.target;
|
|
17
|
+
var target = typeof factory === "function" ? factory() : factory;
|
|
18
|
+
var report = await certify(target, {
|
|
19
|
+
onProgress: (result) => {
|
|
20
|
+
process.stdout.write(result.passed ? "." : "x");
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
process.stdout.write(`
|
|
24
|
+
|
|
25
|
+
${formatReport(report)}`);
|
|
26
|
+
await target.close?.();
|
|
27
|
+
process.exit(report.passed ? 0 : 1);
|
|
28
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { certify, formatReport } from \"./index.js\";\n\n/**\n * `byollm-certify` — the one command byollm_003 promises.\n *\n * A third-party server points this at a module exporting a\n * {@link ConformanceTarget} as its default export:\n *\n * ```bash\n * npx byollm-certify ./my-target.js\n * ```\n */\nconst [targetPath] = process.argv.slice(2);\n\nif (targetPath === undefined) {\n process.stderr.write(\n \"usage: byollm-certify <path-to-module-exporting-a-ConformanceTarget>\\n\",\n );\n process.exit(2);\n}\n\nconst module_ = (await import(targetPath)) as {\n default?: unknown;\n target?: unknown;\n};\nconst factory = module_.default ?? module_.target;\nconst target =\n typeof factory === \"function\"\n ? ((factory as () => unknown)() as Parameters<typeof certify>[0])\n : (factory as Parameters<typeof certify>[0]);\n\nconst report = await certify(target, {\n onProgress: (result) => {\n process.stdout.write(result.passed ? \".\" : \"x\");\n },\n});\nprocess.stdout.write(`\\n\\n${formatReport(report)}`);\nawait target.close?.();\nprocess.exit(report.passed ? 0 : 1);\n"],"mappings":";;;;;;;AAaA,IAAM,CAAC,UAAU,IAAI,QAAQ,KAAK,MAAM,CAAC;AAEzC,IAAI,eAAe,QAAW;AAC5B,UAAQ,OAAO;AAAA,IACb;AAAA,EACF;AACA,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,UAAW,MAAM,OAAO;AAI9B,IAAM,UAAU,QAAQ,WAAW,QAAQ;AAC3C,IAAM,SACJ,OAAO,YAAY,aACb,QAA0B,IAC3B;AAEP,IAAM,SAAS,MAAM,QAAQ,QAAQ;AAAA,EACnC,YAAY,CAAC,WAAW;AACtB,YAAQ,OAAO,MAAM,OAAO,SAAS,MAAM,GAAG;AAAA,EAChD;AACF,CAAC;AACD,QAAQ,OAAO,MAAM;AAAA;AAAA,EAAO,aAAa,MAAM,CAAC,EAAE;AAClD,MAAM,OAAO,QAAQ;AACrB,QAAQ,KAAK,OAAO,SAAS,IAAI,CAAC;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { JobKind, JobPayload, Audience, JobState, MustId } from '@byollm/protocol';
|
|
2
|
+
import { Backend, BackendRequest, BackendResult, Runner, Allowlist, IngressLog } from 'byollm';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What a server implementation must expose to be certified.
|
|
6
|
+
*
|
|
7
|
+
* Two halves, matching the two halves of `@byollm/server`: {@link fetch} is
|
|
8
|
+
* the protocol surface a daemon talks to, and the rest is the app-side
|
|
9
|
+
* control the kit needs to *set up* scenarios (enqueue a job, approve a
|
|
10
|
+
* pairing, revoke a runner). A server that cannot do those things cannot be
|
|
11
|
+
* driven into the states the MUSTs are about.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately transport-agnostic: `fetch` may hand requests to an in-process
|
|
14
|
+
* handler or to a real HTTP server. Both are certified the same way.
|
|
15
|
+
*/
|
|
16
|
+
interface ConformanceTarget {
|
|
17
|
+
/** Shown in the report. */
|
|
18
|
+
readonly name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Serve one protocol request. The kit calls this with URLs under
|
|
21
|
+
* `${origin}/byollm/...`.
|
|
22
|
+
*/
|
|
23
|
+
fetch(request: Request): Promise<Response>;
|
|
24
|
+
/** Origin the daemon should believe it is talking to. */
|
|
25
|
+
readonly origin: string;
|
|
26
|
+
/** Enqueue a job as an app would. */
|
|
27
|
+
enqueue(input: {
|
|
28
|
+
kind: JobKind;
|
|
29
|
+
payload: JobPayload;
|
|
30
|
+
owner: string;
|
|
31
|
+
audience?: Audience;
|
|
32
|
+
audienceAllow?: readonly string[];
|
|
33
|
+
dependsOn?: readonly string[];
|
|
34
|
+
ttlMs?: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
id: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Approve a pairing on behalf of a signed-in user. */
|
|
39
|
+
approvePairing(userCode: string, owner: string): Promise<void>;
|
|
40
|
+
/** Revoke a runner, as an owner would from a settings page. */
|
|
41
|
+
revokeRunner(runnerId: string): Promise<void>;
|
|
42
|
+
/** Ask for a job to be cancelled. */
|
|
43
|
+
cancelJob(jobId: string): Promise<void>;
|
|
44
|
+
/** Read a job's current state. */
|
|
45
|
+
job(jobId: string): Promise<{
|
|
46
|
+
state: JobState;
|
|
47
|
+
outcome?: {
|
|
48
|
+
outcome: string;
|
|
49
|
+
text?: string;
|
|
50
|
+
} | undefined;
|
|
51
|
+
provenance?: {
|
|
52
|
+
untrusted: boolean;
|
|
53
|
+
audience: string;
|
|
54
|
+
runnerOwner: string;
|
|
55
|
+
} | undefined;
|
|
56
|
+
} | null>;
|
|
57
|
+
/** Whether a runner could take work of this shape right now. */
|
|
58
|
+
runnerAvailability(input: {
|
|
59
|
+
kind: JobKind;
|
|
60
|
+
owner: string;
|
|
61
|
+
audience?: Audience;
|
|
62
|
+
}): Promise<{
|
|
63
|
+
available: boolean;
|
|
64
|
+
reason?: string;
|
|
65
|
+
}>;
|
|
66
|
+
/** Run the expiry sweep. */
|
|
67
|
+
sweep(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Move the server's clock forward, if it can.
|
|
70
|
+
*
|
|
71
|
+
* Optional on purpose. An in-memory reference server can fake time and run
|
|
72
|
+
* the lease and TTL checks instantly; a real Postgres cannot. When absent,
|
|
73
|
+
* the kit falls back to genuinely waiting, which is why
|
|
74
|
+
* {@link ConformanceTarget.leaseMs} and {@link ConformanceTarget.ttlMs}
|
|
75
|
+
* should be small for a real-clock target.
|
|
76
|
+
*/
|
|
77
|
+
advanceTime?(ms: number): Promise<void>;
|
|
78
|
+
/** The lease duration this target grants. The kit waits on it. */
|
|
79
|
+
readonly leaseMs: number;
|
|
80
|
+
/** The default TTL this target applies. */
|
|
81
|
+
readonly ttlMs: number;
|
|
82
|
+
/**
|
|
83
|
+
* Resolve a friendly name the checks use ("alice") to the id this server
|
|
84
|
+
* actually uses for that person.
|
|
85
|
+
*
|
|
86
|
+
* Optional, defaulting to identity. It exists because owner ids are
|
|
87
|
+
* **server-namespace-local** — protocol §1.1 — and a target backed by real
|
|
88
|
+
* auth will use uuids, not names. A kit that assumed names round-tripped
|
|
89
|
+
* would be assuming away the very thing the `named` allowlist is about.
|
|
90
|
+
*/
|
|
91
|
+
ownerId?(name: string): Promise<string>;
|
|
92
|
+
/** Return to a clean slate between checks. */
|
|
93
|
+
reset(): Promise<void>;
|
|
94
|
+
/** Release any resources. */
|
|
95
|
+
close?(): Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** One certification check. */
|
|
99
|
+
interface Check {
|
|
100
|
+
/** Stable id, cited in the report. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
/** What it proves, in one sentence. */
|
|
103
|
+
readonly title: string;
|
|
104
|
+
/** Which protocol MUSTs it asserts. */
|
|
105
|
+
readonly musts: readonly MustId[];
|
|
106
|
+
/** Throws to fail. */
|
|
107
|
+
run(target: ConformanceTarget): Promise<void>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The compatibility contract, as executable checks.
|
|
111
|
+
*
|
|
112
|
+
* A server is byollm-compatible when every one of these passes against it.
|
|
113
|
+
* Each drives a **real daemon** — the shipped {@link Runner}, the shipped
|
|
114
|
+
* pairing exchange, the shipped allowlist — so what is certified is the
|
|
115
|
+
* behaviour of the pair, not one side's opinion of the other.
|
|
116
|
+
*/
|
|
117
|
+
declare const CHECKS: readonly Check[];
|
|
118
|
+
|
|
119
|
+
interface CheckResult {
|
|
120
|
+
readonly check: Check;
|
|
121
|
+
readonly passed: boolean;
|
|
122
|
+
readonly durationMs: number;
|
|
123
|
+
readonly error?: string;
|
|
124
|
+
}
|
|
125
|
+
interface CertificationReport {
|
|
126
|
+
readonly target: string;
|
|
127
|
+
readonly passed: boolean;
|
|
128
|
+
readonly results: readonly CheckResult[];
|
|
129
|
+
/**
|
|
130
|
+
* MUSTs no check asserts.
|
|
131
|
+
*
|
|
132
|
+
* byollm_001 requires every MUST carry a conformance test id. Reporting the
|
|
133
|
+
* gap rather than hiding it is what keeps that requirement honest as the
|
|
134
|
+
* protocol grows — a new MUST shows up here until someone writes its check.
|
|
135
|
+
*/
|
|
136
|
+
readonly uncoveredMusts: readonly MustId[];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Run the compatibility contract against a server.
|
|
140
|
+
*
|
|
141
|
+
* "A server is byollm-compatible when the kit passes" — this is the function
|
|
142
|
+
* that decides it.
|
|
143
|
+
*/
|
|
144
|
+
declare function certify(target: ConformanceTarget, options?: {
|
|
145
|
+
only?: readonly string[];
|
|
146
|
+
onProgress?: (result: CheckResult) => void;
|
|
147
|
+
}): Promise<CertificationReport>;
|
|
148
|
+
/** MUSTs with no check asserting them. */
|
|
149
|
+
declare function uncoveredMusts(checks?: readonly Check[]): MustId[];
|
|
150
|
+
/** A human-readable report. */
|
|
151
|
+
declare function formatReport(report: CertificationReport): string;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* A model that answers instantly and predictably.
|
|
155
|
+
*
|
|
156
|
+
* The conformance kit certifies the *protocol*, not anyone's model. Using a
|
|
157
|
+
* real backend would make the suite slow, non-deterministic, and dependent on
|
|
158
|
+
* whatever happens to be installed — so the daemon under test is real in
|
|
159
|
+
* every respect except the thing at the very end of the call.
|
|
160
|
+
*/
|
|
161
|
+
declare class EchoBackend implements Backend {
|
|
162
|
+
readonly id: "openai-http";
|
|
163
|
+
readonly class: "http";
|
|
164
|
+
/** Prompts this backend was asked to run, in order. */
|
|
165
|
+
readonly seen: string[];
|
|
166
|
+
/** Set to make the next call hang, for lease and cancel checks. */
|
|
167
|
+
hangMs: number;
|
|
168
|
+
health(): Promise<{
|
|
169
|
+
healthy: boolean;
|
|
170
|
+
models: string[];
|
|
171
|
+
}>;
|
|
172
|
+
execute(request: BackendRequest): Promise<BackendResult>;
|
|
173
|
+
}
|
|
174
|
+
interface HarnessDaemon {
|
|
175
|
+
readonly runner: Runner;
|
|
176
|
+
readonly backend: EchoBackend;
|
|
177
|
+
readonly allowlist: Allowlist;
|
|
178
|
+
readonly runnerId: string;
|
|
179
|
+
readonly owner: string;
|
|
180
|
+
readonly home: string;
|
|
181
|
+
readonly ingress: IngressLog;
|
|
182
|
+
/** Stop cleanly: cancel in-flight work and clean up. */
|
|
183
|
+
dispose(): Promise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* Simulate `kill -9`: clean up the daemon's files but do **not** cancel its
|
|
186
|
+
* in-flight work, so nothing is released and no result is ever reported.
|
|
187
|
+
*
|
|
188
|
+
* Cancelling would make the backend return `canceled`, the runner would
|
|
189
|
+
* dutifully report it, and the job would reach a terminal state — which is
|
|
190
|
+
* the opposite of the lease-reclaim scenario being tested.
|
|
191
|
+
*/
|
|
192
|
+
abandon(): Promise<void>;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Pair a real daemon against the target and return it, ready to tick.
|
|
196
|
+
*
|
|
197
|
+
* "Real" matters: this is the shipped {@link Runner}, doing the shipped
|
|
198
|
+
* pairing exchange, with the shipped allowlist and budget checks. Only the
|
|
199
|
+
* model at the far end is substituted.
|
|
200
|
+
*/
|
|
201
|
+
declare function pairDaemon(target: ConformanceTarget, options: {
|
|
202
|
+
owner: string;
|
|
203
|
+
label?: string;
|
|
204
|
+
offer?: "self" | "named" | "public";
|
|
205
|
+
/** Use the subscription-class backend, to exercise the self-lock. */
|
|
206
|
+
subscription?: boolean;
|
|
207
|
+
}): Promise<HarnessDaemon>;
|
|
208
|
+
/**
|
|
209
|
+
* The id this target uses for a person, given the friendly name the checks
|
|
210
|
+
* use. Identity when the target does not translate.
|
|
211
|
+
*/
|
|
212
|
+
declare function ownerIdFor(target: ConformanceTarget, name: string): Promise<string>;
|
|
213
|
+
/** Poll a predicate until it holds or the deadline passes. */
|
|
214
|
+
declare function waitFor(predicate: () => boolean | Promise<boolean>, options?: {
|
|
215
|
+
timeoutMs?: number;
|
|
216
|
+
intervalMs?: number;
|
|
217
|
+
what?: string;
|
|
218
|
+
}): Promise<void>;
|
|
219
|
+
declare function sleep(ms: number): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Move the target's clock forward, faking it if the target can and genuinely
|
|
222
|
+
* waiting if it cannot.
|
|
223
|
+
*/
|
|
224
|
+
declare function advance(target: ConformanceTarget, ms: number): Promise<void>;
|
|
225
|
+
|
|
226
|
+
export { CHECKS, type CertificationReport, type Check, type CheckResult, type ConformanceTarget, EchoBackend, type HarnessDaemon, advance, certify, formatReport, ownerIdFor, pairDaemon, sleep, uncoveredMusts, waitFor };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CHECKS,
|
|
3
|
+
EchoBackend,
|
|
4
|
+
advance,
|
|
5
|
+
certify,
|
|
6
|
+
formatReport,
|
|
7
|
+
ownerIdFor,
|
|
8
|
+
pairDaemon,
|
|
9
|
+
sleep,
|
|
10
|
+
uncoveredMusts,
|
|
11
|
+
waitFor
|
|
12
|
+
} from "./chunk-PDQJJ3Q2.js";
|
|
13
|
+
export {
|
|
14
|
+
CHECKS,
|
|
15
|
+
EchoBackend,
|
|
16
|
+
advance,
|
|
17
|
+
certify,
|
|
18
|
+
formatReport,
|
|
19
|
+
ownerIdFor,
|
|
20
|
+
pairDaemon,
|
|
21
|
+
sleep,
|
|
22
|
+
uncoveredMusts,
|
|
23
|
+
waitFor
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@byollm/conformance",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "The BYOLLM compatibility contract — drive a real daemon against any server and assert every protocol MUST.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"byollm-certify": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"targets",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22.12"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@byollm/protocol": "0.1.0-alpha.0",
|
|
28
|
+
"byollm": "0.1.0-alpha.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@supabase/supabase-js": "^2.112.2",
|
|
32
|
+
"@byollm/server": "0.1.0-alpha.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"clean": "rm -rf dist .tsbuild",
|
|
40
|
+
"certify:reference": "vitest run --project conformance --root ../..",
|
|
41
|
+
"certify:supabase": "node --experimental-strip-types targets/supabase.ts"
|
|
42
|
+
}
|
|
43
|
+
}
|