OpenEik.org

Draft OpenEik 0.4.0: draft, not final. From commit 9077aa6c of 1 November 2026. Errata: the errata of 0.4. Raw text: /spec/0.4/drawings.md. Earlier: OpenEik 0.1, OpenEik 0.2, OpenEik 0.3, kept as they were.

On this page

OpenEik 0.4 specification

Part XIV. Drawings

This part is a part of OpenEik 0.2, by the steward's decisions of 15 October 2026 that sheets and issued drawings join OpenEik in 0.2, and of 16 October 2026 that it be written then, as Part XIII was. It binds every conformance class it names, its own two among them, the drawing validator and the drawing issuer (section 19; Conformance). OpenEik 0.1 had it as a proposal, which no class of 0.1 required: a reader of 0.1 keeps the files of this part as section 1.5 says file by file, sheets as the application records they are in 0.1 (Part II, 9.1), the part's other files as kept files (Part III, 7) where they are UTF-8 text of at most 1 MiB, leaving larger or binary files alone and never removing them (Part III, 7, rule 2), and the new members of detail items as unknown members (Part I, 10, rule 1). A reader of 0.2 reads a model of 0.1 by 0.1's rules (Part I, 9.6, rule 3). @openeik/tools applies this part to every model of 0.2, and to a model of 0.1 when asked (proposals: ["drawings"], openeik check --proposal drawings); it works out freshness and verifies sign-offs with openeik drawing verify, status, impact, diff and register (17.3).

1. Status and scope

This part states how a model's drawings are issued and checked. A sheet is a record: its paper, the views placed on it and its title-block fields. A drawing issued from it is a snapshot in a restricted SVG, whose lines derived from the model name the elements that drew them, kept in the folder with a record of what it was drawn from and of every record it read. So a change to the model shows, by hashes and without drawing anything, which issued drawings it makes stale. Around the issued drawings are the project's own codes, a register of every revision, the issues that send them, the reviews that answer them and the sign-offs that approve them.

This part follows the steward's decision of 15 October 2026, which approved the ten decisions of the drawings plan, D1 to D10, with two refinements: signing is optional and scales with the stage, and clouds are chosen for each update. This part cites those decisions by number:

  • D1 sheets and issued drawings join the standard;
  • D2 the current issued revision is kept in the model's folder;
  • D3 OpenEik defines neutral states, and the project its own codes;
  • D4 a sign-off is one statement, signed at one of two strengths: an everyday signature, or a legal one;
  • D5 drawings are the headline of 0.2;
  • D6 a PDF/A-3 rendition at every issue;
  • D7 the AI rule: agents propose, and a person accepts;
  • D8 outside drawings are in the same register;
  • D9 the words of section 1.3;
  • D10 the roadmap says so now.

Status. The rules of this part bind every implementation of 0.2 of a class they name (section 19). They are numbered, and cited as XIV.<section>.<rule>: XIV.6.12.3 is section 6.12, rule 3. A validator reports a breach of a MUST as an error and a breach of a SHOULD as a warning (section 19). The part's schemas are among those of 0.2 (schemas/0.2/drawings/, the SVG profile's allowlist among them, and project/person.schema.json), and its conformance cases in the suite of 0.2.

1.1 What this part covers

  • sheets as standard records: paper, viewports and title-block fields (section 2; D1);
  • annotations: the references of detail items declared as references, with provenance and anchors, and the AI rule (section 3; D7);
  • the project's drawing profile: its codes mapped onto OpenEik's neutral states (section 4; D3);
  • people and keys: the registry that names everyone this part names, with the keys of those who sign (section 5);
  • the issued drawing: a restricted SVG, "OpenEik drawing SVG 0.1", whose derived lines name their elements (section 6);
  • issued files and where they live: drawings/issued/<drawing>/, kept in the model's folder as a deliberate exception to "derived data is never stored" (section 7; D2);
  • the revision record, the read set and the exact freshness rule (sections 8 and 9);
  • change items and revision clouds, chosen for each update (section 10);
  • the register, issues (transmittals), reviews and sign-offs (sections 11 to 14; D4, D8, D9);
  • the PDF/A-3 rendition (section 15; D6);
  • what is derived and never stored (section 16).

1.2 What it leaves out

  • Title-block graphics: the frame, the logo and the layout of the block are the application's (D1); the fields are data (2.3).
  • Drawing style: line weights, hatch patterns, lettering and symbols are the application's or its profile's (ISO 128 and ISO 3098 are defaults an application may claim). This part fixes only what makes a drawing safe, exact, traceable and reproducible.
  • How a generator draws: the hidden-line method is the generator's. This part asks only that output is deterministic, that derived lines name their elements and that the read set is complete.
  • National code lists: status, purpose and decision codes are the project's, in its drawing profile, as plain values (Part II, 8, rules 3 and 4; D3). OpenEik lists none.
  • What a host does: viewers, comparison views, notifications, delivery and read receipts, seen ticks, the page that answers a printed code. A host keeps those; this part's files never depend on them (7.2).
  • Raster images in views, but the picture of a 3D view (6.3); DWG and DXF renditions; and IFC drawings.
  • Legal acceptance of a signed drawing: whether a signature binds in law is not this part's to answer.

1.3 Words

This part uses these words in a sense of its own. A later version may move them into Terminology and references.

WordMeaning
viewthe recipe for one drawing region (Part II, 10): a record since 0.1
sheeta paper: its size, its viewports and its title-block fields; a standard record from this part on
drawinga numbered document, one sheet in this part, whose number is stable across revisions
revisionone issued state of a drawing: its SVG, its records and its sign-offs. Immutable. Identified by its sequence; shown by its revision code
snapshota revision as written: taken deliberately, as a draft, a shared sketch or an issue, and never changed
issuea release of revisions to recipients for a purpose: a transmittal. A BCF item is a topic, as BCF calls it
derivationwhat a revision was drawn from: the version, the sheet and views, the generator and its fonts, the read set by hash
read setevery record a revision's drawing read, with its hash, and the elements its views' volumes held
stalea revision whose read set no longer matches the line of work it tracks, or into one of whose views an element entered
drawing profilethe project's drawing conventions, drawings/profile.json: codes, revision series, cloud rules, required sign-offs, fonts. It is not a profile of Part II, 8, nor the SVG profile
SVG profileOpenEik drawing SVG 0.1: the subset of SVG an issued drawing is written in (section 6)
orphanan annotation whose anchors no longer resolve: drawn, listed, never dropped
candidatea drawing drawn again for a check, from a later version or a proposal: never stored
unlinked drawingan outside drawing, such as a consultant's PDF, registered and issued like any other, never source-mapped
drawing filea JSON file of this part that is not a record: revision records, read sets, registers, issues, reviews, sign-offs, the drawing profile

1.4 Where its files live

FilePathKindSection
a sheetdrawings/<discipline>/sheets/<id>.jsonrecord (list sheets; drawings/sheets/<id>.json in 0.1's layout)2
the provenance and anchors of detail itemsin the view's chunks, drawings/<discipline>/views/<kind>/<id>/details/<n>.jsonmembers of records3
the drawing profiledrawings/profile.jsondrawing file4
a person or an agent, with its keysproject/people/<id>.jsonrecord (list people)5
the current issued drawingdrawings/issued/<drawing>/drawing.svgissued file6, 7
its revision recorddrawings/issued/<drawing>/revision.jsondrawing file8
its read setdrawings/issued/<drawing>/read-set.jsondrawing file9
its sign-offsdrawings/issued/<drawing>/signoffs/<n>.jsondrawing file14
the register of a drawingdrawings/register/<drawing>.jsondrawing file, append-only11
an issue (transmittal)drawings/issues/<issue>.jsondrawing file12
a review rounddrawings/reviews/<review>.jsondrawing file13
renditions, outside drawings, fonts, legal containersassets/<sha256>.<ext>asset, by digest7.3, 15
previews and caches.eik/drawings/hidden: never part of the model16

<drawing> is the path segment (Part III, 2) of the drawing's number; <id>, <issue>, <review> and <n> are path segments of ids. In the owners' layout of Part III, 4.4, the layout of 0.2, a sheet is at drawings/<discipline>/sheets/<id>.json and a view under drawings/<discipline>/views/, <discipline> its owner; the files of this part's own, drawings/profile.json, drawings/issued/, drawings/register/, drawings/issues/ and drawings/reviews/, keep their place, and none of their names is a discipline's.

Part XVIII, written beside this part from plan 688, adds a model's own reviews (project/reviews/), the members of an issue that release a version and name its prints (12.1), an issue's statements and receipts (drawings/issues/<issue>/) and terms accepted (project/terms-accepted/).

1.5 How it fits into 0.1

WhatWhat a 0.1 reader does
drawings/sheets/<id>.jsonkeeps it as an application record (Part II, 9.1): checked for an id only, and written back unchanged
project/people/<id>.jsonkeeps it as a kept file: it is no record path of 0.1 (Part III, 3, rule 1)
the JSON drawing fileskeeps each as a kept file while it is text of at most 1 MiB, and leaves a larger one alone: a read set of a very large sheet may pass 1 MiB
drawing.svgkeeps it as a kept file at 1 MiB or less (A-101's 891 kB at P01 is one), and leaves a larger one alone, so that no 0.1 version holds it (Security and privacy, 5.3, rule 2). A reader of 0.2 holds issued files of up to 64 MiB (7.3)
assets/<sha256>.<ext>binary: left alone and never removed; no 0.1 version holds it, and git carries it
provenance and anchors in a detail itemunknown members, kept at any depth (Part I, 10, rule 1), about which a 0.1 validator may warn (Part I, 10, rule 2)
the single-file formsheets is a list of 0.1 already; people is an unknown member at the top, which a 0.1 reader writes into project/project.json (Part III, 11, rule 4), as it writes Part XIII's circuits; the drawing files travel in extras while they are kept files

A host or a tool that keeps a folder in git SHOULD mark drawings/issued/** and assets/** as binary (-text), so that no conversion of line ends changes a signed file.

1.6 The parts it extends

In 0.2 its text stays in this part. These are the sections of Parts I to VIII and of the other parts that it extends, where a later version may move it:

  • Part II: the sheet record (1, and a new section beside views), the person record, the references of detail items (7) with their provenance and anchors; the documentation profile (8) gains sheets;
  • Part III: the paths (1 and 3), the issued file as a file kind of its own (up to 64 MiB, never rewritten), assets by digest, and the lists sheets and people of the single-file form (11);
  • Part IV: drawings stay derived (1, rule 1), with issued drawings as the stated exception to rule 2 (section 16);
  • Part V: sheet.upsert and sheet.delete into the documentation profile (2.2), person.upsert, and provenance on the detail commands (section 17);
  • Part VI: digests that include detail chunks (8.3); issued files in versions; the register and history (section 11);
  • Part VII: an operation that answers which issued drawings a version or a proposal makes stale (17.4);
  • Part VIII: the IFC mapping of issued drawings (section 18);
  • Conformance: the classes drawing issuer and drawing validator (section 19);
  • Security and privacy: 5.4 ("No signatures in 0.1") replaced by this part's sign-offs; the SVG profile's safety; personal data in the person registry; agents' instructions by digest.

2. Sheets

A sheet becomes a standard record (D1). Its paper and its viewports are those of the reference implementation's sheet (see the reference in 2.2); its title-block fields are this part's (2.3), and the reference implementation's other members map onto them as 2.3's note says, which is to be agreed with it.

The examples of this part are drawings of the L-house, the reference implementation's test model, whose records examples/l-house holds (130 elements and 13 views), with the four sheets that the reference implementation gives it and that folder leaves out. The prototype (section 1.6, the note) issued the sheet A-101 ("Plans, facades and roof section", A1, 841 × 594 mm) at P01, with the house as examples/l-house holds it, and at P02, after the window study-window-east had moved 500 mm along its host wall study-wall-1. Most examples show the east facade: the viewport study-viewport-4, which places the view view-east at 1 : 75. They carry the prototype's real values. Where a value cannot come from the prototype, a hash that this part defines otherwise than the prototype did, it is a placeholder string "<…>", so that every example is valid JSON. Members are in the order of the stored form (Part III, 5), and short objects are written on one line to save room.

2.1 The record

drawings/<discipline>/sheets/<id>.json holds one sheet (Part III, 4.4):

MemberType and rangeMeaning
idrequiredPart I, 6its id
numberrequiredstring, 1 to 80 charactersthe drawing number, ISO 7200's identification number. It names the folder of its issued drawing, and is stable across revisions (2.4, rule 7)
namerequiredstring, 1 to 200 charactersthe title
disciplineoptionalstring, 1 to 4 capital lettersthe sheet's discipline code: the letters a drawing number of its discipline begins with, A, K, V, VS, E or a project's own. Where it gives none, the letters its number begins with are its code. Its folder in the owners' layout of Part III, 4.4 is the code's discipline's (rule 5 there)
revisionrequiredPart I, 8the record's revision, a precondition token; not the drawing's revision code
width, heightrequirednumber, more than 0, at most 10 000the paper, in mm
viewportsrequiredlist, at most 200 (2.2)the views placed on it
fieldsoptionalobject (2.3)the values of the title-block fields
titleBlockIdoptionalstring, or nonethe application's title block (Part II, 9.1) whose graphics it uses; none, a blank sheet
inRegisteroptionalbooleanfalse leaves the sheet out of the register a host lists; absent, it is listed
  1. A sheet of 0.1. In 0.1 a sheet is an application record of its writer's (Part II, 9.1). A record of sheets in a model of 0.2 that does not give every member the table requires, number, name, revision, width, height and viewports, is a sheet of 0.1 kept as an application record, as the migration to 0.2 leaves it (Part I, 9.8, rule 5). It is held to application-record.schema.json alone, a reader keeps it unchanged (Part II, 9.1, rule 2), no drawing is issued on it, and no other rule of this part applies to it. A validator SHOULD warn about it (sheet-application-record). A writer of 0.2 writes a sheet as the table says.

2.2 Viewports

A viewport is {id, viewId, x, y, detailNumber, rotation?, title?}:

MemberMeaning
idrequiredits id, unique in the sheet (2.4, rule 3)
viewIdrequiredthe view placed (x-eik-ref view)
x, yrequiredthe top-left corner of the viewport's box on the paper, in mm, y down. The box's size is the view's crop at the view's scale
detailNumberrequired1 to 40 characters: the number or the name its title and marks show, 5 or GRUNDPLAN
rotationoptionalfrom −360 to 360 degrees, about the box's centre
titleoptional{show?, lines?, width?, offset?}: whether the viewport's title shows, its lines, its width and its offset

Reference: sheetSchema and sheetViewportSchema in Stomra's src/core/sheets/documentation.ts (at 37e8f202), where a viewport's title is showTitle, titleLines, titleWidth and titleOffset, which title gathers; src/components/documents/SheetContent.tsx places a viewport's box by its top-left corner, y down.

2.3 Title-block fields

The printed block is drawn from data. ISO 7200's eight mandatory fields, with its revision index and document status, come from:

ISO 7200 fieldFrom
identification numberthe sheet's number
titlethe sheet's name
date of issuethe revision record's date (8.1)
revision indexthe revision record's revision (8.2)
document statusthe revision record's status, printed where the drawing profile says (4.1)
legal owner, creator, document type, approval personfields.legalOwner, fields.creator, fields.documentType, fields.approver
sheet numberfields.sheetNumber; absent, 1 (a drawing is one sheet in this part)

fields holds those four or five as strings of 1 to 200 characters, the optional supplementaryTitle, responsibleDepartment, technicalReference and language, and extension members (Part I, 11.2). ISO 7200 allows the creator and the approver to be held outside the printed block, which the sign-offs do (section 14): fields.approver is what is printed, not proof of approval.

The values that change with each revision (the date, the revision code, the status, the rows of the revision table) come from the revision record and the register, never from the sheet, so that issuing changes no record.

The reference implementation's sheetHere
id, number, name, revision, width, height, titleBlockId, inRegister, and the viewports' id, viewId, x, y, detailNumber and rotationas they are
author, and the parameters keyed sheet.drawnBy, sheet.checkedBy, sheet.designedBy, sheet.approvedBy and sheet.responsiblefields: creator, approver, and extension members for the others
parameters["sheet.issueDate"], revisionsthe revision record and the register
statusthe revision record's status
fontFamilyone family of the drawing profile's font set (4.1)
references, scaleBar, registerGroupextension members under the reference implementation's prefix, unless it asks for them in the standard
imagesan extension member: the pictures placed on the sheet, which its issued drawing draws in its sheet layer (6.3)

A-101 of the L-house, its fields as the prototype's neutral values would give them (abridged: A-101 has six viewports):

{
  "fields": {
    "creator": "<creator>",
    "documentType": "Plans, facades and section",
    "legalOwner": "<legal owner>"
  },
  "height": 594,
  "id": "roof-study-sheet",
  "name": "Plans, facades and roof section",
  "number": "A-101",
  "revision": 0,
  "titleBlockId": "generic-A1",
  "viewports": [
    {
      "detailNumber": "5",
      "id": "study-viewport-4",
      "viewId": "view-east",
      "x": 290,
      "y": 270
    }
  ],
  "width": 841
}

2.4 Rules

  1. A sheet's number MUST be unique among the model's sheets, and the path segments of two sheets' numbers MUST NOT fold to one (Part III, 4.3): each names a folder of drawings/issued/.
  2. A sheet's number SHOULD match the drawing profile's numbering, where it gives one.
  3. Each viewport's viewId MUST name a view of the model, and each viewport's id MUST be unique in its sheet.
  4. A viewport's detailNumber SHOULD be unique in its sheet. It SHOULD be short: a number, or the word a sheet names its view by where the profile's practice names views, as Swedish sheets often do (BJÄLKLAGSPLAN).
  5. titleBlockId, unless none, SHOULD name a title block of the model.
  6. The members MUST have the types and ranges of 2.1 to 2.3. The schema states this rule.
  7. A drawing's number is stable. A writer MUST NOT change the number of a sheet that has an issued drawing unless that drawing's register ends in withdrawn (11.1): a renumbered sheet is a new drawing. A validator reports an issued drawing whose sheet (by derivation.sheet.id) now carries another number while its register does not end in withdrawn.

3. Annotations: references, provenance and anchors

Detail items (Part II, 10; their schema, drawings/detail-item.schema.json) stay as 0.1 has them. This part declares their references, adds who made each item, and says what an issued drawing does with an item whose element is gone (D7).

A dependent view (dependentOn) draws its primary's detail items, as the reference implementation's src/core/views/viewInheritance.ts resolves a view, followed through each dependentOn to a view that depends on none. Where this part speaks of the detail items or the detail chunks of a viewport's view (3.4, rule 4; 6.12, rule 23; 9.1; 9.4, step 3; 9.7, rule 3), a dependent view's are its primary's.

3.1 References

These members name records, and get x-eik-ref (Part I, 7, rule 4); each SHOULD resolve (Part I, 7, rule 3):

MemberNames (x-eik-ref)
host.elementId, hatchHost.elementId, tag.elementId, floorList.slabIdelement
hatchHost.layerIda layer of the element's type (checked in code)
dimensionReferences[].reference.elementId (of the kinds face, layer, axis, edge and opening)element
dimensionReferences[].reference.gridIdgrid
dimensionReferences[].reference.levelId, floorList.levelIdlevel
dimensionReferences[].reference.detailIddetail: an item of the same view (a new value)
viewReference.viewIdview
partsList.pieceIdpiece (a new value)

In the live model, deleting an element still deletes the items that name it (Part V, 5, rule 3); an issued drawing is a snapshot, and keeps them. An item's reference can still fail to resolve after a merge or a hand edit: the item is then an orphan (3.3), kept and reported.

3.2 Provenance and the AI rule

A detail item MAY carry provenance, and an item an agent writes MUST carry it:

MemberMeaning
byrequiredperson or agent
personoptionalfor person: who drew it, a person of the registry (section 5)
agentrequired for agent{name, version}: the agent, its name 1 to 120 characters and its version 1 to 80
actingForrequired for agentthe person it acts for
instructionrequired for agent{digest, ref?}: the SHA-256 of the instruction, and an opaque reference to it under access control; never the instruction's text, so that what a client asked stays out of the model
maderequired for agent{version, root?}: the version of the model it saw, named as Part VI, 8.2's computedFrom.version names one
statusrequired for agentproposed until a person accepts the item, then accepted
acceptedBy, acceptedAtrequired when acceptedthe person who accepted it, and when (RFC 3339, in UTC)

The AI rule (D7): agents propose through commands, with provenance; a person accepts every agent's item; no sheet is issued while it holds a proposed item (3.4, rule 4); and an agent never signs an approval (14.5). Issued SVGs keep each item's origin (data-eik-origin, 6.8), so that the agents' share stays visible.

An insulation item that an agent drew in a section, accepted:

{
  "a": [1200, 0],
  "b": [1200, 2400],
  "color": "#555555",
  "id": "det-90",
  "insulationKind": "zigzag",
  "kind": "insulation",
  "provenance": {
    "acceptedAt": "2026-10-16T09:20:00Z",
    "acceptedBy": "person-k2m9xa",
    "actingFor": "person-k2m9xa",
    "agent": {"name": "<agent>", "version": "<version>"},
    "by": "agent",
    "instruction": {"digest": "<sha256 of the instruction>"},
    "made": {"version": "<model version id>"},
    "status": "accepted"
  }
}

3.3 Anchors and orphans

An annotation's references are its anchors, tried in order. Each anchor resolves to one of four states, worked out when the drawing is drawn and recorded only in the issued SVG (data-eik-anchor, 6.8):

  • attached: the element and its named feature exist; the position is kept in the feature's own frame, so that the note moves with the wall;
  • moved: found through a recorded successor (a split, a replacement), or by a scored geometric match above the drawing profile's reanchor.threshold;
  • elementOnly: the element exists, and the feature does not;
  • orphaned: drawn at its own last place in the view, in an orphan style, its derived values shown as "?", listed for a person to resolve, and attached again by itself if the element returns.

The members that hold a feature (layer:<id>, face:<name>, edge:<id>; never an index) and a position in the feature's frame, the anchors of a detail item, are to be fixed with the reference implementation's work on anchors. Successors need the lineage that commands record, which 0.2 has not specified: until it does, moved is found by geometry only.

3.4 Rules

  1. The references of 3.1 SHOULD resolve. A validator reports one that does not, and the item is kept: it is an orphan.
  2. An item whose provenance.by is agent MUST give agent, actingFor, instruction.digest, made.version and status. Its schema states this rule.
  3. status accepted MUST give acceptedBy and acceptedAt, and acceptedBy, actingFor and person MUST name people of the registry (5.2, rule 2).
  4. A sheet MUST NOT be issued while a view placed on it holds an item whose provenance.status is proposed. A validator reports it for an issued drawing whose views' detail chunks are unchanged since the issue (their pairs in the read set equal the model's).
  5. provenance.instruction MUST NOT hold the instruction's text: only digest and ref. Its schema states this rule.
  6. An issuer MUST NOT leave an annotation out of an issued drawing because its anchors fail: it draws it orphaned (6.12, rule 27).

4. The project's drawing profile

OpenEik defines neutral states; a project declares its codes (D3). Each model has one drawing profile, drawings/profile.json. It is a drawing file, not a record: tools write it, people may edit it, and every drawing that prints from it reads it (its pair is in the sheet list of every read set, 9.2).

4.1 The file

MemberTypeMeaning
formatrequired"openeik-drawing-profile/0.1"
idrequiredstring, 1 to 80 characters, a plain valuethe profile's name, as revision records cite it: example, iso19650-uk-2021, beast-2.1
statusesrequiredlist, 1 to 100{code, name?, state, sharedFor?, printed, revisions, clouds, requires?}: a status code; its name as people read it, a plain string ("For review and comment", "Granskningshandling"), which a tool shows first, with the code after it; the OpenEik state it means (8.2); for shared, information or review; whether the sheet prints it; the revision series it uses (8.2); whether clouds print by default (on or off); and the sign-offs it needs, [{action, role?}] (section 14)
purposesoptionallist{code, name?}: the purposes of issue (in Sweden, the handling)
decisionsoptionallist{code, gate, outcome, name?}: decision codes. gate is A (approve for sharing) or B (authorise and accept); outcome is accept, acceptWithComments or reject
reviewStatesoptionallist{code, open, name?}: the states of review items, and whether each leaves an item open
newRevisionOnStatusChangeoptionalbooleanwhether a change of status alone takes a new revision code (in Sweden it does; UK guidance says not); absent, false
numberingoptionalstringa regular expression (ECMAScript, with the u flag) that drawing numbers match
fontsrequired where the folder holds a linked issued drawing (4.3, rule 5)list, 1 to 20{family, sha256, file?}: the declared, pinned font set: a family's name as the drawings write it, the SHA-256 of the font file that draws it (which may be a free stand-in for that family), and the asset that holds the file (assets/<sha256>.ttf or .otf)
keepEarlierCloudsoptionalbooleanwhether a revision keeps the clouds of the revisions before it; absent, false
reanchoroptionalobject{threshold}, from 0 to 1: the score below which a moved anchor fails (3.3)
ownersoptionalobject{<drawing number>: <person id>}: who is responsible for each drawing, so that a host can route its reviews

Every code is a plain value: OpenEik lists none, and checks none against a code list (Part II, 8, rules 3 and 4). The schema marks them "x-eik-values": "national".

The prototype's example scheme, made a profile (its codes follow ISO 19650's UK annex, as an illustration only):

{
  "decisions": [
    {"code": "A1", "gate": "B", "outcome": "accept"},
    {"code": "B1", "gate": "B", "outcome": "acceptWithComments"},
    {"code": "approved", "gate": "A", "outcome": "accept"},
    {"code": "rejected", "gate": "A", "outcome": "reject"}
  ],
  "fonts": [
    {"family": "<family>", "file": "assets/<sha256>.ttf", "sha256": "<sha256>"}
  ],
  "format": "openeik-drawing-profile/0.1",
  "id": "example",
  "numbering": "^A-[0-9]{3}$",
  "reviewStates": [
    {"code": "actedOn", "open": false},
    {"code": "elsewhere", "open": false},
    {"code": "needsNewReview", "open": true},
    {"code": "new", "open": true},
    {"code": "rejected", "open": false},
    {"code": "toActOn", "open": true}
  ],
  "statuses": [
    {"clouds": "off", "code": "S0", "name": "Initial status", "printed": false, "revisions": "P.minor", "state": "draft"},
    {"clouds": "off", "code": "S2", "name": "Suitable for information", "printed": false, "revisions": "P", "sharedFor": "information", "state": "shared"},
    {"clouds": "off", "code": "S3", "name": "Suitable for review and comment", "printed": false, "revisions": "P", "sharedFor": "review", "state": "shared"},
    {"clouds": "on", "code": "A1", "name": "Authorised and accepted", "printed": true, "requires": [{"action": "approved", "role": "approver"}], "revisions": "C", "state": "published"},
    {"clouds": "off", "code": "CR", "name": "As constructed record", "printed": true, "revisions": "C", "state": "asBuilt"}
  ]
}

4.2 How common schemes map onto the states (informative)

OpenEik stateISO 19650 (UK annex)Sweden (BEAst Namnruta 2.1)Sign-offs, by defaultClouds, by default
liveno container: nothing is storednonenonenone
draftWIP, S0; P01.01Preliminärnonenone
shared, informationS2; P01Informationnoneoff
shared, reviewS3 (S1, S4, S6, S7 as the profile says); P01Granskning: dated, no letteroptionaloff, switchable
publishedA1…An, B1…Bn; C01Godkänd with its handling; letters from tender or construction issueas the profile and the contract requireon in Sweden, switchable
asBuiltCRRelationshandlingas requiredremoved
superseded, withdrawnnonenonenonenone

Superseded and withdrawn are not statuses: the register records them (section 11). OpenEik ships no national profile. The Swedish default is the authoring tool's default for a Swedish project (D3), never a list in the standard.

4.3 Rules

  1. The file MUST validate against its schema.
  2. Codes MUST be unique within statuses, purposes, decisions and reviewStates, and families within fonts.
  3. A folder that holds an issued drawing MUST hold drawings/profile.json.
  4. Each font SHOULD be in the folder, at assets/<sha256>.<ext>. A font the project may not store is named by its digest alone; then no one else can draw the sheet again or check its rendering. The issued file stays verifiable by its digest.
  5. A profile MUST give fonts where the folder holds a linked issued drawing. A profile that only gives a model's reviews their codes (Part XVIII, 2) needs none (open question 67).

5. People and keys

Every file of this part names people: reviewers, recipients, authors and signers. Each is named by the id of a record of one registry in the folder, of people and agents, which also holds the keys of those who sign. No file of this part names a person by an email address (Security and privacy, 2.3, rule 1 already prefers ids).

5.1 The record

project/people/<id>.json holds one person or agent; the list is people:

MemberType and rangeMeaning
idrequiredPart I, 6; it MUST NOT hold @the person's id, person-k2m9xa, minted without coordination (Part I, 6, rule 5); never an email address
revisionrequiredPart I, 8
kindrequiredperson or agent
nameoptionalstring, 1 to 120 charactersthe name printed or shown: personal data, kept in every version that holds it (Security and privacy, 2.4)
organisationoptionalstring, 1 to 120 characters
rolesoptionallist of plain valuesthe roles the project gives the person (approver, checker)
agentrequired for agent{name, version?}the software
keysoptionallist, at most 20the keys this person or agent signs with

A key is {keyid, algorithm, public, validFrom, validUntil?, rpId?}: keyid, 1 to 80 characters, unique in the registry; algorithm, ed25519 or ecdsa-p256; public, the public key, the base64 of its DER SubjectPublicKeyInfo; validFrom and validUntil, RFC 3339 times in UTC; and rpId, for a passkey, the WebAuthn relying party it was registered with. A passkey's algorithm is ecdsa-p256 (ES256). A key is revoked by giving it a validUntil, never by removing it: a signature made before then, with a time-stamp to prove it, stays valid.

Who may add a key is the project's to decide: the registry changes as any record does, through review and a person's merge. A host's own verified keys may seed it; the folder never depends on the host to check one.

{
  "id": "person-k2m9xa",
  "keys": [
    {"algorithm": "ed25519", "keyid": "k-7f3a9c", "public": "<base64 SPKI>", "validFrom": "2026-10-01T00:00:00Z"}
  ],
  "kind": "person",
  "revision": 0,
  "roles": ["approver"]
}

5.2 Rules

  1. A person record MUST validate against its schema.
  2. Every member of this part's files that names a person MUST name a record of project/people/: the drawing profile's owners; provenance's person, actingFor and acceptedBy; a revision's by; a register's issued.by and withdrawn.by; an issue's sent.by and recipients' person; a review's opened.by, closed.by, reviewers' person, items' and replies' author.person, author.actingFor, author.acceptedBy and history's by; a statement's signer.
  3. A member of this part's files that names a person, and a person's id, MUST NOT hold an email address: people are named by id.
  4. A keyid MUST be unique in the registry, and a key's validUntil MUST NOT be before its validFrom.
  5. A key MUST NOT be removed once a sign-off names it; a writer ends it with validUntil.

6. The issued drawing: OpenEik drawing SVG 0.1

An issued drawing is written in OpenEik drawing SVG 0.1, the SVG profile: the static subset of SVG 1.1 that the renderers tested drew alike, with SVG 2's href and data-* attributes. Its safety comes from an allowlist and a validator, not from sanitising. The allowlist is published once, as data, in schemas/0.2/drawings/svg-profile.json, which a validator and any host's parser share.

6.1 Bytes

The file is UTF-8 without a byte-order mark, with LF line ends, and holds no XML declaration, DOCTYPE, entity declaration, comment, processing instruction or CDATA section. It is its own Canonical XML 1.1 form (without comments), followed by one LF. The canonical form is a lint, never a step of verifying a signature, which covers the exact bytes. It has one element per line: each start tag begins a line; an element with element children ends on a line of its own; and an element with only text is one line.

6.2 Paper and scale

The root's width and height are the sheet's paper, in mm, and its viewBox is 0 0 W H with the same numbers: one user unit is one millimetre of paper. A viewport is a group whose transform is the matrix from the view's own coordinates (u along, v up, in model mm) to the paper: the derivation's matrix (6.9), written matrix(a b c d e f). The paper is white: a renderer draws an issued drawing on white, and the file need not draw the paper. A file whose sheet layer comes after the viewport groups (6.7) draws no white over its views, so it shows the paper only through what it leaves empty.

6.3 Elements

Allowed: svg (the root only), g, defs, title, desc, metadata, path, rect, circle, ellipse, line, polyline, polygon, text, tspan, use, pattern, clipPath and marker, and image only as a picture, below: a 3D view's, or one of the sheet layer. Forbidden: every other element, among them script, foreignObject, style, image anywhere else, symbol, filter and its primitives, mask, gradients, animation elements, a, switch, a nested svg, and any element outside the SVG namespace.

Pictures of 3D views. By the steward's decision of 16 October 2026, the derived layer of the viewport group of a view of kind 3d MAY hold the view's picture in place of line work: one image, and nothing else. Its href is a data:image/png;base64, URI, never a file or a URL, so that the picture fetches nothing; it carries data-eik-role picture and no data-eik-id; its x, y, width and height place it in the viewport group's coordinates; and it counts towards the file's 64 MiB (6.5). A picture is not source-mapped: a review anchors to its place on the sheet, a comparison compares its bytes, and its viewport's volume is the whole model (9.3).

Pictures on the sheet. By the steward's decision of 19 October 2026, the sheet layer MAY hold pictures: a title block's logo, or a picture placed on the sheet. Each is an image, at any depth of the layer and any number of them, whose href is a data:image/png;base64, or data:image/jpeg;base64, URI, never a file or a URL. It carries data-eik-role picture and no data-eik-id, data-eik-record or data-eik-item; its x, y, width and height place it in paper mm, and its preserveAspectRatio, where it has one, is none, xMidYMid meet or xMidYMid slice; it counts towards the file's 64 MiB (6.5). Like a 3D view's, it is not source-mapped: a review anchors to its place on the sheet, and a comparison compares its bytes. Where the picture is a record of the model's (a project's image), the sheet's read set holds that record (9.1).

6.4 Attributes and values

  • On any element: id, class, role, aria-label, transform (not on the root), clip-path, opacity, fill, fill-opacity, fill-rule, stroke, stroke-width, stroke-opacity, stroke-linecap, stroke-linejoin, stroke-miterlimit, stroke-dasharray, stroke-dashoffset, marker-start, marker-mid, marker-end, font-family, font-size, font-weight, font-style, text-anchor, and the data-eik-* attributes of 6.8.
  • By element: on the root, xmlns (SVG's), width, height and viewBox; on rect, x, y, width, height, rx and ry; on circle, cx, cy and r; on ellipse, cx, cy, rx and ry; on line, x1, y1, x2 and y2; on polyline and polygon, points; on path, d; on text and tspan, x, y, dx, dy and xml:space="preserve"; on title and desc, lang; on use, href, x and y; on image, href, x, y, width, height and preserveAspectRatio (6.3); on pattern, x, y, width, height, patternUnits, patternContentUnits, patternTransform and viewBox; on clipPath, clipPathUnits; on marker, markerWidth, markerHeight, markerUnits, refX, refY, orient (auto or an angle) and viewBox; on metadata, id.
  • On any element too, an attribute data-<prefix>-<name> under a prefix registered to an application (Part I, 11.1), which every reader ignores: an application keeps its own markers so, and this part names none of them.
  • Forbidden: on*, style, vector-effect, xlink:*, xml:base, display, visibility, pointer-events, any other data-* attribute, and any attribute in another namespace.
  • Colours: none, #rrggbb in lower case, or url(#<id>) of a pattern.
  • Transforms: matrix, translate, scale and rotate only.
  • Numbers: fixed decimals, with no exponent, no +, no leading zeros and no trailing zeros after the point, and -0 written 0; at most three decimals, except the six numbers of a viewport group's matrix, which have at most nine. No unit anywhere but the root's mm.

6.5 References and limits

href is only on use, as #<id>, and on a picture, a 3D view's or one of the sheet layer, as 6.3 says; url(#<id>) is only in clip-path, marker-*, fill and stroke; and each names an element of the file, of the right kind. A use never reaches itself or an ancestor, directly or through other uses, and expanding the file's uses adds at most 1 000 000 elements. The file is at most 64 MiB, with at most 2 000 000 elements and a depth of at most 32.

6.6 Text and fonts

font-family names exactly one family of the drawing profile's font set, with no list of fallbacks: in tests, engines fell back silently, and each differently. Text stays <text>, so that people, grep and agents read it; outlining text is a rendition's option, never the issued file's.

6.7 Layers and order

The root's children are, in this order: title, never empty, which SHOULD read <number> <revision> <title>; desc (optional); metadata (6.9); defs (optional); the sheet layer, <g data-eik-layer="sheet">, with the border, the title block, the revision table and the optional code of 6.8, all drawn from records; one viewport group per viewport, in the order of the sheet's viewports; and, where there are clouds, <g data-eik-layer="revisions">, in paper millimetres. By the steward's decision of 17 October 2026, the sheet layer MAY instead come after the viewport groups, and before the revisions layer, so that its frame lies over the views' fills. The root holds one sheet layer, in one place or the other. Inside a viewport group are the layers derived, drafted and agent, in that order. Inside a layer, its children are in the order that the derivation's generator.order names (6.9): id, sorted by id (data-eik-id, data-eik-item); or paint, back to front as the generator paints them, ids breaking ties, for a generator whose sections and elevations rely on the order of painting until it draws exact hidden lines. Every value of an id attribute occurs once in the file (6.12, rule 14). Nothing in the file is volatile: no time but the revision's date, no id generated at random, no banner of the generator. The ids that use, clip-path and markers need are made from what they belong to (clip-study-viewport-4).

Parts. By the steward's decision of 17 October 2026, where the derivation's generator.order is paint, an element MAY have several groups in a viewport's derived layer: its parts, in the order the generator paints them, with other elements' groups and parts between them. Each part carries data-eik-id, naming the element (or, for a shared path, its elements) as a group does; data-eik-part, its place among the element's parts in the layer, 0, 1, 2, … in the order painted, which is the order of the file; and its own data-eik-hash (6.8). An element drawn in one group needs no data-eik-part. Where generator.order is id, nothing changes: an element has one group in a layer, and nothing carries data-eik-part.

6.8 The model link

AttributeOnSays
data-eik-layerlayer groupssheet, derived, drafted, agent or revisions
data-eik-viewport, data-eik-viewviewport groupsthe sheet's viewport, and the view placed there
data-eik-ideach element's group in a derived layer, and each of its parts (6.7); a path shared by several elementsthe element, or the elements (an element of a placed copy by its derived name, <copy id>/<element id>, Part I, 6, rule 6), space-separated in ascending order, that produced it
data-eik-parteach part of an element in a derived layer, where generator.order is paint (6.7)the part's place among the element's parts in that layer, in the order painted: 0, 1, 2, …, a whole number with no leading zero
data-eik-recorda group of derived line work of a record that is no element; a record's line work, like the annotations the generator makes, may come in several groups, which are no parts and carry no data-eik-part<list>/<id>: grids/grid-a, levels/level-0, views/view-section (a section mark)
data-eik-roledrawn primitives inside an element's group, and a picture (6.3)cut, poche, projection, hidden, overhead, beyond, hatch, symbol, text, or picture on a picture (6.3)
data-eik-featuredrawn primitives, where the generator can name the featurelayer:<id>, face:<name>, edge:<id>: a named feature, never an index
data-eik-hasheach element's group, each part, and each shared paththe SHA-256, as 64 lowercase hexadecimal digits, of the group's canonical bytes as the file holds them, its own data-eik-hash attribute left out: a part's, of the part alone, its data-eik-part included. The generator snaps line work to a grid of 0.01 mm of paper, in the viewport's coordinates, so that unchanged elements keep their hash and a moved viewport changes none
data-eik-itemeach annotation's group in drafted and agentthe detail item's id
data-eik-refannotation groupsthe elements the item names, space-separated
data-eik-originannotation groupsderived, person or agent; derived for the annotations that the generator makes from the view's settings, which sit in the derived layer
data-eik-anchorannotation groupsattached, moved, elementOnly or orphaned (3.3); absent, attached
data-eik-rev, data-eik-changeclouds and revision marks in the revisions layerthe revision code, and the change items marked, space-separated
data-eik-codethe optional printed code in the sheet layerthe digest it encodes: the derivation's hash (6.9)

6.9 The derivation

<metadata id="openeik-derivation"> holds the derivation, as the text of its canonical JSON (RFC 8785). It never holds the SVG's own digest, nor the revision record's, which names the SVG's: a file cannot contain its own digest. The same object is the revision record's derivation (8.1), and its hash (Part III, 6) is the derivation's digest.

MemberMeaning
formatrequired"openeik-drawing-derivation/0.1"
drawing, revision, titlerequiredthe number; the revision code as printed, 0 to 20 characters, empty where the profile prints none; the title
sourcerequired{version, versionKind, root, ref, upstream}: version and versionKind, the version drawn from, named as Part VI, 8.2's computedFrom names one (null for a folder under no version control); root, the model's root tree hash as read (Part VI, 2, rule 4), always given; ref, the line of work the drawing tracks (main, alternatives/<slug>, a git branch), or null; and upstream, as Part VI, 8.2 has it
sheetrequired{id, hash}
viewsrequired{<view id>: <hash>}: the hash of each placed view with its detail items joined, as the single-file form holds it
viewportsrequired[{id, view, kind, detailNumber, place {x, y, width, height, rotation}, scale, crop, matrix}], in the sheet's order: the view's kind (plan, section, elevation, 3d or drafting), where each sits on the paper (in mm), its scale (the 75 of 1 : 75), its crop, and the matrix [a, b, c, d, e, f] from view to paper, x = a u + c v + e, y = b u + d v + f. A 3D view's picture has no scale and no crop: both are null, and its matrix places the picture's box on the paper
generatorrequired{name, version, order, styles?, request?}: the generator; its version (a release or a commit); the order inside its layers (id or paint, 6.7); the digest of its style set; and the request it was given
fontsrequired{<family>: <sha256>}: each family the file uses
readSetrequired{hash, count}: the read set file's hash (Part III, 6), and its number of distinct pairs
annotationsoptional{derived, person, agent}: how many annotation groups of each origin the file holds

A-101 at P02, abridged to one viewport (the prototype's values, reshaped):

{
  "drawing": "A-101",
  "fonts": {"<family>": "<sha256>"},
  "format": "openeik-drawing-derivation/0.1",
  "generator": {
    "name": "Stomra",
    "order": "paint",
    "request": {"action": "snapshot_2d", "format": "svg", "viewId": "roof-study-sheet"},
    "version": "37e8f202"
  },
  "readSet": {"count": 165, "hash": "<hash of read-set.json>"},
  "revision": "P02",
  "sheet": {"hash": "615ca99ca792f6a421651c275e43fd16abf330dc4cd5b86235644db92196f30d", "id": "roof-study-sheet"},
  "source": {
    "ref": null,
    "root": "6b572fb1e20adea6f4d012a31588f32aef0dc7995796d2630497fb3f74e1f378",
    "upstream": null,
    "version": null,
    "versionKind": null
  },
  "title": "Plans, facades and roof section",
  "viewports": [
    {
      "crop": [-4200, 13500, -700, 6500],
      "detailNumber": "5",
      "id": "study-viewport-4",
      "kind": "elevation",
      "matrix": [0.013333333, 0, 0, -0.013333333, 346, 356.666666667],
      "place": {"height": 96, "rotation": 0, "width": 236, "x": 290, "y": 270},
      "scale": 75,
      "view": "view-east"
    }
  ],
  "views": {"view-east": "f44967a88a44b26fbee6dc50eca8aea9a0c495a20fe34df07a2b975d17561287"}
}

6.10 The file, in outline

In canonical form, with its attributes sorted and empty elements written as start and end tags:

<svg xmlns="http://www.w3.org/2000/svg" height="594mm" viewBox="0 0 841 594" width="841mm">
<title>A-101 P02 Plans, facades and roof section</title>
<metadata id="openeik-derivation">{"drawing":"A-101",…}</metadata>
<g data-eik-layer="sheet">…</g>
<g clip-path="url(#clip-study-viewport-4)" data-eik-view="view-east" data-eik-viewport="study-viewport-4" transform="matrix(0.013333333 0 0 -0.013333333 346 356.666666667)">
<g data-eik-layer="derived">
<g data-eik-hash="…" data-eik-id="study-wall-1">
<path d="…" data-eik-role="projection"></path>
</g>
<g data-eik-hash="…" data-eik-id="study-window-east">
<path d="…" data-eik-role="projection"></path>
</g>
</g>
<g data-eik-layer="drafted"></g>
</g>
<g data-eik-layer="revisions">
<path d="…" data-eik-change="chg-1" data-eik-rev="P02" data-eik-viewport="study-viewport-4" fill="none" stroke="#c0392b" stroke-width="0.5"></path>
</g>
</svg>

The defs with clip-study-viewport-4, and the other five viewports, are left out.

Where generator.order is paint, an element painted in two pieces, with another element painted between them, is two parts (6.7): here the wall's face, then the window in it, then the wall's lines over both.

<g data-eik-layer="derived">
<g data-eik-hash="…" data-eik-id="study-wall-1" data-eik-part="0">
<path d="…" data-eik-role="projection" fill="#ffffff"></path>
</g>
<g data-eik-hash="…" data-eik-id="study-window-east">
<path d="…" data-eik-role="projection"></path>
</g>
<g data-eik-hash="…" data-eik-id="study-wall-1" data-eik-part="1">
<path d="…" data-eik-role="projection"></path>
</g>
</g>

6.11 What a reader may ignore, and how a host shows it

A renderer draws the file as static SVG, and MAY ignore metadata, title, desc, role, aria-label, class and every data-* attribute. A reader of the model link MAY ignore the sheet and revisions layers. A reader MUST NOT fetch, run or follow anything outside the file. A host SHOULD serve an issued SVG as image/svg+xml, as an image, with a strict content security policy and nosniff, and never inline in a page that holds the viewer's credentials: this makes Security and privacy, 11, rule 4 concrete.

6.12 Rules

  1. An issued SVG MUST be UTF-8 without a byte-order mark, with no CR and no NUL.
  2. It MUST hold no XML declaration, DOCTYPE, entity declaration, comment, processing instruction or CDATA section.
  3. It MUST be its own Canonical XML 1.1 form, without comments, followed by one LF.
  4. It SHOULD hold one element per line, as 6.1 says.
  5. The root MUST be svg, in the SVG namespace, and that MUST be the only namespace declared.
  6. Its width and height MUST be the paper of the sheet the derivation names, in mm, and its viewBox MUST be 0 0 W H with the same numbers.
  7. Its first child MUST be a title that is not empty.
  8. It MUST hold only the elements 6.3 allows.
  9. Each element MUST hold only the attributes 6.4 allows it.
  10. Colours, transforms, orient and units MUST be as 6.4 says.
  11. Numbers MUST be as 6.4 says.
  12. Every href and url() MUST name an element of the file, of the kind 6.5 says, and nothing outside it; the href of a 3D view's picture MUST be a data:image/png;base64, URI, and of a picture of the sheet layer a data:image/png;base64, or data:image/jpeg;base64, URI (6.3).
  13. A use MUST NOT recurse, and expanding the file's uses MUST add at most 1 000 000 elements.
  14. Ids MUST be unique in the file.
  15. The file MUST be at most 64 MiB, with at most 2 000 000 elements and a depth of at most 32.
  16. Every font-family MUST name one family of the drawing profile's font set, and the derivation's fonts MUST name each family the file uses with the set's digest.
  17. The root's children, the viewport groups and their layers MUST be in the order 6.7 says, with one sheet layer, before the viewport groups or after them, and the viewport groups MUST be the derivation's viewports.
  18. Where the derivation's generator.order is id, the children of each layer MUST be sorted by id.
  19. Every drawn primitive of a derived layer, but the picture of a 3D view (6.3) and the annotation groups that the generator makes from the view's settings (6.8), MUST have exactly one ancestor-or-self carrying data-eik-id or data-eik-record.
  20. A derived layer MUST hold at most one group per element, or, where the derivation's generator.order is paint, one per element and part. Where an element has parts in a layer, all its groups there MUST be parts, their data-eik-part 0, 1, 2, … in the order of the file; and data-eik-part MUST NOT be on anything but a part (6.7).
  21. Each id of data-eik-id MUST name an element of the model at the source version.
  22. Every element's group, and every shared path, MUST carry data-eik-hash, equal to the hash 6.8 defines.
  23. Each annotation group MUST carry data-eik-origin agreeing with its layer (drafted holds person, agent holds agent, derived holds derived), and each annotation group of the drafted and agent layers MUST carry data-eik-item naming an item of its viewport's view (of a dependent view, its primary's: section 3): an annotation the generator makes from the view's settings is no item.
  24. data-eik-viewport and data-eik-view MUST agree with the derivation and the sheet.
  25. The file MUST hold one metadata, id openeik-derivation, whose text is the derivation in canonical JSON, valid against its schema, with no member that depends on the file's own bytes.
  26. An element's group SHOULD NOT lie wholly outside its viewport's crop: a generator leaves out what the view does not show.
  27. An annotation whose anchors fail MUST be drawn with data-eik-anchor orphaned, never left out, and data-eik-anchor MUST be one of the states of 3.3.

7. Issued files and the folder

7.1 Layout

drawings/issued/<drawing>/ holds the latest snapshot of each drawing, of any state but live: drawing.svg, revision.json, read-set.json and signoffs/<n>.json. An unlinked drawing's folder holds revision.json and signoffs/ only, its file being an asset. signoffs/ holds the sign-offs of every revision of the drawing, the current one's and earlier ones', and none is ever removed: each names the revision it signs by digest (section 14). Earlier revisions stay in the history, and the register (section 11) finds each by its digests and the version it was drawn from: a checkout does not carry every revision, and nothing issued is lost. Issued SVGs are plain, uncompressed text, so that they diff and merge: in tests, ten revisions of a sheet of 7 MB and 100 000 paths packed to 1.68 MiB in git, against 13 MiB as compressed SVG.

7.2 Drawing files

Every JSON file of this part that is not a record:

  • has a format, openeik-drawing-<kind>/0.1, by which a validator chooses its schema. A reader MUST NOT interpret a file whose format it does not implement. The prototype's ids that end in /0.1-proposal name other shapes, and are not read as these formats;
  • is written in the stored form (Part III, 5), and its hash is the SHA-256 of its canonical form (Part III, 6); an SVG's, a PDF's or a font's digest is the SHA-256 of its bytes. Both are 64 lowercase hexadecimal digits, with no sha256: prefix;
  • writes times as RFC 3339, in UTC with Z, and dates as YYYY-MM-DD;
  • is named, where a read set lists it (the drawing profile), by the hash of its leaf in a version tree, as Part VI, 8.3 names a kept file: the hash of its text. Everywhere else this part names a drawing file by the hash above. The two differ, and each has its use: a read set is compared with a tree's leaves without parsing anything;
  • is complete without a host: it holds no host's URL and no id that only a host knows, names people only by ids of the registry (5.2, rules 2 and 3), and holds no email address.

7.3 Assets

assets/<sha256>.<ext> holds a binary file by the SHA-256 of its bytes, of one of the kinds of Part XV, 4: this part's are a PDF rendition or an outside drawing (pdf), a font (ttf, otf) and a container of the legal tier (asice), and the images a review item attaches (png, jpg; 13.2). An asset is never changed. A host may keep the bytes outside the version tree, as stores of large files do, and the folder names them by digest. Part III, 7's limits of 1 MiB and of text do not hold for assets, nor for issued drawings and read sets of up to 64 MiB: a reader and a version store of 0.2 hold them in its versions. Part XV says how a version, a store, a push and a pull hold assets.

7.4 Rules

  1. A drawing's folder SHOULD hold only the files of 7.1.
  2. A drawing's folder's name, read back (Part III, 2, rule 7), MUST equal its revision record's drawing.
  3. Each drawing file MUST be in the stored form and validate against the schema of its format.
  4. An issued drawing's files are written once: a writer MUST NOT replace them except with a later revision of the same drawing, all together (drawing.svg, revision.json and read-set.json; the sign-offs stay), and MUST NOT remove them in any other case. A withdrawn drawing keeps its last revision.
  5. An asset is a file of assets/ as Part XV, 2 says: its name the SHA-256 of its bytes and the extension of one of the kinds of Part XV, 4. A file of assets/ that is not one is no asset (Part XV, 2, rule 3).
  6. Every folder of drawings/issued/ MUST have a register, and every register its folder.

8. The revision record

drawings/issued/<drawing>/revision.json says what the revision is. The derivation is in it, and the SVG's digest beside it; the sign-offs' statements sign both (section 14).

8.1 Members

MemberType and rangeMeaning
formatrequired"openeik-drawing-revision/0.1"
drawingrequiredstring, 1 to 80 charactersthe drawing's number
sequencerequiredinteger, at least 1the revision's place in the drawing's series: its identity
revisionrequiredstring, 0 to 20 charactersthe revision code shown (P02, C01, B), empty where the profile shows none
titlerequiredstring, 1 to 200 characters
daterequireddatethe date of issue
staterequireddraft, shared, published or asBuiltthe OpenEik state (8.2)
sharedForrequired when sharedinformation or review
statusrequired{profile, code, purpose?}the profile's id, its status code, and its purpose code where the project uses one
kindoptionallinked or unlinkedabsent, linked
derivationrequired for linkedobject (6.9)equal to the SVG's
svgrequired for linked{file, sha256, bytes}file is drawing.svg
filerequired for unlinked{asset, sha256, bytes, mediaType}the outside drawing, an asset (8.3)
changesoptionallist (10.1)what changed since the revision it supersedes
cloudsrequiredon, off or throughoutthe choice made for this update (10.2)
supersedesrequired when sequence is more than 1{sequence, revision, record, svg?}the revision it replaces: its sequence, its code, its revision record's hash and its SVG's digest
byoptional; SHOULD be given for shared, published and asBuilt (8.5, rule 12)person idwho issued it, a person of the registry (section 5)

8.2 States, statuses and revision codes

  • States are OpenEik's (D3). draft, shared (for information or for review), published and asBuilt are a revision's; superseded and withdrawn are the register's (section 11); live is never stored.
  • Statuses are the project's: status.code is a code of the drawing profile, which says its state and whether the sheet prints it.
  • Revision codes are worked out from the series that the profile gives the status: none (dated only, as a Swedish preliminary or review issue), P (P01, P02, …), P.minor (P01.01, …, for work in progress), C (C01, …), letters (A to Z, then AA, AB, …, leaving out I and O, as ISO 7200 asks) and numbers (1, 2, …). The register keeps the sequence; the code shown is the profile's rendering of it. Where the profile's newRevisionOnStatusChange is false, a change of status alone keeps the code.
  • A change of status alone MAY be issued as a new revision record over the same drawing.svg, whose bytes then do not change, where the profile neither prints the status nor takes a new revision code on a change of status (newRevisionOnStatusChange false, as in UK practice, where a status is metadata). Its derivation, its revision code and its read set are then the superseded revision's, the read set with the sequence of the revision that drew the file. So what was reviewed is what is issued, through a change of status too.

8.3 Unlinked drawings

An outside drawing, such as a consultant's PDF, is registered, reviewed and issued as any other (D8). Its file is an asset (assets/<sha256>.pdf); its revision record has the kind unlinked and file, and no svg, derivation or read set; and its folder holds no drawing.svg. It is never shown as source-mapped, and its freshness is not worked out. A conversion to SVG for viewing is derived, and not stored.

8.4 Example

A-101 at P02, as the prototype issued it (derivation abridged: it is the whole object of 6.9):

{
  "changes": [
    {
      "by": "person",
      "elements": ["study-wall-1", "study-window-east"],
      "id": "chg-1",
      "viewports": ["study-viewport-0", "study-viewport-1", "study-viewport-4"],
      "what": "East window moved 500 mm"
    }
  ],
  "clouds": "on",
  "date": "2026-10-15",
  "derivation": {"drawing": "A-101", "format": "openeik-drawing-derivation/0.1", "revision": "P02"},
  "drawing": "A-101",
  "format": "openeik-drawing-revision/0.1",
  "revision": "P02",
  "sequence": 2,
  "sharedFor": "review",
  "state": "shared",
  "status": {"code": "S3", "profile": "example"},
  "supersedes": {
    "record": "<hash of P01's revision.json>",
    "revision": "P01",
    "sequence": 1,
    "svg": "742dadf029a3a787dd9589bc1ba00f3d1e0fc157b0584246e81d08e1e7db2efe"
  },
  "svg": {"bytes": 900524, "file": "drawing.svg", "sha256": "7e7e0bbe28f97181127a5e2b7f624004ae6848f9ae322eb81d68c82c018fa05c"},
  "title": "Plans, facades and roof section"
}

8.5 Rules

  1. The record MUST validate against its schema.
  2. drawing, revision and title MUST equal the derivation's, and drawing the number of the sheet the derivation names.
  3. svg.sha256 and svg.bytes MUST equal drawing.svg's.
  4. derivation MUST equal the derivation in drawing.svg, member for member.
  5. derivation.readSet.hash MUST equal read-set.json's hash, and count its number of distinct pairs.
  6. sequence MUST be 1 for a drawing's first revision, else its superseded revision's plus 1; supersedes MUST be absent exactly when sequence is 1.
  7. status.profile MUST be the drawing profile's id; status.code MUST be a code of its statuses, whose state and sharedFor are the record's; status.purpose, where given, MUST be a code of its purposes.
  8. revision SHOULD be the code the profile's series gives for its status and sequence.
  9. A change of status alone MAY keep the superseded revision's drawing.svg, derivation, revision code and read set, where 8.2 allows it.
  10. date SHOULD NOT be earlier than the superseded revision's.
  11. An unlinked revision MUST have file and no svg, derivation or read set, and its folder MUST hold no drawing.svg or read-set.json.
  12. A revision of state shared, published or asBuilt SHOULD give by, the person who issued it: who issued a drawing is among the first things a reviewer asks.

9. The read set and freshness

Staleness is computed, not guessed. A revision records every record its drawing read, with its hash, and the elements its views' volumes held; one look-up of a hash per record and one spatial query per view then tell whether it is still current, without drawing anything. A false alarm is acceptable; a miss is not.

9.1 What a drawing reads

A drawing reads every record that the generator consulted, not only the elements it drew: for each viewport, its view and every detail chunk of it, each element drawn, its type and its type's materials, its host, the elements joined to it, the levels, the scope box, and the views whose marks it draws; for the sheet, the sheet record, its title block, the project record, the levels, the drawing profile, the people whose names it prints, and every sheet that its reference list names: where it lists or counts the project's sheets (a drawing register, a reference list of the other sheets, a sheet count), every sheet record. So does a sheet whose views mark a view placed on no sheet, since a mark prints the number of the sheet its view is placed on, and any sheet may come to place it. A register that prints its sheets' scales and revisions also reads the views placed on them, with their detail chunks. The prototype showed why: the wall's record never changed when its window moved, yet the wall's drawing changed in four viewports, which only the host reference predicted. A read set MAY hold more than the generator read: a pair it did not need costs only a false alarm, never a miss, but one each time it changes. The order of the lists, project/order.json, is an index and no record (Part III, 9), and every type, view or other record added changes it: a sheet's list holds it only where the order of the model's sheets decides something the sheet prints, or where the sheet reads every sheet record and the model holds no other sheet. A sheet added enters no list there (9.4, step 2), and the order index is the one record it changes. What it MUST hold at least is 9.7, rules 3 and 4, say; a generator that cannot report what it read lists every record of its viewports' volumes.

9.2 The file

drawings/issued/<drawing>/read-set.json:

MemberMeaning
formatrequired"openeik-drawing-read-set/0.1"
drawing, sequencerequiredthe revision's
sheetrequiredthe pairs that the sheet as a whole read
viewportsrequiredone entry per viewport of the derivation, in its order: {id, view, volume, read, inVolume}

A pair is [path, hash], as Part VI, 8.3 says: a record's leaf path (architecture/level-0/window/study-window-east) and its hash; a kept file's own path (drawings/profile.json) and the hash of its text as a canonical JSON string. A view gives one pair for view.json (drawings/views/elevation/view-east/view) and one for each detail chunk (…/details/0000): this part's digests include detail chunks, which Part VI, 8.3 leaves out (at 0.2, Part VI, 8.3 changes). Each list is sorted by path, each path once. Pairs are keyed by path, not by id, since ids are unique only within their list (Part I, 6, rule 1). A pair's path names a record by its list and id, and a view's chunk by its view's id and its index, in either layout of Part III, 4.4: a checker compares a pair with the record it names (Part III, 4.4, rule 9), so that a drawing issued before a building's change of layout reads the records that the change moved, its pairs' paths as they were.

In each viewport, read holds the pairs of what it consulted; inVolume, the pairs of the elements that the volume test (9.3) held at the source version and that read does not hold: elements in the view's volume, but hidden or left out; and volume, the test's parameters:

  • a plan: {kind: "plan", crop: [x0, x1, y0, y1], rotation, z: [bottom, top]}, in plan coordinates and absolute elevations, null for an open end;
  • a section or an elevation: {kind, origin, direction, crop: [u0, u1, v0, v1], depth: [0, far]};
  • a drafting view: {kind: "drafting"}, which holds no element;
  • a 3D view: {kind: "3d"}, whose volume is the whole model (9.3): every element of the model is in its read or its inVolume.

Each volume also gives margin, in mm, added all round (the prototype's is 1).

A-101 at P02, the east facade, abridged (the records' hashes are the prototype's; the view's pairs differ from the prototype's single hash for it, so they are placeholders):

{
  "drawing": "A-101",
  "format": "openeik-drawing-read-set/0.1",
  "sequence": 2,
  "sheet": [
    ["drawings/profile.json", "<hash>"],
    ["drawings/sheets/lhouse-sheet", "77c550a96736eb1e9d9ec4d520298443f1c8ba53072428d3a3ebb4290510a615"],
    ["drawings/sheets/outdoor-connection-sheet", "d3f3ed248c259e9a6c953927c06b421e9529ba116981f47bfe2aba6d84b0f8e2"],
    ["drawings/sheets/outdoor-sheet", "9456167e8d031e3c8278a8d6f06e788a73bb6c0a4fa8895146563c9673dffbcf"],
    ["drawings/sheets/roof-study-sheet", "615ca99ca792f6a421651c275e43fd16abf330dc4cd5b86235644db92196f30d"],
    ["project/levels", "59150d955ca1063efc9ded9d21922b75fcaa798727caf7ec38c1593c10b9f997"],
    ["project/project", "9ab0c9e2652ed85c7a57c778fe25032b4aae8653842814de01af0d620577c7d7"],
    ["project/title-blocks/generic-A1", "8777c6ddb90a00327b75fec4bfcbcd1933b5de0e5eb2d239f5ca2469f82cfe43"]
  ],
  "viewports": [
    {
      "id": "study-viewport-4",
      "inVolume": [["<path>", "<hash>"]],
      "read": [
        ["architecture/level-0/wall/study-wall-1", "66ddafe61eb58d12c58382c76e9e24824d84931556c6d160fb8a4ee789ec2f37"],
        ["architecture/level-0/window/study-window-east", "21df22d8acaa1d8d85a9be9238cf35e85a152cd808170c3b73b767dc5091b4eb"],
        ["drawings/views/elevation/view-east/view", "<hash>"],
        ["types/architecture/window/type-window", "4f7a344fcf17aea3d91367c66256bef49a51675ceeb6c6cf75d7e2a6b8ad9b30"]
      ],
      "view": "view-east",
      "volume": {"crop": [-4200, 13500, -700, 6500], "depth": [0, 30000], "direction": [-1, 0], "kind": "elevation", "margin": 1, "origin": [14000, 0]}
    }
  ]
}

The prototype's viewport held 123 pairs in read and 23 in inVolume. At P01 the window's hash was 2ea87a7a92fabbdbd598ac1235a0572ac30a900e42dd1811aa1b284ce14c86fd, its hash in examples/l-house.

9.3 The view volume and element boxes

The volume is where a view can show something:

  • a plan: its crop, in plan, and in height everything that starts below its cut plane (the level's elevation plus cutHeight, or the view range's cut), up to the top of its view range where it draws above the cut;
  • a section or an elevation: its crop across (u along the right normal of direction, v up), and from its origin's plane to far behind it;
  • a dependent view: its primary's range, as the reference implementation's src/core/views/viewInheritance.ts gives it;
  • a 3D view: the whole model, so that its viewport is stale when any element changes, enters or vanishes: a false alarm at times, never a miss.

A checker gives each element a box that holds every line any conforming generator draws for it: the bodies that a core compiler derives (Part IV), grown 150 mm across and 100 mm up and down for the joins that it does not derive; a door or a window, from its host wall's line, along, width, offset and height, across the wall's thickness plus 100 mm and a door's swing; a slab edge or a gutter, from its host; a railing on a stair, whose line follows the stair's flights and whose profile gives no heights (Part II, 12.2, rule 4), across its profile and the stair's, and up from the stair's base to its top (Part IV, 5.1) and the railing's height over it; a beam of a framing family, from every point of its parts as the family's expressions place them over its set-out line (Part II, 5.4), swept across by their widths; and any other element from its profile and its sizes, grown 50 mm. An element of a category that the checker cannot box is taken to be in every volume of its level's views: a false alarm, never a miss. So is a room, whose drawing (its name, area and fill) reaches across its whole boundary; and so is a placed copy (Part II, 10): the elements of a copy are derived, <copy id>/<element id>, and the copy's record is in every volume of the views of its original's level. A view's direction is a direction only: a checker uses it as a unit vector, whatever its length.

9.4 Freshness

A revision is checked against a version of the line of work it tracks (source.ref), or against any version a caller names, such as a proposal's head. In order:

  1. Same tree. Where the version's root tree hash equals source.root, and the generator is the same, the revision is current.
  2. Sheet. Where a pair of sheet has a path that holds a different hash now, or none, the whole drawing is stale. So is it where sheet holds the pair of a sheet record other than the drawing's own (derivation.sheet.id), as a sheet that lists or counts the project's sheets does (9.1), and the version holds a sheet record whose path sheet does not hold: that sheet entered, since such a list would now name it. This too is a dependency on absence, as in step 4. And where sheet holds a view's pair, as a register's does, a detail chunk of that view that sheet does not hold is new since the issue: changed, as in step 3.
  3. Read. In each viewport, where a pair of read or inVolume names a record that changed or vanished, or the viewport's view has a detail chunk that read does not list, that viewport is stale. An element that was in the volume, undrawn, counts only when it changed.
  4. Entered. In each viewport, an element whose box now meets the volume, and whose path is in neither read nor inVolume, entered it, and the viewport is stale: this is a dependency on absence.
  5. Checked. Where steps 2 to 4 found something, a candidate drawn with the recorded generator, whose every element group and annotation group has the issued data-eik-hash and bytes, makes the revision checked at that version: current, with no new revision. An element's groups are compared by viewport, element and part: where an element has parts (6.7), the candidate holds each of its issued parts, with the same bytes, and no other. Where the derivation's generator.order is paint, each layer's groups also come in the same order: in paint order, a group that moves behind another is drawn differently with the same bytes. Without a candidate, it stays stale.
  6. Generator. A checker that knows the generator that would draw now (a candidate's derivation, or what the caller names), and finds that it differs from derivation.generator or fonts, reports wouldDrawDifferently: a state of its own, never a change of the model, and never clouded as a design change without a person's decision. Beside a stale verdict it is reported apart.

In steps 2 to 4 a path is compared by the record it names (9.2): a record that only moved, as the change of layout of Part III, 4.4 moves records, its hash the same, has not changed, and is held where read or inVolume holds its path before the move. A revision issued before the change of layout is therefore current after it, until a record it read changes.

The verdicts are current, checked, stale (with its causes: for the sheet and for each viewport, the paths that changed, vanished and entered), wouldDrawDifferently, and unlinked (no read set: not worked out). Freshness is derived, and never stored (section 16).

9.5 Which viewport, and which elements (informative)

A cause is matched to the sheet, or to the viewport whose list holds its path. Within a viewport, the elements whose drawing may change are the changed and entered elements it holds (direct), and the elements of its read one reference away from them (Part II, 7, and 3.1 here): a wall hosting a moved window. In the prototype this predicted every element whose drawing changed, and over-predicted the wall in two facades where its drawing did not change.

9.6 The prototype's evidence (informative)

On the L-house (130 elements, 13 views, 4 sheets), after study-window-east moved 500 mm, hashes alone flagged A-101 and A-104 as stale in about 20 ms warm (84 ms cold, 68 of them reading and hashing the model), and missed nothing; drawing them again took 0.47 s in the reference implementation's engine; and A-102 and A-103, which do not show the window, came out byte-identical. Of A-101's six viewports, three (the south, north and west facades) were false alarms, which the engine's own culling or a candidate clears. A column created on a scratch copy flagged nine viewports, eight of which drew it: no miss, and one false alarm. Each sheet drew the same bytes twice.

9.7 Rules

  1. The read set MUST validate against its schema; its drawing MUST be its revision's, and its sequence the revision's, or, for a change of status alone (8.2), that of the revision whose drawing it keeps; each list MUST be sorted by path, each path once.
  2. viewports MUST hold exactly the derivation's viewports, by id and view.
  3. A viewport's read MUST hold the pair of every element drawn in it (each id of its data-eik-id), of its view and of each of its view's detail chunks.
  4. A viewport's read MUST hold the type of each element drawn, and the sheet's list MUST hold the sheet record, its title block, the project, the levels and the drawing profile. The rest of 9.1 is the issuer's to meet.
  5. inVolume MUST hold, with their hashes, the elements that the volume test held at the source version and that read does not.
  6. A revision MUST be current against its own source version: one that its own source version makes stale has an incomplete read set.
  7. A checker's boxes MUST hold every line any conforming generator draws for the element (9.3).
  8. A checker MUST NOT report a revision current or checked when step 2, 3 or 4 of 9.4 finds a cause, and MUST name each cause.
  9. A checker MUST report a change of generator alone as wouldDrawDifferently, never as stale.
  10. A checker MAY report checked only from a candidate drawn with the recorded generator (9.4, step 5).

10. Change items and revision clouds

10.1 Change items

changes, in the revision record, holds change items: {id, what, by, elements?, viewports?}. id is unique in the revision (chg-1). what, 1 to 400 characters, is the description that the revision table and the change memo show, and that a host shows first under what changed: it names elements as people know them, by their names, never by their ids ("East window moved 500 mm", not "study-window-east moved 500 mm"). by says who wrote it: person; agent, drafted from the field-level diff of the records, which the person issuing accepts by issuing; or derived, from a template. elements names the elements whose drawing it describes, and viewports where they are (or sheet). The items are recorded whether or not clouds are drawn, so that a viewer can still show what changed.

10.2 Clouds, per update

The profile sets a default for each status (statuses[].clouds); the person issuing switches clouds on or off for any update (clouds on or off); and where the changes cover most of the sheet, the tool proposes throughout, a note "revised throughout" in the revision row instead of a sheet of clouds (the steward's refinement of 15 October 2026). Clouds follow the visible change, not elements' boxes: in the prototype, boxes round the changed elements covered 4 821 mm² of the east facade where the visible change fitted in 672 mm², and in the section the change was invisible and needed no cloud. At asBuilt, the profile removes them. A cloud is a closed path in the revisions layer, in paper mm, with data-eik-rev, data-eik-change and data-eik-viewport, beside its revision mark, a triangle with the code. Where the profile's keepEarlierClouds is false, only this revision's clouds remain.

10.3 Rules

  1. Every data-eik-change of the revisions layer MUST name a change item of the revision, and every data-eik-viewport there a viewport of the sheet or sheet.
  2. Change item ids MUST be unique in the revision.
  3. With clouds off or throughout, the revisions layer MUST hold no cloud of this revision.
  4. With keepEarlierClouds false, the revisions layer SHOULD hold only this revision's clouds.
  5. Clouds SHOULD enclose the visible change, and none SHOULD mark a change that is not visible.
  6. An element whose data-eik-hash differs between the superseded revision's SVG and this one's (any of its parts', where it has parts), or that is in one only, SHOULD be in a change item's elements.

11. The register

11.1 The file

drawings/register/<drawing>.json is append-only: every snapshot ever taken of one drawing. A host lists the registers of a line of work as its drawing register.

MemberMeaning
formatrequired"openeik-drawing-register/0.1"
drawingrequiredthe number
kindrequiredlinked or unlinked
entriesrequiredthe events, oldest first

An entry is one of:

  • {event: "issued", sequence, revision, date, state, sharedFor?, status, record, svg?, derivation?, asset?, source?, by?}: a revision. record is its revision record's hash; svg its SVG's digest and derivation its derivation's hash, for a linked drawing, or asset its file's digest, for an unlinked one; source, {version, root}, what it was drawn from, so that the history finds its files; and by, who issued it, as its revision record's by (8.5, rule 12), so that a sheet's revision table can sign each of its rows from the register;
  • {event: "rendition", sequence, asset, standard, signed}: a PDF rendition kept as an asset (section 15);
  • {event: "withdrawn", date, by, reason?}: the drawing's end. Its last revision stays in the folder.

Superseded is implied: each issued entry supersedes the one before. The issuer adds the entries, in the model; a host never writes the register. Two lines of work that issue the same drawing meet here when they are merged, as a conflict of the register, which a person settles by issuing again from the merged line.

11.2 Example

A-101 after P02:

{
  "drawing": "A-101",
  "entries": [
    {
      "date": "2026-10-15",
      "derivation": "<hash>",
      "event": "issued",
      "record": "<hash>",
      "revision": "P01",
      "sequence": 1,
      "sharedFor": "review",
      "source": {"root": "44562e74bd618479c947bce600227e538cf3bed05cf573bf76947a27884e12b6", "version": null},
      "state": "shared",
      "status": {"code": "S3", "profile": "example"},
      "svg": "742dadf029a3a787dd9589bc1ba00f3d1e0fc157b0584246e81d08e1e7db2efe"
    },
    {
      "date": "2026-10-15",
      "derivation": "<hash>",
      "event": "issued",
      "record": "<hash>",
      "revision": "P02",
      "sequence": 2,
      "sharedFor": "review",
      "source": {"root": "6b572fb1e20adea6f4d012a31588f32aef0dc7995796d2630497fb3f74e1f378", "version": null},
      "state": "shared",
      "status": {"code": "S3", "profile": "example"},
      "svg": "7e7e0bbe28f97181127a5e2b7f624004ae6848f9ae322eb81d68c82c018fa05c"
    }
  ],
  "format": "openeik-drawing-register/0.1",
  "kind": "linked"
}

11.3 Rules

  1. The register MUST validate against its schema.
  2. Entries MUST be in order: each issued entry's sequence is the one before's plus 1, from 1; a rendition names a sequence already issued; nothing follows withdrawn.
  3. The last issued entry MUST be the drawing's folder: its sequence, record and svg (or asset) MUST be the current revision's, and its by, where it gives one, the current revision record's by.
  4. A later version's register MUST hold every entry of an earlier version's, unchanged and in order.
  5. kind MUST be the kind of every revision of the drawing; a linked entry MUST give svg, derivation and source, an unlinked one asset.
  6. An unlinked drawing MAY be registered, reviewed and issued as any other (8.3).

12. Issues

12.1 The file

drawings/issues/<issue>.json is a transmittal: the release of revisions to recipients for a purpose (D9).

MemberTypeMeaning
formatrequired"openeik-drawing-issue/0.1"
idrequiredPart I, 6, minted without coordinationthe file's name: a random id such as a ULID, or one derived from the record's content, which a deterministic issuer needs
purposeoptional{profile, code}a purpose of the profile
sentrequired{by, at}who sent it, a person of the registry, and when; where only the day is known, at is midnight UTC of that day
revisionsrequired unless versions is givenlist, 1 to 10 000{drawing, sequence, revision, record}: the revisions released, each by its revision record's hash
versionsoptionallist, 1 to 20the versions of the model released, each by its root tree hash (Part XVIII, 3.1)
renditionsoptionallist, at most 10 000the prints sent with it, each by its digest, and kept nowhere (Part XVIII, 3.1)
termsoptionallist, at most 20the terms it is sent under, by their digest (Part XVIII, 3.1)
recipientsrequiredlist{person}, a person of the registry, or {name, organisation?} for someone outside it; never an email address
noteoptionalstring, at most 2000 characters

An issue releases revisions, versions of the model or both. versions, renditions and terms are Part XVIII's (its section 3.1), which says what they mean and how they are checked.

Delivery, links and read receipts are the host's, and stay there. The authoring tool writes this file once, when it issues, and it is not changed after. A host that then sends the issue, once or several times, and to recipients the file may not name, keeps its sendings, and offers each recipient's as a receipt (Part XVIII, 5), which the authoring tool saves beside the issue, as it saves reviews (section 13) and sign-offs (14.4). A host never writes the model.

{
  "format": "openeik-drawing-issue/0.1",
  "id": "iss-01jc4p7v2m",
  "purpose": {"code": "S3", "profile": "example"},
  "recipients": [
    {"person": "person-k2m9xa"},
    {"name": "Site manager", "organisation": "Main contractor"}
  ],
  "revisions": [
    {"drawing": "A-101", "record": "<hash>", "revision": "P02", "sequence": 2},
    {"drawing": "A-104", "record": "<hash>", "revision": "P02", "sequence": 2}
  ],
  "sent": {"at": "2026-10-15T14:00:00Z", "by": "person-k2m9xa"}
}

12.2 Rules

  1. The file MUST validate against its schema, and its id MUST be its name read back.
  2. Each revision it lists MUST be in its drawing's register, with that sequence and record.
  3. purpose, where given, MUST be a code of the profile's purposes.
  4. It MUST list each drawing once.
  5. Recipients and sent.by MUST follow 5.2, rules 2 and 3.
  6. An issuer SHOULD write one issue record each time it issues one or more revisions together: the revisions, the purpose, sent.by and sent.at, and the recipients where it knows them. A host that lists what was released together reads these records.

13. Reviews

A review is a round on one revision, as structured data. A host keeps reviews and their working state; at the close it offers the review in this file, and the authoring tool saves it into the model with the next revision it issues, so that the folder holds the conclusion.

13.1 The file

drawings/reviews/<review>.json:

MemberTypeMeaning
formatrequired"openeik-drawing-review/0.1"
idrequiredPart I, 6unique without coordination across hosts and forks, such as a ULID, and never a host's sequence number; the file's name
drawing, sequence, revisionrequiredthe revision reviewed
svg (linked) or asset (unlinked), and recordrequireddigeststhe SHA-256 of drawing.svg, or of the unlinked drawing's asset, and the hash of revision.json, as reviewed
comparedoptional{sequence, revision, record}the revision the round compared it with
profilerequired{id, code?, purpose?}the drawing profile, and the status or purpose code the round reviewed for
openedrequired{by, at}
dueoptionaldate
closedoptional{by, at}absent while the round is open
reviewersrequiredlist{person, role, decision?}: role is a plain value, and decision, {code, at}, a code of the profile's decisions (decision A or B)
itemsrequiredlist (13.2)

13.2 Items, anchors and states

An item:

MemberMeaning
idrequiredunique in the review
kindrequiredcomment, cloud, arrow, text, measure or highlight
authorrequired{person}, or {agent: {name, version}, actingFor, acceptedBy?, acceptedAt?}: an agent's item counts for nothing until a person accepts it
atrequiredwhen it was made
textoptionalat most 4000 characters
repliesoptional[{author, at, text}]
staterequireda code of the profile's reviewStates
historyoptional[{state, by, at}], oldest first
anchorsrequired, and may be emptytried in order: {element, feature?, viewport, position?}, an element the revision draws (data-eik-id), a named feature, the viewport, and a position [s, t] in the feature's frame
sheetrequired{x, y, page?}: the fallback, in mm of paper from the sheet's top-left corner; page, counted from 1, for an unlinked drawing's PDF of several pages
shapeoptional{points, closed?, form?}, in paper mm: the geometry of a cloud, an arrow, a highlight or a measure, or the frame that holds a text's or a comment's words, as a text box has one. A measure's value is derived from its points and the viewport's scale. form says how the points are drawn (below)
anchorStaterequired when the round is closedattached, moved, elementOnly or orphaned, as at the close
changeoptionalthe change item of the revision that the item is about
carriedFromoptional{review, item}: the item of an earlier round that it carries forward
bcfoptionalthe GUID of its BCF topic, for round trips
attachmentsoptional[{asset, mediaType}]: files kept as assets by digest, photographs for example. They are personal data, kept in every version that holds them (Security and privacy, 2.4)

Shapes. Added with open question 61, from plan 688: an item's kind says what it means, and its shape's form how it is drawn, so that a markup keeps its form from one application to another.

  • freehand: a stroke of a pen, drawn straight between points taken close together;
  • polyline: straight between its points, open;
  • polygon: straight between its points, closed;
  • rectangle: four points, the corners of a rectangle in order, which may be turned;
  • ellipse: the ellipse that fills the rectangle of its four points, its axes along the rectangle's sides.

Without form, the points are drawn straight, closed where closed is true, as before. A reader that does not know form draws them so: a rectangle then draws as itself, and an ellipse as the rectangle that holds it. Colour, line weight and the other matters of style are no member of an item: an application keeps its own as extension members under its prefix (Part I, 11.2), stomra:color for one, which every reader keeps.

Seen ticks, read receipts and each person's progress are the host's, and stay out of the file. The six review states of BEAst Effektivare granskning 2.0 (new, rejected, to act on, acted on, needs new review, elsewhere) are the Swedish default of an authoring tool's profile, not a list of the standard.

13.3 Example

A round on A-101 P02, compared with P01, with one comment on the moved window:

{
  "compared": {"record": "<hash>", "revision": "P01", "sequence": 1},
  "drawing": "A-101",
  "format": "openeik-drawing-review/0.1",
  "id": "rv-01jc4n2x8q",
  "items": [
    {
      "anchors": [{"element": "study-window-east", "viewport": "study-viewport-4"}],
      "at": "2026-10-15T15:02:00Z",
      "author": {"person": "person-r4t8wd"},
      "change": "chg-1",
      "id": "i-1",
      "kind": "comment",
      "sheet": {"x": 392.67, "y": 334.67},
      "state": "new",
      "text": "Check the sill height after the move."
    }
  ],
  "opened": {"at": "2026-10-15T14:05:00Z", "by": "person-k2m9xa"},
  "profile": {"code": "S3", "id": "example"},
  "record": "<hash of revision.json>",
  "reviewers": [{"person": "person-r4t8wd", "role": "checker"}],
  "revision": "P02",
  "sequence": 2,
  "svg": "7e7e0bbe28f97181127a5e2b7f624004ae6848f9ae322eb81d68c82c018fa05c"
}

The sheet position is the window's place on the east facade at P02, from the prototype's boxes.

13.4 Rules

  1. The file MUST validate against its schema, and its id MUST be its name read back.
  2. drawing, sequence, svg or asset, and record MUST name a revision in the drawing's register, by its digests.
  3. profile.id MUST be the profile's; every item's state and every state of its history MUST be a code of its reviewStates; every decision.code MUST be a code of its decisions.
  4. An item's anchors SHOULD name elements the reviewed revision draws, and viewports of its sheet.
  5. A closed review MUST be frozen: no item, reply, state or decision is later than closed.at, and a later version holds the file unchanged.
  6. carriedFrom SHOULD name an item of another review of the same drawing, where the folder holds it.
  7. change SHOULD name a change item of the reviewed revision.
  8. The people it names MUST follow 5.2, rules 2 and 3.
  9. A shape's form polyline MUST NOT be closed, and polygon, rectangle and ellipse MUST be; a polygon MUST have three points at least, and a rectangle or an ellipse exactly four, the corners of a rectangle in order: the midpoints of its two diagonals within 0.01 mm of each other, and their lengths within 0.01 mm.

14. Sign-offs

"A named person approved this exact drawing with this status" is a statement about digests, signed apart from the files, so that signatures never change a drawing's bytes, and several people can sign in turn (D4). Signing is optional, and scales with the stage: the profile says which statuses need which sign-offs (requires). A sketch shared for information needs none, and still gets its derivation and read set, at no cost to anyone.

14.1 The statement

A sign-off's statement is an in-toto Statement v1:

  • _type: https://in-toto.io/Statement/v1;
  • subject: exactly two, each {name, digest: {sha256}}: drawings/issued/<drawing>/drawing.svg, with the SHA-256 of its bytes, and drawings/issued/<drawing>/revision.json, with its hash (Part III, 6); for an unlinked drawing, its asset in place of the SVG;
  • predicateType: https://openeik.org/attestation/drawing-signoff/v0.1;
  • predicate:
MemberMeaning
drawing, sequence, revisionrequiredthe revision signed
statusrequired{profile, code, purpose?}: the revision's
actionrequiredchecked, reviewed, approved, authorised, accepted, rejected, withdrawn or checkedByTool
rolerequiredthe role in which the signer acts, a plain value (approver)
signerrequireda person of the registry
modelrequired{version, root}: the derivation's source
atrequiredthe signer's own time; the time-stamp's is the trusted one
decisionoptionala code of the profile's decisions, where the action is a decision (approved, rejected, authorised, accepted)
reviewoptional{id, hash}: the closed review round that the sign-off concludes
withdrawsrequired for withdrawnthe hash of the sign-off file it withdraws
evidenceoptionalfor checkedByTool: {path, hash} of a result manifest (Part VI, 8) that holds what the tool found
{
  "_type": "https://in-toto.io/Statement/v1",
  "predicate": {
    "action": "approved",
    "at": "2026-11-12T09:14:00Z",
    "decision": "approved",
    "drawing": "A-101",
    "model": {"root": "6b572fb1e20adea6f4d012a31588f32aef0dc7995796d2630497fb3f74e1f378", "version": null},
    "revision": "P02",
    "role": "approver",
    "sequence": 2,
    "signer": "person-k2m9xa",
    "status": {"code": "S3", "profile": "example"}
  },
  "predicateType": "https://openeik.org/attestation/drawing-signoff/v0.1",
  "subject": [
    {"digest": {"sha256": "7e7e0bbe28f97181127a5e2b7f624004ae6848f9ae322eb81d68c82c018fa05c"}, "name": "drawings/issued/A-101/drawing.svg"},
    {"digest": {"sha256": "<hash of revision.json>"}, "name": "drawings/issued/A-101/revision.json"}
  ]
}

14.2 The file

drawings/issued/<drawing>/signoffs/<n>.json holds one signer's action:

MemberMeaning
formatrequired"openeik-drawing-signoff/0.1"
enveloperequireda DSSE envelope: payloadType application/vnd.in-toto+json; payload, the statement's JSON in base64; and signatures, [{keyid, sig, webauthn?}], over DSSE's pre-authentication encoding. webauthn, {authenticatorData, clientDataJSON} in base64url, is given where a passkey signed (14.7, rule 9)
timestampsrequired[{keyid, token}]: for each signature, an RFC 3161 time-stamp token (the base64 of its DER) whose message imprint is the SHA-256 of the signature's bytes
legaloptional{asset, sha256}: the container of the legal tier (14.6)

<n> SHOULD be s- followed by the first 12 hexadecimal digits of the envelope's hash, as run ids are made (Part VI, 8.5): two people signing on two lines of work never take one name.

14.3 Verifying offline

A verifier checks the SVG profile and the canonical form (section 6); the records (sections 8 and 9); that every data-eik-id resolves at the recorded version; and, optionally, that drawing the sheet again gives the same bytes. Then, for each sign-off, it checks the DSSE signature with the registry's key, the time-stamp and its imprint, the key's window of validity at the time-stamp's time, the subjects' digests against the files, and the predicate type, explicitly. A verifier needs the folder and the time-stamp authority's certificate, and no host.

14.4 Where sign-offs come from

An authoring tool writes sign-offs, or saves the ones a host made: a host keeps sign-offs and verifies them, and never writes the model. The approver signs the digests of the exact files that will be issued, shown as they are, so that what was reviewed is what is issued. A sign-off whose subjects are an earlier revision's signs that revision: it is saved in the same signoffs/, and checked against that revision's entry in the register.

14.5 Agents and tools

An agent signs with its own registered key (a record of the registry of the kind agent), and only checkedByTool: it never signs an approval or any other decision (D7). This keeps the principle that only a named person approves, which is not that only a person signs. What the tool found belongs in a result set (Part VI, 8), which the statement names as evidence; the statement says only that the tool checked these exact digests.

14.6 The legal tier

Where the client or the law asks, the same statement and files are signed as an ASiC-E container with XAdES (B-LTA when archived), with a qualified or advanced signature made through a federated signing service, and the PDF rendition with PAdES if the recipient asks (D4). The container is an asset (legal). Validating it needs an ETSI validation report (TS 119 102-2), outside the library. Its details wait for a legal review.

14.7 Rules

  1. The file MUST validate against its schema; its envelope's payloadType MUST be application/vnd.in-toto+json, and its payload MUST decode to an in-toto Statement v1.
  2. predicateType MUST be https://openeik.org/attestation/drawing-signoff/v0.1, and the predicate MUST validate against its schema.
  3. The subjects MUST be exactly two, by path the drawing's drawing.svg (or the unlinked drawing's asset) and revision.json, with the digests of a revision in the drawing's register: the svg (or asset) and record of the issued entry whose sequence the predicate names.
  4. The predicate's drawing, sequence, revision and status MUST be those of the revision it signs: the register's issued entry of that sequence.
  5. signer MUST name a person of the registry, and each signature's keyid a key of that record.
  6. A signer of kind agent MUST sign only checkedByTool, and a person MUST NOT sign checkedByTool.
  7. decision, where given, MUST be a code of the profile's decisions; it SHOULD be given for approved, rejected, authorised and accepted.
  8. Every signature MUST have a time-stamp. The schema states this rule.
  9. Each signature MUST verify with its key; its time-stamp MUST verify, and its imprint MUST be the signature's SHA-256; and the key MUST have been valid at the time-stamp's time. With webauthn (a passkey): clientDataJSON's type MUST be webauthn.get and its challenge MUST be base64url of the SHA-256 of DSSE's pre-authentication encoding; authenticatorData's rpIdHash MUST be the SHA-256 of the key's rpId, and its user-present flag MUST be set (user-verified SHOULD be set for decisions); sig MUST verify over authenticatorData ‖ SHA-256(clientDataJSON). The time-stamp's imprint stays the SHA-256 of sig.
  10. A withdrawn statement's withdraws MUST name a sign-off of the same revision, by the same signer.
  11. review, where given, MUST name a closed review of the same revision by its hash.
  12. The sign-offs that the profile's requires asks for the revision's status SHOULD be present and not withdrawn.
  13. The file's name SHOULD be made as 14.2 says.

15. The PDF rendition

15.1 What it is

At issue, a PDF/A-3b is made from the issued SVG (D6): at exact scale, its page the sheet's paper, its hatches as vectors, tagged, and byte-reproducible, with a fixed date (the revision's) and an identifier derived from the content. The SVG is attached with the relationship Source and the media type image/svg+xml; revision.json and read-set.json with Data; and the sign-off files that exist with Supplement, as e-invoices carry their XML. Attach first, then sign: a PAdES signature then covers the attachments. A recipient without OpenEik opens a normal PDF; one with OpenEik takes the source-mapped SVG out of it and checks it. A rendition is reproducible, so it is kept only when it is signed, as an asset that a rendition entry of the register names; otherwise a host makes it on demand.

15.2 Rules

  1. A rendition kept in the folder MUST be an asset assets/<sha256>.pdf, named by a rendition entry of its drawing's register.
  2. It MUST be PDF/A-3b; its page MUST be the sheet's paper; it MUST carry the attachments of 15.1 with their relationships and media types.
  3. Each attachment MUST be byte for byte the issued file.
  4. The same issued files, renderer version and fonts SHOULD give the same bytes.
  5. A writer SHOULD NOT keep an unsigned rendition: it is derived (section 16).

15.3 The margin note

By the steward's decision of 25 October 2026 (plan 688, decision 6), a PDF says on its paper what it is a copy of. A rendition is a print: it is never the record, and two renditions are never compared to find what changed; the revisions they were printed from are (Part XVIII, 7.1). A rendition made at issue, and one printed again later on demand, carry the same note.

  1. A rendition MUST carry a margin note below the drawing frame, in the bottom margin of its page, over nothing the issued drawing draws.
  2. The note MUST name, in one or two lines, the drawing's number and revision code, the building (its project's name, or its id), and the version the revision was drawn from (the derivation's source.root, of which its first 12 hexadecimal digits are enough), and MUST say in a sentence that the print is a copy, as paper is. It MAY also name the revision record's hash.
  3. The note MUST carry a QR code, at the bottom right corner of the page on a white square, that encodes a URL naming the revision by its SVG's SHA-256 (the revision record's svg.sha256), or an unlinked drawing by its asset's, at which a host answers whether that revision is current. The rest of the URL is the host's.
  4. The note MUST hold no time of printing, and nothing that differs by the person who prints or reads it, so that rule 4 of 15.2 holds: every date the file holds (its creation and modification dates, its document information dictionary, its XMP metadata and its attachments' dates) MUST be the revision's date, and the file's identifier MUST be derived from the building, the version and the SVG's digest (or the asset's). A PDF of several revisions, such as an issue's sheets printed as one, carries on each page the note of that page's revision; every date it holds MUST be the latest of its revisions' dates, and its identifier MUST be derived from the building, the versions and every revision's SVG digest (or asset's). A PDF of one revision stays as this rule says.
  5. The host or application that prints MAY name itself as the PDF's creator and producer, and in the check URL of rule 3, as an IFC print names who printed it (Part XVIII, 7.2, rule 4). The note's own words SHOULD NOT name it: they say what the print is a copy of, which is the same whoever prints it. So one revision printed by two hosts differs only in those names and that URL.

16. What is derived, and the stated exception

16.1 Derived, and never stored

These are derived, and never stored (Part IV, 1):

  • the live drawing of a view or a sheet, and every preview, thumbnail and cache (.eik/drawings/, hidden);
  • candidates: drawings drawn again from a later version or a proposal, to check freshness or to show a change;
  • freshness verdicts and their causes (9.4), and the impact of a proposal;
  • comparisons of two revisions, element by element, and descriptions made from them, until a person writes one into a change item;
  • dimension values and tag texts, worked out when drawn: an issued SVG holds them as drawn;
  • anchor states (3.3), worked out when drawn: an issued SVG records them;
  • an unsigned PDF rendition, and an SVG made from an outside PDF for viewing;
  • every other print: a PDF printed from a revision on demand, and an IFC exported from a version (Part XVIII, 7). A print is a copy, like paper: never the record, and never compared to find what changed;
  • the register as a host lists it, from the register files.

16.2 The stated exception

Issued drawings are derived data that the folder keeps: a deliberate exception to "derived data is never stored" (Part IV, 1, rule 2), as a release keeps its built binaries (D2). The exception is narrow. An issued drawing is written only when someone takes a snapshot, it is never changed, and it is never read as model data: no record is derived from it, and no compiler reads it.

17. Commands and operations (reference behaviour)

17.1 Commands

Commands are Part V's:

  • sheet.upsert and sheet.delete move from the application records of the reference vocabulary (Part V, 2.3) into the documentation profile (Part V, 2.2), on the sheet of section 2. sheet.upsert keeps its precondition: a new sheet counts as revision 0 (Part V, 3, rule 2). view.delete is still refused while a sheet uses the view (Part V, 5, rule 4). Deleting a sheet never touches its issued drawing: the issuer withdraws the drawing, with a withdrawn entry in its register.
  • person.upsert writes a person whole (expectedRevision optional; a new person gets revision 0). No command deletes a person that a file of this part names, and a key is ended, not removed (5.2, rule 5).
  • detail.place, detail.update and detail.draw carry provenance as a member of the item, and a processor keeps it. A processor that knows its caller is an agent (by the command envelope of Part XVII) writes by agent and status proposed, and refuses status accepted from an agent.
  • Deletes are Part V, 5's: in the live model, an element's items go with it. Issued drawings are not records, and no command changes them.

17.2 The issue operation

Issuing is not a command: issued files are not records, as results are not (Part VI, 8). An issuer, at a version V of the line of work:

  1. refuses while a view placed on the sheet holds a proposed agent's item (3.4, rule 4);
  2. draws the sheet with its generator from V, and SHOULD draw it twice and compare the bytes, as the prototype did for every sheet;
  3. compares each element's data-eik-hash (each part's, where it has parts) with the superseded revision's, and joins the result with the field-level diff of the records, to propose change items;
  4. draws clouds as the update's choice says (10.2), and the revision row;
  5. writes drawing.svg, read-set.json and revision.json together, replacing the superseded revision's files; the sign-offs stay;
  6. appends the issued entry to the register;
  7. writes one issue record for the revisions it issued together (12.2, rule 6);
  8. records a version, so that the files are in the history: nothing issued is lost.

Sign-offs, reviews and issues are written as they come, by the authoring tool, which saves the files a host offers. In the reference implementation the issue operation is to be its "Issue", which writes canonical SVG and records into the folder instead of hashing and discarding the SVG.

17.3 The library

@openeik/tools, dependency-free like the rest of it, implements this part:

  • checkFolder(…, { proposals: ["drawings"] }) and openeik check --proposal drawings: every rule that the folder decides, and those that need the records concerned unchanged since the issue, where they are (19.2);
  • openeik drawing status <folder> [--generator <name>@<version>] [--candidate <dir>]: the freshness of every issued drawing against the folder (9.4);
  • openeik drawing impact <folder> --against <folder | version>: which issued drawings a later state or a proposal makes stale, with the causes and the elements likely to change (9.5);
  • openeik drawing diff <a.svg> <b.svg>: element by element, by data-eik-hash (part by part, where an element has parts: changed where any part differs, added or removed where all its parts are), and the annotations by data-eik-item;
  • openeik drawing verify <folder> [<drawing>] [--history]: 14.3, with DSSE and RFC 3161 verification; the legal tier is reported as not verified;
  • openeik drawing register <folder>: the register of a folder, its current and superseded revisions;
  • openeik drawing bcf <folder> <review> [--out <file.bcf>]: a review as BCF 3.0 (18).

A DSSE signature, Ed25519 or ECDSA P-256, verifies with the runtime's own cryptography. An RFC 3161 token needs a small DER reader, and the time-stamp authority's certificate as a trust anchor that the caller gives: both are in verify, not in checkFolder.

17.4 Agents

In Part VII: an agent host SHOULD offer an operation that answers, in one call, which issued drawings a version or a proposal makes stale, and why, and one that lists which issued drawings draw an element (a search of data-eik-id).

18. IFC and BCF (informative)

This section is informative, as Part VIII is. It says how a bridge can export issued drawings to IFC, and reviews to BCF.

  • Documents. IFC has no sheet and no entity for an issued drawing. An issued revision exports as an IfcDocumentInformation: Identification the drawing number, Name the title, Revision the revision code, ElectronicFormat image/svg+xml (or application/pdf for an unlinked drawing), Location the file's path in the folder, CreationTime the date of issue, and Status mapped coarsely, draft and shared to FINALDRAFT and published and asBuilt to FINAL: IFC's IfcDocumentStatusEnum has only DRAFT, FINALDRAFT, FINAL and REVISION, besides NOTDEFINED.
  • What it shows. An IfcDocumentReference to it, associated by IfcRelAssociatesDocument with each element the revision draws (its data-eik-ids).
  • Sign-offs. Each sign-off as an IfcApproval (Level the status code, Qualifier the conditions of a B decision, GivingApproval the signer, TimeOfApproval the time-stamp's time), related to the document by IfcResourceApprovalRelationship. The OpenEik files stay richer than IFC: the export does not carry signatures.
  • Annotations. Issued drawings are documents, not IfcAnnotations. A bridge that exports views may write their detail items as IfcAnnotations; 0.1 and this part specify none.
  • A model's reviews (Part XVIII, 2) are on a version in 3D, and map onto BCF more directly than a drawing's (Part XVIII, 2.6).
  • Reviews export as BCF 3.0 topics. BCF's viewpoints are 3D, so a topic carries the element's 3D viewpoint and a document reference to the revision by its digest, and the item keeps the topic's GUID (bcf) for round trips. A 2D extension of BCF is an open question, and not this part's. @openeik/tools exports a review so (openeik drawing bcf): a topic for each item, its GUID the item's bcf or one made from the review's id and the item's, and its status the drawing profile's review state; the reviewed drawing as a document of the BCF file, named by its digest, where the folder holds it; and for an anchored item a viewpoint that selects its elements by their ids as AuthoringToolId (BCF's IfcGuid being optional), with the orthogonal camera BCF 3.0 requires, framing them as the anchor's viewport looks.

19. Conformance

A claim of conformance to OpenEik 0.2 is a claim to what this section asks of each class it names, its own two among them (Conformance, 1 and 1.1). A claim to 0.1 says nothing about it.

19.1 What 0.1 asks covers these files in a model of 0.1

A reader keeps the files as 1.5 says. A validator does not refuse them, may warn about the unknown members of detail items (Part I, 10, rule 2), and checks sheets against the application record's schema only. A writer never removes or rewrites them (Part III, 7, rule 3).

19.2 What each class of 0.2 does

Of 0.2, each class does as follows:

  • a validator checks the rules of this part that the folder decides, and those that need the records concerned unchanged since the issue (below) where they are. It reports a breach of a MUST as an error and a breach of a SHOULD as a warning (19.3), naming the file and the rule, as XIV.6.12.3;
  • a drawing validator, a class of this part, is a validator that also works out freshness (9.4; 9.7, rules 7 to 10), verifies sign-offs (14.3), and checks the rules that need the history where it has the history;
  • a drawing issuer, a class of this part, writes issued drawings: in the SVG profile (section 6), with the files, records and register of sections 7 to 11, a complete read set (9.1; 9.7, rule 6) and deterministic output (the same version and generator give the same bytes); it issues no drawing while a view placed on the sheet holds a proposed agent's item (3.4, rule 4), and never an SVG written by hand;
  • a reader reads sheets and people as records, and the drawing files as this part defines them;
  • a writer writes sheets and people at their paths, and keeps issued files as 7.4, rule 4 says;
  • a command processor implements 17.1;
  • a version store holds issued files and assets in its versions (7.3);
  • a bridge may follow section 18, which is informative.

The folder alone decides most rules. These need more:

  • the records concerned unchanged since the issue, their pairs in the read set equal to the model's: 3.4, rule 4; 6.12, rule 21, and the item that rule 23 names; 8.5, rule 2, for the sheet; and 9.7, rule 4, for the types. Where those records have changed, 3.4, rule 4 and 6.12, rule 21 need the history;
  • the history, an earlier version of the folder: 5.2, rule 5; 7.4, rule 4; 9.7, rules 5 and 6, unless the folder is the revision's source version; 10.3, rule 6; 11.3, rule 4; 13.4, rule 5, for the file held unchanged, and rules 4 and 7 where the reviewed revision is not the current one;
  • cryptography beyond hashing: 14.7, rule 9;
  • a PDF reader: 15.2, rules 2 and 3; 15.3, rules 1 to 4;
  • the generator or a renderer: 3.4, rule 6; 9.7, rules 7 and 10; 10.3, rule 5; and 15.2, rule 4. A validator does not check these; the conformance vectors show them.

19.3 The rules, by severity

A validator reports a breach of these rules as an error: 2.4, rules 1, 3, 6 and 7; 3.4, rules 2 to 5; 4.3, rules 1 to 3 and 5; 5.2, rules 1 to 5; 6.12, rules 1 to 3 and 5 to 25, and rule 27; 7.4, rules 2 to 6; 8.5, rules 1 to 7 and 11; 9.7, rules 1 to 6; 10.3, rules 1 to 3; 11.3, rules 1 to 5; 12.2, rules 1 to 5; 13.4, rules 1 to 3, 5, 8 and 9; 14.7, rules 1 to 11; 15.2, rules 1 to 3; and 15.3, rules 1 to 4.

It reports a breach of these as a warning: 2.4, rules 2, 4 and 5; 3.4, rule 1; 4.3, rule 4; 6.12, rules 4 and 26; 7.4, rule 1; 8.5, rules 8, 10 and 12; 10.3, rules 4 and 6; 13.4, rules 4, 6 and 7; 14.7, rules 12 and 13, rule 7 when a decision is missing, and rule 9 when a passkey's user-verified flag is not set for a decision; and 15.2, rule 5.

The other rules are permissions (8.5, rule 9; 11.3, rule 6); a requirement on issuers (12.2, rule 6); requirements on generators and checkers, which the conformance vectors show (3.4, rule 6; 9.7, rules 7 to 10); or rules on what is drawn and rendered, which a validator does not check (10.3, rule 5; 15.2, rule 4).

@openeik/tools checks this part for every model of 0.2, and for a model of 0.1 when asked: checkFolder(…, { proposals: ["drawings"] }), or openeik check --proposal drawings, and works out freshness and verifies sign-offs with openeik drawing (17.3). Its conformance cases are in the suite of 0.2 (conformance/). Besides the forms of 0.1's cases, a folder and the single-file form, they have two of their own: freshness, whose expected result gives each issued drawing's verdict and causes, and verify, which gives each sign-off's verification and the trust anchor it uses; and two classes of their own, drawing-validator and drawing-issuer.