Status: implemented
Implemented — this change has shipped.
RFC 0028: Make a missing required section a reportable defect
Accepted 2026-08-26, with the three review decisions resolved as follows: the two-rule design and severities stand as proposed;
operating_statementtakes option (a) — it joinsSTAGE_REQUIREMENTS.full_underwrite(and the stages above it), reviving the validator's dead variant-awarehasSectioncase rather than striking the spec's claim; and example stage-honesty cleanup is a tracked follow-up indocs/wiki/13-status.md, not part of this RFC's implementation.
Summary
Format spec §4.1 says the property section is required at every pipeline stage, and §5.1 lists the sections each stage requires — but no validator rule fires when a required section is absent. The only trace is stage_readiness, a block of booleans that says a stage is not ready without saying why, and that nothing downstream of overall_status ever reads. The result, first recorded when RFC 0027 was scanned: 28 in-scope corpus documents have no property section at all and still validate clean/warnings.
This RFC adds two rules. CC-14 (warning) fires when a deal-record UWX document has no property section, unconditionally on stage — the narrow rule the RFC 0027 spin-off note asked for. DQ-06 (info) names, for the declared deal_stage, each required section that is absent — the issues-stream mirror of stage_readiness, sibling to the field-level DQ-04. It also corrects §5.1's drift from the shipped validator: the table predates the v1.1 scope stage and disagrees with STAGE_REQUIREMENTS in three places.
The severities are set by a fresh corpus scan (Appendix A), and the scan is why neither rule is an error: 68 of 75 staged corpus documents — including all twelve worked examples — fail their declared stage's section list, because deal_stage declarations in practice state where a deal is going, not what the file already contains.
Motivation
Three defects, one root cause: section-level completeness is computed but never reported.
A missing
propertysection is silent. §4.1: "Required for pipeline stage: All stages." Yet 28 in-scope corpus documents omit it and validate without a single issue.CC-13(RFC 0027) deliberately does not absorb this — its applicability list states "a missing section is a different defect with a different remedy" — and the spin-off note indocs/wiki/13-status.mdqueues this RFC by name.stage_readinessis invisible in practice.computeStageReadiness(validator.ts) evaluatesSTAGE_REQUIREMENTSper stage and returns seven booleans. Nothing in the issues stream reflects them: a consumer readingissues/overall_status— which is what the CLI exit code, the web editor's remediation panel, and the new Tier-1 validation-verdict baselines all consume — sees nothing.DQ-04closed exactly this gap for scope-stage fields, and its own comment defers sectional gaps tostage_readiness; this RFC gives sections the same treatment.§5.1 has drifted from the validator. Three disagreements:
- §5.1 has no
scoperow. The stage shipped in the v1.1 train;STAGE_REQUIREMENTS.scoperequiresproperty(plus field-level checks thatDQ-04owns). - §5.1 requires
operating_statement(T-12) at Full Underwrite;STAGE_REQUIREMENTS.full_underwritedoes not list it. The validator'shasSectionstill carries a variant-aware special case foroperating_statementthat no stage list reaches — dead code that marks where the requirement was lost. - §5.1's Portfolio Monitoring row adds "updated
operating_statement(annual)" and "re-runvalidation"; the validator'smonitoringlist is identical toclosing. Freshness ("updated", "re-run") is not expressible as section presence at all.
- §5.1 has no
Proposed change
1. CC-14 — the property section must exist (warning)
New row in §5.3:
| Check ID | Description | Sections |
|---|---|---|
CC-14 | A deal-record document must have a property section (§4.1) (RFC 0028) | property |
Normative language, mirroring CC-13's structure:
CC-14severity and applicability.CC-14is a warning, never an error: the scan in RFC 0028 Appendix A found 28 corpus documents that a refusal would invalidate retroactively, and an institution wanting a hard gate expresses it throughINCOMPLETE_DATA_POLICIES. The rule fires only when all of the following hold:
- The source is a UWX record, not a UW Lite summary.
- The document's profile is a deal record (market-data and other non-deal profiles have no property section by construction).
- The
propertysection is not externalized (RFC 0021); an externalized-but-unresolved section is present, not missing.
CC-14is unconditional ondeal_stage— §4.1 requires the section at every stage, and every scope-stage corpus document already satisfies it. WhenCC-14fires,CC-13must not also fire (its precondition 4 already ensures this): one defect, one diagnostic.
2. DQ-06 — declared-stage section readiness (info)
For a document declaring deal_stage: S, each section in STAGE_REQUIREMENTS[S].required_sections that is absent produces one info-severity issue naming the section:
DQ-06: full_underwrite requires noi_model; section is missing.
- Info, not warning: the Appendix A scan shows the corpus treats
deal_stageas aspiration (all twelve worked examples fail their declared stage's list), so any nagging severity would either drown real warnings or pressure authors into boilerplate sections. Info makesstage_readinesslegible without changingoverall_status. DQ-06suppresses thepropertyentry whenCC-14fires — the warning already names it, and one defect gets one diagnostic.- Documents with no
deal_stageproduce noDQ-06(there is no claim to check). This is the same posture asDQ-04. - Escalation is deliberately out of scope: an institution that wants stage-readiness as a gate expresses it through
INCOMPLETE_DATA_POLICIESor a module validation, and a future RFC can revisit once the corpus's own stage declarations are honest (see Unresolved questions).
3. §5.1 alignment (errata-grade, but bundled here for one review)
- Add a Scope row:
property(field-level requirements are §III.6a /DQ-04territory). - Annotate the Full Underwrite row:
operating_statement(T-12) remains the documented institutional expectation, but the machine-checked list (STAGE_REQUIREMENTS) is normative forDQ-06, and it does not includeoperating_statementtoday. Decision requested from review: either (a) addoperating_statementtoSTAGE_REQUIREMENTS.full_underwrite(the validator's variant-awarehasSectionis already built for it), or (b) strike it from §5.1. The author leans (a) — the dead code is evidence it was meant to be checked. Appendix A quantifies the blast radius of (a): it adds one missing-section entry to 47full_underwritedocuments'DQ-06output and changes no verdict, becauseDQ-06is info. - Rewrite the Monitoring row to separate presence (checkable: the
closinglist) from freshness ("updated", "re-run" — not expressible as section presence; belongs toDQ-05staleness machinery and is out of scope here).
Library changes (@uwmd/core, additive)
validator.ts: emitCC-14andDQ-06per the rules above; export nothing new (both ride the existingValidationResult).protocol.ts: twoBUILTIN_REMEDIATIONSentries (CC-14warning,DQ-06info) withspec_refs.- If review chooses (a) for
operating_statement: one line inSTAGE_REQUIREMENTS.full_underwrite, which also revives the deadhasSectionspecial case.
Compatibility analysis
- Existing
.uw.md/.uwx.mdfiles: none become invalid.CC-14is a warning;DQ-06is info; neither changesoverall_statusbeyondclean → warningsfor the 28 property-less documents — the same class of transition RFC 0027 shipped withCC-13. - Tier-1 Readers: must surface the new codes (same obligation as any §5.3 row). The Tier-1 validation-verdict baselines (added 2026-08-25) will show the new codes as explicit diffs — that is the mechanism working as designed, not a break.
- Tier-2/3/4: untouched; no edit, calc, or agent behavior changes.
- Modules: no manifest change. Module-declared validations keep their namespace.
- Receipts / Excel / composition: untouched — no number moves anywhere.
Conformance impact
- Baselines that change (expected, mechanical): any suite that runs
validateUWFileover a fixture missingpropertyor stage-required sections gains warning/info entries. Concretely: the three Tier-1 validation baselines (01-minimal-screeningand02-full-multifamilygainDQ-06entries;04-scope-onlygains none — scope requires onlyproperty, which it has), and Tier-1malformedexpectations are subset-matched, so they absorb the new codes without edits. - New fixtures: a
CC-14positive (deal record, no property section, must warn — and must not also emitCC-13); aCC-14non-fire for a market-data profile document; aDQ-06positive naming exactly the missing sections for a declared stage; aDQ-06non-fire for a document with nodeal_stage; an externalized-property document whereCC-14stays silent (precondition 3).
Reference implementation
- Files affected:
packages/uwmd-core/src/validator.ts,packages/uwmd-core/src/protocol.ts,validator.cc.test.ts/validator.dq.test.ts, spec §5.1/§5.3, conformance fixtures above. - API surface: no new exports.
- Test plan: unit tests for each precondition of
CC-14(Lite source, non-deal profile, externalized section, present section), theCC-14/CC-13mutual-exclusion,DQ-06per-stage output including the property suppression, and no-stage silence. Conformance as above.
Implementation follows acceptance as a separate PR (the RFC 0027 pattern: spec, core, conformance can land together — the change is small).
Alternatives considered
- Error severity for
CC-14. Refuses 28 corpus documents retroactively and breaks several conformance scenarios whose expected verdicts assumewarningsat worst. RFC 0027 already litigated this exact question forCC-13and the same answer holds: the applicability preconditions do the discriminating work, and hard gates are institution policy. - Warning severity for
DQ-06. Fires on all twelve worked examples (Appendix A) — the project would be shipping examples that warn, which either normalizes warnings or pressures the examples into stub sections authored to silence a validator. Info reports the same facts without either failure mode. - Fold both into one code. One diagnostic would then need to carry two severities and two remedies ("add a property section" vs "your stage claim overstates the file"). The registry's design is one code, one remedy.
- Fix
stage_readinessconsumers instead (e.g. have the CLI print the readiness block). Doesn't help any consumer ofValidationMessage[]— the web editor's remediation panel, the conformance baselines, module hosts — and leaves the data outside the one stream the protocol says tools must surface. - Do nothing. The status quo the status doc already flags; the 28 silent documents are the argument against it.
Unresolved questions
- Example stage-honesty. All twelve worked examples declare
full_underwriteand none satisfies its section list (most missvalidation,borrower_sponsor,preliminary_sizing,market_analysis). AfterDQ-06lands, the follow-up work item is to either add those sections to the examples or restage them — tracked outside this RFC. Only once the examples are honest can a future RFC reconsiderDQ-06's severity. operating_statementat Full Underwrite — decision (a)/(b) requested from review, see Proposed change §3.- Monitoring freshness ("updated annually", "re-run") — expressible via
DQ-05-style staleness, not section presence; deferred.
Prior art
- RFC 0027 Appendix A established the scan-before-severity method this RFC reuses, and its acceptance note is where this RFC was queued.
- JSON Schema's
requiredkeyword reports each missing property as its own instance-path error — the per-section granularityDQ-06adopts. - CommonMark's spec tests distinguish "must parse" from "should warn" surfaces; UW Markdown's
errors/warnings/infotriage is the same split, and this RFC keeps advisory facts out of the refusal channel.
Appendix A — corpus scan (2026-08-26)
Method: parse every tracked examples/**/*.uwx.md and structured conformance/**/*.uw{,x}.md, keep documents with a deal_stage, and diff their sections against STAGE_REQUIREMENTS[stage].required_sections (the shipped validator tables, all seven stages).
- 75 staged documents. By stage: 47
full_underwrite, 16screening, 7scope, 5credit_approval. - 68 (91%) fail their declared stage's section list — 47
full_underwrite, 16screening, 5credit_approval. All 7scopedocuments pass: where the stage claim is modest, the file meets it. - 28 documents have no
propertysection. Zero are worked examples — all are conformance fixtures (tier-3 calc-hostdeal.uw.mdfiles, the mixed-usemalformed/set, three capital-stack scenarios) whosedeal_stage: full_underwriteis boilerplate, exactly as the RFC 0027 scan characterized it. - All 12 worked examples fail
full_underwritereadiness. The modal gap isvalidation+borrower_sponsor+preliminary_sizing+market_analysis;Parkview-Apts-Glendale-AZandparkview-after-L6miss onlypreliminary_sizing. - Consequence for severities: an error
CC-14refuses 28 files; a warningDQ-06puts every shipped example inwarnings. The proposal's warning/info split is the only assignment under which no example's verdict changes and no fixture is refused, while every silent gap becomes a named issue.