diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4e24f28 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,21 @@ +# AGENTS.md + +> 通用 AI coding agent(Codex 等)的仓库级薄入口。**全部硬规则以 [`CLAUDE.md`](CLAUDE.md) 为准**,本文只做导航。 + +## 开工顺序 + +1. 读 [`CLAUDE.md`](CLAUDE.md):项目定位、修改原则、技术约定、安全与验证要求(唯一权威规则源)。 +2. 读 [`docs/current-state.md`](docs/current-state.md):当前快照、已验证事实、blocker。 +3. 读 [`tasks.md`](tasks.md):领取唯一任务(一次一个,依赖齐才领)。 +4. `git log --oneline -10`:看最近发生了什么。 +5. 需要背景再读 [`docs/README.md`](docs/README.md) 导航到设计文档 01~06。 + +## 完成任务后 + +- 更新 `tasks.md` 状态;追加 [`progress.md`](progress.md)(含真实验证命令与结果);覆盖更新 `docs/current-state.md`。 +- 验证入口统一走 `./init.sh`(阶段 0 前会提示先建骨架)。 + +## 红线(详见 CLAUDE.md) + +- 严禁提交 `ask` 密钥、真实账号/机构码/身份证、`config.yaml`、`docs/账号.txt`、`scripts/` 联调脚本。 +- 签名、serviceId、checkId、码表、幂等相关改动必须保守,以 `docs/01`、`docs/04`(含 §8 实测契约)为事实来源,不照搬 docx。 diff --git a/CLAUDE.md b/CLAUDE.md index 82b8bc7..d8f053c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,14 +8,25 @@ ## 会话启动 -1. 读取 `docs/README.md` — 了解文档集结构与一句话结论 -2. 执行 `git log --oneline -10` — 了解上次做到哪里 -3. 确认当前所处阶段(见 `docs/05-实施路线图.md` 的阶段 0~6) +1. 读 `docs/current-state.md` — 当前快照、已验证事实、blocker +2. 读 `tasks.md` — 任务看板;一次只领一个 `TODO` 且依赖均 `DONE` 的任务 +3. 执行 `git log --oneline -10` — 了解上次做到哪里 +4. 需要背景再读 `docs/README.md`(文档导航)与 `docs/05-实施路线图.md`(阶段全景) -> 需要架构细节读 `docs/03-目标架构设计.md`;需要接口字段/码表读 `docs/01-OSI接口规范分析.md` 与 `docs/04-字段与接口映射.md`。 +> 需要架构细节读 `docs/03-目标架构设计.md`;需要接口字段/码表读 `docs/01-OSI接口规范分析.md` 与 `docs/04-字段与接口映射.md`(**§8 为联调实测契约,优先级高于 docx 整理**)。 > 用户说"继续开发""继续上次的"时,完成以上步骤后直接接续,不重新介绍项目背景。 +### 三件套职责(完成任务后同步) + +| 工件 | 性质 | 维护方式 | +|------|------|---------| +| `tasks.md` | 任务看板 | 领取改 `DOING`,验收通过改 `DONE`;标 DONE 需有 `progress.md` 里的验证证据 | +| `progress.md` | 执行流水 | **只追加**:变更/验证命令与结果/阻塞/决策/下一步 | +| `docs/current-state.md` | 当前快照 | **覆盖更新**:目录现实、可运行命令、blocker、下一步 | + +统一验证入口:`./init.sh`(阶段 0 骨架未建立前会主动失败并提示 T-001,属预期)。 + --- ## 项目定位 @@ -80,7 +91,7 @@ OSI 是**无状态服务端接口**,鉴权 = 请求头 MD5 签名(`password= ### osi(薄客户端) - 签名只在 `osi` 层完成,业务层无感;用 `crypto/md5` 即可,**不引入 SM2/任何加密库**。 - `ts` 取 13 位毫秒;`password` 取 32 位小写;`ask` **仅参与签名**,不进请求头、不进报文、不进日志。 -- 返回判定集中在 `codes.go`:`code=="1"` 成功(注意是**字符串**);`405` 超时(可重试);其它失败。 +- 返回判定集中在 `codes.go`:成功码为**字符串**,联调实测 `"01"`(docx 误写 `"1"`),判定按去前导零 == `"1"`;`405` 超时(可重试);其它失败。 - 传输层移植自 `chis_upload`(保留 SOCKS5/超时,**去掉 cookiejar 与网页拟态头**)。 ### mapping(核心) @@ -127,6 +138,7 @@ OSI 是**无状态服务端接口**,鉴权 = 请求头 MD5 签名(`password= | serviceId / 接口路径 / 字段映射 / 码表校准 | `docs/01-OSI接口规范分析.md`、`docs/04-字段与接口映射.md` | | 联调确认了开放问题(完整度 / checkId 规则 / 缺漏接口等) | `docs/03` 第 8 节、`docs/04` 第 7 节待补清单 | | 阶段推进或验收通过 | `docs/05-实施路线图.md` 勾选项与阶段状态 | +| 任务领取/完成/受阻 | `tasks.md` 状态 + `progress.md` 追加记录(含验证证据)+ `docs/current-state.md` 覆盖快照 | | 做了重要技术决策 | `docs/decisions/00N-简短描述.md`(背景 / 决策 / 原因 / 影响) | --- diff --git a/docs/README.md b/docs/README.md index 821d209..bf14e40 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,6 +23,19 @@ | [04-字段与接口映射.md](04-字段与接口映射.md) | OSI 接口↔内部能力映射、PHIS→OSI 字段/字典映射策略、checkId 幂等键 | | [05-实施路线图.md](05-实施路线图.md) | 分阶段落地计划、配置项、可观测性、测试与联调清单 | | [06-厂家联调清单.md](06-厂家联调清单.md) | 向厂家索要的凭据/环境/契约/样本清单,带回填状态,可直接发对接人 | +| [current-state.md](current-state.md) | **当前实现状态快照**(可覆盖):仓库现实、已验证事实、可运行命令、blocker | + +## 执行工件(根目录) + +| 文件 | 作用 | +| --- | --- | +| [`../CLAUDE.md`](../CLAUDE.md) | 仓库级硬规则(Claude Code 入口,唯一权威规则源) | +| [`../AGENTS.md`](../AGENTS.md) | 通用 agent 薄入口,导航到 CLAUDE.md 与三件套 | +| [`../tasks.md`](../tasks.md) | 任务看板:小步任务 + 依赖 + 验收 + 状态,一次只领一个 | +| [`../progress.md`](../progress.md) | 执行流水(只追加):每轮变更/验证/阻塞/决策 | +| [`../init.sh`](../init.sh) | 统一启动与验证入口(Go 骨架建立后:download → test → run) | + +维护原则:需求/契约变化先改文档再改代码;任务状态变化同步 `tasks.md` + `progress.md` + `current-state.md`;接口契约以 `01`/`04`(含 §8 实测)为准,代码不得另起一套。 ## 一句话结论 diff --git a/docs/current-state.md b/docs/current-state.md new file mode 100644 index 0000000..5622fa7 --- /dev/null +++ b/docs/current-state.md @@ -0,0 +1,55 @@ +# 当前实现状态 + +> 可覆盖的当前快照:记录仓库现实、可运行命令、blocker 和下一步,防止只看计划而忽略现状。 +> 历史流水追加到 [`../progress.md`](../progress.md);任务状态以 [`../tasks.md`](../tasks.md) 为准。 + +## 当前快照 + +- 日期:2026-07-06 +- 阶段:**pre-code**(设计完成、Go 骨架未建立;路线图阶段 0 未开始) +- 技术栈:目标 Go 1.24 单二进制(未落地);当前仅有 Python 联调脚本(requests,本地不入库) +- 生产代码:**无**。`go.mod` 不存在,`osi/ contract/ mapping/` 等目录均待建 +- 联调现实:**JKDA00002 个人档案查询已用 Python 脚本打通真实沙箱**(`code="01"`),实测契约沉淀在 `docs/04 §8` +- 测试:`tests/test_query_health_record.py` **已失效**(测的是被重写前的脚本 API,import 报错) +- 标准启动路径:`./init.sh`(阶段 0 未完成前会提示先做 T-001,属预期行为) +- 标准验证路径:`go test ./...`(骨架建立后生效) +- 当前 blocker:无硬 blocker。软阻塞:厂家侧 B1/B2/B4/B5 契约缺口(见 `docs/06`),只影响阶段 4,不阻塞阶段 0~3 + +## 当前目录要点 + +| 路径 | 状态 | 说明 | +| --- | --- | --- | +| `docs/` | 已有 | 设计文档集 01~06 + 本快照;`账号.txt` 本地留存不入库 | +| `tasks.md` `progress.md` | 已有 | 任务看板 / 执行流水(根目录) | +| `scripts/` | 已有·不入库 | Python 联调脚本(硬编码真实凭据与身份证,已 gitignore) | +| `tests/` | 已有·失效 | 旧脚本测试,待 T-000 处理 | +| `config.yaml` | 已有·不入库 | 真实凭据;`config.yaml.example` 待 T-001 建立 | +| `main.go` `osi/` `contract/` `mapping/` 等 | 待建 | 路线图阶段 0~2 | + +## 已验证事实(写代码时直接依赖) + +- 签名:`password = md5("ts=<13位毫秒ts>&ask=")` 32 位小写,与平台一致(Python 已打通)。 +- 信封:查询也走 `{"serviceId", "uploadinfo": {"baseInfo", "manageInfo"}}`,见 `docs/04 §8`。 +- 成功码:字符串 `"01"`(判定按去前导零 == `"1"`),见 `docs/01 §1`。 +- 机构码分层:请求头 `orgCode`=18 位统信码 ≠ `manaUnitId`=9 位机构码 ≠ 12 位区划码,见 `docs/01 §3`。 +- `deviceSN` 查询可空。 + +## 当前可运行内容 + +```bash +# 本地联调查询(唯一可运行路径;脚本硬编码凭据,勿提交) +python3 scripts/query_health_record.py + +# Go 侧(阶段 0 后) +./init.sh +go test ./... +``` + +## 下一步 + +1. T-000:处理失效测试(`tasks.md` Phase B)。 +2. T-001:go module + 双子命令骨架,进入路线图阶段 0。 + +## 维护规则 + +发生以下变化时覆盖更新本文:入口/目录变动、任务状态变化、新增可运行命令、发现文档与代码现实不一致。本文只留当前快照,不留历史。 diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..6c471c3 --- /dev/null +++ b/init.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# 标准启动与验证入口:一条命令完成 依赖同步 -> 基础验证 -> 打印启动命令。 +# 每轮会话用同一条路径启动,不靠记忆拼命令。 +# 目标技术栈为 Go 1.24 单二进制(docs/03);阶段 0(T-001)建立骨架前本脚本会主动失败,属预期。 + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$ROOT_DIR" + +if [ ! -f go.mod ]; then + echo "ERROR: 阶段 0 骨架未建立(缺 go.mod)。" + echo " 先领取 tasks.md 的 T-001(初始化 go module 与双子命令骨架)," + echo " 当前唯一可运行验证是本地 Python 联调脚本,见 docs/current-state.md。" + exit 2 +fi + +INSTALL_CMD=(go mod download) +VERIFY_CMD=(go test ./...) +START_CMD=(go run . -mode server) + +echo "==> 当前目录: $PWD" + +echo "==> 同步依赖" +"${INSTALL_CMD[@]}" + +echo "==> 运行基础验证" +"${VERIFY_CMD[@]}" + +echo "==> 启动命令" +printf ' %q' "${START_CMD[@]}" +printf '\n' + +if [ "${RUN_START_COMMAND:-0}" = "1" ]; then + echo "==> 启动应用" + exec "${START_CMD[@]}" +fi + +echo "如需直接启动应用:RUN_START_COMMAND=1 ./init.sh" +echo "如果基础验证失败,先修基线,不要在坏的起点上叠新功能。" diff --git a/progress.md b/progress.md new file mode 100644 index 0000000..84e3a2a --- /dev/null +++ b/progress.md @@ -0,0 +1,42 @@ +# 执行进度记录 + +> 只追加的历史流水:每轮做了什么、跑了什么验证、遇到什么阻塞、做了什么决策。 +> 当前目录/命令/下一步等可覆盖快照写 [`docs/current-state.md`](docs/current-state.md),不在本文重复。 +> 任务状态以 [`tasks.md`](tasks.md) 为准。 + +## 记录格式 + +```markdown +## YYYY-MM-DD T-编号 任务名(或事件名) + +- 状态:DONE / BLOCKED / PARTIAL +- 变更:改了哪些文件或模块 +- 验证:运行的真实命令和结果 +- 阻塞:如有,写明原因和需要谁决策 +- 决策:如有,记录本轮确定的关键取舍 +- 下一步:建议下一个任务 ID 或待确认事项 +``` + +## 执行记录 + +## 2026-05~06 设计文档集初始化(pre-code) + +- 状态:DONE +- 变更:`docs/01~06` 设计文档集、`CLAUDE.md`、`.gitignore`(源材料不入库)。详见 `git log 3498542..1fd2569`。 +- 决策:扁平目录布局对齐 chis_upload;OSI 为无状态 MD5 签名接口,不引入旧项目逆向复杂度;幂等键用 checkId。 + +## 2026-07-06 JKDA00002 联调打通 + 文档校准 + +- 状态:DONE +- 变更:`scripts/query_health_record.py`(本地,不入库)打通真实查询;据实测样本校准 `docs/01`(成功码/信封/机构码分层/坑点坐实)、`docs/04`(新增 §8 实测契约)、`docs/06`(A1~A9/B3/B6/C3/D2/D3 回填)。 +- 验证:沙箱真实请求返回 `code="01" message="操作成功"`,`data` 为档案聚合数组;脚本离线自检(编译 + 信封 + 判码逻辑)通过。 +- 决策:**成功码为 `"01"` 非 docx 所示 `"1"`**,判定按去前导零;**查询也走 `uploadinfo` 信封**;请求头 `orgCode` 用 18 位统一社会信用代码(9 位码是 `manaUnitId`,两者不可混用)。 +- 阻塞:`tests/test_query_health_record.py` 测的是旧脚本 API,已失效(import 报错)→ 登记为 T-000。 +- 下一步:T-000,然后 T-001 起步阶段 0。 + +## 2026-07-06 接入 harness coding 文档工件 + +- 状态:DONE +- 变更:新建 `tasks.md`(看板)、`progress.md`(本文)、`docs/current-state.md`(快照)、`init.sh`(统一验证入口)、`AGENTS.md`(通用 agent 薄入口);更新 `CLAUDE.md` 会话启动流程与文档同步表、`docs/README.md` 导航、`docs/05` 成功码勘误。 +- 决策:任务看板放根目录 `tasks.md`;现有 `docs/01~06` 设计文档不重命名不重排;模板可选增强集(rubric/quality/method-map)暂不引入。 +- 下一步:T-000。 diff --git a/tasks.md b/tasks.md new file mode 100644 index 0000000..6650beb --- /dev/null +++ b/tasks.md @@ -0,0 +1,64 @@ +# 任务看板(Tasks) + +> 把 `docs/05-实施路线图.md` 的阶段拆成小步、可独立交付、可验收的任务。 +> 每轮只领取**一个**状态为 `TODO` 且依赖均 `DONE` 的任务(取最靠前的)。 + +## 使用规则 + +1. 开工前读 `docs/current-state.md`(当前快照)与 `CLAUDE.md`(硬规则)。 +2. 领取任务时把状态改为 `DOING`(同一时间最多 1 个)。 +3. 标 `DONE` 前必须有**可运行证据**:验证命令和结果追加到 [`progress.md`](progress.md);只有"代码已写"不算完成。 +4. 完成后:更新本文状态 → 追加 `progress.md` → 覆盖更新 `docs/current-state.md`。 +5. 代码现实与看板冲突时,先说明冲突,不擅自跳步。 + +状态图例:`TODO` 待开始 · `DOING` 进行中 · `DONE` 完成并验收 · `BLOCKED` 受阻(注明原因) + +--- + +## Phase B · 基线(接入 harness,先于一切新功能) + +| ID | 任务 | 依赖 | 验收要点 | 状态 | +| --- | --- | --- | --- | --- | +| T-000 | 处理失效测试 `tests/test_query_health_record.py` | - | 它 import 的旧脚本 API 已删除(脚本已重写为硬编码版):要么删除,要么改写为校验新信封结构的最小测试;`pytest tests/` 通过或目录清空 | TODO | + +## Phase 0 · 脚手架与契约骨架(路线图阶段 0) + +| ID | 任务 | 依赖 | 验收要点 | 状态 | +| --- | --- | --- | --- | --- | +| T-001 | 初始化 go module + `main.go` 双子命令骨架 + `config/`(viper) | - | `go build ./...` 通过;`-mode server\|deliver` 可解析;`config.yaml.example` 占位值就绪 | TODO | +| T-002 | `osi/sign.go` MD5 头签名 + 单测 | T-001 | 单测校验 `password=md5("ts=&ask=")` 32 位小写;与 Python 脚本(scripts/,本地)产出比对一致 | TODO | +| T-003 | `osi/transport.go`:从 chis_upload 移植传输层 | T-001 | 保留 SOCKS5/超时;去掉 cookiejar 与网页拟态头;单测或最小连通验证 | TODO | +| T-004 | `osi/client.go` `Call` + `osi/codes.go` + `contract/envelope.go` | T-002, T-003 | 信封为 `serviceId`+`uploadinfo{baseInfo,manageInfo,...}`(docs/04 §8);成功码按去前导零 == `"1"` 判定(实测 `"01"`,docs/01 §1);`405` 归类可重试 | TODO | +| T-005 | 阶段 0 验收:Go 侧真实请求打通 + 配置 `init.sh` | T-004 | 用 JKDA00002(Python 已验证的同一查询)发真实请求拿到 `code="01"`;`./init.sh` 三命令替换完成且可运行 | TODO | + +## Phase 1 · 字典服务(路线图阶段 1) + +| ID | 任务 | 依赖 | 验收要点 | 状态 | +| --- | --- | --- | --- | --- | +| T-101 | `osi/public.go` 四个字典查询(网格/责任医生/药品/机构) | T-005 | 真实机构码能查到下级网格、责任医生、机构树 | TODO | +| T-102 | `mapping/dict.go` 全量码表(含 56 项民族) | T-001 | 双向查表;未命中显式 ValidationError;单测覆盖 | TODO | +| T-103 | 字典缓存(内存 + redis 可选) | T-101, T-102 | 映射层能反查 `regionCode/manaDoctorId/manaUnitId`;redis 不可用不阻断 | TODO | + +## Phase 2 · 健康档案闭环(路线图阶段 2,第一条业务线) + +| ID | 任务 | 依赖 | 验收要点 | 状态 | +| --- | --- | --- | --- | --- | +| T-201 | `contract/jkda.go`:以 docs/04 §8 实测契约为基线建结构体 | T-004 | Find 响应能完整反序列化本地联调样本(`data` 数组、null 字段用指针/omitempty、`adressNumber` 坑点拼写) | TODO | +| T-202 | `mapping/health_record.go` + `mapping/checkid.go` | T-102, T-201 | 映射纯函数 + 结构化校验错误;checkId 确定性生成单测 | TODO | +| T-203 | `osi/jkda.go`:Create/Update/Find/FindRqbj | T-201 | Find 真实请求通过;Create 待测试档案确认后联调 | TODO | +| T-204 | `handler`+`router`:`/api/health-record/save` | T-203 | server 模式起服务,curl 全链路返回投递结果 | TODO | +| T-205 | 映射单测基线:docx 样例 + 联调样本 | T-202 | `go test ./mapping/...` 全绿;必填/码表/格式校验生效 | TODO | + +## 里程碑 + +- M1 = T-005:Go 客户端与平台真实握手成功(签名/信封/判码全对)。 +- M2 = T-103:字典服务可反查主数据。 +- M3 = T-205:档案业务线闭环 + 幂等,映射有回归基线。 + +## 待办池(Backlog,按路线图阶段 3~6 展开,进入时再拆小任务) + +- 阶段 3:投递流水线(retry/idempotency/circuit/report + `-mode deliver`)。 +- 阶段 4:其余业务线(体检 JKTJ 字段最多、老年人自理、中医体质、中医指导——B1/B2/B5 契约到位后拆)。 +- 阶段 5:PHIS 真实接入与状态回写。 +- 阶段 6:加固与交接(完整度定论、密钥环境变量化、运维文档、全绿)。 +- 联调依赖跟踪见 `docs/06-厂家联调清单.md`(B 组契约缺口会阻塞阶段 4)。