Skip to content

Promote dev to unstable: Quick export, governed history, annotation review - #272

Merged
mberrys merged 60 commits into
unstablefrom
dev
Oct 12, 2026
Merged

mberrys merged 60 commits into
unstablefrom
dev

Conversation

@mberrys

@mberrys mberrys commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What changed

Promotes 43 non-merge commits (60 including merges) from dev into unstable for qualification. The main work is Quick print-to-PDF and PDF/PNG/TIFF export, governed Undo/Redo over revision history, read-only annotation review with signature status and a publish gate, direct authoring edits routed through Core, Quick measurement and text-selection tools, colour display modes and soft proof, a settings store with diagnostics, and a localization refresh. It also lands the G00 governance and provenance registers and the handler-coverage ratchet for the Quick shell (epic #231).

This merge closes no issues. The target is unstable, not the default branch, so closing keywords would not fire here. Issues stay open until the promotion to stable.

Release changelog

Scope: unstable (9f08efc0) → dev (15fed584), 43 non-merge commits.

Added

Changed

  • Handler-coverage gate: unbound KEEP and ABSORB commands fail the check unless ratcheted, and the ratchet can only shrink. Thirteen KEEP and ABSORB commands still await a handler (L03-13 — Restore Quick GUI coverage for the retired Widgets surfaces #231).
  • G00 governance: identity and issue provenance reconciled, obsolete milestone writer retired, source and architecture proof ownership frozen. Persisted package and application identifiers are retained.
  • Product-surface rows for the absorbed signature and scanner plugins keep their reviewed null follow-ups.

Fixed

  • Incomplete renders are refused before output publication. Export resolution is labelled, and restricted print permissions are reflected in the UI.

Internal

  • Governance register checks, Quick localization checks, command-catalog ratchet tests, and a private adapter for Core render diagnostics.

Breaking changes

None. Every change fragment in this range is marked Breaking-Change: no, and persisted identifiers are unchanged.

Issues referenced (not closed by this merge)

Refs #123
Refs #124
Refs #125
Refs #126
Refs #231
Refs #232
Refs #233
Refs #234
Refs #235
Refs #237
Refs #238
Refs #239
Refs #242

Proof

  • python scripts/agent/check-change.py --base origin/dev --build-dir build-local reports pass, or the report and the failing check are quoted here
  • One changes/<sanitized-head-branch>.md fragment added (Category, Audience, Breaking-Change, Summary). This range includes seven fragments.
  • Changed behaviour has a test that fails without the change
  • Protected-path or contract change named above, with the reason it is required

Internal logic (touched behavior-bearing code)

  • Guard clauses handle invalid, stale, cancelled, absent, unauthorized, and terminal cases before the happy path
  • Untrusted input is parsed once at the boundary into trusted typed or domain state, with no repeated checks downstream
  • Invalid state stops before partial mutation or publication and returns a descriptive error or result
  • Names carry the domain intent, and comments explain rationale rather than restating the code

Quality pass

  • Redundant or explanatory comments that do not match the file's style removed
  • Abnormal defensive checks and broad try/catch blocks removed where a trusted upstream boundary already guarantees the invariant, with real boundary and safety checks kept
  • No any or equivalent cast added only to suppress a type error
  • Python imports stay at file scope unless a local import is required
  • Generated boilerplate, needless wrappers, and local-style drift removed
  • Validation, security, cancellation, provenance, and failure handling preserved

Quality summary (1-3 sentences):

Not yet reviewed in this description. Fill in after the review pass.

Security and rollback

  • Untrusted input validated at the trust boundary; no new unsafe construct without an inline justification
  • Rollback: revert this PR's merge commit on unstable. The change fragments record no persisted-format migration.

Docs

  • Docs updated in this PR: QUICK_PRINT_EXPORT, QUICK_REVISION_HISTORY, QUICK_LOCALIZATION, REPOSITORY_GOVERNANCE, ADR-014 and related docs

Self-review (BSP-002 §4.3)

  • Reviewed in the diff view, not the editor, at least 30 minutes after the final commit; overnight if the change touches security-sensitive code, data handling, or public API surface

&lt;source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3.svg"&gt;&lt;source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v3.svg"&gt;&lt;img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3.svg"&gt; <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1794367539&installation_model_id=435800&pr_number=272&ref=codesmith_pr_footer&repository=studio-berry%2Floop&return_to=https%3A%2F%2Fgithub.com%2Fstudio-berry%2Floop%2Fpull%2F272&signature=5b252bb265cf7aaa0325666a6089194913f183823bf3ebca05f12f9f6a9218ef"&gt;&lt;picture&gt;&lt;source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"&gt;&lt;source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"&gt;&lt;img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"&gt;
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

🤖 Generated with Claude Code

https://claude.ai/code/session_013t7FobDex3xnyJM86dCg6F


Generated by Claude Code

Complete G00 repository governance and provenance (#108)
#231)

The descriptor availability flag is the handler gate: CommandCatalog refuses
a handler for a declared id and invoke() answers command/not-implemented, so a
KEEP or ABSORB action that is still declared is a menu entry that does nothing.
scripts/verify-command-catalog.py now requires every KEEP/ABSORB action to be
implemented or listed in docs/shell-handler-coverage.json, the baseline that
records today's 70 gaps and may only shrink. --record-ratchet rewrites it.
Negative-case tests prove each rule can fail; ci.yml and check-change.py
report the check as whole-tree evidence.
… the live epic (#231)

The G00 provenance repair re-homed the absorbed plugin rows; these two ADVANCED
rows were left null while their replacement surfaces (signing in loop-fix, the
scanner document workflow) are still pending, so no live issue owned them.
#232)

Text and Measure join the closed InteractionTool vocabulary as their own
InteractionKinds: a text selection is a typed, revision-fenced TextSelection
resolved through Core's text layout in reading order, and a measurement is a
typed revision-fenced Measurement in production units that never becomes a
DragSession. The nine actionSelect*/CopyText/GoTo*Line/Screenshot/ExtractImage
commands are bound; screenshot and image extraction write through the atomic
writer and refuse to overwrite; a page without a text layer reports
text/no-text-layer instead of copying an empty string.
)

Five actionColor* display modes become presentation-only filters applied in
CanvasNodeBuilder::syncTiles over admitted surfaces, converted with Core's own
PDFColorConvertor, marked as simulations in the fidelity indicator and never
reachable as production evidence. Soft proof renders through a local
LittleCMS proofing CMS behind its own surface identity (withSoftProofMarker),
shows the profile identity, and a missing or unreadable output intent is a
visible state. Plates expose Core's separations with visibility and isolation
state that never moves the revision, and the ink-coverage readout measures
named channels at a page point.
One typed QSettings-backed store with confirmed reset-to-factory and visible
repair of invalid persisted values; actionOptions, actionResetToFactorySettings,
actionCollectDiagnostics, the six render-option toggles and the text-block/line
views are bound and developer-gated; the ADR-006 diagnostics bundle comes from
Core's PDFDiagnosticsCollector. The five KEEP render options are reclassified
ADVANCED with rationale and the host routes menus from the manifest's
menu_group, so they are reachable in a developer profile only.
The implemented-descriptor pin is now 51 (26 + display modes + select/copy/
capture + settings/diagnostics), and the handler-coverage baseline is
re-recorded from the merged manifest: 51 KEEP/ABSORB commands remain.
…al (#232, #238)

The shell keyboard test pinned "measure" as an unknown tool; it is a real
vocabulary member now, so the negative case moves to "lasso" and the test
asserts both new tools route to the controller. The new host case proves image
extraction refuses to overwrite an existing file and leaves it byte-identical.
The PR fragment and evidence manifest cover the integrated slices.
…tion publish gate

List annotations from the open revision in a read-only review column and paint them in their own overlay band, bounded so findings and selection primitives keep their budget, with page-region navigation from the list. Verify document signatures off the UI thread and reduce results to five distinct operator-facing states behind a request/generation/revision-fenced token. Disclose save-policy signature invalidation in the correction-plan preview and the approval, and refuse to publish an invalidating plan over a signed document until the exact plan digest is acknowledged.
…ignature-review

L03-11: read-only annotation review and signature status with an invalidation publish gate (#125)
mberrys and others added 26 commits October 11, 2026 02:33
…zation

Localize the Quick shell with a shared glossary
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
…tory

Present Quick Undo and Redo as governed revision history
Reconcile the EditorHost constructor: settings come first, then the parent and
the recipes directory dev added, so existing dev call sites pass the null
settings argument explicitly. Keep both sides' members in the editor host.
Keep the undo and redo handlers from dev in the command catalog and drop them
from the handler ratchet baseline, which now records 49 gaps. The facade test
expects the 53 implemented commands.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
Keep both published-output records side by side. The Action List worker
still records the in-memory published bytes that the export and receipt use,
and now also records the published path that the undo and redo history
tracks. The editor host clears and sets both together. Both sides' tests stay,
the command catalog takes the union of the two branches' implemented commands,
and the facade test expects the 30 implemented commands. The quick PDF parity
note lists print and export and undo and redo as done.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
The editor host constructor now takes the settings store first, then the
parent and recipes directory. A test added from dev still used the old
two-argument form, which failed to compile and stopped UnitTestsEditorHost
from being built. Pass a null settings argument at each recipe-path call.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
The editor host constructor now takes the settings store first, then the
parent and recipes directory. The merged tests still used the old two-argument
form, which fails to compile. Pass a null settings argument at each
recipe-path call.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
The previous commit's regex matched calls that already passed the settings
argument and inserted a second one, which produced four-argument calls that
do not compile and break the clang-format check. Restore one null settings
argument per recipe-path call.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
The settings-first constructor exists only on the epic branch. This branch
still builds against dev, where the constructor takes the parent and the
recipes directory, so the test calls I changed here do not compile. Restore
the calls to the dev form.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
…export

Add Quick print-to-PDF and exact document exports
Bring in the print and export commands from #263. Keep this branch's finish
steps and availability updates alongside dev's document output step and the
print and export availability. Keep both sides' editor host tests, with the
print and export tests first and the display-mode test after them. Take the
union of both branches' implemented commands and regenerate the handler
ratchet, which now records 48 gaps. The facade test expects the 55 implemented
commands.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqo8EDq3w2nU1zekEZDoZc
feat(quick): handler-coverage gate and read-only surfaces (#231 PR 1)
Records the #234 precondition: annotation, bookmark, link, form,
attachment and metadata edits are direct Core mutations through
CommandCatalog producing a new revision (fenced, one history event
per edit), not planned Fix operations; adds the 013 row missing
from the ADR index.
#231 PR 2)

Cherry-picks the three slice commits and repairs the conflict regions with
complete blocks from each slice: one facade gateway per family (unified in
follow-up), the 39 implemented ids, expected_action_count 109 -> 113, the
handler ratchet re-recorded to 13, and the PR fragment plus evidence manifest.
…uest (#231 PR 2, ADR-014)

Collapses the three family gateways into the single DirectEditRequest /
DirectEditOutcome / DocumentFacade::applyDirectEdit shape ADR-014 records,
dispatching by edit kind to the annotation, outline and document helpers.
Refusal codes and fence order per family are unchanged; all call sites and
the facade tests are adapted.
… proof lanes (#231 PR 2)

Adds UnitTestsAuthoringEdit to the core module (paths + tests) so the
catalog target has a proof lane, rewrites the evidence manifest against the
touched subsystems' required lanes (core, interaction, quick, build_policy,
governed-execution incl. the canonical-json-golden fixture and packaging
workflows; the independent-validation stub is listed unresolved), and
clang-formats pdfauthoringedit.h.
The defaulted operator== makes GCC 13 instantiate the definition while
QList's own equality is still forming (has_operator_equal probe), a hard
error CI caught; the explicit declaration is portable and MSVC-identical.
…lpers

firstLinkOnPage/linkOnPage returned a raw pointer into a temporary or local
PDFAnnotationPtr, so the annotation was freed before use; glibc's freed-chunk
metadata clobbers the vtable and the next dynamic_cast segfaults (MSVC
survived by heap luck). The helpers now return the owning pointer and call
sites downcast explicitly.
feat(quick): direct mutations through the catalog — bookmarks/links, annotations, forms/attachments/metadata (#231 PR 2)
@mberrys mberrys changed the title Dev Promote dev to unstable: Quick export, governed history, annotation review Oct 12, 2026
@mberrys
mberrys added this pull request to stack #274 October 12, 2026 18:59
@mberrys
mberrys merged commit d809628 into unstable Oct 12, 2026
28 checks passed
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.

2 participants