Machine-readable organizational constitution with permanent citation identifiers. Root key is opencodelaw, resolving the historical three-way disagreement between the docs (OpenCodeLaw), the specs (openconstitution) and the renderer (ammendments). The amendment register is a separate document; see $defs/actRegister.
Schema: https://constitution.stmorg.in/schema/opencodelaw-1.0.schema.json
| Key | Type | Required | Notes |
|---|---|---|---|
opencodelaw |
"1.0" |
yes | Schema version. Quoted so YAML does not coerce it to a float. |
info |
info | yes | |
preamble |
preamble | yes | |
articles |
array of article | yes | Order is presentational only. Identity comes from id/number, never from array position, so reordering this list changes no citation and no anchor. min items 1 |
reconciliation_state |
reconciliationState | no |
Semantic version. A prerelease suffix is how a document states that it is mid-reconciliation: 3.0.0-alpha.1 is not 3.0.0.
Type: string — pattern ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-…
Stable Act identifier: act--, e.g. act-1-2024.
Type: string — pattern ^act-[1-9]\d*-[12]\d{3}$
Provision text. Must contain at least one non-whitespace character. An empty string is rejected: Article 11 published a blank body for two years because nothing checked this.
Type: string — pattern \S, min length 1
Records text that entered the constitution outside the amendment process. Its purpose is to preserve a half-amended state rather than erase it: an edit with no enacting instrument must be visible, not silently normalised.
| Key | Type | Required | Notes |
|---|---|---|---|
applied_outside_process |
boolean |
no | True when this text was hand-applied with no recorded amendment. |
matches_act |
actId | no | Act whose prescribed text this current text matches, where one was identified. |
recorded |
string (date) |
no | |
note |
string |
yes | min length 1 |
| Key | Type | Required | Notes |
|---|---|---|---|
title |
nonEmptyText | yes | |
organization |
nonEmptyText | yes | Full legal name of the body the constitution governs. |
jurisdiction |
string |
no | |
registration |
string |
no | Registration identifier under the governing statute. |
version |
semver | yes | |
status |
current | superseded |
yes | Exactly one document in the corpus may be current. |
legal_status |
legalStatus | no | |
adopted_version |
semver | no | The last version the board actually adopted. Required when legal_status is not_adopted. |
text_as_of |
string (date) |
no | The date the displayed text reflects, which is not the same as the date any instrument took effect. Required when legal_status is not_adopted. |
effective_from |
string (date) |
no | |
superseded_by |
semver | no | Version that replaced this one. Required in practice for archived pages, which must name their successor in a visible banner. |
logo |
object | no | no extra keys |
contact |
object | no | no extra keys |
termsOfService |
string (uri) |
no | |
license |
string |
no | |
instrument |
object | no | House style for rendered instruments: the wording an Act carries on its face. Content, not engine — an organisation adopting this repository replaces these and the renderer follows. no extra keys |
Conditional rules
- When
legal_statusisnot_adopted:adopted_version,text_as_ofbecomes required. Otherwiseeffective_fromis required.
| Key | Type | Required | Notes |
|---|---|---|---|
id |
"preamble" |
yes | |
title |
nonEmptyText | yes | |
title_source |
titleSource | no | |
content |
nonEmptyText | yes | |
adopted |
string |
no | |
amended_by |
array of actId | no | |
provenance |
provenance | no |
active (default when absent) carries text. reserved holds a number that no provision occupies — this is how a statute book represents a gap without renumbering. omitted marks a provision repealed by an Act; its number is never reused.
Type: active | omitted | reserved
| Key | Type | Required | Notes |
|---|---|---|---|
id |
string |
yes | Permanent citation identifier and public URL anchor. Treat as a public API: never regenerate, never derive from array position. pattern ^art-[1-9]\d*$ |
number |
integer |
yes | The number the Acts cite. Explicit, never derived from index. Article 21 is number: 21 even when it is the 20th element of the list. min 1 |
title |
nonEmptyText | yes | |
title_source |
titleSource | no | |
content |
nonEmptyText | no | |
status |
provisionStatus | no | |
note |
string |
no | Required for reserved/omitted: why this number carries no text. min length 1 |
amended_by |
array of actId | no | |
provenance |
provenance | no | |
sections |
array of section | no | min items 1 |
Conditional rules
- When
statusisreservedoromitted:notebecomes required;contentmust be absent;sectionsmust be absent. Otherwise at least one ofcontentorsectionsis required.
| Key | Type | Required | Notes |
|---|---|---|---|
id |
string |
yes | Permanent citation identifier, e.g. art-6-s-1. Must agree with the parent article's number and this section's number; validate.mjs enforces the relationship. pattern ^art-[1-9]\d*-s-[1-9]\d*$ |
number |
integer |
yes | min 1 |
title |
nonEmptyText | yes | |
title_source |
titleSource | no | |
content |
nonEmptyText | no | |
status |
provisionStatus | no | |
note |
string |
no | min length 1 |
amended_by |
array of actId | no | |
provenance |
provenance | no |
Conditional rules
- When
statusisreservedoromitted:notebecomes required;contentmust be absent. Otherwisecontentis required.
| Key | Type | Required | Notes |
|---|---|---|---|
acts |
array of act | yes | min items 1 |
| Key | Type | Required | Notes |
|---|---|---|---|
id |
actId | yes | |
origin |
bill | external-pdf |
no | How the Act entered the record. external-pdf means it was authored as prose and transcribed — the three 2024 Acts, whose history is not rewritten into the new format. bill means it was born from a bill file, which is the only path available for new Acts. |
bill_file |
string |
no | Repository-relative path to the bill this Act was rendered from. Required for origin: bill. |
signed_pdf_sha256 |
string |
no | Checksum of the signed instrument, so the archived PDF can be proved to be the one enacted. pattern ^[a-f0-9]{64}$ |
approvals |
array of object | no | Per-body tallies under Article 16(3). Recorded for Acts born from bills; the 2024 Acts predate the pipeline and carry only the procedure block. |
number |
integer |
yes | min 1 |
year |
integer |
yes | min 1900 |
title |
nonEmptyText | yes | |
short_title |
string |
no | |
application_status |
applied | partially-applied | pending |
no | How much of this Act the current constitution reflects. Observed state, not a legal determination: provisions records only what has been reconciled, and anything held is named in the constitution's reconciliation_state. |
assent_date |
string (date) |
yes | Date of assent, as stated on the face of the instrument. |
passed_date |
string (date) |
no | Date of passage, a distinct event from assent. One field cannot hold both. |
assented_by |
string |
no | |
signed_by |
string |
no | Who signed the instrument, as printed on it. |
moved_by |
string |
no | Who moved the Act. Leave unset rather than guessing. |
unverified_attribution |
string |
no | An attribution recorded elsewhere but unsupported by the face of the instrument. Preserved rather than deleted or promoted, pending confirmation. |
drafting_discrepancy |
array of object | no | Where an Act contradicts itself. Recorded, never silently normalised: a reader must be able to see that the instrument disagrees with itself and which text governs. |
procedure |
object | no | The approval chain the constitution required when the Act was passed. Left explicit and unpopulated where the evidence has not been located: an empty chain of authority is visible, a missing field is not. no extra keys |
pdf |
string |
yes | Repository-relative path. validate.mjs fails the build if the file is absent from disk. |
source_text |
string |
no | Repository-relative path to the extracted plain text, so every assertion below is diffable against a source in the repo. |
amends |
array of string |
no | Provision ids this Act touches. Every entry must resolve against the constitution. |
provisions |
array of object | no |
Conditional rules
- When
originisbill:bill_filebecomes required.
Declares that this document does not yet reflect every instrument that amends it. Rendered as a visible banner on every page; the banner is generated from this block and is never hardcoded, so it cannot fall out of date with the document it describes.
| Key | Type | Required | Notes |
|---|---|---|---|
target_version |
semver | yes | The version this document becomes once reconciliation completes. |
complete |
boolean |
yes | |
applied |
array of string |
no | Instruments reflected in this text, annotated where only partly so. |
held |
array of object | no | What is not yet applied and why. Naming the blocker is the point: an unreconciled state that does not say what it is waiting for is indistinguishable from an oversight. |
Whether this heading carries legal force. enacted means the title appears as a heading in an instrument already applied to this provision. editorial means an editor supplied it — Act 1 titles Article 11's clause (2) Establishment but gives clause (1) no title at all, and the lowercase units above it is editorial. Optional in the schema so frozen archives stay valid unedited; validate.mjs requires it on the current document.
Type: enacted | editorial
Whether the board has adopted the text as published at version. not_adopted means the version string is a working publication label and NOT an assertion about what is in force; the document must then declare adopted_version and text_as_of, and the renderer must lead with the adopted position rather than the label. Optional in the schema so frozen archives stay valid unedited; validate.mjs requires it on the current document.
Type: adopted | not_adopted
npm run validate enforces relational rules a JSON Schema cannot express. Each fails the build:
| Check | Rule |
|---|---|
id-duplicate |
Every provision id is unique across the document |
id-number-mismatch |
An article id must be art-<number>; a section id art-<article>-s-<number> |
number-gap |
Article numbering is dense from 1; a gap is legal only where a reserved or omitted entry occupies it |
number-duplicate |
No number is used twice |
act-reference-unresolved |
Every amended_by, act.amends and provisions[].target resolves |
act-file-missing |
Every pdf and source_text exists on disk |
sor-as-authority |
No provision cites a Statement of Objects and Reasons as its authority |
archive-version-mismatch |
An archived file's info.version matches its filename |
archive-status |
An archived file declares status: superseded |
archive-shadows-current |
No archived version duplicates the current version |
current-count |
Exactly one document is current |
placeholder-url |
No example.com URL in info |
anchor-unresolved |
No template links to an anchor no provision produces |