@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Of Tomorrow, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ > [!WARNING]
2
+ > **Alpha 0.1.0 — under active development. Don't use this yet.**
3
+ >
4
+ > > Install it deliberately: `npm install @byollm/conformance@alpha`.
5
+ > The protocol is v0 and **will** change without a deprecation path, this has
6
+ > never run outside its own test suite, and nothing here has production miles.
7
+ > Read it, take the ideas, tell us what's wrong — but don't put it in front of
8
+ > your users.
9
+ >
10
+ > npm assigns `latest` on a first publish and won't let it be removed, so the
11
+ > alpha is also `latest`; the version is marked deprecated so every install
12
+ > says so out loud.
13
+
14
+ # `@byollm/conformance`
15
+
16
+ The compatibility contract. **A server is byollm-compatible when this kit
17
+ passes against it** — that sentence is the whole versioning story. There is no
18
+ framework version to chase; the tests are what compatibility means.
19
+
20
+ ```bash
21
+ npx byollm-certify ./my-target.js
22
+ ```
23
+
24
+ ```
25
+ byollm conformance — my server
26
+
27
+ ✓ C001_PAIRING_BINDS_ONE_USER a runner token is bound to exactly the approving user (279ms)
28
+ ✓ C002_JOB_ROUND_TRIP an enqueued job runs on the owner's daemon and the result comes back (83ms)
29
+
30
+ 16 checks passed — my server is byollm-compatible.
31
+ ```
32
+
33
+ ## What it actually does
34
+
35
+ Each check drives a **real daemon** — the shipped runner, the shipped
36
+ device-code pairing, the shipped local allowlist, the shipped budget checks —
37
+ against your server. What gets certified is the behaviour of the pair, not
38
+ either side's opinion of the other.
39
+
40
+ Only the model at the very end is substituted, because the kit certifies the
41
+ protocol and not anyone's choice of model.
42
+
43
+ ## Writing a target
44
+
45
+ Implement `ConformanceTarget`: a `fetch` for the protocol surface, plus the
46
+ app-side control the kit needs to set up scenarios.
47
+
48
+ ```ts
49
+ import type { ConformanceTarget } from "@byollm/conformance";
50
+
51
+ export default function target(): ConformanceTarget {
52
+ return {
53
+ name: "my server",
54
+ origin: "https://my-app.test",
55
+ leaseMs: 2_000,
56
+ ttlMs: 1_500,
57
+
58
+ fetch: (request) => myHandler(request),
59
+ enqueue: (input) => myApp.enqueue(input),
60
+ approvePairing: (userCode, owner) => myApp.approve(userCode, owner),
61
+ revokeRunner: (id) => myApp.revoke(id),
62
+ cancelJob: (id) => myApp.cancel(id),
63
+ job: (id) => myApp.job(id),
64
+ runnerAvailability: (q) => myApp.availability(q),
65
+ sweep: () => myApp.sweep(),
66
+ reset: () => myApp.truncate(),
67
+
68
+ // Optional: if your owner ids are not the names the checks use.
69
+ ownerId: (name) => myApp.userIdFor(name),
70
+ // Optional: if you can fake time, the lease and TTL checks run instantly.
71
+ advanceTime: (ms) => myClock.advance(ms),
72
+ };
73
+ }
74
+ ```
75
+
76
+ Two optional hooks worth knowing about:
77
+
78
+ - **`ownerId`** exists because owner ids are server-namespace-local. A target
79
+ backed by real auth uses uuids, not names, and a kit that assumed names
80
+ round-tripped would be assuming away the very thing the `named` allowlist is
81
+ about.
82
+ - **`advanceTime`** lets an in-memory server run the lease and TTL checks in
83
+ milliseconds. A real Postgres cannot fake its clock, so the kit waits for
84
+ real instead — which is why such a target should declare a short `leaseMs`
85
+ and `ttlMs`.
86
+
87
+ ## The checks
88
+
89
+ | Check | Asserts |
90
+ | -------------------------------------- | ------------------------------------------------------------ |
91
+ | `C001_PAIRING_BINDS_ONE_USER` | a token is bound to exactly the approving user |
92
+ | `C002_JOB_ROUND_TRIP` | a job runs on its owner's daemon and the result returns |
93
+ | `C003_UNKNOWN_KIND_REFUSED` | a daemon is never handed a kind it did not advertise |
94
+ | `C004_LEASE_RECLAIM` | a job whose runner vanished is offered again, losing nothing |
95
+ | `C005_AUDIENCE_MATRIX` | all nine audience × offer-scope combinations |
96
+ | `C006_NAMED_LOCAL_ALLOWLIST` | `named` runs only once the daemon's own list admits it |
97
+ | `C007_SUBSCRIPTION_SELF_LOCK` | a subscription backend refuses others' work at any scope |
98
+ | `C008_REVOCATION` | a revoked daemon stops mid-queue |
99
+ | `C009_CANCEL_MID_FLIGHT` | cancel aborts a running job's backend call |
100
+ | `C010_RESULT_IDEMPOTENT` | the first terminal outcome wins |
101
+ | `C011_DEPENDENCY_ORDER` | a dependent job waits, across two daemons |
102
+ | `C012_TTL_AND_NO_RUNNER` | unclaimed jobs expire; no-runner is surfaced |
103
+ | `C013_TTL_CLOCK_STARTS_WHEN_CLAIMABLE` | a blocked job does not expire while waiting |
104
+ | `C014_RESULT_PROVENANCE` | community results arrive marked untrusted |
105
+ | `C015_INGRESS_BEFORE_EXECUTION` | every executed prompt is logged |
106
+ | `C016_UNAUTHENTICATED_REFUSED` | endpoints refuse an unknown token |
107
+
108
+ ## It reports its own gaps
109
+
110
+ `formatReport` lists every protocol MUST that no check asserts. Some are
111
+ daemon-internal and proven by the adversarial suite instead; the point is that
112
+ the gap is **visible in the output** rather than implied away, and a newly
113
+ added MUST shows up there until someone writes its check.
114
+
115
+ MIT