Skip to content

RFC 0040 / 0041 implementation readiness ​

Decision update: the owner approved signed block-level _role on 2026-09-11. RFC 0040 now records the accepted contract; the findings below explain that decision. Its implementation uses Protocol 2.7.0. RFC 0041 was subsequently accepted as the bounded Protocol 2.8.0 implementation on 2026-09-12; the findings below record the original draft review.

Reviewed against 59e8912 (core 2.6.2, Protocol 2.6.0). Documentation cleanup landed in PR #177. The active implementation stage is RFC 0040; RFC 0041 follows. Neither draft has been accepted or implemented by this review.

RFC 0040: role identity and signatures ​

The draft's _meta.role does not survive reshapeMetaV2toV1. Even if a caller puts role in the flat in-memory meta, computeBlockHash(..., { shape: 'v2' }) normalizes it through reshapeMetaV1toV2, which drops it again. That makes the claim that role changes already change the block hash false at this baseline. The envelope/receipt digest is a separate path; this finding concerns block integrity and the block signatures built on it.

A probe of the built library confirmed:

ObservationResult
Nested _meta.role survives the parse-view reshapeNo
Changing flat meta role: senior to role: junior changes the v2 block hashNo
Changing block-level _role: senior to _role: junior changes the v2 block hashYes

The recommended revision is a block-level _role annotation, alongside _meta and _overrides. Existing v2 canonicalization retains this content, so roles can be signed without redefining the normalization of existing metadata. _meta.role must not become an alias: otherwise two spellings have different integrity behavior. The owner must approve this location change before schema implementation. If _meta.role is retained instead, first design an explicitly versioned normalization/signature compatibility policy; do not silently change the hash of pre-existing role-bearing files.

RFC 0040: decisions the implementation contract must pin ​

  • One scalar role per block. primary and detail cannot coexist in one field. A check with no matching preferred role can still select primary.
  • Filter component blocks before every property-level selection step, including named preferences, default, base, and sole-candidate fallback. A standalone component block must not become a property total merely because no map exists.
  • Resolve in this order: check-specific key preference, check-specific role, primary, default, base, sole eligible variant. Never select by insertion order.
  • A duplicated role is ambiguous when that role's step is consulted; do not silently fall through to default. Unconsulted roles do not override an earlier successful explicit choice. Repeated component roles are allowed because those blocks are excluded, not candidates for selection.
  • Unknown roles and malformed role values are structural errors. An invalid candidate cannot be selected as a fallback. Errors are found in all variants, even when a different candidate resolves successfully.
  • Preserve existing results and coverage byte-for-byte for role-free documents. Do not add an unconditional via field to every old coverage entry.
  • Coverage is per rule, but one rule reads several sections. Add an optional resolutions map keyed by section, with the selected variant and via for role-bearing selections; a single top-level via cannot explain both sides.
  • Audit CC-03's direct resolver calls and CC-12's direct getSection use, not only requireSections. Keep CC-15's lease-up base rule unchanged.
  • Keep every financial comparison and tolerance unchanged. Multiple senior facilities remain ambiguous; this feature does not aggregate them.
  • Writers preserve a role during ordinary edits. A trusted explicit role change must be distinct from model-authored section content; raw agent output must not be able to assign or overwrite the host's role annotation.

RFC 0041: findings to resolve next ​

Draft claimSource finding / proposed correction
Year 3 can compare with 2028-Q1 and an ISO dateIts own equality rule says different kinds never compare. Preserve absolute calendar identities; defer date-to-holding-year conversions until a calendar contract exists.
Calendar key is a row's 1-based positionThat conflates two unrelated schedules' first months and relies on validation/order. Use an absolute calendar month/quarter key. If ordinal Qn/Mn aliases remain, specify their anchor and gap behavior separately.
Add @ handling to parser.ts deepGetCalc AST paths walk getPathSegment in calc/evaluator.ts; they do not call deepGet. Lexer/parser, AST traversal, override keys, dependency extraction, and Excel emission all need explicit treatment.
deepGet can look up a merged period registryIts API is deepGet(obj, path) and has no parsed-file or registry context. Preserve the generic helper and add a context-aware period resolver, rather than silently repurposing every data lookup.
A first matching row resolves duplicate periodsThat is order-dependent despite PS-02. Evaluation must refuse an ambiguous match, even when a caller skips validation.
A variant map follows the existing cross-check resolverCalc uses getSection, which refuses maps; cross-check resolution is private to the validator. Declare a calc-specific section-selection contract, with explicit variant context, instead of importing a check's senior preference.
Module registration needs no runtime change unless usedNo manifest field or merged-registry API is specified. Define schema/runtime validation, namespace ownership, collision refusal, and context propagation before promising module registration.
@ can be globally reserved in all existing path stringsGeneric deepGet currently traverses arbitrary object keys, while calc grammar is narrower. Limit new selector syntax to declared expression/reference surfaces; preserve literal-key lookup elsewhere.
Only PS-01 and PS-02 are introducedThe draft also defines PS-03; tables, summary, exported registries, and fixtures must agree.
Both RFCs target Protocol 2.7.0Reconcile the actual landed protocol before each stage. If 0040 lands as 2.7.0, a later separate 0041 minor is 2.8.0; package versions remain independently selected at release time.

Recommended first implementation of 0041: explicit Y<n> selectors on year series and absolute calendar/date selectors on the five standard series, with no implied calendar conversions. Defer relative Q<n>/M<n> aliases, wildcards, and module-defined series until their separate contracts are pinned. This is a scope proposal for the next stage, not approval to alter the current protocol.

Acceptance evidence required ​

RFC 0040 must prove role-driven selection, duplicate refusal, component exclusion, unchanged role-free behavior, writer preservation/authority, and signed role tamper detection in both metadata formats and supported representations. RFC 0041 must additionally prove row-order independence, duplicate refusal without prevalidation, calendar identity, missing-period behavior, explicit variant scope, safe segment traversal, override precedence, dependency extraction, and an honest Excel emission refusal or supported translation for every new AST shape.

Released under the MIT License.