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:

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:

Declaration — a formal declaration by one or more members. Two kinds:

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

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).