Skip to content

fix(suiteui): export-pack finish pass, refused sizes block Export and the CLI says why - #5968

Draft
prakashUXtech wants to merge 52 commits into
devfrom
fix/mac-finish-suiteui-20261028-092121
Draft

prakashUXtech wants to merge 52 commits into
devfrom
fix/mac-finish-suiteui-20261028-092121

Conversation

@prakashUXtech

@prakashUXtech prakashUXtech commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Mac finish pass for the export-pack quality gate. Refs #5834

Covers #3477 and #4523 (export-pack, SuiteUI).

What changed

  • Export button on a refused size (SuiteUI). ExportSheetRows.startBlock gives the reason Export can't start: either the run is past editing, or the Size row's readout is a refusal. The button now uses that reason for .disabled, .help and its control reason. Before, it only checked editable, so a refused size still left Export enabled.
  • CLI refusals (SuiteKernel, CLI).
    • A schema issue in the export options is now a sentence, not a JSON pointer. For example: "Each side in pixels has to be at least 1."
    • The fake document rethrows the refusal as is.
    • The CLI maps ExportOptionRefusal to data (exit 65), not failed (exit 70).
    • The shape refusal tells CLI users to pass "stretch": true. It no longer says to unlock a ratio lock the CLI doesn't have.
  • Design SVG (DesignModel). Design export now reads the suite options and refuses any size except 1x, in words. It used to ignore the size, write 1x and report ok.
  • Photo Export keeps the source's metadata (bug 2). PhotoWindow.write now passes an export's encoded still through PhotoWindow.carryingMetadata, which uses the live StillMetadata. Photo's sheet has no metadata row, so the policy is the suite default .all. The orientation is dropped, because the decode already turned the pixels upright. Test: PhotoExportMetadataTests (gps-phone.jpg opened and exported through ImageIOCodec; GPS, Make, Model, DateTimeOriginal and Copyright kept, orientation dropped, no source copies nothing). Mutation plan: PhotoApp.PhotoWindow+Export.
  • Headless export skips an 8-bit round trip (PhotoModel). PhotoHeadless.export used to turn the resampled buffer into 8-bit RGBA and then back into a linear buffer for core's encoder. Now exportBuffer hands the buffer to CoreRasterImageCodec.encode(buffer:) as is. At 48 MP that saves about 0.4 s. PNG bytes are unchanged (theAgentsJSONOptionsGiveTheSheetsPixels decodes the headless PNG and compares it to exportPixels).
  • Library metadata tests. The three file tests that waited on XP-7 run again. StillMetadata and the gps-phone.jpg sample are both on dev.
  • The CLI's Photo export keeps the source's metadata (bug 7, SuiteImaging, PhotoModel). New JPEGMetadata in SuiteImaging is a Linux-safe MetadataCarrying for JPEG. It copies the source's Exif APP1 onto the encoded still and edits the TIFF structure in place, with bounds checks. It removes each dropped tag (GPS IFD, serial numbers, maker notes and so on), sets a dropped Orientation to 1, and always clears the source's thumbnail and pixel-size tags. XMP and IPTC go along only when the policy drops nothing but the orientation. PhotoHeadless remembers an opened JPEG's bytes, and a JPEG export now runs through it with ExportRules.dropped(metadata) plus Orientation, since the decode already turned the pixels upright. No Package.swift change was needed: PhotoModel already links SuiteImaging, and ImageIO stays inside SuiteImageIO. PNG export carries no metadata yet, because core's PNG writer has no eXIf chunk.
  • Goldens. The export-pack snapshot states now also check Golden/inspector/export-pack-<state>-<light|dark>.png. Golden/README.md says goldens must come from the macOS CI job, so no baselines are committed here. A missing baseline is recorded as a known issue, and CI records it.

Tests

  • ExportPackRowsTests.aRefusedSizeBlocksExportAndSaysWhy and SuiteExportPackSnapshots.eachStateReadsItsSize: Export is blocked only in the refused state.
  • CLIExportRefusalTests: the refusal kind is data with exit 65, there are no schema paths, and the shape refusal names stretch.
  • DesignHeadlessExportOptionsTests: SVG refuses pixels, scale 2, long edge and unknown keys, and accepts none, {} and scale 1.
  • FakeCanvasExportTests, LibraryExportMetadataWriteTests (re-enabled).
  • PhotoHeadlessMetadataTests: all keeps GPS, camera, copyright, date and serial, with the orientation at 1. noLocation drops GPS and the serial (its bytes too) and keeps the rest. none keeps nothing identifying. A PNG export still writes, and an unreadable source copies nothing.
  • Mutation plans: AfterGlowCLICore.Output, DesignModel.DesignHeadless, SuiteKernel.ExportOptions, SuiteKernel.FakeCanvasDocument, SuiteImaging.JPEGMetadata (3/3 caught), and PhotoModel.PhotoHeadless (adds metadataSkipped, caught). Two older entries in that plan, pngRoundTripExact and mergedNotKept, escape on this head. This branch didn't add them, and pngRoundTripExact targets the writePNG fallback that only runs when core throws unsupported.

Proof

  • Proof: Export enabled on a refused size (bug 1) | SuiteExportPackSnapshots.screens() plus ExportPackRowsTests.aRefusedSizeBlocksExportAndSaysWhy on the macOS debug build: a 4:5 artwork set to 1080 × 1351 with Keep Ratio on | The Size row reads "1080 × 1351 doesn't keep the artwork's 4:5 shape. Unlock the ratio to stretch." and the Export button is greyed out next to it; the scale, pixels, long-edge, stretched and vector states keep Export enabled | suiteui-export-pack-refused-light.png / -dark.png; swift test --filter '...|SuiteExportPackSnapshots|ExportPackRowsTests': "✔ Suite ExportPackRowsTests passed", "Suite SuiteExportPackSnapshots passed after 5.997 seconds with 12 known issues" (the 12 are the unrecorded goldens)
  • Proof: SVG ignores size and reports ok (bug 3) | .build/debug/afterglow design export d.design --format svg --json '{"size":{"pixels":[1080,1350]}}' on a 1440x1024 document | kind: data, exit 65, "SVG writes each frame at its own size, so it takes no size. Leave size out."; with no options it writes width="1440" height="1024" and ok | CLI output; DesignHeadlessExportOptionsTests
  • Proof: CLI shape refusal names a ratio lock and exits failed (bug 4) | .build/debug/afterglow photo export p.ora --format png --json '{"size":{"pixels":[1080,1350]}}' on a 1600x1200 image | kind: data, exit 65, "1080 × 1350 doesn't keep the artwork's 4:3 shape. Pass "stretch": true with pixels to stretch." | CLI output; CLIExportRefusalTests
  • Proof: refusals leak schema paths, exit 70 (bug 8) | afterglow photo export p.ora --json '{"size":{"pixels":[0,0]}}' and '{"size":{"scale":0}}' | "Each side in pixels has to be at least 1." and "A scale has to be more than 0.", both kind: data, exit 65, no /size/... path | CLI output; CLIExportRefusalTests, FakeCanvasExportTests
  • Proof: Photo export drops GPS, Copyright and DateTimeOriginal (bug 2) | PhotoExportMetadataTests on the macOS debug build: gps-phone.jpg opened through ImageIOCodec, exported as JPEG and run through PhotoWindow.carryingMetadata | the written file keeps {GPS}, {TIFF}.Make and Model, {Exif}.DateTimeOriginal and Copyright, and drops Orientation; with no source the still is unchanged | "✔ Suite PhotoExportMetadataTests passed after 0.066 seconds."
  • Proof: Photo export drops GPS, Copyright and DateTimeOriginal (bug 2), in the built app | journey PhotoJourneyTests/PhotoExportMetadataJourneyTests/testExportKeepsTheSourcesMetadata (11-02, through the journey wrapper, head ee56f92): Photo.app opens gps-phone.jpg, Export, JPEG, Export | the status bar reads "Exported gps-phone.jpg", and the written file read back with ImageIO keeps {GPS}, {TIFF}.Make, Model and Copyright and {Exif}.DateTimeOriginal, with Orientation 1. All six metadata assertions passed | photo-export-metadata-opened.png, -sheet.png, -exported.png. The run is marked failed by one app-audit contrast reading on photo.adjust.header (1.42:1) in the two shots without a sheet. That header is unchanged here, and dev's hosted journeys (full run 41307844351) show no such fault. On this Mac, macOS's Documents-folder privacy prompt for the freshly signed runner was on screen in those shots.
  • Proof: Library metadata write tests disabled (bug 9) | the three re-enabled LibraryExportMetadataWriteTests on the macOS debug build, writing through the live StillMetadata carrier | all pass | "✔ Suite LibraryExportMetadataWriteTests passed after 0.209 seconds."
  • Proof: metadata 'all' keeps nothing in the CLI (bug 7) | .build/debug/afterglow photo export gps-phone.jpg --format jpeg --out out-<m>.jpg --json '{"metadata":"<m>"}' for all, noLocation and none, each output read back with ImageIO | source: GPS 48.858055,2.294445, Make Generic, Model Phone One, Copyright (c) 2026 Test Owner, DateTimeOriginal 2026:10:01 12:34:56, serial SN-0042-BODY, Orientation 6. all: every one kept, Orientation 1, ok, exit 0. noLocation: no GPS and no serial, the rest kept, Orientation 1. none: none of them. With "pixels":[16,16] the 16x16 output keeps them too | CLI output; "✔ Suite PhotoHeadlessMetadataTests passed after 0.210 seconds" (5 tests)

Not fixed in this pass

  • Slow real-size export (bugs 6 and 11). A release profile of the 4032x3024 scale-2 PNG (8064x6048) puts most of the time in core's PNG.write: 7.8 s for its single-threaded Deflate at level 1, against 2.4 s for the Lanczos resample, on a loaded Mac. A Photo Model can't call Darwin's zlib, because Models stay Linux-safe, and a deflate written in the app would copy engine work. So this case waits on perf(png): level-6 DEFLATE encode of 12 MP within its 2.5 s release budget creative-core#728 and a core bump. PhotoBudgetTests/realSizeExport (gated in release; the scale-2 PNG case has a 6 s budget) fails until then (13.1 s at release). The JPEG cases pass in release: 6000x4000 at 1x 1887 ms (3 s budget), long edge 2048 914 ms, 4:5 crop 526 ms, 4032x3024 at 1080x810 570 ms (1.5 s each). The audit's 6.87 s and 2.4 s were debug-build numbers. The 6000x4000 scale-2 case (53 s) shares the Deflate cost. Profile and details are on Photo export of a 24 MP image takes 5 to 53 s (scale 2 worst) #5976.
  • HEIC and TIFF in Photo (bugs 5 and 10). These fall outside the beta-cut reasons (Export on a refused size, metadata, schema-path refusals, slow scale 2). They move to the issue's ## After beta section. Photo's sheet already lists only the formats it writes (PhotoExportSheetAdapter.formats).

Snapshots

suiteui-export-pack-refused-light.png and suiteui-export-pack-refused-dark.png: Export is now disabled, next to the refused readout. The other export-pack states are unchanged.

Notes

A bad --json export option came back as exit 70 "failed" with the schema's
JSON pointer ("/size/pixels/0: expected at least 1"), and a shape refusal
told CLI users to unlock a ratio lock they don't have. The options schema
now refuses in a sentence, the fake rethrows the refusal as is, and the CLI
maps ExportOptionRefusal to data (65) with the stretch hint.
DesignHeadless.export read no options, so {"size":{"pixels":...}} wrote 1x
SVG and said ok. It now parses the suite options and refuses any size but
1x in words.
The sheet kept Export enabled under a refused size readout. ExportSheetRows
gains startBlock, the reason Export can't start, which the button uses for
disabled, help and its accessibility reason. The export-pack snapshot
states also check goldens under Golden/inspector, which CI records.
XP-7 shipped the live StillMetadata and the gps-phone.jpg sample, so the
three file tests no longer wait on it.
@prakashUXtech prakashUXtech added mac-finish Mac finisher pass PR quality-gate 10-26 audit bugs the Mac finisher fixes and proves in the built app labels Oct 28, 2026
@prakashUXtech prakashUXtech added the fast-lane Merge automatically when small, green and outside protected paths label Oct 28, 2026
@prakashUXtech prakashUXtech removed the fast-lane Merge automatically when small, green and outside protected paths label Oct 30, 2026
…olicy

A Linux-safe JPEGMetadata carrier in SuiteImaging copies the source's Exif
APP1 onto the still and edits it in place: dropped entries are removed and
their bytes zeroed, orientation is set to 1, and the thumbnail and source
pixel size always go. PhotoHeadless runs JPEG exports from a JPEG through it,
so the CLI no longer needs the ImageIO carrier in SuiteShell.

Refs #5834
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mac-finish Mac finisher pass PR quality-gate 10-26 audit bugs the Mac finisher fixes and proves in the built app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant