Files
Jyotisha/PROGRESS-report-skill-parity-20260901.md
T
Jesse_Chen addb94af9b docs(report): record the skill-parity round, BUG-467 and what stayed blocked
PROGRESS carries the engine contract snapshot (including the fields the
task brief assumed exist but the consultation API does not return), the
claim card before/after text, the per-section prompt growth table, the
knowledge pack inventory, and the actual quality-gate output.

BLOCKED records four things: no model credentials and no PostgreSQL here,
so the live writer comparison could not be produced; the per-section
prompt p50 landing at 2.83x raw (2.28x cost-weighted), which is over the
brief's 2x line and needs a decision rather than an evidence cut; and the
fact that /api/consultation_workflow serves the reduced prompt pack, so
the server narrative seeds the brief pointed at do not exist yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016P5RoqzmUQEbeC2qjAkeGr
2026-09-01 20:35:02 +00:00

346 lines
27 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.
# PROGRESS · 个人报告内容对齐 skill 解读深度(2026-09-01
任务书:`TASK-report-skill-parity-20260901.md`
分支:`codex/report-skill-parity-20260901`(基线 `8b7eda9f`,未 push
提交:`7714b5e5`(任务 0+1+2)、`deabcd8b`(任务 3+4 离线部分)、本文件所在提交(收尾)
开工前置:`docs/research/pre_work_error_ledger.md` 已读;`scripts/pre_work_check.py` 全绿(`python_runtime_ok/fragment_scan_ok/external_engine_adapters_ok/focused_tests_ok` 均为 true`remote_visibility_status=verified`);`frontend/AGENTS.md` 已读;`docs/BUG_HISTORY.md` 已检索 bundle / claim card / evidence 同类记录(最近相关为 BUG-457 报告分章生成)。
**偏差说明(经委托方授权)**:未建 worktree,直接在主检出上从 HEAD 建分支(node_modules / .venv 都在主检出)。任务 4 中依赖 staging 部署的部分跳过,只做不依赖部署的 telemetry 补记。
---
## 任务 0 · 引擎响应契约快照
### 做法
用虚构 smoke 出生数据(1990-05-15 10:30lat 31.23 / lon 121.47 / tz +8city "Smoke City",非真人)通过 `frontend/src/mastra/consultation-workflow.ts``runConsultationWorkflow` 真实调用本地 `scripts/jyotish_api_server.py``--port 5200`)的 `/api/consultation_workflow`career / marriage / wealth / education / migration / family / health / timing / general 各一次,9 次全部 `OK`。只记录 key 路径与类型,不记录值。
### 字段存在性清单(9 个主题响应一致)
| 任务书假定的路径 | 实际 | 类型 / 说明 |
|---|---|---|
| `chart.ai_prompt_pack.evidence_snapshot.functional_benefic_malefic` | **存在** | object,键 `status/ascendant/functional_benefics/functional_malefics/functional_neutrals/yogakarakas/owned_houses/effect_on_confidence/source`;本盘 `status="used"` |
| `chart.ai_prompt_pack.evidence_snapshot.strength.shadbala_ranking` | **存在** | array(7),元素 `{planet: string, rupas: number, level: string}`——**不是**任务书写的 `{planet, rank, total_rupas, min_required, strength_level}` |
| `chart.ai_prompt_pack.evidence_snapshot.strength.sav_scores` | **缺失** | 该路径不存在 |
| `chart.ai_prompt_pack.evidence_snapshot.timing.vimshottari` | **缺失** | `timing` 只有 `{current_mahadasha, remaining_years, start_date}`,没有 `vimshottari` 子对象,也没有 antardasha |
| `chart.ai_prompt_pack.evidence_snapshot.timing.convergence_top_domains` | **缺失** | 该路径不存在 |
| `chart.ai_prompt_pack.evidence_snapshot.career_narrative` | **缺失** | — |
| `chart.ai_prompt_pack.evidence_snapshot.relationship_narrative` | **缺失** | — |
| `chart.ai_prompt_pack.evidence_snapshot.finance_narrative` | **缺失** | — |
| `chart.modules.yoga.yogas` | **缺失** | 键名是 `yogas` 不是 `yoga` |
| `chart.modules.guided_topics` | **存在** | array(4),元素键 `id/title/reality_value/why_worth_exploring/evidence/confidence/vedastro/strict_adjudication_bundle/strict_audit_gate/monthly_adjudication_summary/official_day_signal_summary/suggested_questions/answer_mode/priority`id 为 `birth_time_rectification``relationship_partnership``career_direction``wealth_risk` |
**为什么缺**`/api/consultation_workflow` 返回的 `chart.ai_prompt_pack` 来自 `scripts/jyotish_api_server.py:6975``_build_chart_prompt_pack`**不是**任务书引用的 `scripts/jyotish_engine.py:1592``_build_ai_prompt_pack`。前者是精简版,没有叙事种子、没有 dasa convergence、没有 SAV。这不是本轮能改的(任务书把"引擎侧新增计算模块或改动既有模块输出"列为不在范围内,止损分支只允许新增字段,本轮未走该分支)。
### 同一响应里实际可用、任务书未列出的等价路径(已改用)
| 路径 | 类型 | 用途 |
|---|---|---|
| `chart.modules.ashtakavarga.sav.scores` | object,按**星座名**计分(12 键) | SAV:按 D1 上升整宫投影成 1–12 宫 |
| `chart.modules.ashtakavarga.sav.total` | number(本盘 337 | `savTotal` |
| `chart.modules.dasha_sub_periods.current.mahadasha` / `.antardasha` | `{lord, start, end}` | `currentDasha`(含 antardasha |
| `chart.yogas` | array,元素 `{name, planets, category\|cat, desc?}` | 已成盘 yoga |
| `chart.modules.yogas.yogas` | array,元素 `{name, rule_id, hit: bool, ...}` | **候选规则表**,本盘 `hit=true` 数为 0 |
**重要发现(防复发已写进 BUG-467)**`chart.modules.yogas.yogas` 是规则候选表,绝大多数 `hit=false`,把它当成"本盘的 yoga 名单"就是编造。提取层只收 `chart.yogas``hit === true` 的行。
### 缺失字段的处置
按验收条款"缺失即标记不可提取并跳过,不得伪造":
- `convergenceDomains`:本响应无来源 → 恒为空数组(schema 允许),代码保留 `evidence_snapshot.timing.convergence_top_domains``modules.dasa_convergence.top_convergent_domains` 两条读取路径,引擎哪天补上就自动生效。
- 三个 `*_narrative`:本响应无来源 → 叙事种子改由 `guided_topics` 文案 + 服务器确定性投影组成;`readEngineNarratives` 仍保留 `evidence_snapshot.*_narrative``modules.*_strict_evidence.user_narrative` 两条读取路径,且优先级高于 guided topic。
- `strength.sav_scores`:改读 `modules.ashtakavarga.sav.scores`,两条路径都在代码里。
- `timing.vimshottari`:改读 `modules.dasha_sub_periods.current`,两条路径都在代码里。
### 契约 fixture 测试
`frontend/tests/report-interpretive-facts.test.ts`(合成数据,文件头部把上表逐条写成注释)。10 条用例,锁住上述每条路径的读取行为、缺失路径的空值行为、以及 `hit=false` 不算成盘。
---
## 任务 1 · Bundle 承载解读性事实
### schema`frontend/src/lib/report-evidence-bundle-v2.ts`
`schemaVersion` 仍是 `report_evidence_bundle.v2`,两组新字段必填、允许空、`.strict()` 保持:
```
interpretiveFacts: {
yogas: { name(≤80, 净化 pattern), category(17 项闭合枚举), planets(celestial 枚举 ≤9), evidenceRef }[] // ≤40
functionalRoles: { planet(celestial), role(benefic|malefic|neutral|yogakaraka), ownedHouses(1-12, ≤12), evidenceRef }[] // ≤12
shadbalaRanking: { planet(celestial), rank(int 1-9), rupa(0-100|null) }[] // ≤9
savScores: { house(1-12), score(0-100) }[] // ≤12
savTotal: number(0-1000) | null
currentDasha: { mahadasha(celestial), antardasha(celestial|null), start, end } | null // 沿用既有 dashaPeriod 日期校验
convergenceDomains: string[] // ≤6 × ≤80,净化
}
themeNarrativeSeeds: { theme, headline(≤300), strengths(≤8×≤400), risks(≤8×≤400), boundaries(≤8×≤400), evidenceRefs(≤24) }[] // ≤12
```
`ownedHouses` 是相对任务书的**加法**(宫主分工是功能吉凶最有解读价值的一半,且是闭合的 1–12 整数数组),不是放宽。
### 确定性与 hash
`sortedBundleContent` 扩展:yogas 按 `name:category` 排序且 planets 去重排序;functionalRoles 按 planet 排序、ownedHouses 去重升序;shadbalaRanking 按 `rank, planet`savScores 按 houseconvergenceDomains 去重排序;seeds 按 theme 排序、evidenceRefs 去重排序。`computeReportEvidenceBundleHash` 因此覆盖新字段。测试 `bundle hash is stable under interpretive field ordering` 把五个数组全部 `reverse()` 后 hash 不变。
`shadbalaRanking.rank` **不采信引擎给的 rank**,而是按 `rupa` 降序、同分按行星名字典序重新推导,保证同一份输入永远得到同一份排名(本盘 Sun 与 Moon 都是 6.42 rupa,固定为 Moon(5) → Sun(6))。
### 净化与 fail closed
- 行星走既有 `safeCelestialName`;yoga 分类走 17 项闭合枚举,未知归 `other`yoga 名走 `^[\p{L}\p{N} ()/·,.'’++-]{1,80}$`
- `safeSeedText` 逐行清洗:控制字符 → 空格、折叠空白、超长截断,并对 21 个违禁子串(`vedastro` / `mevg` / `workflow` / `references/` / `scripts/` / `modules.` / `skill` / `prompt` / `oracle` / `engine` / `fallback` / `blocked` / `not_found` / `not_available` / `api` …)**整行丢弃**。这是相对任务书的收紧:引擎自产叙事里确实含外部供应商名与内部路由词,写作端红线不允许它们进 prompt。
- `validateReportEvidenceBundleV2` 新增 fail-closed`report_bundle_invalid_interpretive_ref``report_bundle_duplicate_functional_role``report_bundle_duplicate_shadbala_rank` / `_planet``report_bundle_duplicate_sav_house``report_bundle_current_dasha_invalid``report_bundle_duplicate_seed_theme``report_bundle_seed_theme_not_requested``report_bundle_invalid_seed_ref`。consensus ≥2 verified 防升级校验一字未改。
### 提取结果(真实 smoke 盘)
| 层 | 条数 | 样例(值不敏感,为虚构盘) |
|---|---:|---|
| yogas | 1 | `Amala Yoga / extended``chart.yogas` 两行同名合并为一行) |
| functionalRoles | 7 | Mars=yogakaraka(5,10)Jupiter/Moon=beneficMercury/Saturn/Venus=maleficSun=neutral |
| shadbalaRanking | 7 | Venus(1,8.35) → Saturn(2) → Mercury(3) → Jupiter(4) → Moon(5) → Sun(6) → Mars(7) |
| savScores | 12 | 上升 Cancer → 第 1 宫 24、第 10 宫 30、第 2 宫 27、第 11 宫 28 … |
| savTotal | 1 | 337 |
| currentDasha | 1 | Rahu / Sun2011-11-11 2029-11-11 |
| convergenceDomains | 0 | 源缺失,空 |
| themeNarrativeSeeds | 6 | 6 个非 blocked 主题各一条 |
---
## 任务 2 · Claim card 从回执升级为结论
### 改前 / 改后对照(同一份真实 smoke 盘,9 主题请求;career / marriage / timing 因缺 AmK / Transit / DK 仍是 blocked section,逻辑未动)
**改前(`8b7eda9f`)——所有主题只有主题名不同:**
```
[education] parameter_sensitive
conclusion : 服务器已闭合教育学习所需的最低证据组;本节只能在所列事实与确定性级别内解释。
supporting : D1=D1 上升为 Cancer,本次基础盘已建立
D24=D24 已执行并纳入本主题证据计划
Vimshottari=Vimshottari 已执行并纳入本主题证据计划
counterFacts: []
[wealth] parameter_sensitive
conclusion : 服务器已闭合财富结构所需的最低证据组;本节只能在所列事实与确定性级别内解释。
supporting : D1=… / D2=D2 已执行并纳入本主题证据计划 / D11=… / Yoga=… / Ashtakavarga=… / Vimshottari=…
```
**改后:**
```
[education] parameter_sensitive ← 级别未变
conclusion : 本命上升为 Cancer;按宫主判定的功能吉星为 Jupiter、Moon,功能凶星为 Mercury、Saturn、Venus。
本主题相关宫位的八分力总分:第 4 宫 25 分,第 5 宫 35 分(全盘合计 337 分)。
当前处于 Rahu 主运、副运 Sun,主运区间 2011-11-11 至 2029-11-11。
supporting : D1=本命上升 Cancer;功能吉星 Jupiter、Moon,功能凶星 Mercury、Saturn、Venus
D24=D24 已执行并纳入本主题证据计划
Vimshottari=当前 Rahu 主运、副运 Sun2011-11-11 至 2029-11-11
Ashtakavarga=八分力:第 4 宫 25 分,第 5 宫 35 分,全盘合计 337 分
Functional Benefic/Malefic=功能吉凶已判定,Mars 为 yogakaraka
Yoga=已成立组合:Amala Yoga
[wealth] parameter_sensitive ← 级别未变
conclusion : 本命上升为 Cancer;按宫主判定的功能吉星为 …。
本主题相关宫位的八分力总分:第 2 宫 27 分,第 11 宫 28 分(全盘合计 337 分)。
当前处于 Rahu 主运、副运 Sun,主运区间 2011-11-11 至 2029-11-11。
[general] single_system_inference ← 级别未变
conclusion : …本主题相关宫位的八分力总分:第 1 宫 24 分,第 10 宫 30 分(全盘合计 337 分)。…
```
六个可写主题的 conclusion 现在**逐主题不同**(主题相关宫位的 SAV 行不同),且不含任何模板回执句。
### 拼装规则
- `conclusion = seed.headline + 最多 2 条 seed.strengths`,按句号补全后拼接,截断 1200。
- seed 的 headline 优先取引擎叙事 headline(结论式);无叙事时取第一条服务器确定性投影行;再无则取 guided topic 标题。主题相关行(SAV 宫位)排在前面,保证每章 conclusion 不同。
- `supportingFacts`:每条 matched receipt 一条,值改为该技法的真实解读语句;此外把通用解读层(Functional Benefic/Malefic、Yoga、Ashtakavarga、Vimshottari)作为额外事实条目挂在**它们自己的 receipt** 上,不冒名给别的技法。
- `counterFacts` ← seed.risks(本盘引擎叙事缺失,为空;合成夹具用例 `engine risk lines become counter facts on the matching claim card` 覆盖了有 risks 的路径)。
- `boundaries` 留在种子里由 writer 引用(任务书允许的第二种处置),`verificationQuestions` 未动。
- **`assertionLevel` 推导一字未改**;只有"完全没有种子"时把 `multi_system_consensus` 压到 `single_system_inference`(用例 `a theme without any narrative seed keeps the receipt wording and loses consensus` 覆盖)。
### 端到端抽查(叙事内容可回溯到 bundle,3 处)
无模型凭据、无数据库,本地无法真跑 writer(见 BLOCKED.md)。改为对服务器确定性产出的 conclusion 做逐句回溯,这是 writer 唯一被允许复述的结论层:
| # | conclusion 中的表述 | 回溯到 bundle 的哪一行 |
|---|---|---|
| 1 | "本命上升为 Cancer" | `charts[D1].ascendant.sign = "Cancer"`;同时 `supportingFacts` 该条 `evidenceRef = ev-tech-d1``executionLedger[ev-tech-d1].status = verified` |
| 2 | "Mars 同时主管第 5、10 宫,在本盘属 yogakaraka" | `interpretiveFacts.functionalRoles[{planet:"Mars", role:"yogakaraka", ownedHouses:[5,10], evidenceRef:"ev-tech-functional_benefic_malefic"}]`;该 ref 在 `evidenceRefs` 中 status=partial,事实条目 status 同为 partial(未升级) |
| 3 | "当前处于 Rahu 主运、副运 Sun,主运区间 2011-11-11 至 2029-11-11" | `interpretiveFacts.currentDasha = {mahadasha:"Rahu", antardasha:"Sun", start:"2011-11-11", end:"2029-11-11"}`,绑 `ev-tech-vimshottari` |
| 4 | "本盘已成立的组合:Amala Yoga" | `interpretiveFacts.yogas[0] = {name:"Amala Yoga", category:"extended", evidenceRef:"ev-tech-yoga"}``modules.yogas.yogas` 里 6 条 `hit=false` 的候选规则**没有**出现在这里 |
| 5 | "第 2 宫 27 分,第 11 宫 28 分(全盘合计 337 分)" | `interpretiveFacts.savScores[{house:2,score:27},{house:11,score:28}]` + `savTotal=337`,绑 `ev-tech-ashtakavarga` |
---
## 每章 prompt 增量(红线 6:必须摆数据)
同一份真实 smoke 盘、`depth=standard`、6 个可写主题。测量对象是 `sectionPrompt` 的 JSON 载荷 `{bundle, plan, completedSectionTitles}``filterReportEvidenceBundleForSection` 之后)。改前数据是把三个改动文件 checkout 回 `8b7eda9f` 后用同一份 workflow 快照重跑得到的,不是估算。
**token 数是离线估算**(无 tokenizerCJK 字符按 1 token、其余按 1/4 token)。真实 `inputTokens` 必须来自部署后的一次真实生成。
| 章节 | 改前 chars | 改后 chars | 改前 est.tok | 改后 est.tok | 倍数 |
|---|---:|---:|---:|---:|---:|
| theme-general | 3459 | 6993 | 928 | 1999 | 2.15 |
| theme-family | 3774 | 7298 | 1044 | 2112 | 2.02 |
| theme-health_pressure | 3845 | 7354 | 1065 | 2121 | 1.99 |
| theme-education | 4169 | 7361 | 1162 | 2127 | 1.83 |
| theme-migration_home | 4511 | 7726 | 1270 | 2240 | 1.76 |
| theme-wealth | 5129 | 7711 | 1465 | 2262 | 1.54 |
| **p50** | **4004** | **7357** | **1113.5** | **2124** | **1.91** |
改后载荷构成(以 general 章为例,chars):`interpretiveFacts` 1365、`themeNarrativeSeeds` 500、`claimCards` 1262(改前约 500)、`executionLedger` 576、`evidenceRefs` 372、`charts` 1731(未变)、`calculationProfile` 232(未变)。
再加上任务 3 的静态系统内容(改前只有 24 字符的缓存边界句):
| 项 | 改前 est.tok | 改后 est.tok | 是否吃 prompt cache |
|---|---:|---:|---|
| 缓存前缀内的静态内容(通用包 + 边界句) | 22 | 877 | **是**`cachedSystemMessage`,前缀逐字节稳定,有测试锁) |
| 本章主题包(缓存边界之后) | 0 | 203313p50 214 | 否 |
| bundle 载荷 | 1113.5 | 2124 | 否 |
| **每章合计(原始 token** | **1135.5** | **3215** | — |
- **原始 token p50 倍数 = 2.83×,超过改前 2 倍。**
- 计费加权后(缓存写 1.25×、缓存读 0.1×,6 章摊到每章约 256 token):改后 ≈ 2594 token**约 2.28×**,仍超 2 倍。
**按红线 6 与任务 3 止损条款处置**`cachedSystemMessage` 已确认生效且缓存前缀逐字节稳定(`writer system content caches the general pack and appends only the chapter pack` 用例锁定),不属于"cache 未命中"的止损分支;止损条款明确禁止"砍证据来凑成本",因此**未削减任何证据**,数据原样摆出,是否接受这个成本请委托方裁决。可选的降本项(未做,逐条列出以便决策):
1. 主题包不下发,只留通用包:每章省约 214 token(→ 约 2.64×)。代价是丢掉主题级措辞纪律。
2. `themeNarrativeSeeds` 与 conclusion 前两句重复,去重可省约 150 token(→ 约 2.70×)。代价是 writer 看不到种子原始层与 claim 的差别。
3. `shadbalaRanking` 每章只留前 3 + 最弱 1:省约 90 token。代价是丢掉完整发力顺序。
4. `charts`1731 chars ≈ 450 token)是改前就有的开销,与本轮无关;真要压成本,这里比砍新证据划算。
---
## 任务 3 · 写作端静态解读知识包
### 目录与清单
`frontend/src/lib/report-interpretation-packs/``general.ts` / `themes.ts` / `index.ts`),纯静态 TS 常量。蒸馏来源:`references/modern-language-guide.md``references/common-misconceptions.md``references/house-domain-planet-mapping.md` 及各主题判读要点。
| 包 | 字符数 | est.tok | 内容 |
|---|---:|---:|---|
| general_method(通用) | 961 | 855 | 表达顺序、术语现代化映射、强弱与分值怎么说、多层验证、必须避免的推理错误、语气与禁语 |
| career | 366 | 313 | 主指标、10/6 宫怎么说、yogakaraka 怎么落地、禁止承诺升职/薪资/时点 |
| marriage | 330 | 296 | 7 宫=一切长期对等关系、D9 与本命的分工、土星不写成"晚婚"、禁止预测结婚年份与忠诚判断 |
| wealth | 298 | 261 | 赚到 vs 留住必须分开、低分不写成"破财"、禁止推荐任何标的/收益率/借贷建议 |
| education | 248 | 214 | 学得快 vs 学得深、困难写成方法不匹配、禁止预测通过与录取 |
| migration_home | 244 | 208 | 12 宫不写成"损失"、安定与离开并存、禁止指定国家城市方位与日期 |
| family | 231 | 203 | 关系模式而非人品、5 宫不是生育能力、禁止预测生育与亲属健康 |
| health_pressure | 243 | 214 | 只谈负荷与恢复、禁止任何诊断/点名疾病/用药建议 |
| timing | 281 | 256 | 时间层只能激活本命已有结构、主运/副运分工、未获准时不写年月日 |
| general(综合基础章) | 273 | 243 | 建框架不抢主题章结论、功能吉凶是角色分工不是性格好坏 |
单包上限 3000 字符(`PACK_CHARACTER_LIMIT`),最大的通用包用了 32%。
### 注入方式
`buildWriterSystemContents(theme)``frontend/src/mastra/personal-report.ts`)返回:
- `[0]` = 通用包 + `【上下文缓存边界】…`,作为 `cachedSystemMessage` 的内容 → **在缓存断点之内**,且逐字节稳定,第 2 章起是 cache read
- `[1]` = 本章主题包,放在缓存边界之后(每章不同,不能进前缀)。
- 摘要调用 `themePack=null`,只带通用包。
- 非 Anthropic 供应商 `cachedSystemMessage` 返回 null,此时降级为普通 system message(内容不变,只是不缓存)。
### 合同同步
- writer 指令新增:interpretiveFacts / themeNarrativeSeeds 是"可引用的事实层,但不授权 claimCard 之外的结论";知识包"只管怎么解释和怎么措辞,不是事实来源,不能提高确定性"。`Use its claimCards exclusively for narrative conclusions` 原句保留。
- `skills/jyotish-personal-report/SKILL.md` 升到 **1.1.0**`skills/jyotish-personal-report/versions/1.1.0/` 为不可变副本,registry 中 1.0.0 转 `deprecated`、1.1.0 为 `active`sha256 `6be2279b…10e9`)。
### 端到端改前改后同盘同主题章节全文对照
**未做,无法在本地做**:执行环境没有任何模型凭据(`ANTHROPIC_*` / `OPENAI_*` 等全部未设置,仓内只有 `.env.*.example`),也没有 PostgresDocker 不可用),`generateSectionedPersonalReport` 需要 `PersonalReportSectionService`。见 `BLOCKED.md`。可离线给出的替代物是上面的"每章 prompt 增量"表与 claim card 全文对照。
---
## 任务 4 · 观测(只做不依赖部署的部分)
`PersonalReportAgentTelemetry` 新增两个数值字段,沿用既有隐私边界(只记指标名与数值):
- `interpretiveFactCount`:本次调用收到的 bundle 里解读事实的条数(yogas + functionalRoles + shadbalaRanking + savScores + convergenceDomains + currentDasha + savTotal)。本盘各章为 **21**1 + 7 + 7 + 2~3 + 0 + 1 + 1,随该章 SAV 宫位裁剪略有差异)。
- `knowledgePackCharacters`:本次调用随 prompt 下发的静态知识包字符数 = 缓存前缀内容 + 本章主题包。章节调用为 **12181353**987 + 231~366),摘要调用为 **987**
`countInterpretiveFacts` 对缺字段/畸形输入返回 0 而不抛错——telemetry 不得让生成失败。测试 `telemetry carries interpretive and knowledge-pack sizes as numbers only` 断言两个字段是数字,且序列化后不含任何事实文本。
**部署后测量(章节数、每章 in/out tokens、总墙钟、与 `PROGRESS-report-sectioned-20260830.md` 对照)按授权跳过,由委托方在 staging 部署后补。**
---
## 修改既有测试断言的逐条说明(红线 9)
| 文件 | 断言 | 原值 | 原因 |
|---|---|---|---|
| `frontend/tests/personal-report-generation.test.ts` | `bundleV2Fixture()` | 无 `interpretiveFacts` / `themeNarrativeSeeds` | 两个字段按任务书要求为必填;夹具没有引擎快照,声明为 `emptyReportInterpretiveFacts()` + `[]`。断言语义未变。 |
| `frontend/tests/personal-report-generation-v2.test.ts` | 同上 | 同上 | 同上 |
| `frontend/tests/personal-report-plan.test.ts` | 同上 | 同上 | 同上 |
| `frontend/tests/personal-report-generation.test.ts:814` | `snapshot.version` | `"1.0.0"` | Skill 合同变更,版本 +1;已在断言上方注明原值与原因 |
| `frontend/tests/skill-registry.test.ts:92` | jyotish-personal-report 的 version / sha256 | `1.0.0` / `23149b9e…f982` | 同上;已在断言上方注明原值与原因 |
| `tests/test_jyotish_personal_report_skill_package.py` | `VERSION_ROOT` 与 registry 期望行 | `versions/1.0.0` | 同上;改为 `ACTIVE_VERSION` 常量并注明原值与原因,同时**新增**四条断言锁住 1.1.0 的新合同措辞(只加不减) |
没有任何断言被放松:`report-evidence-bundle-v2``.strict()`、consensus ≥2 verified 防升级、`assertionLevel` 推导、章节串行、writer 输出 schema 全部原样。
---
## 质量门实际结果
```
$ ./node_modules/.bin/tsc --noEmit # frontend
(无输出,通过)
$ ./node_modules/.bin/eslint src tests # frontend
✖ 28 problems (0 errors, 28 warnings)
28 条全部是既有的 no-unused-vars warning,与本轮无关)
$ npm run build # frontend
✓ Compiled successfully in 5.6s
✓ Generating static pages using 7 workers (62/62) in 447ms
Turbopack build encountered 5 warnings:
Warning: Dynamic filesystem access causes tracing of the whole project ×5
(该 5 条为既有告警,已记录在 BLOCKED.md 2026-08-17 条目)
$ ./node_modules/.bin/tsx --test tests/*.test.ts # 基线 8b7eda9f
# tests 2427 # pass 2393 # fail 24 # skipped 10 # todo 0
$ ./node_modules/.bin/tsx --test tests/*.test.ts # 本分支
# tests 2444 # pass 2410 # fail 24 # skipped 10 # todo 0
失败集逐条 diff:完全一致(SAME_FAILURE_SET),24 条全部是本机缺 Docker / PostgreSQL 的
数据库与部署夹具,以及 staging workflow YAML 校验,与 BLOCKED.md 既有记录一致:
admin code functions … / admin customer reset … / service and restricted admin database identities …
Owner recovery … / staging backups … / billing order adjustments … / billing, subscriptions, …
saving a published product … / database env validator … / migration runner … / foundation grants …
local PostgreSQL … / personal report job migration … / personal report sections enforce owner-read RLS …
redeem security … / self-hosted identity migration … / database roles have no cluster privileges
server compose defaults … / staging env validator … / Better Auth supports shared user OTP/password …
database drops secret refs … / changed staging workflows are syntactically valid YAML
live staging sync preserves env … / live staging sync repairs nested deploy-tree drift …
新增 17 个通过用例,0 个新增失败。
$ .venv/bin/python -m pytest tests/test_jyotish_personal_report_skill_package.py -q
.. [100%]
$ .venv/bin/python scripts/pre_work_check.py
checks 全 trueremote_visibility_status = verified
```
`npm run test:db` 未跑:Docker 不可用,且本轮红线禁止数据库结构改动与新增迁移,本轮确实没有改任何库结构或迁移。
---
## 交付物清单核对
| # | 交付物 | 状态 |
|---|---|---|
| 1 | 任务 0 契约快照(字段存在性清单 + fixture 测试) | 完成 |
| 2 | bundle 新字段 schema + 提取 + 净化 + hash 覆盖 + fail-closed 测试 | 完成 |
| 3 | `filterReportEvidenceBundleForSection` 主题裁剪 + 每章 prompt 增量数据 | 完成(增量数据超 2×,已摆出待裁决) |
| 4 | 实质化 claim cards + 回退与级别压制 + consensus 回归测试 | 完成 |
| 5 | 端到端抽查记录:叙事可回溯到 bundle(≥3 处) | 部分完成:对服务器确定性 conclusion 做了 5 处逐行回溯;真实 writer 输出因无模型凭据未跑(BLOCKED.md |
| 6 | 知识包目录 + 违禁词扫描测试 + SKILL.md 更新 | 完成 |
| 7 | 改前改后同盘同主题章节全文对照 + tokens/墙钟对照 | 未做:无模型凭据与数据库(BLOCKED.md);已给出 prompt 载荷与 claim card 全文对照作为离线替代 |
| 8 | `docs/BUG_HISTORY.md` 条目 | 完成:BUG-467(远端 `origin/staging` 最大号为 BUG-466,已确认) |
| 9 | `BLOCKED.md` | 完成 |
| 10 | `PROGRESS-report-skill-parity-20260901.md` | 本文件 |
| 11 | tsc / eslint / tsx --test / next build 实际输出 | 完成(见上) |