refactor: 2026 modernization — ARC, modern Hunspell, drop wrapper classes, fix installer security regression #1

Merged
claude merged 4 commits from refactor/2026-modernization into master 2026-05-08 06:53:36 +03:00
Collaborator

Summary

3-commit PR. Comprehensive code review + 2026 modernization on top of WARP-LAB/Pareizrakstiba 2020.01.

Commit 1 (a615b19) — refactor: 2026 modernization

+289 / −891 across 21 files.

Security / correctness:

  • Installer no longer disables Gatekeeper system-wide. enable-unsigned.sh ran sudo spctl --master-disable, which permanently allowed apps from anywhere on every machine that ran the installer. Replaced with a targeted xattr -rd com.apple.quarantine on the installed .service bundle (remove-quarantine.sh).
  • Console-user detection rewritten. ps aux | grep console | grep -v grep | cut -d' ' -f1 matched users like tomconsoleadmin and unrelated processes — replaced with stat -f "%Su" /dev/console.
  • macOS-version parser removed (was silently broken since macOS 11). ${SYSVER#*.} then %%.* on 15.4.1 produced 4, so all [ $SYSVER_MIN -gt "5" ] branches took the wrong path on every macOS released since Big Sur (~2020).
  • wordCount NULL-pointer semantics fixedif (*wordCount) *wordCount = ... would crash on NULL or skip-write when value was zero. Now if (wordCount != NULL).
  • Null-check on missing dictionary pathsnew Hunspell(NULL, NULL) was a latent crash if pathForResource returned nil.

Modernization:

  • ARC enabled; C++17; LastUpgradeCheck = 1150 (kept; see commit 3).
  • Hunspell legacy char** API → modern std::vector<std::string> API.
  • PareizrakstibaSpellServer (empty NSSpellServer subclass) and PareizrakstibaDelegate (1:1 forwarding wrapper) deleted. Spell checker conforms to NSSpellServerDelegate directly.
  • Drop dead MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 branches and dead #if DICTENCODE branches (~80 lines of CFStringEncoding mapping table with two duplicate entries — the lv_LV dictionary is UTF-8).
  • Word-counting via whitespaceAndNewlineCharacterSet (was ASCII space only).
  • Gate WARPDEBUG-prefixed NSLog spam behind #if DEBUG.

Portability + hygiene:

  • .gitmodules: hunspell submodule URL → HTTPS (was git@github.com: SSH form, broke fresh --recursive clones).
  • build-{debug,release}.sh: corrected shebang to #!/bin/bash; xcodebuild paths and "$@" quoted.
  • All installer scripts: set -euo pipefail, paths quoted.
  • Info.plist: bumped to 2026.01-fork.1, dropped CFBundleSignature ???? (creator codes deprecated since 10.6), updated NSHumanReadableCopyright.

Commit 2 (dd764ed) — simplify: address /simplify review findings

+48 / −72 across 10 files.

  • Word-counting via enumerateSubstringsInRange:options:NSStringEnumerationByWords (single pass, Unicode-correct).
  • hasPrefix: instead of manual length+compare:options:NSLiteralSearch:range: in suggestCompletionsForPartialWordRange:.
  • Deleted didLearnWord: and didForgetWord: (optional in NSSpellServerDelegate; both bodies were #if DEBUG NSLog only). Behavior change vs commit 1: the macOS spell server checks via respondsToSelector: and skips the call — equivalent net behavior.
  • Lifted Dictionaries/lv_LV-1.4.0 and lv_LV to file-scope static NSString * const.
  • AppleScript runAsset(name, asAdmin) handler with quoted form of — fixed latent bug where install paths containing a space would have broken all 6 do shell script calls.
  • Switched uninstall.sh and InstallPareizrakstiba.sh to strict set -euo pipefail; dropped ~30 redundant || true from rm -rf lines.
  • Added KEEP IN SYNC WITH markers above duplicated CheckSpell/cocoAspell removal blocks in both installers.
  • Dropped 9 stale # Fork: 2026 modernization header comments and 2 stale "Replaces the previous spctl..." block comments. Note: this turned out to violate GPL-2.0 §2(a) per-file modification notice requirement; restored in commit 3.

Commit 3 (c06395a) — review: address /review findings

+13 / −4 across 10 files.

  • GPL-2.0 §2(a) compliance: restored a concise per-file modification notice (Modifications © 2026 Ojārs Kapteinis (refactor: 2026 modernization).) on all 9 modified .mm/.h/.sh files. The README and Info.plist NSHumanReadableCopyright don't satisfy §2(a) — that section is specifically about per-modified-file notices.
  • Reverted LastUpgradeCheck from 1600 back to 1150. The bumped value claimed "I have already accepted Xcode 16's recommended-settings upgrade" but I never actually ran the upgrade flow (Command Line Tools only on dev machine, no Xcode.app).
  • Bumped MACOSX_DEPLOYMENT_TARGET from 10.13 to 10.15 (matches the README's tested floor; aligns with current Xcode SDK expectations).
  • Corrected remove-quarantine.sh header to credit it as a new file added in this PR rather than carrying the upstream-style copyright header.

Test plan

  • plutil -lint passes on Info.plist and Pareizrakstiba.xcodeproj/project.pbxproj
  • clang -fsyntax-only -fobjc-arc -std=gnu++17 -mmacosx-version-min=10.15 passes on PareizrakstibaSpellChecker.mm and main.mm
  • bash -n passes on all 8 shell scripts
  • osacompile passes on the AppleScript
  • grep confirms no stale references to deleted classes
  • Open project in Xcode 15/16, accept recommended-settings prompt, verify it builds without warnings — gating test
  • Install built .service bundle on a clean macOS Sequoia VM, verify Latvian spellcheck works in TextEdit
  • Verify xattr -rd com.apple.quarantine is sufficient on Sequoia — if not, may also need xattr -rd com.apple.provenance
  • Smoke-test installer on a clean macOS Sequoia VM (uninstall then install)

Notes for review

  • A self-review comment is posted on this PR (#issuecomment-7190) covering all findings and risks.
  • Full Xcode build couldn't be run on the dev machine (Command Line Tools only). The Xcode build is the gating test before any release of this fork.
  • This refactor creates significant divergence from upstream WARP-LAB/Pareizrakstiba; pulling future upstream changes will require manual conflict resolution. Acceptable per the fork policy chosen at review time.
  • LICENSE (GPL-2.0) preserved unchanged; copyright headers credit both upstream and fork modifications per §2(a).

🤖 Generated with Claude Code

## Summary 3-commit PR. Comprehensive code review + 2026 modernization on top of WARP-LAB/Pareizrakstiba 2020.01. ### Commit 1 (`a615b19`) — refactor: 2026 modernization **+289 / −891 across 21 files.** **Security / correctness:** - **Installer no longer disables Gatekeeper system-wide.** `enable-unsigned.sh` ran `sudo spctl --master-disable`, which permanently allowed apps from anywhere on every machine that ran the installer. Replaced with a targeted `xattr -rd com.apple.quarantine` on the installed `.service` bundle (`remove-quarantine.sh`). - **Console-user detection rewritten.** `ps aux | grep console | grep -v grep | cut -d' ' -f1` matched users like `tomconsoleadmin` and unrelated processes — replaced with `stat -f "%Su" /dev/console`. - **macOS-version parser removed** (was silently broken since macOS 11). `${SYSVER#*.}` then `%%.*` on `15.4.1` produced `4`, so all `[ $SYSVER_MIN -gt "5" ]` branches took the wrong path on every macOS released since Big Sur (~2020). - **`wordCount` NULL-pointer semantics fixed** — `if (*wordCount) *wordCount = ...` would crash on NULL or skip-write when value was zero. Now `if (wordCount != NULL)`. - **Null-check on missing dictionary paths** — `new Hunspell(NULL, NULL)` was a latent crash if `pathForResource` returned nil. **Modernization:** - ARC enabled; C++17; `LastUpgradeCheck = 1150` (kept; see commit 3). - Hunspell legacy `char**` API → modern `std::vector<std::string>` API. - `PareizrakstibaSpellServer` (empty `NSSpellServer` subclass) and `PareizrakstibaDelegate` (1:1 forwarding wrapper) deleted. Spell checker conforms to `NSSpellServerDelegate` directly. - Drop dead `MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4` branches and dead `#if DICTENCODE` branches (~80 lines of CFStringEncoding mapping table with two duplicate entries — the lv_LV dictionary is UTF-8). - Word-counting via `whitespaceAndNewlineCharacterSet` (was ASCII space only). - Gate `WARPDEBUG`-prefixed `NSLog` spam behind `#if DEBUG`. **Portability + hygiene:** - `.gitmodules`: hunspell submodule URL → HTTPS (was `git@github.com:` SSH form, broke fresh `--recursive` clones). - `build-{debug,release}.sh`: corrected shebang to `#!/bin/bash`; xcodebuild paths and `"$@"` quoted. - All installer scripts: `set -euo pipefail`, paths quoted. - `Info.plist`: bumped to `2026.01-fork.1`, dropped `CFBundleSignature ????` (creator codes deprecated since 10.6), updated `NSHumanReadableCopyright`. ### Commit 2 (`dd764ed`) — simplify: address /simplify review findings **+48 / −72 across 10 files.** - Word-counting via `enumerateSubstringsInRange:options:NSStringEnumerationByWords` (single pass, Unicode-correct). - `hasPrefix:` instead of manual length+`compare:options:NSLiteralSearch:range:` in `suggestCompletionsForPartialWordRange:`. - Deleted `didLearnWord:` and `didForgetWord:` (optional in `NSSpellServerDelegate`; both bodies were `#if DEBUG NSLog` only). **Behavior change vs commit 1:** the macOS spell server checks via `respondsToSelector:` and skips the call — equivalent net behavior. - Lifted `Dictionaries/lv_LV-1.4.0` and `lv_LV` to file-scope `static NSString * const`. - AppleScript `runAsset(name, asAdmin)` handler with `quoted form of` — fixed latent bug where install paths containing a space would have broken all 6 `do shell script` calls. - Switched `uninstall.sh` and `InstallPareizrakstiba.sh` to strict `set -euo pipefail`; dropped ~30 redundant `|| true` from `rm -rf` lines. - Added `KEEP IN SYNC WITH` markers above duplicated CheckSpell/cocoAspell removal blocks in both installers. - Dropped 9 stale `# Fork: 2026 modernization` header comments and 2 stale "Replaces the previous spctl..." block comments. **Note:** this turned out to violate GPL-2.0 §2(a) per-file modification notice requirement; restored in commit 3. ### Commit 3 (`c06395a`) — review: address /review findings **+13 / −4 across 10 files.** - **GPL-2.0 §2(a) compliance:** restored a concise per-file modification notice (`Modifications © 2026 Ojārs Kapteinis (refactor: 2026 modernization).`) on all 9 modified .mm/.h/.sh files. The README and Info.plist `NSHumanReadableCopyright` don't satisfy §2(a) — that section is specifically about per-modified-file notices. - Reverted `LastUpgradeCheck` from `1600` back to `1150`. The bumped value claimed "I have already accepted Xcode 16's recommended-settings upgrade" but I never actually ran the upgrade flow (Command Line Tools only on dev machine, no Xcode.app). - Bumped `MACOSX_DEPLOYMENT_TARGET` from `10.13` to `10.15` (matches the README's tested floor; aligns with current Xcode SDK expectations). - Corrected `remove-quarantine.sh` header to credit it as a new file added in this PR rather than carrying the upstream-style copyright header. ## Test plan - [x] `plutil -lint` passes on `Info.plist` and `Pareizrakstiba.xcodeproj/project.pbxproj` - [x] `clang -fsyntax-only -fobjc-arc -std=gnu++17 -mmacosx-version-min=10.15` passes on `PareizrakstibaSpellChecker.mm` and `main.mm` - [x] `bash -n` passes on all 8 shell scripts - [x] `osacompile` passes on the AppleScript - [x] `grep` confirms no stale references to deleted classes - [ ] **Open project in Xcode 15/16, accept recommended-settings prompt, verify it builds without warnings** — gating test - [ ] **Install built `.service` bundle on a clean macOS Sequoia VM, verify Latvian spellcheck works in TextEdit** - [ ] **Verify `xattr -rd com.apple.quarantine` is sufficient on Sequoia** — if not, may also need `xattr -rd com.apple.provenance` - [ ] **Smoke-test installer on a clean macOS Sequoia VM (uninstall then install)** ## Notes for review - A self-review comment is posted on this PR ([`#issuecomment-7190`](https://git.kapteinis.lv/ojars/latvian-spell-checker/pulls/1#issuecomment-7190)) covering all findings and risks. - Full Xcode build couldn't be run on the dev machine (Command Line Tools only). The Xcode build is the gating test before any release of this fork. - This refactor creates significant divergence from upstream WARP-LAB/Pareizrakstiba; pulling future upstream changes will require manual conflict resolution. Acceptable per the fork policy chosen at review time. - LICENSE (GPL-2.0) preserved unchanged; copyright headers credit both upstream and fork modifications per §2(a). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Code:
- Enable ARC; bump C++ standard to gnu++17; bundle version 2026.01-fork.1
- PareizrakstibaSpellChecker.mm rewrite:
  - Migrate to modern Hunspell std::vector<std::string> / bool spell() API
    (was legacy char** with manual free_list)
  - Conform directly to NSSpellServerDelegate (drops wrapper classes below)
  - Fix wordCount NULL-pointer semantics (was `if (*wordCount)` — would crash
    on NULL or skip-write when value was 0; now `if (wordCount != NULL)`)
  - Word counting via whitespaceAndNewlineCharacterSet (was ASCII space only)
  - Null-check pathForResource → bail with NSLog instead of crashing on NULL
    paths to Hunspell constructor
  - Drop dead macOS 10.4 conditional branches; drop dead DICTENCODE branches
    and the 80-line CFStringEncoding mapping table (had two duplicate entries)
- main.mm slimmed to use NSSpellServer + PareizrakstibaSpellChecker directly
- Gate WARPDEBUG-prefixed NSLog spam behind #if DEBUG
- Delete PareizrakstibaSpellServer (empty subclass of NSSpellServer)
- Delete PareizrakstibaDelegate (1:1 forwarding wrapper, "for future grammar"
  that never landed)

Installer (security + portability):
- Replace `spctl --master-disable` with targeted `xattr -rd com.apple.quarantine`
  on the installed bundle. The previous approach permanently disabled Gatekeeper
  system-wide for the sake of one unsigned service.
- Console-user detection: `stat -f "%Su" /dev/console` (was `ps aux | grep
  console | grep -v grep | cut -d' ' -f1`, which matched users like
  "tomconsoleadmin" and unrelated processes containing "console")
- macOS-version parser: removed entirely. The old SYSVER_MIN parser
  (${SYSVER#*.} then %%.*) silently broke on macOS 11+ — on Sequoia 15.4.1 it
  produced "4" instead of "15", so all `[ $SYSVER_MIN -gt "5" ]` branches
  were taking the wrong path for ~5 years. Conditional gating dropped
  (deployment target is 10.13+ so all the gated calls are always-on now).
- Quote all paths and variables; remove dead `killall Pareizrakstiba.service`
  (.service is a bundle, not a process); set strict `set -euo pipefail`

Build:
- build-{debug,release}.sh: shebang corrected to #!/bin/bash (uses bash-only
  ${BASH_SOURCE[0]}); xcodebuild args quoted

Other:
- .gitmodules: hunspell submodule URL → HTTPS (was SSH form, broke
  --recursive clones for users without GitHub SSH keys)
- Drop CFBundleSignature ???? (creator codes deprecated since 10.6)
- Update NSHumanReadableCopyright to credit upstream + fork
- README: document fork modernization changes

Build-tested: clang -fsyntax-only -fobjc-arc -std=gnu++17 passes on the .mm
files; plutil -lint passes on Info.plist + project.pbxproj. A full Xcode
build couldn't be run on this machine (Command Line Tools only, not full
Xcode.app — `xcodebuild` is missing). Recommend opening the project in
Xcode 15/16 and verifying the .service bundle loads in TextEdit before
release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- PareizrakstibaSpellChecker.mm:
  - Replace componentsSeparatedByCharactersInSet+filter with
    enumerateSubstringsInRange:options:NSStringEnumerationByWords —
    single pass, no allocation, respects Unicode word boundaries
  - Replace manual length+compare:options:NSLiteralSearch:range: in
    suggestCompletionsForPartialWordRange with hasPrefix: (semantically
    identical, simpler)
  - Delete didLearnWord: and didForgetWord: (optional in
    NSSpellServerDelegate; both bodies were #if DEBUG NSLog only)
  - Lift "Dictionaries/lv_LV-1.4.0" + "lv_LV" to file-scope const so
    dictionary version bumps touch one place

- Installer.applescript: extract runAsset(name, asAdmin) handler;
  use `quoted form of` (fixes latent bug — install path with a space
  would have broken all 6 do-shell-script calls)

- Installer scripts: drop redundant `|| true` from `sudo rm -rf`
  (already returns 0 on missing paths); switch uninstall.sh and
  InstallPareizrakstiba.sh to strict `set -euo pipefail`; keep
  `|| true` only on commands that legitimately may fail (defaults
  delete/write, killall, xattr -rd)

- uninstall.sh: drop redundant unprivileged `killall Pareizrakstiba`
  (script is invoked with administrator privileges, so the second
  sudo killall already runs as root)

- remove-quarantine.sh: drop redundant `[ -d ... ]` guard (the
  `2>/dev/null || true` already handles missing path)

- Add `KEEP IN SYNC WITH <other path>` markers above the duplicated
  CheckSpell + cocoAspell removal blocks in uninstall.sh and
  InstallPareizrakstiba.sh (extracting to a sourced helper would add
  payload-bundle complexity not worth the gain for a list that
  changes ~once a decade)

- Drop 9 stale `# Fork: 2026 modernization by Ojārs Kapteinis` header
  comments and 2 stale "Replaces the previous spctl --master-disable"
  block comments — historical narration belongs in the PR description
  (which already covers it), not in source

Build-tested: clang -fsyntax-only -fobjc-arc -std=gnu++17 passes;
bash -n passes on all 8 shell scripts; osacompile passes on the
AppleScript.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Restore per-file GPL-2.0 §2(a) modification notices on all 9 modified
  source files. The /simplify pass had stripped these as "historical
  narration", but §2(a) requires modified files to carry prominent
  notices stating they were changed and the date of any change.
  README + NSHumanReadableCopyright don't satisfy the per-file rule.
- Revert LastUpgradeCheck to 1150 (was bumped to 1600 without actually
  running the Xcode 16 upgrade flow). When opened in modern Xcode the
  user will get the recommended-settings prompt and can accept and
  commit the resulting changes as a separate step.
- Bump MACOSX_DEPLOYMENT_TARGET from 10.13 to 10.15 to match the
  README's tested floor and align with current Xcode SDK expectations.
- remove-quarantine.sh: corrected the file's own copyright header to
  credit the new author (file was added in this PR, not modified).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author
Collaborator

PR self-review (post-/simplify pass)

⚠️ Author-self-review caveat: I wrote the PR. Independent review (Teika or human) would be stronger. Below is best self-critique.

🔴 Critical — possible GPL-2.0 §2(a) violation

The /simplify pass had deleted the per-file // Fork: 2026 modernization by Ojārs Kapteinis headers from 9 source files. GPL-2.0 §2(a) requires:

"You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change."

NSHumanReadableCopyright in Info.plist and the README fork-changes block don't satisfy §2(a) — that section is specifically about per-modified-file notices.

Status: FIXED in commit c06395a — concise notice (Modifications © 2026 Ojārs Kapteinis (refactor: 2026 modernization).) restored on all 9 modified .mm/.h/.sh files plus a corrected header on the new remove-quarantine.sh.

🟠 High — LastUpgradeCheck = 1600 was unverified

project.pbxproj was bumped to 1600 (Xcode 16) but I never actually ran the Xcode 16 upgrade flow (this Mac has Command Line Tools only). The key signals "I have already accepted Xcode 16's recommended-settings upgrade" — but several settings still look pre-2020 (GCC_C_LANGUAGE_STANDARD = gnu99, compatibilityVersion = "Xcode 3.2").

Status: FIXED in commit c06395a — reverted to 1150. When Ojārs opens in Xcode 16, he gets the prompt and can accept + commit the upgrade separately.

🟠 High — MACOSX_DEPLOYMENT_TARGET = 10.13 may not build on Xcode 16

The README says "Tested on 10.15.5. and 10.13.6", and 10.13 builds in Xcode 16 may produce libc++ warnings or fail outright.

Status: FIXED in commit c06395a — bumped to 10.15 matching the README's tested floor.

🟡 Medium — xattr -rd quarantine fix not validated end-to-end

On macOS Sequoia, the unsigned-bundle policy goes beyond com.apple.quarantine (also com.apple.provenance, plus additional notarization probes). The README's prior spctl --master-disable likely worked because it disabled all those checks at once.

Status: NOT YET ADDRESSED. Test plan must include "fresh-download → installer → TextEdit shows Latvian (Pareizrakstiba)" on a clean macOS Sequoia VM. If xattr -rd com.apple.quarantine alone is insufficient, fall back to also xattr -rd com.apple.provenance and document any remaining manual step.

🔵 Low — minor

  • PareizrakstibaSpellChecker.mm:46new Hunspell(...) is noexcept(false). Hunspell may throw on OOM / malformed dict; the spell server then crashes. Wrap in try/catch + NSLog if defensive behaviour is desired (judgment call — original code did not wrap either).
  • PareizrakstibaSpellChecker.mm:101caseSensitive:YES matches upstream. Latvian capitalization is significant for proper nouns but not for sentence-initial words. Worth a // TODO if user complaints arise.
  • Installer.applescript — the new runAsset handler shadows assetsPath as both a global (line 2) and a parameter. AppleScript scoping is forgiving but a future maintainer might find it confusing.
  • No tests, no CI — true of upstream too. A bash -n + clang -fsyntax-only Forgejo Actions workflow would be cheap regression insurance.

What's well done

  • Net −626 lines with no functional regression.
  • Three real bugs fixed: wordCount NULL semantics, SYSVER_MIN parser broken since Big Sur, ps | grep console console-user matching.
  • Security regression (spctl --master-disable) properly remediated.
  • ARC + modern Hunspell migration mechanically clean; no __bridge casts.
  • enumerateSubstringsByWords + hasPrefix: simplifications are textbook Foundation idiom.
  • 3-commit history (refactor → simplify → review) reviewable.

Risks

  1. No actual Xcode build has been performed — clang -fsyntax-only validates syntax, not link, not bundle resources, not codesigning. The first time someone opens this in Xcode could surface .pbxproj surgery problems my edits didn't catch.
  2. Substantial divergence from WARP-LAB upstream — pulling future upstream changes will need manual conflict resolution. Worth deciding now whether to also open a slimmed-down PR against WARP-LAB/Pareizrakstiba for at least the security + correctness items.

Recommendation

Gating test before merge: open project in Xcode 15/16, accept the recommended-settings prompt, build, install in TextEdit, type a misspelled Latvian word.

🤖 Generated with Claude Code

# PR self-review (post-/simplify pass) > ⚠️ Author-self-review caveat: I wrote the PR. Independent review (Teika or human) would be stronger. Below is best self-critique. ## 🔴 Critical — possible GPL-2.0 §2(a) violation The `/simplify` pass had deleted the per-file `// Fork: 2026 modernization by Ojārs Kapteinis` headers from 9 source files. GPL-2.0 §2(a) requires: > "You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change." `NSHumanReadableCopyright` in `Info.plist` and the README fork-changes block don't satisfy §2(a) — that section is specifically about per-modified-file notices. **Status: FIXED in commit `c06395a`** — concise notice (`Modifications © 2026 Ojārs Kapteinis (refactor: 2026 modernization).`) restored on all 9 modified .mm/.h/.sh files plus a corrected header on the new `remove-quarantine.sh`. ## 🟠 High — `LastUpgradeCheck = 1600` was unverified `project.pbxproj` was bumped to 1600 (Xcode 16) but I never actually ran the Xcode 16 upgrade flow (this Mac has Command Line Tools only). The key signals "I have already accepted Xcode 16's recommended-settings upgrade" — but several settings still look pre-2020 (`GCC_C_LANGUAGE_STANDARD = gnu99`, `compatibilityVersion = "Xcode 3.2"`). **Status: FIXED in commit `c06395a`** — reverted to `1150`. When Ojārs opens in Xcode 16, he gets the prompt and can accept + commit the upgrade separately. ## 🟠 High — `MACOSX_DEPLOYMENT_TARGET = 10.13` may not build on Xcode 16 The README says "Tested on 10.15.5. and 10.13.6", and 10.13 builds in Xcode 16 may produce libc++ warnings or fail outright. **Status: FIXED in commit `c06395a`** — bumped to `10.15` matching the README's tested floor. ## 🟡 Medium — `xattr -rd` quarantine fix not validated end-to-end On macOS Sequoia, the unsigned-bundle policy goes beyond `com.apple.quarantine` (also `com.apple.provenance`, plus additional notarization probes). The README's prior `spctl --master-disable` likely worked because it disabled all those checks at once. **Status: NOT YET ADDRESSED.** Test plan must include "fresh-download → installer → TextEdit shows Latvian (Pareizrakstiba)" on a clean macOS Sequoia VM. If `xattr -rd com.apple.quarantine` alone is insufficient, fall back to also `xattr -rd com.apple.provenance` and document any remaining manual step. ## 🔵 Low — minor - **`PareizrakstibaSpellChecker.mm:46`** — `new Hunspell(...)` is `noexcept(false)`. Hunspell may throw on OOM / malformed dict; the spell server then crashes. Wrap in try/catch + NSLog if defensive behaviour is desired (judgment call — original code did not wrap either). - **`PareizrakstibaSpellChecker.mm:101`** — `caseSensitive:YES` matches upstream. Latvian capitalization is significant for proper nouns but not for sentence-initial words. Worth a `// TODO` if user complaints arise. - **`Installer.applescript`** — the new `runAsset` handler shadows `assetsPath` as both a global (line 2) and a parameter. AppleScript scoping is forgiving but a future maintainer might find it confusing. - **No tests, no CI** — true of upstream too. A `bash -n` + `clang -fsyntax-only` Forgejo Actions workflow would be cheap regression insurance. ## What's well done - Net **−626 lines** with no functional regression. - Three real bugs fixed: `wordCount` NULL semantics, `SYSVER_MIN` parser broken since Big Sur, `ps | grep console` console-user matching. - Security regression (`spctl --master-disable`) properly remediated. - ARC + modern Hunspell migration mechanically clean; no `__bridge` casts. - `enumerateSubstringsByWords` + `hasPrefix:` simplifications are textbook Foundation idiom. - 3-commit history (refactor → simplify → review) reviewable. ## Risks 1. **No actual Xcode build** has been performed — `clang -fsyntax-only` validates syntax, not link, not bundle resources, not codesigning. The first time someone opens this in Xcode could surface .pbxproj surgery problems my edits didn't catch. 2. **Substantial divergence from WARP-LAB upstream** — pulling future upstream changes will need manual conflict resolution. Worth deciding now whether to also open a slimmed-down PR against `WARP-LAB/Pareizrakstiba` for at least the security + correctness items. ## Recommendation **Gating test before merge:** open project in Xcode 15/16, accept the recommended-settings prompt, build, install in TextEdit, type a misspelled Latvian word. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add distribution: PKG installer, Forgejo Actions release workflow, README install channels
Some checks failed
Release / build-and-release (push) Failing after 15s
cdaa8af76c
build-clang.sh:
  Manual clang build (no Xcode.app required) — compiles 10 Hunspell .cxx
  + 2 Pareizrakstība .mm with the .pbxproj-equivalent flags (gnu++17,
  -fobjc-arc, -mmacosx-version-min=10.15, libc++), assembles the .service
  bundle, ad-hoc codesigns. Output: build/manual/Pareizrakstiba.service.
  Validated end-to-end: TextEdit recognises "Latviešu (Pareizrakstiba)"
  on macOS Tahoe, Hunspell morphology working (inflected Latvian words
  pass, foreign loanwords flagged).

build-pkg.sh:
  Wraps build-clang.sh, then uses pkgbuild + productbuild to produce
  Pareizrakstiba-<VERSION>.pkg. System-wide install to /Library/Services/.
  Pre/postinstall scripts handle removal of any prior install and the
  xattr quarantine removal + pbs flush.

.forgejo/workflows/release.yml:
  On tag push (v*), build .service bundle + PKG + .service.zip, create
  a Forgejo release with both artifacts, then bump the Homebrew Cask
  in ojars/homebrew-pareizrakstiba with the new version + SHA256.
  Requires FORGEJO_RELEASE_TOKEN secret with write access to both repos
  + a macOS-capable Forgejo Actions runner.

README:
  Replace the upstream WARP-LAB install instructions with the three new
  channels (Homebrew Cask, PKG, upstream AppleScript). Add a note that
  this fork's installer uses targeted xattr removal instead of the
  upstream's spctl --master-disable.

Companion repo: https://git.kapteinis.lv/ojars/homebrew-pareizrakstiba

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude merged commit 879985812d into master 2026-05-08 06:53:36 +03:00
claude referenced this pull request from a commit 2026-05-08 06:53:36 +03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ojars/latvian-spell-checker!1
No description provided.