Skip to content

fix(#1977): retire the iccPawgReport --read option - #1978

Merged
xsscx merged 2 commits into
masterfrom
issue-1977-retire-pawg-read
Aug 5, 2026
Merged

fix(#1977): retire the iccPawgReport --read option#1978
xsscx merged 2 commits into
masterfrom
issue-1977-retire-pawg-read

Conversation

@colourbill-ctrl

Copy link
Copy Markdown
Contributor

Part of #1977.

Retires iccPawgReport --read. @xsscx confirmed on #1972 that it was leftover prototyping scaffolding rather than an intended feature, and #1977 records the mechanism and scope.

Why it can never have worked

DumpPawgReport() only consulted the flag after the strict path had already returned NULL:

  CIccProfile *pIcc = ValidateIccProfile(szFilename, sReport, nStatus);

  if (bUseRead && !pIcc) {
    pIcc = ReadIccProfile(szFilename);
  }

ValidateIccProfile() returns NULL on a parsed profile only when ReadValidate() reaches icValidateCriticalError, and the two conditions that get it there are exactly the conditions CIccProfile::Read() — behind ReadIccProfile() — bails on:

condition ReadValidate() CIccProfile::Read()
ReadBasic() fails critical, IccProfile.cpp:941 return false, :874
any LoadTag() fails critical, :992 return false, :905
CheckTagLayout() tops out at icValidateWarning not consulted

Supporting facts, both checked rather than assumed: icValidateStatus is ordered OK(0) < Warning(1) < NonCompliant(2) < CriticalError(3) (IccDefs.h:106-111), so >= icValidateCriticalError matches only the maximum and the NonCompliant/Warning header checks cannot trigger the NULL return; and LoadTag() opens with an absolute Seek(offset, icSeekSet), so the repositioning ReadValidate() does beforehand cannot change its outcome relative to Read()'s loop.

The root of the mistake is that ReadIccProfile() is the eager loader, not a permissive one. On tag structure it is stricter than a lazy OpenIccProfile(), so it fails on precisely the conditions that just made ReadValidate() report critical.

Nothing is lost

The graceful degradation --read was reaching for already exists and never depended on it. LoadRawProfile() runs unconditionally at the top of DumpPawgReport(), before and independently of any IccProfLib parsing, so a file the library refuses still receives the full raw-byte security assessment with the parsed-profile items reported as NOT RUN. That reasoning is now recorded where the fallback used to sit, because it is what makes a strict-only load acceptable here.

Retired, not accepted-and-ignored

--read now falls through to the existing unrecognised-switch branch:

$ iccPawgReport --read profile.icc
Unknown option "--read"

Usage: iccPawgReport {--json} profile
...
$ echo $?
1

A caller still passing it is told plainly, rather than believing a fallback ran.

Scripts move with the source

icc-pawg-qa-scan.sh drove two of its four QA variants through --read and runs in CI from ci-iccdev-tool-tests.yml. Leaving it would turn those two into exit 1. They are dropped rather than replaced — both executed the same code path as their non---read counterparts.

pawg-read-option-fidelity, which only ever asserted that a good profile reports identically with the flag set, is replaced by pawg-read-option-retired, which pins the rejection.

Not touched

iccDumpProfile has a separate --read with different semantics — eager ReadIccProfile() instead of lazy OpenIccProfile(), not a post-failure fallback (iccDumpProfile.cpp:210). It is live and working, and along with icc-dumpprofile-qa-scan.sh and docs/ctest.md:273 is deliberately left alone.

Verification

Acceptance test from #1977 — report output unchanged. All 80 tracked Testing/*.icc profiles, text and JSON modes, version string normalised: 12639 lines, 0 diff against pre-removal master.

The new regression case is red-tested. Silently re-accepting --read makes it fail with --read was accepted (expected non-zero exit; the option is retired), so it catches the accepted-and-ignored mode specifically rather than just the presence of the flag.

Build and suite.

  • IccPawgReport.cpp and PawgReport.cpp compile clean under -Wall -Wextra -Wpedantic -Werror on gcc and clang
  • shellcheck -S error clean on both changed scripts
  • 7 PAWG CTests pass
  • full local suite 148/150; the two failures are environmental and reproduce independently of this branch — spectral-tiff-preview (missing python imagecodecs) and qa-profile-manifest (0 mismatched, one unlisted stray untracked file in my working tree)

Rebased onto c0cd71db so CI validates the landing tree.

--read was documented as a fallback that would still assess a profile the strict
validation path rejected. It could never do that. ValidateIccProfile() returns
NULL on a parsed profile only when ReadValidate() reaches icValidateCriticalError,
and the two conditions that get it there -- ReadBasic() failing (IccProfile.cpp:941)
and any LoadTag() failing (:992) -- are exactly the conditions CIccProfile::Read()
bails on (:874, :905), so ReadIccProfile() returned NULL for the same inputs.
CheckTagLayout(), the only other contributor, tops out at icValidateWarning.
The branch therefore only ever assigned NULL over NULL.

xsscx confirmed on #1972 that the option was leftover prototyping scaffolding
rather than an intended feature; it has been present since the tool's first commit
068a3d3 "Add: iccPawgReport (#1026)".

The graceful degradation it was reaching for already exists and does not depend on
it: LoadRawProfile() runs unconditionally before any IccProfLib parsing, so a file
the library refuses still gets the full raw-byte assessment with the
parsed-profile items reported as NOT RUN. That is noted where the fallback used
to sit, since it is the reason a strict-only load is acceptable here.

The option is retired rather than accepted-and-ignored: it now falls through to
the existing unrecognised-switch branch, so a caller still passing it is told
plainly instead of believing a fallback ran.

Scripts move with the source, or CI goes red -- icc-pawg-qa-scan.sh drove two of
its four variants through --read and runs from ci-iccdev-tool-tests.yml. Those two
are dropped rather than replaced: both executed the same code path as their
non---read counterparts. The pawg-read-option-fidelity regression case, which only
ever asserted that a good profile reports identically with the flag, is replaced by
pawg-read-option-retired, which pins the rejection.

Not touched: iccDumpProfile's separate --read, which is a live option with
different semantics (eager instead of lazy load, not a post-failure fallback).

Verified: report output byte-identical across all 80 tracked Testing/*.icc profiles
in both text and JSON modes, with the version string normalised (12639 lines, 0
diff); 7 pawg CTests pass; the new case red-tests correctly, failing with
"--read was accepted" when the option is silently re-accepted; shellcheck clean on
both scripts.
@github-actions github-actions Bot added Tools Command-line tool or GUI tool changes Testing CTest, regression, or test coverage Source C or C++ source code changes Scripts Shell, PowerShell, or repository automation scripts Unix Linux, macOS, Bash, or POSIX shell scope pending CI checks still running labels Aug 5, 2026
The pre-flight gate runs `shellcheck` bare -- no -x, no severity filter -- over
files changed by the PR (preflight-safety-checks.sh:1051). The `# shellcheck
source=` directive records where the sourced helper lives but does not stop
SC1091 being reported when shellcheck is not following external sources, so the
gate failed on a line this change did not introduce.

The finding is pre-existing and identical on master (line 20 there, line 21
here), and is reached only because the gate lints changed files and this is the
first change to touch this script since the gate existed. The two sibling
scripts, icc-dumpprofile-qa-scan.sh and icc-roundtrip-qa-scan.sh, carry the same
latent finding and will fail the same way when something first touches them;
they are left alone rather than swept into this change.

Both directives are kept: source= still documents the path for anyone running
shellcheck -x, and disable=SC1091 silences the info-level report for the way the
gate actually invokes it. Verified with the gate's own invocation form -- both
changed scripts in a single bare shellcheck call, rc=0 -- and the scan still
resolves its two remaining variants.
@github-actions github-actions Bot added passed All CI checks passed and removed pending CI checks still running labels Aug 5, 2026
@xsscx
xsscx merged commit 472d81a into master Aug 5, 2026
35 checks passed
@xsscx xsscx added this to the v2.3.2.3 milestone Aug 5, 2026
@xsscx xsscx linked an issue Aug 5, 2026 that may be closed by this pull request
@xsscx
xsscx deleted the issue-1977-retire-pawg-read branch August 5, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

passed All CI checks passed Scripts Shell, PowerShell, or repository automation scripts Source C or C++ source code changes Testing CTest, regression, or test coverage Tools Command-line tool or GUI tool changes Unix Linux, macOS, Bash, or POSIX shell scope

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove: retire the iccPawgReport --read option

2 participants