# PROGRESS · Python 引擎运行时治理(2026-09-01) 工作树:`.worktrees/engine-runtime-hygiene-20260901` 分支:`codex/engine-runtime-hygiene-20260901` HEAD:`80e7736163be684119c03013a07980031468c634`(仍等于 `origin/staging`) 未提交、未推送。未改 `frontend/src/app/page.tsx`。未改 `.gitea/workflows/**`。未切分支、未 reset。迁移 squash 按任务书明确延后。 ## 任务 1 · api 命名卷 - 容器 `WORKDIR`(`deploy/railway-api.Dockerfile`):`/app` - 代码路径:`Path(REPO_ROOT) / 'scratch' / 'local' / ...` → 容器内 **`/app/scratch/local`** - Compose 卷名:`api_scratch` - 挂载:`api_scratch:/app/scratch/local`(`deploy/docker-compose.server.yml` 的 api 服务) - 项目前缀后的 Docker 卷名:`jyotisha-staging_api_scratch` / `jyotisha-production_api_scratch` - 向后兼容:首次 `docker compose up` 创建命名卷;当前 overlay 数据本就是易失的,无迁移 **备份结论(已写入 `deploy/README.md`)** - Chart cache(`/app/scratch/local/api_chart_cache`,默认 TTL 900s)不值得备份;重建比归档便宜。 - Async / high-rigor job 态(`async_jobs` / `async_jobs.sqlite3` / `high_rigor_jobs`,默认 TTL 3600s)是短生命周期进行中工作,不是恢复单元。 - Staging 加密备份继续只走 `deploy/backup-staging-postgres.sh`。**不要**把 `api_scratch` 加进该脚本。命名卷的唯一目标是容器重建后缓存与进行中任务还在。 **Deploy 脚本:** `run-staging-deploy.sh` / `run-production-deploy.sh` **未改**。`docker compose up` 会创建并重新挂上命名卷;现有 `up -d --remove-orphans` 不会 `down -v`。 **Staging 实机三条验收(blocked)**:需要真正 dispatch 部署后才能 `docker volume ls`、重启 api 证明 `/app/scratch/local` 存活、核对 `/api/health`。Compose 挂载合同已锁在 `tests/test_railway_deployment.py`。 ## 任务 2 · 冻结 `jyotish_api_server.py` - 开工 live `wc -l`:**11063**(任务书 11035 已过时;出生精度合入后又涨了约 28 行) - 本轮薄注册后:**11088** - 合同上限:**11363**(11063 + 300 bugfix slack) - 测试:`tests/test_api_server_growth_contract.py`(注释写明新功能必须开模块) - 已列入 `scripts/run_quality_gate.py` `CORE_PYTEST_TARGETS` - 根 `AGENTS.md` 第 8 节:`scripts/jyotish_api_server.py` must not grow;新端点/功能落 `scripts/` 模块,主文件只薄注册 ## 任务 3 · 重计算并发闸 新模块 `scripts/api_heavy_compute_gate.py`。主文件只 import,并在 `do_POST` 里 acquire/release。`GET`(含 `/api/health` 与 job 轮询)不经过闸门。 - 环境变量 `JYOTISH_HEAVY_COMPUTE_CONCURRENCY`,默认 **2**(对齐 2 vCPU) - `JYOTISH_HEAVY_COMPUTE_RETRY_AFTER_SECONDS`,默认 **2** - 饱和:fail-fast,不排队。HTTP **429** + `Retry-After` + `error_code=ERR_COMPUTE_BUSY` **入闸端点** - `POST /api/rectification/sensitivity_scan` - `POST /api/active_rectification_events` - `POST /api/active_rectification_events_v4` - `POST /api/rectification/v5/candidate-features` - `POST /api/rectification/v5/score` - `POST /api/rectification/v5/diagnostics` - `POST /api/rectification/v5/vedastro-validate` - `POST /api/dynamic_rectification_opportunities` - `POST /api/dynamic_rectification_score` - `POST /api/high_rigor_workflow` - `POST /api/consultation_workflow` - `POST /api/professional_reading` - `POST /api/vedastro/range_scan` - `POST /api/vedastro_gateway/run` - `POST /api/vedastro_gateway/jobs/{id}/run`(前缀匹配) - `POST /api/thematic_report` **不入闸:** `GET /api/health`、城市/位置解析、job 轮询、`/api/chart`(已有 TTL 缓存 + `JYOTISH_ASYNC_JOB_*` 有界队列;再叠 429 会误伤常规排盘)、问卷、v5 versions、capability/catalog 等轻量路由。 ## 验证命令与输出 ```text /opt/anaconda3/bin/python3.12 -m pytest \ tests/test_api_server_growth_contract.py \ tests/test_api_heavy_compute_gate.py -v ``` ```text collected 7 items tests/test_api_server_growth_contract.py ... [ 42%] tests/test_api_heavy_compute_gate.py .... [100%] ============================== 7 passed in 0.28s =============================== ``` 饱和用例(limit=1):第二个重请求 **429** + `Retry-After: 2` + `ERR_COMPUTE_BUSY`;释放后 200;同期 `GET /api/health` 与 `POST /api/location/resolve` 仍 200。 ```text /opt/anaconda3/bin/python3.12 -m pytest tests/test_api_server_security.py -q # 129 passed, ~90s(仅 datetime.utcnow DeprecationWarning) /opt/anaconda3/bin/python3.12 -m pytest \ tests/test_runtime_security_p0.py \ tests/test_api_server_script_entrypoint.py -q # 11 passed /opt/anaconda3/bin/python3.12 -m pytest \ tests/test_api_async_job_contract.py \ tests/test_railway_deployment.py \ tests/test_api_server_security.py::test_health_endpoint_exposes_runtime_accuracy_metadata \ tests/test_api_server_security.py::test_vedastro_range_scan_endpoint_uses_user_birth_and_returns_controlled_blocked_state \ tests/test_api_server_security.py::test_professional_reading_composes_high_rigor_and_gateway \ tests/test_api_server_growth_contract.py \ tests/test_api_heavy_compute_gate.py -v # 22 passed in 0.38s ``` `python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` → `status=pass`。 未改前端,故未跑 `npm test` / tsc。未跑完整 `scripts/run_quality_gate.py --profile quick`(quick 仍会跑 Next.js test/lint/build;本轮前端豁免)。 ## 改动文件 - `deploy/docker-compose.server.yml` - `deploy/README.md` - `AGENTS.md` - `scripts/jyotish_api_server.py`(薄注册;+25 行) - `scripts/api_heavy_compute_gate.py`(新) - `scripts/run_quality_gate.py` - `tests/test_api_server_growth_contract.py`(新) - `tests/test_api_heavy_compute_gate.py`(新) - `tests/test_railway_deployment.py` - `PROGRESS-engine-runtime-hygiene-20260901.md`(本文件) 未改:`deploy/run-staging-deploy.sh`、`deploy/run-production-deploy.sh`、`deploy/backup-staging-postgres.sh`。 ## 明确未做 / blocked - Staging/production 实机挂卷、重启存活、`/api/health` 部署 SHA(需部署窗口)。 - 完整 quick gate(含 frontend runtime)。 - 迁移 squash。 - 把 `/api/chart` 同步路径送进这道闸。 - 提交 / 推送 / 提升 `main`。