From 45aebe36efbfcd9c45ad9b5b16989643fb917d5d Mon Sep 17 00:00:00 2001 From: Agent IX Date: Fri, 7 Aug 2026 18:22:41 -0700 Subject: [PATCH] feat: declare the FR-052 property_idioms registry (FR-001 CR-001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit quire-rs FR-052 adds a property-shape classifier over acceptance criteria and lets a Filament module declare a `property_idioms:` registry merged first-wins over the engine built-ins. This module declares the ISO one. Seven phrases, and the smallness is the point. The registry is applied AFTER the closed structural signals and can only sharpen a label to a higher-precedence shape; `extractable` is derived from the structural shape alone (FR-052-CON-4), so nothing here can make a criterion extractable or remove one from extraction. No finding is emitted on that path, so this declaration cannot change any validation verdict. quire-rs CR-014 retired `no-observable-outcome` because an open verb set whose membership was *required* to earn a label reached ~13% sampled precision. A big speculative phrase list here would recreate that shape, so every candidate had to clear two rules: attested in the authored corpus (counted by distinct file and repo across ~/dev/*/spec, not by raw grep hit — raw counts are inflated several-fold by duplicated repos), and sufficient standing alone, because the matcher sees only the phrase. Declared: round-trip lossless 33 files / 10 repos parse-then-serialize 3 / 1 idempotence idempotent 253 / 81 idempotency 149 / 54 idempotently 49 / 31 idempotence 20 / 11 ordering total order 8 / 6 The idempotence lemma is the strongest case in the corpus: the built-in signal needs a repetition adverb in the same clause as an equality verb, and "re- activation is idempotent" carries neither. `lossless` is the adjective the built-in back-reference set misses — it has `losslessly` only — which is why "Pack then unpack of MSE indices is lossless for all bit widths 1-7" composes but falls through. Declined despite being attested, all on the sufficient-alone rule: `encode/decode` (30 files / 8 repos) is nearly always an API or seam name — "the encode/decode seam", "the complete encode/decode/score API" — not a property claim; likewise `encoding/decoding`, `serialization/deserialization` ("handles JSON serialization/deserialization"), `read`/`write`, `save/load`, and `monotonic` (usually "monotonic clock"). Bare `deterministic` is excluded by FR-052 itself. `marshal`/`unmarshal` and `compress`/`inflate` are unattested and are therefore not declared at all. `round-trip`, `byte-identical` and `losslessly` are already engine built-ins and are not re-declared. `tests/module-manifest.schema.json` gains the `property_idioms` property and a `PropertyIdiomEntry` definition with the closed kebab-case shape enum: the fixture is `additionalProperties: false`, so without it this module's own suite would reject the manifest it ships — the same step `grammar_severity` and `lexicon` each took. quire-rs `Manifest` carries no `deny_unknown_fields`, so an engine predating FR-052 ignores the key rather than failing to load. Verified: `make test` 82 passed / 2 skipped, `make lint` clean (ruff + black). Refs: agent-ix/quire-rs#20, umbrella agent-ix/quire-rs#17 Co-Authored-By: Claude Opus 5 (1M context) --- .../FR-001-module-manifest-activates.md | 20 ++++++ spec/log.md | 4 ++ spec_artifacts_iso/manifest.yaml | 68 +++++++++++++++++++ tests/module-manifest.schema.json | 41 +++++++++++ 4 files changed, 133 insertions(+) diff --git a/spec/functional/FR-001-module-manifest-activates.md b/spec/functional/FR-001-module-manifest-activates.md index 853d873..9e6adbf 100644 --- a/spec/functional/FR-001-module-manifest-activates.md +++ b/spec/functional/FR-001-module-manifest-activates.md @@ -10,6 +10,26 @@ relationships: ## Description +> **CR-001 (property-idiom registry — 2026-08-07):** the manifest additionally +> declares a **`property_idioms:`** registry (quire-rs +> [FR-052](ix://agent-ix/quire-rs/spec/functional/FR-052), umbrella +> agent-ix/quire-rs#20): phrase → `{definition, shape}`, merged first-wins over +> the engine's built-in idioms. It is a **booster, never a prerequisite** — +> quire-rs FR-052-CON-4 derives `extractable` from the closed structural signals +> alone, so a declared phrase can only sharpen a criterion's *label* to a +> higher-precedence shape and can never make a criterion extractable, nor remove +> one from extraction. Nothing on that path emits a finding, so this declaration +> cannot change any validation verdict. The registry is deliberately small and +> every phrase is attested in the authored corpus; quire-rs CR-014 retired +> `no-observable-outcome` because an open set whose membership was *required* to +> earn a label reached ~13% sampled precision, and a speculative phrase list here +> would recreate that shape. This is the first numbered CR in this repo; the two +> earlier notes (FR-002, StR-001, "render removal") predate the sequence. +> AC-1 already covers the addition: the bundled FR-035 schema fixture is +> `additionalProperties: false`, so the new key is gated by that criterion and +> the fixture gains a `property_idioms` property with a `PropertyIdiomEntry` +> definition, exactly as `grammar_severity` and `lexicon` did before it. + The system **SHALL** publish a Filament Module manifest (`spec_artifacts_iso/manifest.yaml`) that conforms to filament-core-service [FR-035](ix://agent-ix/filament-core-service/FR-035) v1.0.0 and activates idempotently against `POST /api/v1/modules/activate`. diff --git a/spec/log.md b/spec/log.md index f6f9b32..20eb437 100644 --- a/spec/log.md +++ b/spec/log.md @@ -8,3 +8,7 @@ description: "Chronological log of structural changes to this bundle." ## History * **2026-06-15** — Adopted OKF-compatible bundle structure with directory indexes. +* **2026-08-07** — FR-001 CR-001: the manifest declares a `property_idioms:` + registry (quire-rs FR-052) — 7 corpus-attested phrases boosting `round-trip`, + `idempotence` and `ordering` labels. Label-only by FR-052-CON-4; emits no + finding and changes no validation verdict. diff --git a/spec_artifacts_iso/manifest.yaml b/spec_artifacts_iso/manifest.yaml index 3a691cc..0e71b27 100644 --- a/spec_artifacts_iso/manifest.yaml +++ b/spec_artifacts_iso/manifest.yaml @@ -33,6 +33,74 @@ grammars: grammar_severity: ac:vacuous-outcome: error ac:non-singular: error + +# FR-052 property-idiom registry (quire-rs FR-052, umbrella agent-ix/quire-rs#20). +# phrase -> {definition, shape}. Merged first-wins OVER the engine built-in idioms +# and applied AFTER the closed structural signals, so a declaration can only +# sharpen a label to a higher-precedence shape. `extractable` is derived from the +# structural shape alone (FR-052-CON-4), so nothing declared here can make a +# criterion extractable, or remove one from extraction — the registry is a +# booster, never a prerequisite. +# +# Deliberately small. quire-rs CR-014 retired `no-observable-outcome` because an +# open verb set whose membership was *required* to earn a label reached ~13% +# sampled precision; an aspirational phrase list here would recreate that shape. +# Two rules were applied to every candidate: +# +# 1. attested — the phrase occurs in the authored corpus (`/home/peter/dev/*/spec`, +# counted by distinct file and repo, not by raw grep hit); +# 2. sufficient alone — the phrase, on its own, is evidence of the shape. The +# matcher sees only the phrase, so a phrase that also names a subsystem is a +# mislabel generator. `encode/decode` (30 files / 8 repos) was DECLINED on +# this rule: nearly every occurrence is an API or seam name ("the encode/decode +# seam", "the complete encode/decode/score API"), not a property claim. So were +# `encoding/decoding`, `serialization/deserialization`, `read`/`write`, +# `save/load`, `monotonic` (usually "monotonic clock") and bare `deterministic` +# (excluded by FR-052 itself). `marshal`/`unmarshal` and `compress`/`inflate` +# are unattested in the corpus and are therefore not declared. +# +# What is NOT declared because the engine built-ins already close it: `round-trip` +# / `round-trips` / `roundtrip` (both a composition signal and an identity +# back-reference), `byte-identical`, `losslessly`. +property_idioms: + # RoundTrip. `losslessly` is a built-in back-reference; the adjective is not, so + # "Pack then unpack of MSE indices is lossless for all bit widths 1-7" composes + # but carries no back-reference and falls through to Universal without this. + # 33 files / 10 repos. + lossless: + definition: "An operation asserted to preserve its input exactly, so composing it with its inverse recovers the original." + shape: round-trip + # 3 files / 1 repo (quire-rs FR-051). Names the composition outright; `then` + # supplies the built-in composition signal but no identity back-reference follows. + parse-then-serialize: + definition: "The composition of a parse with the serialization of its result, asserted against the original text." + shape: round-trip + + # Idempotence. Four inflections of one lemma that names a shape in the closed + # enum outright. The built-in signal needs a repetition adverb (`twice`, + # `again`, `re-run`, ...) in the same clause as an equality verb; a criterion + # that simply says "re-activation is idempotent" carries neither. + # `idempotent` 253 files / 81 repos, `idempotency` 149 / 54, + # `idempotently` 49 / 31, `idempotence` 20 / 11. + idempotent: + definition: "Applying the operation a second time yields the result of the first." + shape: idempotence + idempotently: + definition: "Adverbial form of `idempotent`: the operation is performed such that a repeat application changes nothing." + shape: idempotence + idempotence: + definition: "The property that a repeat application of an operation yields the first result." + shape: idempotence + idempotency: + definition: "Nominal form of `idempotence`, the spelling used in service and API criteria." + shape: idempotence + + # Ordering. The built-in ordering lexicon is a closed set that does not carry + # the term of art. 8 files / 6 repos, e.g. "Ranking is a total order - results + # with absent `stars`/`updatedAt` sort last". + total order: + definition: "Every pair of elements is comparable, so the ordering is complete and not merely partial." + shape: ordering artifact_types: - name: FR grammar_ref: iso-spec-core diff --git a/tests/module-manifest.schema.json b/tests/module-manifest.schema.json index d48dbe6..6ca1058 100644 --- a/tests/module-manifest.schema.json +++ b/tests/module-manifest.schema.json @@ -138,6 +138,13 @@ "pattern": "^[a-z0-9-]+:[a-z0-9-]+$" }, "description": "FR-048: per-check grammar severity, `:` -> off|warning|error. Merged first-wins across modules and layered under a surface's --severity override. Promoting an `ac` check to `error` is gated by quire-rs FR-047-CON-1 (corpus baseline sweep + explicit user sign-off); the engine default remains `warning`." + }, + "property_idioms": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/PropertyIdiomEntry" + }, + "description": "FR-052: mergeable property-idiom registry — phrase -> {definition, shape, optional category}. Merged first-wins across modules and layered over the engine's built-in idioms. The property classifier applies it after the closed structural signals, as a label booster only: no finding is emitted on that path and `extractable` never depends on a declaration (quire-rs FR-052-CON-4)." } }, "$defs": { @@ -584,6 +591,40 @@ "minLength": 1 } } + }, + "PropertyIdiomEntry": { + "type": "object", + "description": "FR-052: one property-idiom registry entry. `shape` is the closed FR-052 property-shape enum in its kebab-case serialization.", + "required": [ + "definition", + "shape" + ], + "additionalProperties": false, + "properties": { + "definition": { + "type": "string", + "minLength": 1 + }, + "shape": { + "type": "string", + "enum": [ + "round-trip", + "idempotence", + "ordering", + "invariant", + "error-case", + "lifecycle", + "concurrency", + "universal", + "example", + "unclassified" + ] + }, + "category": { + "type": "string", + "minLength": 1 + } + } } } }