Commenter 0.3–0.6: ISO Comments From Anywhere — and the Complete Ballot Workflow
#Commenter 0.3–0.6: ISO comments from anywhere — and the complete ballot workflow
ISO comment handling has always been a battle against formats: balloting templates arrive as DOCX, ISO Online Standards Development (OSD) exports arrive as XLSX, and ISO/CS editors return redlined documents full of tracked changes. This work was done for the ISO 2533 publication: at the FDIS stage we needed to distribute the changes the ISO/CS editors had made to the document, together with their disposition, to everyone following the ballot — in the same comment-sheet form as every other response.
The commenter gem (releases 0.3.0 through 0.6.0) now does both halves: it reads every format into one structured, schema-validated YAML — and it carries that YAML through the entire ballot lifecycle. One file, from intake to the final disposition document.
gem install commenter#Import from ISO OSD XLSX exports
OSD comment exports come in two shapes, and commenter auto-detects both from the header row: the "resolved" export with resolution data (Resolution status, Motivation, Resolution date, Stage code) and the comments-only export with discussion replies.
# ISO OSD resolved comment export
commenter import "91855-Comments-resolved.xlsx" -o comments.yaml
# ISO OSD comments-only export
commenter import "ISO 5843-6-Comments.xlsx" -o comments.yamlSheet metadata is extracted automatically — the document reference (ISO/DIS 5843-6(en)), the ballot stage, the project number, and the English/French document titles. Resolution status and motivation are combined into the observations field, ready for comment-sheet assembly. Multi-sheet workbooks are supported: pick the sheet by name, or use --resolved-only / --unresolved-only.
#Import redline DOCX with tracked changes
ISO/CS editors often answer a ballot not with a comment sheet but with a redline — a Word document full of tracked changes. That is exactly what happened with ISO 2533: for the FDIS stage we wanted to distribute the changes the ISO/CS editors made to the document along with their disposition, which meant turning a redline into a comment sheet. commenter now does that:
commenter import "ISO_DIS 2533 Enquiry Trackchange Word.docx" --format redline \
--body CS --document "ISO 2533:2026" --stage DIS \
--observations "Accepted. ISO/CS tracked change accepted." \
-o comments-cs.yamlEach tracked change (w:ins, w:del, w:moveFrom, w:moveTo) becomes a comment whose proposed_change renders the change itself — Insert: "...", Delete: "...", Move ...: "..." — and whose clause is resolved from the nearest preceding heading, including sub-clauses such as 4.2.1 and annexes such as Annex A. Reviewer comment threads in the redline become comment entries too. Redlines can be enormous, so the parser streams word/document.xml with a SAX-style reader instead of loading a full DOM — 100 MB redlines import without issue.
#Collate the ballot: merge member-body sheets
A secretariat receives one comment file per member body per ballot — mixed DOCX templates, OSD XLSX exports, and late redlines that arrive by email. ISO's own Comment Collation Tool gives up on non-conforming formatting, so merging happens by hand. Now:
commenter merge de.yaml us.yaml jp.yaml cs-redline.yaml -o ballot.yamlMetadata comes from the first sheet that provides each field, identical duplicates are dropped, and a comment ID carrying different content in two files stops the merge loudly instead of silently losing someone's comment.
#Resolve on GitHub: from create-once to a true sync
For teams that review comments as GitHub issues, commenter closes the loop.
commenter github-createcreates one issue per comment using customizable Liquid templates, and records issue numbers and URLs back into the YAML.commenter github-synctreats the YAML as the source of truth and reconciles the issues with it: missing issues are created, issue content is refreshed from the YAML under a configurable conflict policy (--conflict yaml,github, orskip— because which side wins is situational), and an open issue whose comment has a recorded disposition is closed.commenter github-retrievepulls official observations back out of closed issues — written as>OBSERVATION:blockquotes — and updates the YAML in place.
Duplicate detection is stage-aware: the same comment ID (GB-001) appears at every ballot stage, so the default unique ID renders as [DIS] GB-001 — CD and DIS comments of the same number become separate issues rather than being skipped as duplicates. Closing dispositioned issues is exactly what keeps the observation round-trip working.
#Report: statistics and stage comparison
Ballot reports need disposition counts, and until now every standards body we looked at — OASIS resolution logs, W3C disposition-of-comments documents, ISO ballot summaries — counted them by hand. The data is already in the YAML:
commenter stats ballot.yamlAnd because the same comment ID reappears at every ballot stage, comparing two stages answers the working group's standing question — what happened between CD and DIS:
commenter diff cd-ballot.yaml dis-ballot.yamlNew, withdrawn, repeated, revised, and resolved counts, as a Markdown table that pastes straight into WG minutes.
#The final deliverable: fill and export
The ballot's last step used to be two commands and a manual header. Now:
commenter export ballot.yaml --config github_config.yaml -o disposition.docx --shadingClosed-issue observations are retrieved, the template is filled, the sheet's Date/Document/Project metadata are written into the page header, and disposition cells get status-based shading (accepted, accepted-with-modifications, noted, rejected). commenter fill remains available for filling without the GitHub step.
#Schema-validated YAML
Every import writes YAML with a matching JSON-Schema-style schema (schema/isocomment2012-03.yaml or schema/isocommentosd.yaml), stamped into the file header for editor support. Short type codes (ge/te/ed) are normalized to full names on load, and the schema reference survives every round-trip — reload your output and you get identical YAML.
#Under the hood
The data model serializes through lutaml-model — the same foundation Metanorma uses elsewhere — with typed nested models for comment locality and GitHub tracking state. The disposition vocabulary lives in one matcher shared by cell shading and ballot statistics, so "what counts as accepted" has one answer everywhere. The test suite has grown from 38 to 122 examples — with runtime-generated XLSX and DOCX fixtures instead of binary files — and CI is green across Ruby 3.2–4.0 on macOS, Linux, and Windows.
#Get involved
Comments, bug reports, and pull requests are welcome at github.com/metanorma/commenter. If you receive ISO comments in a format commenter does not yet understand, open an issue with a (sanitized) sample — format coverage grows one real-world document at a time.