ZDDC/zddc/internal/handler/default-project-rsk.form.yaml
ZDDC e3db2f8473 feat(records): simplest default tracking number + folder-bound originator
Two coupled cleanups so the baked-in defaults reflect the actual
convention instead of leaking one project's choices into every
deployment:

- Drop the project-wide phase/area components from the default
  filename_format, form schemas, and table columns. They must be
  all-on or all-off across a project to keep filenames lexically
  consistent, so the simplest default omits them; operators re-enable
  via the commented-out templates + a .zddc filename_format override.
  Teaching comments (incl. a field_codes: example) now ride along in
  defaults.zddc.yaml, which `show-defaults` dumps verbatim.
- Separate suffix from sequence with a template hyphen
  ({sequence}-{suffix?}); stored suffix is now just the part marker
  (A, 01) with no leading dash.
- New records: key `folder_fields: {field: parent-distance}` binds a
  body field to an ancestor folder name. The default mdl/rsk records
  bind originator to the party folder (distance 1) — the folder is the
  sole source of truth. The server overwrites the body value before
  validation + composition (WriteWithHistory and the rollup create
  path), and the form renderer marks the field read-only and pre-fills
  it. Rollup forms drop originator from required (server derives it
  from the selected party).

Tests: folder-binding overwrite + wrong-originator-filename 422, and a
form-render readOnly/prefill assertion; existing record tests realigned
so the party folder name equals the originator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:31:49 -05:00

160 lines
4.5 KiB
YAML

# Default project-rollup RSK row schema, served by zddc-server when
# no operator-supplied form.yaml exists at <project>/rsk/.
#
# Identical to the per-party RSK schema (default-rsk.form.yaml)
# except for one extra required field: `party`. The server reads it
# on POST <project>/rsk/form.html and routes the row to the matching
# <project>/archive/<party>/rsk/ folder. The `party` value is
# stripped from the YAML on write (folder name IS the identity); on
# read the dispatcher injects it back.
#
# To customize: drop your own form.yaml at <project>/rsk/form.yaml.
# Keep the `party` field shape unless you also customize the rollup
# create handler.
title: Risk (project rollup)
description: One risk across all parties. The first field (Package) routes the row to the matching archive/<party>/rsk/ folder; the rest mirrors the per-party RSK schema.
schema:
type: object
# `type` is intentionally absent from required: — the cascade's
# field_defaults inject type=RSK after schema validation, and the
# form renderer surfaces it as a locked readOnly field. Requiring
# it here would 422 well-behaved clients that omit the cascade-
# owned field.
# `originator` is also omitted from required: the server derives it
# from the selected party folder (folder_fields) after this schema
# runs, same as the rollup MDL form.
required: [party, project, discipline, sequence, title]
additionalProperties: false
properties:
party:
type: string
title: Package (party folder)
description: Routing key — must match an existing <project>/archive/<party>/ folder.
pattern: "^[A-Za-z0-9][A-Za-z0-9.-]*$"
minLength: 1
# --- Table-tracking components (same shape as the per-party rsk
# schema). Together with `row` they compose the filename.
originator:
type: string
title: Originator
description: Auto-set from the selected Package (party folder) — the folder is the source of truth. Read-only; leave blank.
readOnly: true
# phase: # project-wide; sits between originator and project
# type: string
# title: Phase
# minLength: 1
project:
type: string
title: Project
minLength: 1
# area: # project-wide; sits between project and discipline
# type: string
# title: Area
# minLength: 1
discipline:
type: string
title: Discipline
minLength: 1
type:
type: string
title: Document type
description: Locked to RSK by the cascade; the form renders this read-only.
enum: [RSK]
sequence:
type: string
title: Sequence
minLength: 1
suffix:
type: string
title: Suffix
description: Optional structural-part suffix (A, 01, ...). Just the letters/digits — the leading dash is added by the cascade's filename_format.
row:
type: string
title: Row
description: Zero-padded sequence within the parent register. Server-assigned.
readOnly: true
# --- Risk-level data.
title:
type: string
title: Risk
minLength: 1
category:
type: string
title: Category
description:
type: string
title: Description
likelihood:
type: integer
title: Likelihood
minimum: 1
maximum: 5
impact:
type: integer
title: Impact
minimum: 1
maximum: 5
severity:
type: integer
title: Severity
minimum: 1
maximum: 25
mitigation:
type: string
title: Mitigation
owner:
type: string
title: Owner
status:
type: string
title: Status
enum: [open, mitigated, accepted, closed]
dueDate:
type: string
title: Due date
format: date
notes:
type: string
title: Notes
# --- Audit fields (server-managed; read-only).
created_at:
type: string
title: Created
format: date-time
readOnly: true
created_by:
type: string
title: Created by
format: email
readOnly: true
updated_at:
type: string
title: Updated
format: date-time
readOnly: true
updated_by:
type: string
title: Updated by
format: email
readOnly: true
revision:
type: integer
title: Revision
minimum: 1
readOnly: true
previous_sha:
type: string
title: Previous SHA
readOnly: true
ui:
description:
ui:widget: textarea
mitigation:
ui:widget: textarea
notes:
ui:widget: textarea