# Every element and attribute CS-Local 1.0 adds to Akoma Ntoso, as data.
#
# `cs-local-1.0.md` is the specification and argues for the design; this is the reference
# and enumerates it. They are two documents because they answer different questions: a
# reader deciding whether to adopt the format reads the argument, and a reader implementing
# it needs to know that `local:symbol/@outcome` is required and closed and what its six
# values are. Keeping the reference as data rather than as prose means the published page,
# and eventually the validator, are generated from one list that cannot silently disagree
# with itself.
#
# Rendered to /ns/local/1.0/reference/ by render/build_reference.py.
#
# Conventions in this file:
#   required: true          the document is invalid without it
#   required: conditional   required in stated circumstances; `when` says which
#   values: [...]           a closed vocabulary; anything else is invalid
#   recommended: [...]      an open vocabulary; other values are legal but undeclared
#   list: true              whitespace-separated list of #-prefixed eIds, AKN's idiom

version: "1.0"
namespace: https://code.communityscale.io/ns/local/1.0
prefix: local
inherits:
  name: Akoma Ntoso 3.0
  namespace: http://docs.oasis-open.org/legaldocml/ns/akn/3.0
  href: https://docs.oasis-open.org/legaldocml/akn-core/v1.0/akn-core-v1.0-part1-vocabulary.html

groups:
  - id: identity
    title: Document identity
    spec: "1"
    intro: >-
      One <code>local:code</code> per government, holding one or more instruments. The
      jurisdiction says what kind of government it is, which decides what its legislature
      is called and what instruments are available to it; the profile declares the house
      style so nothing downstream has to guess it.

  - id: instruments
    title: Instruments
    spec: "2"
    intro: >-
      An instrument is a body of text adopted as a whole by one body. 19% of codes in the
      corpus contain at least one chapter a legislature never voted on, and the difference
      decides what it takes to change a provision, so it is declared rather than inferred.

  - id: apparatus
    title: Typed notes
    spec: "5"
    intro: >-
      Akoma Ntoso has one <code>note</code>. CS-Local types notes as USLM does, because the
      corpus carries this material in 90% of codes and 41,320 paragraphs, and an editor's
      note and a source credit are not the same kind of statement.

  - id: entities
    title: The entity registry
    spec: "9.1"
    intro: >-
      The join between a schedule column header, the name a code uses in prose, and the key
      a map layer draws on. Declared once, for entities of any kind: zoning districts are
      the first kind, not the only one, since a stormwater chapter keys its schedules on
      watersheds and needs the same declaration rather than a parallel one.

  - id: schedules
    title: Normative schedules
    spec: "9.2 – 9.5"
    intro: >-
      A table that lays text out stays an Akoma Ntoso <code>table</code> and nothing more is
      claimed about it. A table that states rules additionally gets a
      <code>local:schedule</code>, whose axes bind to declared entities. Only 25% of zoning
      instruments publish these matrices inline; 22% publish them as an attachment the code
      merely points at and 17% as per-district prose, so a schedule lives beside its source
      whatever the source is, and declares where it came from.

  - id: provisions
    title: Attributes on inherited elements
    spec: "6"
    intro: >-
      Two attributes CS-Local adds to Akoma Ntoso's own hierarchical elements. 73% of codes
      publish reserved placeholders and every code publishes repealed provisions, and both
      are published rather than dropped: a reserved number asserts that nothing is missing,
      and a repealed section is where a reader following an old citation lands.

  - id: proprietary
    title: Provenance
    spec: "10"
    intro: >-
      Source identifiers only, inside Akoma Ntoso's <code>proprietary</code>. Never drafting
      comments, reviewer names, or internal notes: the working document for Sherborn alone
      carries 28 of them, and the build fails if one appears in rendered output.

elements:
  # -- identity -------------------------------------------------------------------------
  - name: local:code
    group: identity
    summary: The root element. One per government.
    parents: ["(document root)"]
    children: [local:jurisdiction, local:profile, references, local:entities, local:instrument]
    cardinality: Exactly one, as the document element.
    downgrade: Becomes akomaNtoso holding one act per instrument.
    attributes: []
    example: |
      <local:code xmlns:local="https://code.communityscale.io/ns/local/1.0"
                  xmlns="http://docs.oasis-open.org/legaldocml/ns/akn/3.0">

  - name: local:jurisdiction
    group: identity
    summary: The government this code belongs to.
    parents: [local:code]
    children: [local:place, local:enablingFramework]
    cardinality: One per code.
    downgrade: Kept in proprietary; AKN has no element for it.
    attributes: []

  - name: local:place
    group: identity
    summary: >-
      The government itself. The text content is the name as it is written; the attributes
      are what a machine needs.
    parents: [local:jurisdiction]
    content: The place name, e.g. Sherborn.
    cardinality: One per jurisdiction.
    downgrade: Kept in proprietary.
    attributes:
      - name: type
        required: true
        vocabulary: place-type
        summary: >-
          The kind of government, which decides what its legislature is called, which
          instrument types are available to it, and what state framework it acts under. A
          county is not a large city, and this is what lets one model carry both.
      - name: state
        required: true
        type: Two-letter USPS code
        summary: The state whose enabling framework the government acts under.
      - name: gnis
        required: false
        type: GNIS feature ID
        summary: >-
          The federal identifier for the place, so the government resolves to something
          outside this document.

  - name: local:enablingFramework
    group: identity
    summary: The state law under which this government legislates at all.
    parents: [local:jurisdiction]
    content: A citation, e.g. /us-ma/act/mgl.
    cardinality: One per jurisdiction.
    downgrade: Kept in proprietary.
    attributes: []

  - name: local:profile
    group: identity
    summary: >-
      The house style, declared rather than detected. The converter and the renderer both
      read this, which is why a Title/Chapter/Article/Division code and a Part/Chapter/Article
      code round-trip through one code path.
    parents: [local:code, local:instrument]
    cardinality: One per code; may be overridden per instrument.
    downgrade: Kept in proprietary.
    attributes:
      - name: citation
        required: true
        vocabulary: citation-grammar
        summary: >-
          The shape of a section number, which is also the shape of the platform's URLs and
          the rule the eId scheme is derived from.
      - name: enumeration
        required: true
        type: Ladder name from profiles.yaml
        summary: >-
          The marker shapes the code descends through. 34 distinct ladders are in use across
          the corpus and the deepest runs nine rungs, so this cannot be a constant in a parser.
      - name: containers
        required: true
        type: Hyphen-joined container ladder, e.g. title-chapter-article-division
        summary: >-
          The containment vocabulary this government uses, in order. Chapter and article are
          near-universal, but 48% of codes use Part and 44% use Title.

  # -- instruments ----------------------------------------------------------------------
  - name: local:instrument
    group: instruments
    summary: >-
      A body of text adopted as a whole by one body. In a published code this is usually a
      chapter.
    parents: [local:code]
    children: [local:adoption, meta, num, heading, local:generalReferences, body]
    cardinality: One or more per code.
    downgrade: Becomes an AKN act carrying @name; FRBRsubtype already holds the same value.
    attributes:
      - name: type
        required: true
        vocabulary: instrument-type
        summary: >-
          What kind of instrument this is, which is what decides who can change it. This is
          the single most consequential fact about any provision in a municipal code, and the
          incumbent format records it only as a sentence of English.
      - name: eId
        required: true
        type: eId
        summary: The instrument's identifier, e.g. chp_240.

  - name: local:adoption
    group: instruments
    summary: Who adopted this instrument, under what authority, and by what procedure.
    parents: [local:instrument]
    children: [local:body, local:authority, local:procedure, local:date]
    cardinality: One per instrument.
    downgrade: >-
      The date becomes a lifecycle eventRef and the body is already FRBRauthor; the authority
      and procedure have no AKN home and are kept in proprietary.
    attributes: []

  - name: local:body
    group: instruments
    summary: The body that adopted it.
    parents: [local:adoption]
    content: The body's name as published, e.g. Town Meeting.
    cardinality: One per adoption.
    downgrade: Already carried as FRBRauthor.
    attributes:
      - name: role
        required: true
        vocabulary: body-role
        summary: >-
          Declared, never inferred. Classifying adopting bodies by name leaves 5,070 of the
          corpus's 20,308 adoption statements unresolved, because a Board of Selectmen
          legislates in some towns and administers in others. Curated per government from
          that government's charter.
      - name: refersTo
        required: true
        type: Reference to a declared TLCOrganization
        summary: The organization entity, so the body survives being renamed in prose.

  - name: local:authority
    group: instruments
    summary: >-
      The statute that empowers this body to make this instrument. Follows the CFR, which
      requires an AUTH element naming the enabling statute on every part: for a regulation,
      the authority is the whole basis of its validity.
    parents: [local:adoption]
    content: The citation as written, e.g. MGL c. 41, § 81Q.
    cardinality: >-
      Required on every instrument whose type is not ordinance, bylaw or charter. Populated
      at onboarding, since local practice almost never states it anywhere a machine can reach.
    downgrade: No AKN element exists; kept in proprietary and reported as lost.
    attributes:
      - name: href
        required: true
        type: Citation URI
        summary: The machine-resolvable form of the same citation.

  - name: local:procedure
    group: instruments
    summary: >-
      What it takes to change this instrument. The platform renders this as "what it takes to
      change this", and the comment workflow reads it to name the meeting a comment should go to.
    parents: [local:adoption]
    cardinality: One per adoption.
    downgrade: No AKN element exists; kept in proprietary and reported as lost.
    attributes:
      - name: amendedBy
        required: true
        recommended: [town-meeting-article, council-vote, board-vote, ballot, charter-commission]
        summary: The action that amends it.
      - name: hearing
        required: false
        values: [required, none]
        summary: Whether a public hearing is a precondition.
      - name: majority
        required: false
        values: [simple, two-thirds, three-quarters]
        summary: The margin the adopting body needs.
      - name: review
        required: false
        recommended: [ma-attorney-general, none]
        summary: >-
          A state-level review that must follow adoption before the change takes effect.

  - name: local:date
    group: instruments
    summary: A dated event in the instrument's life.
    parents: [local:adoption]
    cardinality: One or more per adoption.
    downgrade: Becomes a lifecycle eventRef.
    attributes:
      - name: date
        required: true
        type: ISO 8601 date
        summary: The date the event happened.
      - name: type
        required: true
        recommended: [adoption, effective, codification, repeal]
        summary: What kind of event it is.

  # -- apparatus ------------------------------------------------------------------------
  - name: local:editorialNote
    group: apparatus
    summary: >-
      The codifier speaking: renumbering, supersession, moves. Present in 90% of codes and
      41,320 paragraphs, and load-bearing rather than decorative.
    parents: [local:instrument, "any hierarchical element"]
    children: [p]
    cardinality: Any number.
    downgrade: Becomes note[refersTo=#noteclass_editorial].
    attributes: []

  - name: local:sourceCredit
    group: apparatus
    summary: >-
      The provenance note as published, verbatim, beside the parsed events. Seven written
      forms exist in the corpus and the parse is lossy, so the string is authoritative.
      Also used at schedule level, where it records the amendment that produced the state
      the schedule is in.
    parents: [local:instrument, "any hierarchical element", local:schedule]
    children: [local:asPublished, local:event]
    cardinality: Any number.
    downgrade: >-
      Becomes note[refersTo=#noteclass_sourceCredit] carrying the published string; the
      parsed events are reported as lost.
    attributes: []
    example: |
      <local:sourceCredit>
        <local:asPublished>[Amended 4-25-2023 ATM by Art. 23]</local:asPublished>
        <local:event date="2023-04-25" type="amendment" by="#org_town_meeting"
                     instrument="Art. 23"/>
      </local:sourceCredit>

  - name: local:asPublished
    group: apparatus
    summary: The provenance note exactly as the code prints it. Authoritative over the parse.
    parents: [local:sourceCredit]
    content: The note, e.g. [Amended 4-25-2023 ATM by Art. 23].
    cardinality: One per source credit.
    downgrade: Becomes the note's paragraph text.
    attributes: []

  - name: local:event
    group: apparatus
    summary: One parsed event from the published string.
    parents: [local:sourceCredit]
    cardinality: Any number.
    downgrade: Reported as lost; AKN keeps only the string.
    attributes:
      - name: date
        required: true
        type: ISO 8601 date
        summary: When it happened.
      - name: type
        required: true
        recommended: [adoption, amendment, repeal, insertion, substitution, renumbering]
        summary: What was done.
      - name: by
        required: false
        type: Reference to a declared TLCOrganization
        summary: The body that did it.
      - name: instrument
        required: false
        type: Free text
        summary: The vehicle, e.g. Art. 23 or Ord. No. 314.
      - name: precision
        required: false
        values: [day, month, year]
        summary: >-
          How exact the published date is. Many notes give a year alone, and recording that
          is not the same as asserting January 1.

  - name: local:generalReferences
    group: apparatus
    summary: >-
      The cross-reference block at the head of a chapter, present in 45% of codes. The
      apparatus a reader uses to find related material.
    parents: [local:instrument]
    children: [p]
    cardinality: At most one per instrument.
    downgrade: Becomes note[refersTo=#noteclass_generalReferences].
    attributes: []

  - name: local:disposition
    group: apparatus
    summary: >-
      The ordinance-to-location audit trail, present in 66% of codes: every ordinance ever
      adopted mapped to where it landed or why it was omitted. The only audit trail a code has.
    parents: [local:instrument]
    children: [p, table]
    cardinality: Any number.
    downgrade: Becomes note[refersTo=#noteclass_disposition].
    attributes: []

  - name: local:derivation
    group: apparatus
    summary: >-
      Current numbering mapped to the prior codification, present in 27% of codes. What lets
      a citation from before the last recodification still resolve.
    parents: [local:instrument]
    children: [p, table]
    cardinality: Any number.
    downgrade: Becomes note[refersTo=#noteclass_derivation].
    attributes: []

  - name: local:effectiveNote
    group: apparatus
    summary: >-
      An effective date that differs from the adoption date, after the CFR's EFFDNOT.
    parents: [local:instrument, "any hierarchical element"]
    children: [p]
    cardinality: Any number.
    downgrade: Becomes note[refersTo=#noteclass_effectiveNote].
    attributes: []

  # -- provisions -----------------------------------------------------------------------
  - name: "@local:inForce"
    group: provisions
    kind: attribute
    summary: >-
      Whether the provision is currently operative. Follows USLM's @inEffect rather than
      AKN's @status, which conflates the dispositions below. This is the boolean the
      renderer keys on.
    parents: ["any Akoma Ntoso hierarchical element"]
    downgrade: A false value becomes @status="removed".
    attributes:
      - name: (value)
        required: false
        values: ["true", "false"]
        summary: Defaults to true when absent.

  - name: "@local:disposition"
    group: provisions
    kind: attribute
    summary: >-
      Why a provision is not in force, or that it is. AKN's @status cannot express the
      difference between a number held in reserve and a section repealed and pointed elsewhere.
    parents: ["any Akoma Ntoso hierarchical element"]
    downgrade: >-
      No AKN attribute carries it and a proprietary attribute is not possible on the same
      element, so it is reported as lost.
    attributes:
      - name: (value)
        required: false
        vocabulary: disposition
        summary: Defaults to current when absent.

  - name: "@local:coversFrom"
    group: provisions
    kind: attribute
    summary: >-
      The first number a provision stands for, when one published heading stands for a block
      of them. One publisher reserves numbers one at a time; the other publishes
      "Secs. 94-1—94-30. Reserved." as a single heading, and does it 7,884 times across
      152,931 section numbers in 70% of its codes.
    parents: ["any Akoma Ntoso hierarchical element"]
    downgrade: Reported as lost, along with the disposition it qualifies.
    attributes:
      - name: (value)
        required: conditional
        when: the provision stands for more than one number
        type: A citation in the document's declared grammar
        summary: >-
          Written as the code writes it. Declared together with coversTo, and only on a
          provision that also declares a disposition, since a span with no disposition
          asserts nothing.

  - name: "@local:coversTo"
    group: provisions
    kind: attribute
    summary: >-
      The last number a provision stands for. A citation to any number within the span
      resolves to this provision, which is the whole point: it is how a reader chasing a
      number is told it is deliberately empty rather than missing.
    parents: ["any Akoma Ntoso hierarchical element"]
    downgrade: Reported as lost.
    attributes:
      - name: (value)
        required: conditional
        when: coversFrom is present
        type: A citation in the document's declared grammar
        summary: The end of the span, inclusive.
    example: |
      <section eId="sec_94-1_thru_94-30" local:inForce="false"
               local:disposition="reserved"
               local:coversFrom="94-1" local:coversTo="94-30">
        <num>94-1—94-30</num>
        <heading>Reserved</heading>
      </section>

  - name: "@local:depth"
    group: provisions
    kind: attribute
    summary: >-
      How far below its section a rung sits, written only on the rungs Akoma Ntoso has no
      element for. AKN offers five below section; 17% of codes in the second corpus descend
      to a sixth or seventh, and repeating the last element would make two different depths
      into one.
    parents: ['hcontainer[@name="level"]']
    downgrade: >-
      Reported as lost. The hcontainer itself survives, so the nesting a reader sees is
      unchanged.
    attributes:
      - name: (value)
        required: true
        type: Integer greater than five
        summary: >-
          Counted from the section, so the first rung below one is 1 and the overflow rungs
          are 6 and beyond.
    example: |
      <hcontainer name="level" local:depth="6" eId="…__indent_a__level_i">
        <num>i.</num>
        <content><p>…</p></content>
      </hcontainer>

  # -- entities -------------------------------------------------------------------------
  - name: local:entities
    group: entities
    summary: >-
      A registry of entities of one declared kind. Zoning districts are the first kind, not
      the only one: the same declaration serves a stormwater chapter's watersheds or a
      licensing chapter's premises.
    parents: [local:code, local:instrument]
    children: [local:entity]
    cardinality: Any number, one per kind.
    downgrade: Each entity becomes a TLCConcept; the registry element itself disappears.
    attributes:
      - name: kind
        required: true
        recommended: [district, watershed, premises, way, overlay, zone]
        summary: >-
          What kind of thing this registry declares. Becomes the ontology path of the
          TLCConcept each entity downgrades to.
      - name: established
        required: false
        type: Reference to a provision
        summary: >-
          The provision that creates these entities, if one provision creates them all. May
          be overridden per entity.

  - name: local:entity
    group: entities
    summary: >-
      One identified thing that provisions refer to, schedules key on, and a map can draw.
    parents: [local:entities]
    cardinality: One or more per registry.
    downgrade: >-
      Becomes TLCConcept keeping eId and showAs. The code, class, map key, governing
      provisions and overlay relation have no AKN home and are reported as lost, which is
      most of why the registry exists.
    attributes:
      - name: eId
        required: true
        type: eId
        summary: The identifier every reference resolves to, e.g. dist_ra.
      - name: showAs
        required: true
        type: Free text
        summary: The full name as the code writes it, e.g. Residence District A.
      - name: code
        required: true
        type: Free text
        summary: >-
          The abbreviation the code itself uses in schedule headers and prose, e.g. RA.
          District codes come in a handful of shapes across the corpus: bare letters, letter
          and digit, letter-dash-digit, with a thin tail of compounds.
      - name: map
        required: false
        type: Free text
        summary: >-
          The value of the geometry layer's attribute, present only when a layer exists. It
          differs from @code whenever the map speaks its own dialect. Its absence is
          information: a district established by the code with no polygon is stated, not
          silent.
      - name: class
        required: false
        vocabulary: entity-class
        summary: What kind of district or entity this is.
      - name: established
        required: false
        type: Reference to a provision
        summary: The provision that creates this entity, overriding the registry's.
      - name: governedBy
        required: false
        list: true
        type: References to provisions
        summary: >-
          The provisions that regulate this entity, which are different provisions from the
          one that establishes it. For an overlay this is the whole answer: one line creates
          the Flood Plain District and another section is what it actually requires.
      - name: relation
        required: conditional
        when: class="overlay"
        vocabulary: overlay-relation
        summary: >-
          What this overlay does to the districts beneath it. A parcel is in an overlay and
          its base district at once, so resolving what may be built there means resolving the
          base district and then applying every overlay in its declared relation.
      - name: over
        required: false
        list: true
        type: References to declared entities
        summary: >-
          The districts this overlay sits on. Absent, the overlay applies wherever it is mapped.

  # -- schedules ------------------------------------------------------------------------
  - name: local:schedule
    group: schedules
    summary: >-
      A table that states rules, as structure. Sits beside the published expression rather
      than replacing it: where an inline table exists it remains untouched, because that is
      what the law is.
    parents: ["the provision that publishes the rule"]
    children: [local:sourceCredit, local:provenance, local:legend, local:dimensions, local:columns, local:group, local:row, local:footnote]
    cardinality: Any number per provision.
    downgrade: >-
      Dropped and reported with its cell count. The AKN table, where one exists, remains, so
      no meaning changes for an AKN consumer; the structured rules simply have no carrier.
    attributes:
      - name: eId
        required: true
        type: eId
        summary: The schedule's identifier, e.g. schd_240-3.2. Footnote eIds derive from it.
      - name: type
        required: true
        vocabulary: schedule-type
        summary: >-
          What kind of rules the schedule states. Typed rather than named, because the same
          table is called Use Regulations in the East and Use Table or Use Matrix in the West.
      - name: source
        required: true
        type: Reference to a provision
        summary: >-
          The provision that publishes these rules. When that provision holds an inline table
          the schedule is a parse of it; otherwise provenance is required.

  - name: local:provenance
    group: schedules
    summary: >-
      Where the rules came from, when they did not come from an inline table. Required
      whenever @source does not point at a provision containing one.
    parents: [local:schedule]
    children: [local:transcribedFrom, local:curatedFrom]
    cardinality: At most one per schedule.
    downgrade: Dropped with the schedule.
    attributes: []

  - name: local:transcribedFrom
    group: schedules
    summary: >-
      The attachment-only mode, 22% of zoning instruments: the rules exist as a PDF the code
      points at, so every number in them is otherwise unreachable to search, to the map, and
      to anyone reading the code online. A transcription says so, and says what it was
      checked against.
    parents: [local:provenance]
    cardinality: Any number.
    downgrade: Dropped with the schedule.
    attributes:
      - name: href
        required: true
        type: URI
        summary: The attachment as published.
      - name: supplement
        required: false
        type: Free text
        summary: The supplement the transcription was taken from, e.g. Supp 3, Aug 2025.
      - name: verified
        required: false
        type: ISO 8601 date
        summary: When a person last checked the transcription against the source.

  - name: local:curatedFrom
    group: schedules
    summary: >-
      The prose mode, 17% of zoning instruments: use rules written as per-district sections
      of running text with no matrix anywhere. The schedule is an index over the prose, and
      each row's @source names the provision it was read from, so every cell is traceable to
      the sentence that justifies it.
    parents: [local:provenance]
    cardinality: Any number.
    downgrade: Dropped with the schedule.
    attributes:
      - name: href
        required: false
        list: true
        type: References to provisions
        summary: The provisions the schedule was built from, where a single list covers it.

  - name: local:legend
    group: schedules
    summary: >-
      What the symbols in this schedule's cells mean. Declared per schedule and never assumed:
      331 codes with a use matrix run 200 distinct symbol systems, the same glyph means
      "allowed", "accessory" or "agriculture permit" in different codes' own legends, and only
      17% publish a legend a machine can read.
    parents: [local:schedule]
    children: [local:symbol]
    cardinality: At most one per schedule; required where cells carry symbols.
    downgrade: Dropped with the schedule.
    attributes: []

  - name: local:symbol
    group: schedules
    summary: >-
      One symbol and what it means here. The code is an opaque string whose meaning is given
      entirely by its outcome.
    parents: [local:legend]
    content: The meaning as the code publishes it, e.g. Allowable on special permit.
    cardinality: One or more per legend.
    downgrade: Dropped with the schedule.
    attributes:
      - name: code
        required: true
        type: Free text
        summary: >-
          The symbol as printed, e.g. P, SP, CUP, or an em dash. Carries no meaning of its own.
      - name: outcome
        required: true
        vocabulary: outcome
        summary: >-
          What the symbol does to the use in that district. This is what makes a cell
          computable across jurisdictions that share no vocabulary.
      - name: approver
        required: conditional
        when: outcome="approval"
        type: Reference to a declared TLCOrganization
        summary: >-
          The body that grants the approval, which connects the schedule to the instrument
          and procedure model: the platform can answer who says yes and by what process.
      - name: procedure
        required: false
        vocabulary: approval-procedure
        summary: The instrument the approval is granted by.

  - name: local:dimensions
    group: schedules
    summary: The columns of a dimensional schedule, declared before the rows use them.
    parents: [local:schedule]
    children: [local:dimension]
    cardinality: At most one per schedule; required for type="dimensional".
    downgrade: Dropped with the schedule.
    attributes: []

  - name: local:dimension
    group: schedules
    summary: >-
      One measurable requirement. About twenty concepts cover the dimension vocabulary of
      every inline dimensional matrix in the corpus, so the concept is normalized while the
      label stays exactly as published.
    parents: [local:dimensions]
    content: The label as printed, e.g. Minimum Lot Size.
    cardinality: One or more.
    downgrade: Dropped with the schedule.
    attributes:
      - name: key
        required: true
        type: Token
        summary: What cells in this schedule use to refer to this dimension.
      - name: concept
        required: false
        vocabulary: dimension-concept
        summary: >-
          The normalized concept, which is what makes one town's schedule comparable with
          another's.
      - name: bound
        required: false
        values: [min, max]
        summary: >-
          Whether the value is a floor or a ceiling. Carried separately from the label
          because "Minimum Lot Size" states it in prose and a machine should not parse prose.
      - name: unit
        required: false
        vocabulary: unit
        summary: The unit the values are in.
      - name: footnote
        required: false
        list: true
        type: Markers declared in this schedule
        summary: >-
          A note that applies to every cell in this column. Attaching it here rather than to
          each cell is what keeps a note that qualifies a whole column to one declaration.

  - name: local:columns
    group: schedules
    summary: >-
      The columns of a schedule whose axis is neither districts nor dimensions. Parking
      tables appear in 825 zoning instruments, more than twice as many as carry a use matrix,
      and sign and landscaping tables behind them; these are usually use by requirement.
    parents: [local:schedule]
    children: [local:column]
    cardinality: At most one per schedule.
    downgrade: Dropped with the schedule.
    attributes: []

  - name: local:column
    group: schedules
    summary: One generic column.
    parents: [local:columns]
    cardinality: One or more.
    downgrade: Dropped with the schedule.
    attributes:
      - name: key
        required: true
        type: Token
        summary: What cells use to refer to this column.
      - name: label
        required: true
        type: Free text
        summary: The column heading as printed.
      - name: footnote
        required: false
        list: true
        type: Markers declared in this schedule
        summary: A note applying to the whole column.

  - name: local:group
    group: schedules
    summary: >-
      A band of rows under a heading. 73% of codes with a use matrix group their rows this
      way, and readers navigate by the bands, so the grouping is structure rather than styling.
    parents: [local:schedule]
    children: [local:row]
    cardinality: Any number.
    downgrade: Dropped with the schedule.
    attributes:
      - name: heading
        required: true
        type: Free text
        summary: The band heading as printed, e.g. Residential uses.
      - name: footnote
        required: false
        list: true
        type: Markers declared in this schedule
        summary: A note applying to every cell in the band.

  - name: local:row
    group: schedules
    summary: >-
      One row of the matrix: a use in a use schedule, a district in a dimensional schedule,
      a subject in a generic one.
    parents: [local:schedule, local:group]
    children: [local:cell]
    cardinality: One or more.
    downgrade: Dropped with the schedule.
    attributes:
      - name: eId
        required: false
        type: eId
        summary: >-
          The row's identifier, which is what a comment addressed to one line of a schedule
          anchors to.
      - name: num
        required: false
        type: Free text
        summary: >-
          The row number as printed, e.g. 1 or 2A. Readers cite these, so they are kept as
          published rather than renumbered.
      - name: subject
        required: conditional
        when: the row is not keyed by an entity
        type: Free text
        summary: What the row regulates, in the schedule's own words.
      - name: refersTo
        required: false
        type: Reference to a defined term
        summary: >-
          The term this row regulates. Bound by identity because the wordings routinely
          differ: a schedule says "Single-family home" where the glossary says DWELLING,
          SINGLE-FAMILY, and matching on text fails silently. Optional, because plenty of
          rows name things a code never defines, though the share that bind is a useful
          measure of how well a schedule and its glossary agree.
      - name: entity
        required: conditional
        when: the schedule is keyed by entity on the row axis
        list: true
        type: References to declared entities
        summary: The entity this row states requirements for, in a dimensional schedule.
      - name: source
        required: false
        type: Reference to a provision
        summary: >-
          The provision this row was read from, which is what makes the prose mode traceable.
      - name: footnote
        required: false
        list: true
        type: Markers declared in this schedule
        summary: A note applying to every cell in the row.

  - name: local:cell
    group: schedules
    summary: >-
      One cell. Uniform everywhere in the schedule vocabulary so a renderer never branches on
      cell shape. An absent cell means the source published nothing, which is distinct from a
      cell whose outcome is not-applicable, and both are preserved.
    parents: [local:row]
    cardinality: Any number per row.
    downgrade: Dropped with the schedule.
    attributes:
      - name: entity
        required: conditional
        when: the schedule is keyed by entity on the column axis
        list: true
        type: References to declared entities
        summary: >-
          The entity this cell states a rule for. A list, because a source cell merged across
          several columns is common and one published cell should stay one cell rather than
          being duplicated per district.
      - name: dim
        required: conditional
        when: type="dimensional"
        type: A key declared in this schedule's dimensions
        summary: Which dimension this cell gives a value for.
      - name: col
        required: conditional
        when: the schedule declares generic columns
        type: A key declared in this schedule's columns
        summary: Which column this cell belongs to.
      - name: symbol
        required: false
        type: A code declared in this schedule's legend
        summary: The permission symbol, in a use schedule.
      - name: value
        required: false
        type: Number
        summary: The numeric value, in a dimensional schedule.
      - name: text
        required: false
        type: Free text
        summary: >-
          The published words where the cell is not a number, e.g. "Not applicable" or an em
          dash. Carried rather than normalized away, because the words are what was adopted.
      - name: footnote
        required: false
        list: true
        type: Markers declared in this schedule
        summary: >-
          Notes qualifying this cell. A footnoted symbol is not the bare symbol, so a
          consumer resolving the outcome has to apply these.
      - name: see
        required: false
        type: Reference to a provision
        summary: >-
          The provision that regulates this combination further. 29% of codes with a use
          matrix carry a per-use reference column.

  - name: local:footnote
    group: schedules
    summary: >-
      A note that qualifies the cells marking it. 45% of codes with a use matrix footnote
      individual cells, and those notes are frequently the rule rather than a gloss, so the
      marker is something a consumer must resolve rather than decoration.
    parents: [local:schedule]
    content: The note as published.
    cardinality: Any number per schedule.
    downgrade: Dropped with the schedule.
    scoping: >-
      A marker means nothing outside its own schedule. Resolution is a lookup in the
      declaring schedule and nowhere else, because codes reuse markers across their tables as
      a matter of course: of the codes carrying two or more footnoted matrices, 93% use the
      same marker on more than one of them, and one California code puts "b" on 91 different
      tables. Markers must be unique within one schedule, which is a validation error rather
      than a resolution rule. Document-unique identity lives in the eId instead.
    attributes:
      - name: marker
        required: true
        type: Free text
        summary: >-
          The marker as printed, e.g. *, **, † or 3. Scoped to this schedule and unique within it.
      - name: effect
        required: true
        vocabulary: footnote-effect
        summary: >-
          What this note does to the cells it marks. A cell's outcome is provisional until its
          footnotes are applied, and a consumer that meets an effect it does not recognize
          treats it as conditions, so an under-curated footnote degrades to a warning rather
          than a false yes.
      - name: eId
        required: false
        type: eId
        summary: >-
          Document-unique identity, derived from the schedule and a slug of the marker, e.g.
          schd_240-3.2__fn_ast. Derived from the marker rather than from position so that
          inserting a footnote does not renumber its neighbours, which matters because
          comments anchor to eIds.
      - name: see
        required: false
        type: Reference to a provision
        summary: Where the circumstance this note states is written out.

  # -- proprietary ----------------------------------------------------------------------
  - name: local:sourceSystem
    group: proprietary
    summary: >-
      The identifiers the source of a capture uses for it, so a later capture of the same
      instrument can be matched against this one.
    parents: [proprietary]
    cardinality: At most one per instrument.
    downgrade: Kept inside proprietary, which AKN already provides.
    attributes:
      - name: customer
        required: false
        type: Free text
        summary: The source's account identifier for this government, e.g. SH4020.
      - name: id
        required: false
        type: Free text
        summary: The source's identifier for this instrument.
      - name: codeDate
        required: false
        type: ISO 8601 date
        summary: The date the published code was current to.
      - name: captured
        required: false
        type: ISO 8601 date
        summary: >-
          When we took the copy, which is not the same as the code date and must not be
          conflated with it.

  - name: local:attachment
    group: proprietary
    summary: >-
      A file the published code refers to but does not contain, most often the schedule or
      the zoning map.
    parents: [proprietary]
    cardinality: Any number.
    downgrade: Kept inside proprietary.
    attributes:
      - name: href
        required: true
        type: URI
        summary: The attachment as published.

vocabularies:
  - id: place-type
    title: Kinds of government
    intro: >-
      A county is not a large city: its legislature may be a Board of Supervisors, a County
      Council or a Board of Commissioners, it may have no charter, and in many states it can
      only legislate on subjects the state has delegated. The type is what lets one document
      model carry both without either being a special case.
    values:
      - {value: city, summary: "A municipal corporation, and the most common form"}
      - {value: town, summary: "A municipality whose legislature, in New England, is usually a Town Meeting"}
      - {value: township, summary: "A subdivision of a county, with powers that vary widely by state"}
      - {value: borough, summary: "The municipal form used in Pennsylvania, New Jersey, Connecticut and Alaska"}
      - {value: village, summary: "An incorporated place, typically smaller than a city"}
      - {value: county, summary: "A subdivision of a state, often able to legislate only on delegated subjects"}
      - {value: authority, summary: "A single-purpose body governed by its own board"}
      - {value: tribal, summary: "A tribal government publishing its own code"}
      - {value: municipality, summary: "Used where the state's own term for the form is simply municipality"}
      - {value: district, summary: "A special-purpose district with rule-making power of its own"}
      - {value: metropolitan, summary: "A regional or consolidated city-county government"}
      - {value: other, summary: "A form none of the above describes"}

  - id: instrument-type
    title: Kinds of instrument
    intro: >-
      Required and closed. What distinguishes these is who can change them, which is the
      question a reader of any provision most needs answered.
    values:
      - {value: ordinance, summary: "Legislation of a city, county, township, borough or village"}
      - {value: bylaw, summary: "Legislation of a New England town"}
      - {value: regulation, summary: "Rules made by a board under delegated authority"}
      - {value: charter, summary: "The instrument the government itself is made under"}
      - {value: specialAct, summary: "State legislation for this government alone"}
      - {value: acceptance, summary: "A local vote to adopt a state statute"}
      - {value: franchise, summary: "A contract with a utility or operator"}
      - {value: policy, summary: "Internal administrative policy"}
      - {value: ruleOfProcedure, summary: "A body's rules for its own conduct"}

  - id: body-role
    title: Roles an adopting body plays
    intro: >-
      Declared per government at onboarding, from that government's charter, because the name
      of a body does not determine its role.
    values:
      - {value: legislative, summary: "Its vote makes law"}
      - {value: executive, summary: "It administers, and may make rules under law"}
      - {value: administrative, summary: "It makes rules under delegated authority"}
      - {value: judicial, summary: "It adjudicates"}

  - id: citation-grammar
    title: Citation grammars
    intro: >-
      The shape of a section number, which is also the shape of the platform's URLs.
      profiles.yaml carries each one's pattern.
    values:
      - {value: chapter-section, summary: "§ 1-14"}
      - {value: dotted-decimal, summary: "§ 14.05.030"}
      - {value: chapter-article-section, summary: "§ 240-4.5"}
      - {value: dashed-triple, summary: "§ 1-04-010"}
      - {value: flat, summary: "§ 112"}
      - {value: alpha-chapter-section, summary: "§ A676-3"}

  - id: disposition
    title: Dispositions
    intro: >-
      Why a provision reads as it does. Published rather than dropped, because a reserved
      number asserts that nothing is missing and a repealed section is where a reader
      following an old citation lands.
    values:
      - {value: current, summary: "In force"}
      - {value: reserved, summary: "A number held deliberately empty; 73% of codes publish these"}
      - {value: deleted, summary: "Removed, with the published note kept in place"}
      - {value: repealed, summary: "Repealed by a later instrument"}
      - {value: superseded, summary: "Displaced by state law or another provision"}
      - {value: renumbered, summary: "Moved; the old number stays as a landing point"}

  - id: entity-class
    title: Entity classes
    intro: Recommended values for zoning districts. Open, since other kinds need their own.
    values:
      - {value: residential, summary: "Dwellings are the principal permitted use"}
      - {value: business, summary: "Trade and services, often at a neighborhood scale"}
      - {value: commercial, summary: "Larger-scale retail, office and service uses"}
      - {value: industrial, summary: "Manufacturing, warehousing and related uses"}
      - {value: mixed, summary: "Residential and non-residential uses together"}
      - {value: overlay, summary: "Sits on top of other districts; must declare a relation and its governing text"}
      - {value: special, summary: "A district that fits none of the above, such as open space or institutional"}

  - id: overlay-relation
    title: What an overlay does
    intro: >-
      Required on an overlay. A parcel is in the overlay and its base district at once, so a
      consumer that cannot resolve the overlay must say so rather than answer from the base
      district alone.
    values:
      - {value: supplements, summary: "Adds uses or allowances the underlying district does not give"}
      - {value: restricts, summary: "Adds constraints; the underlying rules still apply"}
      - {value: replaces, summary: "Supersedes the underlying rules, for the subjects its text covers"}

  - id: schedule-type
    title: Kinds of schedule
    values:
      - {value: use, summary: "Use by district, cells carrying permission symbols"}
      - {value: dimensional, summary: "District by dimension, cells carrying values"}
      - {value: parking, summary: "Usually use by requirement; 825 zoning instruments carry one"}
      - {value: sign, summary: "340 instruments"}
      - {value: landscaping, summary: "218 instruments"}
      - {value: other, summary: "Any other normative matrix, with declared generic columns"}

  - id: outcome
    title: Permission outcomes
    intro: >-
      Required and closed. Symbols are opaque strings and this is where their meaning lives,
      which is the only workable design given 200 distinct symbol systems across 331 codes.
    values:
      - {value: permitted, summary: "Allowed by right"}
      - {value: accessory, summary: "Allowed as an accessory use"}
      - {value: approval, summary: "Allowed on a discretionary approval; names the approver and procedure"}
      - {value: prohibited, summary: "Not allowed"}
      - {value: not-applicable, summary: "The combination cannot occur"}
      - {value: see, summary: "Defers to a provision, which the cell's see attribute names"}

  - id: approval-procedure
    title: Approval procedures
    values:
      - {value: special-permit, summary: "A discretionary permit granted by a named board after a hearing"}
      - {value: conditional-use, summary: "The western equivalent, usually a conditional use permit"}
      - {value: site-plan, summary: "Approval of the layout rather than of the use itself"}
      - {value: variance, summary: "Relief from a requirement on a showing of hardship"}

  - id: footnote-effect
    title: What a footnote does to the cell it marks
    intro: >-
      Required and closed. This is what makes a marker computable rather than decorative.
    values:
      - {value: clarifies, summary: "Defines a term or a measurement datum; the outcome and value stand"}
      - {value: conditions, summary: "The outcome applies only subject to the stated circumstance; a permitted cell so marked must never be presented as an unconditional yes"}
      - {value: varies, summary: "The value or outcome differs in stated circumstances; the text says how and see says where"}

  - id: dimension-concept
    title: Dimension concepts
    intro: >-
      Recommended values. About twenty concepts cover the dimension axis of essentially every
      dimensional schedule, which is what makes one government's schedule comparable with
      another's.
    values:
      - {value: lot-area, summary: "The area of a lot"}
      - {value: lot-width, summary: "The width of a lot, however the code measures it"}
      - {value: lot-depth, summary: "The depth of a lot from front line to rear"}
      - {value: frontage, summary: "The length of a lot along the way that serves it"}
      - {value: setback-front, summary: "Required distance from the front lot line"}
      - {value: setback-side, summary: "Required distance from a side lot line"}
      - {value: setback-rear, summary: "Required distance from the rear lot line"}
      - {value: height, summary: "Building height, in feet or in stories"}
      - {value: coverage-lot, summary: "The share of a lot that may be covered"}
      - {value: coverage-building, summary: "The share covered by buildings specifically"}
      - {value: far, summary: "Floor area ratio: floor area relative to lot area"}
      - {value: open-space, summary: "The share that must be left unbuilt"}
      - {value: density, summary: "Dwelling units relative to land area"}
      - {value: impervious, summary: "The share that may be impervious surface"}

  - id: unit
    title: Units
    values:
      - {value: acre, summary: "Acres"}
      - {value: sqft, summary: "Square feet"}
      - {value: ft, summary: "Linear feet"}
      - {value: story, summary: "Stories, which a code may count differently from height in feet"}
      - {value: percent, summary: "A percentage, written as published"}
      - {value: ratio, summary: "A bare ratio, as floor area ratio is written"}
      - {value: du-per-acre, summary: "Dwelling units per acre"}
