Status: implemented
Implemented — this change has shipped.
RFC 0081: One format, one protocol: remove backward compatibility (pre-release cleanup)
Implemented; released in 4.0.0 (Format 3.0, Protocol 4.0.0). Written from the owner's direction of 2026-10-11 (Product principle 5, D1–D14); the owner decided its three open gates and the other open questions the same day (Owner decisions at acceptance). Drafted with AI assistance; reviewed by maintainers. See Resolution.
Summary
The project is live but pre-release: the owner is its only user. It still carries the compatibility machinery of a mature standard:
- four readable format versions (1.0, 1.1, 2.0, 2.1);
- six honored protocol contracts (1.14.0 through 3.0.0);
- two
_metashapes, with a reshape layer in both directions; - two block body shapes;
- two migration tools;
- a deprecated class alias and two deprecated module packages;
- four deprecated conformance tier names;
- legacy scalar fields beside their structured replacements;
- hotel facts stated in two sections;
- version-conditional severities.
This RFC removes all of it:
- One format. Format 3.0 is the 2.1 shape (nested
_meta, the twelve builtins) minus every alternate spelling. It is described by one spec file, and it is the only format any reader accepts. - One protocol. Protocol 4.0.0 is the only protocol contract.
- No transition plan. There are no grandfathered documents, deprecation periods, aliases, shims, migration tools or old-version readers. The repo's own corpus is re-authored once, with financial values unchanged, and then the migrators are deleted.
Motivation
Owner direction. Product principle 5 (2026-10-11): "we dont need back compatability yet, there are no users other than me and this is essentially pre-release despite being live. we can and should clean things up better and do not need legacy support for old modules basically."
Compatibility is most of the surface. A reader today has to implement all of the following, and none of it changes what a document means:
- two
_metashapes and two block body shapes; - two digest canonicalizations;
- per-file severities for
SRC-01/SRC-02; META-V2-IN-V1/META-V1-IN-V2;- the
org.uwmd.data_centeralias; - module-gated hospitality rules and a version-gated
CLS-04.
All of it is code an independent implementer must write to claim conformance (RFC 0078's boundary test: a lender verifying with only the standard).
- two
The format has two specs.
UW_FORMAT_SPEC_v1.md(4,113 lines) is the base.UW_FORMAT_SPEC_v2.md(387 lines) is a delta that amends it "for 2.0 files only". A reader has to merge the two in their head to learn what a 2.1 document is.The compatibility windows were designed for adopters who do not exist. RFC 0009's own timeline planned this step: "v3.0: flat shape removed from the spec … v3 readers MAY drop the shim". Every other window (RFC 0078's "during 3.x", RFC 0080 §5) protects documents that only the owner has, and the owner's consumers update.
One removal is overdue. FV
legacy_codewas promised to travel "for one release; v1.2 dropslegacy_codeentirely" (validator.ts:68-70). Core 3.0.0 still emits it.
Owner direction (binding)
| # | Direction (owner, 2026-10-11) | Inventory facts (verified on main at 5b94c9f) |
|---|---|---|
| P5 | Clean breaks beat compatibility layers. No grandfathering, deprecation periods, aliases, shims, migration tools or old-version readers. A breaking normative change gets an RFC and a version bump but no transition plan. | Product principle 5. |
| D1 | Ship as Format 3.0, Protocol 4.0.0, @uwmd/core 4.0.0. Format 3.0 is the 2.1 shape minus every alternate spelling, and it is the only supported format. Readers refuse every other uw_version with one clear error. SUPPORTED_FORMAT_VERSIONS = ['3.0'] and SUPPORTED_PROTOCOL_VERSIONS = ['4.0.0']. The major supersedes Protocol 3.0's "during 3.x" promises. | protocol.ts:54 reads ['1.0','1.1','2.0','2.1'], and no corpus file declares 1.0. protocol.ts:65 honors 1.14.0, 2.0.0, 2.1.0, 2.2.0, 2.25.0, 3.0.0. No reader refuses an unknown uw_version today; Protocol §XII.3 only says to refuse editing a newer major. |
| D2 | One format spec. Merge UW_FORMAT_SPEC_v1.md (base) and UW_FORMAT_SPEC_v2.md (delta) into spec/UW_FORMAT_SPEC.md, describing only Format 3.0, and delete both old files. Rename the protocol to spec/UW_PROTOCOL.md. Remove the 34 "Moved to … starter products guide" stubs; the starter guide is their home. | All 34 stubs are in UW_PROTOCOL_v1.md (§III.1–III.6, §IV, §V.1/V.5–V.8, §VIII.2b/2c, §IX, §XIV). |
| D3 | Delete on-disk v1 flat _meta: parser shape detection, META-V2-IN-V1/META-V1-IN-V2, the version-conditional SRC-01/SRC-02 severity, the v1 block-hash branch, the ?? '1.1' defaults, the v1 uwmd-block.schema.json shape and the section_id alias. The target is an in-memory UWMeta that matches the on-disk nested shape, so no reshape layer survives (Phase 4 decides the mechanics). | meta-shape.ts (both reshapes); parser.ts:361-388; validator.ts:3146-3230; integrity.ts:83-95, 267, 397; envelope.ts:95, 317; renderer.ts:373, 435, 731 and report.ts:290; shape selection in editor.ts/runner.ts. About 67 flat-field reads of block.meta.* in 17 non-test source files. |
| D4 | Delete the migration tooling after one last use to re-author the corpus: migrate-to-v2.ts, migrate-source-tags.ts, the CLI migrate commands, their exports, the conformance migrate suite and RFC 0031's legacy _meta.source tags. uwmd init writes only Format 3.0 (drop --format). | cli.ts:478-580, 1461-1478, 2071-2072; init.ts:13-16, 108-114; index.ts:45 and browser.ts:55 export migrateSourceTags/mapLegacySource. migrate-to-v2.ts writes 2.0, not 3.0. It refuses signed blocks unless given a key (--resign) and refuses legacy-tag blocks until --source-tags has run. |
| D5 | Re-author every fixture and example to Format 3.0. Signed fixtures are re-signed, receipt fixtures re-issued and content hashes recomputed. Financial values never change; only envelope and metadata shape do. That is a hard acceptance criterion: the lender fixture and every calc baseline value must stay identical. | Conformance .md files: 435 at 1.1, 227 at 2.0, 54 at 2.1. Examples: 20 at 1.1, 2 at 2.1 (Mesa Gateway, Desert Palms). Also about 26 package, tool and docs fixtures and about 85 inline test strings. Seven corpus files carry signatures; the test key is conformance/signing/keys/signer-private.jwk.json. The lender fixture reads 187 verified / 0 failed / 0 unverifiable. |
| D6 | Remove the RFC 0080 transition surface: the org.uwmd.data_center alias, CLS-01, CLS-02, the frontmatter id: org.uwmd.* grandfathering, declared_asset_class, the batch and lake alias branches (keep toBuiltinAssetClass as the plain builtin lookup), and the LEGACY_MODULE/PRE_RFC_BUILTIN_CALCS severity switching. CLS-04 is always an error, and class rules and calcs behave identically for every document. Hospitality has no module-gated behavior. Re-author alias fixtures with builtin ids. Delete both module packages, the conformance/modules/runtime shell scenarios and every release, verify and lockfile reference; releases from 4.0.0 publish seven packages. | types.ts:593-597; asset-class.ts:243-249; validator.ts:3071-3078; builtin-class-validation.ts:12-104; cli.ts:1186-1189; uwmd-batch/src/index.ts:308; uwmd-lake/src/plan.ts:529-535. 15 corpus files use org.uwmd.data_center. conformance/modules/runtime/01-11. The module packages appear in release.yml, release-packages.mjs, release-state, verify-versions, verify-lockfile, run-conformance and the lockfile. Both packages were deprecated on npm on 2026-10-11. |
| D7 | Old protocol and module ranges. A module manifest must declare ranges satisfied by 4.0.0 and 3.0. All 12 builtin packs move to requires_protocol: '^4.0.0' and requires_format: '^3.0', with a new pack major version (receipts pin pack versions, so receipt fixtures are re-issued). Module conformance manifests and signed module fixtures are regenerated. | 10 packs declare ^1.0.0/^1.1.0. data_center and manufactured_housing declare >=2.25.0/>=2.1.0. All 12 declare requires_tier: tier-3-calc-host. modules.ts:1012-1049 satisfies ranges against any supported version. |
| D8 | Conformance tier names. Delete LEGACY_TIER_READINGS, the readConformanceTier aliasing, ViewerTier, the numeric --tier shorts, legacy --tier=<suite>, the deprecation notices, the legacy_id/portable_legacy_ids/migration_base/before bookkeeping and the deprecated manifest enum values. Rename the tier-* directories, suite ids and portable case ids to content names. Docs-site pages follow, with no redirects. | protocol.ts:91-142; scripts/conformance-targets.mjs:18-45, 99-104; conformance/runner/runner.py:64, 402 and tier-readings.json; corpus-index.json; the deprecated tier branch of implementation-manifest.schema.json. 319 tracked files outside RFC and release history name a tier. |
| D9 | Module tier vocabulary. Replace ModuleManifest.requires_tier (tier-1..4) and the host tier with the Protocol 3.0 vocabulary: requires_conformance: 'reader' | 'verifier' plus an optional requires_profiles. | module-manifest.schema.json requires requires_tier; modules.ts:30, 138, 596-619, 1018-1024 (PROTO-MOD-006, PROTO-MOD-029). |
| D10 | Remove the legacy scalars that have structured replacements: rate_cap_pct (HDG-04), uses.interest_reserve/uses.operating_reserves (ESC-03), uses.renovation_* (CAPX-05), cam_cap_pct (REC-10) and sale_triggers_reassessment (TAX-04), so each fact has one way to be stated. Retire the agreement codes. | Four of the replacements could not state the lone fact; G1 below makes them able to. |
| D11 | Other deprecated items: FV legacy_code; structured content under .uw.md (refuse; no migration); superseded_blocks (remove if it only serves compatibility); getRequiredSections; the renderer's pre-§4.5 NOI keys; the retired-scenario special wording (remove if it is compatibility); receipt_version 1.0 and Lite canonicalization 1.0; RECEIPT_RESULT_TOLERANCE. | validator.ts:66-93; source-representation.ts:66-186; cli.ts:171-221; protocol.ts:772; renderer.ts:398-413; scenario.ts:20, validator.ts:211-222; receipts.ts:68, 92; UW_RECEIPT_v1.md §10.4 ("MUST accept both 1.0 and 1.1"); UW_LITE_SPEC_v1.md §6. |
| D12 | The Lite bridge emits Format 3.0 for all twelve classes, and the Lite spec is updated. | lite-bridge.ts:11, 16, 320-342, 509-520: ten classes compile to flat 1.1 and two to wrapped nested 2.1. Explicit Lite uw_version values pass through. |
| D13 | Keep, because these are not compatibility: RCP-06/07/10 (a version or engine mismatch is unverifiable), the INT-08 deprecated algorithms, the generic canonicalize/sha256Hex digest, the historical release evidence in docs/releases, the releasePackagesForGeneration history (edited to drop the module packages going forward), Excel's no-MCP-sheet path, and the web viewer (fixed to read the nested shape). | tools/web-viewer/index.html:161-165 reads only the flat _meta.section/_meta.superseded. |
| D14 | Supersession. List each compatibility clause this RFC supersedes, and note the partial supersession in each affected RFC's status line. | See Superseded clauses. |
Owner decisions at acceptance (2026-10-11)
The draft raised three gates and several open questions. The owner decided all of them:
| # | Question | Owner decision |
|---|---|---|
| G1 | Legacy scalars whose structured replacement could not state the lone fact | Option (a): each replacement gains the ability to state the lone fact, and no fixture invents a value. rate_cap_cost vs premium (HDG-05) gets the same treatment. Footing rule: the moved amounts count in the derived uses total exactly as the scalars did, so no derived total changes. |
| G2 | One block body shape | Bare. A block is the section payload with one inline _meta key; the {section_id, _meta, content} wrapper is not allowed in documents. The envelope representation keeps its own structure, and the conversion is mechanical because the fence carries the section id. The schemas change to match the spec text. The block hash is the canonical JSON of the payload minus _meta. |
| G3 | Hotel facts stated in both rent_roll and hotel_metrics | Consolidate now. Each fact lives once: keys, ADR, occupancy and available room nights live in the hospitality rent_roll (builtin precedent), and hotel_metrics keeps only facts not stated elsewhere. RevPAR stays rooms_revenue / available_room_nights, and the CC-HOSP rules read the single home. |
| Q1 | The other _v1 spec files | Rename them in Phase 2 alongside the format and protocol specs. |
| Q2 | Mojibake in uwmd-block-v2.schema.json | Phase 2 fixes it; that schema is itself renamed and merged. |
| Q3 | The deriveSourcesUses renovation double count | Out of scope for RFC 0081. The owner handles it separately. |
Proposed change
1. Versions
- Format 3.0.
uw_version: "3.0"is REQUIRED in frontmatter. A reader MUST refuse a document whoseuw_versionis absent or is anything other than"3.0", withUNSUPPORTED_FORMAT_VERSION(parse stage, error). The message names the declared value and the one supported value. There is no partial read, no display-only mode and no tolerance for a newer minor. - Protocol 4.0.0. The 4.0.0 contract is Protocol 3.0.0 with every compatibility clause below removed,
requires_tierreplaced (§6) and the tier-alias machinery gone (§8). §XII.3 is rewritten: the format-version refusal above replaces "refuse to edit a newer major". §XII.4 keeps the protocol-range rule. @uwmd/core4.0.0 ships with CLI 4.0.0. Other package versions move by semver-per-surface at release preparation.- Constants:
FORMAT_VERSION = '3.0',SUPPORTED_FORMAT_VERSIONS = ['3.0'],PROTOCOL_VERSION = '4.0.0'andSUPPORTED_PROTOCOL_VERSIONS = ['4.0.0']. Modulerequires_format/requires_protocolranges are checked against those single values.
2. One spec file per spec, no version in any file name
spec/UW_FORMAT_SPEC.md describes Format 3.0 only. Version history lives in the RFCs and the CHANGELOG, not in the normative text. Disposition:
| Source | Disposition in UW_FORMAT_SPEC.md |
|---|---|
| v1 front matter, Part I, Part II (except §2.4 body and §2.5) | Kept, with the version banner set to 3.0. |
| v1 §2.4 data block | Kept, and states the bare block body (§3 below) normatively. |
v1 §2.5 flat _meta table and the "only valid form for 1.x" paragraph | Replaced by v2 §2 (nested _meta) and v2 §3 (_overrides). |
| v1 §2.6 source identifiers | Kept, without the read-time interpretation, migration notes or legacy-tag tables. The actor grammar is always enforced, and the resolution vocabulary is the v2 §4.1 closed set. |
| v1 Part III provenance model | Kept, with the single block digest rule of §3 below. The v1 and v2 digest rules, the migration text and the signature-loss text are deleted. |
| v1 Part IV section registry | Kept, with the §7 field changes, the §5 hospitality fields, and the RFC 0080 "Official class sections" appendix moved into Part IV beside the other sections. |
| v1 Part V validation | Kept, with every per-generation clause removed (no "in both format generations", no "warning in 1.x"). |
| v1 Part VI toolchain | Kept, with the v2 §7 amendments applied: no migrate, init writes 3.0, and the Lite bridge emits 3.0. §6.1 parse output drops superseded_blocks. |
| v1 Part VII and Appendices A–D | Kept. |
| v2 §1 versioning and the one-shape rule | Replaced by §1 above. With one shape there is nothing to mix. |
| v2 §4 vocabulary changes | Folded into §2.6 as plain rules, without the "at 2.0" framing. |
| v2 §5 canonicalization and migration, §6 deprecations, §8 conformance, Appendix A shape mapping | Deleted. §3 below gives the digest rule; conformance is described against the renamed corpus. |
| v2 "Signed block roles" and v2 §8 official builtin classes | Moved to their topical homes: §2.8 for roles, §2.2 and Part IV for classes. |
Renamed spec files.
- The protocol becomes
spec/UW_PROTOCOL.md. This supersedes RFC 0078 D12's "rename in a later editorial pass". - The other specs drop their version suffix in the same phase (owner Q1):
UW_LITE_SPEC.mdUW_RECEIPT.mdUW_XML_MAPPING.mdUW_CSV_BUNDLE.mdUW_COMPOSITION.md
- The protocol's 34 starter stubs are deleted, and the §0/§I section map points to
docs/starter/once. - Appendix E's worked example re-authors the
org.uwmd.hospitalitymanifest as a neutral third-party example (com.example.*), because there is no longer an official module.
Every in-repo link follows the renames. Historical RFCs and release records are not edited. Instead, the docs-site prebuild link map resolves each old file name to its new page, so the site build does not fail on dead links (the RFC 0025 / PR #57 failure mode). This is a build-time link map, not a redirect.
3. One block shape, one _meta shape, one digest (G2)
Block body. A Format 3.0 data block is the fenced JSON object of §2.4.
- Its members are the section payload plus up to four reserved members:
_meta— REQUIRED, the first key;_role— optional (RFC 0040);_overrides— optional (v2 §3);_notes— optional.
- Every other member is payload. A payload member may be named
contentlike any other field. - The section id is carried by the fence annotation (
uw:section) and by_meta.section. It is never a block member. - A block with a top-level
section_idmember (the retired{section_id, _meta, content}wrapper) is refused withMETA-01. blockPayload()stops guessing at layout: the payload is the object minus the reserved members. The parse projection's wrapped-fence branch (cli.ts:181-191) is deleted, and the bare-fence projection rule of Protocol §II.6a.6 applies unchanged.
Envelope. The Document Envelope (uw-document-envelope) keeps its own structure. An envelope block is { annotation, content, prose? }, where content is the fenced object. Conversion in both directions is mechanical, because the annotation carries the section id.
_meta.
_metaMUST be the nested object:section,provenance,quality,lifecycle, and optionalintegrity. Readers never reshape it.- A block whose
_metalacks the nestedprovenanceandlifecycleobjects is alsoMETA-01(error: "block is not in the Format 3.0 shape").META-V2-IN-V1andMETA-V1-IN-V2are retired. - The provenance-completeness family is unchanged:
META_MISSING,META_FIELD_MISSING_<FIELD>andMETA_LOW_CONFIDENCE_NO_REVIEW_FLAG. _meta.sectionis the only spelling; thesection_idalias inside_metais gone.SRC-01andSRC-02are always errors. No read-time interpretation moves a resolution tag out ofprovenance.source.SRC-03changes from "resolutionismanual" to "provenance.resolutionis outside the closed resolution vocabulary" (error).- The in-memory
UWMetabecomes the nested shape (the D3 target), andUWBlock.meta_shapeis removed.
Block digest (normative). A block's content_hash is the lowercase hexadecimal SHA-256 of the UTF-8 bytes of the RFC 8785 (JCS) canonical JSON serialization of the block object with its _meta member removed:
- Every other member is included: all payload fields, plus
_role,_overridesand_noteswhen present. - Nothing else is excluded, defaulted or reordered beyond JCS.
- The reference serializer is the existing
canonicalizeExact, so no new serializer is introduced.
This rule has three consequences:
- What the hash covers.
content_hashcommits to what the block states, not to who stated it._meta(provenance, quality, lifecycle and the wholeintegrityobject, includingparent_hashandalgorithm) is outside the digest. - What a signature covers. The signature input is unchanged (
content_hash,section,actor,timestamp,kid,signed_at; RFC 0010 "What is signed"). A signature therefore still binds the author and time to the content. It no longer bindsparent_hashtransitively, which is exactly what RFC 0010 §4 intended ("re-rooting a chain after a merge must not invalidate every prior signature"); its note that the repository did not deliver this is resolved. - Chain verification.
parent_hashis still compared with the prior block'scontent_hash(INT-*codes). An edit that changes only_metaleavescontent_hashunchanged.
The generic canonicalize/sha256Hex remains for receipts and other non-block digests (D13).
One block schema. uwmd-block-v2.schema.json and uwmd-block.schema.json merge into a single uwmd-block.schema.json:
- an object with REQUIRED
_meta(the nested definitions); - optional
_role,_overridesand_notes; "not": {"required": ["section_id"]};- other members allowed (the payload, governed by the per-section schemas).
The merged file is written as clean UTF-8, which fixes the § mojibake (owner Q2), and its description no longer mentions META-* mixing.
4. No migration tooling
The migrators are used exactly once, in Phase 3. They are then deleted along with their exports, CLI commands, tests and the migrate conformance suite.
uwmd initwrites Format 3.0 bare nested blocks and takes no--format.- Structured fences in a file named
.uw.mdare refused withSOURCE_CONTENT_MISMATCH, the existing code for content that contradicts its representation. SOURCE_LEGACY_STRUCTURED, the explicit-UWX override that accepted the old name with a warning, andmigrateLegacyUWMarkdownare removed.
5. Builtin classes without transition rules; hospitality consolidated (G3)
Identity.
toBuiltinAssetClass(raw)returns a value only for the twelve builtin ids.org.uwmd.data_centeris an ordinary namespaced id. It is refused byINVALID-ASSET-CLASS-002, like every namespaced id that ends in a builtin name.CLS-01,CLS-02andCLS-05are retired.CLS-05("new ids require Format 2.1") cannot fire when only 3.0 exists.declaredModuleDependenciesreads only the object-list spelling. Amodulesentry namingorg.uwmd.hospitalityororg.uwmd.datacentersis an ordinary dependency that no installed module satisfies.uwmd scopedropsdeclared_asset_class. Batch and lake group by the stated id.
Every class follows the same rules.
CLS-03andCLS-04are errors for every document.- A class-content calculation that fails reports
MOD-CALC-ERROR(error). - Class rules keep their declared severity regardless of
uw_version,moduleslist or prior packaging. PRE_RFC_BUILTIN_CALCSandLEGACY_MODULEare deleted.
Hospitality: each fact lives once. Resulting fields:
| Home | Field | Status | Notes |
|---|---|---|---|
property | keys (integer ≥ 0) | as today (primary size, Protocol §XIII) | The key count's single home. hotel_metrics.key_count and rent_roll.keys are removed. |
rent_roll | available_room_nights (integer ≥ 0) | required by the hospitality class contract (CLS-04 when rent_roll is stated without it) | Keys × days in the period. rent_roll itself stays required by the §5.1 stage lists (DQ-06). |
rent_roll | occupied_room_nights (integer ≥ 0) | optional | Input to the dictionary occupancy/adr. |
rent_roll | adr (number ≥ 0) | optional | The stated ADR. Moved from hotel_metrics.adr. |
rent_roll | occupancy (fraction, 0–1) | optional | The stated occupancy. Moved from hotel_metrics.occupancy. |
hotel_metrics | market_revpar (number or null) | optional; the section is optional | The comp-set RevPAR for the same period, the only fact not stated elsewhere. adr, occupancy, available_room_nights and key_count are removed from this section. |
hotel_brand | flag, franchise_fee_pct_of_rooms, marketing_fund_pct, loyalty_program_pct, term_years | optional; section optional | Unchanged. |
hotel_food_beverage | fb_revenue, fb_cogs, fb_labor, complimentary_breakfast_cost_per_occupied_room | optional; section optional | Unchanged. |
Hospitality has no class-required section. Its required class facts sit in rent_roll, which the stage lists already require. This replaces the D6 default ("hotel_metrics required"), which had assumed hotel_metrics kept its facts.
Hospitality calculations and rules.
revparstaysnoi_model.income.rooms_revenue / rent_roll.available_room_nights.revpar_indexandfb_gross_marginare unchanged.total_room_revenuebecomesrent_roll.adr * rent_roll.occupancy * rent_roll.available_room_nights.room_revenue_per_keybecomesround(total_room_revenue, 2) / property.keys.- Both keep their null guards, units and
round_to. Their dictionary entries are re-pathed in Phase 2. The formulas are the same; only the input paths move. CC-HOSP-01,CC-HOSP-03andCC-HOSP-04are unchanged.CC-HOSP-02readsrent_roll.occupancy(rent_roll.occupancy == null || (rent_roll.occupancy >= 0 && rent_roll.occupancy <= 1)).
Hospitality corpus.
- Saguaro Select.
rent_roll.keys(142) is dropped becauseproperty.keys(142) states it, and Saguaro needs nohotel_metrics. Its newly computabletotal_room_revenueandroom_revenue_per_keyare listed additions. builtin-classes/01-03.- Move
adrandoccupancyintorent_roll, which already states the sameavailable_room_nights(29,200). - Restate the non-standard
property.key_count(80) asproperty.keys. The per-key size intensives that become computable are listed additions. - Keep
hotel_metrics.market_revpar.
- Move
builtin-classes/04. Its subject, a missing requiredhotel_metrics, no longer exists. It is replaced by aCLS-04case: a hospitalityrent_rollwithoutavailable_room_nights.
Module packages. packages/uwmd-module-data-center and packages/uwmd-module-hospitality are deleted, together with conformance/modules/runtime/01-11 and every reference in release, verify and lockfile tooling. From 4.0.0 the release publishes seven packages: core, CLI, signing, batch, Excel, report and lake. releasePackagesForGeneration keeps the module packages for generations before 4.0.0.
6. Module manifests: requires_conformance and requires_profiles
requires_tier is removed from ModuleManifest, the module-manifest schema, protocol.ts and Protocol §X. Two fields replace it:
requires_conformance(REQUIRED):"reader"or"verifier", the minimum Protocol tier (§II.1/§II.2) a host must claim to load the module.reader<verifier.requires_profiles(OPTIONAL): an array of unique members of the closedCONFORMANCE_PROFILESlist. The host must claim every profile listed. Absent means none.
Rules:
- A module that declares calculations SHOULD declare
requires_conformance: "verifier"andrequires_profiles: ["module"]. This replaces today's equally non-enforced "requires at least tier-3-calc-host", and no new refusal is added. - An invalid value or an unknown profile is
PROTO-MOD-006. - A host whose claimed tier is below
requires_conformance, or that lacks a listed profile, isPROTO-MOD-029. LoadModuleOptions.hostTierbecomeshostConformance(default"verifier") andhostProfiles(default: the profiles in the reference implementation'sImplementationManifest).- The twelve builtin packs declare
requires_conformance: "verifier"with no profiles. - Re-authored module fixtures map
tier-1-reader/tier-2-editortoreaderandtier-3-calc-host/tier-4-agent-hosttoverifier. They addmoduletorequires_profilesonly when the manifest declares calculations. Every fixture keeps its accept/refuse outcome.
7. One way to state each fact (G1)
Each removed scalar's fact moves to a structured home that can now state it alone. The phrase "all-or-none" means that stating some members of the group but not all of them is a shape error under the section's existing shape code.
Reserves (ESC-03 retired).
uses.interest_reserveanduses.operating_reservesare removed.- The fact is stated as
uses.escrows[]with{"name": "interest" | "operating", "upfront": <amount>}. That is valid today: onlynameis required, andESC-01needsupfrontormonthly.
Rate cap strike (HDG-04 retired).
debt_structure.rate_cap_pctis removed.rate_hedgenow requires onlyinstrumentandstrike_rate.notional,index,effective_date,expiration_dateandpost_expiration_assumptionform the terms group, which is all-or-none (HDG-01).- The lone fact is
"rate_hedge": {"instrument": "rate_cap", "strike_rate": 0.035}. HDG-01(on stated members),HDG-02andHDG-03apply to every hedge.HDG-06,HDG-07,HDG-08,HDG-09,HDG-10,replacement_fundingand the hedge clauses ofESC-04evaluate only when the terms group is stated. A strike-only hedge therefore never triggers a selection check.
Rate cap cost (HDG-05 retired).
uses.rate_cap_costis removed. The cost's single home israte_hedge.premium. RFC 0056 listsrate_cap_costamong the "four flat scalars" ofusesthat its typed fields describe.premiumkeeps itsHDG-01shape rule. It needs no terms group, so a hedge may state{"instrument", "premium"}together withstrike_rate.- Documents that stated both the cost and the premium already agree, because
HDG-05enforced it. - A cost-only document moves the amount onto its single stated hedge.
Renovation (CAPX-05 retired).
uses.renovation_budgetanduses.renovation_contingencyare removed.uses.renovationrequires no member except at least one ofbudgetorcontingency.contingency_used,drawn_to_dateandas_of_dateform the draw group, which is all-or-none. Stating it requires bothbudgetandcontingency.contingency_remainingis allowed only with the draw group.CAPX-01applies to the stated members.CAPX-02,CAPX-03andCAPX-04evaluate only with the draw group.- The lone fact is
"renovation": {"budget": 4000000}. No draw figure is invented.
CAM cap (REC-10 retired).
- Tenant
cam_cap_pctis removed. recovery_termsmay statecapalone.methodis required as soon as any member other thancapis stated.- The lone fact is
"recovery_terms": {"cap": {"pct": 0.05}}, withoverandaccumulationleft unstated as today. RECrules that readmethodevaluate only when it is stated.
Sale-triggered reassessment (TAX-04 retired).
sale_triggers_reassessmentis removed.reassessmentnow requires onlytrigger.assessed_value,millage_rateandindicated_taxform the assessment group, which is all-or-none.jurisdiction,value_basis,assessment_ratioandround_to_decimalsare allowed only with that group.TAX-01,TAX-02andTAX-03evaluate only with the assessment group.- The lone fact is
"reassessment": {"trigger": "sale"}. Every corpus document states the old boolean astrue. The onlyfalseis the retiredTAX-04negative control. Afalsenamed no trigger, so a document that knows only "not on sale" states nothing rather than inventing one.
Footing rule. deriveSourcesUses derives uses.total, when uses is stated, as today's sum of the numeric leaves of uses plus:
- the
upfrontof eachuses.escrowsentry namedinterestoroperating, each counted once; - the
premiumof eachrate_hedgestated in an activedebt_structureblock, each counted once.
Other escrow names stay uncounted, as today. The typed renovation object's leaves are already summed by today's rule, so a document that stated only the renovation scalars and becomes renovation: {budget, contingency} derives the same total.
For every document that stated each fact once, the derived total is unchanged. Two corpus documents differ, and neither total is pinned by any baseline:
capex/accept-draw-with-verified-remainingstated the renovation scalars and the typed object. Today's sum counts both, on top of the separate, out-of-scope draw-field double count (owner Q3). Removing the scalars lowers its still-defective total from 11,350,000 to 6,850,000. This RFC neither fixes nor preserves that defect.hedge/0076-two-seniors-no-hedge-escrowstates one 400,000 cap cost andrate_cap_pcton two identical senior variants. Each senior becomes a strike-only hedge, but the cost cannot be attributed to either without inventing a fact. Phase 3 drops the amount: the fixture asserts onlyESC-04andunverifiable/invalid_structure, neither of which reads it. Phase 3 reports the dropped amount for owner confirmation.
Also removed:
- FV
legacy_code.ValidationMessage.legacy_code,fvCode()and theFV_*mapping are removed. superseded_blocksinuwmd parseJSON. The source labels it compatibility-only (cli.ts:171-172).getRequiredSections.- The renderer's pre-§4.5 NOI keys (
noiLegacyValue). - The retired-scenario wording.
RETIRED_SCENARIOSand its special message are removed. A retired value gets the ordinaryDQ-07warning; the open-scenarioDQ-07rule itself stays. - Receipt versions.
receipt_versionstays1.1, and it is the only accepted value (SUPPORTED_RECEIPT_VERSIONS = ['1.1']). Lite canonicalization is1.1only.UW_RECEIPT.mddescribes 1.1 directly.RECEIPT_RESULT_TOLERANCEis deleted, andRCP-10stays (D13). - The web viewer now reads
_meta.lifecycle.supersededand_meta.section.
8. Conformance names
- Tier aliases are removed in every form listed in D8.
--tieracceptsreaderorverifier, fixture families are selected with--suite, and any other--tiervalue is a usage error.ImplementationManifest.tieris"reader" | "verifier"only.
| Today | 4.0.0 | Suite id(s) | Why |
|---|---|---|---|
tier-1-reader/ (fixtures, expected, malformed) | documents/ | documents | The base documents are parsed (Reader), validated (Verifier) and rendered (starter products): 20, 31 and 34 cases, plus 1 integrity case. A reader/ directory would mislabel 66 of its 86 cases. |
tier-1-reader/v2-fixtures/ (suite meta-v2) | removed | — | Its shim, one-shape and digest shape-insensitivity cases test deleted behavior. The META-01 refusals move to documents/malformed, and the defaulted-algorithm case is retired with the new digest scope. |
tier-2-editor/ | starter/editor/ | starter-editor | 6 starter-products cases. |
tier-3-calc-host/ | calc/ | calc | 96 Verifier cases plus revpar-basic (Module). |
tier-3-calc-host/refinement/ | starter/refinement/ | starter-refinement | Starter. |
tier-4-agent-host/ (fixtures, profile, replay) | starter/agent/ | starter-agent, starter-agent-profile, starter-agent-replay | Starter. |
migrate/, modules/runtime/ | removed | — | D4, D6. |
- Portable case ids keep the
<owner>__<suite>__<scenario>__<op>pattern with the new suite ids, for examplereader__documents__01-minimal-screening__parse. legacy_id,portable_legacy_ids,migration_baseandbeforeare removed fromcorpus-index.jsonand its schema.- Docs-site conformance pages follow the new names, with no redirects.
Decisions
The calls this RFC makes where D1–D14 and the owner's acceptance answers leave a detail open:
| Question | Decision | Why (precedent) |
|---|---|---|
Error for an unsupported or absent uw_version | UNSUPPORTED_FORMAT_VERSION, parse stage, error. | UNSUPPORTED_YAML_FEATURE and ENVELOPE_UNSUPPORTED_VERSION; D1's "one clear error". |
Wrapper member or flat _meta in a 3.0 file | One code, META-01. Retire both META-V* codes. | Codes are not renamed in place (the FV_* → FV-NN precedent). The hyphenated META-* family already owns block shape. |
SRC-03 | Generalize it to any resolution outside the closed vocabulary. | House pattern of closed vocabularies; the block schema already enumerates ResolutionTagV2. |
| Digest serializer | JCS via the existing canonicalizeExact. No _meta-aware stripping is needed once _meta is excluded whole. | G2 (owner); RFC 0010 "Canonicalization uses RFC 8785 (JCS)". |
| Receipt version | Keep 1.1 and drop 1.0. No renumbering. | The receipt shape does not change. receipts.ts refuses to stamp a version for a change that did not happen. UWX canonicalization stays 1.0: envelope canonicalization reads the raw fenced object, and its rule is unchanged. |
superseded_blocks | Remove. | The source labels it compatibility-only, and it duplicates superseded. |
| Retired scenarios | Remove the special wording and keep the generic DQ-07. | RFC 0072 R3's reason for the special wording is compatibility. |
.uw.md with structured fences | SOURCE_CONTENT_MISMATCH. | The existing code for content that contradicts its representation. |
| Module host vocabulary | As §6 states. Reuse PROTO-MOD-006/029 and add no new refusal. | RFC 0078 §II tiers; fix-scope discipline. |
| Corpus directory names | documents/, calc/, starter/{editor,refinement,agent}/. | RFC 0078 Phase 3 tags owners per case, so directories are named by content. |
| Key count's home (G3) | property.keys, not rent_roll. | It is the builtin primary size: Protocol §XIII and the dictionary's price_per_key/loan_per_key/noi_per_key read it, and RFC 0080 put every primary size on property. G3's "builtin precedent" points here. The other three hotel facts live in rent_roll. |
| Hospitality required section (G3) | None. The required facts are in rent_roll. | G3 consolidation leaves hotel_metrics holding one nullable comp-set figure, and requiring that section would require nothing. |
| Home of the rate cap's cost (G1) | rate_hedge.premium. | RFC 0056 lists rate_cap_cost among the "four flat scalars" its typed fields describe. Nine corpus documents state premium with no cost, two of them testing a missing sources_uses/uses. The opposite choice would force sources_uses blocks into them. |
| Lone-fact groups (G1) | All-or-none groups under the existing shape codes. Dependent rules evaluate only when their group is stated. | RFC 0056 group-statement precedent (ESC-01: "at least one of the two stated"); no new code family. |
| Status lines of superseded RFCs | Edited in this acceptance PR. | Matches the RFC 0080 precedent. |
Superseded clauses
Each RFC below carries a status-line note pointing here:
- RFC 0006: the
hotel_metricsfield set (nowmarket_revparonly). - RFC 0009:
- "Migration story (the back-compat parser shim)";
- "One shape per file" (both directions);
- "Deprecation timeline" (carried out here);
- the v1 and v2 block digest rules under "Canonicalization, integrity, and signatures across the shape change" (replaced by §3 above);
- the per-file boundary later written into v2 §1.3.
- RFC 0017: "Legacy detection", and the bridge pinned to Format 1.1.
- RFC 0022: acceptance of receipt_version 1.0 beside 1.1, as written into
UW_RECEIPT_v1.md§10.4. - RFC 0025: the explicit-override acceptance of a structured
.uw.md. - RFC 0031: §4 read-time interpretation, the 1.x warning severities and the legacy-tag migration tool.
- RFC 0053:
sale_triggers_reassessment,TAX-04, and the required assessment members (now an all-or-none group). - RFC 0056:
rate_cap_pct,uses.interest_reserve,uses.operating_reservesanduses.rate_cap_cost;HDG-04,HDG-05andESC-03;- the hedge's required set (the terms group is now all-or-none).
- RFC 0057:
uses.renovation_budget/_contingency,CAPX-05, and the required draw members (now an all-or-none group). - RFC 0058:
cam_cap_pct,REC-10, andmethodbeing required when only acapis stated. - RFC 0072: R3's retired-value wording and the "in both 1.x and 2.x" clauses.
- RFC 0078: D12; the Compatibility analysis's "during 3.x the four old values stay readable"; the Phase 3 decisions on legacy aliases,
legacy_idandportable_legacy_ids. - RFC 0080:
- §5 in full;
- §6's final 0.2.0 shells;
- §7's "2.1 readers read 2.0 and 1.x unchanged";
- the decision rows Lite bridge, Required hotel section, Compatibility identity, Native block/envelope shape, Versions, Pre-existing hospitality calculations, Compatibility severities, Scope identity (
declared_asset_class), Grouping keys and Official module packages; - §4's placement of the hotel facts in
hotel_metrics.
RFC 0010 is not superseded. §3 restores its §4 intent, so its implementation note about hash scope no longer applies; that RFC carries a short note saying so.
Compatibility analysis
None, by design (P5):
- Documents. Every document that is not Format 3.0 is refused, including every document produced before 4.0.0.
- Implementations. Protocol 3.0.0 claims do not carry over.
- Modules. Third-party modules must re-declare their ranges and replace
requires_tier.
The only consumers are the owner's, and they update their exporters to emit Format 3.0 with the 4.0.0 release. The deprecated npm module packages stay deprecated and are never published again.
Conformance impact
Re-authored. Every fixture listed in D5, with baselines regenerated where shape appears in them: parse projections (nested
meta, bare payloads, nosuperseded_blocks), hashes (§3 rule), signatures, receipt digests and pack versions.Removed.
- the
meta-v2suite and themigratesuite; modules/runtime/01-11;- the
CLS-01/CLS-02/CLS-05cases; - the
HDG-04,HDG-05,ESC-03,CAPX-05,REC-10andTAX-04agreement cases; builtin-classes/04;- the deprecated-tier runner cases.
- the
New.
UNSUPPORTED_FORMAT_VERSIONforuw_version1.1, 2.0, 2.1, 4.0 and absent;META-01for a flat_metaand for asection_idwrapper member;- a bare payload with a field named
content, read as payload; - the §3 digest: a
_meta-only edit keepscontent_hash, and a payload edit changes it; - the generalized
SRC-03; org.uwmd.data_centerrefused byINVALID-ASSET-CLASS-002;- a structured
.uw.mdrefused bySOURCE_CONTENT_MISMATCH; - a hospitality
rent_rollwithoutavailable_room_nightsrefused byCLS-04; CC-HOSP-02read fromrent_roll;- the lone-fact acceptances and all-or-none refusals of §7;
- accept and refuse cases for
requires_conformance/requires_profiles; receipt_version1.0 refused.
Invariant (hard acceptance criterion). These are unchanged:
- every calc baseline value;
- the lender fixture (187 / 0 / 0, with identical per-statement evidence);
- every receipt's result values;
- every derived uses total except the two §7 documents.
The newly computable hotel calculations and per-key intensives are listed as additions.
Tiers and profiles. This changes the Reader corpus (version and shape refusals), the Verifier corpus (codes and the hospitality paths) and the Module profile (manifest vocabulary).
Reference implementation
Each phase is its own PR, in order. [Unreleased] carries the CHANGELOG entries, and nothing ships until Phase 6.
- RFC acceptance (this PR, #307). Record the owner's decisions and add the status-line notes listed under Superseded clauses.
- Spec, schemas and
protocol.ts.- Write
UW_FORMAT_SPEC.md. - Rename every
_v1spec file (§2) and delete the protocol stubs. - Rewrite
UW_RECEIPT.mdfor 1.1, the Lite spec §6 for 3.0 and Protocol §V.9/§V.10 for the §3 digest. - Merge the block schemas and fix the mojibake. Update the module-manifest, implementation-manifest, corpus-index, hedge, renovation, recovery-terms, tax-reassessment and hotel-section schemas, and the hospitality dictionary paths.
- In
protocol.ts, set the new code registry and therequires_conformancetypes, and add'3.0'/'4.0.0'to the supported sets somainstays green. - Update AGENTS.md, the wiki, and the docs-site copy list and link map.
- Write
- Corpus re-authoring.
- A one-off script:
- runs
migrate --source-tags, thenmigrate --to-v2 --resignwith the conformance test key; - stamps
uw_version: "3.0"and unwraps every wrapped block into the bare shape; - moves the §7 scalars and the §5 hotel facts;
- replaces alias and module ids, and rewrites module manifests (§6) and pack ranges;
- re-stamps hashes under the §3 rule and re-signs. Receipts are re-issued.
- runs
- The PR carries a before/after value diff over every calc baseline, the lender fixture, every receipt result and every derived uses total. The diff must be empty except for the listed additions and the two §7 documents.
- A one-off script:
- Code deletion.
- Narrow the supported sets to
['3.0']/['4.0.0']. - Delete the reshape layer and the wrapper handling, make
UWMetanested, and implement the §3 digest. - Delete both migrators, the CLI
migratecommands andinit --format. - Delete the alias, the transition rules, the module packages and their tooling references.
- Delete the legacy scalars and the remaining items in §7; implement the lone-fact groups and the footing rule; move the hospitality fields.
- Make Lite emit bare 3.0 and fix the web viewer.
- Narrow the supported sets to
- Conformance renames (§8), the runner and generator, and the docs-site pages.
- Release 4.0.0 by the wiki 11 procedure: Format 3.0, Protocol 4.0.0, seven packages. Release preparation pairs core/CLI 4.0.0 with Protocol 4.0.0 and Format 3.0; signing moves to 0.3.0 and batch, Excel, report and lake take patch steps (CHANGELOG 4.0.0 records why). Released in 4.0.0.
Combining. Phase 2 and the set-narrowing half of Phase 4 could share a PR only if Phase 3 landed inside it, which would make one unreviewable diff of roughly 800 files. Keep 2 → 3 → 4 separate. Phase 5 is mechanical and could fold into Phase 4. Keeping it separate is recommended, because renames dominate any diff they share.
Alternatives considered
- Keep the read path and drop only the write path (readers accept 1.x/2.x, writers emit 3.0). Rejected: the read path is the expensive half, and P5 rules it out.
- Format 2.2 instead of 3.0. Rejected: refusing every earlier version and removing fields is a breaking change, and semver-per-surface (invariant 6) requires a major.
- Keep the migrators as an unsupported script. Rejected (D4): a tool nobody tests rots, and git history keeps the one use.
- Deprecate first and remove in 5.0. Rejected (P5).
- The wrapped block shape (G2). Rejected by the owner. It contradicts the spec text, adds a third copy of the section id, and 635 of 759 corpus files are already bare.
- Keep hotel facts in
hotel_metricsand make it required (G3 draft default). Rejected by the owner: it states the same facts twice.
Unresolved questions
None for this RFC. The owner placed these outside it:
- the
deriveSourcesUsesdouble count of the typedrenovationdraw fields (owner Q3, handled separately); MOD-CALC-ERROR/MOD-RULE-ERRORnaming for builtin class failures.
What remains after this RFC
The reference implementation supports exactly one format version (3.0) and one protocol version (4.0.0):
- one block body shape, one
_metashape and one block digest rule; - one receipt version;
- one spelling for each class id and one home for each fact;
- two conformance tiers with six profiles and no aliases;
- one spec file per spec, with no version in any file name.
Every later breaking change follows P5: an RFC and a version bump but no transition plan, until the owner declares the standard released.
Resolution
Accepted 2026-10-11 (PR #307); implemented 2026-10-12; released in 4.0.0 with Format 3.0, Stable Protocol 4.0.0, core/CLI 4.0.0 and seven packages. Signing moved to 0.3.0, because a 0.2.26 signature does not verify under the §3 digest; batch, Excel, report and lake took patch steps. The two module packages were never published again and stay at their final, deprecated 0.2.0. The decisions are P5 and D1–D14 under Owner direction, G1–G3 and Q1–Q3 under Owner decisions at acceptance, and the Decisions table. Implementing PRs: #308 (spec, schemas and protocol.ts), #309 (corpus re-authoring), #310 (code deletion), #311 (conformance renames) and #312 (release preparation). FORMAT_VERSION and PROTOCOL_VERSION equal the single member of their supported sets; the interim SPEC_FORMAT_VERSION/SPEC_PROTOCOL_VERSION constants were removed.
Contract details settled during implementation
- Digest and canonicalization. §3 governs every spec: a
_meta-only change keepscontent_hashand the signature, and a signature does not bindparent_hashtransitively. Protocol §V.11.2 no longer saysintegrityis "covered like any other_metafield".canonicalizeandcanonicalizeExactbecame onecanonicalize, plain RFC 8785 JCS with no stripping of_meta-shaped members, and Protocol §V.9 names that one function. - Restored normative text. The spec merge kept every MUST, SHOULD and table this RFC does not remove:
partial/provisionaland the provisional-label SHOULD, the closed_overrides[].reasonvocabulary, the cascade-tag MUST, §V.9's non-finite andundefinedrules, theMETA_FIELD_MISSING_<FIELD>list (code names unchanged, soVERSIONnameslifecycle.revision), theDQ-07preserve MUST, and the RFC 0071/0074 module floors restated as>=4.0.0. - Format version everywhere. The envelope schema pins
frontmatter.uw_versionto"3.0"and drops theCLS-05conditionals.assertUWEnvelope, the Lite bridge and the web viewer refuse any otheruw_versionwithUNSUPPORTED_FORMAT_VERSION. A.uwpart.mdstatesuw_version: "3.0"(Composition §2.1,uwpart.schema.json); a part without it is refused like any other document. An unquoteduw_version: 3.0is refused with a message to quote it, because YAML reads it as the number 3. - Structured content under
.uw.mdstaysSOURCE_CONTENT_MISMATCHeven with an explicit UWX representation. The informational code for an extension-inferred representation isSOURCE_REPRESENTATION_INFERRED(wasSOURCE_LEGACY_EXTENSION). - G1 groups. All-or-none groups use
dependentRequired, anduses.renovationrequires at leastbudgetorcontingency;replacement_fundingrequires the terms group. A member stated asnullis not stated: it neither triggers nor satisfies a group requirement (soreplacement_funding: null,contingency_remaining: nullandjurisdiction: nullneed no group); the schemas use null-exemptdependentSchemas, and a non-nullable member stated asnullstays a type error. A lone recoverycapis valid withoutmethod,overoraccumulation; oncemethodis stated, a statedcap.pctrequirescap.accumulation(REC-02, also in the schema). - Hospitality
rent_roll. No class has arent_rollschema, so the class contract is the open fragmentrent-roll-hospitality.schema.json:available_room_nightsrequired,occupied_room_nights,adrandoccupancyoptional and non-nullable as §5 types them,keysrefused, other members unconstrained. With the transition switches gone, a class calculation error is an error for every document of the class. _metain memory and in edits.UWMetais one nested type whose members are exactlyuwmd-block.schema.json's;block.metais the parsed_metaandblockPayloadreturns the block minus_meta,_role,_overridesand_notes. AnEditOperation'smetais a closedUWMetaPatch(optionalprovenanceandquality, merged over the host-built_meta; the host ownssection,lifecycleandintegrity). Any other member, or ameta.provenance.sourceother than the writer's own source, is refused asPROTO-EDIT-002;edit-operation.schema.jsonand Protocol §V state it. Field overrides are read only from the reserved_overridesmember. The reference host strips_overridesfrom every agent-authored write, because an override entry is per-field provenance the cascade honors asuser_override(invariant 5).- Effective cascade tag.
_overrides[].resolution, thenprovenance.resolution, thenmanualfor amanualactor. No tag is read out ofprovenance.source, and an_overridesentry that states only an actorsourcedoes not shadow the block's resolution. - Receipts.
SUPPORTED_RECEIPT_VERSIONSis['1.1']; a 1.0 receipt is refused at read asRCP_MALFORMED. - Module dependencies and hosts.
declaredModuleDependenciesreads object entries and the restricted YAML reader's- id: xitems; amodulesentry that is not an object with anidisMOD-DEPENDENCY-UNDECLARED(warning) per entry, for every class, and the Appendix Did: <module>scalar still reads.LoadModuleOptionstakeshostConformance(defaultverifier) andhostProfiles(default every profile); a conformance reject case states its host inexpected.host. - Parse projection. Extension blocks get the same projection as standard sections (§II.6a.6), so a member named
contentis payload there too. - Conformance tooling.
--tiertakesreaderorverifierin both drivers;conformance/runner/vocabulary.json, generated fromscripts/conformance-targets.mjs, replacestier-readings.json, and the portable report'stier_readingbecomesmanifest_tier. - Guards.
verify-codesreads the Protocol's "Retired agreement/transition codes are not emitted" sentence: it exempts those codes from the implemented-RFC check (RFCs 0053, 0056, 0057 and 0058 keep their historical code tables) and fails if core still emits any of them.verify-indexesrunsscripts/spec-refs.mjs, so a spec§target,spec_refor spec link that resolves to nothing fails CI.
Corpus re-authoring and approved value exceptions
The re-authoring was checked against a snapshot of the corpus taken before it: every calc baseline, the lender evidence, receipt verdicts and results, validation codes, conformance outcomes and derived uses totals. All are identical (including the lender fixture at 187 / 0 / 0, the 97 calc baselines, the 15 receipts, the 89 module manifest load results and every block digest and signature outcome) except the items below, each confirmed or approved by the owner on 2026-10-11.
Planned additions (Saguaro Select). total_room_revenue: null → $6,080,000; room_revenue_per_key: null → $42,816.90. All stated figures and the lender evidence are unchanged.
Derived uses totals. The rule: retire a fixture whose only assertion is a retired conflict code, and keep every live refusal.
| Fixture | Derived uses total | Cause |
|---|---|---|
capex/accept-draw-with-verified-remaining | $11,350,000 → $6,850,000 | The duplicate legacy budget and contingency are dropped; the typed group stays. The draw accounting itself is unchanged (Q3 stays out of scope). |
hedge/0076-two-seniors-no-hedge-escrow | $1,150,000 → $750,000 | The $400,000 cost has no attributable stated hedge home and is dropped; no allocation across loans is invented. |
capex/reject-legacy-budget-disagrees | $9,470,000 → $6,470,000, then retired | Removing the disagreeing $3,000,000 legacy budget leaves the typed budget; CAPX-05-only control. |
hedge/reject-legacy-reserve-disagrees | $750,000 → $500,000, then retired | Removing the legacy reserve leaves the stated escrow upfront; ESC-03-only control. |
hedge/reject-premium-disagrees-with-use | $500,000 → $410,000, then retired | The typed premium is the single cost home; HDG-05-only control. |
hedge/0070-ambiguous-debt | $1,150,000 → $1,550,000 | Each of two stated $400,000 premiums counts once beside the $750,000 interest escrow; the live refusal stays. |
hedge/0076-sources-refused-malformed-hedge | $1,150,000 → $750,000 (each sources variant) | The malformed hedge supplies no attributable home, so the $400,000 cost is dropped; the live refusal stays. |
In hedge/0075-malformed-hedge-beside-junior the $400,000 rate_cap_cost becomes premium on the junior's hedge, the only well-formed one, and the total is unchanged.
Other expected-output changes (no stated value changed).
- Rendered outputs of
documents/01-minimal-screeningand16-frontmatter-yaml-scalarsnow print property facts the old wrapped block stated but the renderer could not read, and lose the retired missing-section warning. receipts/issue/01-uwx-multifamily: validation warnings 5 → 0 (metadata-shape warnings); result values and verdict unchanged.source/04-colon-form-rejectedreports an error, becauseSRC-01/SRC-02are always errors.- The 71 reserve-account and reserve-draw documents are now bare blocks with their source, timestamp, confidence and revision in their nested homes; reserve verifier outcomes are unchanged, 45 documents lose
CF-02,LU-01orLU-03errors that only the wrapper caused, andinvalid-source-dategainsCF-01for its stated 2026-02-30 row. - Moving hotel keys to
property.keysremoves nineCC-13warnings;builtin-classes/04becomes theCLS-04case of a hospitalityrent_rollwithoutavailable_room_nights. - With
SRC-03always applied, 176resolution: manual_overridevalues becameuser_overrideand 21resolution: source_documentvalues were removed (a source document is an actor, not a cascade step)._metais outside the digest, so no hash, signature or receipt changed. - The all-in yield's reserves input reads
sources_uses.uses.escrows[0].upfront. - Re-stamped hashes, signatures and receipts keep every intentional negative control failing: tampering, invalid source vocabulary, malformed parent links and stale digests.
Conformance outcome
Twenty checks were retired with their subject (meta-v2 6, migrate 3, modules/runtime 11), along with meta-v2/06-digest-shape-insensitive and the six conflict-only cases for CAPX-05, ESC-03, HDG-04/05, REC-10 and TAX-04. Thirty-five checks were added: five UNSUPPORTED_FORMAT_VERSION controls, flat _meta and wrapper (META-01), an out-of-vocabulary resolution (SRC-03), the retired alias (INVALID-ASSET-CLASS-002), a content payload member (4 checks), a structured Lite name, a _meta-only edit after signing, receipt 1.0, four module refusals (8 checks with schema parity), nine lone-fact controls and two PROTO-EDIT-002 refusals of meta members outside the patch. New hedge cases carry the RFC number (0081-accept-strike-only, 0081-reject-partial-terms-group). The corpus is 1,069 reference checks and 336 portable cases.
The renames follow §8 with no old path, suite selector or id accepted. Both reserve legacy-v1 cases became bare-block with unchanged documents and assertions. Portable ids and file stems are <owner>__<suite>__<scenario>__<operation>; malformed-document scenarios use malformed-<stem> and replacement-funding projections use the reference suite hedge. Family membership is unchanged: calc includes starter-refinement, starter-agent includes starter-agent-profile, replay is selected separately, and child-only baseline updates stay refused. Former tier spellings survive only as inputs that refusal tests prove are refused. The docs site maps old links in historical RFCs and release records to current pages at build time, with no redirects or old pages.
The rename was verified case by case: each of the 1,069 reference checks and 336 portable cases kept its owner and outcome (every one passed before and after), the portable definitions are identical apart from the renamed paths and ids, and the lender's per-statement evidence is unchanged at 187 / 0 / 0. The full old-to-new id table was published with PR #311 and remains in this file's history.
Out of scope: the deriveSourcesUses renovation double count (Q3) and the restricted YAML reader's handling of lists of mappings, each left for a separate fix.
Prior art
- RFC 0009's own timeline planned the shim's removal at the next major; this RFC carries it out.
- RFC 0010's signing design intended a content hash that does not bind
parent_hash; §3 delivers it. - Pre-1.0 semver practice (the spirit of semver §4): before a public release, anything may change and no compatibility is owed.