diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md
index b151272..3db9246 100644
--- a/.specify/memory/constitution.md
+++ b/.specify/memory/constitution.md
@@ -6,7 +6,7 @@ This file is the governing contract for every zzThat spec, plan, and task under
zzThat is the iOS and Android apps portion of zzThis. The product rules live in the zzThis repository. This file adapts those rules to the apps. It does not replace them.
-Source pin: zzThis at `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40` (2026-10-14), recorded in `contracts/ZZTHIS-API-PIN`. One pin covers the product rules, the API, design, strings, test vectors, and the wordlist. Later zzThis changes do not change this repo until a pull request moves the pin.
+Source pin: zzThis at `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4` (2026-10-14), recorded in `contracts/ZZTHIS-API-PIN`. One pin covers the product rules, the API, design, strings, test vectors, and the wordlist. Later zzThis changes do not change this repo until a pull request moves the pin.
## Labels used in every artifact
diff --git a/README.md b/README.md
index 71a2904..618b6b0 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
Board ·
Issues ·
zzThis ·
- zzThis spec pin
+ zzThis spec pin
@@ -73,7 +73,7 @@ This repo does not publish its own colors, type, spacing, fonts, icons, or sente
| [`CONTRIBUTING.md`](CONTRIBUTING.md) | How to open a change |
| [`README.md`](README.md) | This file |
-zzThis, not this repo, holds the central server, the later web client, the marketing page, the grammar, the resolver, the wordlist, and capture. The pin is commit `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`, recorded in `contracts/ZZTHIS-API-PIN`.
+zzThis, not this repo, holds the central server, the later web client, the marketing page, the grammar, the resolver, the wordlist, and capture. The pin is commit `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`, recorded in `contracts/ZZTHIS-API-PIN`.
| zzThis path | Role for these apps |
|---|---|
@@ -83,7 +83,7 @@ zzThis, not this repo, holds the central server, the later web client, the marke
| `specs/002-resolver-core` | Server behavior the client calls |
| `specs/003-wordlist-checkword` | Wordlist, check word, grammar library |
| `specs/004-capture` | Camera, typing, and voice |
-| `design/` and `scripts/pin-zzthis.sh` | Tokens, generated Swift and Kotlin, fonts, masters, UX patterns, `copy.json`. Pin `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40` |
+| `design/` and `scripts/pin-zzthis.sh` | Tokens, generated Swift and Kotlin, fonts, masters, UX patterns, `copy.json`. Pin `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4` |
| `specs/005-v1-api` and `docs/ONE-SHOT-BRIEF.md` | The `/v1` contract and the one-shot build brief |
## Architecture
diff --git a/apps/DESIGN-PIN b/apps/DESIGN-PIN
index 1e0c3b1..8e6bb42 100644
--- a/apps/DESIGN-PIN
+++ b/apps/DESIGN-PIN
@@ -1 +1 @@
-ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40
+fd99d276e4546d2ebf9d23b5f6de85b08bad56c4
diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml
index 0207b6c..cb8d460 100644
--- a/apps/android/app/src/main/res/values/strings.xml
+++ b/apps/android/app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
-
+
Demo · demo data
Loading
@@ -23,6 +23,11 @@
This is a zz mark with no words. Type the code to open it.
No code found. Take another photo, or type it.
Take another photo
+ A marker is cut off.
+ The photo is blurred.
+ Glare hides part of the code.
+ Move closer
+ Try a better angle
Is this word right?
Keep it as written
The check word does not match. Check the words and try again.
diff --git a/apps/ios/zzThat/App/CopyKey.swift b/apps/ios/zzThat/App/CopyKey.swift
index 5d79389..3e4af36 100644
--- a/apps/ios/zzThat/App/CopyKey.swift
+++ b/apps/ios/zzThat/App/CopyKey.swift
@@ -112,6 +112,11 @@ enum CopyKey: String, CaseIterable, Sendable {
case scanPhotoSend = "scan.photo_send"
case scanPickOne = "scan.pick_one"
case scanRetry = "scan.retry"
+ case scanRetryAngle = "scan.retry_angle"
+ case scanRetryBlur = "scan.retry_blur"
+ case scanRetryCloser = "scan.retry_closer"
+ case scanRetryGlare = "scan.retry_glare"
+ case scanRetryMarkerCut = "scan.retry_marker_cut"
case scanTakePhoto = "scan.take_photo"
case scanTypeInstead = "scan.type_instead"
case scanWrongLength = "scan.wrong_length"
diff --git a/apps/ios/zzThat/Resources/Localizable.xcstrings b/apps/ios/zzThat/Resources/Localizable.xcstrings
index 6587abb..70c3dc6 100644
--- a/apps/ios/zzThat/Resources/Localizable.xcstrings
+++ b/apps/ios/zzThat/Resources/Localizable.xcstrings
@@ -1178,6 +1178,61 @@
}
}
},
+ "scan.retry_angle" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Try a better angle"
+ }
+ }
+ }
+ },
+ "scan.retry_blur" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "The photo is blurred."
+ }
+ }
+ }
+ },
+ "scan.retry_closer" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Move closer"
+ }
+ }
+ }
+ },
+ "scan.retry_glare" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Glare hides part of the code."
+ }
+ }
+ }
+ },
+ "scan.retry_marker_cut" : {
+ "extractionState" : "manual",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "A marker is cut off."
+ }
+ }
+ }
+ },
"scan.take_photo" : {
"extractionState" : "manual",
"localizations" : {
diff --git a/contracts/ZZTHIS-API-PIN b/contracts/ZZTHIS-API-PIN
index 1e0c3b1..8e6bb42 100644
--- a/contracts/ZZTHIS-API-PIN
+++ b/contracts/ZZTHIS-API-PIN
@@ -1 +1 @@
-ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40
+fd99d276e4546d2ebf9d23b5f6de85b08bad56c4
diff --git a/specs/001-zzthat-apps/design.md b/specs/001-zzthat-apps/design.md
index 9628bfb..aedd92a 100644
--- a/specs/001-zzthat-apps/design.md
+++ b/specs/001-zzthat-apps/design.md
@@ -1,6 +1,6 @@
# Design consumption: zzThat apps
-The apps do not define a visual system or their own sentences. Colors, type, spacing, fonts, the zz code mark, strings, and screen patterns come from [Zero-State-LLC/zzthis](https://github.com/Zero-State-LLC/zzthis) at one pin: `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`, recorded in `contracts/ZZTHIS-API-PIN`. The same pin covers the OpenAPI file, the shared test vectors, and the wordlist. It is a pinned copy, not a git submodule. Do not track `main`.
+The apps do not define a visual system or their own sentences. Colors, type, spacing, fonts, the zz code mark, strings, and screen patterns come from [Zero-State-LLC/zzthis](https://github.com/Zero-State-LLC/zzthis) at one pin: `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`, recorded in `contracts/ZZTHIS-API-PIN`. The same pin covers the OpenAPI file, the shared test vectors, and the wordlist. It is a pinned copy, not a git submodule. Do not track `main`.
## Sync
diff --git a/specs/001-zzthat-apps/plan.md b/specs/001-zzthat-apps/plan.md
index c908fe1..40da63b 100644
--- a/specs/001-zzthat-apps/plan.md
+++ b/specs/001-zzthat-apps/plan.md
@@ -25,7 +25,7 @@ anti-slop-code, production-systems, google-developer-style. Spec lint: `.github/
| On-device storage | Session tokens, last canonical read, public resolves for 60 seconds online and 360 seconds offline (FR-041), drafts labeled "Not a code yet." | FR-041, ZQ16, ZQ26. zzThis spec 005 FR-018. |
| Secrets | None in the tree. No record-signing keys in the app. | Constitution IX |
| Structure | Trees, modules, and navigation in runtime.md | [runtime.md](runtime.md) |
-| API client | Generated from the pinned `contracts/zzthis-v1.openapi.yaml`: Swift OpenAPI Generator, and OpenAPI Generator `kotlin` with Retrofit | zzThis `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`. ZQ19. |
+| API client | Generated from the pinned `contracts/zzthis-v1.openapi.yaml`: Swift OpenAPI Generator, and OpenAPI Generator `kotlin` with Retrofit | zzThis `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`. ZQ19. |
| Design and strings | Pinned copy via `scripts/sync-zzthis.sh`, one sha in `contracts/ZZTHIS-API-PIN`, with fonts and `copy.json` | design.md. Not a submodule. |
| Recognition engines | Engine-neutral recognition adapters. Apple Vision is the iOS baseline. Android ML Kit and PP-OCR are qualification candidates; only the ZZ-OCR-QUAL-001 winner ships enabled by default. One still photo, on device. | runtime.md, Read pipeline; zzThis PR #89 / accepted 2026-10-06 recognition intent |
| Builds | Demo, Local, and Release, with XcodeGen and Gradle flavors | runtime.md, Build configurations |
diff --git a/specs/001-zzthat-apps/runtime.md b/specs/001-zzthat-apps/runtime.md
index 5755f8e..85d1661 100644
--- a/specs/001-zzthat-apps/runtime.md
+++ b/specs/001-zzthat-apps/runtime.md
@@ -4,7 +4,7 @@ Feature: [spec.md](spec.md). This file is the build and runtime contract for the
Decisions: [decisions.md](decisions.md). Visuals: [design.md](design.md).
Status: implementation in progress. The trees below now exist; this document remains normative for implementation and verification. A path being present does not mean its task or acceptance evidence is complete. V1 capture is on-device only and never sends a photo, crop, or OCR transcript.
-Every named screen uses the pattern in zzThis `design/UX.md` at pin `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`, and every sentence comes from `design/copy.json` at that pin. Do not invent a pattern, a palette, or a sentence.
+Every named screen uses the pattern in zzThis `design/UX.md` at pin `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`, and every sentence comes from `design/copy.json` at that pin. Do not invent a pattern, a palette, or a sentence.
## Toolchain
diff --git a/specs/001-zzthat-apps/spec.md b/specs/001-zzthat-apps/spec.md
index eb6476c..d260c2b 100644
--- a/specs/001-zzthat-apps/spec.md
+++ b/specs/001-zzthat-apps/spec.md
@@ -7,8 +7,8 @@ Constitution: [.specify/memory/constitution.md](../../.specify/memory/constituti
Runtime: [runtime.md](runtime.md). Design consumption: [design.md](design.md).
Camera boundary: [recognition-adapter.md](recognition-adapter.md). Camera Accept remains blocked on the upstream contract and qualification gates.
Decisions: [decisions.md](decisions.md) (ZQ1 to ZQ28 decided by 2026-10-05).
-zzThis pin: `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`, in `contracts/ZZTHIS-API-PIN`. One pin covers the product rules, the API, design, strings, test vectors, and the wordlist.
-Deepened 2026-10-04 so both apps can be built in one pass with the zzThis server and web client: zzThis [analysis](https://github.com/Zero-State-LLC/zzthis/blob/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/analysis-2026-10-04.md) and [build brief](https://github.com/Zero-State-LLC/zzthis/blob/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/docs/ONE-SHOT-BRIEF.md).
+zzThis pin: `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`, in `contracts/ZZTHIS-API-PIN`. One pin covers the product rules, the API, design, strings, test vectors, and the wordlist.
+Deepened 2026-10-04 so both apps can be built in one pass with the zzThis server and web client: zzThis [analysis](https://github.com/Zero-State-LLC/zzthis/blob/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/analysis-2026-10-04.md) and [build brief](https://github.com/Zero-State-LLC/zzthis/blob/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/docs/ONE-SHOT-BRIEF.md).
## Why
@@ -164,7 +164,7 @@ Acceptance:
## API contract
-The contract is zzThis spec 005 and its OpenAPI file, pinned at `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40` as [`contracts/zzthis-v1.openapi.yaml`](../../contracts/zzthis-v1.openapi.yaml). Wire shapes live in that file, and this section does not restate them. It lists what the apps call and the rules on the app side.
+The contract is zzThis spec 005 and its OpenAPI file, pinned at `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4` as [`contracts/zzthis-v1.openapi.yaml`](../../contracts/zzthis-v1.openapi.yaml). Wire shapes live in that file, and this section does not restate them. It lists what the apps call and the rules on the app side.
| Call | When the app calls it | App rule |
|---|---|---|
diff --git a/specs/README.md b/specs/README.md
index 4ed244c..7dc0767 100644
--- a/specs/README.md
+++ b/specs/README.md
@@ -2,22 +2,22 @@
zzThat uses [Spec Kit](https://github.com/github/spec-kit) order: constitution, specify, clarify, plan, checklist, tasks, analyze, implement, converge. The rules for every spec are in [`.specify/memory/constitution.md`](../.specify/memory/constitution.md) (v1.3.1; see constitution for ratification state).
-Product behavior that is already specified lives in [zzThis](https://github.com/Zero-State-LLC/zzthis) at commit `ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40`. This repo references those specs. It does not copy them.
+Product behavior that is already specified lives in [zzThis](https://github.com/Zero-State-LLC/zzthis) at commit `fd99d276e4546d2ebf9d23b5f6de85b08bad56c4`. This repo references those specs. It does not copy them.
| zzThis artifact | What zzThat uses it for |
|---|---|
-| [`docs/SPEC.md`](https://github.com/Zero-State-LLC/zzthis/blob/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/docs/SPEC.md) | Grammar (Section 2.2a), architecture (Section 10), questions (Section 9), v1 and v2 line (Section 12) |
-| [`specs/002-resolver-core`](https://github.com/Zero-State-LLC/zzthis/tree/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/002-resolver-core) | The server the apps call. Free public codes are v2 there. |
-| [`specs/003-wordlist-checkword`](https://github.com/Zero-State-LLC/zzthis/tree/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/003-wordlist-checkword) | Wordlist, check word, and the v1 text grammar |
-| [`specs/005-v1-api`](https://github.com/Zero-State-LLC/zzthis/tree/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/005-v1-api) | The `/v1` contract the apps call, pinned as `contracts/zzthis-v1.openapi.yaml` |
-| [`design/`](https://github.com/Zero-State-LLC/zzthis/tree/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/design) | Tokens, fonts, logos, UX patterns, and `copy.json` |
-| [`specs/004-capture`](https://github.com/Zero-State-LLC/zzthis/tree/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/004-capture) | Camera, typing, and voice capture. Voice is not in the first app release (ZQ10). |
+| [`docs/SPEC.md`](https://github.com/Zero-State-LLC/zzthis/blob/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/docs/SPEC.md) | Grammar (Section 2.2a), architecture (Section 10), questions (Section 9), v1 and v2 line (Section 12) |
+| [`specs/002-resolver-core`](https://github.com/Zero-State-LLC/zzthis/tree/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/002-resolver-core) | The server the apps call. Free public codes are v2 there. |
+| [`specs/003-wordlist-checkword`](https://github.com/Zero-State-LLC/zzthis/tree/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/003-wordlist-checkword) | Wordlist, check word, and the v1 text grammar |
+| [`specs/005-v1-api`](https://github.com/Zero-State-LLC/zzthis/tree/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/005-v1-api) | The `/v1` contract the apps call, pinned as `contracts/zzthis-v1.openapi.yaml` |
+| [`design/`](https://github.com/Zero-State-LLC/zzthis/tree/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/design) | Tokens, fonts, logos, UX patterns, and `copy.json` |
+| [`specs/004-capture`](https://github.com/Zero-State-LLC/zzthis/tree/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/004-capture) | Camera, typing, and voice capture. Voice is not in the first app release (ZQ10). |
## Features
| ID | Feature | Built? | specify | clarify | plan | checklist | tasks | analyze |
|---|---|---|---|---|---|---|---|---|
-| [001](001-zzthat-apps/spec.md) | iOS and Android apps | In progress | Done, deepened 2026-10-04 | ZQ1 to ZQ28 decided ([log](001-zzthat-apps/decisions.md)) | Done | [Done](001-zzthat-apps/checklists/requirements.md) | [Build order](001-zzthat-apps/tasks.md) | [Done 2026-10-04](https://github.com/Zero-State-LLC/zzthis/blob/ed5b0bd5dba2a6e8a1c583c443207dbb3c692a40/specs/analysis-2026-10-04.md) (in zzThis) |
+| [001](001-zzthat-apps/spec.md) | iOS and Android apps | In progress | Done, deepened 2026-10-04 | ZQ1 to ZQ28 decided ([log](001-zzthat-apps/decisions.md)) | Done | [Done](001-zzthat-apps/checklists/requirements.md) | [Build order](001-zzthat-apps/tasks.md) | [Done 2026-10-04](https://github.com/Zero-State-LLC/zzthis/blob/fd99d276e4546d2ebf9d23b5f6de85b08bad56c4/specs/analysis-2026-10-04.md) (in zzThis) |
Web is not a feature of this repo [DANNY 2026-10-04]. zzThing is not a feature of this repo [ZZTHIS SPEC].