Files
SimpleFarm/.workbuddy/memory/MEMORY.md
T
snowy-yang cb4c1e7800 feat(engine): 四座自动化设施——喷灌 / 收割机 / 售货机 / 磨坊
为什么:自动化建筑只有水井和喂食器,中期以后每天的操作只剩浇水喂食
的重复劳动。新设施把"替代行动点动作"的思路推到完整流水线:
浇水(井/喷灌)→ 收割机收熟地 → 磨坊把陈粮变饲料 → 喂食器喂牲口
→ 售货机趁高价清库存,人不在也能持续产出。

- config.BUILDINGS 注册 4 座:喷灌系统 2800 金(全量浇水)、
  自动收割机 900 金 ×3(每天各收 2 块熟地,刻意不给经验——机器收的
  不算劳动,给手动玩法留价值)、自动售货机 1200 金(市价 > 基准价才
  出手、每天上限 5 份、越贵越先卖)、饲料磨坊 500 金(1 份最便宜的
  作物磨 3 份饲料)。
- engine._run_buildings 扩成六段流水线,顺序即依赖:磨坊排在喂食器前,
  早上磨的饲料当天就能喂上;收割机遇满仓停摆、作物留地(同喂食器
  缺料停摆哲学——自动系统绝不硬来,更绝不自动花钱)。
- webui / build 动作 / catalog 全部由 config.BUILDINGS 驱动,零改动。
- 测试 +6(喷灌全量浇水、收割入库且无经验、满仓停摆留作物、磨坊挑
  最便宜、磨坊→喂食器同日链路、售货机阈值与配额)。修复断言时确认
  两个既有行为:引擎自带 START_FEED=5;advance_day 末尾会把动物 fed
  复位("喂到了"的证据是 pending 累计而非 fed 本身)。
- 门禁:534 项 OK(skip 39)、ruff/pyright 全绿。
2026-09-25 21:05:27 +08:00

78 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SimpleFarm 项目长期约定
## 是什么与运行
终端农场游戏 + 多人服务器(HTTP + SSE 给 AI/脚本;TUI/网页纯客户端)。
uv 管理:所有命令带 `uv run `;依赖只改 pyproject(uv add/remove),uv.lock 要提交;
requirements.txt 是导出产物只读。门禁(改动后必跑):
`uv run ruff format . && uv run ruff check . && uv run pyright && uv run python -m unittest discover -s tests`
(现 528 项;TestClient/真机档 39 项因无 httpx 自动 skip;`ruff check .` 会扫 tests,
测试文件要自己保持 lint 干净)。性能复核 `uv run python tools/bench.py --repeat 5`。
## 玩法与存档
- 一天 40 分钟(DEFAULT_TICK_SECONDS=2400);**没有手动快进一天**的入口,别再加。
- 天气 5 种决定水分蒸发,`state.forecast` 明天提前可见;收获进 `inventory` 谷仓、
`sell` 才换钱;建筑每天在 advance_day 里**先于生长**执行。
- 存档 SQLite `saves/farm.db` 一牧场一行:标量列 + 整份 payload JSON(加字段改
`_raw_state()`,不改表结构);SAVE_VERSION=2 / MIN=1 向后兼容;老 JSON 启动时自动
迁移(原文件 *.json.migrated 留底)。`StorageError = sqlite3.Error`,别写 except OSError。
WAL 是持久属性,建库设一次即可。测试钩子:`advance_day(weather="sunny")` 钉死天气。
## 架构约定
- 分层:engine 不认识网络;`server/actions.py` 是动作唯一登记表;RemoteFarm 与
FarmEngine 同名同语义(加动作两边都补)。StateView.apply():带 plots=整体替换、
不带=合并字段。farm/keys.py 是按键名唯一来源(全小写),tui.py 不许手写字符串字面量。
- session 的 `dirty`(推送节流,250ms 清)与 `unsaved`(自动存档依据,只有 save() 清)
必须分开——合并会让 autosave 瞎掉。网页禁用 window.prompt/confirm(嵌入预览里被
静默屏蔽),交互一律页面内弹层。
- **用户名登录(2026-09-23)**:仅用户名、一账号一牧场(用户名即 farm_id)。
`auth.py` 签发 HMAC HttpOnly Cookie `sf_auth`(30 天),密钥 `<save_dir>/secret.key`
(重启不掉线)。app.py 三个认 ?farm= 的地方(session_of / SSE / POST /api/farms)
都是**有 Cookie 强制本人牧场、无 Cookie 保持 ?farm= 旧语义**(脚本/AI 兼容)。
动登录逻辑别破坏这条边界;/api/me 刻意不 guard。
- SSE `/api/stream` 是唯一实时通道(单向);写操作一律 POST /api/actions;停机必须
hub.close_all()。uvicorn+zttp HTTP/2:uvicorn 0.53 不内置 h2,必须 `http="zttp"`;
信号接管=子类覆盖 Server.handle_exit(不调 super());as_asgi() 是 pyright 类型桥。
- app.py 结构:create_app 只装配,路由全在模块级 `_register_*`;轻量路径只走
brief_source()(BRIEF_KEYS 白名单要同步);>60 行的函数应视为信号。
- 守护进程:路径只有文件名时用 ensure_parent_dir()(别手写 makedirs(dirname));
pid 由服务进程自己写;端口自检用 port_busy()(判断「能连上」而非「能 bind」)。
## 本机环境(coreutils 残缺禁管道 / LF / 句柄等详见用户级记忆 ~/.workbuddy/MEMORY.md)
- `RemoteFarm.snapshot()` 是本地缓存不发请求;realtime=False 的脚本必须自己 refresh(),
否则轮询读到旧数据像卡死。
- 本机 HTTP 一律走 farm/net.py 的 open_url()(环境有 HTTP_PROXY 没 no_proxy)。
- 幂等补丁脚本注意:`new == ""` 时 `if new in text` 恒真会误报 ALREADY 漏改;
删除类编辑直接用 Edit 工具。
- 批量改同一文件用幂等补丁脚本(read_bytes/write_bytes + APPLIED/ALREADY/MISS);
同一文件一条消息里多次 Edit 会被静默覆盖。
## 远端与推送
- https://gitea.4i.hk/hhhge/SimpleFarm(public,main)。推送:
`NO_PROXY=gitea.4i.hk no_proxy=gitea.4i.hk GCM_INTERACTIVE=always git push origin main`
(NO_PROXY 缺了被系统代理拦成 502;GCM_INTERACTIVE 缺了 GCM 拒交互报
"Failed to authenticate")。还不行加 GCM_TRACE=1。沙箱会丢
.git/refs/remotes 写入使 status 显示 [gone]——假象,验证推送看 `git ls-remote`。
- credential.helper 链已修(2026-09-23 晚):system 级 `helper-selector` 会开
选择框等人点导致 push 永久挂死,已用 global **空 helper 重置列表**顶掉,
现为:"" → wincred → `!"C:/Program Files/Git/mingw64/bin/git-credential-manager.exe"`
(**必须带 `!` 和引号**,否则空格截断)。push 反复挂死先 taskkill 清
git.exe/GCM 僵尸(占 GCM 单例锁)。凭据库有 GCM 刷新令牌
`git:https://refresh_token.gitea.4i.hk`。
- 真浏览器验收(UI bug API 测不出):headless Chrome 自己起进程
(--headless=new --remote-debugging-port=9333 --user-data-dir=临时目录,
后台任务保活),agent-browser 用 `--cdp 9333` 连(每条命令都要带);
系统浏览器 --executable-path 直起会 exit 0 连不上。详见项目技能
simplefarm-verify-and-ship。
## webui 前端铁律(2026-09-23)
- **HTTP 头只允许 Latin-1**:用户可输入内容(中文用户名)塞进请求头会让
fetch 发送前抛 TypeError。headers() 里非 ASCII 一律不塞(登录态走 Cookie)。
- api() 必须接住 fetch 异常并 toast——静默 Promise 拒绝曾让登录后所有写
操作失效却毫无痕迹。
- localStorage 裸调用全走 lsGet/lsSet 兜底(sandbox iframe 无
allow-same-origin 时访问即抛,会炸掉整个启动脚本)。
## 文档
README.md 是入口文档(接口表、SSE 协议、设计取舍);当天记录在
.workbuddy/memory/YYYY-MM-DD.md。