尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Ledgerline · Three-way receiving reconciliation (Task 4)
Kestrel's handwritten register, ERP GRNs and storekeeper sheet never agree, and month-end takes
three days. Upload the four files once: an AI model reads the two register photos (twice,
independently), then code — never the model — normalises, reconciles, runs control checks and
proves completeness. Agreeing lines clear themselves; only doubtful items reach a person. On
finalise the controller gets a short Telegram summary plus report.html, exceptions first.查看完整 README ↗Kestrel's handwritten register, ERP GRNs and storekeeper sheet never agree, and month-end takes
three days. Upload the four files once: an AI model reads the two register photos (twice,
independently), then code — never the model — normalises, reconciles, runs control checks and
proves completeness. Agreeing lines clear themselves; only doubtful items reach a person. On
finalise the controller gets a short Telegram summary plus report.html, exceptions first.
Each photo is fingerprinted (SHA-256), so a later run only sends new pages to the model; pages
already read come from cache.
On the pack: 86 rows (28 register, 28 ERP, 30 sheet), every one in exactly one outcome. Problems found and how they surface:
| GRN | Problem | Outcome |
|---|---|---|
| 4409 | Sheet keyed twice | Duplicate, not double-counted |
| 4412 | ERP lot L2609-021 vs L2609-012 | Mismatch, ERP is the odd one out |
| 4415 | ERP date 13 Sep vs 12 Sep (a Sunday) | Mismatch + flag |
| 4417 | ERP qty 46 CTN vs 48 | Mismatch |
| 4419 | Register 60 struck out, 66 written | Person confirms, then sheet mismatch |
| 4421 | In register and sheet, not ERP | Missing from ERP |
| 4425 | Register 1200 yds = 1097.28 m; sheet 1200 m | Converted; sheet mismatch |
| 4428 | Register qty under an ink blot | Person enters it; never guessed |
| 4429 | In no source | Sequence gap to acknowledge |
| 4430 | ERP only, keyed 2 Oct by admin2 | Missing + backdated + unusual user |
| — | Sheet return row (Sunday, out of order) | Non-receipt |
Not flagged: "H202" (OCR of H2O2), text-date and Excel-serial dates, supplier and unit aliases.
Hosted: https://ledgerline-mutahir.vercel.app — demo credentials are in the submission
email. Start a run, upload the four files from data/kestrel-2026-09/, resolve the review items,
check Proof, then Finalise.
Local (Windows: Git Bash): Python 3.12, uv, Node 20+, pnpm, Supabase CLI.
make setup; create a Supabase project, supabase link, supabase db push.apps/api/.env.example to apps/api/.env, apps/web/.env.example to
apps/web/.env.local, fill in the table below.make seed [email protected] makes you CONTROLLER; set a password in Supabase.make dev, open http://localhost:3000. make test runs the offline suite (no keys).| Variable | App | Purpose |
|---|---|---|
SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY (secret) | api | Database and private storage |
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY | web | Login only; RLS denies tables |
OPENAI_API_KEY (secret), EXTRACT_MODEL, PROMPT_VERSION | api | Register reads |
EXTRACT_PRICE_INPUT_PER_MTOK, EXTRACT_PRICE_OUTPUT_PER_MTOK, EXTRACT_EST_INPUT_TOKENS_PER_PAGE, EXTRACT_EST_OUTPUT_TOKENS_PER_PAGE | api | Read-cost estimate |
TELEGRAM_BOT_TOKEN (secret), TELEGRAM_CONTROLLER_CHAT_ID, TELEGRAM_OPS_CHAT_ID | api | Summary chat and ops-alert chat |
LEDGERLINE_NOW, LEDGERLINE_CLOCK_MODE, LEDGERLINE_NOW_ANCHOR | api | Scenario clock (below) |
ALLOW_FAULTS | api | true only for the fault demo |
APP_BASE_URL, API_BASE_URL, CORS_ORIGINS | both | URLs |
BUILDER_EMAIL | make seed | Your login |
OPENAI_TIMEOUT_S, EXTRACT_ATTEMPTS, EXTRACT_BACKOFF_S, TELEGRAM_ATTEMPTS, TELEGRAM_BACKOFF_S, TELEGRAM_TIMEOUT_S, UPLOAD_WINDOW_S, DOWNLOAD_URL_S, JWKS_CACHE_S, JWKS_MIN_REFETCH_S, REPO_BACKEND | api | Tuning; defaults are right |
Scenario clock: LEDGERLINE_NOW=2026-10-15T08:30:00+05:00 replays the brief's "now";
LEDGERLINE_CLOCK_MODE=frozen holds it, offset (with LEDGERLINE_NOW_ANCHOR) lets it tick.
All code reads time through app/core/clock.py.
Telegram → WhatsApp: the sender is one small class (app/services/telegram.py). Moving to
the WhatsApp Cloud API means a pre-approved template for the summary (business-initiated),
report.html as a document message, and phone numbers instead of chat IDs; retries and
at-most-once logic stay as they are.
Nothing partial or wrong is ever sent, and nothing fails silently:
Bad input file: every problem listed, no model call made.
OpenAI slow or down: 3 retries with backoff, then the step fails and ops is alerted; retry re-reads only the failed page.
Proof fails: no report, no summary, ops alerted with the numbers.
Telegram down: the run still finalises, the summary is marked failed, a "Summary not delivered — Resend" banner appears, ops is alerted.
Finalising twice or a crash mid-send never sends a second message.
Same month and files finalised twice: refused with a link to the earlier run.
With ALLOW_FAULTS=true, an API call (not the web UI) with ?fault= and EXTRACT_TIMEOUT,
EXTRACT_BAD_JSON, TELEGRAM_DOWN or PROOF_DROP_ROW forces each path; the offline tests run all
four. Measured targets: NFR_REPORT.md.
Only Nocturnal's fictional pack. Only the register photos go to OpenAI; ERP and sheet data never
leave Supabase. Every normalised value keeps its raw value and a log entry. Files sit in private
buckets behind expiring signed links (10 min upload, 5 min download). The browser's anon key can
read no table; only the API's service key can. A controller can delete a run (its files, results
and report); the audit log keeps its history plus the delete, and cannot be edited or deleted. No
secrets in the repo: every .env file is git-ignored and gitleaks runs in CI.