BS 0:2006 meeting minutes — statements, declarations, and actual times
BS 0:2006 is the British Standard formally titled A standard for standards. It is the meta-standard that governs how BSI technical committees operate — and §7.6 specifies the structure of committee meeting minutes.
Two concepts from §7.6 are universal across standards bodies but rarely modelled natively: statements (who said what, and in what capacity) and declarations (conflicts of interest and IPR positions). Edoxen 1.0 promotes both to first-class core entities, because ISO, IEC, BIPM, IETF, and every other body needs the same tracking.
Why BS 0:2006?
Every standards body has a notion of “what was said at the meeting” and “who declared a conflict.” Until now, Edoxen modelled the outcomes (decisions, resolutions) and the procedure (motions, votings), but not the discourse — the individual statements members make during debate, or the formal declarations of interest that precede participation.
BS 0:2006 §7.6 is the most precise published treatment of these concepts. It distinguishes:
- Statements — general remarks, comments, and standpoints (a member’s position on the topic).
- Declarations — conflicts of interest and IPR positions (patents, copyright claims) that members must disclose before participating.
The same distinction exists in ISO, IEC, IETF, and every parliamentary body. By deriving the model from BS 0, we get a published standard as the provenance — not an invented taxonomy.
What’s new in the model
Three new core entities
Statement — one remark by one or more members on a topic or minutes
section. The kind discriminator separates three types:
statement— a general remark.comment— a sub-type (typically shorter, often procedural).standpoint— a member’s position on the topic.
Declaration — a formal declaration by one or more members. Two kinds:
conflict_of_interest— a member declares a conflict on a target (typically a Topic or TopicDocument).ipr— a member declares an IPR position on a target (a published standard or work in progress). Carries typedEntityRefslots foripr_subject_ref(the IPR item, e.g. a specific patent) andipr_target_ref(the standard it applies to).
DateTimeRange — a start + end pair with sub-day precision. Parallel
to DateRange (day granularity); the two are intentionally separate
types so the precision is visible at the type level.
Extended models
- Meeting —
dateRangerenamedscheduledDateRange; newoccurredDateRange: DateTimeRange; newdeclarations: Declaration[]. - Topic — new
statements[](standing position that travels with the topic) +declarations[](standing declarations). - MinutesSection — new
statements[](per-meeting: what was said this time) +topic_ref(URN back-link to the Topic).
Every translatable field is per-field LocalizedString[] per ISO 24229.
IPR subject/target use typed EntityRef — cross-references that the
schema validates.
When to use these concepts
| If your domain tracks… | Use |
|---|---|
| Who said what during a meeting | MinutesSection.statements[] |
| A committee’s long-held position on a subject | Topic.statements[] with kind: standpoint |
| Conflicts of interest | Meeting.declarations[] with kind: conflict_of_interest |
| IPR positions (patents, copyright) | Meeting.declarations[] with kind: ipr + ipr_subject_ref / ipr_target_ref |
| Actual meeting times (not just scheduled dates) | Meeting.occurredDateRange |
The scheduled-vs-occurred distinction matters more than it sounds. A meeting scheduled for a full day but actually ran 09:00–11:30 has different reporting implications — attendance thresholds, quorum calculations, venue costs — and the model now captures both.
A bilingual example
This is the bs0-sample.yaml fixture — a BSI TC/1 sitting with
bilingual statements, both declaration kinds, and scheduled-vs-occurred
times:
identifier:
- prefix: BSI
number: "TC/1/2026/03"
urn: urn:edoxen:meeting:bsi:tc1-2026-03
type: committee
status: completed
scheduled_date_range:
start: 2026-03-12
end: 2026-03-12
occurred_date_range:
start: 2026-03-12T09:00:00+00:00
end: 2026-03-12T11:45:00+00:00
declarations:
- kind: conflict_of_interest
description:
- spelling: eng
value: Mr Smith declares a conflict of interest on agenda item 5.2.
- spelling: fra
value: M. Smith déclare un conflit d'intérêts sur le point 5.2.
party:
- name:
- spelling: eng
value:
formatted: Mr John Smith
- kind: ipr
description:
- spelling: eng
value: Ms Doe declares a patent on the technology described in clause 7.
party:
- name:
- spelling: eng
value:
formatted: Ms Jane Doe
ipr_subject_ref:
urn: urn:edoxen:ipr-subject:iso-patent-policy:2024
ipr_target_ref:
identifier:
prefix: ISO
number: "8601-1:2019"
minutes:
- identifier:
- prefix: BSI
number: "TC/1/2026/03/min"
spelling: eng
sections:
- number: "5.2"
title:
- spelling: eng
value: Patent clause discussion
narrative:
- spelling: eng
value: |
The committee discussed the patent clause in detail.
statements:
- kind: standpoint
description:
- spelling: eng
value: Ms Doe supports the clause as drafted.
party:
- name:
- spelling: eng
value:
formatted: Ms Jane Doe
- kind: comment
description:
- spelling: eng
value: Mr Smith requested his dissent be recorded.
party:
- name:
- spelling: eng
value:
formatted: Mr John Smith
topic_ref: urn:edoxen:topic:bsi:tc1-patent-clause
How to use the API
Ruby (gem)
require 'edoxen'
collection = Edoxen::MeetingCollection.from_yaml(File.read('meeting.yaml'))
meeting = collection.meetings.first
# Scheduled vs occurred times
scheduled = meeting.scheduled_date_range # DateRange (day precision)
occurred = meeting.occurred_date_range # DateTimeRange (sub-day)
# Declarations on the meeting
meeting.declarations.each do |decl|
kind = decl.kind # "conflict_of_interest" or "ipr"
desc = decl.description.find { |l| l.spelling == "eng" }&.value
puts "[#{kind}] #{desc}"
if decl.kind == "ipr"
puts " subject: #{decl.ipr_subject_ref.urn}"
puts " target: #{decl.ipr_target_ref.identifier.first.number}"
end
end
# Statements in a minutes section
meeting.minutes.first.sections.each do |section|
section.statements.each do |stmt|
kind = stmt.kind # "statement", "comment", or "standpoint"
text = stmt.description.find { |l| l.spelling == "eng" }&.value
who = stmt.party.map { |p| p.name.first.value.formatted }.join(", ")
puts " [#{kind}] #{who}: #{text}"
end
end
TypeScript / JavaScript (@edoxen/edoxen)
import { validateMeetings } from '@edoxen/edoxen'
import yaml from 'js-yaml'
import fs from 'node:fs'
const doc = yaml.load(fs.readFileSync('meeting.yaml', 'utf-8'))
const result = await validateMeetings(doc)
if (result.valid) {
const meeting = doc.meetings[0]
console.log('scheduled:', meeting.scheduled_date_range)
console.log('occurred:', meeting.occurred_date_range)
for (const decl of meeting.declarations ?? []) {
console.log(`[${decl.kind}]`, decl.description[0]?.value)
if (decl.kind === 'ipr') {
console.log(' subject:', decl.ipr_subject_ref?.urn)
console.log(' target:', decl.ipr_target_ref?.identifier?.[0]?.number)
}
}
for (const section of meeting.minutes?.[0]?.sections ?? []) {
for (const stmt of section.statements ?? []) {
const who = stmt.party?.map(p => p.name?.[0]?.value?.formatted).join(', ')
console.log(` [${stmt.kind}] ${who}: ${stmt.description?.[0]?.value}`)
}
}
}
OCP: extending the kinds
The StatementKind and DeclarationKind enums are designed for
extension. If your domain has a statement or declaration type not in
the standard set, you extend the enum (or use other + an extension
profile) — the Statement / Declaration models themselves never
need to change. This is the Open/Closed Principle at work: the flat
class + kind discriminator pattern means new domain concepts are a
config change, not a model rewrite.
Try it
gem install edoxen
edoxen validate-meetings meetings/*.yaml
Or read the BS 0:2006 Minutes docs page, walk the
architecture, or browse the
samples
(bs0-sample.yaml is the bilingual fixture shown above).