Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Native Release
on:
workflow_dispatch:
push:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Updated the tag for the new release correctly.

🤖 WarpFix

tags: [ 'v2.0.0rc2' ]
tags: [ 'v2.0.0rc3' ]

permissions:
contents: read
Expand Down Expand Up @@ -54,9 +54,9 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f
- name: Build OCI image

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

The build and run commands for the new version are updated correctly.

🤖 WarpFix

run: docker build -t comic-sol:2.0.0rc2 .
run: docker build -t comic-sol:2.0.0rc3 .
- name: Smoke OCI image
run: docker run --rm --entrypoint comic-sol comic-sol:2.0.0rc2 doctor --output-root /data/doctor
run: docker run --rm --entrypoint comic-sol comic-sol:2.0.0rc3 doctor --output-root /data/doctor

source:
runs-on: ubuntu-latest
Expand All @@ -82,7 +82,7 @@ jobs:
publish:
needs: [native, container, source]
runs-on: ubuntu-latest
if: github.ref == 'refs/tags/v2.0.0rc2'
if: github.ref == 'refs/tags/v2.0.0rc3'
permissions:
contents: write
env:
Expand All @@ -108,7 +108,7 @@ jobs:
records = []
for platform in ('linux', 'macos', 'windows'):
bundle = root / f'comic-sol-{platform}-x86_64'
verify_release_directory(bundle, ReleaseIdentity('2.0.0rc2', platform, 'x86_64'))
verify_release_directory(bundle, ReleaseIdentity('2.0.0rc3', platform, 'x86_64'))
for path in sorted(bundle.iterdir()):
if path.name == 'SHA256SUMS':
continue
Expand All @@ -121,6 +121,6 @@ jobs:
- name: Publish immutable prerelease assets
shell: bash
run: |
gh release create v2.0.0rc2 --repo "${GITHUB_REPOSITORY}" --verify-tag --prerelease --title 'Comic Sol v2.0.0rc2' --notes-file docs/releases/v2.0.0rc2.md
find bundles -type f ! -name SHA256SUMS -print0 | xargs -0 gh release upload v2.0.0rc2 --repo "${GITHUB_REPOSITORY}" --clobber
gh release upload v2.0.0rc2 bundles/SHA256SUMS --repo "${GITHUB_REPOSITORY}" --clobber
gh release create v2.0.0rc3 --repo "${GITHUB_REPOSITORY}" --verify-tag --prerelease --title 'Comic Sol v2.0.0rc3' --notes-file docs/releases/v2.0.0rc3.md
find bundles -type f ! -name SHA256SUMS -print0 | xargs -0 gh release upload v2.0.0rc3 --repo "${GITHUB_REPOSITORY}" --clobber
gh release upload v2.0.0rc3 bundles/SHA256SUMS --repo "${GITHUB_REPOSITORY}" --clobber
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Changelog is well-structured and provides clear information about the new release.

🤖 WarpFix


## 2.0.0rc3 — 2026-07-30

Focused PDF fidelity prerelease.

### Fixed

- Encode composed page rasters at JPEG quality 95 before deterministic PDF publication.
- Preserve detailed, high-frequency comic artwork under the unchanged full-content verification thresholds.
- Add a deterministic regression reproducing the live Codex App dogfood failure.

### Distribution notes

- Linux, macOS, and Windows x86_64 archives remain available with wheel, sdist, installers, checksums, and CycloneDX SBOMs.
- Native artifacts remain **unsigned**; verify downloads against `SHA256SUMS`.

## 2.0.0rc2 — 2026-07-30

Comic Quality release candidate.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ The CLI currently exposes `doctor`, `init`, `status`, `validate`, `resume`,
`finalize`, and the optional `mcp` launcher. Machine-readable responses use one

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

The README is updated to reflect the new version, maintaining clarity.

🤖 WarpFix

stable envelope containing `ok`, `command`, `data`, and `error`.

## Native Distribution (`v2.0.0rc2`)
## Native Distribution (`v2.0.0rc3`)

The `v2.0.0rc2` prerelease provides bundled portable archives for Linux, macOS,
The `v2.0.0rc3` prerelease provides bundled portable archives for Linux, macOS,
and Windows x86_64, plus transactional user-local installers and a non-root OCI
image. Native archives include Python, Pillow, MCP, fonts, templates, the Skill,
and references, so installed execution does not require a system Python.
Expand Down
2 changes: 1 addition & 1 deletion comic_sol_product/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Installed product surface for Comic Sol."""

__version__ = "2.0.0rc2"
__version__ = "2.0.0rc3"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Version number updated correctly.

🤖 WarpFix

2 changes: 1 addition & 1 deletion comic_sol_product/distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pathlib import Path

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Version number updated correctly.

🤖 WarpFix

from typing import Iterable

_VERSION = "2.0.0rc2"
_VERSION = "2.0.0rc3"
_PLATFORMS = {"linux", "macos", "windows"}
_ARCHITECTURES = {"x86_64", "arm64"}
_SAFE_NAME = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
Expand Down
2 changes: 1 addition & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
comic-sol:
build: .
image: comic-sol:2.0.0rc2
image: comic-sol:2.0.0rc3
read_only: true
command: ["mcp", "--root", "/data"]
volumes:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Image tag updated correctly for the new version.

🤖 WarpFix

Expand Down
22 changes: 11 additions & 11 deletions docs/install.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Install Comic Sol v2.0.0rc2
# Install Comic Sol v2.0.0rc3

Comic Sol `v2.0.0rc2` is a prerelease distributed as native portable archives for Linux, macOS, and Windows, plus a Python wheel/source archive and an OCI image definition. Native archives bundle Python 3.11, Pillow, MCP, fonts, templates, the Skill, and references; no system Python is required after extraction.
Comic Sol `v2.0.0rc3` is a prerelease distributed as native portable archives for Linux, macOS, and Windows, plus a Python wheel/source archive and an OCI image definition. Native archives bundle Python 3.11, Pillow, MCP, fonts, templates, the Skill, and references; no system Python is required after extraction.

## Security status

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Installation instructions are updated to reflect the new version.

🤖 WarpFix

Expand All @@ -11,29 +11,29 @@ This release is **unsigned**. It is not Authenticode-signed, notarized, or GPG-s
Download the matching ZIP and copy `installers/install.sh` from the same release or repository checkout. Read it before execution, then verify and install:

```bash
sha256sum comic-sol-2.0.0rc2-linux-x86_64.zip
sha256sum comic-sol-2.0.0rc3-linux-x86_64.zip
# Compare the digest with SHA256SUMS.
sh installers/install.sh \
--archive ./comic-sol-2.0.0rc2-linux-x86_64.zip \
--archive ./comic-sol-2.0.0rc3-linux-x86_64.zip \
--sha256 <digest-from-SHA256SUMS>

$HOME/.local/share/comic-sol/bin/comic-sol --version
$HOME/.local/share/comic-sol/bin/comic-sol doctor
```

For macOS, use `comic-sol-2.0.0rc2-macos-x86_64.zip`. The default installation root is `$HOME/.local/share/comic-sol`. Override it with `--install-root PATH` or `COMIC_SOL_INSTALL_ROOT`.
For macOS, use `comic-sol-2.0.0rc3-macos-x86_64.zip`. The default installation root is `$HOME/.local/share/comic-sol`. Override it with `--install-root PATH` or `COMIC_SOL_INSTALL_ROOT`.

The POSIX installer requires `sha256sum`, `unzip`, and standard POSIX utilities. Native binaries are unsigned, so macOS Gatekeeper may require an explicit local approval for this prerelease.

## Windows PowerShell

Download `comic-sol-2.0.0rc2-windows-x86_64.zip` and copy `installers/install.ps1` from the same release or repository checkout, then run:
Download `comic-sol-2.0.0rc3-windows-x86_64.zip` and copy `installers/install.ps1` from the same release or repository checkout, then run:

```powershell
(Get-FileHash .\comic-sol-2.0.0rc2-windows-x86_64.zip -Algorithm SHA256).Hash
(Get-FileHash .\comic-sol-2.0.0rc3-windows-x86_64.zip -Algorithm SHA256).Hash
# Compare the digest with SHA256SUMS.
.\installers\install.ps1 `
-Archive .\comic-sol-2.0.0rc2-windows-x86_64.zip `
-Archive .\comic-sol-2.0.0rc3-windows-x86_64.zip `
-SHA256 <digest-from-SHA256SUMS>

& "$HOME\AppData\Local\ComicSol\bin\comic-sol.exe" --version
Expand Down Expand Up @@ -80,8 +80,8 @@ Uninstall removes only the user-local runtime installation. Comic projects are p
Build and run the non-root image from a checkout:

```bash
docker build -t comic-sol:2.0.0rc2 .
docker run --rm --entrypoint comic-sol comic-sol:2.0.0rc2 doctor --output-root /tmp/comic-sol-doctor
docker build -t comic-sol:2.0.0rc3 .
docker run --rm --entrypoint comic-sol comic-sol:2.0.0rc3 doctor --output-root /tmp/comic-sol-doctor
docker compose up
```

Expand All @@ -91,7 +91,7 @@ The image runs as `comic-sol`, uses `/data` for persistent projects, and exposes

Each platform bundle contains:

- `comic-sol-2.0.0rc2-<platform>-x86_64.zip`
- `comic-sol-2.0.0rc3-<platform>-x86_64.zip`
- platform metadata declaring the unsigned state
- a CycloneDX SBOM
- `SHA256SUMS`
Expand Down
36 changes: 36 additions & 0 deletions docs/releases/v2.0.0rc3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Comic Sol v2.0.0rc3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Release notes are comprehensive and provide valuable information.

🤖 WarpFix


`v2.0.0rc3` is a focused Comic Quality **prerelease** that preserves detailed composed pages during PDF export.

## Fixed

- PDF page rasters are encoded at JPEG quality 95 before deterministic publication.
- Detailed, high-frequency comic artwork now remains within the existing full-content fidelity ceiling without relaxing any verification threshold.
- A deterministic high-frequency regression fixture protects the behavior.

The issue was found during a live Codex App dogfood run. The same page measured a mean absolute channel error of 3.87 with the previous encoder default and 2.24 with the RC3 setting, below the unchanged 3.1 ceiling. The completed two-page output passed final validation with no warnings.

## Quality and compatibility

RC3 retains every RC2 Comic Quality guarantee: deterministic panel normalization,
typography preflight, the immutable `four-grid` layout, artifact-bound page QA,
full-content PDF verification, and the deterministic quality matrix. Matrix evidence
proves mechanics only and is not a substitute for visual review.

- The exact 17-tool MCP surface is unchanged.
- Quality schema and project formats are unchanged.
- Full-page verification thresholds remain `3.1 / 0.021 / 16.0`.
- RC2 projects remain readable; no migration is required.

## Distribution

The prerelease includes:

- Linux, macOS, and Windows x86_64 portable archives
- Python wheel and source archive
- transactional POSIX and PowerShell installers
- SHA-256 checksums
- CycloneDX SBOMs
- non-root OCI build definition

Native archives and installers remain **unsigned**. Verify every downloaded artifact against `SHA256SUMS` before use.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "comic-sol"
version = "2.0.0rc2"
version = "2.0.0rc3"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Version number updated correctly in the project configuration.

🤖 WarpFix

description = "Local-first deterministic comic production pipeline"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion scripts/assemble_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def main() -> int:
parser.add_argument("--architecture", default="x86_64", choices=("x86_64", "arm64"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise documentation

Release identity updated correctly for the new version.

🤖 WarpFix

args = parser.parse_args()

identity = ReleaseIdentity("2.0.0rc2", args.platform, args.architecture)
identity = ReleaseIdentity("2.0.0rc3", args.platform, args.architecture)
output = args.output.resolve()
output.mkdir(parents=True, exist_ok=True)
archive = output / artifact_name(identity, "zip")
Expand Down
24 changes: 12 additions & 12 deletions tests/test_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,25 @@
class NativeDistributionContractTests(unittest.TestCase):
def setUp(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise testing

Test cases updated to reflect the new version, ensuring consistency.

🤖 WarpFix

self.identity = ReleaseIdentity(
version="2.0.0rc2", platform="linux", architecture="x86_64"
version="2.0.0rc3", platform="linux", architecture="x86_64"
)

def test_identity_and_artifact_names_are_canonical(self):
self.assertEqual("v2.0.0rc2", self.identity.tag)
self.assertEqual("v2.0.0rc3", self.identity.tag)
self.assertEqual(
"comic-sol-2.0.0rc2-linux-x86_64.tar.gz",
"comic-sol-2.0.0rc3-linux-x86_64.tar.gz",
artifact_name(self.identity, "tar.gz"),
)
with self.assertRaises(ValueError):
ReleaseIdentity("2.0.0-rc2", "linux", "x86_64")
with self.assertRaises(ValueError):
ReleaseIdentity("2.0.0rc2", "Linux", "amd64")
ReleaseIdentity("2.0.0rc3", "Linux", "amd64")

def test_metadata_checksum_and_sbom_are_deterministic(self):
with tempfile.TemporaryDirectory() as temporary_directory:
release = Path(temporary_directory)
first = release / artifact_name(self.identity, "tar.gz")
second = release / "comic-sol-2.0.0rc2-linux-x86_64.sbom.json"
second = release / "comic-sol-2.0.0rc3-linux-x86_64.sbom.json"
first.write_bytes(b"portable-runtime")
second.write_text("{}\n", encoding="utf-8")

Expand All @@ -64,7 +64,7 @@ def test_metadata_checksum_and_sbom_are_deterministic(self):
self.assertEqual("CycloneDX", sbom_record["bomFormat"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Warning testing

Ensure that the version comparison in tests is robust against future changes.

Suggested change
self.assertEqual("CycloneDX", sbom_record["bomFormat"])
Consider using a constant for version comparison to avoid hardcoding.

🤖 WarpFix

self.assertEqual("1.6", sbom_record["specVersion"])
self.assertEqual("comic-sol", sbom_record["metadata"]["component"]["name"])
self.assertEqual("2.0.0rc2", sbom_record["metadata"]["component"]["version"])
self.assertEqual("2.0.0rc3", sbom_record["metadata"]["component"]["version"])

def test_verifier_rejects_missing_or_tampered_artifact(self):
with tempfile.TemporaryDirectory() as temporary_directory:
Expand All @@ -75,7 +75,7 @@ def test_verifier_rejects_missing_or_tampered_artifact(self):
write_sbom(release, self.identity)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Warning testing

Verify that the artifact names are generated dynamically to avoid hardcoding.

Suggested change
write_sbom(release, self.identity)
Use a function to generate artifact names based on the version.

🤖 WarpFix

write_checksums(
release,
[artifact, release / "comic-sol-2.0.0rc2-linux-x86_64.sbom.json"],
[artifact, release / "comic-sol-2.0.0rc3-linux-x86_64.sbom.json"],
)
verify_release_directory(release, self.identity)

Expand Down Expand Up @@ -155,7 +155,7 @@ def test_container_and_release_workflow_are_hardened(self):
self.assertIn("/data", compose)

self.assertIn("workflow_dispatch:", workflow)
self.assertIn("tags: [ 'v2.0.0rc2' ]", workflow)
self.assertIn("tags: [ 'v2.0.0rc3' ]", workflow)
for runner in ("ubuntu-latest", "macos-latest", "windows-latest"):
self.assertIn(runner, workflow)
self.assertIn("scripts/build_portable.py", workflow)
Expand All @@ -169,9 +169,9 @@ def test_container_and_release_workflow_are_hardened(self):
self.assertIn("installers/install.sh", workflow)
self.assertIn("installers/install.ps1", workflow)
self.assertIn("prerelease: true", workflow)
self.assertIn("if: github.ref == 'refs/tags/v2.0.0rc2'", workflow)
self.assertIn("comic-sol:2.0.0rc2", workflow)
self.assertIn("gh release create v2.0.0rc2", workflow)
self.assertIn("if: github.ref == 'refs/tags/v2.0.0rc3'", workflow)
self.assertIn("comic-sol:2.0.0rc3", workflow)
self.assertIn("gh release create v2.0.0rc3", workflow)
self.assertNotIn("refs/tags/v2.0.0rc1", workflow)
for line in workflow.splitlines():
if "uses:" in line:
Expand All @@ -187,7 +187,7 @@ def test_rc2_version_sources_and_quality_runtime_are_consistent(self):
compose = (root / "compose.yaml").read_text(encoding="utf-8")
release_contract = (root / "comic_sol_product/release.py").read_text(encoding="utf-8")
for source in (pyproject, package, distribution, assembler, compose):
self.assertIn("2.0.0rc2", source)
self.assertIn("2.0.0rc3", source)
for module in (
"normalize_panels.py", "typography.py", "layouts.py", "page_quality.py",
"pdf_quality.py", "quality_sample.py",
Expand Down
2 changes: 1 addition & 1 deletion tests/test_product_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_version_flag_reports_release_identity(self):
with self.assertRaises(SystemExit) as exit_context, redirect_stdout(stdout):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise testing

Version flag test updated correctly for the new version.

🤖 WarpFix

cli.build_parser().parse_args(["--version"])
self.assertEqual(0, exit_context.exception.code)
self.assertEqual("comic-sol 2.0.0rc2\n", stdout.getvalue())
self.assertEqual("comic-sol 2.0.0rc3\n", stdout.getvalue())

def test_default_output_roots_are_platform_native(self):
home = Path("/users/example")
Expand Down
6 changes: 3 additions & 3 deletions tests/test_release_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ def setUpClass(cls):
cls.readme = (cls.root / "README.md").read_text(encoding="utf-8")
cls.install = (cls.root / "docs/install.md").read_text(encoding="utf-8")
cls.changelog = (cls.root / "CHANGELOG.md").read_text(encoding="utf-8")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise testing

Tests for release notes updated to reflect the new version.

🤖 WarpFix

cls.notes = (cls.root / "docs/releases/v2.0.0rc2.md").read_text(encoding="utf-8")
cls.notes = (cls.root / "docs/releases/v2.0.0rc3.md").read_text(encoding="utf-8")

def test_readme_links_native_install_and_release_security(self):
self.assertIn("docs/install.md", self.readme)
self.assertIn("v2.0.0rc2", self.readme)
self.assertIn("v2.0.0rc3", self.readme)
self.assertIn("SHA256SUMS", self.readme)
self.assertIn("unsigned", self.readme.lower())
self.assertIn("docker compose", self.install)
Expand Down Expand Up @@ -42,7 +42,7 @@ def test_install_guide_covers_every_supported_lifecycle(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise testing

Test for release notes limitations updated correctly.

🤖 WarpFix

def test_release_notes_and_changelog_identify_rc_limitations(self):
for document in (self.changelog, self.notes):
self.assertIn("2.0.0rc2", document)
self.assertIn("2.0.0rc3", document)
self.assertIn("unsigned", document.lower())
self.assertIn("Linux", document)
self.assertIn("macOS", document)
Expand Down
Loading