Reporting problems and feedback
This guide is for anyone who produces or consumes UW Markdown: products that export .uwx.md records, independent implementations of the protocol, and people using the reference packages directly. It explains how to report a problem so a maintainer can reproduce it, how to keep confidential deal data out of public issues, and how to follow a report through to a fix, a release or an RFC.
Reports from adopters are requirements evidence. They inform, and can help determine, where the format and protocol go next. They do not define UWMD semantics, and no adopter, however large, sets what the standard requires. That is decided through the RFC process.
Where to report
| You have | Use |
|---|---|
| A security vulnerability, including a crafted document that hangs or crashes a parser | Email security@uwmd.org (SECURITY.md). Never a public issue. |
| A UWMD package, CLI command, tool or conformance fixture that does not do what the spec says | Bug or interoperability report |
| Two implementations that read, accept or compute the same document differently | Bug or interoperability report |
| Spec text that is unclear, contradicts a schema or itself, or is silent on a case | Spec question or ambiguity |
| Something you need to express, verify or do that has no home | Capability request |
| A ready-made normative proposal | An RFC pull request (process). Opening an issue first is fine. |
If you're unsure which form fits, pick the closest one. Triage moves a misfiled report to the right category.
What to include
The forms ask for these items. Each one exists because a maintainer can't reproduce or classify the report without it.
- Your implementation and its version. Give the product or tool that hit the problem, with a version or commit. When you vendor or pin UWMD packages, that version and the UWMD version can differ, and both matter.
- UWMD versions.
npx @uwmd/cli manifestprints the @uwmd/core version and the Protocol and Format versions it implements, and from 4.1.0 writes the@uwmd/verifyversion to stderr;npx @uwmd/cli --versionprints all four on one screen. An independent implementation exposes its own manifest under Protocol §II.6a. A document's Format version is itsuw_versionfrontmatter (uw_lite_versionfor Lite). Documents do not carry a Protocol version, so report the one your implementation runs. - Where the spec says so. Cite the section, schema property or conformance fixture that requires the behavior you expected. That citation is what separates a bug from a spec question (see Does it need an RFC?).
- A minimal reproduction. Give the smallest document, calc declaration, edit operation or plan that shows the problem, and the exact commands to run.
- Diagnostics.
uwmd validate <file> --jsonanduwmd verify <file> --jsonprint the issue codes. Codes carry a registered family prefix (Protocol §III.6a), soCF-02orCALC-XIRR-DIVERGEtells a maintainer more than the message does. For a disputed number, a receipt of the synthetic reproduction (uwmd receipt issue) records the pack, engine and protocol versions and the computed results. For a conformance disagreement, the language-agnostic runner's--manifest-outreport lists each case result (runner). - Your own tracker ID. If your team tracks upstream problems with its own ID, such as an
UPSTREAM-NNN, put it in Related links. The fix, the CHANGELOG entry and any RFC can then cite it, and both sides can find the same history.
Keeping deal data out of public issues
Issues on this repository are public and indexed, and an issue's edit history is public too. Assume anything you post can't be fully withdrawn.
Real deal data is validation evidence, not public material. A document derived from a real transaction does not belong in an issue, and it does not enter the conformance corpus. When a report leads to a new fixture, the fixture is synthetic: invented inputs that reproduce the behavior, never a private deal's amounts.
To turn a confidential document into a public reproduction:
- Find the smallest failing piece. Remove every section the problem does not need, then every field. Re-run after each cut. Most reproductions need one to three sections.
- Replace identity. Change
deal_id, property and party names, addresses, tenant names, loan numbers and file names to placeholders. - Replace amounts. Use round invented figures that still trigger the problem. If it depends on a specific value, such as a boundary date or a rounding edge, keep only that value and say why.
- Check
_metaand notes. Provenance can carry actor and agent IDs, internal user names, notes,market_data_refvalues and timestamps. Strip them or replace them with placeholders. - Check the output too. Validation messages,
valuefields, receipts and rendered output repeat document figures. Post output from the reduced document, not from the original. - Re-run on the reduced document and confirm it still reproduces before you post.
If the problem won't reproduce without confidential data, say so in the issue. Describe the structure instead: which sections and fields are present, their types and shapes, the codes emitted, and the versions. A maintainer will work with you on a synthetic reproduction. To show that later reports concern the same private input without sharing it, you can post its SHA-256 digest (sha256sum deal.uwx.md), or the subject.digest of a receipt. Don't post the receipt itself, because it contains the computed figures.
If confidential data does end up in an issue, tell a maintainer. Comment revisions can be deleted from edit history, and the owner can delete an issue.
What happens next
Every report moves through the same steps:
received → triage → reproduced and classified → decision → fix, RFC, docs or workaround → released → closedStatus is visible on the issue itself: its open or closed state, its labels, maintainer comments and the pull requests and RFCs linked in its timeline. Label changes do not send notifications, so every change of state also gets a comment that says what changed and what happens next.
| State | How it shows on the issue |
|---|---|
| Received | Open, labelled needs-triage |
| Needs information | needs-info, with a comment listing exactly what is missing. Replying with it puts the report back in triage. |
| Reproduced | reproduced, with a comment naming the commit and command used |
| Working as specified | Closed as not planned, labelled working-as-specified, with the section that requires the behavior. If the spec could be clearer, a documentation follow-up may be opened. |
| Accepted as a defect | Open, classified as bug, drift, conformance-gap or documentation |
| Needs a normative change | needs-rfc. The RFC links the issue, which stays open until the RFC is accepted, decided or rejected. |
Fixed on main | Closed as completed by the pull request that fixed it, linked in the timeline |
| Awaiting release | The closed issue keeps awaiting-release while the fix sits in a package or Protocol version that has not shipped. Documentation and site fixes go live on merge and skip this step. |
| Released | awaiting-release is removed, with a comment naming the released version and its CHANGELOG entry |
| Rejected or out of scope | Closed as not planned, labelled wontfix, adopter-specific or duplicate, with the reason |
The project has a single maintainer and makes no response-time commitment for ordinary issues. Security reports have the acknowledgement commitment in SECURITY.md.
Labels
After triage, a report carries one category label, plus needs-rfc when resolving it changes what conforming implementations must do. While needs-triage is present, the category is the one set by the form you chose.
| Label | Meaning | RFC? |
|---|---|---|
bug | The implementation departs from behavior the spec already requires. | No |
drift | Spec, schemas, protocol.ts, implementation or conformance corpus disagree with each other. | No, when the intended behavior is already established and the fix brings the inconsistent artifact back to it. Yes, when resolving it changes required behavior or needs new semantics. |
conformance-gap | The behavior is specified, but the corpus does not pin it, so a wrong implementation could still pass. | No (governance: a fixture for already-specified behavior is an ordinary PR) |
documentation | Documentation is wrong or missing. Behavior is unchanged. | No |
spec | A spec question the form set, which triage always replaces with a category. | Not decided yet |
spec-ambiguity | The text supports more than one conforming reading. | Yes, if implementations follow different readings (see below) |
enhancement | A requested capability. | Only with needs-rfc |
adopter-specific | The behavior belongs to the reporting implementation, not to UWMD. | No; usually closed |
needs-rfc | Resolving the report changes what a conforming implementation must do. | Yes |
Status labels: needs-triage, needs-info, reproduced and awaiting-release. Closing labels: working-as-specified, duplicate and wontfix.
The labels and their descriptions are defined in .github/labels.json. A workflow creates and updates them from that file when it changes on main, and npm run verify-issue-forms checks that the forms, this guide and that file agree.
Does it need an RFC?
The test comes from GOVERNANCE.md: does resolving the report change what a conforming implementation must do? Changes of that kind touch MUST/SHOULD requirements, standard fields, schemas, calc grammar, conformance expectations or breaking public API.
- No: it restores already-established behavior. Fixing an implementation bug, adding a fixture that pins existing requirements, correcting documentation, and correcting an inconsistent artifact back to behavior the normative contract already establishes all go through an ordinary pull request. Recent examples are the early-year day-count fix (Protocol §VIII.9.1 already said proleptic Gregorian) and the RFC 0066 fixtures that a fence-order reader used to pass.
- Yes: it changes the contract. That covers a new field or code, a changed severity or result, or a new calc behavior. It also covers any fix that changes what conforming implementations must do, and any fix that has to select new semantics because the existing contract is genuinely ambiguous. That includes picking one reading when conforming implementations follow different readings. Each of these gets
needs-rfc, and maintainers don't change normative artifacts until an RFC is accepted.
Drift between normative sources
The format and protocol specs, the normative JSON Schemas and the normative conformance corpus form one joint conformance contract. None of them outranks the others in general. When they disagree, that disagreement is repository drift to reconcile, not a contest one source wins by default.
Triage first establishes the behavior the contract already governs. It reads all of the normative sources together, along with the accepted RFC that introduced the behavior, its conformance fixtures, the CHANGELOG and the release records. Then:
- If that evidence establishes the intended behavior, the artifacts that disagree with it are corrected by an ordinary pull request. Which artifact is wrong depends on the case. A precedent where the spec text held the intended behavior (adopter report 003 in 2.3.0, where a schema's
requiredarray was corrected) shows only that it did in that case. - If the evidence doesn't establish it, or every way of reconciling the sources changes what some conforming implementation must do, the report gets
needs-rfc.
The report's evidence (versions, reproduction, readings, who is affected) becomes the RFC's Motivation, and the RFC links the issue.
Triage, for maintainers
Screen. If the report discloses a vulnerability, move it to the SECURITY.md process and remove the details from the issue. If it contains confidential deal data, delete the content and its revisions, and ask the reporter for a reduced reproduction.
Check completeness. If versions, a spec citation or a reproduction are missing, add
needs-infoand comment with the specific items.Reproduce on current
main. Use the reporter's versions as well when they differ. Comment with the commit and command, and addreproduced. If it doesn't reproduce, say what you ran.Classify. Keep or replace the category label so exactly one remains, and decide
needs-rfcwith the test above. Fordrift, first establish the already-governed behavior as Drift between normative sources describes, and cite the evidence in the comment. Removeneeds-triageand comment with the classification and the next step.Resolve. Link the fixing pull request with
Fixes #N. If the fix is to a package or Protocol version that has not shipped, addawaiting-releasewhen the issue closes. For a normative change, open the RFC and cite the issue and the reporter's tracker ID in its Motivation.Use a closing keyword only for the issue a change actually resolves. GitHub closes an issue when a merged PR description or a commit on the default branch contains "close", "fix" or "resolve" (in any form) followed by
#N. It ignores the words around them. "This PR does not resolve #255" closed #255 on merge. To mention an issue a change does not resolve, write "see #N", "related: #N" or "part of #N". If an issue closes by mistake, reopen it with a comment explaining why, and keep its labels.Close the loop at release. When a release ships, search
is:issue is:closed label:awaiting-release. Comment on each with the version and its CHANGELOG entry, then remove the label.
Why there is no machine-readable report format
UWMD does not define a feedback or bug-report envelope, and it doesn't need one yet. A report's reader is a maintainer, not another implementation, so there is no interoperability contract to standardize. The facts a report needs already exist as normative, machine-readable outputs: the implementation manifest, validation results with registered codes, ProtocolError, receipts with input and result digests, and the conformance runner's report. The forms ask for exactly those outputs. The evaluation behind this decision, and the evidence that would reopen it, is recorded in the adopter feedback review.