# ✂ docujoint template — adapt this to your system; delete this line when it is yours.
# Programming knowledge-base format — a profile on top of OKF v0.1 for
# documenting a software system: apps (pages, modules), services, events,
# data architecture, flows with scenario coverage, actors, decisions and
# engineering practice.
#
# Design principles baked in:
#   · state is DERIVED from what is written + what the scan confirms — never
#     stored, so it cannot contradict the prose (no Status columns allowed)
#   · tests are EVIDENCE (test:// URIs on feature/scenario rows), not prose
#     documents that drift
#   · open questions are first-class everywhere — the channel for the team and
#     coding agents to surface doubts, tied to the exact feature they block;
#     answered is not done: an answer is folded into the prose/gaps and the
#     row is then ARCHIVED, so the open list stays a worklist
#   · flows carry BOTH surfaces: Scenarios (the paths, with coverage) and
#     Features (the traceability of what each step must do, with evidence) —
#     anomalies point at scenarios, open questions point at features

format:
  name: programming-kb
  version: "0.1"
  okf_version: "0.1"

vault:
  reserved_files: [index.md, log.md, CLAUDE.md]
  links:
    forbid:
      - { rule: wikilink, severity: error, code: wikilink }
    broken_internal: warn
  index: { generated: true }
  tree:
    - { path: "Apps/",         types: [app, page, module] }
    - { path: "Shared/",       types: [module] }
    - { path: "Services/",     types: [service, integration] }
    - { path: "Events/",       types: [event] }
    - { path: "Data/",         types: [database, table, enum] }
    - { path: "Flows/",        types: [flow] }
    - { path: "Actors/",       types: [actor] }
    - { path: "Engineering/",  types: [engineering-note, decision] }
    - { path: "Conventions/",  types: [convention] }
    - { path: "Team/",         types: [person] }
    - { path: "Backlog/",      types: [epic] }

# Evidence schemes — how documentation cites reality. Syntax always checked;
# with `dj lint --inventory` they reconcile against a code scan.
schemes:
  repo:  { pattern: "repo://[\\w.-]+/\\S+" }     # source file in an app/service
  route: { pattern: "route://[\\w.-]+/\\S*" }    # URL route in an app
  api:   { pattern: "api://[\\w.-]+/\\S+" }      # endpoint of a service
  db:    { pattern: "db://[\\w.-]+/[\\w.-]+" }   # database/table
  event: { pattern: "event://[\\w.-]+" }         # topic/queue
  test:  { pattern: "test://[\\w.-]+/\\S+" }     # test file

shared:
  empty_markers: ["—", "-", "–", ""]
  stub_marker: "_To be documented._"
  # One colour vocabulary for every value renderers colour — path kinds,
  # graph node types, coverage states. Semantic tokens (success · warning ·
  # error · info · brand · muted) adapt to light/dark; raw CSS colours pass
  # through. Anything undeclared falls back to engine defaults, then a palette.
  colors:
    # every value this format produces — derived states, its own enums — says
    # what it MEANS here. The engine assumes nothing about these words.
    built: success
    covered: success
    answered: success
    partial: warning
    open: warning
    missing: error
    drift: info
    unspecified: muted
    untested: muted
    deferred: muted
    archived: muted
    wontfix: muted
    unknown: muted
    happy: success
    unhappy: error
    edge: warning
    app: brand
    service: info
    integration: info
    event: "#6b21a8"
    database: "#0e7490"
    table: "#0e7490"
  enums:
    q_status: [open, answered, deferred, wontfix, archived]
    feature_kind: [step, feature, capability, rule, ux, behaviour]
    ticket_kind: [spike, build, test, docs, ops]
    scenario_kind: [happy, unhappy, edge]
    nav_direction: [arrives-from, leads-to]
    http_method: [GET, POST, PUT, PATCH, DELETE]
    participant_role: [producer, consumer]
    decision_status: [proposed, accepted, superseded]

markdown:
  comments: [html, obsidian]

blocks:
  # Discrete feature set with acceptance-criteria semantics: what must hold
  # (Feature), what exists and how (Implemented + evidence URIs), what is
  # missing (Gap), what proves it (Tests). State is derived.
  features:
    heading: Features
    identity: uuid
    columns:
      - { name: ID, id_grammar: "f<n>", unique: error, sequential: warn }
      - { name: Feature, required: true }
      - { name: Kind, enum: shared.feature_kind, unknown: warn }
      - { name: Implemented, refs: [repo, route, api, db, event] }
      - { name: Gap }
      # who is on it. Optional, so a table that has not started assigning is
      # still valid — and a LINK, so ownership joins the Team document rather
      # than stringly naming a person
      - { name: Owner, optional: true }
      - { name: Tests, optional: true, refs: [test] }
    forbid_columns:
      - { name: Status, severity: error, code: feature-status-column }
    derive:
      state:
        - { when: "implemented && !gap && ref_broken", then: drift }
        - { when: "implemented && !gap", then: built }
        - { when: "implemented && gap", then: partial }
        - { when: "!implemented && gap", then: missing }
        - { when: "!implemented && !gap && open_question_about", then: unspecified }
        - { else: unknown }
    checks:
      # Ownership is assigned per FEATURE, not per document — so one flow can
      # end up split across people. That is allowed and sometimes right, but it
      # is worth seeing: it means no single person holds the whole path.
      - { code: features-owner-split, severity: warn, scope: block,
          when: "owner_varies",
          message: "features here are assigned to more than one person — no one owns the whole path" }
      - { code: feature-unbound, severity: warn,
          when: "implemented && !gap && !has_refs",
          message: "claims complete but cites no evidence — nothing proves it" }
      - { code: feature-untested, severity: warn,
          when: "implemented && !gap && has_tests_column && !cites_test",
          message: "complete but no test:// evidence — built and untested" }
      # No "empty row" check: a row with neither Implemented nor Gap derives
      # `unspecified` when an open question points at it, `unknown` otherwise —
      # both visible on the dashboard, which is where un-audited rows belong.
    forms:
      # the picker's choices are the DOCUMENTS of type person — the roster is
      # the vault's, so it can never drift from who is actually on the team
      assign:
        label: Assign
        set: { Owner: "[{who}](</Team/{who}.md>)" }
        fields:
          - { name: who, label: Owner, kind: options, from_concepts: person }
    display:
      intro: prose
      # cards at EVERY width: a feature reads as an entry — id + state dot up
      # top beside the row's Comments trigger, the feature as the title, kind
      # as a toned chip, the evidence columns as labelled fields underneath
      layout: { narrow: cards, wide: cards }
      # reader filters (power search): derived state · kind · gap · tests —
      # "Tests is empty" = untested, "Gap is not empty" = gapped
      filters: [state, Kind, Gap, Tests]
      columns:
        - { col: ID, style: mono, state: marker, card: eyebrow }
        - { col: Feature, style: md, card: title }
        - { col: Kind, style: chip, card: badge }
        - { col: Implemented, style: md }
        - { col: Gap, style: md }
        # an edit form attached to its column: the cell IS the control
        - { col: Owner, style: md, control: { form: assign } }
        - { col: Tests, style: md }

  # Every path a flow covers — happy, unhappy, edge — as enumerable data.
  # Coverage is derived from test evidence; the dashboard can then answer
  # "which unhappy paths have no tests" instead of anyone guessing.
  scenarios:
    heading: Scenarios
    identity: uuid
    columns:
      - { name: ID, id_grammar: "s<n>", unique: error, sequential: warn }
      - { name: Scenario, required: true }
      - { name: Kind, enum: shared.scenario_kind, unknown: error }
      - { name: Outcome }
      # Result is a SHORT canonical label — paths that declare the same Result
      # CONVERGE in the path tree; different Results diverge. Outcome stays
      # free prose; Result is the join key.
      - { name: Result }
      - { name: Tests, refs: [test] }
    forbid_columns:
      - { name: Status, severity: error, code: scenario-status-column }
    derive:
      state:
        - { when: "tests && ref_broken", then: drift }
        - { when: "tests", then: covered }
        - { else: untested }
    display:
      intro: prose
      # Path-tree explorer on documents carrying this block: a layered tree of
      # flow → branches (docs whose `parent_flow` names this doc) → paths →
      # results (converged by equal Result labels), with selectable paths.
      explorer: { kind: Kind, result: Result, children: parent_flow }
      columns:
        - { col: ID, style: mono, state: marker }
        - { col: Scenario, style: md }
        - { col: Kind, style: plain }
        - { col: Outcome, style: md }
        - { col: Result, style: plain }
        - { col: Tests, style: md }

  # Explicit node wiring. Every flow document is a NODE in its process — a
  # step, a stage, a complement — and its Transitions table declares which
  # nodes can follow it and the business rule that fires each move. Link the
  # To cell when the target has a document; plain text becomes a converging
  # terminal outcome. A scenario is, at bottom, a chain of transitions.
  transitions:
    heading: Transitions
    columns:
      - { name: To, required: true }
      - { name: When, required: true }
    display:
      intro: prose
      # Process graph on documents carrying this block: the document and its
      # `parent_flow` children chain into one chart — nodes are documents,
      # edges carry the When rule (revealed on hover), rollback edges draw as
      # dashed returns, unlinked To cells converge as terminal boxes.
      graph: { to: To, when: When, children: parent_flow }
      columns:
        - { col: To, style: md }
        - { col: When, style: md }

  # The page graph, typed: where users arrive from and where they go next.
  navigation:
    heading: Navigation
    columns:
      - { name: Direction, enum: shared.nav_direction, unknown: error }
      - { name: Page, required: true }
      - { name: Trigger }
    display:
      intro: prose
      columns:
        - { col: Direction, style: chip }
        - { col: Page, style: md }
        - { col: Trigger, style: md }

  endpoints:
    heading: Endpoints
    columns:
      - { name: Method, enum: shared.http_method, unknown: warn }
      - { name: Path, required: true }
      - { name: Purpose }
      - { name: Auth }
    display:
      intro: prose
      columns:
        - { col: Method, style: chip }
        - { col: Path, style: mono }
        - { col: Purpose, style: md }
        - { col: Auth, style: md }

  columns:
    heading: Columns
    columns:
      - { name: Column, required: true }
      - { name: Type }
      - { name: Nullable }
      - { name: Purpose }
    display:
      intro: prose
      columns:
        - { col: Column, style: mono }
        - { col: Type, style: mono }
        - { col: Nullable, style: plain }
        - { col: Purpose, style: md }

  # Canonical values as parsed rows — a flow that says "when status =
  # approved" can be crossed against the enum that defines approved.
  values:
    heading: Values
    columns:
      - { name: Value, required: true }
      - { name: Meaning }
      - { name: Notes }
    display:
      intro: prose
      columns:
        - { col: Value, style: mono }
        - { col: Meaning, style: md }
        - { col: Notes, style: md }

  message:
    heading: Message
    columns:
      - { name: Field, required: true }
      - { name: Type }
      - { name: Purpose }
    display:
      intro: prose
      columns:
        - { col: Field, style: mono }
        - { col: Type, style: mono }
        - { col: Purpose, style: md }

  # Who produces and who consumes a topic — the async dependency graph.
  participants:
    heading: Participants
    columns:
      - { name: Participant, required: true }
      - { name: Role, enum: shared.participant_role, unknown: error }
      - { name: Notes }
    display:
      intro: prose
      columns:
        - { col: Participant, style: md }
        - { col: Role, style: chip }
        - { col: Notes, style: md }

  # Anomalies: a scenario whose DOCUMENTED outcome reads as a defect rather
  # than an accepted behaviour. Same shape as an open question — it asserts
  # nothing the scenario does not already say, and always offers "this is
  # intended", because the judgement belongs to the reader.
  anomalies:
    heading: Anomalies
    identity: uuid
    columns:
      - { name: A, id_grammar: "a<n>", unique: error }
      - { name: Anomaly, required: true }
      - { name: About, required: true,
          ref: { block: scenarios, column: ID, dangling: error, code: anomaly-about-dangling } }
      - { name: Why, required: true }
      - { name: Status, enum: shared.q_status, unknown: error, code: anomaly-status }
      - { name: Resolution }
      - { name: Options }
      - { name: Owner, optional: true }
    display:
      intro: prose
      # a table is unusable on a phone — say so, and the same markup restyles
      # into cards below the narrow breakpoint
      layout: { narrow: cards }
      filters: [Status]
      columns:
        - { col: A, style: mono, card: eyebrow }
        - { col: Anomaly, style: md, card: title }
        - { col: About, style: mono }
        - { col: Why, style: md }
        - { col: Status, style: chip, card: badge, control: { form: set-status } }
        - { col: Owner, style: md, control: { form: assign } }
        - { col: Resolution, style: md }
    forms:
      assign:
        label: Assign
        set: { Owner: "[{who}](</Team/{who}.md>)" }
        fields:
          - { name: who, label: Owner, kind: options, from_concepts: person }
      set-status:
        label: Status
        set: { Status: "{value}" }
        fields:
          - { name: value, kind: options, from_enum: Status }
      reply:
        label: Resolve
        set: { Resolution: "{choice} {note}", Status: answered }
        fields:
          - { name: choice, label: Verdict, kind: options, from: Options, mode: single, other: true, required: true }
          - { name: note, label: What you found, kind: textarea }

  # Open questions: the doubt channel. `About` ties a question to the exact
  # row it blocks — a feature in a flow or a page, a ticket in an epic — which
  # also feeds the `unspecified` derived state on features.
  open-questions:
    heading: Open questions
    identity: uuid
    # the wiring behind open_question_about: About points at the row the
    # question is about, and a question blocks it while its Status is open.
    # One wiring covers every block the ref names below.
    questions: { ref_column: About, open_when: "status == 'open'" }
    columns:
      - { name: Q, id_grammar: "q<n>", unique: error }
      - { name: Question, required: true }
      # a LIST of targets: this same block sits in `flow` (features) and in
      # `epic` (tickets). With one target, a question about a ticket had to
      # name it in the sentence — an untyped reference joining to nothing,
      # which is the thing this format exists to remove.
      - { name: About, optional: true,
          ref: { block: [features, tickets], column: ID, dangling: error, code: q-about-dangling } }
      - { name: Status, enum: shared.q_status, unknown: error, code: q-status }
      - { name: Resolution }
      # optional, authored by the coding agent: proposed answers, ';'-separated —
      # capture forms with `kind: options, from: Options` render them as choices
      - { name: Options, optional: true }
      - { name: Owner, optional: true }
    display:
      intro: prose
      layout: { narrow: cards }
      filters: [Status]
      columns:
        - { col: Q, style: mono, card: eyebrow }
        - { col: Question, style: md, card: title }
        - { col: About, style: mono }
        - { col: Status, style: chip, card: badge, control: { form: set-status } }
        - { col: Owner, style: md, control: { form: assign } }
        - { col: Resolution, style: md }

    forms:
      assign:
        label: Assign
        set: { Owner: "[{who}](</Team/{who}.md>)" }
        fields:
          - { name: who, label: Owner, kind: options, from_concepts: person }
      # review an answered question — fold the answer into the prose or a Gap,
      # then set it archived (or any status by hand). `answered` means the
      # knowledge arrived; `archived` means it has been written where it lives.
      set-status:
        label: Status
        set: { Status: "{value}" }
        fields:
          - { name: value, kind: options, from_enum: Status }
      reply:
        label: Answer
        set: { Resolution: "{choice} {note}", Status: answered }
        fields:
          # the choices are the row's OWN proposed answers, ';'-separated
          - { name: choice, label: Answer, kind: options, from: Options, mode: single, other: true, required: true }
          - { name: note, label: Additional context, kind: textarea }

  # The development backlog's rows. Work, held to the same rule as features:
  # NO stored status. A ticket derives missing → partial → built from its
  # evidence, so "done" means the Implemented cell cites shipped code rather
  # than someone having moved a card. Priority and sprints do not exist here;
  # ordering lives in Depends and in the epic's own map.
  tickets:
    heading: Tickets
    identity: uuid
    columns:
      - { name: ID, id_grammar: "t<n>", unique: error, sequential: warn }
      - { name: Ticket, required: true }
      - { name: Kind, enum: shared.ticket_kind, unknown: warn }
      # the documentation that holds this ticket's requirements — the reason
      # a backlog belongs in the vault at all rather than in a tracker
      - { name: Context }
      - { name: Depends }
      - { name: Implemented, refs: [repo, route, api, db, event] }
      - { name: Gap }
      - { name: Owner, optional: true }
      - { name: Tests, optional: true, refs: [test] }
    forbid_columns:
      - { name: Status, severity: error, code: ticket-status-column }
      - { name: Priority, severity: error, code: ticket-priority-column }
    derive:
      state:
        - { when: "implemented && !gap && ref_broken", then: drift }
        - { when: "implemented && !gap", then: built }
        - { when: "implemented && gap", then: partial }
        - { when: "!implemented && gap", then: missing }
        - { else: unknown }
    checks:
      - { code: ticket-unbound, severity: warn,
          when: "implemented && !gap && !has_refs",
          message: "claims done but cites no evidence — nothing proves it" }
      - { code: ticket-no-context, severity: warn,
          when: "!context",
          message: "no Context link — a ticket should point at the documentation holding its requirements" }
    display:
      intro: prose
      layout: { narrow: cards }
      filters: [state, Kind]
      columns:
        - { col: ID, style: mono, state: marker, card: eyebrow }
        - { col: Ticket, style: md, card: title }
        - { col: Kind, style: chip, card: badge }
        - { col: Context, style: md }
        - { col: Depends, style: plain }
        - { col: Implemented, style: md }
        - { col: Gap, style: md }
        - { col: Owner, style: md, control: { form: assign } }
    forms:
      assign:
        label: Assign
        set: { Owner: "[{who}](</Team/{who}.md>)" }
        fields:
          - { name: who, label: Owner, kind: options, from_concepts: person }

types:
  app:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, audience: string }
    sections: { duplicates: error }
    blocks: [features, open-questions]

  page:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, app: string, route: string }
    sections:
      expect: [Features]
      duplicates: error
    blocks: [features, navigation, open-questions]

  module:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, app: string }
    sections: { duplicates: error }
    blocks: [features, open-questions]

  service:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, owner: string }
    sections:
      expect: [Endpoints]
      duplicates: error
    blocks: [features, endpoints, open-questions]

  integration:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, provider: string }
    sections: { duplicates: error }
    blocks: [endpoints, open-questions]

  event:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, topic: string }
    sections:
      expect: [Message, Participants]
      duplicates: error
    blocks: [message, participants, open-questions]

  database:
    frontmatter:
      required: { title: string, description: string }
      # `name` is the short identifier used in db:// URIs and in tables'
      # `database:` frontmatter — it is what graph views join on
      optional: { tags: "string[]", timestamp: date, name: string, engine: string }
    sections: { duplicates: error }
    blocks: [open-questions]

  table:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, database: string }
    sections:
      expect: [Columns]
      duplicates: error
    blocks: [columns, open-questions]

  enum:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, database: string, stored_in: string }
    sections:
      expect: [Values]
      duplicates: error
    blocks: [values, open-questions]

  # A flow carries BOTH surfaces: Scenarios enumerate the paths (with test
  # coverage), Features carry the traceability of what each step must do
  # (with evidence). Anomalies point at scenarios; open questions point at
  # features — one doubt channel, same shape everywhere.
  flow:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, parent_flow: string }
    sections:
      expect: [Scenarios, Features]
      duplicates: error
    blocks: [features, scenarios, anomalies, open-questions, transitions]

  # Who is on the team. A roster the vault maintains as documents, so the
  # ownership picker and any "whose work is this" query read from one place.
  # A unit of work big enough to need its own document: the why, the map of
  # how its tickets depend on each other, and the tickets themselves.
  epic:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date }
    sections:
      expect: [Tickets]
      duplicates: error
    blocks: [tickets, open-questions]

  person:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date, email: string }
    sections: { duplicates: error }
    blocks: [open-questions]

  actor:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date }
    sections: { duplicates: error }
    blocks: [open-questions]

  decision:
    frontmatter:
      required: { title: string, description: string,
                  status: { enum: [proposed, accepted, superseded] } }
      optional: { tags: "string[]", timestamp: date }
    sections:
      expect: [Context, Decision]
      duplicates: error
    blocks: [open-questions]

  engineering-note:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date }
    sections: { duplicates: error }
    blocks: [open-questions]

  convention:
    frontmatter:
      required: { title: string, description: string }
      optional: { tags: "string[]", timestamp: date }
    sections: { duplicates: error }
    blocks: [open-questions]

# Feedback: the capture layer. Readers post feedback LINKED to an entity (a
# document, or a specific row); it lands in a ledger (feedback.jsonl), never
# in the documents. An agent applies accepted items to the docs later
# (dj annotate) and advances their status. Vocabulary is yours.
#
# `when: read-only` is how a capture and a write-through form coexist for the
# same question: where the host can write documents the reader answers the
# document itself (the `reply` forms above); where it cannot, the same question
# is captured to the ledger instead.
feedback:
  # archived = seen, nothing to action — kept for the record but skipped by an
  # agent's review pass (which reads --status new)
  statuses: [new, acknowledged, applied, rejected, archived]
  default: new
  capture:
    # This form demos every field kind — trim it to taste. In practice a light
    # form wins: a capture longer than the documents it judges goes unused,
    # and where the host already knows the reader (SSO email) drop Name too.
    comment:
      on: concept
      label: Leave feedback
      fields:
        - { name: text, label: Comment, kind: textarea, required: true }
        - { name: screenshot, label: Screenshot, kind: image, hint: paste or pick — downscaled before upload }
        - { name: sketch, label: Sketch, kind: diagram, hint: optional mermaid — a drawn answer stays parseable data }
        - { name: related, label: Related entities, kind: concepts, hint: click nodes on the graph to select }
        - { name: usefulness, label: How useful is this document?, kind: rating, max: 5 }
        - { name: author, label: Name }
    triage:
      submit: replace
      when: read-only
      on: rows
      block: anomalies
      label: Triage
      fields:
        - { name: choice, label: Verdict, kind: options, from: Options, mode: single, other: true, required: true }
        - { name: note, label: What you found, kind: textarea }
        - { name: author, label: Name }
    answer:
      submit: replace
      when: read-only
      on: rows
      block: open-questions
      label: Suggest answer
      fields:
        - { name: choice, label: Answer, kind: options, from: Options, mode: single, other: true, required: true }
        - { name: note, label: Additional context, kind: textarea }
        - { name: author, label: Name }
    # A comment pinned to a single feature row — captured into the ledger on
    # every dashboard, reviewed by a coding agent (`dj feedback list --status
    # new`). Appends: two people disagreeing about one feature are both worth
    # keeping. Archive keeps a seen comment out of the next review pass.
    feature-feedback:
      on: rows
      block: features
      label: Comment
      review:
        - { label: Archive, status: archived }
      fields:
        - { name: note, label: Comment, kind: textarea, required: true, hint: "what is wrong, missing, or worth the agent's attention on this feature?" }
        - { name: author, label: Name }
    # A course of action to close a feature's Gap — usually authored by a
    # coding agent into the ledger, then judged by a person on the dashboard:
    # "Endorse" moves it to acknowledged (the agent acts on it, applied when
    # the gap closes); "Ignore" rejects it. The labels only promise what the
    # engine performs — a status verdict; what follows is your team's loop.
    # The beside: link surfaces it from the Gap legend on the feature's card.
    gap-proposal:
      on: rows
      block: features
      label: Propose gap fix
      beside: { column: Gap, label: View proposal }
      review:
        - { label: Endorse, status: acknowledged }
        - { label: Ignore, status: rejected }
      fields:
        - { name: proposal, label: Course of action, kind: textarea, required: true, hint: "concrete steps that would close this feature's gap" }
        - { name: author, label: Name }
