Skip to content

content icon: --strict, --min-contrast and optional --ocr checks (#57) - #127

Merged
CompleteDotTech merged 33 commits into
mainfrom
issue/57
Nov 1, 2026
Merged

CompleteDotTech merged 33 commits into
mainfrom
issue/57

Conversation

@CompleteDotTech

@CompleteDotTech CompleteDotTech commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Change and affected skills

What: content icon check gains --strict (fails on family-ink; family key icon_strict_family_ink), a configurable contrast floor --min-contrast, and an opt-in OCR no-text check --ocr (runs tesseract when it is on PATH; with --strict an OCR text finding fails; skipped with a log entry when the tool is absent). The icon is composited on the configured family card colour (card_fill) before OCR reads it. Undecodable PNG data now yields a structured QA failure instead of a traceback: icon_qa returns result: fail with a logs entry naming the unreadable image once, icon check exits 1, and icon normalize exits 1 with out null and leaves an existing destination file byte-identical; this includes a PNG with a CRC-valid zero-length iCCP chunk after IDAT, which made Pillow raise IndexError. Schema, references/content.md, SKILL.md (icon command reference) and the CHANGELOG are updated.

Why: family-ink was only a warning, so an old off-brand icon passed with warn; the fixed 3:1 floor accepted a dim 3.17:1 icon; no-text was manual only; a corrupt PNG crashed the QA command.

Resolves #57
Resolves #58
Resolves #59
Resolves #60

Prior work: searched this repository's PRs and issues for the icon check, strict mode, contrast floor and OCR. Related but not duplicating: merged PR #20, merged PRs #14 to #19, merged PR #124 (footer), open issue #7 with open PR #13, and the already-resolved icon issues 8 to 12 (not linked here). No other open PR covers issues #57 to #60.

Evidence (exact head 334eaaf958d954239981663a7326e32214dfc667, base main a30979d4481c3f2124faceb2cf602bb71c95fea8 integrated by a normal merge)

  • Isolated VM (Ubuntu 24.04, Python 3.12.3, run by the outer coordinator; receipt vm-334eaaf958d954239981663a7326e32214dfc667-result.json): package tests, package validator, full pytest and quality validator passed; pytest 1224 passed, 11 skipped, 37 subtests. The skips are the pre-existing absent external fixtures. This VM has Tesseract 5.3.4 installed (an optional test dependency installed only in the VM; the repository gains no auto-install code).
  • Real-engine tests executed in the VM (real-ocr-tests-334eaaf...-vm.json): pytest -k real_tesseract -vv -rs selected 5 tests and all 5 PASSED with no skips: dark text on light, a text-free control, white lettering on a dark card (warns no-text, fails under --strict), a text-free icon passing, and the CLI icon check. They use synthetic PIL images and the real discovery/subprocess path (no mocks); they skip only where tesseract is not installed, which is why they show as skipped in a local run on a host without it.
  • Hosted CI on this head: validate-package (ubuntu, windows, macos), pytest (ubuntu, windows, macos), and validate, for the push and pull-request matrices: 14 check runs, all completed with success.
  • Independent reviews of this exact head and base (native provenance verified): two Opus reviewers (claude-opus-5-5) and Codex gpt-6.1-sol at max effort each returned an explicit approve with zero findings. Earlier reviews of older heads (including a Sol request for the real-engine tests, now satisfied) do not carry over.
  • Local (host) run at this head, preserved failure: the owner's guarded native full pytest run had 2 failures out of 1215 passed and 18 skipped, in tests/test_org_labels_live.py::test_sparse_default_checkout_uses_index_not_visible_files[Northwind-Labs] and tests/test_review_action_commit.py::test_template_icon_removal_is_committed. Both failed at their fixture git commit (exit 128) and the log does not print the Git stderr, so the cause is unknown (I do not claim a signing cause). The two tests were rerun unchanged in a focused retry with a stderr tracer and passed (2 passed in 5.10 s). This is NOT a passing local full run and is not claimed as one; the exact-head VM and hosted CI are the passing evidence. Earlier local runs on earlier heads failed at the same kind of fixture commit step (one of them printed Cannot open A for signing); those logs are preserved and are not evidence for this head.
  • Earlier-head replays (history, kept): at 2c76d3a root's VM replays covered the seven real-Tesseract controls, corrupt-IDAT API/CLI handling, normalize with and without OCR preserving the destination, and the trailing-iCCP API plus all four CLI paths with a valid paired control.
  • Not run: mmdc/Mermaid rendering (tool unavailable); private deny-list check (no private fixtures); pyright (no config).

Limitations and tracked suggestions

  • OCR is optional and off by default; without tesseract the check logs needs-input:ocr-unavailable and stays manual.
  • Non-blocking reviewer suggestions tracked for later: _ocr_words composites on white again after _flatten_on_card (harmless and redundant), _ocr_words and _flatten_on_card catch a narrower exception set than icon_qa, icon_strict_family_ink is read with bool() (a non-schema string would enable strict mode if schema validation were bypassed; the default stays OFF), the --strict help text does not yet mention the OCR text finding, and a Windows-native full-suite receipt for this exact head is absent (hosted windows-latest pytest is green).

Boundaries

Activation keys, consent, approval gates and specialist entry points are unchanged. No brand decision is altered and no brand mark was created or redrawn. Defaults are unchanged: strict mode and OCR are opt-in. No registry release, visibility change or live external action is implied. Shared validators (scripts/validate_package.py, tests/test_package_contract.py) are byte-identical to main.

Family consistency

Single-repository change; no sibling skill PRs are affected.

🤖 Generated with Claude Code

Timothy Wayne Gregg and others added 11 commits October 30, 2026 08:57
Family-ink fails instead of warning when `--strict` is given on
`content icon check` or `content icon normalize`, or when the family
sets `icon_strict_family_ink: true`. Off by default; the default
output and exit codes are unchanged. With no family palette the
family-ink check is still not emitted.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The contrast-on-card floor is now configurable per run (`--min-contrast`)
and per family (`icon_min_contrast`, schema range 1 to 21). Precedence is
CLI > family key > 3.0, so the default output is unchanged. 4.5:1 is
documented as the recommended card-plate floor but stays off by default.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`content icon check` and `content icon normalize` take `--ocr`. When tesseract is on PATH the
icon is flattened on white and read; words of 2+ alphanumerics warn (fail with --strict). Without
the tool, or if it fails, no-text stays a manual review and the logs name
needs-input:ocr-unavailable or needs-input:ocr-failed. The result and exit code do not change
when the tool is missing. Off by default; the default manual entry is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rn (E3.2.3 fix)

The OCR commit converted scripts/ctshowcase/content.py to CRLF, so the whole file showed as
changed (5394 lines) instead of the real ~78. The base file is LF; this restores LF so the
diff against base is the 78 real lines. Also removes stray spaces on the second return in
_cmd_icon. No behaviour change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
icon_qa returned before the OCR step when the PNG could not be validated, so
ocr=True produced a result without `logs`. The early return now carries
`logs: []` only when ocr is on; the default shape is unchanged. Adds a
malformed-PNG regression test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…review)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ze --strict (E3 review)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-31T23:43:35.010881Z
We couldn’t complete this review. Comment @codex review to try again.
ae38a62 PR opened
🔒 Security Review ⚠️ Failed 2026-10-31T23:43:40.177386Z
We couldn’t complete this review. Comment @codex security review to try again.
ae38a62 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@chatgpt-codex-connector

Copy link
Copy Markdown

The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins.

CompleteDotTech and others added 2 commits October 31, 2026 19:54
… with logs=[] (#60)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…AT comment (#60)

Fixes ruff E401 at tests/test_content.py (import struct, zlib) by splitting the import, and corrects the comment: the icon_qa API raised OSError('broken data stream'); the CLI already caught it globally (JSON result=usage, logs=['usage'], exit 2). No noqa, no config change.

Deviation: the Haiku worker produced no result, so the Sonnet owner made this edit itself.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Bounded native OCR validation for exact head ae38a62431b2d6824e8dbd9675320f151c2e8b10 (no Codex or VM launch).

Executed the pinned icon_qa implementation directly in the existing Linux container with Python 3.12.14, Pillow 13.0.0 and installed Tesseract 5.5.0/English data. All eight imported source modules matched their pinned Git blob identities. Synthetic fixtures only; no repository source edits or installations.

Five assertions passed (exit 0): OCR disabled keeps manual review; actual Tesseract reads white HELLO on the transparent/dark-card fixture and warns; strict mode fails for that text; a text-free circle passes; isolated absence of Tesseract logs needs-input:ocr-unavailable while preserving the manual-result behavior. The HELLO fixture independently has the expected 2.7% coverage warning, so this does not claim every image-quality check passed.

Evidence scope: current-container, direct icon_qa integration only. This does not establish fresh-VM validation, full CLI/end-to-end behavior, full-suite acceptance, independent review approval or merge readiness. Fresh-environment validation remains outstanding. The PR-body assignment to Codex is not authorization to launch it; current orchestration is native-only. Existing ownership and acceptance gates remain unchanged.

CompleteDotTech and others added 13 commits October 31, 2026 20:17
…bad arguments still exit 2 (#60)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…60)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…colour (card_fill), not a --card flag (#60)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add test_icon_normalize_cli_undecodable_idat_exits_1_with_logs_and_missing_input_exit_2:
a structurally valid PNG with corrupt IDAT must yield exit 1, result fail, out null,
an art-fail:icon-qa log and a png fail check, with no output written; a nonexistent or
omitted --in stays exit 2. Expected to fail until the content.py normalize handler lands.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ecodable sources (#57, #60)

Read --in as bytes first (missing or unreadable stays a usage error, exit 2). A readable
source that cannot be decoded now goes through icon_qa on the raw bytes and returns
result=fail with logs and out=null, exit 1, nothing written, instead of raising from Image.open/load.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…xit 1), missing --in stays exit 2 (#60)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…alize (#57)

Pre-create the normalize destination with known bytes and assert it is
unchanged after the undecodable-IDAT failure, with and without --ocr, and
after the usage (exit 2) cases. Test-only change.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
icon_qa gains a `source` keyword. Every png failure now returns
logs == ["unreadable-image:<source>"] (or <bytes> when no source is
known), with and without --ocr. The icon check and icon normalize CLI
paths pass the real file path. The normalize decode-failure branch
appends the same unreadable-image entry before art-fail:icon-qa,
without duplicating it.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
#57)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CompleteDotTech and others added 7 commits October 31, 2026 22:34
…ailure (#57)

Catch IndexError at both image-decoding boundaries (icon_qa and the
normalize source load) so icon check and icon normalize report the
structured PNG failure (exit 1, unreadable-image log, out null,
destination preserved) with and without --ocr.

Reproduced first with a synthetic PNG (valid IHDR, zlib-compressed valid
IDAT, zero-length iCCP with correct CRC, IEND): validate_png accepts it
and, before the source fix, icon_qa, icon check and icon normalize
raised IndexError from PIL PngImagePlugin. Regression test added in
tests/test_content.py covering API, check and normalize, with and
without --ocr, plus missing --in exiting 2.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…57)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…trol bytes (#57)

The malformed PNG is now the valid control with a zero-length CRC-valid iCCP chunk
inserted before IEND, so the pixel payload is identical. The unused opaque helper is removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds skip-marked controls that invoke the installed tesseract binary without
monkeypatching: dark-on-light positive, text-free negative, white lettering on
a dark card through icon_qa (warn, and fail under strict), a text-free icon
pass, and the icon check CLI with --ocr. They skip with an explicit reason when
tesseract is absent; the VM and hosted CI run them.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…md; accurate real-OCR skip reason (#57)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant