Ariver
2026-07-02 cf4a1ad4dbc8f4a3f61a0a1a32f63d31c3562b27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env bash
set -euo pipefail
 
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
 
python3 - "$ROOT_DIR" <<'PY'
import re
import sys
from pathlib import Path
 
root = Path(sys.argv[1])
app_dir = root / "Apptag"
 
 
def fail(message: str) -> None:
    raise SystemExit(f"FAIL: {message}")
 
 
def read(name: str) -> str:
    return (app_dir / name).read_text(encoding="utf-8")
 
 
def require(source: str, needle: str, message: str) -> None:
    if needle not in source:
        fail(message)
 
 
def function_body(source: str, signature: str) -> str:
    start = source.find(signature)
    if start == -1:
        fail(f"missing function signature: {signature}")
    brace = source.find("{", start)
    depth = 0
    for index in range(brace, len(source)):
        char = source[index]
        if char == "{":
            depth += 1
        elif char == "}":
            depth -= 1
            if depth == 0:
                return source[brace + 1:index]
    fail(f"unterminated function body for: {signature}")
 
 
pro = read("ProEntitlement.swift")
data_layer = read("DataLayer.swift")
content = read("ContentView.swift")
english = (app_dir / "Localization" / "en.json").read_text(encoding="utf-8")
chinese = (app_dir / "Localization" / "zh-Hans.json").read_text(encoding="utf-8")
 
require(pro, "static let freeNoteLimit = 3", "free note limit must be 3")
decision_body = function_body(pro, "static func noteSaveDecision(note: String, for path: String, in store: TagDatabase.Store? = nil) -> ProNoteSaveDecision")
require(decision_body, "manualNonEmptyNotePaths", "quota must count manual non-empty notes")
require(decision_body, "let hasExistingManualNote = manualNotePaths.contains(path)", "editing an existing note must not consume new quota")
require(decision_body, "guard manualNotePaths.count < limit else", "new notes beyond quota must be blocked")
require(decision_body, "case (true, false):", "deleting an existing note must release quota")
 
set_note_body = function_body(data_layer, "static func setAppNote(_ note: String, for path: String) -> ProNoteSaveDecision")
require(set_note_body, "ProEntitlementPolicy.noteSaveDecision", "note writes must ask Pro policy")
require(set_note_body, "guard case .allow = decision else", "blocked note writes must return before mutation")
require(set_note_body, "store.appNotes.removeValue(forKey: path)", "empty note must delete saved note")
require(set_note_body, "store.appNotes[path] = limited", "allowed non-empty note must save")
 
require(content, "presentProPrompt(for: .unlimitedNotes, noteQuotaStatus: status)", "blocked note save must show Pro prompt")
require(content, "noteQuotaHintText(for: context.app)", "editing bubble must show quota hint")
require(english, "3 app notes", "English UI must say 3 app notes")
require(chinese, "3 个应用备注", "Simplified Chinese UI must say 3 app notes")
if re.search(r"5[- ]?(note|app notes)|5 个应用备注|5 条备注", english + chinese):
    fail("old 5-note copy remains in English or Simplified Chinese")
 
print("PASS Pro notes quota QA: free limit is 3, existing edits/deletes are handled, over-quota writes are blocked, and UI copy no longer says 5 notes")
PY