# PrintCraft parity checklist vs Acrobat Pro (offline feature set). Generated from plan docs; maintained by hand. # Validated and reported by `cargo xtask parity`. Schema: see the [schema] table. # Status rules: `shipped` = usable today with at least one cited test; `partial` = part exists (notes say what is # missing); `planned` = not started; `na` = Adobe-cloud-only (notes name the local or pluggable alternative). # `commands` lists registry ids from crates/engine/src/commands.rs only; `tools` lists crates/automation/src/tools.rs names. [schema] version = 1 statuses = ["planned", "partial", "shipped", "na"] tiers = ["P0", "P1", "P2", "P3", "N/A"] areas = { A = "core", B = "view", C = "edit", D = "organize", E = "comment", F = "form", G = "protect", H = "sign", I = "ocr", J = "create", K = "optimize", L = "print", M = "a11y", N = "misc" } # ================================================================================================== # A. Core document model and fidelity # ================================================================================================== [[feature]] id = "core.open-pdf" title = "Open PDF files" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.open"] tools = ["doc_open"] evidence = ["crates/automation/tests/automation.rs::open_inspect_render_and_find", "crates/ui-egui/tests/ui.rs::opening_a_pdf_shows_comments_and_bookmarks"] notes = "" [[feature]] id = "core.repair-broken-files" title = "Open damaged files by reconstructing the cross-reference table" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.open"] tools = ["doc_open"] evidence = ["crates/cos/src/document.rs::damaged_xref_is_reconstructed", "crates/cos/src/parser.rs::indirect_stream_with_wrong_length_recovers", "crates/cos/src/document.rs::self_referential_length_does_not_overflow"] notes = "" [[feature]] id = "core.malformed-input-safety" title = "Reject garbage or hostile input without crashing" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::garbage_input_is_rejected_without_panicking", "crates/cos/src/parser.rs::garbage_never_panics", "crates/render/src/raster.rs::missing_page_and_garbage_input_fail_gracefully"] notes = "fuzzed nightly (M1.10)" [[feature]] id = "core.repair-log" title = "Record repairs and show them to the user" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/viewer.rs::damaged_files_say_they_were_repaired"] notes = "a notice says the file was repaired; Document Properties ▸ Advanced lists the repairs; doc_info reports them" [[feature]] id = "core.xref-streams" title = "Read cross-reference streams and compressed object streams" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/cos/tests/writer.rs::incremental_saves_stack_on_an_xref_stream_file", "crates/cos/tests/writer.rs::page_tree_loops_in_object_streams_do_not_crash_readers"] notes = "" [[feature]] id = "core.hybrid-xref" title = "Hybrid-reference files (/XRefStm) and quirky xref subsections" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = ["doc_open"] evidence = ["crates/cos/src/document.rs::hybrid_reference_files_read_the_xref_stream_too"] notes = "/XRefStm entries supplement the classic table and replace its free entries for objects in object streams; each section is merged as a unit so older revisions only fill gaps" [[feature]] id = "core.revision-chain" title = "Follow /Prev revision chains with loop protection" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.properties"] tools = ["doc_revisions"] evidence = ["crates/cos/src/document.rs::looping_revision_chains_stop", "crates/cos/src/document.rs::revision_ends_split_incremental_updates"] notes = "/Prev chains followed newest first with a visited set (loops stop and are logged); revisions listed and opened (doc_revisions, doc_open_revision)" [[feature]] id = "core.stream-filters" title = "Standard stream filters (Flate, LZW, ASCII85, ASCIIHex, RunLength, predictors)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/filters/src/lib.rs::chain_three_filters_with_predictor", "crates/filters/src/lzw.rs::spec_example", "crates/filters/src/predictor.rs::png_hand_vectors"] notes = "" [[feature]] id = "core.image-filters" title = "Image codecs in the filters crate (DCT, JPX, JBIG2, CCITT)" area = "A" tier = "P0" milestone = "M1" status = "partial" commands = [] tools = [] evidence = [] notes = "decoded through the hayro bootstrap for display; own codecs are M1.1/M1.2" [[feature]] id = "core.decompression-limits" title = "Bounded decompression (filter bomb protection)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/filters/src/flate.rs::bomb_is_bounded", "crates/filters/src/lib.rs::limit_applies_to_intermediate_buffers"] notes = "" [[feature]] id = "core.open-rc4" title = "Open RC4-encrypted documents (40/128-bit)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.open"] tools = ["doc_open"] evidence = ["crates/crypt/src/tests.rs::rc4_reference_vectors", "crates/cos/tests/encryption.rs::every_algorithm_round_trips_and_hides_the_content"] notes = "" [[feature]] id = "core.open-aes" title = "Open AES-128 and AES-256 encrypted documents (R4-R6)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.open"] tools = ["doc_open"] evidence = ["crates/crypt/src/tests.rs::aes_cbc_nist_sp800_38a_vectors", "crates/cos/tests/encryption.rs::every_algorithm_round_trips_and_hides_the_content"] notes = "" [[feature]] id = "core.password-prompt" title = "Ask for the user or owner password, with retry" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.open"] tools = ["doc_open"] evidence = ["crates/ui-egui/tests/editing.rs::password_prompt_opens_and_security_tab_reports_the_details", "crates/crypt/src/tests.rs::empty_user_password_opens_without_asking"] notes = "" [[feature]] id = "core.unicode-passwords" title = "Unicode passwords normalised with SASLprep" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/crypt/src/tests.rs::r6_passwords_are_saslprepped"] notes = "" [[feature]] id = "core.owner-password-unlock" title = "Owner password lifts document restrictions" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = ["doc_open"] evidence = ["crates/engine/src/tests.rs::restricted_documents_refuse_changes_unless_opened_by_the_owner", "crates/engine/src/tests.rs::owner_password_of_older_revisions_opens_the_viewer_too", "crates/crypt/src/tests.rs::owner_authentication_recovers_the_user_password"] notes = "" [[feature]] id = "core.permissions-enforced" title = "Honour document permissions (print, modify, assemble, copy)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::restricted_documents_show_a_notice_and_block_page_changes", "crates/crypt/src/tests.rs::permission_bits_follow_table_22", "crates/engine/src/tests.rs::combining_protected_files_is_refused_clearly"] notes = "" [[feature]] id = "core.crypt-filters" title = "Crypt filters (Identity, /StmF, /StrF)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/crypt/src/tests.rs::identity_crypt_filters_leave_data_alone"] notes = "" [[feature]] id = "core.attachment-only-encryption" title = "Attachment-only encryption (/EFF) opens without a password" area = "A" tier = "P1" milestone = "M1" status = "partial" commands = [] tools = [] evidence = [] notes = "two corpus files still ask for a password (M1.6)" [[feature]] id = "core.unencrypted-metadata" title = "Leave XMP metadata readable when /EncryptMetadata is false" area = "A" tier = "P1" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/cos/tests/encryption.rs::unencrypted_metadata_is_left_readable"] notes = "" [[feature]] id = "core.unsupported-handlers" title = "Clear message for unsupported security handlers" area = "A" tier = "P1" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/crypt/src/tests.rs::unsupported_handlers_are_reported"] notes = "" [[feature]] id = "core.open-public-key" title = "Open certificate-encrypted (public-key handler) documents" area = "A" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.incremental-save" title = "Save as an incremental update (original bytes kept, atomic write)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.save"] tools = ["doc_save"] evidence = ["crates/ui-egui/tests/editing.rs::save_writes_an_incremental_update_and_clears_dirty", "crates/engine/src/tests.rs::save_is_incremental_stamps_mod_date_and_rebases", "crates/organize/src/tests.rs::successive_incremental_saves_stack_revisions"] notes = "" [[feature]] id = "core.save-as-full-rewrite" title = "Save as a new file with a full rewrite and garbage collection" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.save_as"] tools = ["doc_save"] evidence = ["crates/organize/src/tests.rs::full_save_drops_unreachable_objects", "crates/engine/src/tests.rs::full_save_is_readable_and_smaller_after_deletes"] notes = "" [[feature]] id = "core.object-stream-compression" title = "Compress objects into object streams behind an xref stream on full save" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.save_as"] tools = ["doc_save"] evidence = ["crates/cos/tests/writer.rs::full_save_packs_objects_into_object_streams", "crates/cos/tests/writer.rs::qpdf_accepts_object_stream_output", "crates/cos/tests/writer.rs::objects_referenced_by_the_encrypt_dictionary_stay_outside_object_streams"] notes = "" [[feature]] id = "core.encrypted-save" title = "Save encrypted documents re-encrypted under the same keys" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = ["file.save"] tools = ["doc_save"] evidence = ["crates/cos/tests/encryption.rs::incremental_edits_of_encrypted_documents_stay_encrypted", "crates/engine/src/tests.rs::encrypted_documents_open_edit_and_save_encrypted"] notes = "" [[feature]] id = "core.copy-on-write-fidelity" title = "Preserve untouched objects byte-for-byte (copy-on-write edits)" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/cos/src/document.rs::reads_classic_revision_and_edits_are_copy_on_write"] notes = "" [[feature]] id = "core.write-validity" title = "Written files pass qpdf --check" area = "A" tier = "P0" milestone = "M1" status = "shipped" commands = [] tools = [] evidence = ["crates/cos/tests/encryption.rs::qpdf_agrees", "crates/cos/tests/writer.rs::qpdf_accepts_object_stream_output"] notes = "skipped when qpdf is absent" [[feature]] id = "core.deterministic-save" title = "Deterministic full-save mode" area = "A" tier = "P2" milestone = "M1" status = "planned" commands = [] tools = [] evidence = [] notes = "M1.9 option" [[feature]] id = "core.linearization" title = "Linearized save (Fast Web View)" area = "A" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.revision-list" title = "List document revisions from the xref chain" area = "A" tier = "P1" milestone = "M1" status = "shipped" commands = ["file.properties"] tools = ["doc_revisions"] evidence = ["crates/cos/src/document.rs::revision_ends_split_incremental_updates", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "revision ends from the xref chain (linearized first-page sections fold into their revision); listed in Document Properties ▸ Advanced and by doc_revisions with the signatures covering each" [[feature]] id = "core.view-revision" title = "View an earlier revision as a read-only snapshot" area = "A" tier = "P1" milestone = "M9" status = "shipped" commands = ["file.properties"] tools = ["doc_open_revision"] evidence = ["crates/ui-egui/tests/viewer.rs::an_earlier_revision_opens_from_document_properties", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "opens the revision's bytes as a new unsaved document named ' (revision n)'" [[feature]] id = "core.lazy-loading" title = "Lazy loading of very large (GB) files within a memory budget" area = "A" tier = "P0" milestone = "M1" status = "planned" commands = [] tools = [] evidence = [] notes = "ByteSource (M1.5); files are buffered whole today" [[feature]] id = "core.pdf20-utf8-strings" title = "PDF 2.0 UTF-8 text strings" area = "A" tier = "P1" milestone = "M2" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.pdf20-associated-files" title = "PDF 2.0 associated files (/AF)" area = "A" tier = "P1" milestone = "M2" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.pdf20-dpart" title = "PDF 2.0 document parts (DPart)" area = "A" tier = "P2" milestone = "M2" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.pdf20-namespaces" title = "PDF 2.0 structure namespaces" area = "A" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.arlington-validation" title = "Structural validation against the Arlington PDF model" area = "A" tier = "P1" milestone = "M2" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.undo-redo" title = "Undo and redo every document edit" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = ["edit.undo", "edit.redo"] tools = ["edit_undo", "edit_redo"] evidence = ["crates/engine/src/tests.rs::undo_and_redo_restore_exact_states", "crates/ui-egui/tests/editing.rs::organize_delete_then_undo_and_redo_with_keys"] notes = "" [[feature]] id = "core.undo-labels" title = "Edit menu names the step to undo or redo" area = "A" tier = "P1" milestone = "M4" status = "shipped" commands = ["edit.undo", "edit.redo"] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::edit_menu_names_the_step_to_undo", "crates/engine/src/commands.rs::enablement_follows_the_document_state"] notes = "" [[feature]] id = "core.undo-after-save" title = "Undo still works after saving" area = "A" tier = "P1" milestone = "M4" status = "shipped" commands = ["edit.undo"] tools = ["edit_undo"] evidence = ["crates/engine/src/tests.rs::undo_still_works_after_save"] notes = "" [[feature]] id = "core.atomic-batch-edits" title = "Multi-step edits are one undo step and all-or-nothing" area = "A" tier = "P1" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/engine/src/tests.rs::batch_is_one_undo_step_and_all_or_nothing", "crates/engine/src/tests.rs::failed_edit_changes_nothing"] notes = "" [[feature]] id = "core.history-panel" title = "History panel with named snapshots" area = "A" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.autosave" title = "Autosave changed documents periodically" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/engine/src/tests.rs::autosave_snapshots_only_changed_documents", "crates/ui-egui/tests/recovery.rs::saving_or_closing_clears_the_entry_and_nothing_is_written_for_clean_documents"] notes = "" [[feature]] id = "core.crash-recovery" title = "Offer to recover unsaved work after a crash" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/recovery.rs::a_crashed_session_is_offered_and_recovered_unsaved", "crates/ui-egui/tests/recovery.rs::discarding_removes_the_autosaves", "crates/engine/src/tests.rs::recovered_documents_reopen_unsaved_at_their_original_path"] notes = "" [[feature]] id = "core.encrypted-autosave" title = "Autosaves of encrypted documents stay encrypted" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/recovery.rs::encrypted_documents_are_autosaved_encrypted_and_recovered_with_the_password"] notes = "" [[feature]] id = "core.web-recovery" title = "Crash recovery in the web app" area = "A" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "core.unsaved-changes-prompt" title = "Ask before closing or quitting with unsaved changes" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = ["file.close"] tools = ["doc_close"] evidence = ["crates/ui-egui/tests/editing.rs::closing_a_dirty_tab_asks_and_cancel_keeps_it", "crates/ui-egui/tests/editing.rs::closing_a_dirty_tab_can_save_first", "crates/ui-egui/tests/editing.rs::quitting_with_unsaved_changes_asks_for_each_document"] notes = "" [[feature]] id = "core.dirty-indicator" title = "Unsaved-changes marker on document tabs" area = "A" tier = "P1" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::organize_delete_then_undo_and_redo_with_keys", "crates/engine/src/tests.rs::edits_update_view_data_and_mark_dirty"] notes = "" [[feature]] id = "core.close-document" title = "Close a document" area = "A" tier = "P0" milestone = "M3" status = "shipped" commands = ["file.close"] tools = ["doc_close"] evidence = ["crates/ui-egui/tests/editing.rs::clean_tabs_close_without_asking"] notes = "" [[feature]] id = "core.close-all" title = "Close all documents" area = "A" tier = "P1" milestone = "M3" status = "shipped" commands = ["file.close_all"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::close_all_asks_only_for_changed_documents"] notes = "clean documents close; each changed one asks" [[feature]] id = "core.revert" title = "Revert to the last saved version" area = "A" tier = "P1" milestone = "M4" status = "shipped" commands = ["file.revert"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::revert_after_confirming", "crates/engine/src/tests.rs::revert_goes_back_to_the_saved_version"] notes = "with confirmation; clears undo, as Acrobat" [[feature]] id = "core.signed-save-policy" title = "Force incremental saves for signed documents" area = "A" tier = "P0" milestone = "M4" status = "shipped" commands = ["file.save"] tools = ["doc_save"] evidence = ["crates/engine/src/tests.rs::signing_saving_trusting_and_commenting_afterwards"] notes = "saves of signed documents are always incremental: full rewrites are refused, and edits that would need one (applying redactions, changing security, sanitizing) are refused before they change anything" [[feature]] id = "core.drag-drop-open" title = "Open files by drag and drop" area = "A" tier = "P1" milestone = "M3" status = "partial" commands = [] tools = [] evidence = [] notes = "desktop drop is handled; no test yet" [[feature]] id = "core.recent-files" title = "Local recent-files list" area = "A" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::persistence_round_trips_and_tolerates_garbage"] notes = "never reads other apps' lists" [[feature]] id = "core.usage-rights-preserve" title = "Preserve usage-rights (UR3) signatures from Reader-extended files" area = "A" tier = "P3" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "preserve only" # ================================================================================================== # B. Viewing and navigation # ================================================================================================== [[feature]] id = "view.render-pages" title = "Render pages (text, vectors, images)" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = ["page_render"] evidence = ["crates/render/src/raster.rs::renders_a_blue_rectangle", "crates/automation/tests/automation.rs::open_inspect_render_and_find"] notes = "hayro bootstrap renderer; own DisplayList devices in M2.6" [[feature]] id = "view.render-shadings-patterns" title = "Shadings, gradients and tiling patterns" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::self_referencing_tiling_pattern_terminates"] notes = "via hayro bootstrap" [[feature]] id = "view.render-transparency" title = "Blend modes, soft masks and transparency groups" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::soft_mask_without_group_colour_space_is_applied"] notes = "via hayro bootstrap" [[feature]] id = "view.render-knockout" title = "Knockout transparency groups" area = "B" tier = "P1" milestone = "M11" status = "shipped" commands = [] tools = ["doc_save"] evidence = ["crates/engine/src/tests.rs::signing_saving_trusting_and_commenting_afterwards", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "full rewrites of signed documents are refused; saves stay incremental" [[feature]] id = "view.render-type3" title = "Type 3 fonts" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = [] evidence = [] notes = "hayro bootstrap with vendored patches" [[feature]] id = "view.render-cid-fonts" title = "CID fonts and CMaps incl. CJK without ToUnicode" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::huge_cid_width_ranges_terminate"] notes = "CID-to-Unicode tables are M2.4" [[feature]] id = "view.render-image-codecs" title = "JBIG2, JPEG 2000, CCITT and JPEG images" area = "B" tier = "P0" milestone = "M2" status = "partial" commands = [] tools = [] evidence = [] notes = "hayro bootstrap" [[feature]] id = "view.render-annotation-appearances" title = "Annotation and widget appearances incl. appearance states" area = "B" tier = "P0" milestone = "M2" status = "shipped" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::widget_appearance_states"] notes = "" [[feature]] id = "view.render-error-isolation" title = "Per-page error isolation (a bad page never takes down the app)" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::missing_page_and_garbage_input_fail_gracefully", "crates/render/src/raster.rs::scale_is_clamped_for_huge_pages", "crates/render/src/raster.rs::watchdog_skips_a_stuck_page_and_keeps_rendering"] notes = "" [[feature]] id = "view.render-priority" title = "Render visible pages first, then neighbours and thumbnails" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::inline_pool_renders_in_priority_order"] notes = "" [[feature]] id = "view.deep-zoom-tiles" title = "Tiled rendering keeps deep zoom sharp" area = "B" tier = "P0" milestone = "M3" status = "partial" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::tiles_match_full_render", "crates/render/src/raster.rs::effective_scale_never_exceeds_the_caps"] notes = "capped at 8192 px per side (M3.3)" [[feature]] id = "view.layout-continuous" title = "Single page continuous scrolling" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::continuous_layout_stacks_pages_vertically"] notes = "" [[feature]] id = "view.layout-single-page" title = "Single page view" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::single_page_layout_shows_one_page_at_a_time"] notes = "" [[feature]] id = "view.layout-two-up" title = "Two-page view" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::two_up_layout_places_pages_side_by_side"] notes = "" [[feature]] id = "view.layout-two-up-scrolling" title = "Two-page scrolling" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] notes = "the two-page view scrolls continuously" [[feature]] id = "view.cover-page" title = "Show cover page in two-page view" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] notes = "View ▸ Show cover page in two-page view" [[feature]] id = "view.page-gaps" title = "Show or hide gaps between pages" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.auto-scroll" title = "Automatic scrolling" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.zoom-in-out" title = "Zoom in and out around the cursor (keys, wheel, pinch)" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::zoom_keeps_the_point_under_the_cursor_still"] notes = "" [[feature]] id = "view.zoom-to-percent" title = "Zoom to a chosen percentage" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::selection_works_in_every_view_rotation"] notes = "" [[feature]] id = "view.zoom-actual-size" title = "Actual size" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::actual_size_fit_width_and_fit_page"] notes = "" [[feature]] id = "view.zoom-fit-page" title = "Fit page" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::actual_size_fit_width_and_fit_page"] notes = "" [[feature]] id = "view.zoom-fit-width" title = "Fit width" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::actual_size_fit_width_and_fit_page"] notes = "" [[feature]] id = "view.zoom-fit-height" title = "Fit height" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] notes = "View ▸ Fit to height" [[feature]] id = "view.zoom-fit-visible" title = "Fit visible content" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["view.fit_visible"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::fit_visible_zooms_to_the_content_width", "crates/ui-egui/src/zoom_snap.rs::ink_bounds_finds_the_marked_area"] notes = "View ▸ Zoom ▸ Fit visible (⌘3): the current page's inked area (found by a quick low-resolution render) spans the window width; respects view rotation; drivable via the control channel's command" [[feature]] id = "view.marquee-zoom" title = "Marquee zoom tool" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["view.marquee_zoom"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::marquee_zoom_and_snapshot"] notes = "drag to fill the window with an area; click to zoom in" [[feature]] id = "view.dynamic-zoom" title = "Dynamic zoom (drag to zoom)" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.loupe" title = "Loupe magnifier tool" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.pan-and-zoom" title = "Pan and zoom overview window" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.hand-tool" title = "Hand tool for panning" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::the_hand_tool_pans_by_dragging"] notes = "drag to pan; Grab/Grabbing cursors" [[feature]] id = "view.rotate-view" title = "Rotate the view without changing the file" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::selection_works_in_every_view_rotation"] notes = "" [[feature]] id = "view.read-mode" title = "Read mode (hide tool chrome)" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = ["view.read_mode"] tools = [] evidence = ["crates/ui-egui/tests/control.rs::inspect_and_click_by_label_and_id", "crates/ui-egui/tests/commands.rs::every_registered_command_is_implemented"] notes = "" [[feature]] id = "view.full-screen" title = "Full screen mode" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = ["view.full_screen"] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::full_screen_toggles_by_shortcut_and_command_and_escape_leaves"] notes = "" [[feature]] id = "view.full-screen-presentation" title = "Full-screen presentation options (auto-advance, loop, click to advance)" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.reflow" title = "Reflow text to the window width" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.page-navigation" title = "Page navigation (next, previous, first, last, go to page)" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/control.rs::state_and_view_options", "crates/ui-egui/tests/ui.rs::theme_and_view_options_apply"] notes = "" [[feature]] id = "view.goto-page-label" title = "Go to a page by its label (logical page numbers)" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] notes = "the page box takes labels (iv, A-1) before numbers" [[feature]] id = "view.view-history" title = "Previous view / next view" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::view_history_select_all_and_find_options"] notes = "⌘[ / ⌘] and View ▸ Page navigation" [[feature]] id = "view.follow-links" title = "Follow links and destinations" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::clicking_a_link_goes_to_its_destination"] notes = "GoTo and URI links; other action types (JavaScript, Launch, named actions) arrive with M6" [[feature]] id = "view.annotation-hover" title = "Show comment text on hover" area = "B" tier = "P1" milestone = "M3" status = "partial" commands = [] tools = [] evidence = [] notes = "no test yet" [[feature]] id = "view.document-tabs" title = "Tabbed documents" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = ["doc_list"] evidence = ["crates/ui-egui/tests/editing.rs::combining_files_opens_a_new_unsaved_tab", "crates/ui-egui/tests/control.rs::state_and_view_options"] notes = "" [[feature]] id = "view.multiple-windows" title = "Multiple windows; drag a tab out into a window" area = "B" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.split-window" title = "Split window (two panes on one document)" area = "B" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.spreadsheet-split" title = "Spreadsheet split (four synchronised panes)" area = "B" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.thumbnails-panel" title = "Page thumbnails panel" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::theme_and_view_options_apply"] notes = "" [[feature]] id = "view.thumbnail-context-ops" title = "Page operations from the thumbnails panel (drag reorder, context menu)" area = "B" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.bookmarks-panel" title = "Bookmarks panel with navigation" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/ui.rs::opening_a_pdf_shows_comments_and_bookmarks", "crates/ui-egui/tests/control.rs::state_and_view_options"] notes = "" [[feature]] id = "view.highlight-current-bookmark" title = "Highlight the current bookmark" area = "B" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.attachments-panel" title = "Attachments panel: list, open and save embedded files" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = ["doc_info"] evidence = ["crates/render/src/inspect.rs::attachments_of_both_kinds_are_listed_and_extracted"] notes = "" [[feature]] id = "view.layers-panel" title = "Layers panel: toggle optional content visibility" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = ["doc_info"] evidence = ["crates/render/src/raster.rs::layer_override_hides_content", "crates/engine/src/tests.rs::layer_choices_survive_edits"] notes = "" [[feature]] id = "view.layers-reset" title = "Reset layers to initial visibility; list for all or current pages" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.destinations-panel" title = "Named destinations panel" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.articles-panel" title = "Articles panel and article reading" area = "B" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.model-tree" title = "3D model tree panel" area = "B" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.page-labels-display" title = "Show page labels (i, ii, 1, 2...)" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = ["doc_info"] evidence = ["crates/render/src/inspect.rs::roman_and_alpha_labels", "crates/automation/tests/automation.rs::open_inspect_render_and_find"] notes = "" [[feature]] id = "view.find" title = "Find text across the document" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = ["edit.find"] tools = ["text_find"] evidence = ["crates/ui-egui/tests/ui.rs::find_counts_matches_across_pages", "crates/ui-egui/tests/ui.rs::find_reports_no_matches", "crates/automation/tests/automation.rs::open_inspect_render_and_find"] notes = "" [[feature]] id = "view.find-next-previous" title = "Find next / previous match" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = ["edit.find"] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::find_counts_matches_across_pages"] notes = "" [[feature]] id = "view.find-options" title = "Find options: whole words, case-sensitive" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["edit.find"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::view_history_select_all_and_find_options"] notes = "whole words only, case-sensitive" [[feature]] id = "view.find-in-comments-bookmarks" title = "Find in comments and bookmarks" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.find-results-panel" title = "Find results list" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["edit.advanced_search"] tools = ["text_find"] evidence = ["crates/ui-egui/tests/viewer.rs::advanced_search_lists_results_with_context"] notes = "Search panel (⇧⌘F): every match grouped by page with its context, whole words / case options, click to go; shares the find bar's search (closing the panel moves it to the bar)" [[feature]] id = "view.advanced-search" title = "Advanced search window" area = "B" tier = "P1" milestone = "M12" status = "partial" commands = ["edit.advanced_search"] tools = ["text_find"] evidence = ["crates/ui-egui/tests/viewer.rs::advanced_search_lists_results_with_context"] notes = "in the current document, as a side panel; searching other open documents, folders and indexes is still to come" [[feature]] id = "view.search-folder" title = "Search all PDFs in a folder" area = "B" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.search-boolean" title = "Boolean, proximity and stemming search" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.search-index" title = "Build and search a full-text index across files" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.embedded-index" title = "Embedded search index" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.text-select" title = "Select text in reading order" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::drag_selects_text_and_copy_returns_it", "crates/ui-egui/tests/ui.rs::selection_works_in_every_view_rotation"] notes = "" [[feature]] id = "view.copy-text" title = "Copy selected text" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::drag_selects_text_and_copy_returns_it"] notes = "" [[feature]] id = "view.select-all" title = "Select all text on a page" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::view_history_select_all_and_find_options"] notes = "⌘A on the current page" [[feature]] id = "view.copy-with-layout" title = "Copy text keeping layout" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.snapshot" title = "Snapshot tool (copy a region as an image)" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["edit.snapshot"] tools = ["page_render"] evidence = ["crates/ui-egui/tests/viewer.rs::marquee_zoom_and_snapshot"] notes = "copies the area at the current zoom to the clipboard as an image" [[feature]] id = "view.rulers" title = "Rulers" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.grid" title = "Grid and snap to grid" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.guides" title = "Guides" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.line-weights" title = "Show line weights" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.cursor-coordinates" title = "Cursor coordinates" area = "B" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.theme-light-dark" title = "Light and dark themes" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["view.theme"] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::theme_and_view_options_apply"] notes = "" [[feature]] id = "view.theme-system" title = "Follow the system theme" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = ["view.theme"] tools = [] evidence = ["crates/ui-egui/tests/viewer.rs::layouts_fit_height_labels_and_system_theme"] notes = "Display theme ▸ Use system setting (and --theme system)" [[feature]] id = "view.home-view" title = "Home view with recommended tools and recent files" area = "B" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::home_shows_welcome_and_tools"] notes = "" [[feature]] id = "view.all-tools" title = "All tools catalogue with milestone badges" area = "B" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/ui.rs::every_catalog_tool_is_listed_after_view_more", "crates/engine/src/commands.rs::every_ready_catalogue_item_is_a_registered_command"] notes = "" [[feature]] id = "view.command-palette" title = "Command palette (⌘K) over every command" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = ["view.palette"] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::the_palette_lists_commands_with_shortcuts_and_runs_them"] notes = "" [[feature]] id = "view.keyboard-shortcuts" title = "Platform keyboard shortcuts for registered commands" area = "B" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::shortcuts_run_registered_commands", "crates/engine/src/commands.rs::shortcut_labels_follow_platform_conventions"] notes = "" [[feature]] id = "view.shortcuts-dialog" title = "Keyboard shortcuts reference dialog" area = "B" tier = "P1" milestone = "M4" status = "shipped" commands = ["help.shortcuts"] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::the_shortcuts_dialog_lists_the_real_bindings"] notes = "" [[feature]] id = "view.menus-from-registry" title = "Menus generated from the command registry" area = "B" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::the_pages_menu_comes_from_the_registry"] notes = "" [[feature]] id = "view.about-dialog" title = "About dialog" area = "B" tier = "P2" milestone = "M3" status = "shipped" commands = ["help.about"] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::the_about_dialog_shows_the_running_version"] notes = "" [[feature]] id = "view.check-for-updates" title = "Help ▸ Check for updates" area = "B" tier = "P2" milestone = "M3" status = "partial" commands = ["help.check_updates"] tools = [] evidence = ["crates/ui-egui/tests/updates.rs::a_newer_release_is_offered_for_download", "crates/ui-egui/tests/updates.rs::nothing_is_asked_until_the_user_checks", "apps/printcraft/src/updates.rs::answers_are_read_and_only_our_release_pages_are_offered"] notes = "asks GitHub Releases on request and offers the release page. By the owner's decision there is no check at start and no in-place install (Acrobat has both)" [[feature]] id = "view.single-key-accelerators" title = "Single-key tool accelerators" area = "B" tier = "P2" milestone = "M3" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.customize-quick-tools" title = "Customise the quick-action toolbar and pinned tools" area = "B" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.restriction-notice" title = "Message bar for restricted documents" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::restricted_documents_show_a_notice_and_block_page_changes"] notes = "" [[feature]] id = "view.pdfa-view-mode" title = "Read-only view for PDF/A files with an Enable editing bar" area = "B" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.show-page-boxes" title = "Show art, trim and bleed boxes" area = "B" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "view.web-app" title = "Run in the browser (WebAssembly)" area = "B" tier = "P0" milestone = "M3" status = "partial" commands = [] tools = [] evidence = [] notes = "web build works; IndexedDB/OPFS recent list and download flow are M3.10" [[feature]] id = "view.large-document-performance" title = "Smooth scrolling on 500-page documents" area = "B" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/perf.rs::scrolling_a_500_page_document_stays_within_the_frame_budget", "crates/ui-egui/tests/perf.rs::panels_with_hundreds_of_items_stay_within_the_frame_budget"] notes = "UI work per frame ~6 ms scrolling 500 pages (comments panel with 500 cards ~6 ms, thumbnails ~2 ms); rendering is off-thread and tiled" # ================================================================================================== # C. Content editing # ================================================================================================== [[feature]] id = "edit.text-edit" title = "Edit existing text in place" area = "C" tier = "P0" milestone = "M7" status = "partial" commands = ["edit.edit_text"] tools = ["text_lines", "text_paragraphs", "text_edit"] evidence = ["crates/edit/src/tests.rs::paragraphs_are_found_and_rewrapped", "crates/edit/src/tests.rs::text_lines_are_found_and_replaced_in_place", "crates/ui-egui/tests/editing.rs::editing_existing_text_in_place", "crates/automation/tests/automation.rs::editing_existing_text_through_tools"] notes = "click a paragraph box and retype it in place (font reused or Helvetica substituted, colour and spacing kept, rewrapped); per-character formatting changes and moving or resizing boxes are next" [[feature]] id = "edit.text-reflow" title = "Reflow edited text inside its paragraph box" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::paragraphs_are_found_and_rewrapped", "crates/edit/src/tests.rs::text_lines_are_found_and_replaced_in_place", "crates/ui-egui/tests/editing.rs::editing_existing_text_in_place", "crates/automation/tests/automation.rs::editing_existing_text_through_tools"] notes = "edited paragraphs are rewrapped to the box width with the font's own advance widths and the original line spacing, starting at the original text matrix; text state and fill colour restored after; a single line grows to the right margin" [[feature]] id = "edit.paragraph-detection" title = "Detect paragraphs and text blocks for editing" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_paragraphs"] evidence = ["crates/edit/src/tests.rs::paragraphs_are_found_and_rewrapped", "crates/edit/src/tests.rs::text_lines_are_found_and_replaced_in_place", "crates/ui-egui/tests/editing.rs::editing_existing_text_in_place", "crates/automation/tests/automation.rs::editing_existing_text_through_tools"] notes = "lines grouped into paragraphs by stream, font, size, left alignment and regular baseline spacing; hyphenated line ends are joined" [[feature]] id = "edit.font-reuse-substitution" title = "Reuse embedded fonts or substitute with a warning" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::missing_glyphs_substitute_helvetica_and_impossible_text_is_refused", "crates/fonts/src/pdf.rs::subset_fonts_only_encode_the_glyphs_they_have", "crates/fonts/src/pdf.rs::composite_fonts_use_to_unicode"] notes = "the line's font is reused when every character has a code and a glyph (ToUnicode, encodings, Differences; subset glyph checks); otherwise Helvetica (WinAnsi) is used and reported; text no font can show is refused" [[feature]] id = "edit.text-format-font" title = "Change font, size and colour" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text", "edit.text"] tools = ["text_edit", "content_update"] evidence = ["crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited", "crates/automation/tests/automation.rs::editing_existing_text_through_tools"] notes = "existing paragraphs and added text: font family (Helvetica, Times, Courier) with bold and italic, size, colour; existing paragraphs are rewrapped" [[feature]] id = "edit.text-format-style" title = "Bold, italic, underline" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::justify_underline_and_spacing", "crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited"] notes = "bold and italic through the standard families; underline drawn under each line in the text colour" [[feature]] id = "edit.text-super-subscript" title = "Superscript and subscript" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.paragraph-alignment" title = "Paragraph alignment (left, centre, right, justify)" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text", "edit.text"] tools = ["text_edit", "content_update"] evidence = ["crates/edit/src/tests.rs::justify_underline_and_spacing", "crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited"] notes = "left, centre, right and justify (word spacing per line, last line left) for existing paragraphs and added text" [[feature]] id = "edit.line-paragraph-spacing" title = "Line and paragraph spacing" area = "C" tier = "P1" milestone = "M7" status = "partial" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::justify_underline_and_spacing", "crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited"] notes = "line spacing (1, 1.15, 1.5, 2 × size or any multiple); space between paragraphs is not adjustable yet" [[feature]] id = "edit.char-spacing-scale" title = "Character spacing and horizontal scaling" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::justify_underline_and_spacing", "crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited"] notes = "character spacing in points and horizontal scaling in percent for a paragraph (Tc, Tz), rewrapped" [[feature]] id = "edit.lists" title = "Bulleted and numbered lists" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.add-text" title = "Add a new text box as page content" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.text"] tools = ["page_add_text", "content_update"] evidence = ["crates/ui-egui/tests/content.rs::typing_moving_styling_and_deleting_added_content", "crates/automation/tests/automation.rs::adding_content_through_tools", "crates/edit/src/tests.rs::added_text_and_images_are_page_content_that_stays_editable", "crates/engine/src/tests.rs::added_text_and_images_render_and_stay_editable"] notes = "page content, editable later (retype, move, restyle); standard fonts, Windows-1252 text" [[feature]] id = "edit.find-replace" title = "Find and replace in edit mode" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.rtl-cjk-editing" title = "Edit right-to-left and CJK text" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.rotated-text-editing" title = "Edit rotated text" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.keep-tags-on-edit" title = "Keep structure tags when editing" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.image-add" title = "Add an image" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.image"] tools = ["page_add_image"] evidence = ["crates/ui-egui/tests/content.rs::typing_moving_styling_and_deleting_added_content", "crates/automation/tests/automation.rs::adding_content_through_tools", "crates/edit/src/tests.rs::added_text_and_images_are_page_content_that_stays_editable", "crates/engine/src/tests.rs::added_text_and_images_render_and_stay_editable"] notes = "PNG, JPEG, TIFF, GIF, BMP; centred at natural size or in a rect" [[feature]] id = "edit.image-replace" title = "Replace an image (keep position and size)" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text", "edit.image"] tools = ["image_edit"] evidence = ["crates/edit/src/tests.rs::page_images_move_turn_replace_and_delete", "crates/ui-egui/tests/editing.rs::editing_existing_images_on_the_page", "crates/automation/tests/automation.rs::editing_page_images_through_tools"] notes = "existing page images (right-click ▸ Replace Image) and added images: the new picture is drawn in the same place" [[feature]] id = "edit.image-crop" title = "Crop an image" area = "C" tier = "P0" milestone = "M7" status = "partial" commands = ["edit.image"] tools = ["content_update"] evidence = ["crates/engine/src/tests.rs::added_images_rotate_flip_and_crop_as_drawn", "crates/automation/tests/automation.rs::adding_content_through_tools"] notes = "for added images: trim each side, clipped" [[feature]] id = "edit.image-rotate-flip" title = "Rotate and flip images" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["image_edit"] evidence = ["crates/edit/src/tests.rs::page_images_move_turn_replace_and_delete", "crates/ui-egui/tests/editing.rs::editing_existing_images_on_the_page", "crates/automation/tests/automation.rs::editing_page_images_through_tools"] notes = "existing page images: rotate either way about the centre, flip horizontally or vertically (a q/cm/Q wrapper); added images too" [[feature]] id = "edit.image-move-resize" title = "Move and resize images" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["image_edit"] evidence = ["crates/edit/src/tests.rs::page_images_move_turn_replace_and_delete", "crates/ui-egui/tests/editing.rs::editing_existing_images_on_the_page", "crates/automation/tests/automation.rs::editing_page_images_through_tools"] notes = "existing page images: select, drag to move, drag a corner to resize keeping proportions; Delete removes; added images too" [[feature]] id = "edit.image-extract" title = "Save an image to a file" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["image_save"] evidence = ["crates/edit/src/tests.rs::page_images_move_turn_replace_and_delete", "crates/ui-egui/tests/editing.rs::editing_existing_images_on_the_page", "crates/automation/tests/automation.rs::editing_page_images_through_tools", "crates/create/src/tests.rs::images_export_as_jpeg_unchanged_and_others_as_png"] notes = "right-click an image ▸ Save Image As: JPEG unchanged, others PNG" [[feature]] id = "edit.image-external-editor" title = "Edit an image in an external application" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.arrange-objects" title = "Arrange objects (bring forward, send backward)" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.align-distribute-objects" title = "Align and distribute objects" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.vector-edit" title = "Select, move, scale, recolour and delete vector paths" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.edit-object-tool" title = "Edit object tool for any page object" area = "C" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.object-properties" title = "Object properties (colour space, font, convert colour)" area = "C" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.link-create" title = "Create web and page links" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.link"] tools = ["link_add"] evidence = ["crates/ui-egui/tests/pdf_links.rs::drawing_editing_and_deleting_links", "crates/automation/tests/automation.rs::links_through_tools", "crates/annot/src/tests.rs::links_are_added_edited_listed_and_removed"] notes = "drag a rectangle; go to a page or open a web page" [[feature]] id = "edit.link-properties" title = "Link appearance and properties" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.link"] tools = ["link_edit"] evidence = ["crates/ui-egui/tests/pdf_links.rs::drawing_editing_and_deleting_links", "crates/automation/tests/automation.rs::links_through_tools", "crates/annot/src/tests.rs::links_are_added_edited_listed_and_removed"] notes = "visible/invisible rectangle, highlight, thickness, solid/dashed/underline, colour; action" [[feature]] id = "edit.links-from-urls" title = "Create links from URLs in the text" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.links_from_urls"] tools = ["links_from_urls"] evidence = ["crates/engine/src/tests.rs::links_from_urls_and_link_edits", "crates/automation/tests/automation.rs::links_through_tools", "crates/annot/src/tests.rs::urls_are_found_in_text"] notes = "http(s):// and www. addresses; already-linked text skipped" [[feature]] id = "edit.remove-all-links" title = "Remove all links" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-goto" title = "Go-to-page-view action (with named destinations)" area = "C" tier = "P1" milestone = "M7" status = "partial" commands = ["edit.link"] tools = ["link_add"] evidence = ["crates/annot/src/tests.rs::links_are_added_edited_listed_and_removed", "crates/ui-egui/tests/pdf_links.rs::drawing_editing_and_deleting_links"] notes = "go to a page (Fit view); named destinations and zoom pending" [[feature]] id = "edit.action-uri" title = "Open-a-web-link action" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.link"] tools = ["link_add"] evidence = ["crates/annot/src/tests.rs::links_are_added_edited_listed_and_removed", "crates/automation/tests/automation.rs::links_through_tools"] notes = "" [[feature]] id = "edit.action-launch" title = "Open-a-file action" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-named" title = "Execute-a-menu-item action (safe list)" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-set-ocg-state" title = "Set-layer-visibility action" area = "C" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-show-hide-field" title = "Show/hide-a-field action" area = "C" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-javascript" title = "Run-a-JavaScript action" area = "C" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-thread" title = "Read-an-article action" area = "C" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-goto-embedded" title = "Go to a target in an embedded file (GoToE)" area = "C" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.action-media" title = "Play sound / media / rich-media actions" area = "C" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.header-footer-add" title = "Add header and footer" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.header_footer"] tools = ["doc_header_footer"] evidence = ["crates/ui-egui/tests/marks.rs::header_and_footer_dialog_inserts_tokens_and_applies_to_a_subset", "crates/edit/src/tests.rs::header_and_footer_are_drawn_in_display_space_and_wrap_the_original_content", "crates/engine/src/tests.rs::headers_footers_watermarks_and_backgrounds_show_update_and_remove"] notes = "Helvetica only (no font choice yet); drawn in display space on rotated pages; artifact-tagged" [[feature]] id = "edit.header-footer-update-remove" title = "Update or remove header and footer" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.header_footer.update", "edit.header_footer.remove"] tools = ["doc_header_footer", "doc_remove_marks"] evidence = ["crates/edit/src/tests.rs::replace_and_remove_restore_the_original_content", "crates/ui-egui/tests/marks.rs::header_and_footer_dialog_inserts_tokens_and_applies_to_a_subset"] notes = "recognises PrintCraft marks; Acrobat-made headers are not detected yet" [[feature]] id = "edit.header-footer-tokens" title = "Page number and date tokens in header and footer" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.header_footer"] tools = ["doc_header_footer"] evidence = ["crates/edit/src/tests.rs::tokens_expand", "crates/engine/src/tests.rs::headers_footers_watermarks_and_backgrounds_show_update_and_remove"] notes = "<<1>>, <>, <<1 of n>>, <>, dates, Bates" [[feature]] id = "edit.header-footer-ranges" title = "Header and footer page ranges (all, range, odd, even)" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.header_footer"] tools = ["doc_header_footer"] evidence = ["crates/ui-egui/src/marks_ui.rs::page_ranges_with_subsets", "crates/ui-egui/tests/marks.rs::header_and_footer_dialog_inserts_tokens_and_applies_to_a_subset"] notes = "all / from–to, all / even / odd" [[feature]] id = "edit.header-footer-shrink" title = "Shrink document to avoid overwriting content" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.watermark-add-text" title = "Add a text watermark" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.watermark"] tools = ["doc_watermark"] evidence = ["crates/edit/src/tests.rs::watermarks_rotate_fade_and_can_go_behind", "crates/ui-egui/tests/marks.rs::watermark_and_background_dialogs", "crates/automation/tests/automation.rs::headers_watermarks_and_backgrounds_through_tools"] notes = "Helvetica; fit-to-page or a size" [[feature]] id = "edit.watermark-add-file" title = "Add a watermark from an image or PDF page" area = "C" tier = "P1" milestone = "M7" status = "shipped" commands = ["edit.watermark"] tools = ["doc_watermark"] evidence = ["crates/engine/src/tests.rs::backgrounds_and_watermarks_from_files"] notes = "an image or a page of a PDF, scaled relative to the page, rotated, with opacity, behind or on top" [[feature]] id = "edit.watermark-update-remove" title = "Update or remove watermarks" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.watermark.update", "edit.watermark.remove"] tools = ["doc_watermark", "doc_remove_marks"] evidence = ["crates/edit/src/tests.rs::replace_and_remove_restore_the_original_content", "crates/engine/src/tests.rs::headers_footers_watermarks_and_backgrounds_show_update_and_remove"] notes = "" [[feature]] id = "edit.watermark-appearance" title = "Watermark rotation, opacity, scale, position, print/screen visibility" area = "C" tier = "P1" milestone = "M7" status = "partial" commands = ["edit.watermark"] tools = ["doc_watermark"] evidence = ["crates/edit/src/tests.rs::watermarks_rotate_fade_and_can_go_behind"] notes = "rotation, opacity, behind/on top; no position offsets, scale or print/screen-only variants in the UI yet" [[feature]] id = "edit.background-add" title = "Add a page background (colour or file)" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.background"] tools = ["doc_background"] evidence = ["crates/ui-egui/tests/marks.rs::watermark_and_background_dialogs", "crates/engine/src/tests.rs::headers_footers_watermarks_and_backgrounds_show_update_and_remove", "crates/engine/src/tests.rs::backgrounds_and_watermarks_from_files", "crates/ui-egui/tests/marks.rs::backgrounds_and_watermarks_from_a_file", "crates/organize/src/tests.rs::a_page_becomes_a_form_xobject_upright"] notes = "colour, or a picture from a file (an image or a page of a PDF) scaled relative to the page" [[feature]] id = "edit.background-update-remove" title = "Update or remove backgrounds" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.background.update", "edit.background.remove"] tools = ["doc_background", "doc_remove_marks"] evidence = ["crates/edit/src/tests.rs::replace_and_remove_restore_the_original_content", "crates/engine/src/tests.rs::headers_footers_watermarks_and_backgrounds_show_update_and_remove"] notes = "" [[feature]] id = "edit.decoration-profiles" title = "Saved header/footer and watermark settings" area = "C" tier = "P2" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.bates-numbering" title = "Bates numbering" area = "C" tier = "P1" milestone = "M7" status = "partial" commands = ["edit.bates", "edit.header_footer"] tools = ["doc_header_footer"] evidence = ["crates/edit/src/tests.rs::tokens_expand"] notes = "Bates ▸ Add opens Header & Footer with a Bates number; no multi-file batch yet" [[feature]] id = "edit.bates-multi-file" title = "Bates numbering across multiple files" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.bates-remove" title = "Remove Bates numbering" area = "C" tier = "P1" milestone = "M7" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.spell-check" title = "Spell check in comments, form fields and edited text" area = "C" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.spell-dictionaries" title = "Spelling dictionaries per language and a user dictionary" area = "C" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "edit.format-panel" title = "Format panel for edited text" area = "C" tier = "P0" milestone = "M7" status = "shipped" commands = ["edit.edit_text"] tools = ["text_edit"] evidence = ["crates/edit/src/tests.rs::paragraphs_take_new_formatting", "crates/ui-egui/tests/editing.rs::the_format_panel_restyles_the_paragraph_being_edited", "crates/automation/tests/automation.rs::editing_existing_text_through_tools"] notes = "Edit a PDF ▸ Format text shows the paragraph being edited (family, bold/italic guessed from its font, size) and applies changes at once as one undo step each, keeping the paragraph open" [[feature]] id = "edit.adobe-express-edits" title = "Adobe Express image edits (remove background, generative fill)" area = "C" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "cloud-only; images open in an external editor instead" # ================================================================================================== # D. Organize pages and documents # ================================================================================================== [[feature]] id = "organize.organize-grid" title = "Organize pages thumbnail grid" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.organize"] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::shift_click_selects_a_range_and_moves_it"] notes = "" [[feature]] id = "organize.multi-select-pages" title = "Select pages with click, ⌘-click and ⇧-click" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.organize"] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::command_click_toggles_and_rotation_applies_to_selection", "crates/ui-egui/tests/editing.rs::shift_click_selects_a_range_and_moves_it"] notes = "" [[feature]] id = "organize.rotate-pages" title = "Rotate pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.rotate", "page.rotate_ccw"] tools = ["page_rotate"] evidence = ["crates/organize/src/tests.rs::rotate_uses_inherited_rotation_and_round_trips", "crates/ui-egui/tests/editing.rs::command_click_toggles_and_rotation_applies_to_selection"] notes = "" [[feature]] id = "organize.rotate-filters" title = "Rotate by range with even/odd and orientation filters" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.rotate_dialog"] tools = ["page_rotate"] evidence = ["crates/ui-egui/tests/editing.rs::extract_options_and_rotate_pages_dialog", "crates/automation/tests/automation.rs::organizing_with_filters_bookmark_splits_and_extract_options", "crates/engine/src/tests.rs::split_by_size_and_bookmarks_and_page_filters"] notes = "Rotate Pages: all/selection/range; even/odd; landscape/portrait" [[feature]] id = "organize.delete-pages" title = "Delete pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.delete"] tools = ["page_delete"] evidence = ["crates/organize/src/tests.rs::delete_keeps_inherited_attributes_on_survivors", "crates/organize/src/tests.rs::cannot_delete_every_page_or_missing_pages", "crates/ui-egui/tests/editing.rs::delete_is_refused_when_it_would_remove_every_page"] notes = "" [[feature]] id = "organize.move-pages" title = "Move pages earlier or later" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["page_move"] evidence = ["crates/organize/src/tests.rs::move_pages_reorders", "crates/ui-egui/tests/editing.rs::shift_click_selects_a_range_and_moves_it"] notes = "" [[feature]] id = "organize.drag-reorder" title = "Reorder pages by drag and drop" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/editing.rs::dragging_thumbnails_reorders_pages"] notes = "drag thumbnails (or the selection) in the page grid; an insertion bar shows where they go; move earlier/later buttons too" [[feature]] id = "organize.insert-blank" title = "Insert blank pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.insert_blank"] tools = ["page_insert_blank"] evidence = ["crates/organize/src/tests.rs::inserts_blank_page", "crates/ui-egui/tests/editing.rs::insert_blank_page_after_selection", "crates/engine/src/tests.rs::insert_blank_between_pages_keeps_both_neighbours"] notes = "" [[feature]] id = "organize.insert-from-file" title = "Insert pages from another file" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.insert"] tools = ["page_insert_file"] evidence = ["crates/organize/src/tests.rs::inserting_pages_from_another_file_is_an_incremental_edit", "crates/ui-egui/tests/editing.rs::inserting_a_file_goes_after_the_selection_and_undoes"] notes = "" [[feature]] id = "organize.insert-from-clipboard" title = "Insert pages from the clipboard" area = "D" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.insert-from-scanner" title = "Insert pages from a scanner" area = "D" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.insert-from-web" title = "Insert pages from a web page" area = "D" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.insert-by-drop" title = "Insert by dropping files onto the page grid" area = "D" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.extract-pages" title = "Extract pages to a new document" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.extract"] tools = ["page_extract"] evidence = ["crates/ui-egui/tests/editing.rs::extract_button_copies_selected_pages_to_a_new_tab", "crates/automation/tests/automation.rs::combine_extract_and_split"] notes = "" [[feature]] id = "organize.extract-separate-files" title = "Extract pages as separate files" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.extract"] tools = ["page_extract"] evidence = ["crates/ui-egui/tests/editing.rs::extract_options_and_rotate_pages_dialog", "crates/automation/tests/automation.rs::organizing_with_filters_bookmark_splits_and_extract_options"] notes = "" [[feature]] id = "organize.extract-and-delete" title = "Delete pages after extracting" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.extract"] tools = ["page_extract"] evidence = ["crates/ui-egui/tests/editing.rs::extract_options_and_rotate_pages_dialog", "crates/automation/tests/automation.rs::organizing_with_filters_bookmark_splits_and_extract_options"] notes = "undoable" [[feature]] id = "organize.replace-pages" title = "Replace pages with pages from another file" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.replace"] tools = ["page_replace"] evidence = ["crates/organize/src/tests.rs::replace_pages_swaps_content_but_keeps_annotations", "crates/ui-egui/tests/editing.rs::replace_pages_dialog_swaps_page_content", "crates/automation/tests/automation.rs::replacing_pages_through_tools"] notes = "content, resources and boxes replaced; links, comments, fields and bookmarks kept" [[feature]] id = "organize.duplicate-pages" title = "Duplicate pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.duplicate"] tools = ["page_duplicate"] evidence = ["crates/ui-egui/tests/pageboxes.rs::duplicate_pages_copies_the_current_page", "crates/organize/src/tests.rs::duplicate_pages_inserts_copies_after_the_last"] notes = "copies share fonts and images with the originals" [[feature]] id = "organize.reverse-pages" title = "Reverse page order" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.cut-copy-paste-pages" title = "Cut, copy and paste pages" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.copy", "page.cut", "page.paste"] tools = ["page_insert_file"] evidence = ["crates/ui-egui/tests/editing.rs::copying_cutting_and_pasting_pages"] notes = "⌘C/⌘X/⌘V and the thumbnail menu in Organize Pages; paste works across documents" [[feature]] id = "organize.drag-pages-between-documents" title = "Drag pages between documents" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-range-selection" title = "Select by range, odd/even, landscape/portrait" area = "D" tier = "P1" milestone = "M4" status = "partial" commands = ["page.organize"] tools = ["page_rotate"] evidence = ["crates/engine/src/tests.rs::split_by_size_and_bookmarks_and_page_filters"] notes = "Organize ▸ Select: all, odd, even, landscape, portrait; ranges via the page tools" [[feature]] id = "organize.thumbnail-size" title = "Thumbnail size slider" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.split-every-n" title = "Split every N pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.split"] tools = ["doc_split"] evidence = ["crates/ui-egui/tests/editing.rs::split_dialog_writes_one_file_per_part", "crates/organize/src/tests.rs::split_ranges_cover_every_page_once", "crates/organize/src/tests.rs::split_produces_standalone_documents_with_metadata"] notes = "" [[feature]] id = "organize.split-before-pages" title = "Split before chosen pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.split"] tools = ["doc_split"] evidence = ["crates/ui-egui/tests/editing.rs::split_before_selected_pages"] notes = "" [[feature]] id = "organize.split-by-size" title = "Split by file size" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.split"] tools = ["doc_split"] evidence = ["crates/automation/tests/automation.rs::organizing_with_filters_bookmark_splits_and_extract_options", "crates/engine/src/tests.rs::split_by_size_and_bookmarks_and_page_filters"] notes = "greedy by single-page size (an over-estimate: parts stay under the limit)" [[feature]] id = "organize.split-by-bookmarks" title = "Split by top-level bookmarks" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.split"] tools = ["doc_split"] evidence = ["crates/automation/tests/automation.rs::organizing_with_filters_bookmark_splits_and_extract_options", "crates/engine/src/tests.rs::split_by_size_and_bookmarks_and_page_filters"] notes = "files named after the bookmarks" [[feature]] id = "organize.split-naming" title = "Name split parts after bookmarks; never overwrite" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.split-multiple-files" title = "Split multiple files in one run" area = "D" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.combine-files" title = "Combine files into one PDF" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.combine"] tools = ["doc_combine"] evidence = ["crates/organize/src/tests.rs::combine_concatenates_with_a_bookmark_per_file", "crates/ui-egui/tests/editing.rs::combining_files_opens_a_new_unsaved_tab", "crates/automation/tests/automation.rs::combine_extract_and_split"] notes = "" [[feature]] id = "organize.combine-bookmarks" title = "Combine adds a bookmark per file with its own bookmarks nested" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.combine"] tools = ["doc_combine"] evidence = ["crates/organize/src/tests.rs::combine_nests_source_bookmarks_and_keeps_attachments"] notes = "" [[feature]] id = "organize.combine-choose-pages" title = "Choose which pages of each file to combine" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.combine"] tools = ["doc_combine"] evidence = ["crates/ui-egui/tests/editing.rs::combine_files_takes_chosen_pages_in_the_order_listed", "crates/automation/tests/automation.rs::combine_extract_and_split"] notes = "Combine files list: order (move up/down), remove, add files, a page range per file (such as 1-3, 6; in the order given); bookmarks to left-out pages lose their destination" [[feature]] id = "organize.combine-sort" title = "Sort and reorder files before combining" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.combine-options" title = "Combine options (file size, convert to PDF/A, include open files)" area = "D" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.resource-dedupe" title = "Store identical fonts and images once when combining or inserting" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["page.combine", "page.insert"] tools = ["doc_combine"] evidence = ["crates/organize/src/tests.rs::combine_and_insert_share_identical_resources", "crates/organize/src/dedupe.rs::merges_bottom_up_and_keeps_identity_objects"] notes = "" [[feature]] id = "organize.preserve-links-dests" title = "Rewire links and named destinations to copied pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/organize/src/tests.rs::links_are_rewired_to_copied_pages_or_dropped", "crates/organize/src/tests.rs::named_destinations_are_resolved_to_the_copies"] notes = "" [[feature]] id = "organize.preserve-fields" title = "Keep form fields interactive when copying pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/organize/src/tests.rs::form_fields_come_along_and_are_registered"] notes = "" [[feature]] id = "organize.preserve-layers" title = "Keep layers and their default state when copying pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/organize/src/tests.rs::layers_are_registered_with_their_default_state"] notes = "" [[feature]] id = "organize.preserve-inherited" title = "Copy inherited page attributes with pages" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/organize/src/tests.rs::inherited_attributes_travel_with_copied_pages"] notes = "" [[feature]] id = "organize.preserve-attachments" title = "Keep attachments when combining" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/organize/src/tests.rs::combine_nests_source_bookmarks_and_keeps_attachments"] notes = "" [[feature]] id = "organize.field-name-conflicts" title = "Rename or merge colliding field names when combining" area = "D" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.struct-tree-merge" title = "Merge structure trees when combining" area = "D" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-labels-edit" title = "Edit page labels (style, prefix, start)" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.number"] tools = ["page_number"] evidence = ["crates/organize/src/tests.rs::number_pages_like_acrobat", "crates/engine/src/tests.rs::number_pages_shows_in_the_viewer_and_undoes", "crates/ui-egui/tests/bookmarks.rs::number_pages_dialog_labels_the_selected_pages", "crates/automation/tests/automation.rs::numbering_pages_through_tools"] notes = "" [[feature]] id = "organize.page-boxes" title = "Set page boxes (crop, trim, bleed, art)" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.boxes"] tools = ["page_set_box"] evidence = ["crates/ui-egui/tests/pageboxes.rs::set_page_boxes_dialog_applies_margins_to_the_chosen_pages", "crates/organize/src/tests.rs::page_boxes_default_inherit_and_set"] notes = "crop/trim/bleed/art/media, margins in pt/in/mm, page ranges, preview; no Remove white margins yet" [[feature]] id = "organize.crop-tool" title = "Crop pages by dragging a rectangle" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["page.crop"] tools = ["page_set_box"] evidence = ["crates/ui-egui/tests/pageboxes.rs::the_crop_tool_crops_to_the_dragged_rectangle_then_returns_to_select"] notes = "drag to crop; double-click opens Set Page Boxes" [[feature]] id = "organize.remove-white-margins" title = "Remove white margins" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.change-page-size" title = "Change page size" area = "D" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-transitions" title = "Page transitions" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-tab-order" title = "Page tab order property" area = "D" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-actions" title = "Page open/close actions" area = "D" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.page-templates" title = "Page templates" area = "D" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.bookmark-add" title = "Add a bookmark (⌘B)" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["bookmark.add"] tools = ["bookmark_add"] evidence = ["crates/ui-egui/tests/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/engine/src/tests.rs::bookmark_edits_show_in_the_viewer_undo_and_save", "crates/automation/tests/automation.rs::bookmarks_through_tools"] notes = "" [[feature]] id = "organize.bookmark-rename" title = "Rename bookmarks" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["bookmark_rename"] evidence = ["crates/ui-egui/tests/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/ui-egui/tests/bookmarks.rs::escape_cancels_a_rename", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/organize/src/tests.rs::bookmark_edits_keep_unknown_keys_and_touch_few_objects"] notes = "" [[feature]] id = "organize.bookmark-delete" title = "Delete bookmarks" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["bookmark_delete"] evidence = ["crates/ui-egui/tests/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/engine/src/tests.rs::bookmark_edits_show_in_the_viewer_undo_and_save"] notes = "" [[feature]] id = "organize.bookmark-move" title = "Reorder and nest bookmarks" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["bookmark_move"] evidence = ["crates/ui-egui/tests/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/engine/src/tests.rs::bookmark_edits_show_in_the_viewer_undo_and_save", "crates/automation/tests/automation.rs::bookmarks_through_tools"] notes = "" [[feature]] id = "organize.bookmark-set-destination" title = "Set a bookmark's destination" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["bookmark_set_page"] evidence = ["crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/engine/src/tests.rs::bookmark_edits_show_in_the_viewer_undo_and_save", "crates/automation/tests/automation.rs::bookmarks_through_tools"] notes = "" [[feature]] id = "organize.bookmark-appearance" title = "Bookmark style and colour" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.bookmark-actions" title = "Bookmark actions" area = "D" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.bookmark-expand-collapse" title = "Expand and collapse all bookmarks" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["file.properties"] tools = [] evidence = ["crates/ui-egui/tests/bookmarks.rs::expanding_and_collapsing_all_bookmarks"] notes = "Bookmarks panel options: expand all, expand top-level, collapse all" [[feature]] id = "organize.bookmarks-from-structure" title = "Generate bookmarks from headings or tags" area = "D" tier = "P1" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.attachments-add" title = "Add file attachments" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.attachments-delete" title = "Delete attachments" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.attachments-description" title = "Edit attachment descriptions" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.associated-files" title = "Associated files with relationships (PDF/A-3, PDF 2.0)" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.portfolio-view" title = "View PDF Portfolios as a file list" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.portfolio-extract" title = "Extract files from a portfolio" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.portfolio-create" title = "Create PDF Portfolios" area = "D" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.document-properties" title = "Document properties dialog (description, fonts, advanced)" area = "D" tier = "P0" milestone = "M3" status = "shipped" commands = ["file.properties"] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/editing.rs::document_properties_edit_is_one_undoable_step", "crates/ui-egui/tests/editing.rs::cancelling_properties_discards_the_draft"] notes = "" [[feature]] id = "organize.edit-metadata" title = "Edit title, author, subject and keywords" area = "D" tier = "P0" milestone = "M4" status = "shipped" commands = ["file.properties"] tools = ["doc_set_info"] evidence = ["crates/organize/src/tests.rs::document_info_edits_round_trip_with_unicode", "crates/ui-egui/tests/editing.rs::document_properties_edit_is_one_undoable_step"] notes = "" [[feature]] id = "organize.fonts-list" title = "List fonts with type and embedding status" area = "D" tier = "P1" milestone = "M3" status = "shipped" commands = ["file.properties"] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/view.rs::fonts_tab_lists_fonts_and_embedding"] notes = "" [[feature]] id = "organize.initial-view" title = "Edit initial view (layout, magnification, panels, window options)" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["file.properties"] tools = ["doc_initial_view"] evidence = ["crates/organize/src/tests.rs::initial_view_round_trips_and_keeps_scripts", "crates/ui-egui/tests/viewer.rs::initial_view_is_edited_and_honoured_on_open", "crates/automation/tests/automation.rs::initial_view_through_tools"] notes = "navigation panel, layout, magnification, page, window and interface options; honoured on open; script open actions kept" [[feature]] id = "organize.custom-properties" title = "Custom document properties" area = "D" tier = "P2" milestone = "M4" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.xmp-editor" title = "Additional metadata (XMP) editor" area = "D" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.document-language" title = "Set document language and binding" area = "D" tier = "P1" milestone = "M4" status = "shipped" commands = ["file.properties"] tools = ["doc_initial_view"] evidence = ["crates/organize/src/tests.rs::initial_view_round_trips_and_keeps_scripts", "crates/automation/tests/automation.rs::initial_view_through_tools"] notes = "Advanced ▸ Reading Options: binding and language" [[feature]] id = "organize.print-presets" title = "Print dialog presets in document properties" area = "D" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "organize.base-url" title = "Base URL for relative links" area = "D" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" # ================================================================================================== # E. Comments and review # ================================================================================================== [[feature]] id = "comment.list-view" title = "Comments panel with threaded replies (read-only)" area = "E" tier = "P0" milestone = "M3" status = "shipped" commands = ["comment.list"] tools = ["comment_list"] evidence = ["crates/ui-egui/tests/ui.rs::opening_a_pdf_shows_comments_and_bookmarks", "crates/ui-egui/tests/comments.rs::the_panel_posts_comments_and_replies"] notes = "cards grouped by page with replies, status badges, selection, reply box and an Add a comment box" [[feature]] id = "comment.appearance-generation" title = "Generate correct appearances for every markup type" area = "E" tier = "P0" milestone = "M5" status = "partial" commands = [] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment", "crates/engine/src/tests.rs::highlight_multiplies_over_text", "crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn"] notes = "appearances for every type PrintCraft creates (highlight multiplies; clouds, callouts, stamps, polygons, carets); rich text not yet" [[feature]] id = "comment.sticky-note" title = "Sticky note comments" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.note"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::sticky_note_composer_posts_and_returns_to_select", "crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "our own Comment/Note icon drawings, with a pop-up" [[feature]] id = "comment.highlight" title = "Highlight text" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.highlight"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::dragging_over_text_with_the_highlighter_highlights_it", "crates/engine/src/tests.rs::highlight_multiplies_over_text"] notes = "drag over text, or pick the tool with text selected; agents can highlight by text search" [[feature]] id = "comment.underline" title = "Underline text" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.underline"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment", "crates/ui-egui/tests/comments.rs::a_selection_made_first_is_marked_when_a_tool_is_picked"] notes = "" [[feature]] id = "comment.strikeout" title = "Strikethrough text" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.strikeout"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::a_selection_made_first_is_marked_when_a_tool_is_picked", "crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "" [[feature]] id = "comment.squiggly" title = "Squiggly underline" area = "E" tier = "P2" milestone = "M5" status = "partial" commands = [] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "engine and agent tool; no toolbar entry yet" [[feature]] id = "comment.replace-text" title = "Replace-text proposal (strikeout + caret)" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.replace"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::replace_text_groups_a_strikeout_and_a_caret", "crates/ui-egui/tests/comments.rs::replacing_text_strikes_it_and_adds_a_caret", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "strikeout (/IT StrikeOutTextEdit) and a grouped caret (/RT /Group) with the replacement" [[feature]] id = "comment.insert-text" title = "Insert-text proposal (caret)" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = ["comment.caret"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn", "crates/ui-egui/tests/comments.rs::polygons_clouds_connected_lines_callouts_and_inserted_text", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "caret at a click; not yet snapped to the text insertion point" [[feature]] id = "comment.typewriter" title = "Add text comment (typewriter)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["sign.fill.text"] tools = ["fill_sign_add"] evidence = ["crates/annot/src/tests.rs::fill_and_sign_items_are_drawn", "crates/ui-egui/tests/fill_sign.rs::text_marks_and_date"] notes = "" [[feature]] id = "comment.text-box" title = "Text box comment with rich text" area = "E" tier = "P0" milestone = "M5" status = "partial" commands = ["comment.freetext"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::sticky_note_composer_posts_and_returns_to_select", "crates/annot/src/tests.rs::text_box_text_and_colour_changes_are_drawn"] notes = "Helvetica text with colour, size and alignment; /RC (XHTML) and /DS are written and kept in step with edits; per-run formatting (bold/italic spans) is not yet" [[feature]] id = "comment.callout" title = "Callout comment" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.callout"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn", "crates/annot/src/tests.rs::editing_a_callout_refits_the_box_and_keeps_the_leader", "crates/ui-egui/tests/comments.rs::polygons_clouds_connected_lines_callouts_and_inserted_text", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "drag from the target to the box; resizing re-attaches the leader, and so does editing the text" [[feature]] id = "comment.pencil" title = "Freehand drawing (ink)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.ink"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::shapes_and_ink_are_drawn_by_dragging"] notes = "one ink annotation per stroke" [[feature]] id = "comment.eraser" title = "Eraser for ink strokes" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.eraser"] tools = [] evidence = ["crates/annot/src/tests.rs::the_eraser_cuts_strokes_and_removes_empty_drawings", "crates/ui-egui/tests/comments.rs::erasing_part_of_a_drawing"] notes = "cuts strokes where the eraser passes; an emptied drawing is deleted; one undo step" [[feature]] id = "comment.line" title = "Line" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.line"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "" [[feature]] id = "comment.arrow" title = "Arrow" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.arrow"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::shapes_and_ink_are_drawn_by_dragging"] notes = "" [[feature]] id = "comment.rectangle" title = "Rectangle" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.square"] tools = ["comment_add", "comment_edit"] evidence = ["crates/ui-egui/tests/comments.rs::shapes_and_ink_are_drawn_by_dragging", "crates/annot/src/tests.rs::restyle_and_resize_redraw_the_appearance"] notes = "resize with the 8 handles" [[feature]] id = "comment.oval" title = "Oval" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.circle"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "" [[feature]] id = "comment.polygon" title = "Polygon" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.polygon"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn", "crates/ui-egui/tests/comments.rs::polygons_clouds_connected_lines_callouts_and_inserted_text", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "click the corners; Enter, double-click or the first point finishes" [[feature]] id = "comment.polyline" title = "Connected lines (polyline)" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.polyline"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn", "crates/ui-egui/tests/comments.rs::polygons_clouds_connected_lines_callouts_and_inserted_text", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "" [[feature]] id = "comment.cloud" title = "Cloud shape" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.cloud"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::polygons_clouds_connected_lines_callouts_and_carets_are_drawn", "crates/annot/src/tests.rs::cloud_paths_bulge_outwards_either_way_round", "crates/ui-egui/tests/comments.rs::polygons_clouds_connected_lines_callouts_and_inserted_text", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "polygon with a cloudy border (/BE /S /C, /IT /PolygonCloud)" [[feature]] id = "comment.area-highlight" title = "Area highlight" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.highlight"] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::highlighting_an_area_off_the_text"] notes = "drag the highlighter off text to highlight a box" [[feature]] id = "comment.attach-file-comment" title = "Attach a file as a comment" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.attach"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::files_attach_as_comments", "crates/ui-egui/tests/comments.rs::attaching_a_file_as_a_comment", "crates/automation/tests/automation.rs::drawing_comments_through_tools"] notes = "push pin, paperclip, graph or tag icon; the file is embedded and listed in the Attachments panel" [[feature]] id = "comment.record-audio" title = "Sound comments" area = "E" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.image-comment" title = "Add an image as a comment" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.line-endings" title = "All ten line-ending styles and dashed/cloudy borders" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = [] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::every_tool_creates_a_drawable_comment"] notes = "None, OpenArrow and ClosedArrow are drawn; other endings are kept but not redrawn" [[feature]] id = "comment.properties-dialog" title = "Comment properties (appearance, author, subject)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_edit"] evidence = ["crates/ui-egui/tests/comments.rs::comment_properties_change_appearance_and_author", "crates/annot/src/tests.rs::author_subject_and_note_icon_change"] notes = "Appearance (colour, opacity, thickness, note icon), General (author, subject), Review History" [[feature]] id = "comment.properties-bar" title = "Comment properties bar" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = ["comment.note"] tools = ["comment_edit"] evidence = ["crates/annot/src/tests.rs::restyle_and_resize_redraw_the_appearance"] notes = "quick-bar colour swatches and line thickness per tool, colour from the context menu; no opacity control in the UI yet" [[feature]] id = "comment.lock-comment" title = "Lock comments" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = [] tools = ["comment_lock"] evidence = ["crates/engine/src/tests.rs::comments_lock_take_checkmarks_hide_and_summarize", "crates/ui-egui/tests/comments.rs::comments_take_checkmarks_lock_hide_and_summarize", "crates/automation/tests/automation.rs::comment_checkmarks_locks_hiding_and_summaries_through_tools"] notes = "Comment Properties ▸ Locked; locked comments refuse move, resize, restyle and delete; text stays editable" [[feature]] id = "comment.default-properties" title = "Make current properties the tool default" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = [] evidence = ["crates/ui-egui/tests/comments.rs::make_current_properties_default"] notes = "colour, opacity and line width become the tool's defaults (canvas and Comments panel menus)" [[feature]] id = "comment.author-identity" title = "Author name from identity preferences" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = [] tools = ["comment_add"] evidence = ["crates/ui-egui/tests/comments.rs::dragging_over_text_with_the_highlighter_highlights_it"] notes = "the login name, as Acrobat defaults to; no Identity preferences yet" [[feature]] id = "comment.reply" title = "Reply to comments" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_reply"] evidence = ["crates/ui-egui/tests/comments.rs::the_panel_posts_comments_and_replies", "crates/annot/src/tests.rs::replies_and_status_thread_onto_the_parent"] notes = "" [[feature]] id = "comment.set-status" title = "Set review status (accepted, rejected, cancelled, completed)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_set_status"] evidence = ["crates/annot/src/tests.rs::replies_and_status_thread_onto_the_parent", "crates/engine/src/tests.rs::comments_are_added_drawn_threaded_and_undone"] notes = "status replies (/State, /StateModel Review), shown as a badge" [[feature]] id = "comment.checkmark" title = "Mark comments with a checkmark" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = [] tools = ["comment_mark"] evidence = ["crates/engine/src/tests.rs::comments_lock_take_checkmarks_hide_and_summarize", "crates/ui-egui/tests/comments.rs::comments_take_checkmarks_lock_hide_and_summarize", "crates/automation/tests/automation.rs::comment_checkmarks_locks_hiding_and_summaries_through_tools"] notes = "hidden /StateModel /Marked reply; card toggle and context menu" [[feature]] id = "comment.delete-comment" title = "Delete comments" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_delete"] evidence = ["crates/ui-egui/tests/comments.rs::comments_are_selected_moved_and_deleted_with_the_select_tool", "crates/annot/src/tests.rs::delete_takes_popup_and_reply_chain"] notes = "deletes the pop-up and the reply thread" [[feature]] id = "comment.edit-comment-text" title = "Edit comment text" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_edit"] evidence = ["crates/annot/src/tests.rs::text_box_text_and_colour_changes_are_drawn", "crates/annot/src/tests.rs::editing_a_text_box_refits_its_rectangle", "crates/automation/tests/automation.rs::comments_through_tools"] notes = "double-click a comment or card, or Edit in the menus; a text box's rectangle follows the new text (wrap width and top edge stay, the height fits the wrapped lines)" [[feature]] id = "comment.copy-comment-text" title = "Copy comment text" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/comments.rs::comments_take_checkmarks_lock_hide_and_summarize"] notes = "card and canvas context menus" [[feature]] id = "comment.filter-comments" title = "Filter comments (type, author, status, colour, checkmark)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_list"] evidence = ["crates/ui-egui/tests/comments.rs::the_panel_filters_and_sorts", "crates/ui-egui/tests/comments.rs::the_panel_filters_by_colour_and_checkmark"] notes = "type, author, status, colour and checkmark" [[feature]] id = "comment.sort-comments" title = "Sort comments (page, author, date, type, colour)" area = "E" tier = "P0" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_list"] evidence = ["crates/ui-egui/tests/comments.rs::the_panel_filters_and_sorts"] notes = "page, author, date, type, colour, with group headers" [[feature]] id = "comment.search-comments" title = "Search comments" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = ["comment.list"] tools = ["comment_list"] evidence = ["crates/ui-egui/tests/comments.rs::the_panel_posts_comments_and_replies"] notes = "search by author, text and type in the panel; not yet in the Find bar" [[feature]] id = "comment.show-hide-comments" title = "Show or hide all comments and pop-ups" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = ["comment.hide_all"] tools = ["comments_hide"] evidence = ["crates/engine/src/tests.rs::comments_lock_take_checkmarks_hide_and_summarize", "crates/ui-egui/tests/comments.rs::comments_take_checkmarks_lock_hide_and_summarize", "crates/automation/tests/automation.rs::comment_checkmarks_locks_hiding_and_summaries_through_tools"] notes = "hide/show all comments (fields and links still draw); per-type hiding not yet" [[feature]] id = "comment.popups" title = "Open and reposition comment pop-ups" area = "E" tier = "P1" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.connector-lines" title = "Connector lines between markups and pop-ups" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.review-history" title = "Review history of state changes" area = "E" tier = "P2" milestone = "M5" status = "shipped" commands = ["comment.list"] tools = ["comment_list"] evidence = ["crates/ui-egui/tests/comments.rs::comment_properties_change_appearance_and_author"] notes = "status changes listed in Comment Properties" [[feature]] id = "comment.stamps-standard" title = "Standard business stamps" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.stamp"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::stamps_draw_their_label_and_by_line", "crates/ui-egui/tests/stamps.rs::choosing_and_placing_stamps", "crates/automation/tests/automation.rs::stamps_through_tools"] notes = "12 standard business stamps in PrintCraft's own design; ISO 32000 stamp names where defined" [[feature]] id = "comment.stamps-sign-here" title = "Sign-here stamps" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.stamp"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::stamps_draw_their_label_and_by_line", "crates/ui-egui/tests/stamps.rs::choosing_and_placing_stamps", "crates/automation/tests/automation.rs::stamps_through_tools"] notes = "Accepted, Initial Here, Rejected, Sign Here, Witness as pointed tags" [[feature]] id = "comment.stamps-dynamic" title = "Dynamic stamps (name and date)" area = "E" tier = "P1" milestone = "M6" status = "shipped" commands = ["comment.stamp"] tools = ["comment_add"] evidence = ["crates/annot/src/tests.rs::stamps_draw_their_label_and_by_line", "crates/ui-egui/tests/stamps.rs::choosing_and_placing_stamps", "crates/automation/tests/automation.rs::stamps_through_tools"] notes = "Approved, Confidential, Received, Reviewed, Revised with a By author at time, date line (local time)" [[feature]] id = "comment.stamps-custom" title = "Custom stamps from images or PDF pages" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.stamp"] tools = ["stamp_custom"] evidence = ["crates/ui-egui/tests/stamps.rs::creating_placing_and_keeping_custom_stamps", "crates/automation/tests/automation.rs::stamps_through_tools"] notes = "Create custom stamp from a PDF page or an image (category and name), kept in the app's settings; placed at natural size (at most 200 pt) keeping its shape; resizable (appearance redrawn from /PCPicture); delete from the palette" [[feature]] id = "comment.stamps-manage" title = "Manage stamp categories and imports" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.stamps-rotate" title = "Rotate stamps with a handle" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.import-fdf-xfdf" title = "Import comments from FDF/XFDF" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.import"] tools = ["doc_import_data"] evidence = ["crates/xfdf/src/tests.rs::xfdf_round_trips_comments_and_values", "crates/xfdf/src/tests.rs::fdf_round_trips_values_and_comments", "crates/automation/tests/automation.rs::comments_and_form_data_travel_as_xfdf_fdf_and_text"] notes = "replies, pop-ups, ink, quads, line ends; same /NM replaces" [[feature]] id = "comment.export-fdf-xfdf" title = "Export all comments to FDF/XFDF" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.export"] tools = ["doc_export_data"] evidence = ["crates/xfdf/src/tests.rs::xfdf_round_trips_comments_and_values", "crates/xfdf/src/tests.rs::fdf_round_trips_values_and_comments", "crates/automation/tests/automation.rs::comments_and_form_data_travel_as_xfdf_fdf_and_text"] notes = "" [[feature]] id = "comment.export-selected" title = "Export selected comments" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.import-from-pdf" title = "Import comments from another PDF" area = "E" tier = "P2" milestone = "M5" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.summarize" title = "Summarize comments into a new PDF" area = "E" tier = "P1" milestone = "M5" status = "partial" commands = ["comment.summarize"] tools = ["comments_summarize"] evidence = ["crates/engine/src/tests.rs::comments_lock_take_checkmarks_hide_and_summarize", "crates/ui-egui/tests/comments.rs::comments_take_checkmarks_lock_hide_and_summarize", "crates/automation/tests/automation.rs::comment_checkmarks_locks_hiding_and_summaries_through_tools"] notes = "Comments only layout, sorted by page, author, date or type; the layouts with the document and connector lines not yet" [[feature]] id = "comment.flatten" title = "Flatten comments into page content" area = "E" tier = "P1" milestone = "M5" status = "shipped" commands = ["comment.flatten"] tools = ["doc_flatten"] evidence = ["crates/edit/src/tests.rs::flattening_draws_appearances_into_the_page_and_removes_the_comments", "crates/engine/src/tests.rs::flattening_keeps_the_look_and_drops_the_objects", "crates/automation/tests/automation.rs::flattening_through_tools"] notes = "appearances become page content; pop-ups and replies removed" [[feature]] id = "comment.migrate" title = "Migrate comments to a revised document" area = "E" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-distance" title = "Distance measuring tool" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-perimeter" title = "Perimeter measuring tool" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-area" title = "Area measuring tool" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-scale" title = "Scale ratio and calibration per viewport" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-snap" title = "Snap to paths, endpoints, midpoints and intersections" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-info-panel" title = "Measurement info panel" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.measure-export" title = "Export measurements as CSV" area = "E" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.geospatial" title = "Geospatial location and measuring" area = "E" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "comment.shared-review" title = "Send for comments / shared review" area = "E" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; exchange XFDF files or a pluggable review server instead" [[feature]] id = "comment.mentions-live-review" title = "@mentions, presence and live co-review" area = "E" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; no local equivalent" [[feature]] id = "comment.review-tracker" title = "Review tracker" area = "E" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud / legacy" [[feature]] id = "comment.enable-reader-commenting" title = "Enable commenting and measuring in Reader (usage rights)" area = "E" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "needs Adobe's private key; modern readers allow commenting anyway" # ================================================================================================== # F. Forms and JavaScript # ================================================================================================== [[feature]] id = "form.field-list" title = "Form fields panel listing every field and value" area = "F" tier = "P0" milestone = "M3" status = "shipped" commands = ["form.fields"] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/view.rs::field_list_jumps_to_a_fields_page"] notes = "read-only list with jump-to-field; filling and editing are separate features (M6)" [[feature]] id = "form.highlight-fields" title = "Highlight existing fields" area = "F" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/view.rs::highlight_fields_tints_the_field_area"] notes = "" [[feature]] id = "form.field-appearance-display" title = "Display checkbox, radio, list and signature widgets as designed" area = "F" tier = "P0" milestone = "M2" status = "shipped" commands = [] tools = [] evidence = ["crates/render/src/raster.rs::widget_appearance_states"] notes = "" [[feature]] id = "form.fill-text" title = "Fill text fields" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.fields"] tools = ["form_fill", "form_fields"] evidence = ["crates/ui-egui/tests/forms.rs::typing_into_a_text_field_and_tabbing_on", "crates/forms/src/tests.rs::text_fields_get_new_appearances", "crates/engine/src/tests.rs::filling_a_form_shows_saves_and_undoes"] notes = "in-place editor; Enter or clicking away commits, Escape cancels; no format/keystroke JavaScript yet (M6.4)" [[feature]] id = "form.fill-checkbox-radio" title = "Toggle checkboxes and radio buttons (radios in unison)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.fields"] tools = ["form_fill"] evidence = ["crates/ui-egui/tests/forms.rs::check_boxes_radios_and_choices", "crates/forms/src/tests.rs::check_boxes_and_radios_switch_states"] notes = "NoToggleToOff honoured; widgets without appearances get our own" [[feature]] id = "form.fill-choice" title = "Choose from combo boxes and list boxes" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.fields"] tools = ["form_fill"] evidence = ["crates/ui-egui/tests/forms.rs::check_boxes_radios_and_choices", "crates/forms/src/tests.rs::choices_accept_exports_or_display_text"] notes = "combo and list boxes, multi-select lists; editable combo boxes accept free text" [[feature]] id = "form.push-buttons" title = "Push buttons run their actions" area = "F" tier = "P0" milestone = "M6" status = "partial" commands = ["form.fields"] tools = [] evidence = ["crates/ui-egui/tests/buttons.rs::buttons_reset_navigate_and_print", "crates/forms/src/af.rs::common_button_scripts_are_recognised", "crates/ui-egui/tests/javascript.rs::button_scripts_run_and_alert"] notes = "Reset form, Named (print, page navigation), URI, Go to, and any JavaScript (run in the sandboxed engine); submit explained, not sent" [[feature]] id = "form.field-navigation" title = "Tab between fields" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.fields"] tools = [] evidence = ["crates/ui-egui/tests/forms.rs::tabbing_into_a_filled_field_selects_it_so_typing_replaces"] notes = "Tab / Shift+Tab move between text and choice fields in field order; entering with Tab selects the value" [[feature]] id = "form.appearance-regeneration" title = "Regenerate field appearances (auto-size, comb, multiline, password)" area = "F" tier = "P0" milestone = "M6" status = "partial" commands = ["form.fields"] tools = ["form_fill"] evidence = ["crates/forms/src/tests.rs::text_fields_get_new_appearances", "crates/forms/src/tests.rs::choices_accept_exports_or_display_text"] notes = "auto-size, comb, multiline, password, quadding, /MK colours; approximate Helvetica metrics, no /MK rotation yet" [[feature]] id = "form.rich-text-fields" title = "Rich-text field values" area = "F" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.af-number" title = "Number and currency formatting (AFNumber)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::numbers_format_like_acrobat", "crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "AFNumber_Format/Keystroke run natively: decimals, 5 separator styles, currency before/after, negative styles (red shown as minus/parentheses)" [[feature]] id = "form.af-percent" title = "Percentage formatting" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::numbers_format_like_acrobat"] notes = "AFPercent_Format/Keystroke" [[feature]] id = "form.af-date-time" title = "Date and time formatting and parsing" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::dates_times_and_masks", "crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat"] notes = "AFDate_FormatEx/KeystrokeEx, AFDate_Format presets, AFTime_Format(Ex): lenient parsing, month and day names, impossible dates refused" [[feature]] id = "form.af-special" title = "Special formats (zip, phone, SSN, arbitrary mask)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::dates_times_and_masks"] notes = "zip, zip+4, phone, SSN, arbitrary masks (9 A O X)" [[feature]] id = "form.af-range-validate" title = "Range validation" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::validation_and_calculation", "crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "AFRange_Validate with Acrobat's messages" [[feature]] id = "form.af-simple-calculate" title = "Sum, product, average, min, max calculations" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::validation_and_calculation", "crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat"] notes = "SUM, PRD, AVG, MIN, MAX over fields and groups" [[feature]] id = "form.simplified-notation" title = "Simplified field notation calculations" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/af.rs::validation_and_calculation", "crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "BVCALC expressions with + - * / and parentheses, escaped names" [[feature]] id = "form.custom-scripts" title = "Custom format, keystroke, validate and calculate scripts" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_set_script"] evidence = ["crates/engine/src/tests.rs::form_javascript_validates_calculates_and_formats", "crates/automation/tests/automation.rs::javascript_through_tools"] notes = "Custom keystroke (commit), validate, calculate and format scripts run in Acrobat's event order; AF calls still run natively." [[feature]] id = "form.calculation-order" title = "Calculation order" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/forms/src/tests.rs::formats_validation_and_calculations_run_like_acrobat"] notes = "/CO order, then other calculated fields; recalculated after every fill and Clear form" [[feature]] id = "form.event-order" title = "Keystroke, validate, calculate, format event order" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_fill"] evidence = ["crates/engine/src/tests.rs::form_javascript_validates_calculates_and_formats"] notes = "Keystroke (commit) \u2192 Validate \u2192 value \u2192 Calculate (in /CO order) \u2192 Format, for AF calls and custom scripts." [[feature]] id = "form.date-picker" title = "Date picker for date fields" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = [] tools = ["form_fill"] evidence = ["crates/ui-egui/tests/forms.rs::date_fields_offer_a_calendar"] notes = "a month calendar under date fields; the pick is written in the field's own date format" [[feature]] id = "form.auto-complete" title = "Auto-complete from previous entries" area = "F" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.required-fields" title = "Required-field highlighting" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = [] tools = ["form_set_props"] evidence = ["crates/ui-egui/tests/view.rs::required_fields_get_a_red_border_when_highlighting"] notes = "required fields get a red border when fields are highlighted" [[feature]] id = "form.reset-form" title = "Clear or reset a form" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.clear"] tools = ["form_reset"] evidence = ["crates/forms/src/tests.rs::reset_restores_defaults", "crates/ui-egui/tests/forms.rs::check_boxes_radios_and_choices"] notes = "back to /DV; undoable" [[feature]] id = "form.submit-form" title = "Submit form to a URL or email (with a prompt)" area = "F" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.import-data" title = "Import form data (FDF, XFDF)" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.import_data"] tools = ["doc_import_data"] evidence = ["crates/xfdf/src/tests.rs::xfdf_round_trips_comments_and_values", "crates/xfdf/src/tests.rs::fdf_round_trips_values_and_comments", "crates/automation/tests/automation.rs::comments_and_form_data_travel_as_xfdf_fdf_and_text"] notes = "XFDF, FDF; values go through formats and validation; read-only fields take data" [[feature]] id = "form.export-data" title = "Export form data (FDF, XFDF)" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.export_data"] tools = ["doc_export_data"] evidence = ["crates/xfdf/src/tests.rs::xfdf_round_trips_comments_and_values", "crates/automation/tests/automation.rs::comments_and_form_data_travel_as_xfdf_fdf_and_text"] notes = "XFDF, FDF" [[feature]] id = "form.data-xml-csv-txt" title = "Form data as XML, CSV or tab-delimited text" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.export_data", "form.import_data"] tools = ["doc_export_data", "doc_import_data"] evidence = ["crates/xfdf/src/tests.rs::form_data_as_xml_csv_and_text", "crates/automation/tests/automation.rs::comments_and_form_data_travel_as_xfdf_fdf_and_text"] notes = "Acrobat's XML (xfdf:original), CSV, tab-delimited" [[feature]] id = "form.merge-to-spreadsheet" title = "Merge form data files into a spreadsheet" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.merge_data"] tools = ["form_merge_data"] evidence = ["crates/xfdf/src/tests.rs::data_files_merge_into_a_spreadsheet", "crates/automation/tests/automation.rs::merging_form_data_into_a_spreadsheet", "crates/ui-egui/tests/javascript.rs::merge_data_files_into_a_spreadsheet"] notes = "FDF, XFDF or filled-in PDF forms \u2192 CSV, a column per field and a row per file." [[feature]] id = "form.flatten-fields" title = "Flatten form fields" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.flatten"] tools = ["doc_flatten"] evidence = ["crates/edit/src/tests.rs::flattening_draws_appearances_into_the_page_and_removes_the_comments", "crates/engine/src/tests.rs::flattening_keeps_the_look_and_drops_the_objects", "crates/automation/tests/automation.rs::flattening_through_tools"] notes = "widgets drawn into content and pruned from the field tree" [[feature]] id = "form.prepare-form-mode" title = "Prepare a form mode" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_add_field", "form_set_props", "form_delete_field"] evidence = ["crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field", "crates/engine/src/tests.rs::preparing_a_form_adds_renames_and_deletes_fields"] notes = "fields shown with blue fill and name tags; select, move, resize by corners, Delete; field tools return to Select after one field" [[feature]] id = "form.add-text-field" title = "Add text fields" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.text"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn", "crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field", "crates/automation/tests/automation.rs::preparing_a_form_through_tools"] notes = "click for the default size or drag; named Text1, Text2…" [[feature]] id = "form.add-checkbox" title = "Add checkboxes" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.checkbox"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn", "crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field"] notes = "Check Box1…, Yes/Off appearance states" [[feature]] id = "form.add-radio" title = "Add radio buttons" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.radio"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn", "crates/automation/tests/automation.rs::preparing_a_form_through_tools"] notes = "new group Group1… or join the selected group with the next ChoiceN" [[feature]] id = "form.add-dropdown" title = "Add drop-down lists" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.combo"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn", "crates/automation/tests/automation.rs::preparing_a_form_through_tools"] notes = "Dropdown1…; items in Field Properties ▸ Options" [[feature]] id = "form.add-listbox" title = "Add list boxes" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.list"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn"] notes = "List Box1…" [[feature]] id = "form.add-button" title = "Add push buttons" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.button"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn"] notes = "Button1…; actions arrive with the JavaScript engine" [[feature]] id = "form.add-image-field" title = "Add image fields" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.add.image"] tools = ["form_add_field", "form_set_image"] evidence = ["crates/forms/src/tests.rs::image_fields_ask_for_a_picture_and_show_it", "crates/ui-egui/tests/prepare.rs::image_fields_take_a_picture_when_clicked", "crates/automation/tests/automation.rs::preparing_a_form_through_tools"] notes = "icon-only push button with event.target.buttonImportIcon(), recognised natively; clicking asks for a PNG/JPEG/TIFF/GIF/BMP that becomes /MK /I, scaled proportionally and centred" [[feature]] id = "form.add-date-field" title = "Add date fields" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.date"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn"] notes = "text field with AFDate_FormatEx(\"mm/dd/yyyy\") format/keystroke actions" [[feature]] id = "form.add-signature-field" title = "Add digital signature fields" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.add.signature"] tools = ["form_add_field"] evidence = ["crates/forms/src/tests.rs::every_field_type_can_be_added_named_and_drawn"] notes = "unsigned /Sig field; signing is M9" [[feature]] id = "form.add-barcode-field" title = "Barcode fields (PDF417, QR, Data Matrix)" area = "F" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.props-general" title = "Field properties: general (name, tooltip, visibility, read-only, required)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props"] evidence = ["crates/forms/src/tests.rs::properties_rename_and_delete", "crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field", "crates/automation/tests/automation.rs::preparing_a_form_through_tools"] notes = "name, tooltip, read only, required (visibility/orientation pending)" [[feature]] id = "form.props-appearance" title = "Field properties: appearance (border, fill, font)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props"] evidence = ["crates/forms/src/tests.rs::appearance_properties_restyle_every_widget", "crates/ui-egui/tests/prepare.rs::appearance_tab_restyles_the_field", "crates/automation/tests/automation.rs::tab_order_and_field_appearance_through_tools"] notes = "border/fill colour, thin/medium/thick, solid/dashed/beveled/inset/underline, text colour, Helvetica/Times/Courier, font size" [[feature]] id = "form.props-position" title = "Field properties: position and size" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props"] evidence = ["crates/forms/src/tests.rs::properties_rename_and_delete", "crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field"] notes = "left/bottom/width/height in points; drag to move, corners to resize" [[feature]] id = "form.props-options" title = "Field properties: options per field type" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props"] evidence = ["crates/forms/src/tests.rs::properties_rename_and_delete", "crates/automation/tests/automation.rs::preparing_a_form_through_tools", "crates/forms/src/tests.rs::options_tab_flags_alignment_and_defaults", "crates/ui-egui/tests/prepare.rs::options_tab_sets_flags_alignment_and_defaults"] notes = "text: alignment, default, multi-line, scroll, rich text flag, limit, password, file selection, spell check, comb; choices: items, default, sort, custom text, multiple selection, commit immediately; check boxes and radios: checked by default, radios in unison" [[feature]] id = "form.props-actions" title = "Field properties: actions per trigger" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_actions", "form_set_actions"] evidence = ["crates/forms/src/tests.rs::field_actions_round_trip_on_every_trigger", "crates/automation/tests/automation.rs::field_actions_through_tools", "crates/ui-egui/tests/prepare.rs::actions_tab_adds_and_removes_actions"] notes = "Six triggers; Run a JavaScript, Open a web link, Reset a form, Execute a menu item, Go to a page view, Show/hide a field, Submit a form. Other action types are kept." [[feature]] id = "form.props-format" title = "Field properties: format" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/ui-egui/tests/prepare.rs::format_validate_and_calculate_tabs", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "None/Number/Percentage/Date/Time/Special with a live example; writes Acrobat's AF scripts" [[feature]] id = "form.props-validate" title = "Field properties: validate" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/ui-egui/tests/prepare.rs::format_validate_and_calculate_tabs", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "range from/to" [[feature]] id = "form.props-calculate" title = "Field properties: calculate" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.field.properties"] tools = ["form_set_props", "form_fill"] evidence = ["crates/ui-egui/tests/prepare.rs::format_validate_and_calculate_tabs", "crates/automation/tests/automation.rs::form_formats_and_calculations_through_tools"] notes = "sum/product/average/min/max of picked fields, simplified field notation; custom script pending" [[feature]] id = "form.props-selection-change" title = "Field properties: selection change" area = "F" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.props-signed" title = "Field properties: signed (lock fields when signed)" area = "F" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.align-distribute-fields" title = "Align, centre, distribute and match field sizes" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_set_props"] evidence = ["crates/ui-egui/tests/prepare.rs::aligning_distributing_and_sizing_several_fields"] notes = "Shift/⌘-click to select several; right-click: Align (left, right, top, bottom, centres), Distribute, Set Fields to Same Size; the right-clicked field is the anchor" [[feature]] id = "form.duplicate-fields" title = "Duplicate fields across pages" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = [] evidence = ["crates/forms/src/tests.rs::duplicating_a_field_across_pages_shares_its_value", "crates/ui-egui/tests/prepare.rs::duplicating_a_field_onto_every_page"] notes = "right-click a field ▸ Duplicate: all pages or a range; one field, shared value" [[feature]] id = "form.multiple-copies" title = "Create multiple copies of a field in a grid" area = "F" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.rename-lock-fields" title = "Rename and lock fields" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = ["form_set_props"] evidence = ["crates/forms/src/tests.rs::locked_fields_only_take_unlocking", "crates/ui-egui/tests/prepare.rs::preview_fills_the_form_and_locked_fields_keep_their_properties"] notes = "rename in Field Properties ▸ General; Locked sets the widgets' annotation Locked flag (/F bit 8) and greys out the properties until unlocked; values can still be filled in" [[feature]] id = "form.tab-order" title = "Tab order (row, column, structure, manual)" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["form.tab_order.row", "form.tab_order.column", "form.tab_order.structure"] tools = ["form_tab_order"] evidence = ["crates/forms/src/tests.rs::tab_order_follows_the_page_setting", "crates/automation/tests/automation.rs::tab_order_and_field_appearance_through_tools", "crates/forms/src/tests.rs::ordering_tabs_manually", "crates/ui-egui/tests/prepare.rs::the_fields_panel_orders_tabs_manually"] notes = "rows, columns, structure/annotation order (page /Tabs), and manual order from the Fields panel while preparing a form; honoured by Tab" [[feature]] id = "form.show-tab-numbers" title = "Show tab numbers" area = "F" tier = "P2" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.preview-form" title = "Preview mode for testing a form" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.prepare"] tools = [] evidence = ["crates/ui-egui/tests/prepare.rs::preview_fills_the_form_and_locked_fields_keep_their_properties"] notes = "Preview / Edit fields toggle in the Prepare a form panel" [[feature]] id = "form.auto-detect-fields" title = "Automatic form field detection" area = "F" tier = "P1" milestone = "M6" status = "partial" commands = ["form.detect", "form.prepare"] tools = ["form_detect_fields"] evidence = ["crates/forms/src/tests.rs::detection_finds_blanks_rules_boxes_and_names_them", "crates/engine/src/tests.rs::detecting_fields_on_a_printed_form", "crates/automation/tests/automation.rs::detecting_form_fields_through_tools", "crates/ui-egui/tests/javascript.rs::prepare_a_form_detects_fields_on_a_paper_form"] notes = "Underscore runs, rules, empty boxes and small squares (check boxes); runs when Prepare a form starts on a document without fields. Not yet: comb boxes, tables of cells, scanned forms (needs OCR first), radio groups." [[feature]] id = "form.auto-name-fields" title = "Name new fields from nearby labels" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["form.detect"] tools = ["form_detect_fields"] evidence = ["crates/forms/src/tests.rs::detection_finds_blanks_rules_boxes_and_names_them", "crates/engine/src/tests.rs::detecting_fields_on_a_printed_form", "crates/automation/tests/automation.rs::detecting_form_fields_through_tools"] notes = "Names come from the label to the left (or above; right of check boxes), unique like Acrobat's (Name2, Text1)." [[feature]] id = "form.document-javascripts" title = "Document-level JavaScripts" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["tools.document_js"] tools = ["js_document_scripts", "js_set_document_script"] evidence = ["crates/ui-egui/tests/javascript.rs::document_scripts_and_preferences", "crates/automation/tests/automation.rs::javascript_through_tools", "crates/engine/src/tests.rs::form_javascript_validates_calculates_and_formats"] notes = "Names /JavaScript tree: list, add, edit, delete; functions are available to field scripts." [[feature]] id = "form.document-actions" title = "Document actions (will close, will save, did save, will print, did print)" area = "F" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.js-host" title = "JavaScript engine with the Acrobat object model subset" area = "F" tier = "P0" milestone = "M6" status = "partial" commands = ["tools.js_console"] tools = ["js_run"] evidence = ["crates/js/src/tests.rs::calculate_scripts_read_fields_and_set_the_value", "crates/engine/src/tests.rs::form_javascript_validates_calculates_and_formats", "crates/automation/tests/automation.rs::javascript_through_tools"] notes = "boa (pure Rust) with the forms object model: event, getField/Field (value, readonly, display, colours, items, check boxes), app, util.printf/printd/printx, console, display, color; no annotations, layers or dialogs (app.response returns null) yet." [[feature]] id = "form.js-console" title = "JavaScript console" area = "F" tier = "P1" milestone = "M6" status = "shipped" commands = ["tools.js_console"] tools = ["js_run"] evidence = ["crates/ui-egui/tests/javascript.rs::console_runs_scripts_against_the_document", "crates/automation/tests/automation.rs::javascript_through_tools"] notes = "\u2318J: run JavaScript against the document, with console output, results and errors." [[feature]] id = "form.js-debugger" title = "JavaScript debugger" area = "F" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.edit-all-javascripts" title = "Edit all JavaScripts in one editor" area = "F" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.js-security" title = "JavaScript enable switch and sandboxing" area = "F" tier = "P0" milestone = "M6" status = "shipped" commands = ["app.preferences"] tools = ["js_enabled"] evidence = ["crates/js/src/tests.rs::the_sandbox_has_no_host_access", "crates/js/src/tests.rs::errors_and_runaway_scripts_are_contained", "crates/ui-egui/tests/javascript.rs::document_scripts_and_preferences"] notes = "Preferences \u25b8 JavaScript \u25b8 Enable Acrobat JavaScript (remembered); no host access; loop and recursion limits." [[feature]] id = "form.folder-level-js" title = "Folder-level JavaScript" area = "F" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.xfa-static" title = "View and fill static XFA forms" area = "F" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.xfa-dynamic" title = "View and fill dynamic XFA forms" area = "F" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.xfa-formcalc" title = "FormCalc scripting" area = "F" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.xfa-data" title = "XFA XML data import and export" area = "F" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.xfa-flatten" title = "Flatten XFA forms" area = "F" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "form.fill-sign-text" title = "Fill & Sign: add text on flat forms" area = "F" tier = "P0" milestone = "M5" status = "shipped" commands = ["sign.fill.text"] tools = ["fill_sign_add"] evidence = ["crates/ui-egui/tests/fill_sign.rs::text_marks_and_date", "crates/annot/src/tests.rs::fill_and_sign_items_are_drawn", "crates/automation/tests/automation.rs::fill_and_sign_through_tools"] notes = "typewriter FreeText, 10 pt Helvetica" [[feature]] id = "form.fill-sign-marks" title = "Fill & Sign: check, cross, dot, line marks" area = "F" tier = "P0" milestone = "M5" status = "shipped" commands = ["sign.fill.check", "sign.fill.cross", "sign.fill.dot", "sign.fill.line"] tools = ["fill_sign_add"] evidence = ["crates/ui-egui/tests/fill_sign.rs::text_marks_and_date", "crates/annot/src/tests.rs::fill_and_sign_items_are_drawn"] notes = "PrintCraft-drawn stamps" [[feature]] id = "form.fill-sign-date" title = "Fill & Sign: today's date" area = "F" tier = "P0" milestone = "M5" status = "shipped" commands = ["sign.fill.date"] tools = ["fill_sign_add"] evidence = ["crates/ui-egui/tests/fill_sign.rs::text_marks_and_date", "crates/automation/tests/automation.rs::fill_and_sign_through_tools"] notes = "local date, m/d/yyyy" [[feature]] id = "form.fill-sign-signature" title = "Fill & Sign: typed, drawn or image signature and initials" area = "F" tier = "P0" milestone = "M5" status = "partial" commands = ["sign.fill.signature", "sign.fill.initials"] tools = ["fill_sign_add"] evidence = ["crates/ui-egui/tests/fill_sign.rs::typed_signatures_and_initials", "crates/ui-egui/tests/fill_sign.rs::signing_draws_a_signature_once_and_places_it", "crates/fonts/src/script.rs::a_name_becomes_outlines", "crates/automation/tests/automation.rs::fill_and_sign_through_tools"] notes = "signature and initials, typed (Dancing Script outlines as filled paths, no font embedded) or drawn, saved in settings; image signatures not yet" [[feature]] id = "form.fill-sign-flatten" title = "Fill & Sign: flatten on save" area = "F" tier = "P0" milestone = "M5" status = "partial" commands = ["comment.flatten"] tools = ["doc_flatten"] evidence = ["crates/edit/src/tests.rs::flattening_draws_appearances_into_the_page_and_removes_the_comments", "crates/engine/src/tests.rs::flattening_keeps_the_look_and_drops_the_objects", "crates/automation/tests/automation.rs::flattening_through_tools"] notes = "Flatten comments flattens Fill & Sign items; no flatten-on-save option yet" [[feature]] id = "form.autofill-profile" title = "Autofill collection synced to an Adobe account" area = "F" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; a local profile may come later" [[feature]] id = "form.distribute-track" title = "Distribute and track forms, collect responses" area = "F" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; only submit-to-URL/email actions are supported" [[feature]] id = "form.web-forms" title = "Acrobat Sign web forms" area = "F" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud" # ================================================================================================== # G. Protect, redact, sanitize # ================================================================================================== [[feature]] id = "protect.security-properties" title = "Security properties (method, which password opened it, each permission)" area = "G" tier = "P0" milestone = "M3" status = "shipped" commands = ["protect.properties"] tools = ["doc_info"] evidence = ["crates/ui-egui/tests/editing.rs::password_prompt_opens_and_security_tab_reports_the_details"] notes = "" [[feature]] id = "protect.password-to-open" title = "Protect with a password to open" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = ["doc_protect"] evidence = ["crates/ui-egui/tests/protect.rs::protecting_for_viewing_requires_matching_passwords_and_saves_encrypted", "crates/engine/src/tests.rs::protect_with_an_open_password_then_save_reopen_and_undo", "crates/automation/tests/automation.rs::protecting_through_tools"] notes = "Protect Using Password (Viewing); applied by the next save" [[feature]] id = "protect.permissions-password" title = "Restrict editing and printing with a permissions password" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = ["doc_protect"] evidence = ["crates/ui-egui/tests/protect.rs::editing_restrictions_via_advanced_options", "crates/engine/src/tests.rs::permissions_password_restricts_others_but_not_this_session", "crates/automation/tests/automation.rs::protecting_through_tools"] notes = "Protect Using Password (Editing); the author keeps full rights after saving" [[feature]] id = "protect.permissions-matrix" title = "Choose printing, changes, copying and accessibility permissions" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = ["doc_protect"] evidence = ["crates/ui-egui/tests/protect.rs::editing_restrictions_via_advanced_options", "crates/engine/src/tests.rs::permissions_password_restricts_others_but_not_this_session"] notes = "Advanced Options: printing (none/low/high), changes (5 levels), copying, screen readers" [[feature]] id = "protect.encryption-level" title = "Choose encryption compatibility (RC4 40/128, AES-128, AES-256)" area = "G" tier = "P1" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = ["doc_protect"] evidence = ["crates/engine/src/tests.rs::protection_is_validated_undoable_and_never_logged"] notes = "AES-256 (default), AES-128, RC4-128, RC4-40" [[feature]] id = "protect.encrypt-except-metadata" title = "Encrypt everything except metadata" area = "G" tier = "P1" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = ["doc_protect"] evidence = ["crates/engine/src/tests.rs::protection_is_validated_undoable_and_never_logged"] notes = "Advanced Options; disabled for RC4 levels as in Acrobat" [[feature]] id = "protect.encrypt-attachments-only" title = "Encrypt only file attachments" area = "G" tier = "P2" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.password-strength" title = "Password strength meter" area = "G" tier = "P2" milestone = "M8" status = "shipped" commands = ["protect.password"] tools = [] evidence = ["crates/ui-egui/tests/protect.rs::protecting_for_viewing_requires_matching_passwords_and_saves_encrypted"] notes = "Weak / Medium / Strong under the password field" [[feature]] id = "protect.remove-security" title = "Remove security" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["protect.remove"] tools = ["doc_unprotect"] evidence = ["crates/engine/src/tests.rs::protect_with_an_open_password_then_save_reopen_and_undo", "crates/automation/tests/automation.rs::protecting_through_tools"] notes = "needs the permissions password (or none set)" [[feature]] id = "protect.certificate-encryption" title = "Encrypt with certificates for recipients" area = "G" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.recipient-permissions" title = "Per-recipient permissions for certificate security" area = "G" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.recipient-ldap" title = "Find recipients in a directory (LDAP)" area = "G" tier = "P3" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.security-policies" title = "Local security policies (saved presets)" area = "G" tier = "P2" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.rights-management" title = "Server-based rights management (AEM/LiveCycle)" area = "G" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "server product; local policy presets only" [[feature]] id = "protect.mip-labels" title = "Open Microsoft Purview-protected PDFs and apply labels" area = "G" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "optional Windows plug-in" [[feature]] id = "protect.redact-text" title = "Mark text for redaction" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.mark"] tools = ["redact_mark"] evidence = ["crates/ui-egui/tests/redact.rs::marking_applying_and_clearing", "crates/automation/tests/automation.rs::redacting_through_tools", "crates/redact/src/tests.rs::glyphs_under_a_mark_go_and_the_rest_stays_put"] notes = "drag across text (or select first) with the Redact tool" [[feature]] id = "protect.redact-area" title = "Mark areas and images for redaction" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.mark"] tools = ["redact_mark"] evidence = ["crates/ui-egui/tests/redact.rs::marking_applying_and_clearing", "crates/redact/src/tests.rs::images_are_removed_or_have_their_pixels_cleared"] notes = "drag a box anywhere else" [[feature]] id = "protect.redact-pages" title = "Mark whole pages for redaction" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.pages"] tools = ["redact_mark"] evidence = ["crates/ui-egui/tests/redact.rs::marking_applying_and_clearing"] notes = "Mark Page Range: current page or a range" [[feature]] id = "protect.search-and-redact" title = "Find text and redact" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.search"] tools = ["redact_mark"] evidence = ["crates/automation/tests/automation.rs::redacting_through_tools"] notes = "single word or phrase, every match on every page" [[feature]] id = "protect.redact-word-lists" title = "Redact lists of words or phrases" area = "G" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.redact-patterns" title = "Redact patterns (phone, email, card, SSN, dates)" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.search"] tools = ["redact_mark"] evidence = ["crates/redact/src/patterns.rs::phone_numbers", "crates/redact/src/patterns.rs::credit_cards_need_a_valid_checksum", "crates/automation/tests/automation.rs::redacting_through_tools"] notes = "phone, e-mail, credit card (Luhn), SSN, dates (English US forms)" [[feature]] id = "protect.redact-pattern-locales" title = "Pattern sets per locale" area = "G" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.redact-partial-words" title = "Redact part of a match (e.g. all but the last four digits)" area = "G" tier = "P2" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.redact-folder" title = "Search and redact across a folder" area = "G" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.redaction-properties" title = "Redaction fill colour and overlay text" area = "G" tier = "P0" milestone = "M8" status = "partial" commands = ["redact.properties"] tools = ["redact_mark"] evidence = ["crates/ui-egui/tests/redact.rs::marking_applying_and_clearing", "crates/redact/src/tests.rs::overlay_text_takes_its_font_size_colour_alignment_and_repeats"] notes = "fill colour or none; overlay text with font, size or auto-size, colour, alignment and repeat; redaction codes pending" [[feature]] id = "protect.redaction-codes" title = "Redaction code sets (e.g. FOIA exemptions)" area = "G" tier = "P1" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.apply-redactions" title = "Apply redactions (remove underlying content)" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/ui-egui/tests/redact.rs::marking_applying_and_clearing", "crates/engine/src/tests.rs::redaction_marks_apply_for_good_and_undo", "crates/automation/tests/automation.rs::redacting_through_tools"] notes = "confirmation; one undo step; next save is a full rewrite" [[feature]] id = "protect.redact-glyph-removal" title = "Remove redacted text glyphs from content streams" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::glyphs_under_a_mark_go_and_the_rest_stays_put", "crates/redact/src/tests.rs::kerning_spacing_scaling_and_line_operators_are_honoured", "crates/redact/src/tests.rs::rotated_text_and_composite_fonts", "crates/redact/src/tests.rs::shared_form_xobjects_are_copied_not_changed"] notes = "TJ displacement keeps the rest in place; simple, composite (CMaps), Type 3 fonts" [[feature]] id = "protect.redact-image-pixels" title = "Remove redacted image pixels" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::images_are_removed_or_have_their_pixels_cleared"] notes = "covered pixels cleared in a copy; DCT/JPX/JBIG2/CCITT images removed whole" [[feature]] id = "protect.redact-vectors" title = "Remove or cut redacted vector paths" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::vectors_are_removed_or_clipped_and_inline_images_go"] notes = "covered paths removed, others clipped; shadings clipped" [[feature]] id = "protect.redact-annots-fields" title = "Remove annotations and fields under redactions" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::comments_links_and_fields_under_a_mark_go", "crates/ui-egui/tests/redact.rs::marking_applying_and_clearing"] notes = "with pop-ups; fields lose all widgets" [[feature]] id = "protect.redact-struct-tree" title = "Remove redacted content from tags and alternate text" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::tags_lose_what_redaction_removed"] notes = "marked content changed by redaction is found by comparing each MCID before and after; its elements lose Alt, ActualText and E, and references to now-empty marked content are dropped; untouched tags stay" [[feature]] id = "protect.redaction-verification" title = "Verify no residue remains after redaction" area = "G" tier = "P0" milestone = "M8" status = "shipped" commands = ["redact.apply"] tools = ["redact_apply"] evidence = ["crates/redact/src/tests.rs::unreadable_content_fails_closed", "crates/engine/src/tests.rs::redaction_marks_apply_for_good_and_undo"] notes = "re-reads redacted pages; residue or unreadable content fails the whole operation" [[feature]] id = "protect.redact-filename-suffix" title = "Add a suffix to redacted file names" area = "G" tier = "P3" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.redact-ai-suggestions" title = "Suggest sensitive content to redact via an AI provider" area = "G" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "local or user-provided model; off by default" [[feature]] id = "protect.remove-hidden-information" title = "Remove hidden information (selectable categories)" area = "G" tier = "P1" milestone = "M8" status = "shipped" commands = ["protect.remove_hidden"] tools = ["doc_hidden_info", "doc_remove_hidden"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/ui-egui/tests/redact.rs::removing_hidden_information_and_sanitizing", "crates/automation/tests/automation.rs::removing_hidden_information_through_tools"] notes = "metadata, attachments, comments, form fields (flattened), hidden text, hidden layers, bookmarks, links/actions/scripts, private data; overlapping objects and cropped content pending" [[feature]] id = "protect.sanitize" title = "Sanitize document (remove all hidden information)" area = "G" tier = "P1" milestone = "M8" status = "shipped" commands = ["redact.sanitize"] tools = ["doc_remove_hidden"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/ui-egui/tests/redact.rs::removing_hidden_information_and_sanitizing", "crates/automation/tests/automation.rs::removing_hidden_information_through_tools"] notes = "every category, then a full rewrite on save" [[feature]] id = "protect.remove-hidden-on-close" title = "Remove hidden information when closing or sending" area = "G" tier = "P3" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.attachment-trust" title = "Block opening risky attachment types" area = "G" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.url-access-control" title = "Control internet access from PDFs" area = "G" tier = "P1" milestone = "M6" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.protected-view" title = "Open untrusted files in a restricted view" area = "G" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "protect.security-envelope" title = "Security envelopes" area = "G" tier = "P3" milestone = "M8" status = "planned" commands = [] tools = [] evidence = [] notes = "legacy" # ================================================================================================== # H. Digital signatures # ================================================================================================== [[feature]] id = "sign.pkcs12" title = "Sign with a PKCS#12 (.p12/.pfx) digital ID" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/sign/tests/crypto.rs::opens_every_openssl_flavour_of_pkcs12", "crates/sign/tests/pdf.rs::signing_then_validating_with_and_without_trust", "crates/ui-egui/tests/signing.rs::certifying_without_a_visible_signature", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "PBES2 (AES, 3DES) and legacy SHA-1 3DES/RC2 files; RSA, P-256, P-384" [[feature]] id = "sign.macos-keychain" title = "Sign with macOS Keychain identities" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_keychain_ids", "sign_document"] evidence = ["crates/sign/tests/pdf.rs::signing_with_keychain_identities", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "Security framework identities (RSA PKCS #1 v1.5, ECDSA P-256/P-384) listed with the digital IDs in Sign with a Digital ID; the key never leaves the Keychain (ExternalKey); keychain: for agents. The test uses a throwaway keychain file (run with --ignored)" [[feature]] id = "sign.windows-cert-store" title = "Sign with the Windows certificate store" area = "H" tier = "P0" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.pkcs11" title = "Sign with PKCS#11 tokens and smart cards" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.self-signed-id" title = "Create a self-signed digital ID" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_id_create"] evidence = ["crates/sign/tests/crypto.rs::new_digital_ids_are_self_signed_and_survive_a_p12_round_trip", "crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "RSA 2048/3072/4096 or P-256, saved as a password-protected .p12" [[feature]] id = "sign.export-certificate" title = "Export a public certificate" area = "H" tier = "P2" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = [] evidence = ["crates/sign/tests/crypto.rs::certificates_load_from_pem_and_der_and_export_as_pem"] notes = "Signatures panel ▸ Export certificate (.cer, PEM)" [[feature]] id = "sign.visible-signature" title = "Visible signature by drawing a rectangle" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "drag a rectangle; Acrobat's name-and-details appearance" [[feature]] id = "sign.sign-existing-field" title = "Sign an existing signature field" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/sign/tests/pdf.rs::signing_an_existing_field_and_counter_signing", "crates/ui-egui/tests/signing.rs::clicking_an_empty_signature_field_signs_it"] notes = "" [[feature]] id = "sign.invisible-signature" title = "Invisible signature" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.certify_invisible"] tools = ["sign_document"] evidence = ["crates/sign/tests/pdf.rs::invisible_signatures_and_refusals", "crates/ui-egui/tests/signing.rs::certifying_without_a_visible_signature"] notes = "" [[feature]] id = "sign.signature-appearance" title = "Configure signature appearance (text, graphic, name)" area = "H" tier = "P1" milestone = "M9" status = "partial" commands = ["sign.digital"] tools = [] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "text items (name, date, reason, location, DN, labels); no graphics or saved appearances yet" [[feature]] id = "sign.reason-location" title = "Reason, location and contact info" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/sign/tests/pdf.rs::signing_then_validating_with_and_without_trust", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "" [[feature]] id = "sign.lock-after-signing" title = "Lock document or fields after signing" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.pkcs7-detached" title = "PKCS#7 detached signatures" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.validate"] tools = ["sign_list"] evidence = ["crates/sign/tests/pdf.rs::validates_a_signature_made_by_openssl"] notes = "validated; new signatures use CAdES" [[feature]] id = "sign.cades-pades-bb" title = "CAdES / PAdES B-B signatures" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/sign/tests/crypto.rs::signatures_round_trip_for_every_key_type", "crates/sign/tests/pdf.rs::signing_then_validating_with_and_without_trust"] notes = "ETSI.CAdES.detached with signing-certificate-v2; pdfsig reports them valid" [[feature]] id = "sign.hash-algorithms" title = "SHA-256/384/512 hashes; no SHA-1 for new signatures" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.digital"] tools = ["sign_document"] evidence = ["crates/sign/tests/crypto.rs::signatures_round_trip_for_every_key_type"] notes = "SHA-256, SHA-384 for P-384; SHA-1 refused for new signatures, validated in old ones" [[feature]] id = "sign.certify" title = "Certify a document (DocMDP)" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.certify", "sign.certify_invisible"] tools = ["sign_document"] evidence = ["crates/sign/tests/pdf.rs::later_changes_are_classified_under_the_signature_permissions", "crates/ui-egui/tests/signing.rs::certifying_without_a_visible_signature"] notes = "" [[feature]] id = "sign.certify-permissions" title = "Allowed changes after certifying" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.certify"] tools = ["sign_document"] evidence = ["crates/sign/tests/pdf.rs::later_changes_are_classified_under_the_signature_permissions"] notes = "DocMDP P=1/2/3 enforced when validating" [[feature]] id = "sign.field-mdp" title = "Field locks (FieldMDP)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.document-timestamp" title = "Add a document timestamp (RFC 3161)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.timestamp-servers" title = "Configure timestamp servers" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.pades-bt" title = "PAdES B-T (signature timestamp)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.ltv" title = "Long-term validation (DSS/VRI)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.pades-blta" title = "PAdES B-LT and B-LTA" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.ocsp-crl" title = "Revocation checking (OCSP and CRL)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.validate-all" title = "Validate all signatures" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.validate"] tools = ["sign_list"] evidence = ["crates/sign/tests/pdf.rs::signing_then_validating_with_and_without_trust", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "" [[feature]] id = "sign.signatures-panel" title = "Signatures panel with per-revision tree" area = "H" tier = "P0" milestone = "M9" status = "partial" commands = ["sign.panel"] tools = ["sign_list"] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "per-signature tree with details and actions; no per-revision page outline yet" [[feature]] id = "sign.status-icons" title = "Signature status (valid, unknown, invalid)" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = ["sign_list"] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "" [[feature]] id = "sign.validation-banner" title = "Signed/certified document message bar" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = [] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/ui-egui/tests/signing.rs::certifying_without_a_visible_signature"] notes = "signed/valid, problems, invalid and certified bars" [[feature]] id = "sign.signature-properties" title = "Signature properties (validity summary, signer, time)" area = "H" tier = "P0" milestone = "M9" status = "partial" commands = ["sign.panel"] tools = ["sign_list"] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "validity summary, signer, issuer, time, algorithm in the panel; no separate properties dialog" [[feature]] id = "sign.certificate-viewer" title = "Certificate viewer" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = ["sign_list"] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "Signatures panel ▸ Show certificate: the chain (root on top) and Summary, Details (serial, key, constraints, usage, SHA-1/SHA-256 digests) and Trust tabs; add to trusted certificates; export" [[feature]] id = "sign.trust-store" title = "Trusted certificates store" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = ["sign_trust"] evidence = ["crates/sign/tests/pdf.rs::signing_then_validating_with_and_without_trust", "crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "trusted certificates persist with the app's settings" [[feature]] id = "sign.trust-import" title = "Import trusted certificates and set trust" area = "H" tier = "P1" milestone = "M9" status = "partial" commands = [] tools = ["sign_trust"] evidence = ["crates/automation/tests/automation.rs::digital_ids_signing_and_validation_through_tools"] notes = "import .cer/.pem/.der/.p12 through the tool; per-certificate trust settings not yet" [[feature]] id = "sign.eutl" title = "EU Trusted Lists" area = "H" tier = "P2" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.os-trust" title = "Trust the operating system's root certificates" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.verification-time" title = "Verification time (signing time, timestamp, now)" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.changes-after-signing" title = "List changes made after signing (MDP-aware diff)" area = "H" tier = "P0" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = ["sign_list"] evidence = ["crates/sign/tests/pdf.rs::later_changes_are_classified_under_the_signature_permissions", "crates/sign/tests/pdf.rs::signing_an_existing_field_and_counter_signing", "crates/engine/src/tests.rs::signing_saving_trusting_and_commenting_afterwards"] notes = "revision diff classified as signing, form fill, comments, metadata, page content or structure" [[feature]] id = "sign.view-signed-version" title = "View the signed version" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = ["sign.panel"] tools = [] evidence = ["crates/ui-egui/tests/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting"] notes = "" [[feature]] id = "sign.compare-signed-version" title = "Compare signed version with the current one" area = "H" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.verify-on-open" title = "Verify signatures when a document opens" area = "H" tier = "P1" milestone = "M9" status = "shipped" commands = [] tools = ["sign_list"] evidence = ["crates/engine/src/tests.rs::signing_saving_trusting_and_commenting_afterwards"] notes = "validated when opened and after every edit" [[feature]] id = "sign.clear-signature" title = "Clear an unsaved signature; clear all signature fields" area = "H" tier = "P2" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.seed-values" title = "Signature seed values" area = "H" tier = "P2" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.preview-mode" title = "Preview document mode before signing" area = "H" tier = "P2" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.qualified-labels" title = "Show qualified signature/seal labels" area = "H" tier = "P2" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.web-signing" title = "Sign in the browser with a PKCS#12 file" area = "H" tier = "P1" milestone = "M9" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "sign.aatl" title = "Adobe Approved Trust List" area = "H" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe-hosted list; use OS trust stores and EU Trusted Lists" [[feature]] id = "sign.request-esignatures" title = "Request e-signatures (Acrobat Sign)" area = "H" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; pluggable provider hook only" [[feature]] id = "sign.cloud-signatures" title = "Cloud signature (CSC) digital IDs via Adobe" area = "H" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; a pluggable remote-signing KeyProvider may follow" # ================================================================================================== # I. Scan and OCR # ================================================================================================== [[feature]] id = "ocr.recognize-text" title = "Recognize text (OCR) in this file" area = "I" tier = "P0" milestone = "M10" status = "shipped" commands = ["ocr.recognize"] tools = ["ocr_recognize", "ocr_status"] evidence = ["crates/engine/src/tests.rs::recognize_text_makes_a_scanned_page_searchable", "crates/automation/tests/automation.rs::ocr_tools_make_a_scan_searchable", "crates/ui-egui/tests/ocr.rs::recognize_text_dialog_adds_searchable_text"] notes = "ocrs engine (MIT/Apache) with CC-BY-SA models fetched by `cargo xtask models`; runs on a worker thread with progress; one undoable step; pages with text are skipped." [[feature]] id = "ocr.recognize-range" title = "Recognize text in the current page or a range" area = "I" tier = "P0" milestone = "M10" status = "shipped" commands = ["ocr.recognize"] tools = ["ocr_recognize"] evidence = ["crates/automation/tests/automation.rs::ocr_tools_make_a_scan_searchable", "crates/ui-egui/tests/ocr.rs::recognize_text_dialog_adds_searchable_text"] notes = "All pages, current page or a range." [[feature]] id = "ocr.recognize-multiple" title = "Recognize text in multiple files" area = "I" tier = "P1" milestone = "M10" status = "shipped" commands = ["ocr.recognize_batch"] tools = ["ocr_recognize_files"] evidence = ["crates/automation/tests/automation.rs::ocr_recognize_files_writes_searchable_copies", "crates/ui-egui/tests/ocr.rs::recognize_text_in_multiple_files_writes_searchable_copies"] notes = "Pick PDFs, then an output folder; copies are saved incrementally under the same names, in the background with progress." [[feature]] id = "ocr.ocr-languages" title = "OCR document language selection" area = "I" tier = "P0" milestone = "M10" status = "partial" commands = ["ocr.recognize"] tools = ["ocr_recognize"] evidence = ["crates/ui-egui/tests/ocr.rs::recognize_text_dialog_adds_searchable_text"] notes = "Language choice exists, but the models read only the Latin alphabet without accents (English)." [[feature]] id = "ocr.searchable-image" title = "Searchable image output (invisible text layer)" area = "I" tier = "P0" milestone = "M10" status = "partial" commands = ["ocr.recognize"] tools = ["ocr_recognize"] evidence = ["crates/engine/src/tests.rs::recognize_text_makes_a_scanned_page_searchable"] notes = "Invisible text (Tr 3) fitted to each word box; the image is not deskewed or downsampled (exact mode only)." [[feature]] id = "ocr.searchable-image-exact" title = "Searchable image (exact): leave the image untouched" area = "I" tier = "P1" milestone = "M10" status = "shipped" commands = ["ocr.recognize"] tools = ["ocr_recognize"] evidence = ["crates/engine/src/tests.rs::recognize_text_makes_a_scanned_page_searchable"] notes = "The image is left untouched." [[feature]] id = "ocr.editable-text-output" title = "Editable text and images output" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.ocr-downsample" title = "Downsample images during OCR" area = "I" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.skip-renderable-text" title = "Skip pages that already have text" area = "I" tier = "P1" milestone = "M10" status = "shipped" commands = ["ocr.recognize"] tools = ["ocr_recognize"] evidence = ["crates/engine/src/tests.rs::recognize_text_makes_a_scanned_page_searchable", "crates/automation/tests/automation.rs::ocr_tools_make_a_scan_searchable"] notes = "Pages that already have text are skipped and reported (skip_text_pages false reads them anyway)." [[feature]] id = "ocr.rotation-detection" title = "Detect and fix page rotation" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.deskew" title = "Deskew" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.despeckle" title = "Despeckle" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.background-removal" title = "Background removal" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.descreen" title = "Descreen" area = "I" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.remove-halo" title = "Remove halos" area = "I" tier = "P3" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.edge-shadow-removal" title = "Edge shadow removal" area = "I" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.camera-perspective" title = "Enhance camera images (edges, perspective, contrast)" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.camera-document-type" title = "Camera image document types (whiteboard, card, form)" area = "I" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.correct-recognized-text" title = "Correct recognized text (low-confidence suspects)" area = "I" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.adaptive-compression" title = "Adaptive (MRC) compression of scans" area = "I" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.scan-pdfa" title = "Make scans PDF/A compliant" area = "I" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.ocr-engines" title = "Pluggable OCR engines (ocrs default; tesseract optional)" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.ocr-web" title = "OCR in the browser" area = "I" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.scanner-acquire" title = "Scan from TWAIN/WIA/ICA/SANE scanners" area = "I" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.scan-presets" title = "Scan presets" area = "I" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.scan-append" title = "Append scans to an existing PDF or split into files" area = "I" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "ocr.adobe-scan-sync" title = "Adobe Scan mobile capture sync" area = "I" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; import images from any source instead" # ================================================================================================== # J. Create and export # ================================================================================================== [[feature]] id = "create.from-images" title = "Create PDF from images (JPEG, PNG, TIFF, GIF, BMP, JPEG 2000)" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["create.images"] tools = ["doc_create"] evidence = ["crates/create/src/tests.rs::jpeg_2000_images_are_embedded_as_is", "crates/create/src/tests.rs::images_export_as_jpeg_unchanged_and_others_as_png"] notes = "PNG, JPEG, TIFF (multi-page), GIF (first frame), BMP, and JPEG 2000 (JP2 or codestream, embedded as JPXDecode with its capture resolution)" [[feature]] id = "create.from-multipage-tiff" title = "Multi-page TIFF to multi-page PDF" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["create.images", "create.file"] tools = ["doc_create"] evidence = ["crates/create/src/tests.rs::bmp_gif_and_multi_page_tiff_images"] notes = "every page; 1-bit scans stay 1-bit; resolution from the TIFF" [[feature]] id = "create.from-text" title = "Create PDF from plain text" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["create.file"] tools = ["doc_create"] evidence = ["crates/create/src/tests.rs::text_is_wrapped_and_paginated", "crates/automation/tests/automation.rs::creating_and_reducing_through_tools"] notes = "Helvetica 11 pt on US Letter; form feeds start pages" [[feature]] id = "create.from-markdown" title = "Create PDF from Markdown" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.from-clipboard" title = "Create PDF from the clipboard" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["create.clipboard"] tools = [] evidence = ["crates/ui-egui/tests/create.rs::clipboard_images_and_text_become_new_pdfs"] notes = "an image (one page at its size) or text; headless tools read files instead" [[feature]] id = "create.from-screenshot" title = "Create PDF from a screen capture" area = "J" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.blank" title = "Create a blank PDF" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["create.blank"] tools = ["doc_create"] evidence = ["crates/ui-egui/tests/create.rs::opening_images_and_text_converts_them_to_new_pdfs", "crates/create/src/tests.rs::blank_documents", "crates/automation/tests/automation.rs::creating_and_reducing_through_tools"] notes = "" [[feature]] id = "create.from-html" title = "Create PDF from an HTML file" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.from-web-page" title = "Create PDF from a web page URL" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.from-office" title = "Create PDF from Office documents (LibreOffice sidecar)" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.create-multiple" title = "Convert many files to PDF in one run" area = "J" tier = "P1" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.image-conversion-options" title = "Image compression options when converting" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.pdf-printer" title = "Print to PDF from other applications" area = "J" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.distiller" title = "PostScript/EPS to PDF (Distiller)" area = "J" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "deferred: a PostScript interpreter is a large project" [[feature]] id = "create.job-options" title = "PDF settings presets (job options)" area = "J" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-docx" title = "Export to Word (.docx)" area = "J" tier = "P1" milestone = "M10" status = "partial" commands = ["export.docx"] tools = ["doc_export_office"] evidence = ["crates/export/src/lib.rs::docx_is_a_word_package", "crates/engine/src/tests.rs::exporting_office_files_keeps_images", "crates/automation/tests/automation.rs::exporting_to_word_html_and_rtf", "crates/ui-egui/tests/compare.rs::export_to_word_html_and_rtf"] notes = "Flowing Word document: paragraphs, Heading 1/2 from larger text, bold/italic, images inline, page breaks; checked with macOS textutil. Not yet: tables, columns, fonts and colours, exact layout mode." [[feature]] id = "create.export-rtf" title = "Export to RTF" area = "J" tier = "P1" milestone = "M10" status = "shipped" commands = ["export.rtf"] tools = ["doc_export_office"] evidence = ["crates/export/src/lib.rs::rtf_escapes_and_sizes", "crates/automation/tests/automation.rs::exporting_to_word_html_and_rtf", "crates/ui-egui/tests/compare.rs::export_to_word_html_and_rtf"] notes = "Paragraphs with sizes, bold, italic, Unicode; page breaks. Images are left out." [[feature]] id = "create.export-xlsx" title = "Export to Excel (.xlsx) with table detection" area = "J" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-pptx" title = "Export to PowerPoint (.pptx)" area = "J" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-png" title = "Export pages as PNG" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["export.image"] tools = ["doc_export_images", "page_render"] evidence = ["crates/ui-egui/tests/export.rs::export_dialogs_write_images_and_text", "crates/engine/src/tests.rs::export_images_and_text_follow_the_working_file", "crates/automation/tests/automation.rs::exporting_images_and_text_through_tools"] notes = "PNG at 72–600 dpi, page ranges; includes unsaved edits; background thread with progress" [[feature]] id = "create.export-jpeg-tiff" title = "Export pages as JPEG or TIFF" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["export.image"] tools = ["doc_export_images"] evidence = ["crates/engine/src/tests.rs::pages_export_as_png_jpeg_and_tiff", "crates/automation/tests/automation.rs::exporting_images_and_text_through_tools"] notes = "JPEG with quality, TIFF; flattened onto white" [[feature]] id = "create.export-jpeg2000" title = "Export pages as JPEG 2000" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-all-images" title = "Export all embedded images" area = "J" tier = "P1" milestone = "M10" status = "shipped" commands = ["export.all_images"] tools = ["doc_export_all_images"] evidence = ["crates/create/src/tests.rs::images_export_as_jpeg_unchanged_and_others_as_png", "crates/create/src/tests.rs::indexed_and_one_bit_images_decode", "crates/automation/tests/automation.rs::exporting_all_images_through_tools", "crates/ui-egui/tests/export.rs::export_dialogs_write_images_and_text"] notes = "each image once (page resources and nested forms); JPEG unchanged, others PNG (gray/RGB/CMYK/ICC/Indexed, 1–16 bpc, stencil masks, soft mask as alpha); JPX/JBIG2/CCITT/separations reported as skipped; minimum size filter" [[feature]] id = "create.export-html" title = "Export to HTML" area = "J" tier = "P1" milestone = "M10" status = "partial" commands = ["export.html"] tools = ["doc_export_office"] evidence = ["crates/export/src/lib.rs::html_has_headings_paragraphs_and_images_in_order", "crates/automation/tests/automation.rs::exporting_to_word_html_and_rtf", "crates/ui-egui/tests/compare.rs::export_to_word_html_and_rtf"] notes = "Single HTML file with headings, paragraphs and inline images. Not yet: multi-page folder output, tables, CSS from fonts." [[feature]] id = "create.export-text" title = "Export to plain text" area = "J" tier = "P0" milestone = "M10" status = "shipped" commands = ["export.text"] tools = ["doc_export_text", "text_extract"] evidence = ["crates/ui-egui/tests/export.rs::export_dialogs_write_images_and_text", "crates/automation/tests/automation.rs::exporting_images_and_text_through_tools"] notes = "plain reading-order text; accessible text (tags) comes with M12" [[feature]] id = "create.export-accessible-text" title = "Export accessible text (from tags)" area = "J" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-xml" title = "Export to XML" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-svg" title = "Export to SVG" area = "J" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-ps" title = "Export to PostScript" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-eps" title = "Export to EPS" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-ocr" title = "Run OCR automatically when exporting scans" area = "J" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.export-settings" title = "Per-format export settings" area = "J" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "create.text-extraction" title = "Extract text in reading order (columns, RTL, CJK)" area = "J" tier = "P0" milestone = "M2" status = "shipped" commands = [] tools = ["text_extract"] evidence = ["crates/render/src/text.rs::rtl_runs_come_out_in_logical_order_and_cjk_has_no_spaces", "crates/render/src/text.rs::lines_words_and_search", "crates/automation/tests/automation.rs::parallel_text_extraction_keeps_page_order_and_follows_edits"] notes = "" [[feature]] id = "create.translate" title = "Translate documents" area = "J" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "through an optional AiProvider; never Adobe's cloud" [[feature]] id = "create.cloud-office-conversion" title = "Cloud conversion from the macOS Office add-in" area = "J" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; LibreOffice sidecar instead" # ================================================================================================== # K. Optimize and standards # ================================================================================================== [[feature]] id = "optimize.reduce-file-size" title = "Reduce file size (one click)" area = "K" tier = "P0" milestone = "M11" status = "shipped" commands = ["optimize.reduce"] tools = ["doc_reduce"] evidence = ["crates/ui-egui/tests/create.rs::reduce_file_size_writes_a_compact_copy", "crates/engine/src/tests.rs::create_and_reduce", "crates/automation/tests/automation.rs::creating_and_reducing_through_tools", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "images above 225 ppi to 150 ppi JPEG medium, thumbnails dropped, resources merged, object streams" [[feature]] id = "optimize.compatibility-level" title = "Make compatible with a chosen PDF version" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.optimizer" title = "Advanced optimization (PDF Optimizer)" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/ui-egui/tests/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "Images, Discard Objects, Discard User Data, Clean Up; no Fonts or Transparency panels, no space audit" [[feature]] id = "optimize.downsample-images" title = "Downsample colour, grey and mono images" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::images_are_measured_where_drawn_and_downsampled", "crates/optimize/tests/optimize.rs::settings_choose_what_happens", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "colour and grayscale, bicubic, effective resolution measured where drawn; monochrome not yet" [[feature]] id = "optimize.recompress-images" title = "Recompress images (JPEG, JPEG 2000, Flate)" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::images_are_measured_where_drawn_and_downsampled", "crates/optimize/tests/optimize.rs::settings_choose_what_happens"] notes = "JPEG (quality steps) and ZIP; no JPEG 2000" [[feature]] id = "optimize.mono-compression" title = "Monochrome compression (JBIG2, CCITT G4)" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.only-if-smaller" title = "Optimize images only if smaller" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::images_are_measured_where_drawn_and_downsampled"] notes = "always on" [[feature]] id = "optimize.unembed-fonts" title = "Unembed fonts" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.flatten-transparency" title = "Flatten transparency" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.discard-javascript" title = "Discard JavaScript actions" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "with links and actions (Remove Hidden Information)" [[feature]] id = "optimize.discard-thumbnails" title = "Discard embedded thumbnails" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::images_are_measured_where_drawn_and_downsampled"] notes = "" [[feature]] id = "optimize.discard-tags" title = "Discard document tags" area = "K" tier = "P2" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::discards_and_clean_up", "crates/ui-egui/tests/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy"] notes = "" [[feature]] id = "optimize.discard-bookmarks" title = "Discard bookmarks" area = "K" tier = "P2" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "" [[feature]] id = "optimize.discard-search-index" title = "Discard embedded search index" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.discard-print-settings" title = "Discard embedded print settings" area = "K" tier = "P2" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::discards_and_clean_up"] notes = "" [[feature]] id = "optimize.discard-alternate-images" title = "Discard alternate images" area = "K" tier = "P2" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::images_are_measured_where_drawn_and_downsampled"] notes = "" [[feature]] id = "optimize.discard-form-actions" title = "Discard form submit, import and reset actions" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.flatten-form-fields" title = "Flatten form fields while optimizing" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "" [[feature]] id = "optimize.discard-comments" title = "Discard comments, forms and multimedia" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "" [[feature]] id = "optimize.discard-metadata" title = "Discard document information and metadata" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/automation/tests/automation.rs::optimizing_through_tools", "crates/ui-egui/tests/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy"] notes = "" [[feature]] id = "optimize.discard-attachments" title = "Discard file attachments" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "" [[feature]] id = "optimize.discard-private-data" title = "Discard private application data (PieceInfo)" area = "K" tier = "P2" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "" [[feature]] id = "optimize.discard-external-refs" title = "Discard external cross-references" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.discard-hidden-layers" title = "Discard hidden layers and flatten visible ones" area = "K" tier = "P2" milestone = "M11" status = "partial" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/redact/src/tests.rs::hidden_information_is_counted_and_removed", "crates/automation/tests/automation.rs::optimizing_through_tools"] notes = "hidden layer content removed; visible layers not flattened" [[feature]] id = "optimize.merge-image-fragments" title = "Detect and merge image fragments" area = "K" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.lines-to-curves" title = "Convert smooth lines to curves" area = "K" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.compress-structure" title = "Compress document structure (object streams)" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["file.save_as"] tools = ["doc_save"] evidence = ["crates/cos/tests/writer.rs::full_save_packs_objects_into_object_streams"] notes = "on by default for full saves; no Optimizer option yet" [[feature]] id = "optimize.flate-unencoded" title = "Flate-encode unencoded streams; replace LZW with Flate" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::discards_and_clean_up"] notes = "unencoded streams; LZW not yet re-encoded" [[feature]] id = "optimize.remove-invalid-links" title = "Remove invalid links, bookmarks and unreferenced destinations" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_optimize"] evidence = ["crates/optimize/tests/optimize.rs::invalid_links_and_unreferenced_destinations_go"] notes = "Clean Up: links to missing pages or names are removed; bookmarks keep their place (and children) but lose a broken destination; named destinations nothing refers to (links, bookmarks, actions anywhere) are removed from the name tree and the old /Dests; counts reported" [[feature]] id = "optimize.optimize-content" title = "Optimize page content streams" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.audit-space" title = "Audit space usage" area = "K" tier = "P1" milestone = "M11" status = "shipped" commands = ["optimize.advanced"] tools = ["doc_audit_space"] evidence = ["crates/optimize/tests/optimize.rs::space_audit_shares_the_file_out_by_kind", "crates/automation/tests/automation.rs::auditing_space_through_tools", "crates/ui-egui/tests/viewer.rs::optimizer_audits_space_usage"] notes = "PDF Optimizer ▸ Audit space usage: 16 categories (images, content streams, fonts, X Object forms, structure, bookmarks, thumbnails, comments, forms, named destinations, colour spaces, shadings, patterns, graphics states, embedded files, overhead) with bytes and percentages" [[feature]] id = "optimize.optimizer-presets" title = "Optimizer presets" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.batch-optimize" title = "Optimize multiple files" area = "K" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight" title = "Preflight analysis" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-fix" title = "Preflight analyze and fix" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-profiles" title = "Built-in preflight profiles" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-single-checks" title = "Single checks" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-single-fixups" title = "Single fixups" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-custom-profiles" title = "Create and edit custom profiles" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-profile-exchange" title = "Import, export and lock profiles" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-results" title = "Preflight results tree with object details" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-snap-view" title = "Snap view of a flagged object" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-reports" title = "Preflight reports (PDF, XML, text)" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-droplets" title = "Preflight droplets and batch preflight" area = "K" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.preflight-audit-trail" title = "Embed preflight audit trail" area = "K" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfa-validate" title = "Verify PDF/A compliance (1-4)" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["standards.pdfa"] tools = ["pdfa_verify"] evidence = ["crates/preflight/src/tests.rs::verify_reports_what_breaks_pdfa", "crates/preflight/src/tests.rs::convert_fixes_all_but_fonts", "crates/automation/tests/automation.rs::pdfa_through_tools", "crates/ui-egui/tests/compare.rs::pdfa_dialog_verifies_and_converts"] notes = "PDF/A-2b/3b structural rules: identification, encryption, output intent, fonts embedded, annotations, actions, images, embedded files. Not yet: content-stream operator checks, transparency details, PDF/A-1 and -4, a veraPDF comparison." [[feature]] id = "optimize.pdfa-convert" title = "Save as PDF/A (1b, 2b, 3b, 4)" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["standards.pdfa"] tools = ["pdfa_convert"] evidence = ["crates/preflight/src/tests.rs::convert_fixes_all_but_fonts", "crates/automation/tests/automation.rs::pdfa_through_tools", "crates/ui-egui/tests/compare.rs::pdfa_dialog_verifies_and_converts"] notes = "Fixes XMP, output intent (generated sRGB ICC profile), forbidden actions, annotation flags, interpolation, encryption, AFRelationship. Not yet: embedding fonts, converting device CMYK, flattening transparency for PDF/A-1." [[feature]] id = "optimize.pdfa-accessible-levels" title = "PDF/A conformance levels a and u" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfx-validate" title = "Verify PDF/X compliance" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfx-convert" title = "Save as PDF/X (1a, 3, 4)" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.output-intents" title = "Choose output intents and conditions" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["standards.pdfa"] tools = ["pdfa_convert", "pdfa_verify"] evidence = ["crates/preflight/src/tests.rs::convert_fixes_all_but_fonts", "crates/automation/tests/automation.rs::pdfa_through_tools", "crates/ui-egui/tests/compare.rs::pdfa_dialog_verifies_and_converts"] notes = "sRGB output intent added and listed; no choice of other conditions yet." [[feature]] id = "optimize.pdfe" title = "PDF/E" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfvt" title = "PDF/VT" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfua-validate" title = "Verify PDF/UA-1 and PDF/UA-2" area = "K" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.standards-panel" title = "Standards panel showing declared conformance" area = "K" tier = "P1" milestone = "M11" status = "partial" commands = ["standards.pdfa"] tools = ["pdfa_verify"] evidence = ["crates/automation/tests/automation.rs::pdfa_through_tools", "crates/ui-egui/tests/compare.rs::pdfa_dialog_verifies_and_converts"] notes = "Declared PDF/A, PDF/UA and output intents shown in the PDF/A dialog and returned by pdfa_verify." [[feature]] id = "optimize.remove-standards-id" title = "Remove PDF/A or PDF/X identification" area = "K" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.pdfx5-reference-xobjects" title = "Show PDF/X-5 reference XObjects" area = "K" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "optimize.einvoice-pdfa3" title = "Embed e-invoice XML in PDF/A-3" area = "K" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" # ================================================================================================== # L. Print and print production # ================================================================================================== [[feature]] id = "print.print-dialog" title = "Print dialog" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print", "printers"] evidence = ["crates/ui-egui/tests/print.rs::print_dialog_lays_out_sheets_and_saves_a_pdf", "crates/engine/src/tests.rs::printing_lays_out_sheets_that_render"] notes = "⌘P; settings and live sheet preview" [[feature]] id = "print.printer-selection" title = "Choose printer and properties" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["printers", "doc_print"] evidence = ["crates/print/src/tests.rs::spooler_arguments_and_printer_list"] notes = "CUPS printers via lpstat; Save as PDF; Windows spooler pending" [[feature]] id = "print.copies-collate" title = "Copies and collation" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::spooler_arguments_and_printer_list"] notes = "lp -n, collate option" [[feature]] id = "print.page-range" title = "Print all, current page or a range (labels allowed)" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::page_selection", "crates/automation/tests/automation.rs::printing_through_tools"] notes = "all, current, ranges with labels and open ends" [[feature]] id = "print.odd-even-reverse" title = "Odd/even pages and reverse order" area = "L" tier = "P1" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::page_selection"] notes = "" [[feature]] id = "print.scaling" title = "Fit, actual size, shrink oversized, custom scale" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::size_modes"] notes = "fit, actual size, shrink oversized, custom %" [[feature]] id = "print.paper-source-by-size" title = "Choose paper source by PDF page size" area = "L" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.duplex" title = "Print on both sides" area = "L" tier = "P1" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::spooler_arguments_and_printer_list"] notes = "long/short edge via the spooler" [[feature]] id = "print.n-up" title = "Multiple pages per sheet" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::multiple_pages_per_sheet", "crates/automation/tests/automation.rs::printing_through_tools"] notes = "2/4/6/9/16, four orders, borders, auto-rotate" [[feature]] id = "print.booklet" title = "Booklet printing" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::booklets_pair_pages_for_folding"] notes = "both/front/back, left/right binding" [[feature]] id = "print.poster" title = "Poster / tiled printing with overlap and cut marks" area = "L" tier = "P1" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::posters_tile_with_overlap", "crates/automation/tests/automation.rs::printing_through_tools"] notes = "tile scale, overlap, cut marks (labels pending)" [[feature]] id = "print.orientation" title = "Auto portrait/landscape" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::size_modes"] notes = "auto portrait/landscape" [[feature]] id = "print.comments-and-forms" title = "Print document, markups, stamps or form fields only" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::imposed_pdf_has_the_sheets_and_honours_comments_and_forms"] notes = "Print flag honoured" [[feature]] id = "print.print-with-comment-summary" title = "Print with a comments summary" area = "L" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.print-preview" title = "Print preview" area = "L" tier = "P0" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = [] evidence = ["crates/ui-egui/tests/print.rs::print_dialog_lays_out_sheets_and_saves_a_pdf"] notes = "live sheet preview with sheet navigation" [[feature]] id = "print.grayscale" title = "Print in grayscale" area = "L" tier = "P1" milestone = "M10" status = "partial" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/print/src/tests.rs::spooler_arguments_and_printer_list"] notes = "asks the printer for monochrome; the PDF itself stays in colour" [[feature]] id = "print.print-as-image" title = "Print as image" area = "L" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.page-setup" title = "Page setup" area = "L" tier = "P1" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.print-ready-pdf" title = "Produce a print-ready imposed PDF" area = "L" tier = "P1" milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] evidence = ["crates/ui-egui/tests/print.rs::print_dialog_lays_out_sheets_and_saves_a_pdf", "crates/automation/tests/automation.rs::printing_through_tools", "crates/engine/src/tests.rs::printing_lays_out_sheets_that_render"] notes = "Save as PDF from the dialog" [[feature]] id = "print.print-pages-from-thumbnails" title = "Print selected pages from thumbnails" area = "L" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.postscript-output" title = "PostScript Level 3 output" area = "L" tier = "P2" milestone = "M10" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.output-preview" title = "Output preview" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.separations" title = "Separations preview with area coverage" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.total-area-coverage" title = "Total area coverage warning" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.color-warnings" title = "Overprint and rich-black warnings" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.object-inspector" title = "Object inspector" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.simulate-paper-ink" title = "Simulate paper colour and black ink" area = "L" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.overprint-preview" title = "Overprint preview" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.convert-colors" title = "Convert colours" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.ink-manager" title = "Ink manager" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.ink-aliases" title = "Ink aliases and spot-to-process" area = "L" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.printer-marks" title = "Add printer marks (crop, bleed, registration, colour bars)" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.fix-hairlines" title = "Fix hairlines" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.flattener-preview" title = "Flattener preview" area = "L" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.color-management" title = "Colour management settings (working spaces, intents)" area = "L" tier = "P1" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.advanced-print-separations" title = "Print separations and in-RIP separations" area = "L" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.print-marks-bleeds" title = "Marks and bleeds when printing" area = "L" tier = "P2" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.trap-presets" title = "Trap presets (stored as data)" area = "L" tier = "P3" milestone = "M11" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "print.jdf" title = "JDF job definitions (read-only)" area = "L" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" # ================================================================================================== # M. Accessibility # ================================================================================================== [[feature]] id = "a11y.app-screen-reader" title = "Screen-reader support for the app (AccessKit)" area = "M" tier = "P0" milestone = "M3" status = "partial" commands = [] tools = [] evidence = ["crates/ui-egui/tests/control.rs::inspect_and_click_by_label_and_id"] notes = "AccessKit labels on all custom widgets; full audit in M14.3" [[feature]] id = "a11y.keyboard-only" title = "Full keyboard operation of the app" area = "M" tier = "P0" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.checker" title = "Accessibility checker (full check)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::an_untagged_document_fails_the_document_rules", "crates/a11y/src/tests.rs::a_well_tagged_document_passes", "crates/ui-egui/tests/accessibility.rs::checking_fixing_skipping_and_reporting", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "full check: options dialog (report, page range, 32 rules by category, 31 on by default), results panel by category with Passed / Failed / Needs manual check / Skipped and findings that go to their page" [[feature]] id = "a11y.checker-report" title = "Accessibility report" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.report"] tools = ["accessibility_report"] evidence = ["crates/a11y/src/tests.rs::rules_have_ids_and_the_report_lists_them", "crates/ui-egui/tests/accessibility.rs::checking_fixing_skipping_and_reporting", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "HTML report: summary counts and a table per category with descriptions and findings" [[feature]] id = "a11y.checker-fix" title = "Fix, skip, explain and re-check rules" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_fix"] evidence = ["crates/ui-egui/tests/accessibility.rs::checking_fixing_skipping_and_reporting", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "right-click a rule: Fix (language via Document Properties, title, tab order), Skip Rule (kept on Check Again), Explain, Check Again, Show Report, Options" [[feature]] id = "a11y.rule-permission-flag" title = "Rule: accessibility permission flag" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::an_untagged_document_fails_the_document_rules"] notes = "rule permission-flag: the file's /P bit 10 whichever password opened it" [[feature]] id = "a11y.rule-image-only" title = "Rule: image-only PDF" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::scans_identity_fonts_and_long_documents"] notes = "rule image-only: images and no text on the checked pages" [[feature]] id = "a11y.rule-tagged-pdf" title = "Rule: tagged PDF" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::an_untagged_document_fails_the_document_rules"] notes = "rule tagged-pdf: StructTreeRoot and MarkInfo Marked true" [[feature]] id = "a11y.rule-logical-order" title = "Rule: logical reading order (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule logical-reading-order: needs manual check" [[feature]] id = "a11y.rule-primary-language" title = "Rule: primary language" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "rule primary-language: catalog /Lang; fix via Document Properties or accessibility_fix" [[feature]] id = "a11y.rule-title" title = "Rule: title shown in the window" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "rule title: Info Title and DisplayDocTitle; Fix sets both" [[feature]] id = "a11y.rule-bookmarks" title = "Rule: bookmarks in long documents" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::scans_identity_fonts_and_long_documents"] notes = "rule bookmarks: more than 20 pages need bookmarks" [[feature]] id = "a11y.rule-color-contrast" title = "Rule: colour contrast (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "rule color-contrast: needs manual check; off by default as in Acrobat" [[feature]] id = "a11y.rule-tagged-content" title = "Rule: all content tagged or artifact" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::page_content_and_annotation_problems_are_found"] notes = "rule tagged-content: painting outside MCID or Artifact marked content, through form XObjects; counted per page" [[feature]] id = "a11y.rule-tagged-annotations" title = "Rule: tagged annotations" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::page_content_and_annotation_problems_are_found"] notes = "rule tagged-annotations: annotations other than popups, widgets and multimedia need /StructParent" [[feature]] id = "a11y.rule-tab-order" title = "Rule: tab order follows structure" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::page_content_and_annotation_problems_are_found"] notes = "rule tab-order: pages with annotations need /Tabs /S; Fix sets it on every page" [[feature]] id = "a11y.rule-character-encoding" title = "Rule: reliable character encoding" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::scans_identity_fonts_and_long_documents"] notes = "rule character-encoding: ToUnicode, a standard encoding, or a predefined CJK collection; each font once" [[feature]] id = "a11y.rule-tagged-multimedia" title = "Rule: tagged multimedia" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule tagged-multimedia: Screen, Movie, Sound, RichMedia and 3D annotations need /StructParent" [[feature]] id = "a11y.rule-screen-flicker" title = "Rule: screen flicker (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule screen-flicker: needs manual check" [[feature]] id = "a11y.rule-scripts" title = "Rule: scripts (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "rule scripts: needs manual check" [[feature]] id = "a11y.rule-timed-responses" title = "Rule: timed responses (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule timed-responses: needs manual check" [[feature]] id = "a11y.rule-navigation-links" title = "Rule: navigation links (manual)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule navigation-links: needs manual check" [[feature]] id = "a11y.rule-tagged-fields" title = "Rule: tagged form fields" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::a_well_tagged_document_passes"] notes = "rule tagged-form-fields: widgets need /StructParent" [[feature]] id = "a11y.rule-field-descriptions" title = "Rule: field descriptions" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::page_content_and_annotation_problems_are_found"] notes = "rule field-descriptions: fields need a tooltip (/TU)" [[feature]] id = "a11y.rule-figure-alt" title = "Rule: figures have alternate text" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule figures-alt-text: Figure elements need Alt or ActualText (or an ancestor's)" [[feature]] id = "a11y.rule-nested-alt" title = "Rule: no nested alternate text" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule nested-alt-text: Alt inside an element with Alt" [[feature]] id = "a11y.rule-alt-associated" title = "Rule: alternate text associated with content" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule alt-text-associated: Alt on an element with no content beneath it" [[feature]] id = "a11y.rule-alt-hides-annot" title = "Rule: alternate text does not hide annotations" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule alt-text-hides-annotation: Alt on an element containing an OBJR" [[feature]] id = "a11y.rule-other-alt" title = "Rule: other elements have alternate text" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule other-elements-alt-text: Formula elements need Alt" [[feature]] id = "a11y.rule-table-rows" title = "Rule: table rows" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule table-rows: TR parent is Table, THead, TBody or TFoot" [[feature]] id = "a11y.rule-table-cells" title = "Rule: TH and TD in rows" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule table-cells: TH/TD parent is TR" [[feature]] id = "a11y.rule-table-headers" title = "Rule: tables have headers" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule table-headers: at least one TH" [[feature]] id = "a11y.rule-table-regularity" title = "Rule: table regularity" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::row_and_column_spans_keep_a_table_regular"] notes = "rule table-regularity: equal row widths counting ColSpan and RowSpan" [[feature]] id = "a11y.rule-table-summary" title = "Rule: table summary" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule table-summary: Summary table attribute" [[feature]] id = "a11y.rule-list-items" title = "Rule: list items" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule list-items: LI parent is L" [[feature]] id = "a11y.rule-lbl-lbody" title = "Rule: Lbl and LBody" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule lbl-lbody: Lbl/LBody parent is LI (TOCI and notes allowed)" [[feature]] id = "a11y.rule-heading-nesting" title = "Rule: heading nesting" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] tools = ["accessibility_check"] evidence = ["crates/a11y/src/tests.rs::structure_problems_are_found"] notes = "rule heading-nesting: H1–H6 never skip a level going down; the first is H1" [[feature]] id = "a11y.autotag" title = "Automatically tag a document" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.autotag-fields" title = "Autotag form fields" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.reading-order-tool" title = "Reading order tool" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.tags-panel" title = "Tags panel (new, delete, find, change to artifact)" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.tag-properties" title = "Tag properties (type, title, actual text, alternate text, language)" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.role-map" title = "Role map editor" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.class-map" title = "Class map editor" area = "M" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.order-panel" title = "Order panel" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.content-panel" title = "Content panel" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.create-tag-from-selection" title = "Create a tag from a selection" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.artifact-marking" title = "Mark content as artifact" area = "M" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.find-untagged" title = "Find unmarked content, comments and links" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.table-editor" title = "Table editor (headers, scope, spans)" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.alt-text-workflow" title = "Set alternate text figure by figure (with decorative option)" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.alt_text"] tools = ["accessibility_figures", "accessibility_set_alt"] evidence = ["crates/a11y/src/tests.rs::figures_are_listed_with_their_alt_text_and_place", "crates/a11y/src/tests.rs::setting_alt_text_and_marking_decorative", "crates/ui-egui/tests/accessibility.rs::setting_alternate_text_figure_by_figure", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] notes = "Set Alternate Text dialog: each tagged figure (role map honoured) with a preview of where it is drawn, its alternate text, Decorative figure (content becomes /Artifact, element leaves the tags and parent tree), Previous/Next, Save & Close as one undo step" [[feature]] id = "a11y.alt-text-suggestions" title = "Suggest alternate text via an AI provider" area = "M" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "optional provider; off by default" [[feature]] id = "a11y.set-language" title = "Set document language" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["file.properties"] tools = ["doc_initial_view"] evidence = ["crates/organize/src/tests.rs::initial_view_round_trips_and_keeps_scripts", "crates/automation/tests/automation.rs::initial_view_through_tools", "crates/ui-egui/tests/viewer.rs::initial_view_is_edited_and_honoured_on_open"] notes = "Document Properties ▸ Initial View ▸ Language (catalog /Lang)" [[feature]] id = "a11y.set-title-display" title = "Show the document title in the window" area = "M" tier = "P1" milestone = "M12" status = "shipped" commands = ["file.properties"] tools = ["doc_initial_view"] evidence = ["crates/automation/tests/automation.rs::initial_view_through_tools", "crates/ui-egui/tests/viewer.rs::tab_and_window_show_the_document_title_when_asked"] notes = "Initial View ▸ Show: Document Title (/DisplayDocTitle); the tab and window then show the title" [[feature]] id = "a11y.make-accessible-action" title = "Make Accessible guided action" area = "M" tier = "P1" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.setup-assistant" title = "Accessibility setup assistant" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.read-aloud" title = "Read out loud (platform TTS)" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.read-aloud-options" title = "Read-aloud voice, pitch and speed" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.replace-page-colors" title = "Replace page colours (high contrast)" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.reflow-tagged" title = "Reflow tagged content" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "a11y.keyboard-selection-cursor" title = "Always show the keyboard selection cursor" area = "M" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" # ================================================================================================== # N. Compare, automation, AI, preferences, misc # ================================================================================================== [[feature]] id = "misc.compare-text" title = "Compare files: text differences" area = "N" tier = "P1" milestone = "M12" status = "shipped" commands = ["doc.compare"] tools = ["doc_compare", "doc_compare_mark"] evidence = ["crates/compare/src/lib.rs::insertions_deletions_and_replacements", "crates/engine/src/tests.rs::comparing_two_versions_of_a_document", "crates/automation/tests/automation.rs::comparing_documents_through_tools", "crates/ui-egui/tests/compare.rs::compare_two_versions"] notes = "Word-level Myers diff with patience anchors for long files; replaced/inserted/deleted shaded on the new file, listed in the Compare panel, or added as comments." [[feature]] id = "misc.compare-visual" title = "Compare files: visual differences" area = "N" tier = "P1" milestone = "M12" status = "shipped" commands = ["doc.compare"] tools = ["doc_compare"] evidence = ["crates/compare/src/lib.rs::finds_changed_regions", "crates/engine/src/tests.rs::comparing_two_versions_of_a_document", "crates/automation/tests/automation.rs::comparing_documents_through_tools"] notes = "Pages rendered at 72 dpi and compared page by page; differing regions shaded orange where no text change explains them." [[feature]] id = "misc.compare-side-by-side" title = "Side-by-side compare view with synchronised scrolling" area = "N" tier = "P1" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.compare-report" title = "Compare summary report as PDF" area = "N" tier = "P1" milestone = "M12" status = "shipped" commands = ["doc.compare"] tools = ["doc_compare_report"] evidence = ["crates/engine/src/tests.rs::comparing_two_versions_of_a_document", "crates/automation/tests/automation.rs::comparing_documents_through_tools", "crates/ui-egui/tests/compare.rs::compare_two_versions"] notes = "Summary report as a new PDF (counts and every change with pages)." [[feature]] id = "misc.compare-filters" title = "Filter changes by type (text, images, formatting)" area = "N" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.compare-page-ranges" title = "Compare page ranges" area = "N" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.compare-scanned" title = "Compare scanned documents via OCR" area = "N" tier = "P2" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.action-wizard-run" title = "Run guided actions on files" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = ["actions.wizard"] tools = ["action_list", "action_run"] evidence = ["crates/engine/src/tests.rs::actions_run_their_steps_on_files", "crates/automation/tests/automation.rs::actions_through_tools", "crates/ui-egui/tests/actions.rs::run_and_create_actions"] notes = "Pick an action and files; results go to a chosen folder, in the background with progress." [[feature]] id = "misc.action-wizard-create" title = "Create and edit actions" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = ["actions.wizard"] tools = ["action_run"] evidence = ["crates/automation/tests/automation.rs::actions_through_tools", "crates/ui-egui/tests/actions.rs::run_and_create_actions"] notes = "New/Edit/Delete actions with 12 step kinds (OCR, reduce size, remove hidden information, sanitize, flatten, watermark, header, footer, title, detect fields, JavaScript); remembered between runs." [[feature]] id = "misc.action-wizard-manage" title = "Import, export, copy and delete actions" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.action-prepare-distribution" title = "Built-in action: prepare for distribution" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = ["actions.distribution"] tools = ["action_run"] evidence = ["crates/engine/src/tests.rs::actions_run_their_steps_on_files", "crates/automation/tests/automation.rs::actions_through_tools", "crates/ui-egui/tests/actions.rs::run_and_create_actions"] notes = "Remove hidden information, flatten comments and fields." [[feature]] id = "misc.action-optimize-scans" title = "Built-in action: optimize scanned documents" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = ["actions.optimize_scans"] tools = ["action_run"] evidence = ["crates/engine/src/tests.rs::actions_run_their_steps_on_files", "crates/automation/tests/automation.rs::actions_through_tools"] notes = "Recognize text, then reduce file size." [[feature]] id = "misc.action-archive" title = "Built-in action: archive documents" area = "N" tier = "P1" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.action-publish-web" title = "Built-in action: prepare for web publishing" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.batch-processing" title = "Batch processing over files and folders" area = "N" tier = "P1" milestone = "M13" status = "partial" commands = ["actions.wizard", "ocr.recognize_batch"] tools = ["action_run", "ocr_recognize_files"] evidence = ["crates/automation/tests/automation.rs::actions_through_tools", "crates/ui-egui/tests/actions.rs::run_and_create_actions"] notes = "Actions and OCR run over chosen files; whole folders (with subfolders) not yet." [[feature]] id = "misc.action-prompt-steps" title = "Prompt-user and instruction steps" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.action-javascript-step" title = "Execute JavaScript step" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.custom-commands" title = "Custom commands" area = "N" tier = "P1" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.custom-tools" title = "Custom tool sets" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.command-registry" title = "One command registry for menus, shortcuts, palette and automation" area = "N" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["command_list"] evidence = ["crates/engine/src/commands.rs::ids_and_shortcuts_are_unique", "crates/ui-egui/tests/commands.rs::every_registered_command_is_implemented"] notes = "" [[feature]] id = "misc.disabled-command-reasons" title = "Disabled commands explain why" area = "N" tier = "P1" milestone = "M4" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/commands.rs::disabled_commands_explain_themselves"] notes = "" [[feature]] id = "misc.cli-inspect" title = "CLI: inspect, render and extract text" area = "N" tier = "P0" milestone = "M2" status = "shipped" commands = [] tools = ["doc_info", "page_render", "text_extract"] evidence = ["crates/automation/tests/automation.rs::open_inspect_render_and_find"] notes = "" [[feature]] id = "misc.cli-edit" title = "CLI: edit, combine, extract, split" area = "N" tier = "P0" milestone = "M4" status = "shipped" commands = [] tools = ["page_rotate", "page_delete", "doc_combine", "page_extract", "doc_split"] evidence = ["crates/automation/tests/automation.rs::combine_extract_and_split", "crates/automation/tests/automation.rs::edit_undo_redo_and_save_round_trip"] notes = "" [[feature]] id = "misc.cli-run" title = "CLI run: call any automation tool or a JSON script" area = "N" tier = "P0" milestone = "M13" status = "shipped" commands = [] tools = [] evidence = ["crates/automation/tests/automation.rs::tool_table_is_well_formed", "crates/automation/tests/automation.rs::edit_undo_redo_and_save_round_trip"] notes = "" [[feature]] id = "misc.cli-completeness" title = "CLI covers every shipped command" area = "N" tier = "P0" milestone = "M13" status = "partial" commands = [] tools = [] evidence = ["crates/automation/tests/automation.rs::command_list_reports_enablement_and_tools"] notes = "tools grow as features land" [[feature]] id = "misc.automation-tools" title = "Headless JSON-Schema tool table" area = "N" tier = "P0" milestone = "M13" status = "shipped" commands = [] tools = ["command_list"] evidence = ["crates/automation/tests/automation.rs::tool_table_is_well_formed", "crates/automation/tests/automation.rs::errors_are_specific_and_safe"] notes = "" [[feature]] id = "misc.command-list-tool" title = "List commands with enablement and their tools" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = [] tools = ["command_list"] evidence = ["crates/automation/tests/automation.rs::command_list_reports_enablement_and_tools"] notes = "" [[feature]] id = "misc.mcp-server" title = "Opt-in MCP server over stdio" area = "N" tier = "P0" milestone = "M13" status = "shipped" commands = [] tools = [] evidence = ["crates/automation/tests/automation.rs::mcp_session_over_stdio", "crates/automation/tests/automation.rs::mcp_errors"] notes = "" [[feature]] id = "misc.automation-root-confinement" title = "Confine automation file access to a root directory" area = "N" tier = "P0" milestone = "M13" status = "shipped" commands = [] tools = [] evidence = ["crates/automation/tests/automation.rs::errors_are_specific_and_safe"] notes = "" [[feature]] id = "misc.mcp-resources" title = "MCP resources for page images and text" area = "N" tier = "P1" milestone = "M13" status = "shipped" commands = [] tools = ["doc_info", "text_extract", "page_render"] evidence = ["crates/automation/tests/automation.rs::mcp_resources_expose_open_documents", "crates/automation/src/mcp.rs::resource_uris_parse"] notes = "resources/list, resources/templates/list and resources/read: printcraft://doc/{doc}/info (JSON), /text, /page/{page}/text, /page/{page}/image?dpi= (PNG)" [[feature]] id = "misc.ui-control-channel" title = "UI control channel (inspect, click, type, keys, commands)" area = "N" tier = "P0" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/control.rs::inspect_and_click_by_label_and_id", "crates/ui-egui/tests/control.rs::commands_keys_and_typing", "crates/ui-egui/tests/control.rs::loopback_transport_requires_the_token"] notes = "" [[feature]] id = "misc.ui-screenshots" title = "Screenshots of the window or a region via the control channel" area = "N" tier = "P1" milestone = "M3" status = "shipped" commands = [] tools = [] evidence = ["crates/ui-egui/tests/control.rs::screenshots_of_window_and_region"] notes = "" [[feature]] id = "misc.ai-provider" title = "AI provider interface (local model or own endpoint), off by default" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-summary" title = "Summarize a document" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-ask" title = "Ask questions with citations to pages" area = "N" tier = "P2" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-conversational-edit" title = "Natural-language editing through registry commands" area = "N" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-presentation" title = "Generate a presentation from documents" area = "N" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-podcast" title = "Generate an audio overview" area = "N" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.ai-charts" title = "Charts from document data" area = "N" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.contract-analysis" title = "Contract key terms and multi-contract compare" area = "N" tier = "P3" milestone = "M13" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.adobe-ai-assistant" title = "Adobe AI Assistant" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; replaced by the optional local/BYO AiProvider" [[feature]] id = "misc.pdf-spaces" title = "PDF Spaces" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; no local equivalent planned" [[feature]] id = "misc.adobe-express" title = "Adobe Express integration and generated images" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud" [[feature]] id = "misc.document-cloud-storage" title = "Adobe Document Cloud storage" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; local files and native dialogs (pluggable storage later)" [[feature]] id = "misc.share-links" title = "Share links and invitations" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; pluggable share provider" [[feature]] id = "misc.connected-storage" title = "Connected third-party storage accounts in-app" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe cloud; use OS file dialogs and synced folders" [[feature]] id = "misc.cross-device-sync" title = "Sync signatures, stamps and preferences across devices" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Adobe account service" [[feature]] id = "misc.adobe-account" title = "Adobe account sign-in" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "not applicable; no account needed" [[feature]] id = "misc.rich-media-preserve" title = "Preserve 3D, video and sound content" area = "N" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.rich-media-poster" title = "Show posters for rich media" area = "N" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.rich-media-playback" title = "Play video and sound via the platform" area = "N" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.3d-view" title = "View 3D (U3D/PRC) content" area = "N" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.legacy-multimedia" title = "Legacy multimedia (screen annotations, renditions)" area = "N" tier = "P3" milestone = "M12" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.flash-swf" title = "Flash/SWF content" area = "N" tier = "N/A" milestone = "none" status = "na" commands = [] tools = [] evidence = [] notes = "Flash is end-of-life; content is preserved but not played" [[feature]] id = "misc.preferences-dialog" title = "Preferences dialog generated from a schema" area = "N" tier = "P1" milestone = "M14" status = "partial" commands = ["app.preferences"] tools = ["js_enabled"] evidence = ["crates/ui-egui/tests/javascript.rs::document_scripts_and_preferences"] notes = "Preferences dialog with the JavaScript category; other categories still live in their tools." [[feature]] id = "misc.prefs-general" title = "Preferences: general" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-page-display" title = "Preferences: page display" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-documents" title = "Preferences: documents (autosave interval, recent count)" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-commenting" title = "Preferences: commenting" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-forms" title = "Preferences: forms" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-identity" title = "Preferences: identity" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-full-screen" title = "Preferences: full screen" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-search" title = "Preferences: search" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-signatures" title = "Preferences: signatures" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-security" title = "Preferences: security and trust" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-spelling" title = "Preferences: spelling" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-language" title = "Preferences: language" area = "N" tier = "P1" milestone = "M14" status = "partial" commands = [] tools = [] evidence = ["crates/ui-egui/src/i18n.rs::language_persists_and_invalid_input_keeps_current_language"] notes = "Preferences switches English/Japanese and persists; ui.set language en|ja and ui.state expose it. Core menu labels translated; broader dialog/panel translations and additional languages remain open." [[feature]] id = "misc.prefs-reading" title = "Preferences: reading" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-accessibility" title = "Preferences: accessibility" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-color-management" title = "Preferences: colour management" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-javascript" title = "Preferences: JavaScript" area = "N" tier = "P1" milestone = "M14" status = "shipped" commands = ["app.preferences"] tools = ["js_enabled"] evidence = ["crates/ui-egui/tests/javascript.rs::document_scripts_and_preferences"] notes = "Enable Acrobat JavaScript, remembered between runs." [[feature]] id = "misc.prefs-measuring" title = "Preferences: measuring" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-units-guides" title = "Preferences: units and guides" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-content-editing" title = "Preferences: content editing" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-convert" title = "Preferences: convert to and from PDF" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.prefs-catalog" title = "Preferences: catalog / index" area = "N" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.admin-preferences" title = "Admin-deployable preference defaults" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.localization" title = "Localization (Fluent catalogs)" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.rtl-ui" title = "Right-to-left user interface" area = "N" tier = "P2" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.installers" title = "Signed installers for macOS, Windows and Linux" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.web-deploy" title = "Hosted web app deployment" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.performance-budgets" title = "Meet performance budgets on Tier-1 platforms" area = "N" tier = "P0" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.send-email" title = "Send the file by email (system mail client)" area = "N" tier = "P3" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = "" [[feature]] id = "misc.user-docs" title = "User documentation and keyboard reference" area = "N" tier = "P1" milestone = "M14" status = "planned" commands = [] tools = [] evidence = [] notes = ""