Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,19 @@ documents them, it does not own them. Canonical definitions live in

### Top-level containers

The model has four top-level container roots, used depending on what
The model has five top-level container roots, used depending on what
you want to capture:

- **MeetingCollection** — meeting-grain. Holds meetings with agendas,
components, officers, deadlines, and the decisions each meeting
adopted.
- **DecisionCollection** — decision-grain. Holds the decisions
themselves with their admin fields and per-language renderings.
- **ContactCollection** (1.0) — registry of Contacts indexed by scoped
- **ContactRegister** (1.0) — registry of Contacts indexed by scoped
URN. Referenced from Meetings, Components, HostRefs via `ref:`.
- **VenueCollection** (1.0) — registry of Venues indexed by scoped URN.
- **VenueRegister** (1.0) — registry of Venues indexed by scoped URN.
- **BodyRegister** (1.0) — registry of Bodies (committees, working
groups); members matched by `code` or `ref`.

### Decision-grain entities

Expand Down Expand Up @@ -121,9 +123,12 @@ URN format: `urn:edoxen:{entity}:{scope}:{local-id}`.
- `scope`: the dataset/registry name (e.g. `isotc154`, `oiml`).
- `local-id`: local identifier within that scope.

Any entity-typed field accepts either **inline data** (full object) or
**a URN reference** (`{ ref: urn:edoxen:contact:... }`). Both patterns
are valid; the discriminator is presence of `ref`.
Any entity-typed field accepts **inline data** (full object), a
**document-scoped reference** (`{ local_ref: ... }` resolved against the
containing document's scoped collection), or **a URN reference**
(`{ ref: urn:edoxen:contact:... }` resolved against the matching
top-level Register). The discriminator is presence of `ref` /
`local_ref`.

## Site-level presentation terms

Expand Down
22 changes: 21 additions & 1 deletion docs/agenda.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ agenda:

| Field | Type | Description |
|---|---|---|
| `urn` | `String` | First-class URN, hierarchical under the parent meeting URN (`{meetingUrn}:agenda:{label}`). Optional in source data — computable via `Edoxen::UrnFor.agenda_item` (see below). |
| `label` | `String` | The printed number (`"4.2"`, `"10.a"`). May be empty for headers. |
| `kind` | `AgendaItemKind` | One of `numbered`, `unnumbered`, `header`, `opening`, `closing`. |
| `title` | `String` | Short title as printed. |
| `description` | `String` | Optional body / context. |
| `references` | `Reference[0..*]` | Supporting documents (background papers, prior resolutions). |
| `outcome` | `AgendaItemOutcome` | What happened with this item. |
| `resolution_ref` | `String` | If the item produced a resolution, its identifier. |
| `decision_ref` | `String` | URN of the decision this item produced, if any. |
| `topics` | `Topic[0..*]` | The subject(s) of discussion at this item. |
| `components` | `String[0..*]` | MeetingComponent identifiers covering this item. |

### AgendaItemKind

Expand Down Expand Up @@ -83,6 +86,23 @@ Captures what the meeting did with this item. The enum is
- `adopted` — meeting adopted the proposal as presented
- `withdrawn` — proponent withdrew the item

### AgendaItem URNs

An item's `urn` is derived from the parent meeting URN plus the item
label — `{meetingUrn}:agenda:{label}`. It is optional in source data;
the gem computes it on demand and can backfill a whole agenda:

```ruby
Edoxen::UrnFor.agenda_item(meeting_urn: "urn:oiml:ciml:meeting:ciml-60", label: "6.2")
# => "urn:oiml:ciml:meeting:ciml-60:agenda:6.2"

Edoxen::UrnFor.parse("urn:oiml:ciml:meeting:ciml-60:agenda:6.2")
# => { meeting_urn: "urn:oiml:ciml:meeting:ciml-60", label: "6.2" }

Edoxen::UrnFor.assign_to_agenda!(meeting.agenda, meeting.urn)
# sets urn on every item that doesn't already carry one
```

## References

`Reference` is a small lightweight citation attached to agenda items.
Expand Down
72 changes: 72 additions & 0 deletions docs/body-register.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Body Register
---

# BodyRegister

The authoritative register of [Bodies](/docs/body) — committees,
subcommittees, and working groups. Parallel to
[ContactRegister](/docs/contact-register) and
[VenueRegister](/docs/venue-register).

Other documents (Meeting, MeetingCollection) reference bodies via
`ref: urn:edoxen:body:{scope}:{local-id}` and resolve against the
matching BodyRegister.

```yaml
scope: oiml
title:
- spelling: eng
value: OIML Bodies
bodies:
- code: CIML
kind: committee
name:
- spelling: eng
value: International Committee of Legal Metrology
- spelling: fra
value: Comité international de métrologie légale
- code: TC18
kind: technical_committee
name:
- spelling: eng
value: 'TC 18 Instruments of measurement'
parent_ref:
urn: urn:edoxen:body:oiml:ciml
```

## Fields

| Field | Type | Description |
|---|---|---|
| `scope` | `String` | Registry scope (matches the scope segment in referencing URNs). |
| `title` | `LocalizedString[0..*]` | Display title (localized). |
| `bodies` | `Body[0..*]` | Registry members. |
| `extensions` | `MeetingExtension[0..*]` | Profile-specific extensions. |

## Lookup: matched by `code` or `ref`

Body has **no `urn` attribute** — a difference from Contact and Venue,
whose register members carry `urn`. `BodyRegister#find_by_urn` therefore
matches the requested value against a member's `code` **or** `ref`:

```ruby
register = Edoxen::BodyRegister.from_yaml(File.read("bodies.yaml"))

register.find_by_urn("CIML")
# => #<Edoxen::Body code="CIML" ...> (matched on code)

register.find_by_urn("urn:edoxen:body:oiml:ciml")
# => matches a member whose ref is that URN
```

In practice, members are keyed by their short `code`; a member whose
canonical identity is a full URN carries it in `ref`.

## See also

- [Body](/docs/body) — member shape
- [Entity resolution](/docs/entity-resolution) — the three-tier pattern
- [Contact Register](/docs/contact-register) — parallel registry for Contacts
- [Venue Register](/docs/venue-register) — parallel registry for Venues
- [Localization](/docs/localization) — spelling codes
85 changes: 85 additions & 0 deletions docs/body.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Body
---

# Body

A **Body** is a committee, subcommittee, working group, or other
organised body that owns meetings and decisions. It carries a short
`code` (e.g. `ISO/TC 154`, `CIML`) and a localised full name.

Body replaces the bare `String` previously used for
`Meeting.committee` and `Meeting.committee_group` — those fields are
now typed `Body`, so a committee can carry its own localised name,
kind, and parent body instead of a label.

```yaml
# Inline — the Body carries full data
committee:
code: CIML
kind: committee
name:
- spelling: eng
value: International Committee of Legal Metrology
- spelling: fra
value: Comité international de métrologie légale
```

## Reference vs inline

Like [Contact](/docs/contact) and [Venue](/docs/venue), a Body field
follows the three-tier [entity resolution](/docs/entity-resolution)
pattern:

```yaml
# 1. Inline — full data, neither ref nor local_ref set (above)

# 2. Document-scoped — local_ref matches the code of a Body in the
# same document's bodies[] collection (e.g. Meeting#bodies)
committee: { local_ref: CIML }
bodies:
- code: CIML
name:
- spelling: eng
value: International Committee of Legal Metrology

# 3. Global register — ref resolves against a BodyRegister
committee: { ref: urn:edoxen:body:oiml:ciml }
```

The `reference?` predicate is true when `ref` **or** `local_ref` is
set; when either is set, other fields are ignored.

Unlike Contact and Venue, **Body has no `urn` attribute** — a Body is
identified by its `code` (or by a full URN carried in `ref`). See
[Body Register](/docs/body-register) for how lookups match.

## Fields

| Field | Type | Description |
|---|---|---|
| `ref` | `String` | URN reference into a [BodyRegister](/docs/body-register) (alternative to inline data). |
| `local_ref` | `String` | Document-scoped reference — matches the `code` of an entry in the document's own `bodies[]`. |
| `code` | `String` | Short code of the body (`CIML`, `ISO/TC 154`). |
| `name` | `LocalizedString[0..*]` | Localized full name. |
| `kind` | `String` | What kind of body: `committee`, `subcommittee`, `working_group`, etc. Free-form. |
| `parent_ref` | `EntityRef` | The parent body (e.g. a working group's parent committee). |
| `extensions` | `MeetingExtension[0..*]` | Profile-specific attributes. |

## Where Body is used

| Entity | Field | Context |
|---|---|---|
| `Meeting` | `committee` | Owning committee. |
| `Meeting` | `committee_group` | Sub-committee / working group. |
| `Meeting` | `bodies[]` | Document-scoped bodies for `local_ref` resolution. |
| `BodyRegister` | `bodies[]` | Registry members. |
| `Body` | `parent_ref` | Parent body (as an EntityRef). |

## See also

- [Body Register](/docs/body-register) — scoped registry of Bodies
- [Entity resolution](/docs/entity-resolution) — the three-tier pattern
- [Contact](/docs/contact) / [Venue](/docs/venue) — the parallel resolvable entities
- [EntityRef](/docs/entity-ref) — the `parent_ref` type
- [Meeting Collection](/docs/meeting-collection) — where `committee` and `bodies[]` attach
14 changes: 11 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ data files.
```sh
edoxen help
# Commands:
# edoxen help [COMMAND] # Describe available commands or one specific
# edoxen normalize YAML_FILE_PATTERN # Normalize YAML files using Edoxen schema
# edoxen validate YAML_FILE_PATTERN # Validate YAML files against Edoxen schema
# edoxen help [COMMAND] # Describe available commands or one specific
# edoxen validate YAML_FILE_PATTERN # Validate YAML files against Edoxen schema
# edoxen normalize YAML_FILE_PATTERN # Normalize YAML files using Edoxen schema
# edoxen validate-meetings YAML_FILE_PATTERN # Validate Meeting YAML files against the meeting schema
# edoxen normalize-meetings YAML_FILE_PATTERN # Normalize Meeting YAML files
```

`validate` / `normalize` cover decision-side files
(`schema/edoxen.yaml` — DecisionCollection plus the register documents:
ContactRegister, VenueRegister, BodyRegister);
`validate-meetings` / `normalize-meetings` cover meeting-side files
(`schema/meeting.yaml` — MeetingCollection, Meeting, MeetingSeries).

## validate

```sh
Expand Down
25 changes: 14 additions & 11 deletions docs/contact-collection.md → docs/contact-register.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
---
title: Contact Collection
title: Contact Register
---

# ContactCollection
# ContactRegister

A registry of [Contacts](/docs/contact) indexed by scoped URN. Members
carry `urn: urn:edoxen:contact:{scope}:{local-id}`; the collection's
carry `urn: urn:edoxen:contact:{scope}:{local-id}`; the register's
`scope` MUST match the scope segment in member URNs.

Other documents (Meeting, MeetingComponent, HostRef, etc.) reference
contacts via `ref: urn:edoxen:contact:{scope}:{local-id}` and resolve
against the matching ContactCollection.
against the matching ContactRegister. See
[Entity resolution](/docs/entity-resolution) for the full three-tier
pattern (inline / document-scoped / register).

```yaml
scope: isotc154
Expand Down Expand Up @@ -46,26 +48,27 @@ contacts:

## Storage patterns

A ContactCollection can be serialized as:
A ContactRegister can be stored as:

1. **Single YAML file** — typical for small registries (10–1000 contacts).
2. **YAML Stream** — one Contact per document, separated by `---`,
for large registries that need partial updates. Glossarist-style.

```ruby
Edoxen::ContactCollection.load_stream("contacts.stream.yaml")
```
Stream loading is a service-layer concern (file-system I/O); the model
owns only the (de)serialisation of one register.

## Ruby helpers

```ruby
collection = Edoxen::ContactCollection.from_yaml(File.read("contacts.yaml"))
collection.find_by_urn("urn:edoxen:contact:isotc154:jianfang-zhang")
register = Edoxen::ContactRegister.from_yaml(File.read("contacts.yaml"))
register.find_by_urn("urn:edoxen:contact:isotc154:jianfang-zhang")
# => #<Edoxen::Contact urn=... name=[...]>
```

## See also

- [Contact](/docs/contact) — member shape
- [VenueCollection](/docs/venue-collection) — parallel registry for Venues
- [Entity resolution](/docs/entity-resolution) — how `ref` / `local_ref` / inline resolve
- [Venue Register](/docs/venue-register) — parallel registry for Venues
- [Body Register](/docs/body-register) — parallel registry for Bodies
- [Localization](/docs/localization) — spelling codes
27 changes: 19 additions & 8 deletions docs/contact.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,31 @@ contact:

## Reference vs inline

A Contact field may be either **inline** (full data, as above) or a
**URN reference** to a Contact stored in a
[ContactCollection](/docs/contact-collection):
A Contact field follows the three-tier
[entity resolution](/docs/entity-resolution) pattern — **inline**
(full data, as above), a **document-scoped reference** (`local_ref`)
matching the `urn` of a Contact in the same document's `contacts[]`
collection (e.g. `Meeting#contacts[]`), or a **register reference**
(`ref`) to a Contact stored in a
[ContactRegister](/docs/contact-register):

```yaml
chair:
ref: urn:edoxen:contact:isotc154:anaya-muller
# Document-scoped — resolves within this file
chair: { local_ref: urn:edoxen:contact:isotc154:anaya-muller }

# Global register — resolves against a ContactRegister document
chair: { ref: urn:edoxen:contact:isotc154:anaya-muller }
```

The `ref` field discriminates. When set, other fields are ignored.
The `ref` / `local_ref` fields discriminate: `reference?` is true when
either is set, and when set, other fields are ignored.

## Fields

| Field | Type | Description |
|---|---|---|
| `ref` | `String` | URN reference (alternative to inline data). |
| `ref` | `String` | URN reference into a ContactRegister (alternative to inline data). |
| `local_ref` | `String` | Document-scoped reference — matches the `urn` of an entry in the document's own `contacts[]`. |
| `urn` | `String` | This contact's registry URN (`urn:edoxen:contact:{scope}:{id}`). |
| `name` | `LocalizedName[0..*]` | Localized structured name (see below). |
| `kind` | `String` | What kind of contact: `person`, `organisation`, `department`, `role`, etc. Free-form. |
Expand Down Expand Up @@ -125,6 +134,7 @@ for the full format.
| Entity | Field | Context |
|---|---|---|
| `Meeting` | `contact` | General contact for the meeting. |
| `Meeting` | `contacts[]` | Document-scoped contacts for `local_ref` resolution. |
| `Officer` | `person` (type: Contact/Person) | Chair, secretary, etc. |
| `Attendance` | `person` (type: Contact/Person) | Who attended. |
| `VoteRecord` | `person` (type: Contact/Person) | Who voted. |
Expand All @@ -133,7 +143,8 @@ for the full format.

## See also

- [ContactCollection](/docs/contact-collection) — scoped URN registry of Contacts
- [ContactRegister](/docs/contact-register) — scoped URN registry of Contacts
- [Entity resolution](/docs/entity-resolution) — the inline / `local_ref` / `ref` pattern
- [Localization](/docs/localization) — how per-field localization works
- [Officer](/docs/officer) — Officer.person is a Contact
- [MeetingExtension](/docs/extension) — profile-specific extensions
1 change: 1 addition & 0 deletions docs/entity-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,6 @@ fields (non-breaking). The String fields will be removed in 1.0.
## See also

- [Structured Identifier](/docs/structured-identifier) — the `{prefix, number}` type used in `identifier`
- [Entity resolution](/docs/entity-resolution) — the Contact/Venue/Body inline / `local_ref` / `ref` pattern (a different mechanism from EntityRef's own `local_ref`)
- [Motion](/docs/motion) — pilot entity for EntityRef
- [Architecture](/docs/architecture) — cross-grain pointer overview
Loading
Loading