Skip to content

feat(rules,backend,web): narrative identity — epithet, appearance, traits, backstory#36

Merged
StreamDemon merged 2 commits into
mainfrom
feat/narrative-identity
Jul 4, 2026
Merged

feat(rules,backend,web): narrative identity — epithet, appearance, traits, backstory#36
StreamDemon merged 2 commits into
mainfrom
feat/narrative-identity

Conversation

@StreamDemon

@StreamDemon StreamDemon commented Jul 4, 2026

Copy link
Copy Markdown
Owner

PR B of #10: users own their characters. New optional, player-authored narrative fields with designed homes on the sheet — story, not mechanics.

Rules

  • narrativeSchemaepithet (≤200), appearance (height/weight/age/eyes/origin/disposition), traits (≤12 chips, ≤60 chars each), backstory (≤20k) — all optional, attached as characterSchema.narrative.
  • deriveSheet passes it through onto the sheet untouched. A test derives the same build with and without a narrative and asserts identical combat/vitals/skills/saves: nothing here can affect a number.

Backend

  • characterFields.narrative mirrors the shape; create/update validate it for free via the existing rules round-trip.
  • characters.updateNarrative — a narrow mutation to edit the story without resubmitting the whole build. It merges into the stored character and re-validates through the rules layer, so bounds are enforced at the write; passing no narrative clears it.

Web

  • Identity band on the sheet (per DESIGN.md): schematic portrait frame ("NO IMAGE ON FILE" — upload is future work), name with the epithet in the one human serif voice, trait chips, physicals readout beside the alignment stamp, and the "PERSONNEL FILE — NARRATIVE" backstory panel.
  • Wizard: the identity step grows a collapsible "PERSONNEL FILE — OPTIONAL" section (shared NarrativeFields form; name remains the only required field).
  • Dossier: an "EDIT FILE" panel using the same form, saving via updateNarrative. Deliberately rendered outside the keyed sheet <Match> so live subscription updates (e.g. rolling vitals mid-edit) can''t remount the editor and wipe typed text.

Verification

Browser-verified against the local deployment: opened Kestrel''s dossier → EDIT FILE → filled epithet/appearance/traits/backstory → Commit to File → the identity band, chips, physicals, and backstory panel streamed in live over the subscription with zero console errors. Wizard personnel-file section renders and folds.

157 tests across the workspace (7 new); per-package vp check and the production build are clean.

Out of scope: portrait upload (file storage), PR C (interactive rolls + telemetry rail + vitals bars).


Summary by cubic

Add optional player-authored narrative fields (epithet, appearance, traits, backstory) that appear on the character sheet and never affect mechanics. Adds a focused way to edit this story data without resubmitting a build.

  • New Features

    • Rules: narrativeSchema added to characterSchema.narrative (epithet, appearance, traits, backstory). deriveSheet passes it through untouched; does not change any numbers.
    • Backend: characterFields.narrative plus characters.updateNarrative to edit or clear narrative. Changes re-validated through the rules layer to enforce limits.
    • Web: Sheet identity band (portrait frame, epithet, trait chips, appearance readout, backstory panel). Builder identity step gains an optional collapsible section. Dossier adds an EDIT FILE panel using shared NarrativeFields, saving via updateNarrative and rendered outside the keyed sheet to avoid wiping in-progress edits.
  • Bug Fixes

    • Rules: Traits reject commas to preserve round-trip via comma-separated editors; test added.
    • Web: Narrative editor resets (and closes) when the route id changes, preventing cross-character drafts.
    • Web: PERSONNEL FILE and EDIT FILE toggles expose aria-expanded/aria-controls.
    • Web: Form fields mirror schema caps via maxLength so writes can't fail on length.
    • Web: Appearance block hides when an API-written appearance: {} has no values.

Written for commit 5b1007e. Summary will update on new commits.

Review in cubic

…aits, backstory

PR B of #10: users own their characters. New optional player-authored
fields, ignored by the rules engine (story, not mechanics — nothing
here can affect a derived number).

- rules: narrativeSchema (epithet <=200, appearance fields, <=12
  traits, backstory <=20k) as optional characterSchema.narrative;
  deriveSheet passes it through onto the sheet untouched. 5 tests
  incl. proof that identical builds with/without narrative derive
  identical numbers.
- backend: characterFields.narrative + characters.updateNarrative — a
  narrow mutation that edits the story without resubmitting the build,
  still round-tripping the merged character through the rules layer so
  bounds are enforced at the write; passing no narrative clears it.
  2 tests (round-trip incl. clear; bounds rejection).
- web: shared NarrativeFields form (wizard identity step grows a
  collapsible PERSONNEL FILE section; the dossier gains an EDIT FILE
  panel via updateNarrative). SheetView identity band: schematic
  portrait frame ("NO IMAGE ON FILE"), name + serif epithet, trait
  chips, physicals readout, and the backstory panel in the one human
  voice. The editor lives outside the keyed sheet Match so live
  updates (e.g. rolling vitals mid-edit) cannot remount it and wipe
  typed text.

Browser-verified: edited Kestrel via EDIT FILE -> identity band,
chips, physicals, and backstory streamed onto the dossier live; wizard
personnel-file section renders. 157 tests, per-package checks and
prod build clean.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 12 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/web/src/pages/character-sheet.tsx
Comment thread apps/web/src/builder/steps/identity.tsx Outdated
Comment thread apps/web/src/lib/narrative.ts
Comment thread apps/web/src/components/narrative-fields.tsx
Comment thread apps/web/src/components/sheet-view.tsx Outdated
…mma traits, disclosure a11y, form caps, empty-appearance guard

- the dossier editor resets its form (and closes) whenever the route
  id changes, so one character''s draft can never be written into
  another''s file — no longer relying on remount timing
- traits reject commas at the schema (chips are comma-separated in
  editors; a comma would split a chip on round-trip) + regression test
- both disclosure toggles (PERSONNEL FILE, EDIT FILE) carry
  aria-expanded/aria-controls
- form controls mirror the schema caps via maxLength (epithet 200,
  appearance 40-120, backstory 20k, traits worst-legal-case), so
  writes cannot be rejected for length
- the physicals block hides when an API-written `appearance: {}` has
  no rows to show

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 6 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@StreamDemon StreamDemon merged commit 113af55 into main Jul 4, 2026
2 checks passed
@StreamDemon StreamDemon deleted the feat/narrative-identity branch July 4, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant