Commit Graph

10 Commits

Author SHA1 Message Date
anonsaber 29178cb093 docs: fold quickstart into README, rename gateway→load balancer
Two changes requested by the user:

1. Fold the hand-holding quickstart tutorial into README §3 (both
   languages). Delete docs/quickstart.md and docs/quickstart.zh-CN.md.
   Remove them from all 5 validator DOCS lists, README §6 doc index,
   and charter §7 boundary table. The tutorial now lives as
   README §3.0–§3.11: prerequisites, create Telegram bot, find chat id,
   get JMAP credentials, run backend, sign in, fill config, register
   callbacks, enable processing, verify, schedule drain, troubleshoot.

2. Replace 'gateway'/'网关' with 'load balancer'/'负载均衡器' across
   all markdown (README, docs/, AGENTS.md, cloudflare-worker/README).
   Also fix 4 markdown anchor links whose heading slugs changed.
   Also fix charter §8 '18 safe routes' → '19' (was missed in the
   earlier reference.md fix).

GATE-DOCS 6/6 PASS (71 anchors, 727 path-refs, 455 sec-refs).
2026-10-08 21:35:14 +08:00
anonsaber 7ed1a086fe docs: add hand-holding quickstart tutorial (EN + ZH)
New docs/quickstart.md and docs/quickstart.zh-CN.md walk a human operator from
zero to the first notification: create a Telegram bot via BotFather, find the
chat id, get a Stalwart app password, provision Redis, deploy the container,
sign in with CONFIG_ENCRYPTION_KEY, fill the business config, register
callbacks, enable processing, verify end-to-end, and schedule the cron drain.

Every claim was verified against the code:
- healthz is static 200 'ok'; /ready returns 503 until all upstreams
  reachable, 200 with per-component booleans
- admin session TTL = 1800s (30 min) in state.rs
- first save must be complete -> 422 (is_complete in config.rs)
- 409 conflict on revision mismatch
- secrets are write-only (Option<SecretString>, never echoed)
- /worker and /reconcile return 204 on success, 503 when disabled
- webhook secret mismatch returns 401 (not 403)
- search triggers: 搜索/查找/检索 + /search command only
- cron-drain.sh uses MW_APP_URL (req), MW_WORKER_TOKEN (req),
  MW_RECONCILE_TOKEN (opt)

Registered both files in all 5 validator DOCS lists (audit_paths globs
automatically). Added rows to README §6 and charter §7 in both languages.
Added discoverable links from README §3 to the quickstart.

GATE-DOCS 6/6 PASS (71 anchors, 735 path-refs).
2026-10-08 17:35:35 +08:00
anonsaber 42128433ed docs: add the worker bilingual README and name both deployment forms
Root README gains §2 "Two ways to run it": a side-by-side table of
Form A (backend origin only) against Form B (behind the Cloudflare Worker
gateway) — what answers, failover, the callback URL to register, the
reachable route surface, which health endpoint to watch, and the docs to
read. Late in the switch: registration is idempotent and re-adding retires
the previous subscription, so the switch is one SPA field, not a migration;
nothing secret moves to the gateway; /api/bootstrap and /debug/* stay
origin-only either way. Later sections renumbered, and the monitoring
paragraph now points at the gateway aggregate GET /healthz-worker instead
of the origin-passthrough /healthz.

cloudflare-worker/README.md rewritten as the canonical English version and
cloudflare-worker/README.zh-CN.md added as its translation, covering the
route safelist (19 paths with per-path methods), the timeout/retry budget
with per-route overrides, bounded failover, the two health endpoints,
callback registration, config, local verification, deploy, and the design
invariants.

Both fixes along the way:

- README.zh-CN said the startup env block has 2 required + 2 optional
  variables; the table has 3 rows, 2 required + 1 optional.
- docs/charter.md §8 / registry list now names the zh-CN twin next to the
  gateway README.

scripts/docs_check gains the new file in validate_docs, check_tables,
audit_anchors and audit_anchor_semantics so it is checked like every other
document. check_sec_refs resolves §-refs against the document being scanned
when a basename is shared: README.md exists both at the repo root and under
cloudflare-worker/, and the basename-keyed heading map silently dropped one
of them. The gate was passing for the wrong reason before.

GATE-DOCS 6/6 clean: 72 anchors, 454 section refs, 727 path refs.
audit_anchor_semantics still reports the same 7 pre-existing candidates,
none in the new or edited files.
2026-10-01 13:40:39 +08:00
anonsaber 7a27f7ff00 docs: add bilingual guides and callback setup in SPA 2026-10-01 02:36:03 +08:00
anonsaber d4c4c1d09b docs: rename roadmap.md to opengaps.md and drop completed items
- rename docs/roadmap.md -> docs/opengaps.md: file now holds only
  still-open / still-unverified items, so the name matches its content
- removed items proven done during the 2026-09-28 live integration run:
  /search E2E, Telegram 429 backoff, multi-instance duplicate window,
  /ready end-to-end dependency probe, JMAP read-only adapter real-device
  verification, real platform log collection acceptance
- removed the C-NO-LONG-CONN long-polling item (permanent non-goal,
  already registered in docs/retired.md) and the duplicated Redis ACL
  encoding clause (merged into the Redis TLS item)
- removed the whole 验收待办 section (all 3 items resolved)
- narrowed the phase goal to setWebhook + PushSubscription callback chain
- baseline corrected 61 -> 69 passed / 0 failed / 1 ignored, re-measured
  2026-09-29 with cargo test --locked --bin message-weave
- docs/charter.md D-G1-1 marked real-device verified, closing the
  contradiction with docs/design.md:397/:600
- update the DOCS list in all 4 docs gate scripts + TARGET_BEFORE regex
- GATE-DOCS 6/6 pass: VALIDATION, TABLE, ANCHOR 269, SECTION-REF 224,
  SIZE, PATH 392
2026-09-29 19:38:38 +08:00
anonsaber 1ecba9d961 docs(tooling): close the phantom-identifier blind spot for bare filename anchors
audit_anchors.py's phantom check only ran on anchors carrying a line number
(`.rs:NN`), so a claim written next to a bare filename was never checked. And
fixing the regex alone would not have been enough: the verdict was a substring
test, so `TelegramClient::send` passed twice over -- `send` is a substring of
`send_text`, and reqwest's `.send()` is `send` at a word boundary, both in
src/channel.rs.

Adds PAIR_BARE for the bare-filename shape plus a stricter member_present test
(a definition site, or a reference not preceded by `.` or a word char) for it.
The numbered PAIR branch is untouched, so both the established
"248 line-refs checked, 0 errors" baseline and the `checked` counter are
unchanged.

The numbered branch deliberately keeps the loose test: a `T::member` claim next
to `foo.rs:NN` still passes when the member only exists as a longer name, but
there the anchor hands the reader a line to read, which is a weaker but honest
guarantee than the bare shape can offer.
2026-09-29 08:45:12 +08:00
anonsaber c8af429ffe fix(mode): restore executable bit on the doc validators
audit_anchors.py lost its exec bit and check_file_size.py was created without
one, so the scripts/ directory no longer had uniform permissions. run_all.sh
invokes them through python3 so nothing broke, but every sibling validator was
100755.
2026-09-29 01:16:43 +08:00
anonsaber 638c3a8cbc docs: consume all four self-checks; make the file-size rule enforceable
Every member's audit is now read and each real finding fixed, not just reported.

AGENTS.md §2.1
- The 500-line soft cap now has a machine-checkable exception: an over-limit
  file must carry a one-line `SPLIT-EVAL:` marker stating the split decision.
- Six files were over the cap with no justification: notify.rs 2036, state.rs
  1586, worker.rs 1045, config.js 1079, client.rs 601, config.rs 521. All now
  carry the marker. client.rs was missed by my own earlier line count, which
  did not descend into src/domain/jmap/.
- New validator scripts/docs_check/check_file_size.py; GATE-DOCS 4/4 -> 5/5.
  It proves the marker exists, not that the written reason is sound.
- Re-based 144 line anchors across six docs for the +1 line each file gained;
  every shifted anchor verified against the code, not just for non-blankness.

audit-arch.md
- design.md §6.1 module matrix omitted the `debug` module entirely; added.
- Seven numeric duplications in design.md now defer to reference.md §6.1 as
  the single authority instead of restating the values.
- reference.md §5.1 was missing DEBUG_TOKEN; §5.3 listed six recognised names
  and guessed `JMAP_*`. It now lists all 20 exactly as config.rs reads them.
- Corrected two wrong claims in the audit itself: debug.rs is compiled
  unconditionally, not under #[cfg(debug_assertions)] (there are no cargo
  features at all), and /debug/* exposes 7 routes, not the invented session
  list / resend / rebuild surface.

audit-fileplanner.md
- reference.md cited a nonexistent `jmap_service.rs`; replaced with the real
  adapter chain worker.rs -> domain/jmap.rs -> domain/jmap/client.rs.
- cloudflare-worker/README.md was outside every validator's scope; all four
  doc validators now include it (208 section refs, 250 line refs).
- README.zh-CN.md stated only half of what README.md says about RUN_MODE; the
  forward-placeholder sentence is now bilingual.
- charter.md §7 boundary table was missing rows for itself and for web/.

audit-rust.md / audit-frontend.md
- Error envelope corrected: `error` is a bare machine code, no `message`.
- Status table, AI-consent labels and ~15 stale or phantom facts fixed against
  notify.rs; `TelegramClient::SendMessage` and `web_config` phantoms removed.
- GET|PUT /api/enabled forwarded by the worker so the SPA kill switch works.
- Ten UI strings that called the admin credential the Redis ACL password now
  say CONFIG_ENCRYPTION_KEY.
- POST /healthz returns 405; dead HTTP_STATUS removed.
- audit_anchors.py now flags identifiers that do not exist in the file they
  are anchored to.

charter.md
- `SAF-ENABLE-FLAG` registered (85 IDs); `SAF-ADMIN-SESSION` row corrected;
- `REQ-PUSH-TYPES` registered; the stale `admin_session_digest` removed.

Gates: GATE-DOCS PASS 5/5 (250 line-refs, 208 section refs, 0 errors);
GATE-P0 62 passed / 0 failed / 1 ignored, baseline unchanged; worker and SPA
36 tests, 0 failures.

Real Stalwart / Telegram / managed Redis verification stays blocked on missing
credentials and remains labelled as unverified.
2026-09-29 01:16:11 +08:00
anonsaber e0882c7c68 docs: de-projectize AGENTS.md into language-agnostic norms; add docs/charter.md
AGENTS.md (276 -> 239 lines) is now a language-agnostic engineering-norms
document: code style, config and secrets handling, build environment,
testing gates, document governance. It states no project fact and names no
language, framework, dependency, or file. Verified: zero hits for JMAP,
Telegram, Redis, axum, Cloudflare, LLM, *.rs, and every project env var.

All project-specific content moved to the new docs/charter.md (~276 lines):
project goals, locked technology choices, 23 numbered security invariants,
implementation stages, prohibitions, test/acceptance gates with the full
GATE-P0 command and baseline, document boundary rules, and the stable ID
registry.

docs/charter.md §8 is the single authority index for stable IDs: 83 rows,
no duplicates, ID | definition file | one-line statement | category. Four
IDs that were referenced across the docs but never registered are now
registered: ARCH-STATE-REDIS, C-REDIS-EXTERNAL, GATE-UPTIME-KUMA, GATE-DOCS.
All previously registered IDs are preserved.

Defect fixed while rebuilding the registry: SAF-ADMIN-SESSION cited
src/config.rs `admin_session_digest`, a name that has 0 hits in src/ -- a
phantom identifier that survived in the authoritative registry since before
this restructure. Corrected to `session_digest` (src/config.rs:7). All 8
distinct backticked symbols in the registry's definition-file column now
verify against src/.

Two false project facts removed from the docs (both claimed the SPA writes
through POST /api/bootstrap, which web/config.js never calls -- 0 hits; the
actual path is PUT /api/business-config): README.md, README.zh-CN.md,
docs/reference.md. The first successful write creates the configuration and
later writes hot-reload it; POST /api/bootstrap remains the one-shot
automation endpoint.

Cross-reference redirections in 9 files: README.md, README.zh-CN.md,
docs/deployment.md, docs/design.md, docs/reference.md,
cloudflare-worker/README.md, cloudflare-worker/src/index.js,
cloudflare-worker/wrangler.toml now point project facts at charter.md and
language-agnostic quality rules at AGENTS.md.

Four validators extended to cover docs/charter.md: DOCS lists in
audit_anchors.py, check_tables.py, validate_docs.py, check_sec_refs.py, plus
charter.md added to check_sec_refs.py's TARGET_BEFORE regex and to
validate_docs.py's index-file cross-doc exemption.

Gates: GATE-DOCS PASS 4/4 (VALIDATION 0 errors, TABLE STRUCTURE 0
mismatches, ANCHOR AUDIT 227 line-refs / 0 errors, SECTION-REF AUDIT 191
refs / 0 errors). GATE-P0 PASS, baseline unchanged 62 passed / 0 failed /
1 ignored. Anchor audit proves line reachability only, not that the line
contains what the prose claims.
2026-09-28 23:39:26 +08:00
anonsaber a2297c21e8 tools: 固化文档校验器为 GATE-DOCS(此前只存在于 /tmp,保证不可复现)
四个校验器原先散落在 /tmp,本会话 /tmp 就被清过一次(validate_docs.py
中途消失),仓库里没有任何引用——「222 个行号锚点 0 error」这个结论在脚本
被清之后就无从再证,属于静默漂移。现固化进 scripts/docs_check/:

- validate_docs.py  代码块围栏闭合 / 行内反引号偶数 / 本地链接与 #锚点可达
- check_tables.py   表格表头、分隔行、数据行列数一致(行内代码里的 | 不计)
- audit_anchors.py  每个 foo.rs:N / foo.rs:N-M 锚点指向存在且非空的目标行
- check_sec_refs.py 每个 §N.N 交叉引用解析到归属文档的真实标题
- run_all.sh        驱动脚本,任一失败即 exit 1,仿 GATE-P0 的用法

改动说明(相对 /tmp 原版)
- ROOT 由硬编码绝对路径改为 Path(__file__).resolve().parents[2],干净 clone
  即可运行,无需改任何路径。四个文件已 diff 确认仅此一处差异。
- audit_anchors.py 加了 docstring 写明能力边界:只证明锚点可达,不证明该行
  内容与所述一致,无法发现「指向错行」的锚点。
- run_all.sh 用 grep -m1 '^===' 取摘要而非 head -1:validate_docs.py 摘要前
  带一个空行(原版自带瑕疵,保留原样以免偏离已验证版本),按位置取会取错。

双向验证:干净树 PASS/exit 0;注入 worker.rs:99999 与 §99.9 后分别被
audit_anchors 与 check_sec_refs 报出、exit 1;git checkout 还原后回到 PASS。

AGENTS.md 记录跑法与「可达 ≠ 准确」的区分。GATE-P0(cargo)不受影响,本次
无任何 src/ 改动。
2026-09-28 21:58:07 +08:00