diff --git a/web/app/src/ui/docks.ts b/web/app/src/ui/docks.ts index 3b7565205..8a15c190f 100644 --- a/web/app/src/ui/docks.ts +++ b/web/app/src/ui/docks.ts @@ -259,13 +259,20 @@ const OPERATOR_DECLARED = { }; /** - * The one capability field backed by a mechanism, and the only one current as - * of the beat that carries it (protocol v1 §4.5.3, §4.5.4). + * The only capability field current as of the beat that carries it, and a + * claim filter rather than a dispatch guarantee (protocol v1 §4.5.3, §4.5.4). + * + * The wording here is constrained for the same reason `LAST_OBSERVED`'s is. + * Nothing at the seat reads `harness_family`: dispatch selects a harness by the + * offer's `agent` preset alone. Any verb implying it binds execution — enforced, + * pinned, guaranteed, exact-or-nothing at dispatch — states a fact no code + * supports, and a multi-harness seat matching the filter can run a different + * harness within the family. */ -const ENFORCED_AT_DISPATCH = { - mark: "enforced at dispatch", +const FILTERS_CLAIMS_NOT_DISPATCH = { + mark: "filters claims, not dispatch", markClass: "provenance", - title: "Read from the live roster each time a beat is drafted, so it is current as of this beat. Dispatch binds to the named family exactly or not at all — the only one of the three filterable fields backed by a mechanism.", + title: "Read from the live roster each time a beat is drafted, so it is current as of this beat. It decides which seats may claim a job, never which harness runs one — dispatch selects by the offer's `agent` preset alone, so a seat configured with several presets in this family can match and run a different one. A buyer that needs the execution guarantee must name the preset.", }; /** @@ -299,17 +306,21 @@ const AS_OF_SEAT_START = { * * THE ROWS ARE NOT EQUAL, and the difference is provenance, not confidence. * Protocol v1 §4.5.3 is explicit that a reader MUST NOT read the three - * filterable fields as three grades of proof: `harness_family` is an - * ENFORCEMENT, `harness_model` is an ECHO a buyer can notice a divergence - * against, and `capabilities` is a SILENCE — no event carries a capability back - * at all. §4.5.4 then gives the three different freshness guarantees, and only + * filterable fields as three grades of proof, and that NONE of the three is an + * enforcement: `harness_model` is ECHOED, so a divergence is at least visible + * in a buyer's own records, while `harness_family` and `capabilities` are both + * SILENCE — nothing at the seat reads the family, and no event carries a + * capability back at all. One inconsistency signal and two silences. §4.5.4 + * then gives the three different freshness guarantees, and only * `harness_family` is current as of the beat carrying it. * - * So every row wears its own mark and the marks differ where the proof differs. - * Flush and unmarked, the weakest row reads as solidly as the enforced one, and - * a buyer commits sats on the weakest of the three. The last two rows are free - * text an operator typed; they stay marked apart from all three, because - * nothing pays out on them. + * So every row wears its own mark, and the marks differ on what a reader can + * DO with the value, not on how true it is. Two rows being equally unenforced + * does not make them interchangeable: they differ in freshness and in what + * they gate, and that is what the marks carry. Flush and unmarked, the stalest + * row would read as solidly as the freshest, and a buyer commits sats on the + * stalest of the three. The last two rows are free text an operator typed; + * they stay marked apart from all three, because nothing pays out on them. * * Every row is an ANNOUNCEMENT either way. This reader sees the claim, never * the probe. A mark says what a claim is worth, not that anything verified it @@ -322,7 +333,7 @@ const AS_OF_SEAT_START = { export function capabilityRows(s: { harnessFamilies?: string[]; harnessModels?: HarnessModel[]; capabilities?: string[]; harnessVariant?: string | null; hardware?: string | null } | null): ProfileRow[] { if (!s) return []; return [ - ["Harness family", s.harnessFamilies?.length ? s.harnessFamilies.join(" · ") : null, ENFORCED_AT_DISPATCH], + ["Harness family", s.harnessFamilies?.length ? s.harnessFamilies.join(" · ") : null, FILTERS_CLAIMS_NOT_DISPATCH], ["Harness model", s.harnessModels?.length ? s.harnessModels.map((m) => `${m.family} ${m.model}`).join(" · ") : null, LAST_OBSERVED], ["Capabilities", s.capabilities?.length ? s.capabilities.join(" · ") : null, AS_OF_SEAT_START], diff --git a/web/app/test/capability.test.ts b/web/app/test/capability.test.ts index be57b8908..cbcfcb64c 100644 --- a/web/app/test/capability.test.ts +++ b/web/app/test/capability.test.ts @@ -130,12 +130,15 @@ test("every capability row wears the mark its provenance earns", () => { assert.match(profileRowHtml(row!), /class="unverified">operator-declared { + // This is the row a buyer reads before paying for a family, and the title is + // where the contract is stated — the mark beside it is a chip with no room + // for one. §4.5.3: the family is neither enforced nor echoed. It decides who + // may be CONSIDERED and never what executes, because dispatch selects on the + // offer's `agent` preset alone. + // + // ⚠ The forbidden list below is an INCLUSION filter, exactly as in the model + // row's test: it pins the spellings this claim has already worn here and + // CANNOT prove a new one is safe. The load-bearing assertions are the three + // positive ones. + const row = rowOf(capabilityRows({ harnessFamilies: ["codex"] }), "Harness family"); + const title = row?.[2]?.title ?? ""; + assert.notEqual(title, "", "positive control: an empty title would pass every doesNotMatch below"); + + for (const shape of [/enforced/i, /enforcement/i, /backed by a mechanism/i, /exactly or not at all/i, /binds dispatch/i]) { + assert.doesNotMatch(title, shape, `claims the family binds execution, which no code supports: ${shape}`); + } + + // The three a buyer needs, asserted separately so that satisfying one cannot + // stand in for another: what the field DOES, what it does NOT do, and what to + // name instead when the execution guarantee is the thing being bought. + assert.match(title, /decides which seats may claim a job/, "must say the family filters claimant eligibility"); + assert.match(title, /never which harness runs one/, "must say the family does not select what executes"); + assert.match(title, /must name the preset/, "must say the `agent` preset is what buys the execution guarantee"); + + // Assert on the RENDERED attribute too. The object field and the string a + // buyer actually hovers are different artifacts, and only the second one ships. + assert.match(profileRowHtml(row!), /title="[^"]*never which harness runs one/); +}); + test("the model row never states an execution fact", () => { // The emitter names this defect family: any wording that upgrades this // SELF-REPORT into an EXECUTION FACT is the same error, and it has been