Changelog
This is the development changelog for the scratch branch. It has one entry per build (0.1.0-dev.N), newest first. Every commit that changes the project adds an entry here, and tools/check_version.py checks that the top entry matches VERSION.
Related logs:
- CHANGELOG-STABLE.md: releases tagged on
Stable-Release. - CHANGELOG-COMMUNITY.md: changes merged into
community. - Release and versioning map: which build introduced each format and ABI.
Builds dev.1 to dev.10 predate the repository history, which starts at dev.11 (fe01f26). Their entries are kept as written. Some later builds (for example dev.33 to dev.36 and dev.44) were recorded here but committed together with a neighbouring build.
0.1.0-build.85 — 2026-11-07
- Safe Actions (spec/CKey-Safe-Actions.md). A Safe Action is a code a reader may act on without asking first:
ckey-action:1:<base64url envelope>, signed with Ed25519 by a site (the issuer, named by its domain) for one app and one action that app registered, with a single-use request ID and a short lifetime. Anything that does not verify runs nothing. Same-device actions run at once; cross-device actions (sign in a browser elsewhere, approve a payment) run only after a confirmation the SDK owns, which shows the issuer's account of who is asking (device, place, time) fetched from the issuer's own domain. The issuer's scope and the app's registration both count, and the stricter wins. This is the one exception to rule 1 of the payload conventions (now draft 0.2). - Core: SHA-512 and Ed25519 (RFC 8032, canonical-S check) in
src/ed25519.inc;ckey_is_safe_action,ckey_safe_action_parse,ckey_safe_action_verify,ckey_safe_action_sign,ckey_ed25519_public_key, structckey_safe_actionand statusCKEY_EXPIRED(7). Additive: the C ABI stays 4. - Conformance vectors:
tests/vectors/safe-actions-v1.json, 22 envelopes from an implementation independent of the core (tools/safe_actions_vectors.mjs, Node crypto), each with its required verdict. The core'sckey_safe_actionstest, the web, Android and .NET tests check every one; CI checks the file is current. - CLI:
ckey action keygen | public-key | sign | verify. - SDKs: a policy class in each SDK (
SafeActionsfor the web,CKeySafeActionsfor Swift, Android and .NET) that pins issuer keys, registers actions, and returns not-a-safe-action / rejected / performed / needs-confirmation. Approval is internal to the SDK: only its own prompt (a<dialog>, SwiftUICKeySafeActionPrompt, AndroidCKeySafeActionPromptover AlertDialog, WPFCKeySafeActionPromptorCKeySafeActionConsolePrompt) can run a cross-device action. Web bridgeckw_safe_action; Android JNInativeSafeAction; .NET P/Invoke overckey_safe_action. - Verified here: core tests in release and sanitizer builds; web tests; the Android host check (JNI signatures, exports, Safe Action vectors through JNI, Kotlin API checks, 28 JUnit tests); 76 of 76 .NET tests against
libckeynative.so. Not compiled here: the Swift sources (CI macOS) andCKey.Wpf(needs the Windows desktop SDK; CI Windows).
0.1.0-build.84 — 2026-11-07
- Field tests.
field-tests/suite.jsondefines eleven real-world tests: smallest printed size, reading distance, viewing angle, lighting, screens, damage, styles, density, the print layout on small labels, time to read, and payload safety. Each states the claim it checks and why, the set-up and steps, the test codes (payload, version, level, layout, style and print size), what to record, and a pass / partial / fail rubric.tools/field_tests.pyvalidates the suite and generatesfield-tests/README.md, one page per test infield-tests/tests/, and the GitHub issue form.github/ISSUE_TEMPLATE/field-test-report.yml; CI runs it with--checkand encodes every test code with the CLI. openckey.org reads the samesuite.jsonfrom the release it pins, prints the test sheets with the web SDK, and publishes every result, from the site or from GitHub issues, at openckey.org/tests. - No change to the core, formats or packages.
0.1.0-build.83 — 2026-11-06
The release that goes to every registry, v0.1.0-build.83.
- npm package renamed
openckey. The nameckeyon npm belongs to an unrelated package published in 2018, sov0.1.0-build.82could not be published there. Install withnpm install openckeyand import from'openckey'; the API is unchanged. The release tarball isopenckey-<version>.tgz. - No change to the core, formats or other packages.
0.1.0-build.82 — 2026-11-06
Tagged v0.1.0-build.82; superseded by build.83 (the npm name ckey was taken).
- Style validation without undefined behaviour. The structural check read
policy,modules,ringsandraysas their enum types before range-checking them, so a caller passing an out-of-range value (the certification test passes 9) was undefined behaviour, and the sanitizer CI job stopped on it. The check now reads each field's raw integer and refuses unknown values as before. - Android host check:
jni-host-test/run.shlooked up optional jars in the Gradle distribution withls, and underset -euo pipefaila missing jar ended the script with exit code 2 before the Kotlin step. Missing optional jars are now ignored. - Verified here: the full suite under AddressSanitizer and UBSan with
-fno-sanitize-recover=all(13 of 13), and the Android host check (JNI signatures, exports, 60 harness checks, Kotlin API checks, 17 JUnit tests).
0.1.0-build.81 — 2026-11-06
Tagged v0.1.0-build.81; superseded by build.82 (two CI checks stopped its release workflow).
- .NET native library renamed to
ckeynative(ckeynative.dll,libckeynative.so,libckeynative.dylib). Windows file names ignore case, so the nativeckey.dlland the managedCKey.dllwere the same file in an application's output folder; one overwrote the other and P/Invoke found nockey_get_abi_version(33 of 65 tests failed on Windows). Every Windows consumer of the package would have hit this. The CMake output name,NativeLibraryName.Name, the package'sruntimes/<rid>/native/assets, the .NET Framework copy target and the CI checks all use the new name. - Verified here: 65 of 65 .NET tests pass against
libckeynative.so; a local pack places every native asset and both target frameworks where the CI layout check expects them.
0.1.0-build.80 — 2026-11-06
- .NET SDK compiles again.
CKeyPayload.csheld a literal LINE SEPARATOR and PARAGRAPH SEPARATOR (U+2028, U+2029) inside a string. C# treats both as line breaks, so the string ended mid-line and the SDK had not compiled since build 67. They are written as\u2028and\u2029; no other source file holds either character. - .NET certification test: it still expected every modelled trial to pass. Since build 72 the photo sweep includes sizes too small to read, so a certified style passes some trials, not necessarily all; the test now checks that.
- Verified here:
dotnet buildofCKeyandCKey.Wpf(net8.0 and netstandard2.0) with no errors or warnings, anddotnet test: 65 of 65 pass against the Linux native library.
0.1.0-build.79 — 2026-11-06
- macOS CI: GitHub retired the
macos-14runners ("The configuration 'macos-14-arm64-us-default' is not supported"), so every macOS job (the .NET natives forosx-arm64andosx-x64, the .NET tests, the Swift package and the release CLI build) was cancelled before it started. They run onmacos-15.
0.1.0-build.78 — 2026-11-06
- Windows .NET build: the struct-layout check compared the probe's output (carriage returns stripped) with an expected file that the Windows runner had checked out with CRLF endings, so every line differed although every offset and size matched. The check now uses
diff --strip-trailing-cr, and.gitattributeskeeps LF endings for the expected layout and the test vectors on every platform.
0.1.0-build.77 — 2026-11-06
Fixes for the release build, which failed at the v0.1.0-build.76 tag.
- Windows (.NET native library): MSVC has no
__int128, which the telemetry core used for exact 128-bit multiply-divides. Amul_divhelper keeps__int128where the compiler has it and otherwise uses a portable 64×64→128 multiply and long division (checked against__int128on 3.5 million random and edge-case inputs). The bound check on a histogram's sum no longer needs 128 bits. - Linux (.NET native library):
libckey.soexported C++ standard-library template instantiations under GCC 11. A linker version script (sdk/dotnet/native/exports.map) now exportsckey_*only (57 symbols); there is still no libstdc++ dependency. - Debug and sanitizer builds:
field_score, which calls the scan library's calibration scores, moved from the shared internals toapi_scan.inc. Unoptimized codec and render builds no longer reference scan symbols, sockey_interchange_testslinks. - Docs: the release table and changelogs record build.76 as tagged but not released.
0.1.0-build.76 — 2026-11-06
The first release, promoted to Stable-Release as v0.1.0-build.76.
- README: rewritten for people using CKey: a gallery of rendered codes, install lines and a short example for every package (Swift, npm, Maven, NuGet, Homebrew, CMake), what CKey can do, and an index of the documentation. The former README's technical walk-through moved, almost unchanged, to
docs/OVERVIEW.md. - Gallery:
docs/gallery/holds eight codes rendered by the core (plain, print layout, custom colours, Concept, dotted rings, accents, light on dark and a dense v17).tools/gallery/ckey_gallery.cpp(targetckey-gallery) renders them, reads each one back with the real decoder, certifies it and writes the gallery page. All eight read back and certify. - Publishing:
tools/release/publish.sh <tag>publishes a release from the Release workflow's draft (npm, NuGet, Maven Central, Homebrew tap, then the GitHub Release), after checkingSHA256SUMSand provenance. It rebuilds nothing.docs/PUBLISHING.mdcovers registry accounts and the release procedure. - Lock-down: every GitHub Action is pinned to a commit SHA with its tag as a comment;
.github/CODEOWNERSadded;docs/REPOSITORY-SETTINGS.mdlists the branch, tag and security settings to apply in GitHub. - Repository:
CONTRIBUTING.mdandSECURITY.mdadded;.gitignorecovers SDK build outputs.tools/check_version.pychecksCONTEXT.mdonly where it exists, since release branches ship without it.tools/bump_version.pyalso updates the README and SDK READMEs, whose install lines name the version.
0.1.0-build.75 — 2026-11-05
- Swift package resolves in Xcode: the
CKeyScan,CKeyRenderandCKeyCertifytargets now ship aninclude/directory. Git stores no empty directories, so a fresh clone lacked them and Xcode refused the package graph with "public headers ("include") directory path for 'CKeyScan' is invalid or not contained in the target".
0.1.0-build.74 — 2026-11-05
Swift SDK fixes, found while building the Open CKey Scanner iPhone app:
CKeyPayload.classify,tel:andsms:: the number now ends at the first;or?, so URI parameters are never dialled as digits. Previouslytel:+15550100;ext=7became+155501007.CKeyPayload.text(from:)andCKeyResult.text: only C0 controls other than tab, LF and CR, plus DEL and C1, make a payload binary, as in the web reader. Emoji ZWJ sequences, soft hyphens, bidi marks and BOMs are text.- vCards must begin with a
BEGIN:VCARDline and end with anEND:VCARDline, as in the web reader. CKeyCameraScanner(observer:resolution:): new.uhd4K(default) and.hd1080resolutions..hd1080suits memory-limited camera extensions.- Camera errors: reported as
.cameraAccessDeniedor.cameraUnavailableinstead of.invalidConfiguration. - XCTests added for each fix. They have not been compiled here;
sdk-swift.ymlruns them on macOS.
0.1.0-build.73 — 2026-11-05
- The photo sweep, not fixed rules, decides certification. Custom backgrounds were refused by the old 3:1 rule even when they scanned well; concept on slate
#555, for example, has a 2.9:1 accent and is graded "good" by the sweep. Now:- Hard refusals remain only for near-invisible marks (below 1.5:1), mixed polarity, and logo limits (Ring Key, plate, 50% budget).
- Low contrast below 3:1 and strong depth on dark-on-light styles are warnings. They appear in the style check ("style OK, but …; certify it to check that it scans") and in the certification message ("note: …").
- Strict renderers draw these styles. Adaptive repairs only hard failures up front, and the advisory repairs only if the sweep fails.
- Measured: concept on navy, forest and burgundy is excellent; on slate, teal and
#777it is good; on tan and cream it is refused or marginal.
- Tests updated:
#e8e8e8on white is the near-invisible refusal case, and#bbbbbbrenders but fails the sweep.
0.1.0-build.72 — 2026-11-05
- Certification now models real photographs. The old check decoded the styled symbol from a perfectly known position at a comfortable 8 px per module, so almost every style passed.
ckey_certify_scalable_stylenow runs a photo sweep:- place the symbol in a cluttered frame, with rotation, keystone, glare, defocus and noise;
- run the full reader pipeline: find borders, refine, decode;
- walk a ladder of camera resolutions (9 down to 3 px per module) to find the smallest that still decodes;
- grade the style against plain black on white for the same symbol: excellent as small as plain, good one step larger, marginal two steps, otherwise fails.
- Certification needs the safety rules plus a grade of good or better.
- The message states both sizes, so the cost of a decoration is visible.
- The plain reference is cached per symbol.
- Typical cost is 0.1–0.7 s for v1–v11 and about 5 s for v31, natively.
- The API and ABI are unchanged;
model.px_per_modulenow sets the resolution the style must decode at. - The design-system spec and the header document the new semantics.
- Profile 0.1 regression coverage: the simulated-reader test now also scans print-layout symbols (v2, v11, v20) through the exact pipeline the iPhone reader uses. All 48 new scenes decode, and under heavy blur Profile 0.1 decodes far better than the standard layout. The reported CKey Reader failure is consistent with an app build from before build 58, when Profile 0.1 did not exist.
- CKey Reader: the subtitle now lists Profiles 0, 0.1 and 1–3.
0.1.0-build.71 — 2026-11-05
- Removed
services/openckey, the Node prototype of the openckey.org service. Its telemetry ingestion, renderer page and abuse controls now live in the proprietary openckey.org site. That site follows the same normativedocs/adoption-and-telemetry.md, and it pins this repository's commits to build the web SDK.
0.1.0-build.70 — 2026-11-05
- openckey.org is now a separate, proprietary site. It provides:
- the browser renderer;
- package downloads;
/text/{id}and/sq/{id}destinations;- telemetry ingestion.
- README, implementation status and context now say so. The CI job for the prototype
services/openckeyis removed. The prototype itself is retired in the next build.
- Release workflow: reuses the SDK workflows, which now accept
workflow_call, to build and test each package, and attaches it to the draft release:- the npm tarball;
- NuGet packages;
- a Maven repository zip for Android;
- a Swift source zip.
- These join the CLI archives, the source archive and the Homebrew formula, so openckey.org can host every package for download.
- The
sdk-webworkflow also uploads thenpm packtarball.
0.1.0-build.69 — 2026-11-05
- Android SDK, Maven
org.openckey:ckey(sdk/android/, spec §3 and §7): AGP 8 and Kotlin. NDK CMake compiles the repository's ownsrc/files with a JNI bridge that exports only theJava_*functions.- Modules:
ckey, the core AAR, with no dependencies beyond the Kotlin standard library;ckey-compose, which providesCKeyImage;ckey-camerax, which providesCKeyAnalyzer.
- Scan-only and render-only builds: set the Gradle properties
ckey.native.scan,ckey.native.renderandckey.native.telemetry. - API:
CKeySymbol.encode;toBitmap, which converts straight alpha to Android's premultiplied form;toPng,toSvg,toPdfandcertify;CKeyStyle, with presets and a policy;CKeyDecoder, for gray buffers, aByteBuffer,android.media.Imageor aBitmap;CKeyScanner, which records telemetry sessions;CKeyPayload.classify.
- Telemetry:
CKey.telemetrytakes 0, 1 or 2; any other value throwsIllegalArgumentException. One background thread sends batches over HTTPS only, and the SDK tries a send when the app moves to the background. - Publishing: maven-publish to a local directory, with no credentials in the build.
- Verified here with
jni-host-test/run.sh:- the Kotlin native declarations and the C++ bridge are checked against each other through a generated JNI header;
- a JVM harness runs 60 checks under
-Xcheck:jni, including round trips, premultiplication, exports, refusals, certification and the full telemetry cycle; - the real Kotlin sources compile with Kotlin 2.0.21 against stubs;
- 22 Java-side API checks pass, and 17 JUnit tests pass.
- Not verified here: the Gradle/AGP/NDK build, the Compose module and the instrumented tests run only in
sdk-android.yml.
- Modules:
tools/bump_version.pynow also covers the SDK READMEs.
0.1.0-build.68 — 2026-11-05
docs/IMPLEMENTATION-STATUS.md: rewritten against builds 61–67, item by item against the specification. It ends with a list of what only the maintainer can do: deploy openckey.org, publish to the registries, set up branch protection, make real prints and camera captures, and pin action SHAs.docs/platform-integration.md(new) is for camera-platform teams. It covers:- what to link (only
ckey_codecandckey_scan); - the decoding pipeline for each frame;
- threading and memory;
- the security review surface;
- conformance;
- a proposed device benchmark plan, with a p90 first-decode target to be confirmed by measurement.
- what to link (only
- README: new sections on libraries, SDKs and services, and on rendering, certification and verification. The documentation index is extended.
- CONTEXT: records the decisions from builds 61–68.
- No code changes.
0.1.0-build.67 — 2026-11-05
- Swift package
CKey(Package.swiftat the repo root,sdk/swift/, spec §3 and §7): apps add the repository URL in Xcode.- C++ targets:
CKeyCodec,CKeyScan,CKeyRender,CKeyCertifyandCKeyTelemetry. Each is a one-line shim that compiles the repository's ownsrc/file, so nothing is copied. - Products:
CKey, the full SDK;CKeyScanner, scan only: moduleCKeyScanKit, with no renderer and no telemetry.
- Rendering API:
CKeySymbol.encode;cgImage,pngData,svgandpdfData;certify;CKeyStyle, with presets and a policy.
- Scanning API:
CKeyView, a SwiftUI view that draws native pixels and is transparent by default, plus UIKit and AppKit views;CKeyDecoderforCGImageandCVPixelBuffer;CKeyScanner, an AVFoundation camera helper that drives telemetry sessions.
- Payloads:
CKeyPayload.classify. - Telemetry:
CKey.telemetrytakes 0, 1 or 2, andtry CKey.setTelemetry(rawValue:)rejects anything else. Batches are sent off the scan queue through an ephemeralURLSession, and the SDK tries a send when the app moves to the background. - Privacy:
PrivacyInfo.xcprivacydeclares analytics that are not linked to the user and not used for tracking. - Verified here: the C++ shims and module maps compile with gcc and clang, and their results were checked.
- Not verified here: the Swift sources have not been compiled.
sdk-swift.ymlrunsswift build,swift testand an iOS Simulator build on macOS.
- C++ targets:
- .NET SDK, NuGet
CKey(sdk/dotnet/, namespaceOpenCKey):- Native library: one shared
ckeylibrary built by CMake, exporting exactly the 55 C ABI functions. On Linux it statically links the C++ runtime. The package carries it forwin-x64,linux-x64,osx-arm64andosx-x64. - Interop:
LibraryImporton net8.0 andDllImporton netstandard2.0. Struct layouts are checked against a Coffsetofprobe in tests and in CI. - API:
CKeySymbol.Encode;RenderRgba,ToPng,ToSvgandToPdf;Certify;CKeyDecoder.Decode, using the same pipeline as the iOS reader;CKeyPayload.Classify.
- Telemetry:
CKey.Telemetrytakes 0, 1 or 2, and anything else throwsArgumentOutOfRangeException. Batches are sent asynchronously withHttpClient.CKeyScanSessionrecords scan sessions. - Optional
CKey.Wpfadapter, which returnsWriteableBitmap. - Verified here: the native build, its exported symbols and the struct layouts.
- Not verified here: the C# has not been compiled.
sdk-dotnet.ymlbuilds the native libraries on Linux, Windows and macOS, then runsdotnet testanddotnet pack.
- Native library: one shared
.gitignore: SwiftPM's.build/and.swiftpm/.
0.1.0-build.66 — 2026-11-05
- CMake package (spec §7):
cmake --installinstalls the libraries, headers and theckeyCLI, plusCKeyConfig.cmake.- Consumers call
find_package(CKey)and linkCKey::core, or individual targets:CKey::scan,CKey::render,CKey::codec,CKey::certify,CKey::telemetry. examples/c/has an encode → raster → PNG → scan example and a scan-only example. CI installs the package and builds and runs the example.
- Consumers call
- Homebrew (proposed in spec §7):
packaging/homebrew/ckey.rb.inandtools/release/make_homebrew_formula.py, which fills in the tag and the source archive's SHA-256. - Release workflow (
release.yml, spec §7–8):- Trigger: runs only for
v*tags. The tag must equalv+VERSIONand sit onStable-Release. The full test suite runs first. - Artifacts:
- CLI and library archives for Linux x64, macOS arm64 and Windows x64;
- the source archive;
- the Homebrew formula;
support-matrix.json;SHA256SUMS.
- Provenance: Sigstore build provenance through
actions/attest-build-provenance. - Result: a draft GitHub Release titled
CKey <version>, for the maintainer to publish.
- Trigger: runs only for
- Deprecate workflow (
deprecate-release.yml, spec §8.2): a manual run retitles a releaseDeprecated - {release name}and adds a notice naming the replacement and the reason. The tag and its source stay. - Community workflow (
community.yml, spec §8):- runs ASan/UBSan tests on pull requests and pushes to
community; - uses
pull_requestwith a read-only token and no persisted credentials, so fork code never sees secrets; - rejects changes to
VERSIONor to the release workflow, and warns whenCHANGELOG-COMMUNITY.mdhas no entry.
- runs ASan/UBSan tests on pull requests and pushes to
- CI: new jobs for the openckey.org service tests, and for synthetic benchmarks with QR Code and Data Matrix through zxing-cpp (uploaded as an artifact).
- Web SDK, npm
ckey(sdk/web/): an Emscripten build of codec, scan, render, telemetry and certify, plus a small C bridge and an ES module API. It matches the openckey.org renderer page:encode,renderToCanvas,renderPixels,renderPNG,renderSVGandrenderPDF;decodeImageData,createScanner,classifyPayloadandcertify;telemetry, valued 0, 1 or 2, raisingRangeErrorotherwise. The telemetry sender usesfetchwith keepalive, sends no credentials or referrer, and never throws;- TypeScript types.
- Verified here: 26 JS tests pass, and native bridge tests pass under ASan/UBSan.
- Not verified here: the wasm build and its tests run only in
sdk-web.yml, because emsdk is not available in this environment.
tools/bump_version.pybumps every versioned file, including SDK manifests.
0.1.0-build.65 — 2026-11-05
.ckeyinterchange v1 (spec §2.5;spec/CKey-Interchange-v1.md):ckey_write_interchangeandckey_read_interchangestore a Profile 0 or 0.1 codeword, an optional style and an optional logo reference.- Layout: a 12-byte header, type-length-value records, and a closing CRC-32C. Bit 15 marks a record as optional.
- Strict, bounded reader: at most 64 KiB, all reserved bytes must be zero, and an unknown required record is rejected. The codeword must decode and must be the canonical encoding of its payload.
- The file is optional: rendering never needs it. The payload is stored in clear.
- Library: the reader is in
ckey_codecand needs no renderer. - Tests: new test
ckey_interchangecovers round trips, the rejection cases, and 20,000 mutated files, clean under AddressSanitizer and UBSan.
- Conformance suite (spec §6; acceptance criterion 1):
tools/conformance/ckey_conformance.cppandtests/vectors/conformance-v1.json.- 19 vectors: P0 and P0.1 across versions and levels, an empty payload, a vCard, and P1, P2 and P3 legacy encodings.
- Expected outputs: the codeword, an FNV-1a 64 hash of the canonical geometry with coordinates rounded to 10⁻⁶, a
.ckeyfile hash, and a check that a raster decodes. Pixels are checked by behaviour, not by hash. - Verified identical under gcc -O0 and -O2, and under clang -O2 with
-ffast-math. - New CTest
ckey_conformance_vectors. SDKs load the same JSON; seetools/conformance/README.md.
- Support matrix (spec §8.2): machine-readable
docs/support-matrix.jsonwith the current build, ABI, tag form, formats and their status, interchange and telemetry schema versions, packages and deprecations.check_version.pychecks it. - Benchmark harness (spec §5, §6):
ckey-bench(tools/optical-benchmarks/).- Pipeline: generate, degrade (clutter, rotation, keystone, glare, defocus, noise), then decode with the full reader pipeline.
- Measures:
- recovery;
- corrected bytes;
- latency p50, p90 and p99;
- the smallest side for 90% success, and bytes per 1,000 px² at equal area;
- false positives.
- QR Code and Data Matrix comparison through zxing-cpp with
-DCKEY_BENCH_ZXING=ON. - A quick, CKey-only synthetic run is committed in
docs/benchmarks/. It found 0 false positives in 60 clutter frames. Results are explicitly synthetic.
0.1.0-build.64 — 2026-11-05
- ABI 4:
ckey_stylegainspolicy. Code that fills styles withckey_style_defaultorckey_style_preset_fillneeds no other change. - Style policies (spec §4):
CKEY_POLICY_STRICT(the default),CKEY_POLICY_ADAPTIVE(renderers repair the style by fixed rules, then check it) andCKEY_POLICY_OVERRIDE(renderers draw the style as given; checks report "NOT scan-safe"). Structurally invalid values are refused under every policy. - Optical certification (spec §4; acceptance criteria 5 and 6):
ckey_certify_scalable_stylecertifies through a modelled scan, not a contrast ratio:- render with the native raster;
- composite over each backdrop;
- apply glare, defocus and noise;
- decode with the real decoder, on 3 seeded trials per backdrop.
- It also reports the minimum contrast, the mark/gap luma separation and the logo load.
- Adaptive certification returns the repaired style and a
CKEY_ADJUST_*bit for each change. - Transparent output needs a
ckey_backdrop(colours and/or the host's pixels). Without one the result is "background unknown" and is never certified.
- New library
ckey_certify(needs scan and render).ckey_corenow includes it. - New test
ckey_style_certification:- The default style certifies at v1, v11 and v31 (v31 in about 1.3 s).
- A coarse, blurred model fails v31.
- Strict refuses low contrast in the check, the renderer and certification.
- Override renders but never certifies.
- Adaptive repairs ink, accents and depth.
- Transparent output: refused without a backdrop, certified on white, refused for black on #333333, which adaptive fixes by flipping the ink.
- A half-black host image is refused.
- The concept preset certifies.
spec/CKey-Design-System.md: new section on policies and certification.
0.1.0-build.63 — 2026-11-05
- Separate libraries (spec §2.1, §6, §9.2; acceptance criterion 8): the core is now
ckey_codec,ckey_scan(needs only the codec),ckey_renderand the optionalckey_telemetry.ckey_coreremains as the union of the first three.- A scanner app links no renderer and no telemetry.
ckey_optical_image_decodenow linksckey_scanalone, so CI enforces this. - The source is split into shared internals plus one file of public functions per library.
src/ckey.cppstays as the amalgamation for the Xcode projects. Seesrc/README.md. -DCKEY_BUILD_TELEMETRY=OFFleaves telemetry out entirely.
- A scanner app links no renderer and no telemetry.
- Telemetry core (spec §9;
docs/adoption-and-telemetry.md):include/ckey/telemetry.h.- Modes: 0, 1 (the default) and 2. Any other value returns
CKEY_INVALID_ARGUMENTand leaves the mode unchanged. Mode switches follow the documented table: switching to 0 purges everything; 1 → 2 drops the unsent delta and ignores any batch in flight. - Sessions: a session starts when scanning starts, succeeds at the first decode, and fails when scanning ends or after a 30 s timeout. Frames are counted separately.
- Data: counts by profile, and histograms of time to decode and per-frame processing time.
- Batches:
- the exact schema-1 JSON, with per-batch clamping to the schema's limits;
- an hourly send cadence;
- result handling that drops a batch on 2xx, 400 or 413, and keeps it on 429, 5xx or a network error.
- State: optional export and import, strictly parsed.
- No networking: the core never sends; SDK wrappers post to
CKEY_TELEMETRY_ENDPOINT(https://openckey.org/api/telemetry/v1/batch). It uses no clock, heap or exceptions, and is thread-safe. - Tests: new test
ckey_telemetry, clean under AddressSanitizer, UBSan and ThreadSanitizer.
- Modes: 0, 1 (the default) and 2. Any other value returns
- openckey.org service (
services/openckey/): a Node 22 service with no dependencies. Runnpm test; 75 tests pass.- Telemetry ingestion:
- strict parsing, rejecting unknown fields, non-integer literals, duplicate keys and over-size bodies;
- rate limits keyed by a daily-salted HMAC of the client IP, kept in memory only;
- daily aggregates only, kept for 400 days;
- a summary labelled "not total usage".
- Short links (
/r/:id): created by an admin. The interstitial shows the destination host first;?go=1redirects directly. Counts are opt-in, per link and per day. - Hosted text pages (
/t/:id): escaped HTML under a strict CSP, plus.txt. - Web renderer page (
/): uses the web SDK when it is built. - No IPs, bodies or URLs are logged.
- Telemetry ingestion:
0.1.0-build.62 — 2026-11-05
- Canonical geometry (spec §2.1):
ckey_scalable_geometryreturns a Profile 0 / 0.1 symbol as a list of primitives in canonical units, in painter's order. The primitives are rect, rect outline, circle, diamond, line, arc and logo, each tagged with a layer and a paint. Every native backend draws this list. - Direct raster backend (spec §2.2, §2.5, acceptance criteria 2 and 4):
ckey_render_scalable_rasterturns the geometry into pixels with no SVG, file system, network or graphics library.- Output: RGBA8 (straight alpha) or GRAY8.
- Three raster policies:
COVERAGE: supersampled antialiasing.BINARY: a pixel is ink when at least 50% of its samples are covered.HYBRID: coverage, with marks thinner than a minimum feature, 1 px by default, widened to it.
- Transparency: in transparent mode the background is not painted and unpainted pixels have alpha 0.
- Materials: natively rendered approximations of sheen, vignette, grain, drop shadow and bevel. The logo is supplied by the caller as RGBA and drawn into its clip circle.
- PNG export:
ckey_encode_png, with DEFLATE implemented in the core (fixed Huffman codes, LZ77), RGBA8, GRAY8 or 1-bit, and pHYs. There is no zlib dependency. - PDF vector export (spec §2.3–2.4):
ckey_render_scalable_pdfwrites a one-page PDF 1.4 with exact paths, arcs as cubic Béziers, flat ink, accents and background, and an optional transparent mode. - Print path:
ckey_render_scalable_printnow rasterizes the geometry directly, with the binary policy and a 3×3 sample grid, instead of generating SVG and parsing it back. The core no longer includes the SVG parser, which stays a test and reference tool. - CLI:
encode-scalablegains--raster out.png --size-px N --policy coverage|binary|hybrid --transparent yes|noand--pdf out.pdf(--size-insets the width).--pngandprint-sheetuse the core print raster and PNG encoder.
- New test
ckey_native_render:- The direct raster matches the rasterized SVG export to within 0.01% of pixels, from SVG's 4-decimal rounding, at v2, v11, v20 and v31 across shapes, ring styles and caps.
- All three policies decode at 7 px/module for v1, v9 and v31 in both layouts, and the output is deterministic.
- HYBRID adds ink to thin features.
- Transparent margins have alpha 0.
- The concept preset with depth, grain and a logo decodes.
- Geometry API layers are checked.
- PNG round-trips through an independent inflater.
- PDF cross-reference offsets are valid.
- Print output is pure ink or paper.
- No format changes, and conformance hashes are unchanged.
- The partial
services/openckey/files committed by accident in build 61 are finished in the next build.
0.1.0-build.61 — 2026-11-05
- Version scheme: from this build, versions are
0.1.0-build.Nand release tags arev0.1.0-build.N, as the maintainer chose. Builds 1–60 keep their0.1.0-dev.Nnames in this log. See the map. - Default look (specification §4): with no style, every profile now renders black ink on white. This covers the P0 default style and the P1–P3 SVG renderers.
- Presets: the previous cream-on-black concept look is a named preset,
ckey_style_preset_fill(style, CKEY_PRESET_CONCEPT). The CLI's--preset conceptuses it. - Mac renderer: defaults to black on white. Its colour swap for P1–P3 now goes through placeholders, so a black background cannot be repainted as ink.
- No format changes. Site hashes are unchanged; only SVG colours changed.
- Added
docs/adoption-and-telemetry.md, the normative telemetry definition:- modes 0/1/2 and what switching between them does;
- what counts as a scan session;
- the batch schema, version 1;
- the openckey.org service's obligations.
0.1.0-dev.60 — 2026-11-05
- Cleaned up
CHANGELOG.md:- Removed the duplicate dev.11 and dev.42 entries.
- Restored newest-first order.
- Recorded what happened to dev.27–30: dev.28's entry had been folded into dev.31, and the other three were never committed builds.
- Added a header that explains the log.
- Added
CHANGELOG-STABLE.mdfor taggedStable-Releasereleases (none yet) andCHANGELOG-COMMUNITY.mdforcommunitymerges. Each has an entry template and rules. - Added
docs/RELEASE-AND-VERSIONING-MAP.md. It covers:- how the software, format, profile and ABI numbers relate;
- the current support matrix, including legacy formats that still decode;
- the history of all 28 formats, with byte, profile, introducing build and status;
- the ABI history;
- a build-to-commit table;
- the procedures for cutting and deprecating a release.
- README: added sections on the repository, its branches, releases, versions, changelogs and documentation. The current-format list now includes Profile 0 and 0.1.
tools/check_version.pynow also requires the map and both branch changelogs to exist and be linked from the README.- No code or format changes.
0.1.0-dev.59 — 2026-11-05
- Work moves to the maintainer-only
scratchbranch. It was created frommainat47f80a9;communityandStable-Releaseare being set up by the maintainer. - Added the consolidated Rendering, SDK, Distribution, Adoption & Telemetry Specification (
docs/SPECIFICATION-rendering-sdk-distribution-telemetry.md), as written by the maintainer. - Added
docs/IMPLEMENTATION-STATUS.md, which maps every section of that specification to the current code. It also flags five conflicts:- the print path rasterizes through SVG;
- there is no transparent output;
- the default palette is cream on black, not black on white;
- the style check certifies from WCAG contrast alone;
- the scanner and renderer ship as one library.
- Added
docs/BRANCHES-AND-RELEASES.mdwith the branch model and release rules. Releases are immutable tags onStable-Release, and deprecated releases are retitledDeprecated - {release name}. - No code changes.
0.1.0-dev.58 — 2026-11-04
- Profile 0.1, a print-robust layout (Format 0.28.0, byte
1C).- Every mark and gap is at least about one module: equal-arc ring slots (dots at least one module apart on every ring), 0.3-module ring dots, 0.35-module rays at least one module apart, and a compact 8-slot Ring Key.
- Shared with P0: the same skeleton, 31-version table, framing and correction levels.
- Identification: the decoder tells the layouts apart by their keys.
- Simulated result: the same payload decodes at about half Profile 0's printed width. For example, on an old inkjet with plain paper: 30 B at 0.24 in (P0: 0.42), 120 B at 0.32 in (0.68), 1,200 B at 0.91 in (1.47).
- ABI 3:
ckey_scalable_symbolgainslayout, and the P0 encode, decode, capacity and logo-radius calls take a layout.ckey_decode_scalable_gray8also reports it. - Print output.
ckey_render_scalable_printrenders black ink on paper on the printer's dot grid, with no grey for halftoning.- The CLI gains
encode-scalable --png --size-in --dpi --layoutandprint-sheet, a self-identifying calibration ladder written as a 1-bit PNG that records its dpi. - The CKey Renderer gains a Layout picker and Export Print PNG….
- Print simulator (
tests/print_sim.h): binary device dots, ink spread, paper blur, then a camera at any resolution.- Findings for P0: dark-on-paper prints about 35% smaller than the cream-on-black palette on plain inkjet. Ink-spread compensation does nothing at 600 dpi, because the spread is about one dot. Ring dots fail first.
- Regression test: a 120-byte payload at 0.42 in on the inkjet model must fail as P0 and decode as P0.1.
- The reader shows
Profile 0.1 · print · v<N>. Guides added:spec/CKey-Printing.mdandspec/CKey-Format-v0.28.0.md. The reference rasterizer moved tosrc/svg_raster.h.
0.1.0-dev.57 — 2026-11-04
- Profile 0 design system (
spec/CKey-Design-System.md). Styling changes how a symbol is painted, never where a reader samples.- Fixed: the frame, finders and keys keep their geometry.
- Mark shapes: payload modules can be rounded, square, circle or diamond; ring marks joined or dotted; rays round or flat.
- Paint: colour is free within checks: metallic sheen, radial vignette, up to four accent colours, bevel, depth and grain.
- Logo: sits in the empty centre, or larger on a plate within an error-correction budget.
- API:
ckey_style,ckey_check_scalable_style(contrast ≥ 3:1, one polarity, effect limits, logo budget ≤ 50% of the worst block),ckey_render_scalable_styled_svg,ckey_scalable_logo_max_radius,ckey_scalable_logo_load. The plain P0 renderer is now the default style.
- P0 decoding no longer depends on the finders' split or the empty centre. Its skeleton is the frame stroke plus all eight finder arm ends, against the moat and quiet margin, so it is symmetric by design. Orientation comes from the Grid, Ring and Ray Keys. A logo in the centre therefore costs no calibration evidence. No wire change.
- Tests. All 16 mark-shape combinations decode at v2 and v20. The concept palette passes the checker. Low-contrast, mixed-polarity and heavy-shadow-on-light styles are refused. At every level, the largest logo the checker allows still decodes. The test rasterizer gained polygons,
<defs>, background detection and painter's-order logo plates. - Real-browser check. The concept look rendered in Chromium (champagne sheen, navy vignette, sage/grey accents, bevel, depth, grain, PNG logo) decodes exactly at v6, v11 and v20, sharp and blurred.
- CKey Renderer: a Profile 0 Design panel (shapes, sheen, vignette, accents, bevel, depth, grain, logo picker, size, plate, Concept preset), with the style check shown live.
- CLI:
encode-scalablegains--preset plain|concept,--modules,--rings,--rays,--logo <file>and--logo-radius. - Known limit: Profile 0 scatters each byte's bits across the symbol. That keeps stripes and smudges cheap but makes covered area expensive, so logos currently fill the empty centre (about 22% of the width) with little room beyond. Byte-grouped placement would be a future wire-format change.
0.1.0-dev.56 — 2026-11-04
- Profile 0, the scalable family (Format 0.27.0, byte
1B, profile00). Added alongside Profiles 1–3, which are unchanged.- One skeleton at 31 sizes. Every version shares Profile 2's frame, finders, rings and dial in the 29-unit field. Only the module pitch changes, from 29 to 232 modules across (normative integer tables), about 7% finer per step.
- No appearance jumps. Capacity at level M rises smoothly from 27 to 4,619 bytes, with no step above 1.6×. A 33-character URL is v2, which looks like a locator, not Profile 2.
- No filler waste. Every site carries a codeword bit. Four correction levels are available: L/M/Q/H.
- The keys identify the version. The Grid, Ring and Ray Keys are drawn at each version's own module and slot pitch, so the decoder recognizes the version from them. The frame's version byte, RS and CRC confirm.
- New core API:
ckey_encode_scalable,ckey_decode_scalable,ckey_decode_scalable_gray8,ckey_calibration_score_scalable_gray8,ckey_render_scalable_svg,ckey_scalable_capacity,ckey_scalable_modules_across, andCKEY_FIELD_SCALABLEforckey_refine_quad_gray8. - Localization improvements (all profiles):
- Border candidates are ranked by how well the shared skeleton fits, so a dense symbol's interior components can't crowd out its border.
- Per-corner refinement iterates down to sub-pixel steps.
- P0 aligns on the frame stroke's two edges with coarse-to-fine sample spacing. At v31 the corners resolve to 0.06–0.22 modules, from 2–5.5 px before.
- Tests and tools.
- New
ckey_scalable_profile0suite. - The simulated reader covers P0 v1/v2/v11/v20/v31 and now decodes 144/144 scenes.
- New CLI command:
ckey encode-scalable [--version 1-31] [--level L|M|Q|H].
- New
- Apps.
- The iOS reader tries P0 first and shows
Profile 0 · v<N>. - The CKey Renderer defaults to P0, with version and correction pickers, and its read check reports
px/module. - Both use 64 KB output buffers, because P0 payloads exceed P3's 2,048 bytes.
- The iOS reader tries P0 first and shows
0.1.0-dev.55 — 2026-11-04
- Payload conventions. New informative document,
spec/CKey-Payload-Conventions.md. It defines how readers interpret text payloads:- Standard URI forms:
https:/http:,mailto:,tel:(E.164),sms:,geo:(RFC 5870), and vCard. - One CKey convention:
address:followed by a free-text street address, handed to the platform map app. - Safety rules: never act automatically, allowlist only, keep the payload visible, and validate before offering an action.
- No wire format changes.
- Standard URI forms:
- iPhone reader actions.
- The reader offers one tappable action per recognized payload: Open, Email, Call, Message, Show in Maps (
geo:andaddress:, throughmaps.apple.com, which iOS routes to Maps), or Add to Contacts (vCard, through the share sheet). javascript:,data:,file:and unknown schemes are shown as text only.- Text detection now accepts CR, which vCard line endings use.
- The reader offers one tappable action per recognized payload: Open, Email, Call, Message, Show in Maps (
0.1.0-dev.54 — 2026-11-04
- The iPhone reader shows decoded payloads as text. A payload that is valid UTF-8 without control characters (other than tab and newline) is displayed as text. An
http/httpsURL gets an explicit "Open host" button and never opens automatically. The hex stays underneath for checking, and binary payloads still show hex. - First successful live scan: the dev.53 reader decoded
https://citeory.com/touron the maintainer's iPhone.
0.1.0-dev.53 — 2026-11-04
- The iPhone reader started almost every decode from the wrong orientation, so P1 never scanned and P2 rarely did. Its border detector oriented each candidate from the border's second moments (principal axes). A square outline's second moments are the same in every direction, so that fit cannot orient a square, and the angle came from pixel noise.
- On rendered P1/P2 symbols, an upright symbol was fitted at −45°, a diamond around the square. Rotations from 0° to 30° gave orientation errors of 11–45°.
- The refinement that followed could only scale, shift and nudge corners. It could not recover.
- Full-frame localization moved into the shared C++ core, so it is tested here and identical on every platform.
ckey_find_borders_gray8orients each border from its convex hull's minimum-area rectangle, which is exact for a square. It then line-fits each side's straight middle for a perspective-correct quadrilateral.- It requires the whole border in view, instead of capping the border at 90% of the frame. That cap rejected large rotated P3 symbols.
ckey_refine_quad_gray8starts from the known border-to-field scale (29/28.65). Its descent covers scale, rotation and offset, then per-corner moves.- The iPhone reader now calls both functions. Its Swift border finder, threshold, and principal-axis fit are deleted.
- New simulated-reader test (
ckey_simulated_reader). Rendered symbols are composited into full 1080×1920 (P1/P2) and 2160×3840 (P3) camera frames with background clutter, rotation 0–33°, 8% keystone, 3×3 blur, noise, and dark-on-light polarity. The test then runs the reader's exact pipeline.- Result: 80/80 scenes decode, with 16 skipped because the rotated symbol cannot fit in the frame.
- Restoring the principal-axis orientation drops this to 51/80.
- Measured cost per frame on the CI-class CPU: about 28 ms (1080p) or 42 ms (4K) to find borders, plus about 11 ms per candidate to refine all three profiles.
0.1.0-dev.52 — 2026-11-04
- Ignore
macos/build/andmacos/DerivedData/. A command-linexcodebuildof the renderer writes there; only/build/and/ios/build/were ignored. - Recorded the first verified CKey Renderer build:
xcodebuild(Xcode 27A9269, macOS 27.0 SDK, arm64 + x86_64) succeeded on the maintainer's Mac with the dev.51 Swift changes.
0.1.0-dev.51 — 2026-11-04
- The iPhone reader could not decode Profile 3 at all. It captured 1920×1080, but P3 needs about 11 px per symbol unit, about 1,280 px across its 116-unit field, which is more than the frame's height. Its border detector also capped candidates at 78% of the short frame side.
- The reader now prefers 4K capture, falling back to 1080p.
- The border search scales its sampling step with frame size, so it keeps about 960 × 540 points and the same angular resolution at constant cost.
- The size limits scale with that step, and the upper bound is now 90% of the short side.
- Not yet compiled or run on a device in this environment.
- The CKey Renderer's preview read check now reports the raster density it decoded at. It flags results below each profile's decode floor, so a P3
FAILcaused by a small window or the Resolution slider is distinguishable from a symbol fault. - The app READMEs now describe how to confirm a rebuild picked up the current core, and what correct P2/P3 output looks like.
0.1.0-dev.50 — 2026-11-04
An independent second review of dev.49 was run under rule 7 and every verified finding is resolved. Formats 0.25 and 0.26 are unchanged on the wire; their specifications gain clarifications only.
- P3 isolated ring dots under blur. Each 3×3 blur turned every isolated P3 ring dot into a 0. The reviewer measured 608/608 failing at 12 px/unit, and P3 failed with two blurs at every density. Ring sites are now re-thresholded by neighbour context, with fill sites' known values as the anchor. P3 now decodes 3/3 at 10–16 px/unit through two blurs. P2 now survives one blur at 10 px/unit and two blurs at 12.
- Threshold bound. The two-means cut bound widened from [0.2, 0.8] to [0.05, 0.95]. P3 width coverage separates near 0.85.
- P2 calibration reference. One "empty" reference, at (5.626, 5.626), was a payload site under the new safe area. It now samples the finder's split gap at 225°.
- Faster dense decoders. They gate each orientation on fixed-key agreement (≥ 80%) before sampling every site. On a 1080p noise frame, P3 decode fell from 18 ms to 0.42 ms per call and P2 from 0.34 ms to 0.05 ms. Calibration scores are value-identical.
- Specification clarifications. v0.25/v0.26 now give full render geometry, the explicit SplitMix32 definition and whitening bit order, the P3 Gray component order, the gap measurement basis, the reason for the ring-33 Ring Key clear field, and an integer-only conformance vector.
- Tests.
- The layout tests now check known-answer vectors.
- They measure the Cartesian-to-radial-alphabet ink gap; it is 0.58 in both profiles.
- They enforce the documented boundary slack.
- The round-trip tests add blur across densities and noise rejection.
- The SVG payload layer is split into
ckey-data-cartesianandckey-data-polar. - A dead branch was removed.
0.1.0-dev.49 — 2026-11-04
- Profile 2/3 image decoding fixed. At HEAD, neither profile could decode its own clean renders at any resolution. The sampler's fixed ±0.12-unit support, sized for P1's one-unit modules, averaged P2/P3's 0.10–0.20-unit dots and rays below threshold. Each feature class now uses a support matched to its width and a threshold calibrated from its own samples (two-means). P3 ray width is read as integrated coverage.
- Dead space removed. These changes ship as Profile 2 Format 0.25 (byte
19) and Profile 3 Format 0.26 (byte1A). Every site now carries a value, and sites are ordered by a keyed bijective hash so the codeword is spread uniformly. A specified SplitMix32 whitening stream (modulation, not ECC) prevents payload-dependent empty or solid regions. The previous P2 layout left everything below y = 22.75 empty. In the previous P3 layout, 400 of 573 rays were blank stubs. - Safe area enforced. Payload modules now keep a declared ink clearance from the frame, from the finder arcs (including round caps and the concave side), from the Grid Key, and from the radial alphabet. The old moat let modules overlap finder ink (P2 −0.32, P3 −1.5 units).
- P3 polar join. The ring field and Ring Key move outward (24.62 / 25.11), so the Ring Key-to-ray gap matches P2 (1.19 units) instead of a 1.85-unit dark annulus.
- Ring arcs over half a turn now set the SVG large-arc flag. Previously they were drawn as the complementary short arc on the wrong side of the ring.
- Profile 1 decoder (format unchanged). P1's empty reference at (1.5, 11.5) was a payload module, which skewed the threshold whenever that bit was set. It now uses a point in the polar aperture. Thresholds are also per class. On 40 random renders, failures at 6–8 px/unit fell from 19/40 to 0/40, and the committed iPhone fixtures still decode. The P3 calibration score's polar empty reference was a data ray and has moved too.
- Tests now run in Release.
assert()was compiled out underNDEBUG, so CI executed none of the checks. Tests use an always-onCKEY_CHECK. New suites cover render → rasterize → decode round trips for all profiles (including all-zero/all-FFpayloads, rotation, winding, inversion, keystone and blur) and white-box layout checks for site counts, clearance-boundary stability, uniform spread, measured ink gaps and dead space. CI adds a Debug ASan/UBSan job. - Site layouts are built once and cached instead of on every call. On a 1080p noise frame, P3 decode fell from about 27 ms to 18 ms per call. The remaining cost is sampling all 8 orientations when the cheap contrast gate passes.
- The image decoders and calibration scores share one argument check (finite coordinates,
height × strideoverflow). - A corrupt Profile 2 length field now returns
CKEY_INTEGRITY_FAILUREinstead ofCKEY_INSUFFICIENT_BUFFER. - The CLI rejects malformed hex such as
1g,-1,1and0x, and reports real profile and format numbers. - Stale format references corrected in the README, CONTEXT, header and code comments. The three
patches/files no longer applied and were removed (they remain in history).
0.1.0-dev.48 — 2026-11-04
- Enlarged the radial safety moat surrounding the actual P2/P3 finder arcs and closed the unnecessary annular gap between each radial alphabet and Cartesian field. P2 emits Format 0.23; P3 emits Format 0.24.
- Corrected the dev.47 real-time diagnostic string so the iOS reader builds.
0.1.0-dev.47 — 2026-11-04
- Added a live reader diagnostic panel: detected border side, candidate count, independent P1/P2/P3 key-fit scores, decode-attempt time, and per-profile integrity outcome refresh while scanning.
0.1.0-dev.46 — 2026-11-04
- Added an independent native Profile 2 calibration-score ABI and reader fit. Profile 2 no longer uses Profile 1 key coordinates before projective sampling.
0.1.0-dev.45 — 2026-11-04
- Added Profile 2 Format 0.22, correcting its Cartesian finder clearance from four square reservations to the actual curved finder quadrants.
0.1.0-dev.44 — 2026-11-04
- Corrected Profile 3 finder clearance to reserve the finders' true outer corner quadrants. This removes the four false inward wedges and prevents Cartesian payload marks from printing behind the visible finder arcs.
- Added Profile 3 Format 0.21: all 34 ring rows now occupy the same outer radius while preserving a 7-unit central quiet zone.
- The iOS reader now fits compact (P1/P2) and extended (P3) candidates against their own calibration fields. A calibration score from one profile can no longer choose the sampling transform for another profile.
0.1.0-dev.43 — 2026-11-03
- Replaced the live reader's generic Vision rectangle path with a measured border-component locator. It fits an oriented quadrilateral from the continuous frame, then independently refines all four corners against the permanent Grid, Ring, Ray, and finder keys before decoding.
- Explicitly selects the physical back wide camera, holds 1× zoom, limits focus to the far range, and disables video stabilization so the capture geometry does not switch focal systems mid-scan.
- Added a reproducible synthetic training script and generated on-device logistic candidate ranker. It only orders measured border components; structural keys plus RS and CRC remain the decode acceptance gate.
- Added Profile 2 Format 0.19's border safety moat and Profile 3 Format 0.20's 34-ring filled polar field and 5-unit frame moat. These mappings prevent payload marks from spilling into the frame and remove the large unused P3 centre.
0.1.0-dev.42 — 2026-11-03
- Added Profile 3 capacity/ECC tiers at 256, 384, 512, 768, 1,024, 1,536, and 2,048 payload bytes. The fixed optical codeword stays fully populated; each tier changes the RS data/parity split, and automatic encoding selects the smallest tier that fits.
- Added deterministic SplitMix32 visual fill to new Profile 2 and Profile 3 frames, protected by RS and checked by frame/CRC validation. This prevents short payloads from rendering as mostly empty fields; it provides no secrecy.
- Kept decoders compatible with legacy Profile 2 and 3 frames, and added the 0.17/0.18 format specifications.
- Fixed the Mac renderer's stale-preview behavior on invalid input, stopped padding Profile 1 text into a different payload, debounced regeneration, updated preview effects without reloading the SVG, and rendered Profile 3 at the same module scale as lower profiles.
- Expanded live scanner candidates from the visible border bounds to account for the border's inset from the canonical sampling field. This is a geometry correction; renderer-origin camera scans still need physical-device validation.
- C++ core tests, optical locator fixtures, and version-node validation pass. Xcode builds and physical iPhone scans are not available in this environment.
0.1.0-dev.41 — 2026-11-03
- Reworked the iOS scanner hot path to try measured quadrilaterals directly against Profiles 1, 2, and 3 before any search. Vision now runs on alternating frames as a rotation/perspective fallback; continuous key-based refinement is restricted to one leading candidate instead of every candidate. Camera capture resolution remains adaptive at 1080p/high.
- Split detection and CKey decode timing so the displayed measurements no longer include the same work in both values. Updated scanner documentation to distinguish experimental multi-profile camera paths from camera-validated performance.
- No on-device speed, distance, or reliability target is claimed yet. Xcode and a physical iPhone are required to build and characterize the live scanner.
0.1.0-dev.40 — 2026-11-03
- Fixed Swift/C interop in the macOS renderer: C diagnostic message storage is converted from its imported fixed-size tuple safely, and SVG output buffers are passed through scoped mutable buffer pointers. This resolves the renderer's Xcode compile error without changing C ABI or wire-format behavior.
- Bumped all current software-version nodes. The CKeyReader and renderer still require Xcode validation on macOS; this Linux workspace cannot run Xcode.
0.1.0-dev.39 — 2026-11-03
- Corrected the macOS renderer project's current-SDK import and runtime status interpolation, keeping its UI build path explicit and versioned.
0.1.0-dev.38 — 2026-11-03
- Added the shared C ABI contracts required for projective grayscale sampling of the Profile 2 and Profile 3 encodings. The Mac rendering laboratory and camera reader use the same versioned native core.
0.1.0-dev.37 — 2026-11-03
- Removed the stale Grok-era nested-finder rewrite script so no repository tool can reapply rejected protruding or nested finder geometry.
0.1.0-dev.36 — 2026-11-03
- Applied the approved one-arc, inward-facing rounded-corner finder to all profiles. Profile 2 now emits Format 0.15 (
0F); Profile 3 now emits Format 0.16 (10). Their legacy Format 0.9/0.10 codewords remain decoder-readable. - Added profile-specific format documents and tests asserting each encoder emits its versioned frame byte and the common canonical finder SVG construction.
0.1.0-dev.35 — 2026-11-03
- Established the approved finder construction as CKey Format 0.14.0 / byte
0E: a continuous rounded-square border and exactly one broad inboard arc per corner. Every arc opens toward the central polar field; only the top-left arc is split for orientation. - Applied this normalized construction to the Profile 1 locator, Profile 2 text/binary renderer, and Profile 3 extended renderer. Added profile-specific SVG regression assertions for the one-arc geometry and retained reader calibration sampling of the same signature.
0.1.0-dev.34 — 2026-11-03
- Replaced the still-incorrect inside-corner interpretation with CKey Format 0.13.0 / byte
0D. Finder arcs now form the symbol's convex external rounded corners; frame side segments terminate into the outermost finder arc. Only the top-left finder set is split for orientation. - Updated reader calibration geometry and Profile 3 finder reservations to the external-corner definition. Historic formats 8, 11, and 12 remain decoder-readable; new locators emit format 13.
0.1.0-dev.33 — 2026-11-03
- Superseded the rejected dev.32 nested-finder interpretation with CKey Format 0.12.0 / byte
0C: one broad rounded-corner arc per corner, aligned to the structural rounded border. The top-left arc alone has the measured diagonal split; it does not project a three-finger pattern into payload space. - Updated Profile 3 clearance and shared reader calibration samples to the actual single-arc geometry. Formats 8 and 11 remain decoder-readable for historic fixtures; new locator encodes emit format 12.
0.1.0-dev.32 — 2026-11-03
- Introduced CKey Format 0.11.0 / byte
0Bfor the locator's reference-oriented finder correction. Each corner now has three inset, edge-oriented, round-capped quarter arcs; top-right, bottom-right, and bottom-left sets are continuous, while every top-left arc has a measured 0.85-module diagonal clear gap. - Applied the same proportional finder renderer to all capacity profiles and corrected Profile 3's reservation geometry to follow the real inset arc envelope rather than the previous large leaf-shaped clearance.
- Added finder-signature samples to the native continuous calibration score used by CKeyReader's geometry refinement. These samples are localization evidence only; Grid/Ray/Ring keys plus RS and CRC remain the decode acceptance gates. Format 8 remains decoder-readable for historical camera fixtures but is no longer emitted.
0.1.0-dev.31 — 2026-11-03
- Added experimental Format 0.10.0 Profile 3 for 1–2,048 byte payloads: ten byte-interleaved systematic RS(255,223) blocks, 320 total parity bytes, CRC-32C, deterministic codeword decode, and SVG rendering.
- Expanded polar capacity by lateral geometry rather than dot shrinkage: 24 rings at 288 angular slots, exact run-length arcs, and 573 data rays with a calibrated 3-bit Gray-length/stroke-weight alphabet. Cartesian candidate order is a deterministic two-dimensional permutation so all usable regions fill evenly instead of forming top-to-bottom or radial dead zones.
- Restored the Grid Key to a 2×2 block made of the exact same 0.34-unit marks and 0.5-unit pitch as Cartesian payload; it now genuinely calibrates payload scale and clear-space ratio.
- Restricted Profile 3 finder reservation to its curved finder strokes and guard bands rather than an entire corner square.
- Excluded the structural-border guard from Profile 3 payload placement after visual inspection found modules outside the rounded frame.
- Reserved the interior of each curved finder as well as its stroke guard, while leaving the surrounding exterior Cartesian field available for data.
- Preserved the camera-validated Format 0.8 locator unchanged. Profile 3 image/mobile decoding remains unimplemented and is explicitly not camera validated.
0.1.0-dev.30, dev.29, dev.28, dev.27 — 2026-11-03
- dev.28 (
98cdcb9) first added Profile 3, Format 0.10.0. That entry was folded into the dev.31 entry above when dev.31 corrected it, so its text appears there. - dev.27, dev.29 and dev.30 have no commit that changed
VERSIONand no recorded entry. They were not published builds.
0.1.0-dev.26 — 2026-11-03
- Added experimental Format 0.9.0 Profile 2 for 1–200 byte text/binary payloads: a framed full RS(255,210) codeword with 45 parity bytes, CRC-32C, and deterministic SVG rendering in a denser 58×58 Cartesian / 144-slot eight-ring polar field.
- Added the public
ckey_text_symbol, text encode/decode APIs, ackey_render_text_svgrenderer, andckey encode-text --utf8/--hexCLI commands. Core tests verify a 200-byte round trip and correction of 22 distinct byte errors; renderer output is XML-valid and includes connected multi-unit payload arcs. - Preserved the Format 0.8.0 locator and its camera reader. Profile 2 is not yet accepted by the grayscale/mobile image decoder and must not be represented as camera validated until its own sampling, real-capture, blur, damage, and noise suite passes.
0.1.0-dev.25 — 2026-11-03
- Replaced discrete scale/offset ladders in the iPhone reader with continuous, key-driven quadrilateral refinement. The new C ABI calibration-score operation evaluates the permanent Grid, Ring, and Ray keys for contrast and expected evidence under a proposed projective field; it never accepts a payload.
- The reader starts from each observed border/rectangle, then performs a shrinking-step coordinate search over physical scale and position to maximize that score before one shared-core decode. This removes fixed distance intervals from localization while retaining the decoder's RS and CRC acceptance checks.
- Kept C ABI version 2 and Format 0.8.0 unchanged: the new function is an additive ABI entry point. Physical-device benchmark evidence remains required.
0.1.0-dev.24 — 2026-11-03
- Reverted the dev.23 localization throttle and candidate caps after physical testing reported slower, less reliable reads. Restored the dev.22 farther-reading search behavior rather than retaining a regression.
- Configured the rear capture stream for 1920×1080 where supported (falling back to
.high) and enables continuous autofocus plus continuous autoexposure. This addresses the acquisition limit directly: a distant CKey needs sufficient pixels per module before any decoder can recover blur, noise, or damage. - Kept format 0.8.0 unchanged. This is a recovery and acquisition-quality change; benchmark results remain unclaimed pending device measurements.
0.1.0-dev.23 — 2026-11-03
- Made the border-first CKey locator the bounded hot path: up to six square-border candidates and three framing hypotheses are tested per sampled frame. The earlier broad Vision scale/offset sweep could attempt up to 1,800 core decodes per frame, producing the slow, intermittent far-distance reads reported from dev.22.
- Throttled generic Vision localization to once per 300 ms, capped it at eight candidates and three framing hypotheses, and retained it only as a fallback for rotated or projective symbols. The direct border locator is sampled every 80 ms and accepts dimmer blurred display edges before the calibration/ECC/CRC checks reject false candidates.
- Kept format 0.8.0 unchanged. Physical-device latency and damage/blur/noise recovery still require benchmark evidence.
0.1.0-dev.22 — 2026-11-03
- Added a CKey-specific, luminance connected-component locator before Vision rectangle analysis. It searches for the continuous bright rounded-square border at half resolution and tests the recovered square bounds directly with the shared C++ decoder.
- This directly addresses the dev.21 field result: Vision still failed to propose the distant symbol despite the core successfully decoding a 135 px camera-derived fixture when supplied its field corners. Vision remains as the fallback for rotated and projective candidates.
- Kept format 0.8.0 unchanged. This Swift implementation requires Xcode/iPhone validation and has no distance or latency claim until measured.
0.1.0-dev.21 — 2026-11-03
- Fixed distant-symbol candidate selection: the reader previously ranked generic Vision rectangles by area and only tested the largest eight, which the field recording shows were laptop/display rectangles rather than the contained CKey.
- Added a second Vision request for small, near-square candidates (up to 64 observations) and ranks the merged candidate set by squareness before testing up to 24 candidates. The expensive refinement is limited to the leading four candidates.
- Kept format 0.8.0 unchanged. This fix requires iPhone/Xcode validation.
0.1.0-dev.20 — 2026-11-03
- Expanded the far-distance fallback from 12 to 18 scale hypotheses (0.25×–1.80×) and from nine to 25 center shifts per scale for each of the six leading candidates.
- Added on-screen Vision candidate-size diagnostics to reveal whether the square detector is selecting the symbol, its surrounding canvas, or a larger object.
- Kept CKey Format 0.8.0 unchanged. The wider fallback is not yet compiled or benchmarked on-device; the UI reports the candidate bounds for the next field test.
0.1.0-dev.19 — 2026-11-03
- Broadened the distant-symbol localization fallback to test 12 candidate scales from 0.40× to 1.40× and a 3×3 center-shift grid for each of the six leading Vision squares. The existing small set of fast hypotheses still runs first.
- Kept format 0.8.0 unchanged. The wide fallback has not yet been compiled or benchmarked on-device; far-camera fixtures demonstrate decoder performance only when corners are supplied.
0.1.0-dev.18 — 2026-11-03
- Fixed the Swift compiler type-check timeout in quadrilateral generation by using explicit Double conversions and an imperative coordinate loop.
- Replaced deprecated iOS 17 camera orientation properties with supported video rotation angle APIs.
- Kept wire format 0.8.0 unchanged. Xcode build verification requires the user's Apple toolchain.
0.1.0-dev.17 — 2026-11-03
- Added a coarse-to-fine camera localization fallback: the six leading square candidates are tested at smaller and larger scales with small center shifts when the fast hypotheses fail. This addresses distant targets whose display boundary is detected instead of the symbol boundary.
- Added a far-camera regression image with a 135 px symbol (~4.7 px/module); the C++ image decoder recovers its payload when supplied the observed field corners.
- Kept format 0.8.0 unchanged. The far-distance fixture validates image decoding with known geometry; live Vision localization and latency still require physical-device measurement.
0.1.0-dev.16 — 2026-11-03
- Fixed the iPhone reader's corner-expansion helper: it previously ignored each requested scale, causing every candidate to use the same quadrilateral.
- Increased camera sampling from 8 to 20 frames per second and exposed CKey check latency while scanning, alongside Vision detection latency.
- Added a grayscale camera-preview regression crop from the user's laptop-screen capture; the shared C++ decoder recovers its locator payload with the captured perspective and rasterization.
- Kept wire format 0.8.0 unchanged. Camera live performance is not yet independently measured on the user's iPhone; QR-parity performance is not claimed.
0.1.0-dev.15 — 2026-11-02
- Fixed a throttled UI status update that left the reader stuck on “Testing square candidates…” after each frame.
- Candidate frames now publish their final CKey validation result immediately; empty-frame progress remains throttled.
0.1.0-dev.14 — 2026-11-02
- Loosened Vision square-candidate thresholds and added nearby quadrilateral scale hypotheses for the rounded CKey frame.
- Added live reader status showing whether Vision found candidates or the CKey structural/ECC checks rejected them, plus ongoing localization timing.
- Added a regression image from the user's exact CKey target at 20 px/module; the C++ image decoder reads its payload successfully. iPhone camera localization still requires on-device validation.
0.1.0-dev.13 — 2026-11-02
- Fixed two SwiftUI color inference errors in the iPhone reader by making foreground and status colors explicitly use
Color. - Versioned the build fix. Apple-platform compilation still needs verification in Xcode.
0.1.0-dev.12 — 2026-11-02
- Added an experimental iPhone SwiftUI reader that uses Vision for square-candidate localization and calls the existing C++ C ABI for pixel decoding.
- Added an Xcode project, camera permission copy, live result display, and separate Vision/CKey timing readouts; the app compiles
src/ckey.cppdirectly without duplicating encoding or decoding logic. - Recorded iPhone build/run instructions and current camera-validation limits. The app has not been compiled or tested on an Apple device in this environment.
0.1.0-dev.11 — 2026-11-03
- Added C ABI grayscale image decoding for a caller-supplied symbol quadrilateral, with projective rectification, calibration-key checks, polarity normalization, data sampling, RS correction, and CRC-32C validation.
- Added an optical PGM fixture cropped from a browser-rendered v0.8 symbol; tests cover actual pixel-to-payload decode, rotated quadrilateral order, inverted polarity, and invalid geometry.
- Kept wire geometry at CKey Format 0.8.0. Full-frame symbol localization, lens-distortion correction, camera video scanning, and camera robustness benchmarks remain open.
0.1.0-dev.10 — 2026-11-03
- Corrected the finder interpretation to match the supplied geometry blueprint: one thick quarter-arc at bottom-left, top-right, and bottom-right, with the top-left arc split into two pieces for orientation.
- Kept the corner centerline radius at 4.5 modules and made each arc a 1.0-module band with round caps; the split has a one-module visible gap.
- Versioned the geometry as CKey Format 0.8.0 / format byte 08 and regenerated the CRC-32C/Reed–Solomon fixture. The payload, RS code, and C ABI remain unchanged.
0.1.0-dev.9 — 2026-11-03
- Restored three nested quarter-arc finders at all corners, with the three top-left arcs split by a one-module orientation gap.
- Made all inner-ring and Ring Key dots the same 0.30-module diameter; Ring Key arc caps are round while its visible length remains exactly four angular pitches.
- Encoded each of the 69 data dial bits by a short 0.65-module ray or long 1.35-module ray; calibration rays remain reserved and fixed.
- Versioned the wire geometry as CKey Format 0.7.0 / format byte 07 and regenerated the CRC-32C/Reed–Solomon example vector. The RS code and C ABI are unchanged.
0.1.0-dev.8 — 2026-11-03
- Increased the central clear radius and moved the four rings outward into a tighter radial group.
- Sized each ring dot to 72% of its adjacent-slot chord, so marks are visibly sized and closely spaced at every ring radius.
- Set the Ring Key arc width to one dot diameter and its centerline length to exactly four slot intervals.
- Versioned the geometry as CKey Format 0.6.0 / format byte 06; the RS(77,26) code and ABI remain unchanged.
0.1.0-dev.7 — 2026-11-03
- Fixed oversized ring dots: SVG circles inherited the parent group’s default 1-module stroke. Circle marks now explicitly use no stroke, rendering at their specified 0.12-module diameter.
- Added a renderer regression assertion for stroke-free 0.06-radius dots. The four-slot Ring Key arc remains 0.12 modules wide and spans the same four angular slots.
0.1.0-dev.6 — 2026-11-03
- Reduced ring data dots and Ring Key dots to 0.12-unit diameter; made the four-slot Ring Key arc exactly match four angular slots and dot diameter.
- Increased locator protection to shortened RS(77,26), adding 51 mathematically computed parity bytes and using 616 of 621 eligible sites for codeword bits.
- Bumped the C ABI because the public codeword grew from 42 to 77 bytes.
- Versioned the wire geometry as CKey Format 0.5.0 / format byte 05 and refreshed the independent vector.
0.1.0-dev.5 — 2026-11-03
- Updated locator geometry to one thick arc at three corners and a split top-left orientation arc with a one-module visible gap; enlarged the reserved corner envelopes to eliminate finder/data collisions.
- Replaced the previous vertical calibration sequence with the specified 2×2 Grid Key.
- Spread payload placement across angular sectors of the Cartesian matrix and round-robin across the dial plus all four inner rings.
- Versioned the wire format as 0.4.0 / format byte 04 and regenerated the CRC-32C/Reed–Solomon interoperability vector.
- Added maintained geometry and version context for the supplied blueprint.
0.1.0-dev.4 — 2026-11-02
- Reworked the polar field into four inner concentric rings plus a separate 1.9-unit annular dial band; all 12:00/9:00/9:05 calibration rays now stay within that band rather than extending to the center.
- Added a round-robin angular traversal, retained the outer Cartesian matrix, and replaced corner dots with three nested arcs; split the top-left finder into two arc segments for orientation.
- Advanced the wire format to 0.3.0 and preserved earlier version specs and fixtures.
0.1.0-dev.3 — 2026-11-02
- Replaced solid QR-like block finders with nested open corner arcs and switched the reference SVG to dark-field/light-mark styling with rounded data modules to follow the supplied target geometry.
- Advanced the wire geometry version to CKey Format 0.2.0; preserved the 0.1.0 draft and fixture as historical versions.
- Kept Reed–Solomon error correction and CRC-32C framing; geometry evolved independently of framing.
0.1.0-dev.2 — 2026-11-02
- Corrected the format note to reflect the implemented byte-codeword RS decoder and its tested eight-error correction bound.
- Fixed shared-library C ABI exports and bounded SVG render scale to prevent dimension overflow and unreasonable outputs.
- Added independent-review findings and synchronized the public software version and fixture metadata.
0.1.0-dev.1 — 2026-11-02
- Added draft locator-v1 framing with CRC-32C and shortened RS(42,26) over GF(256).
- Added C++20 encoder and byte-codeword decoder with correction of up to eight unknown byte errors.
- Added fixed Cartesian/polar calibration geometry and monochrome SVG renderer.
- Added C ABI, CLI encoder, independent RS parity reference/vector, unit tests, and CI workflow.
- Recorded versioning, context, research, license, and milestone rules.
- Not included: erasure correction, image/camera decoder, perspective recovery, SDKs, browser lab, or measured device benchmarks.