docs: revise M2 plan per independent plan review
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
| `src/polygateway/backends/redis/__init__.py` | C | 导出 RedisLimiter/RedisGate |
|
||||
| `src/polygateway/backends/redis/limiter.py` | C | 六道闸 Lua + RedisLimiter/_RedisPermit |
|
||||
| `src/polygateway/backends/redis/breaker.py` | C | 熔断五操作 Lua + RedisGate |
|
||||
| `src/polygateway/middleware/retry.py` | M | stall 双条件 + poll jitter + 记账侧降级捕获 |
|
||||
| `src/polygateway/middleware/retry.py` | M | stall 双条件 + poll jitter + 记账侧降级捕获 + `_backoff_delay` 提取为模块级纯函数 |
|
||||
| `src/polygateway/middleware/ratelimit.py` | M | QuotaGate 增 `progress_age_s()` 透传(stall 判定消费) |
|
||||
| `src/polygateway/telemetry/postgres.py` | C | PostgresRecorder(18 列,两级降级) |
|
||||
| `src/polygateway/pricing.py` | C | ModelPrice/PricingTable |
|
||||
| `src/polygateway/middleware/telemetry.py` | M | TelemetryEmitter 增 pricing 注入,cost 换算 |
|
||||
@@ -23,7 +24,7 @@
|
||||
| `src/polygateway/embedding.py` | C | EmbeddingClient(精简治理循环 + from_env/from_settings) |
|
||||
| `src/polygateway/config.py` | M | 解禁 redis 后端键、telemetry 白名单扩 postgres、新键 PG_DSN/PRICING_PATH/BATCH_SIZE 等、probe_ttl 派生补第三项、守卫补齐 |
|
||||
| `src/polygateway/client.py` | M | from_settings 分支建 Redis 后端/PostgresRecorder/PricingTable;aclose 探测 async aclose |
|
||||
| `pyproject.toml` | M | extra `postgres = ["asyncpg>=0.29"]`;import-linter 契约补 redis 后端模块 |
|
||||
| `pyproject.toml` | M | 核对既有 `postgres` extra(已存在于 pyproject.toml:22,勿重复添加);pytest `addopts = -m "not slow"`(见 T3);import-linter layers 契约已覆盖 `backends` 子包,**无需改动** |
|
||||
| `.env.example` | M | 回填全部新键 |
|
||||
| `tests/contracts/conftest.py` | M | fixture 增 redis param + 哨兵时钟 |
|
||||
| `tests/integration/test_redis_governance_time.py` | C | 时间语义 1:1 真实等待变体(slow) |
|
||||
@@ -55,7 +56,9 @@ T6-T9 非迁移(Postgres/pricing 零先例;Embedding 为按设计 §7.3 裁决
|
||||
2. `PGW_TELEMETRY_BACKEND` 白名单 → `("sqlite","postgres","none")`;`postgres` 时 `_require("PGW_TELEMETRY_PG_DSN")`;DSN 若含 `+asyncpg`/`+psycopg` 后缀在装配层剥为 `postgresql://`。
|
||||
3. 新可选键 `PGW_PRICING_PATH`(存 `GatewaySettings.pricing_path: Path | None`)。
|
||||
4. probe_ttl 缺省派生式改为 `max(2×最大源 timeout_s, cooldown_s, 最大源 timeout_s+5)`;新增装配守卫 `probe_ttl_s ≥ max(timeout_s)+5`、核对既有守卫 `max(timeout_s) ≤ lease_ttl_s` 与 `stall_window_s ≥ max(ttft_timeout_s)`(缺则补),违反 ValueError。
|
||||
5. `pyproject.toml`: extra `postgres=["asyncpg>=0.29"]` 并入 `all`;import-linter 独立实现层清单加 `polygateway.backends.redis`。
|
||||
5. `pyproject.toml`: 仅核对——`postgres` extra 已存在(pyproject.toml:22),import-linter layers 契约自动涵盖 `backends.redis` 子包,两者**均无需改动**。
|
||||
6. DSN 存 `GatewaySettings.telemetry_pg_dsn: str | None`(T6 消费此字段名)。
|
||||
7. **既有测试修订**: `tests/unit/test_config.py:111-112` 显式 `PROBE_TTL_S=45`(源 timeout=120)将触新守卫 → 改为合法值(≥125)并保留断言意图;另增守卫违反用例。`.env` 实况已核:probe 走派生路径(240≥125),e2e 装配不受影响。
|
||||
|
||||
**测试(先红)**: redis 后端键通过校验/缺 REDIS_URL 报错;postgres 缺 DSN 报错;DSN 后缀剥离;派生式三项取最大;守卫违反报错。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/unit/test_config.py -v` 全 PASS;`make lint`。
|
||||
@@ -79,11 +82,11 @@ class RedisLimiter:
|
||||
**行为**(逐段比对 CHS,设计 §2.2 保真点全数落实):
|
||||
- Lua 常量:ACQUIRE(六闸同脚本,判据顺序与 `>=`/`+est>` 语义照抄 scripts.py:6-34)、RELEASE(37-41)、SETTLE(44-48)、STATS(含 ZREMRANGEBYSCORE 清过期)、PROGRESS_MARK(60-67)、PROGRESS_AGE(70-78)。key 前缀 `pgw:limit:`,布局 `pgw:limit:{GLOBAL|<scope>}:{<source>|}:lease|rpm:{win}|tpm:{win}`,窗口 id = `redis.time() sec//60`。
|
||||
- `_RedisPermit`:released/settled flag 幂等;settle 只动 TPM、`INCRBY delta`、落 acquire 窗口;`source_stats` 读侧 `max(0, ·)` clamp。
|
||||
- 限额 0 = 该闸不启用(与内存版一致,Lua ARGV 传 0 时跳过该闸——CHS 同款,比对 scripts.py 闸判据的 `>0` 守卫)。
|
||||
- 限额 0 = 该闸不启用——**这是对 CHS 的有意偏离,不是同款**(核实:CHS scripts.py:18-23 六判据均为裸比较、无 `>0` 守卫,0 在 CHS 语义下是全拒,CHS 靠传大数表示不限);M1 契约已冻结 0=禁用(`_NO_GLOBAL = GlobalLimits(0,0,0)`),故库版 Lua **显式新增** `limit > 0` 守卫。逐段比对时此处以设计 §9 勘误行为准,勿视为失真。
|
||||
- RedisError:try_acquire/acquire/source_stats/progress_age_s → `GovernanceBackendError`;settle/release → `logger.warning` 降级(设计 §10)。mark_progress 也抛 `GovernanceBackendError`(降级责任在中间件,T5)。
|
||||
- `aclose()` 幂等关闭自建 client(from_url 路径);注入 client 不代关。
|
||||
|
||||
**契约接入(红→绿证据)**: conftest `limiter_factory` params 增 `"redis"`:读 `REDIS_URL`(缺则 `pytest.skip`),每次构造用唯一 `scope=f"t{uuid4().hex[:8]}"`;`clock` fixture 对 redis param 返回哨兵 `SkipClock`(`advance()` 即 `pytest.skip("redis 时间语义由 tests/integration/test_redis_governance_time.py 变体覆盖")`)。**先提交 conftest 增参跑一次记录红**(RedisLimiter 未实现 → collection/构造失败),实现后非时间用例全绿。
|
||||
**契约接入(红→绿证据,conftest 结构定案)**: 重构为单一 `backend` fixture(`params=["memory","redis"]`,async fixture),`clock` 与两工厂**都依赖它**——memory 时 clock=FakeClock、工厂建内存版;redis 时 clock=哨兵 `SkipClock`(`advance()` 即 `pytest.skip("redis 时间语义由 tests/integration/test_redis_governance_time.py 变体覆盖")`)、工厂建 Redis 版(读 `REDIS_URL`,缺则 skip;每次构造唯一 `scope=f"t{uuid4().hex[:8]}"`);redis param 的 fixture setup 先做**分钟窗口 headroom 防抖**(`redis.time()` 剩余窗口 <10s 则睡至翻滚,防 RPM/TPM 用例跨窗 flake,CHS `_await_window_headroom` 同款)。**先提交 conftest 增参跑一次记录红**(RedisLimiter 未实现 → 构造失败),实现后非时间用例全绿。
|
||||
|
||||
**验证**: `conda run -n PolyGateway pytest tests/contracts/test_limiter_contract.py tests/unit/test_redis_key_layout.py -v` → memory 全 PASS + redis 非时间用例 PASS + 时间用例 SKIP(2 个:`test_lease_expiry_reclaims_slot`、`test_progress_marks_fresh`)。
|
||||
- [ ] 提交 `feat: add redis six-gate rate limiter backend`
|
||||
@@ -109,7 +112,9 @@ class RedisLimiter:
|
||||
|
||||
**文件**: `tests/integration/test_redis_governance_time.py`(C)
|
||||
|
||||
**1:1 映射表**(每行一个 `@pytest.mark.slow` 用例,断言与契约原用例同名行为;配置用真实量级:BreakerConfig(fail_threshold=3, cooldown_s=60.0, probe_ttl_s=120.0) 同契约 `_CFG`;limiter lease_ttl_s=30.0;等待 = `asyncio.sleep(时长+1)`):
|
||||
**注**: 设计 §2.3 写"10 用例(限流 2+熔断 8)"为笔误——契约文件实际含 `clock.advance` 的用例是 **9 个**(熔断 7:`test_stale_epoch_write_rejected` 虽声明 clock 但无 advance,属非时间用例应 PASS),本表为准。**slow 排除策略(全局)**: pyproject `[tool.pytest.ini_options]` 增 `addopts = "-m \"not slow\""`——pre-commit hook 与 `make test` 默认跳过 slow(否则每次提交等 15 分钟),显式 `pytest -m slow` 覆盖之(CLI 的 `-m` 后到覆盖 addopts);T12 显式跑全量 slow。
|
||||
|
||||
**1:1 映射表**(每行一个 `@pytest.mark.slow` 用例,断言与契约原用例同名行为;配置用真实量级:BreakerConfig(fail_threshold=3, cooldown_s=60.0, probe_ttl_s=120.0) 同契约 `_CFG`;limiter lease_ttl_s=30.0;等待 = `asyncio.sleep(时长+1)`,**唯 #2 例外精确睡 42s**——其断言 `41<age<43` 有上界):
|
||||
|
||||
| # | 契约原用例(skip 于 redis param) | 变体断言要点 | 真实等待 |
|
||||
|---|---|---|---|
|
||||
@@ -125,7 +130,7 @@ class RedisLimiter:
|
||||
|
||||
另加:RPM/TPM 分钟窗口翻滚用例(等待至下一分钟边界,移植 CHS `tests/integration/test_redis_limiter.py:17-30` `_await_window_headroom` 防抖:剩余窗口 <10s 先等翻滚)。整文件预计 12-15 分钟。
|
||||
|
||||
**完整性守卫**: 文件头一个 meta 断言用例——收集 redis param 下契约 skip 的用例名集合(硬编码上表 9 名),与本文件变体函数名集合比对,防未来契约新增时间用例而变体漏配。
|
||||
**完整性守卫**: 文件头一个 meta 断言用例——**解析两份契约测试源码**(ast/正则)提取所有调用 `clock.advance` 的测试函数名集合,与本文件变体函数名集合(约定 `test_variant_<原名>`)比对相等;未来契约新增时间用例而变体漏配即此 meta 用例红(手维护清单达不到此效果)。
|
||||
**红→绿**: 变体先写、RedisLimiter/RedisGate 已存在故直接跑;每例首跑必须真实观察等待(执行时禁止用 FakeClock 捷径)。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/integration/test_redis_governance_time.py -v -m slow`(全 PASS,时长 >600s 属预期)。
|
||||
- [ ] 提交 `test: add real-wait time-semantics variants for redis backends`
|
||||
@@ -135,8 +140,8 @@ class RedisLimiter:
|
||||
**文件**: `tests/integration/test_redis_cross_connection.py`(C)
|
||||
|
||||
**行为**(双连接池 = 多 worker 等价,人类已认可):
|
||||
1. 移植 CHS 三用例(蓝本 `reference/CHSAnalyzer/tests/integration/test_redis_limiter.py:105-188`):双连接池共享全局并发 / 共享全局 RPM / 进度跨连接可见。
|
||||
2. 联合验证:两个 `GatewayClient`(各自连接池、同 scope、MockTransport)+ 双源;断言 (a) 源 A 熔断开路后另一 client 的 try_enter 也被拒(状态共享);(b) 全局 RPM=N 时两 client 并发打满,遥测重算任意 60s 窗口 ≤N(不超配);(c) in-flight 取消 → lease 释放(`source_stats.inflight` 归零)。
|
||||
1. 移植 CHS 用例(蓝本 `reference/CHSAnalyzer/tests/integration/test_redis_limiter.py`):**2 个跨连接用例**(:127 双连接池全局并发、:166 进度跨连接可见)+ 将 `test_global_rpm_cap`(:105,CHS 原版为单连接)**升级为跨连接**版本(两池共享全局 RPM)。
|
||||
2. 联合验证:两个 `GatewayClient`(各自连接池、同 scope、文件内自建 ScriptedTransport——参照 `tests/unit/test_retry.py` FakeTransport 形态,库内无现成 MockTransport)+ 双源;断言 (a) 源 A 熔断开路后另一 client 的 try_enter 也被拒(状态共享);(b) 全局 RPM=N 时两 client 并发打满,遥测重算任意 60s 窗口 ≤N(不超配);(c) in-flight 取消 → lease 释放(`source_stats.inflight` 归零)。
|
||||
3. Redis 掉线方向:对错误端口的 RedisLimiter/RedisGate,准入侧抛 `GovernanceBackendError`(fail-closed 集成证据)。
|
||||
|
||||
**验证**: `conda run -n PolyGateway pytest tests/integration/test_redis_cross_connection.py -v` 全 PASS。
|
||||
@@ -144,12 +149,14 @@ class RedisLimiter:
|
||||
|
||||
## T5 背压 stall + 记账侧降级(`middleware/retry.py`)
|
||||
|
||||
**文件**: `src/polygateway/middleware/retry.py`(M)、`tests/unit/test_backpressure.py`(C)
|
||||
**文件**: `src/polygateway/middleware/retry.py`(M)、`src/polygateway/middleware/ratelimit.py`(M)、`tests/unit/test_backpressure.py`(C)
|
||||
|
||||
**行为**(比对 governance.py:200-285):
|
||||
1. 循环入口记 `entered_at = self._now()` 一次,**不重置**(CHS :207 口径)。
|
||||
2. `_on_no_runnable` wait 分支:`local_waited > stall_window_s and await self._quota.progress_age_s() > stall_window_s` → `raise AllSourcesExhausted(scope, reason="stalled", retry_after_s=await self._breaker.retry_after_s(names), per_source_reasons=reasons)`;否则 `await self._sleep(self._bp.poll_interval_s * (0.5 + 0.5 * self._rng()))`(:283-285)。fail_fast 路径不变。
|
||||
3. 记账侧降级:`record_success`/`record_failure`/`mark_progress`/`release_probe` 的调用点包 `try/except GovernanceBackendError: logger.warning(...)`,收敛为单个私有 helper `_record_quietly(coro)`;不吞 CancelledError;`_settle_and_release` 既有降级保持。
|
||||
1. `ratelimit.py` 的 `QuotaGate` 增透传方法 `async def progress_age_s(self) -> float`(现仅有 try_acquire/stats/mark_progress,直接委托 `self._limiter.progress_age_s()`,异常原样冒泡归准入侧语义)。
|
||||
2. 循环入口记 `entered_at = self._now()` 一次,**不重置**(CHS :207 口径)。
|
||||
3. `_on_no_runnable` wait 分支:`local_waited > stall_window_s and await self._quota.progress_age_s() > stall_window_s` → `raise AllSourcesExhausted(scope=self._scope, reason="stalled", retry_after_s=await self._breaker.retry_after_s(names), per_source_reasons=reasons)`(构造函数 keyword-only,errors.py:72-80);否则 `await self._sleep(self._bp.poll_interval_s * (0.5 + 0.5 * self._rng()))`(:283-285)。fail_fast 路径不变。
|
||||
4. 记账侧降级:`record_success`/`record_failure`/`mark_progress`/`release_probe` 的调用点包 `try/except GovernanceBackendError: logger.warning(...)`,收敛为单个私有 helper `_record_quietly(coro)`;不吞 CancelledError;`_settle_and_release` 既有降级保持。
|
||||
5. **提取退避纯函数**(T9 消费,本任务交付):实例方法 `_backoff_delay`(retry.py:254-259)提升为模块级 `def backoff_delay(policy: RetryPolicy, fails: int, exc: BaseException | None, rng: Callable[[], float]) -> float`,RetryMW 内部改为调用它;行为零变化,既有 test_retry 回归即证据。
|
||||
|
||||
**测试(先红,memory 后端 + FakeClock)**: stall 四象限(仅本地超窗不判死/仅全局超窗不判死/双超窗抛 stalled 且 reason 正确/未超窗继续 poll);jitter 界 [0.5p, p];记账降级——注入 record_success 抛 GovernanceBackendError 的 FakeGate,断言成功响应仍返回且有 warning;取消在 stall 等待中穿透。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/unit/test_backpressure.py tests/unit/test_retry.py -v` 全 PASS(既有 retry 测试回归)。
|
||||
@@ -235,7 +242,20 @@ class EmbeddingTransport(Protocol):
|
||||
|
||||
## T9 EmbeddingClient 治理循环 + 装配 + e2e 探测
|
||||
|
||||
**文件**: `src/polygateway/embedding.py`(C)、`src/polygateway/config.py`(M:`{SCOPE}__BATCH_SIZE` 必填、`{SCOPE}__NORMALIZE`/`{SCOPE}__EXPECTED_DIM` 可选)、`src/polygateway/__init__.py`(M:导出)、`tests/unit/test_embedding.py`(M)、`tests/e2e/test_embed_probe.py`(C)
|
||||
**文件**: `src/polygateway/embedding.py`(C)、`src/polygateway/config.py`(M)、`src/polygateway/__init__.py`(M:导出)、`tests/unit/test_embedding.py`(M)、`tests/e2e/test_embed_probe.py`(C)
|
||||
|
||||
**装配定案(不动 GatewaySettings 冻结形态)**: config.py 新增独立
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class EmbeddingSettings:
|
||||
gateway: GatewaySettings # 复用 from_env(scope) 的源表/韧性/遥测/redis 字段
|
||||
batch_size: int # {SCOPE}__BATCH_SIZE 必填,≥1
|
||||
normalize: bool = False # {SCOPE}__NORMALIZE 可选(true/false)
|
||||
expected_dim: int | None = None # {SCOPE}__EXPECTED_DIM 可选,≥1
|
||||
@classmethod
|
||||
def from_env(cls, scope: str = "EMBED", env=None) -> "EmbeddingSettings": ...
|
||||
```
|
||||
EMBED 专用键**不**进 GatewaySettings(LLM scope 不受影响);`EmbeddingClient.from_settings(EmbeddingSettings, *, limiter=None, breaker=None, telemetry=None)` + `from_env` 委托之(cache/structured 键对 embedding 无意义,装配时忽略)。
|
||||
|
||||
**接口**:
|
||||
```python
|
||||
@@ -255,7 +275,7 @@ class EmbeddingClient:
|
||||
async def aclose(self) -> None: ...
|
||||
```
|
||||
|
||||
**行为**: 空输入即返空响应零请求;按 batch_size 切批,批间串行;每批 = 完整治理调用:选源(selector+cooldown memo)→ try_enter → try_acquire → transport.embed → 成功 record_success+settle+mark_progress / 失败按四分类 record_failure(SourceDead force_open)换源退避——退避公式复用 retry.py 提取的模块级纯函数 `backoff_delay(policy, fails, exc, rng)`(T5 中提取,此处 import);stall 双条件与 quota_full 语义同 chat;每批遥测一行(messages=texts 截断摘要 JSON、response=`"<vectors n=N dim=D>"`、thinking=""、completion_tokens=0),cost 经 pricing;聚合响应 vectors 拼接、tokens 求和、usage_source 任一 estimated 则 estimated、call_id 取首批;normalize=True 时纯 Python L2 归一化(`max(norm,1e-12)` 防除零,VT embedding.py:167-170 语义);expected_dim 不符 → ResultInvalidError。取消穿透:批间/等待/请求中取消即上抛,in-flight permit/probe 在 finally 释放。
|
||||
**行为**: 空输入即返空响应零请求;按 batch_size 切批,批间串行;每批 = 完整治理调用:选源(selector+cooldown memo)→ try_enter → try_acquire → transport.embed → 成功 record_success+settle+mark_progress / 失败按四分类 record_failure(SourceDead force_open)换源退避——退避公式复用 retry.py 提取的模块级纯函数 `backoff_delay(policy, fails, exc, rng)`(T5 中提取,此处 import);stall 双条件与 quota_full 语义同 chat;每批遥测一行(messages=texts 截断摘要 JSON、response=`"<vectors n=N dim=D>"`、thinking=""、completion_tokens=0),cost 经 pricing;聚合响应 vectors 拼接、prompt_tokens 求和、latency_ms 求和、usage_source 任一 estimated 则 estimated、call_id 取首批;normalize=True 时纯 Python L2 归一化(`max(norm,1e-12)` 防除零,VT embedding.py:167-170 语义);expected_dim 不符 → ResultInvalidError。取消穿透:批间/等待/请求中取消即上抛,in-flight permit/probe 在 finally 释放。
|
||||
**测试(先红,ScriptedEmbeddingTransport)**: 分批数与保序;归一化数值;expected_dim 违约;TransientError 重试换源、SourceDead 熔断换源;批失败时已完成批不重发(整调用失败上抛,已耗批次遥测可见);取消释放;遥测行字段与 usage_source 聚合。
|
||||
**e2e 探测(人类默认认可)**: `test_embed_probe.py` 对 `.env` MiniMax 源发一次真实 `/embeddings` 请求(无 EMBED 源配置则用 LLM 源 base_url);200 → 断言向量返回并落 `tests/outputs/embedding/`;404/不支持 → `pytest.skip` 并把响应记录进 outputs(记录降级证据)。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/unit/test_embedding.py -v` PASS;e2e 单独跑记录结果。
|
||||
@@ -278,17 +298,17 @@ class EmbeddingClient:
|
||||
|
||||
**行为**:
|
||||
- `run_soak.py`: argparse `--scenario P1..P6 --budget-calls N --budget-tokens M --workers K --concurrency C --run-id`(缺省 run-id=时间戳);启动守卫——`REDIS_URL` 必须以 `/3` 结尾否则拒跑、`PGW_TELEMETRY_PG_DSN`(若配)路径库名必须 `polygateway` 否则拒跑;开跑 FLUSHDB(仅 db3)+ `cache_namespace=run_id` + 回放请求 `cache_salt=run_id`;预算硬顶(签字值:全程 token ≤2 亿,单场景 calls 上限见设计 §8.1)任一命中优雅停(等 in-flight 收尾);`--workers>1` 用 `multiprocessing` 起真实子进程,预算按 worker 均分,各 worker 独立遥测 db 文件 `data/soak/telemetry_<run_id>_<w>.db`;全局并发/RPM 保护(签字值 100/600)配在 SOAK scope 源上。
|
||||
- `scoreboard.py`: 读全部 worker 遥测库合并,断言 findings §4 六条硬不变量(1 记账归零:结束后 source_stats inflight==0 且 gate 可再准入;2 行数==请求数±取消、call_id 唯一;3 按时间戳重算任意 60s 窗口单源请求 ≤RPM;4 RSS 首末差 <阈值(run_soak 周期采样自身 RSS 落 json);5 P3 structured 最终成功率 ≥基线(首跑建立基线文件);6 成本/延迟分位),产出报告 `tests/outputs/soak/<run_id>.md`(结构化 Markdown)。不变量断言实现为纯函数(输入行迭代器),unit 可测。
|
||||
- `scoreboard.py`: 断言 findings §4 六条硬不变量,产出报告 `tests/outputs/soak/<run_id>.md`(结构化 Markdown)。**输入口径分三类**:不变量 2/3/5/6 = 纯函数(输入合并后的遥测行迭代器,unit 可测);不变量 1(记账归零)= 跑后经活 Redis 连接查 `source_stats.inflight==0` 且 gate 可再准入(集成性检查,unit 用注入的 fake limiter/gate 测判定逻辑);不变量 4(RSS 平稳)= 纯函数(输入 run_soak 周期采样落盘的 RSS json)。
|
||||
**测试(先红)**: 六条不变量函数各造一组违例数据断言报错、一组合规数据通过;db3 守卫拒非 /3 连接串。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/unit/test_soak_corpus.py -v` PASS;`conda run -n PolyGateway python tools/soak/run_soak.py --scenario P3 --budget-calls 5 --budget-tokens 50000` 真实小跑通(冒烟,记入 outputs)。
|
||||
**验证**: `conda run -n PolyGateway pytest tests/unit/test_soak_corpus.py -v` PASS;`conda run -n PolyGateway python tools/soak/run_soak.py --scenario P3 --budget-calls 6 --budget-tokens 50000 --workers 2` 真实小跑通(冒烟,**必须带 --workers 2**——多进程验收口径的执行证据,人类认可 §13.5 的第二条腿;记入 outputs)。
|
||||
- [ ] 提交 `feat: add soak runner with budget guards and invariant scoreboard`
|
||||
|
||||
## T12 收尾与独立验证
|
||||
|
||||
**文件**: `.env.example`(M)、`research-wiki/migrations/video-tree-trm5.md` 与 `govdoc-saas.md`(M:embedding 迁移条目——VT 需同步壳+ndarray adapter,GovDoc 替换 OpenAICompatEmbedding 映射)、`research-wiki/ROADMAP.md`(M:M2 状态)
|
||||
|
||||
**行为**: `.env.example` 回填全部新键(PGW_TELEMETRY_PG_DSN、PGW_PRICING_PATH、EMBED__*、SOAK__* 示例,含"严禁指向在用库"注释);`make ci` 全绿(含 slow 集成;运行环境需 REDIS_URL 与 PG DSN);覆盖率 ≥80%;派**全新上下文 verifier subagent**(只读)对照设计逐条验收(verification-before-completion),Critical/Important 清零后方可声称完成;按 findings §2 预算跑一轮 P3 中等规模(≤500 calls)真实验收记入 outputs。
|
||||
**验证**: `conda run -n PolyGateway make ci` 输出 0 failed;verifier 报告落 findings(若有问题)。
|
||||
**行为**: `.env.example` 回填全部新键(PGW_TELEMETRY_PG_DSN、PGW_PRICING_PATH、EMBED__*、SOAK__* 示例,含"严禁指向在用库"注释;**REDIS_URL 示例改为 `/3` 并注明 db3 纪律**——现示例是 `/0`);ARCHITECTURE §7.3 记账侧勘误**已随设计批准提交(commit b165c2a),本任务无需重做,verifier 勿误报缺失**;`make ci` 全绿 + **显式跑全量 slow**(addopts 默认排除);覆盖率 ≥80%;派**全新上下文 verifier subagent**(只读)对照设计逐条验收(verification-before-completion),Critical/Important 清零后方可声称完成;按 findings §2 预算跑一轮 P3 中等规模(≤500 calls,`--workers 2`)真实验收记入 outputs。
|
||||
**验证**: `conda run -n PolyGateway make ci` 输出 0 failed;`conda run -n PolyGateway pytest -m slow -v` 全 PASS(≥12 分钟属预期);verifier 报告落 findings(若有问题)。
|
||||
- [ ] 提交 `docs: backfill env template and migration notes for M2`
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user