From 786f3a2f9dcadecb42c6dc2eea4518b67477ebaf Mon Sep 17 00:00:00 2001 From: "agent.develop" Date: Tue, 22 Sep 2026 17:00:53 +0800 Subject: [PATCH] =?UTF-8?q?deliver:=20=E4=BA=A4=E4=BB=98=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=EF=BC=88=E5=BC=95=E6=93=8E=E4=BB=A3=E4=B8=BA=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wwwroot/api/pbl_artifact_options.dspy | 9 +++++---- wwwroot/api/pbl_evidence_aggregate.dspy | 16 +++++++++------- .../api/pbl_evidence_collect_from_events.dspy | 16 +++++++++++----- wwwroot/api/pbl_evidence_collect_idempotent.dspy | 16 +++++++++------- wwwroot/api/pbl_evidence_delete.dspy | 9 ++++----- wwwroot/api/pbl_evidence_query.dspy | 16 +++++++++------- wwwroot/api/pbl_evidence_stats.dspy | 12 +++++++----- wwwroot/api/pbl_evidence_subject_summary.dspy | 16 +++++++++------- wwwroot/api/pbl_evidence_update.dspy | 9 ++++----- 9 files changed, 67 insertions(+), 52 deletions(-) diff --git a/wwwroot/api/pbl_artifact_options.dspy b/wwwroot/api/pbl_artifact_options.dspy index d7e1484..b491174 100644 --- a/wwwroot/api/pbl_artifact_options.dspy +++ b/wwwroot/api/pbl_artifact_options.dspy @@ -1,15 +1,16 @@ -debug(f'pbl_artifact_options.dspy: START params_kw={dict(params_kw)}') +debug('pbl_artifact_options.dspy: START params_kw=' + str(dict(params_kw))) # 下拉数据源(json/pbl_evidence.json -> browserfields.alters.artifact_id.dataurl) # 契约:必须返回**裸 JSON 数组** [{value,text},...],异常/空数据返回 [], # 不许包 status/data(crud-definition-spec Pitfall:包了会让下拉静默不渲染)。 # 后端函数 pbl_artifact_options 由 load_pbl_evidence() 注册到 ServerEnv(init.py ③)。 +# dspy 禁项:无 import、无 f-string(日志一律字符串拼接)。 try: _rows = await pbl_artifact_options(**dict(params_kw)) if not isinstance(_rows, list): _rows = [] - debug(f'pbl_artifact_options.dspy: OK rows={len(_rows)}') + debug('pbl_artifact_options.dspy: OK rows=' + str(len(_rows))) return json.dumps(_rows, ensure_ascii=False) except Exception as e: - debug(f'pbl_artifact_options.dspy: FAIL {e}') - debug(f'pbl_artifact_options.dspy: TRACE {format_exc()}') + debug('pbl_artifact_options.dspy: FAIL ' + str(e)) + debug('pbl_artifact_options.dspy: TRACE ' + str(format_exc())) return json.dumps([], ensure_ascii=False) diff --git a/wwwroot/api/pbl_evidence_aggregate.dspy b/wwwroot/api/pbl_evidence_aggregate.dspy index 0012b36..e03bd34 100644 --- a/wwwroot/api/pbl_evidence_aggregate.dspy +++ b/wwwroot/api/pbl_evidence_aggregate.dspy @@ -1,8 +1,9 @@ # pbl_evidence/api/pbl_evidence_aggregate.dspy # M5b 契约②:证据聚合(四类计数 + 覆盖度 + 分组 + 时间水位)。 # Q-OPEN-10:预览 / Playtest 数据默认剔除,需显式 include_preview=true 才纳入。 -# dspy 铁律:无 import、无 ServerEnv()、显式 return。 -debug(f'pbl_evidence/api/pbl_evidence_aggregate.dspy: START params_kw={dict(params_kw)}') +# dspy 铁律:无 import、无 ServerEnv()、无 f-string、显式 return; +# 日志/异常一律字符串拼接(dspy-file-implementation-spec 硬规则 6)。 +debug('pbl_evidence/api/pbl_evidence_aggregate.dspy: START params_kw=' + str(dict(params_kw))) try: kw = dict(params_kw) @@ -11,10 +12,11 @@ try: kw[flag] = kw[flag].strip().lower() in ('1', 'true', 'yes', 'y') res = await pbl_evidence_aggregate(**kw) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_aggregate.dspy: DONE total={res.get("total")} ' - f'groups={len(res.get("groups") or [])}') - return {'status': status, 'data': res, 'message': res.get('message') or '', - 'total': res.get('total')} + debug('pbl_evidence_aggregate.dspy: DONE total=' + str(res.get('total')) + + ' groups=' + str(len(res.get('groups') or []))) + result = {'status': status, 'data': res, 'message': res.get('message') or '', + 'total': res.get('total')} + return result except Exception as e: - error(f'pbl_evidence_aggregate.dspy: FAIL {format_exc()}') + error('pbl_evidence_aggregate.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_collect_from_events.dspy b/wwwroot/api/pbl_evidence_collect_from_events.dspy index d7474ed..d3968da 100644 --- a/wwwroot/api/pbl_evidence_collect_from_events.dspy +++ b/wwwroot/api/pbl_evidence_collect_from_events.dspy @@ -1,7 +1,8 @@ # pbl_evidence/api/pbl_evidence_collect_from_events.dspy # M5a 主能力:批量从 pbl_runtime_event(M11b 产物)采集学习证据,幂等落 pbl_evidence。 -# 铁律:dspy 内不 import、不 new ServerEnv();ServerEnv 注册的契约函数是直接全局;必须显式 return。 -debug(f'pbl_evidence_collect_from_events.dspy: START params_kw={dict(params_kw)}') +# 铁律:dspy 内不 import、不 new ServerEnv();ServerEnv 注册的契约函数是直接全局;必须显式 return; +# 禁 f-string(硬规则 6),日志一律字符串拼接。 +debug('pbl_evidence_collect_from_events.dspy: START params_kw=' + str(dict(params_kw))) try: tenant = params_kw.get('tenant_id') or (await get_userorgid()) or '0' @@ -27,11 +28,16 @@ try: update_existing=params_kw.get('update_existing'), ) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_collect_from_events.dspy: DONE status={status} msg={res.get("message")}') + debug('pbl_evidence_collect_from_events.dspy: DONE status=' + str(status) + + ' msg=' + str(res.get('message'))) + data = {} + for _k, _v in res.items(): + if _k != 'items': + data[_k] = _v return {'status': status, - 'data': {k: v for k, v in res.items() if k != 'items'}, + 'data': data, 'items': res.get('items') or [], 'message': res.get('message') or ''} except Exception as e: - error(f'pbl_evidence_collect_from_events.dspy: FAIL {format_exc()}') + error('pbl_evidence_collect_from_events.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_collect_idempotent.dspy b/wwwroot/api/pbl_evidence_collect_idempotent.dspy index 43b559f..9932216 100644 --- a/wwwroot/api/pbl_evidence_collect_idempotent.dspy +++ b/wwwroot/api/pbl_evidence_collect_idempotent.dspy @@ -1,15 +1,17 @@ # pbl_evidence/api/pbl_evidence_collect_idempotent.dspy # M5b 契约①:四类证据(decision/action/observation/artifact_version)幂等采集。 # 重复采集(同 idempotency_key / 同唯一索引三元组)不报错,返回 created=false。 -# dspy 铁律:无 import、无 ServerEnv()、显式 return;函数由 load_pbl_evidence() 挂 ServerEnv。 -debug(f'pbl_evidence/api/pbl_evidence_collect_idempotent.dspy: START params_kw={dict(params_kw)}') +# dspy 铁律:无 import、无 ServerEnv()、无 f-string、显式 return; +# 函数由 load_pbl_evidence() 挂 ServerEnv;日志一律字符串拼接。 +debug('pbl_evidence/api/pbl_evidence_collect_idempotent.dspy: START params_kw=' + str(dict(params_kw))) try: - res = await pbl_evidence_collect_idempotent(**params_kw) + res = await pbl_evidence_collect_idempotent(**dict(params_kw)) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_collect_idempotent.dspy: DONE created={res.get("created")} ' - f'deduped={res.get("deduped")} id={res.get("id")}') - return {'status': status, 'data': res, 'message': res.get('message') or ''} + debug('pbl_evidence_collect_idempotent.dspy: DONE created=' + str(res.get('created')) + + ' deduped=' + str(res.get('deduped')) + ' id=' + str(res.get('id'))) + result = {'status': status, 'data': res, 'message': res.get('message') or ''} + return result except Exception as e: - error(f'pbl_evidence_collect_idempotent.dspy: FAIL {format_exc()}') + error('pbl_evidence_collect_idempotent.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_delete.dspy b/wwwroot/api/pbl_evidence_delete.dspy index 4fba7bf..55b84ee 100644 --- a/wwwroot/api/pbl_evidence_delete.dspy +++ b/wwwroot/api/pbl_evidence_delete.dspy @@ -1,4 +1,4 @@ -debug(f'pbl_evidence_delete.dspy: START params_kw={dict(params_kw)}') +debug('pbl_evidence_delete.dspy: START params_kw=' + str(dict(params_kw))) # 证据删除端点(json/pbl_evidence.json -> delete_data_url,DataViewer editable 提交目标)。 # 薄包装:无 import、无业务逻辑,直接委托 init.py 注册的 pbl_evidence_delete # (支持单条 id 与批量 ids;每条都按 tenant_id + id 双条件校验归属,防越权删除)。 @@ -7,8 +7,7 @@ debug(f'pbl_evidence_delete.dspy: START params_kw={dict(params_kw)}') # 1) dspy-file-implementation-spec「DataViewer CRUD endpoints 必须返回 Message widget # JSON 字符串」——本端点是 editable 提交端点,故返回 bricks Message widget, # 删除提交后能正确渲染成功/失败提示;不得返回裸数据 dict。 -# 2) 禁项 f-string 出现在 dict 字面量内会被 ahserver exec() 误判提前闭合外层 dict -# (SyntaxError: '{' was never closed,整文件编译失败),异常分支一律用字符串拼接。 +# 2) dspy 禁项 f-string(硬规则 6):一律字符串拼接,异常分支亦然。 try: _data = await pbl_evidence_delete(**dict(params_kw)) _msg = (_data or {}).get('message') or '证据已删除' @@ -17,8 +16,8 @@ try: debug('pbl_evidence_delete.dspy: OK deleted=' + str((_data or {}).get('deleted'))) return json.dumps(_widget, ensure_ascii=False) except Exception as e: - debug(f'pbl_evidence_delete.dspy: FAIL {e}') - debug(f'pbl_evidence_delete.dspy: TRACE {format_exc()}') + debug('pbl_evidence_delete.dspy: FAIL ' + str(e)) + debug('pbl_evidence_delete.dspy: TRACE ' + str(format_exc())) _widget = {'widgettype': 'Message', 'options': {'title': '失败', 'message': '证据删除失败:' + str(e), diff --git a/wwwroot/api/pbl_evidence_query.dspy b/wwwroot/api/pbl_evidence_query.dspy index ed874d2..cf70418 100644 --- a/wwwroot/api/pbl_evidence_query.dspy +++ b/wwwroot/api/pbl_evidence_query.dspy @@ -2,8 +2,9 @@ # M5b 契约③:证据分页查询(含 timestamp + payload,US-17「证据不只是分数」)。 # 支持 blueprint_id / learner_id / session_id / artifact_id / evidence_type / # evidence_types / time_from,time_to / page / rows;预览数据默认过滤(Q-OPEN-10)。 -# dspy 铁律:无 import、无 ServerEnv()、显式 return。 -debug(f'pbl_evidence/api/pbl_evidence_query.dspy: START params_kw={dict(params_kw)}') +# dspy 铁律:无 import、无 ServerEnv()、无 f-string、显式 return; +# 日志/异常一律字符串拼接(dspy-file-implementation-spec 硬规则 6)。 +debug('pbl_evidence/api/pbl_evidence_query.dspy: START params_kw=' + str(dict(params_kw))) try: kw = dict(params_kw) @@ -12,10 +13,11 @@ try: kw[flag] = kw[flag].strip().lower() in ('1', 'true', 'yes', 'y') res = await pbl_evidence_query(**kw) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_query.dspy: DONE total={res.get("total")} ' - f'page={res.get("page")} rows={len(res.get("rows") or [])}') - return {'status': status, 'data': res, 'message': res.get('message') or '', - 'total': res.get('total')} + debug('pbl_evidence_query.dspy: DONE total=' + str(res.get('total')) + + ' page=' + str(res.get('page')) + ' rows=' + str(len(res.get('rows') or []))) + result = {'status': status, 'data': res, 'message': res.get('message') or '', + 'total': res.get('total')} + return result except Exception as e: - error(f'pbl_evidence_query.dspy: FAIL {format_exc()}') + error('pbl_evidence_query.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_stats.dspy b/wwwroot/api/pbl_evidence_stats.dspy index 310f10e..5b7b200 100644 --- a/wwwroot/api/pbl_evidence_stats.dspy +++ b/wwwroot/api/pbl_evidence_stats.dspy @@ -1,6 +1,7 @@ # pbl_evidence/api/pbl_evidence_stats.dspy -# 证据类型分布统计(供 M6 评估 / 概览卡片)。dspy 无 import、无 ServerEnv()、显式 return。 -debug(f'pbl_evidence_stats.dspy: START params_kw={dict(params_kw)}') +# 证据类型分布统计(供 M6 评估 / 概览卡片)。 +# dspy 铁律:无 import、无 ServerEnv()、无 f-string、显式 return(日志字符串拼接)。 +debug('pbl_evidence_stats.dspy: START params_kw=' + str(dict(params_kw))) try: tenant = params_kw.get('tenant_id') or (await get_userorgid()) or '0' @@ -10,8 +11,9 @@ try: blueprint_id=params_kw.get('blueprint_id'), ) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_stats.dspy: DONE total={res.get("total")}') - return {'status': status, 'data': res, 'message': res.get('message') or ''} + debug('pbl_evidence_stats.dspy: DONE total=' + str(res.get('total'))) + result = {'status': status, 'data': res, 'message': res.get('message') or ''} + return result except Exception as e: - error(f'pbl_evidence_stats.dspy: FAIL {format_exc()}') + error('pbl_evidence_stats.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_subject_summary.dspy b/wwwroot/api/pbl_evidence_subject_summary.dspy index 39b2347..14267c2 100644 --- a/wwwroot/api/pbl_evidence_subject_summary.dspy +++ b/wwwroot/api/pbl_evidence_subject_summary.dspy @@ -2,8 +2,9 @@ # M5b 契约④:学生 / 团队证据档案(设计 §3.2 list_evidence_by_student / by_team 等价实现)。 # 入参:subject_type=student|team + subject_id(或 student_id / team_id)+ blueprint_id(可选) # 出参:四类分组明细 + 产出物计数 + 水位;预览/Playtest 数据默认过滤(Q-OPEN-10)。 -# dspy 铁律:无 import、无 ServerEnv()、显式 return。 -debug(f'pbl_evidence/api/pbl_evidence_subject_summary.dspy: START params_kw={dict(params_kw)}') +# dspy 铁律:无 import、无 ServerEnv()、无 f-string、显式 return; +# 日志/异常一律字符串拼接(dspy-file-implementation-spec 硬规则 6)。 +debug('pbl_evidence/api/pbl_evidence_subject_summary.dspy: START params_kw=' + str(dict(params_kw))) try: kw = dict(params_kw) @@ -13,10 +14,11 @@ try: kw['include_student_private'] = kw['include_student_private'].strip().lower() in ('1', 'true', 'yes', 'y') res = await pbl_evidence_subject_summary(**kw) status = 'OK' if res.get('ok') else 'ERROR' - debug(f'pbl_evidence_subject_summary.dspy: DONE subject={res.get("subject_type")}:' - f'{res.get("subject_id")} total={res.get("evidence_total")}') - return {'status': status, 'data': res, 'message': res.get('message') or '', - 'total': res.get('evidence_total')} + debug('pbl_evidence_subject_summary.dspy: DONE subject=' + str(res.get('subject_type')) + + ':' + str(res.get('subject_id')) + ' total=' + str(res.get('evidence_total'))) + result = {'status': status, 'data': res, 'message': res.get('message') or '', + 'total': res.get('evidence_total')} + return result except Exception as e: - error(f'pbl_evidence_subject_summary.dspy: FAIL {format_exc()}') + error('pbl_evidence_subject_summary.dspy: FAIL ' + str(format_exc())) return {'status': 'ERROR', 'data': None, 'message': str(e)} diff --git a/wwwroot/api/pbl_evidence_update.dspy b/wwwroot/api/pbl_evidence_update.dspy index 046a9c3..04a3bd7 100644 --- a/wwwroot/api/pbl_evidence_update.dspy +++ b/wwwroot/api/pbl_evidence_update.dspy @@ -1,4 +1,4 @@ -debug(f'pbl_evidence_update.dspy: START params_kw={dict(params_kw)}') +debug('pbl_evidence_update.dspy: START params_kw=' + str(dict(params_kw))) # 证据人工修订端点(json/pbl_evidence.json -> update_data_url,DataViewer editable 提交目标)。 # 薄包装:无 import、无业务逻辑,直接委托 init.py 注册的 pbl_evidence_update # (强制 tenant_id 打头校验归属;改唯一索引三元组时同步重算 dedup_key)。 @@ -7,8 +7,7 @@ debug(f'pbl_evidence_update.dspy: START params_kw={dict(params_kw)}') # 1) dspy-file-implementation-spec「DataViewer CRUD endpoints 必须返回 Message widget # JSON 字符串」——本端点是 editable 提交端点,故返回 bricks Message widget, # 表单提交后能正确渲染成功/失败提示;不得返回裸数据 dict。 -# 2) 禁项 f-string 出现在 dict 字面量内会被 ahserver exec() 误判提前闭合外层 dict -# (SyntaxError: '{' was never closed,整文件编译失败),异常分支一律用字符串拼接。 +# 2) dspy 禁项 f-string(硬规则 6):一律字符串拼接,异常分支亦然。 try: _data = await pbl_evidence_update(**dict(params_kw)) _msg = (_data or {}).get('message') or '证据已更新' @@ -17,8 +16,8 @@ try: debug('pbl_evidence_update.dspy: OK') return json.dumps(_widget, ensure_ascii=False) except Exception as e: - debug(f'pbl_evidence_update.dspy: FAIL {e}') - debug(f'pbl_evidence_update.dspy: TRACE {format_exc()}') + debug('pbl_evidence_update.dspy: FAIL ' + str(e)) + debug('pbl_evidence_update.dspy: TRACE ' + str(format_exc())) _widget = {'widgettype': 'Message', 'options': {'title': '失败', 'message': '证据更新失败:' + str(e),