diff --git a/README.md b/README.md index 5ba9111..072a4c4 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,22 @@ def init(): `env. = `。漏 ② → import 期 ImportError;漏 ③ → .dspy 调用 NameError。 新增对外路径还要同步 ④ `scripts/load_path.py`(+ 中央 `apps/pbls/scripts/load_path.py`)。 +### 接口返回形态(wwwroot/api/*.dspy,三类,勿混用) + +| 端点类别 | 返回体 | 依据 | +|---|---|---| +| **DataViewer editable 提交端点**:`pbl_evidence_update.dspy`、`pbl_evidence_delete.dspy` | `json.dumps({'widgettype':'Message','options':{'title','message','type'}})` **字符串**,成功 `type='success'`、异常 `type='error'` | dspy-file-implementation-spec「DataViewer CRUD endpoints 必须返回 Message widget JSON 字符串,不得返回裸数据」 | +| **下拉数据源**:`pbl_artifact_options.dspy` | 裸数组 `[{value,text}]`,异常降级 `[]` | crud-definition-spec(包 status/data 会让下拉静默不渲染) | +| **契约直调端点**:`pbl_artifact_{create,read,update,delete,list}.dspy`、`pbl_evidence_{collect,collect_from_events,list,stats}.dspy` | 直接 `return` 后端函数的结构化 dict(`status/data/message/total`) | module-development-spec 2.5(薄包装,不加工返回体) | + +前两类是 editable/表单相关端点、第三类是程序化契约端点,形态差异**有意为之**, +不构成同目录格式分裂(后端 `crud_api.py` 仍返回结构化 dict,由 dspy 层转 Message)。 + +**写 dspy 的铁律**:dict 字面量内**禁止** f-string(`{'message': f'...{e}'}` 会让 ahserver +`exec()` 误判提前闭合外层 dict → `SyntaxError: '{' was never closed` → 整文件编译失败), +一律 `'前缀:' + str(e)` 拼接;顶部 `debug(f'...')` 前缀日志不受此限。 +自查:`grep -n "f'" wwwroot/api/*.dspy | grep -v debug` 无输出。 + ## 目录结构 ``` diff --git a/skill/SKILL.md b/skill/SKILL.md index e54b1e2..ba3a676 100644 --- a/skill/SKILL.md +++ b/skill/SKILL.md @@ -40,8 +40,8 @@ xls2ui 会生成到同一目录互相覆盖)。 | 9 | `pbl_evidence_stats` | `pbl_evidence_stats.dspy` | 证据类型分布统计,供 M6 评估与概览页 | | 10 | `pbl_evidence_watermark` | **无独立 .dspy**(见下) | 返回某会话/蓝图已采集到的时间水位,供 M5b/cron 增量续采 | | 11 | `pbl_artifact_options` | `pbl_artifact_options.dspy` | **CRUD 适配**(`crud_api.py`):产出物下拉数据源,返回**裸数组** `[{value,text}]`,异常降级 `[]`;供 `json/pbl_evidence.json` 的 `alters.artifact_id.dataurl` | -| 12 | `pbl_evidence_update` | `pbl_evidence_update.dspy` | **CRUD 适配**(`crud_api.py`):人工修订证据,强制 `tenant_id` 归属校验;改唯一索引三元组时同步重算 `dedup_key`;供 `editable.update_data_url` | -| 13 | `pbl_evidence_delete` | `pbl_evidence_delete.dspy` | **CRUD 适配**(`crud_api.py`):按 id/ids 删除证据,逐条校验归属;供 `editable.delete_data_url` | +| 12 | `pbl_evidence_update` | `pbl_evidence_update.dspy` | **CRUD 适配**(`crud_api.py`):人工修订证据,强制 `tenant_id` 归属校验;改唯一索引三元组时同步重算 `dedup_key`;供 `editable.update_data_url`。**dspy 返回 bricks Message widget JSON 字符串**(成功 type=success / 异常 type=error),不是裸数据 | +| 13 | `pbl_evidence_delete` | `pbl_evidence_delete.dspy` | **CRUD 适配**(`crud_api.py`):按 id/ids 删除证据,逐条校验归属;供 `editable.delete_data_url`。**dspy 返回 bricks Message widget JSON 字符串**(成功 type=success / 异常 type=error),不是裸数据 | **watermark 的调用方式(第 10 条契约刻意不生成 .dspy)**: - 内部调用:宿主/cron/M5b 通过 `ServerEnv().pbl_evidence_watermark(...)` 直调; @@ -66,6 +66,20 @@ xls2ui 会生成到同一目录互相覆盖)。 > 自查命令:`grep -rn 'pbl_evidence_update' pbl_evidence/ --include='*.py'` > 必须命中 定义(crud_api.py) / __init__.py import / __all__ / init.py import / env 注册。 +> **editable 提交端点返回形态(QC #15 收口,勿回退)**: +> `pbl_evidence_update.dspy` / `pbl_evidence_delete.dspy` 是 `json/pbl_evidence.json` 的 +> `update_data_url` / `delete_data_url` 目标,即 DataViewer **editable 提交端点**,按 +> dspy-file-implementation-spec 必须返回 +> `{"widgettype":"Message","options":{"title","message","type"}}` 的 **JSON 字符串** +> (`json.dumps(..., ensure_ascii=False)`),成功 `type='success'`、异常 `type='error'`。 +> 后端 `crud_api.py` 仍返回结构化 dict(`ok/status/id/message`)供程序化调用, +> **由 dspy 负责转成 Message widget**——这是 Pitfall 25「直接 return 被委托 helper」之外的 +> 自行组装形态,故必须走 Message,不得返回裸数据。 +> `pbl_artifact_options.dspy` 是**下拉数据源**(非 editable 端点),按 crud-definition-spec +> 继续返回裸数组 `[{value,text}]`,异常降级 `[]`,**不要**改成 Message。 +> `json/pbl_artifact.json` 的 new/update/delete 走 `api.py` 契约端点(框架生成语义), +> 与上面两者形态不同属**有意区分**(editable 提交 vs 契约直调),非目录内格式分裂。 + ## 编码字典(init/data.json,Format B) | parentid(≤22 字符) | 含义 | 子项 | |---|---|---| @@ -93,6 +107,7 @@ xls2ui 会生成到同一目录互相覆盖)。 漏 ② → import 期 ImportError;漏 ③ → .dspy NameError;漏 ④ → 403。 - 批量采集依赖 M11b 的 `pbl_runtime_event`;该表不存在时按设计抛 `CollectError → PBL_E_DB_UNAVAILABLE`(本地环境未联调,勿当成代码缺陷)。 +- **dspy 内 dict 字面量禁写 f-string(QC #14)**:`{'message': f'...{e}'}` 的花括号嵌在 dict 字面量里会被 ahserver 的 `exec()` 误判提前闭合外层 dict,触发 `SyntaxError: '{' was never closed`,**整文件编译失败**(不只是异常路径失效)。一律写字符串拼接 `'证据更新失败:' + str(e)`。顶部 `debug(f'...')` 前缀日志是推荐写法,不受此限。自查:`grep -n "f'" wwwroot/api/*.dspy | grep -v debug` → 无输出即合格。 - `wwwroot/{alias}/`(xls2ui 生成物)是只读构建产物,改逻辑改 `json/*.json` + `models/*.json` 后重跑 build。 ## 依赖