Skip to content

projcore: rich task notes in the plan model (Task, task.set, .yppx, format plugin read/write) - #1802

Merged
yeroo merged 5 commits into
mainfrom
issue-1801-projcore-rich-task-notes-in-the
Oct 26, 2026
Merged

yeroo merged 5 commits into
mainfrom
issue-1801-projcore-rich-task-notes-in-the

Conversation

@yeroo

@yeroo yeroo commented Oct 25, 2026

Copy link
Copy Markdown
Owner

What and why

Closes #1801. A plugin's richtext Task Information Notes page could edit bold, italic, alignment and bullets, but the plan kept only plain text, so the formatting was dropped at OK. Task notes now carry their formatting beside the plain text.

  • Model. Task::rich_notes: canonical projcore::richtext markup, Some only when it formats something, and its plain text is always notes. notes stays plain for every existing reader (MSPDI <Notes>, the grid, search, yppxy).
  • Editing. Editor::set_rich_notes sets text and markup as one undo step; a style-only change is a step and marks the plan dirty; an identical value is no step. set_notes with new text clears the markup in the same step (same text keeps it).
  • projctl. task.set {rich_notes} (taken verbatim, never through the one-line \n escape; refused together with notes); task replies (task.get, task.set, task.list) carry rich_notes whenever the task has notes, as markup (canonical for unformatted notes, so a plain note starting with <p is never misread).
  • .yppx and format plugins. formatting.xml carries <note uid="N" markup="…"/> (newlines &#10;, tabs &#9;), written by one formatting::part_xml for .yppx and for yppx_plugin_write_ex; read back by .yppx and yppx_plugin_read_ex. No new ABI symbol. A plan without rich notes saves byte-identically. A <note> is applied only where the task's plain notes are its plain text, so old formatting never lands on new text; MSPDI imports and plugin reads without notes have none.
  • UI plugins. Every UI plugin request (suite view_json, yppxy run_command) carries a read-only view.rich_notes {uid: markup}; task.set rich_notes stays the only writer. The fixture's fixture.richnote (command only, no manifest change) proves the read-edit-write loop.
  • Docs: plugin_abi.rs, PROJECT.md, CLAUDE.md, yppxy's control table.

Resource and assignment notes are out of scope.

Tests

New tests in richtext (split_notes_keeps_markup_only_when_it_formats), editor (6, with an invariant helper), formatting::notes (6), yppx (2), projcore/tests/plugins.rs (rich_notes_cross_the_plugin_seam_both_ways), projctl (5), yppxy/tests/plugins.rs (a_ui_plugin_reads_and_writes_rich_notes), suite plugin_ui (the_view_json_carries_the_rich_notes). fmt and clippy -D warnings clean on projcore, projctl, yppxy, the fixture and the suite. No .uit was needed or run (the fixture's manifest is unchanged; macOS cannot drive the window).

Review

Plan agreed in two rounds (v1's gap: UI plugins see only MSPDI plus view, so view.rich_notes was added). revmux r1 (claude-only, 4 reviewers, none degraded): 0 Major, 2 Minor, both fixed in c183911 (the _ex ABI doc said the formatting text is NULL without formatting; yppxy's task.set table lacked rich_notes). Nothing disputed or deferred.

review stopped: round 1 had no Major; all findings fixed

🤖 Generated with Claude Code

https://claude.ai/code/session_01QPxLA5cJ1on1ZkqWFBMya6

yeroo and others added 5 commits October 26, 2026 01:19
A task's notes can carry richtext markup beside the plain text every
reader uses. set_rich_notes splits a value into the two (markup kept only
when it formats something), and a plain set_notes of new text drops the
markup so old formatting never comes back over new text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2XCadpiTmNZGJmLxXsMvK
#1801)

The markup travels where the formatting does, as <note uid markup>
children of formatting.xml, so a .mpp plugin gets it through the
existing _ex symbols and a .yppx save keeps it. A note is applied on read
only to a task whose plain notes it still describes; a plan without rich
notes writes the part exactly as before (or none).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2XCadpiTmNZGJmLxXsMvK
Markup is taken verbatim (never the one-line notes form), refused with
notes in one call, and every task reply with notes carries markup: the
stored formatting, else the plain notes' own canonical markup, so a plain
note that starts with <p> is never read as markup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2XCadpiTmNZGJmLxXsMvK
MSPDI carries plain notes only, so without this a plugin's richtext Notes
page would prefill plain text and its OK would wipe the formatting. Both
hosts add a read-only {uid: markup} map built in projcore; the fixture's
fixture.richnote runs the downstream loop (read, extend, task.set).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2XCadpiTmNZGJmLxXsMvK
…s rich_notes (#1801)

Review r1: the plugin ABI, PROJECT.md and CLAUDE.md still said the
formatting text is NULL whenever the plan has no formatting and is only
formatting, so a plugin author could drop every rich note. yppxy's control
verb table now lists task.set rich_notes and the reply key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2XCadpiTmNZGJmLxXsMvK
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 99.32660% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
projcore/src/formatting/notes.rs 97.14% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@yeroo
yeroo merged commit 3897908 into main Oct 26, 2026
14 checks passed
@yeroo
yeroo deleted the issue-1801-projcore-rich-task-notes-in-the branch October 26, 2026 00:15
@yeroo

yeroo commented Oct 26, 2026

Copy link
Copy Markdown
Owner Author

Merged automatically (auto-merge is on for this checkout): review stopped: round 1 had no Major; all findings fixed; merge rounds: none; whole suite green on c183911 (12798 tests); merge-check ok; CI 14/14 green.

Follow-ups: leftovers issue #1803 (both minor, plan out-of-scope items, filed new):

No finding was disputed or deferred.

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.

projcore: rich task notes in the plan model (Task, task.set, .yppx, format plugin read/write)

2 participants