Every document page that opts into the Universal Document Shell gets a "Notes / Requirements" section at the bottom. Users submit improvement requests, content gaps, requirements, or bugs against a specific page. Notes persist in browser localStorage (scaffold). A future AI periodic sweep reviews the backlog across all documents. This page is the contract.
Notes are per-document · 14-field schema · 8 lifecycle states · 2 sort modes · localStorage-backed today · server-ready schema · AI sweep is MODELED not live.
The system answers a simple question: "How do we capture 'this document should do X' without losing it?" Every document gets a note loop with submit form, sort toggle (newest/oldest), status transitions (open → triaged → … → done/rejected), and a summary counter (open/done/deferred/latest-activity). Notes belong to doc_id (from data-ds-doc-id) and never leak across documents.
AI periodic review is a model (document_note_sweep_model.json): defines 10 checks an automated sweep would run, allowed mutations, report shape. No scheduler yet. An operator can apply the rules manually today.
Persistence is honest: browser-local only. The schema is designed so a future server backend can consume identical rows. Batch 7+ will implement persistence.
Full spec: assets/notes/document_note_schema.json
| Field | Type | Required | Purpose |
|---|---|---|---|
note_id | string | yes | Stable id · never changes |
doc_id | string | yes | Partition key (from data-ds-doc-id) |
section_ref | string? | no | Anchor inside the doc |
created_at | ISO-8601 | yes | First creation |
created_by_type | enum | yes | human · AI · system · imported |
title | string | yes | Summary |
body | string | no | Details |
note_type | enum | yes | requirement · bug · content-gap · … |
priority | P0/P1/P2/P3 | yes | Default P2 |
status | enum | yes | See status matrix |
resolved_flag | bool | yes | Derived · true when status in (done, rejected) |
linked_change_ref | string? | no | Commit / PR pointer |
resolved_at | ISO-8601? | no | Terminal timestamp |
last_action_at | ISO-8601 | yes | Any mutation |
Full spec: assets/notes/document_note_status_matrix.json
| Status | Meaning | Terminal? | Color |
|---|---|---|---|
| open | Newly submitted · awaiting triage | no | blue |
| triaged | Acknowledged · classified | no | purple |
| in_review | Under active evaluation | no | amber |
| planned | Scheduled for a future batch | no | amber |
| in_progress | Work has started | no | pink |
| done | Resolved · should have linked_change_ref | yes | green |
| deferred | Valid but postponed | no | gray |
| rejected | Declined | yes | rose |
Terminal states allow reopen (→ open). No other ad-hoc transitions permitted.
Full spec: assets/notes/document_note_sweep_model.json
Honest state: MODELED · NOT WIRED. No cron. No queue. No scheduler.
10 checks (C-01 through C-10):
AI mutation rules: may create notes with created_by_type="AI"; may NOT edit human-created notes' status or linked_change_ref. Full rules in the model file.
A page gets the notes UI by including this block inside a .ds-tabpanel (or anywhere in a shelled page):
<div class="ds-section ds-section--notes" data-ds-notes>
<h2>Notes</h2>
<div class="ds-notes-meta" data-ds-notes-summary></div>
<form class="ds-notes-new" data-ds-notes-form> ... </form>
<div class="ds-notes-toolbar">
<div class="ds-sort" data-ds-notes-sort>
<button data-sort="newest" class="on">Newest</button>
<button data-sort="oldest">Oldest</button>
</div>
</div>
<div data-ds-notes-list class="ds-notes-list"></div>
</div>
document-shell.js auto-wires submit, sort, status transitions, delete, and summary. No page-specific code.
note-<base36-ts>-<5char>.data-ds-doc-id. Notes are partitioned by this key.done or rejected. Reopen allowed.