From bff204e58adab070a49f6f2e543a99b5bc54863d Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 1 May 2026 21:30:32 +0800 Subject: [PATCH] docs: add phase 13 knowledge card import flow --- .../README.md | 5 +- .../legal-knowledge-card-inventory.csv | 10 + .../knowledge-cards/README.md | 11 + .../KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md | 39 ++ .../civil-code/KC-CIVIL-CONTRACT-FORM-001.md | 40 ++ .../KC-CIVIL-RESCISSION-NOTICE-001.md | 39 ++ .../KC-CIVIL-STANDARD-CLAUSES-001.md | 39 ++ .../KC-COMPANY-AUTHORIZATION-001.md | 39 ++ .../KC-DISPUTE-ARBITRATION-LITIGATION-001.md | 40 ++ .../KC-E-SIGN-EVIDENCE-RETENTION-001.md | 40 ++ .../data-privacy/KC-DATA-PI-PROCESSING-001.md | 40 ++ .../KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md | 40 ++ .../KC-LABOR-CONTRACT-TERM-PROBATION-001.md | 39 ++ ...¾‹知识库与合同模板库建设闭环方案-2026-05-01.md | 17 +- ...“与合同模板库建设闭环第二批执行记录-2026-05-01.md | 106 +++ scripts/import-phase13-library.ps1 | 657 ++++++++++++++++++ scripts/run-legal-knowledge-library-gate.ps1 | 93 ++- 17 files changed, 1283 insertions(+), 11 deletions(-) create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/README.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-CONTRACT-FORM-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-RESCISSION-NOTICE-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-STANDARD-CLAUSES-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-COMPANY-AUTHORIZATION-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-DISPUTE-ARBITRATION-LITIGATION-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-E-SIGN-EVIDENCE-RETENTION-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/data-privacy/KC-DATA-PI-PROCESSING-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/intellectual-property/KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md create mode 100644 project-docs/phase13-legal-knowledge-template-library/knowledge-cards/labor-employment/KC-LABOR-CONTRACT-TERM-PROBATION-001.md create mode 100644 project-docs/阶段13-法律知识库与合同模板库建设闭环第二批执行记录-2026-05-01.md create mode 100644 scripts/import-phase13-library.ps1 diff --git a/project-docs/phase13-legal-knowledge-template-library/README.md b/project-docs/phase13-legal-knowledge-template-library/README.md index 4d12dc79..d04f4f42 100644 --- a/project-docs/phase13-legal-knowledge-template-library/README.md +++ b/project-docs/phase13-legal-knowledge-template-library/README.md @@ -12,6 +12,7 @@ 6. 合同模板库字段规范。 7. 合同审核、合同生成和知识库问答黄金样本字段规范。 8. 法律专家和业务负责人复核登记规范。 +9. 法务复核知识库导入脚本。 重要规则: @@ -25,4 +26,6 @@ 1. 阶段 13.0 资料结构和字段规范已建立。 2. 阶段 13.1 第一批官方法源采集任务已建立。 -3. 生产发布仍需等待法务复核和业务复核完成。 +3. 阶段 13.2 第一批中文法律知识卡已建立,共 10 张,全部保持 `LEGAL_REVIEW`。 +4. 阶段 13.7 第一版一键导入脚本已建立,默认 `Validate` 模式不改系统,`Review` 模式可导入待法务复核知识库,`Production` 模式只导入已复核且生产就绪资料。 +5. 生产发布仍需等待法务复核和业务复核完成。 diff --git a/project-docs/phase13-legal-knowledge-template-library/inventories/legal-knowledge-card-inventory.csv b/project-docs/phase13-legal-knowledge-template-library/inventories/legal-knowledge-card-inventory.csv index 4797a507..7dc13fd4 100644 --- a/project-docs/phase13-legal-knowledge-template-library/inventories/legal-knowledge-card-inventory.csv +++ b/project-docs/phase13-legal-knowledge-template-library/inventories/legal-knowledge-card-inventory.csv @@ -1 +1,11 @@ knowledge_card_id,title,source_ids,legal_question,applicable_scenarios,non_applicable_scenarios,summary_path,original_reference,answer_boundary,status,owner,legal_reviewer,review_required,production_ready,notes +KC-CIVIL-CONTRACT-FORM-001,合同形式与电子数据形式,LAW-CIVIL-001;LAW-E-SIGN-001,纸质合同、电子合同、电子邮件和系统订单能否作为合同形式和履约证据,采购合同;服务合同;软件与软件即服务合同;电子签署,特殊形式合同;强监管合同;跨境签署,knowledge-cards/civil-code/KC-CIVIL-CONTRACT-FORM-001.md,民法典合同形式规则;电子签名法数据电文与可靠电子签名规则,只能回答合同形式和电子证据的一般审核方向;特殊形式、监管审批、跨境签署必须人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,第一批知识卡;需法务确认条款号和电子签署边界 +KC-CIVIL-STANDARD-CLAUSES-001,格式条款提示说明与效力边界,LAW-CIVIL-001;LAW-CONTRACT-001,标准合同和平台条款如何提示说明并避免格式条款无效风险,标准合同;平台服务条款;采购模板;服务模板,充分逐条协商条款;个案效力判断,knowledge-cards/civil-code/KC-CIVIL-STANDARD-CLAUSES-001.md,民法典格式条款规则;民法典合同编通则司法解释相关规则,只能提示格式条款风险;单个条款效力需人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于审核规则和模板条款边界 +KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001,违约责任与违约金调整边界,LAW-CIVIL-001;LAW-CONTRACT-001,如何约定违约责任、赔偿范围和违约金以降低争议风险,付款;交付;验收;质量;保密;软件服务,行政处罚;刑事责任;已进入争议程序的损失计算,knowledge-cards/civil-code/KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md,民法典违约责任与违约金规则;民法典合同编通则司法解释相关规则,只能给出结构化审核方向;具体比例和金额需结合法务复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,后续绑定违约责任审核规则 +KC-CIVIL-RESCISSION-NOTICE-001,合同解除条件与通知留痕,LAW-CIVIL-001;LAW-CONTRACT-001,解除权、解除通知、视为送达和解除后果如何约定,采购合同;服务合同;软件服务合同;技术合同,劳动合同解除;消费者合同解除;个案解除效力判断,knowledge-cards/civil-code/KC-CIVIL-RESCISSION-NOTICE-001.md,民法典合同解除规则;民法典合同编通则司法解释相关规则,不能直接判断某次解除是否有效;涉及争议时必须人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,后续绑定解除和通知审核规则 +KC-LABOR-CONTRACT-TERM-PROBATION-001,劳动合同订立、期限与试用期边界,LAW-LABOR-001;LAW-LABOR-002,劳动合同如何约定期限、岗位、地点、工资、社保和试用期,劳动合同模板;人事合同审核;劳务边界识别,退休返聘;平台用工;工伤;竞业限制;劳动争议个案,knowledge-cards/labor-employment/KC-LABOR-CONTRACT-TERM-PROBATION-001.md,劳动合同法劳动合同订立和试用期规则;劳动法劳动保护规则,不能直接认定劳动关系或计算解除补偿;复杂用工必须人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于劳动与劳务合同边界提示 +KC-DATA-PI-PROCESSING-001,个人信息处理与委托处理条款边界,LAW-DATA-001;LAW-DATA-002;LAW-DATA-003,合同涉及个人信息和数据处理时如何约定处理目的、范围、授权和安全义务,软件与软件即服务合同;数据处理协议;外包服务;平台服务,数据出境;重要数据;关键信息基础设施;行业监管数据,knowledge-cards/data-privacy/KC-DATA-PI-PROCESSING-001.md,个人信息保护法处理规则;数据安全法安全管理规则;网络安全法网络运营者义务,只能做合同条款层面初筛;数据出境和高风险处理必须合规专项复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,后续绑定数据安全和隐私审核规则 +KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001,软件成果著作权归属与许可边界,LAW-IP-001;LAW-CIVIL-001;LAW-TECH-001,软件开发和技术服务合同中如何约定成果归属、源代码交付和授权使用,技术开发;软件开发;系统实施;软件服务,开源合规;专利申请权;商业秘密争议;职务作品争议,knowledge-cards/intellectual-property/KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md,著作权法作品权利与许可规则;民法典技术合同规则;技术合同司法解释相关规则,不能直接判断具体成果权属;开源、专利、商业秘密需专项复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于技术开发和软件服务模板 +KC-COMPANY-AUTHORIZATION-001,签约主体资格与授权代表核验,LAW-COMPANY-001;LAW-CIVIL-001,签约前如何核验主体资格、代表权限、授权委托和盖章风险,采购合同;服务合同;技术合同;授权代表签署,境外主体;重大资产交易;国资交易;个案表见代理判断,knowledge-cards/company-commercial/KC-COMPANY-AUTHORIZATION-001.md,公司法公司主体与治理规则;民法典代理和合同效力规则,只能提示主体和授权核验事项;越权代表和表见代理需人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于主体资格审核规则 +KC-DISPUTE-ARBITRATION-LITIGATION-001,仲裁与诉讼争议解决条款选择,LAW-ARBITRATION-001;LAW-CIVIL-PROCEDURE-001;LAW-CIVIL-001,争议解决条款如何选择仲裁或诉讼并避免机构、管辖冲突,采购合同;服务合同;保密协议;技术开发合同,涉外合同;劳动争议;消费者争议;专属管辖事项,knowledge-cards/company-commercial/KC-DISPUTE-ARBITRATION-LITIGATION-001.md,仲裁法仲裁协议规则;民事诉讼法管辖规则;民法典合同争议规则,不能判断具体仲裁协议或管辖条款最终效力;争议发生后需律师复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于争议解决条款审核 +KC-E-SIGN-EVIDENCE-RETENTION-001,电子签名与电子合同证据留存,LAW-E-SIGN-001;LAW-CIVIL-001;LAW-CIVIL-PROCEDURE-001,电子合同签署后如何保存签署证据、身份认证、时间戳和履约记录,电子签署;线上订单;系统确认;邮件签署,不得适用电子文书的场景;电子签名技术鉴定,knowledge-cards/company-commercial/KC-E-SIGN-EVIDENCE-RETENTION-001.md,电子签名法数据电文与可靠电子签名规则;民法典合同形式规则;民事诉讼法电子数据证据规则,不能判断某一电子签名是否满足可靠电子签名标准;证据能力和技术鉴定需人工复核,LEGAL_REVIEW,法律资料运营,待法务复核,true,false,用于电子签署和证据留存条款 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/README.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/README.md new file mode 100644 index 00000000..96bdfd9f --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/README.md @@ -0,0 +1,11 @@ +# 法律知识卡目录 + +本目录保存阶段 13.2 拆解出的中文法律知识卡。知识卡不是法律全文备份,而是面向合同审核、知识库问答和合同生成的结构化摘要。 + +使用规则: + +1. 每张知识卡必须登记到 `../inventories/legal-knowledge-card-inventory.csv`。 +2. 每张知识卡必须绑定一个或多个中国官方法源编号。 +3. 未经法务复核前,知识卡状态保持 `LEGAL_REVIEW`,不得进入生产确定性索引。 +4. 知识卡可以进入法务复核知识库,用于内部复核、调试和样本建设。 +5. 回答边界必须明确:无法确认条款号、有效状态或适用条件时,应提示人工复核。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md new file mode 100644 index 00000000..11afe11c --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001.md @@ -0,0 +1,39 @@ +# 违约责任与违约金调整边界 + +知识卡编号:KC-CIVIL-BREACH-LIQUIDATED-DAMAGES-001 + +绑定法源:LAW-CIVIL-001;LAW-CONTRACT-001 + +## 法律问题 + +合同如何约定违约责任、赔偿范围、违约金和损失计算方式,避免责任不清或明显过高过低。 + +## 适用场景 + +1. 采购、服务、技术开发、软件服务合同中约定延期交付、延期付款、质量不合格、保密违约等责任。 +2. 合同需要设置违约金比例、赔偿上限、继续履行、补救措施或解除权。 +3. 审核违约责任是否缺少触发条件、计算口径或责任上限。 + +## 不适用场景 + +1. 行政处罚、刑事责任或劳动争议中的法定责任判断。 +2. 已进入诉讼或仲裁阶段,需要结合证据计算损失的案件。 + +## 依据范围 + +1. 《中华人民共和国民法典》关于违约责任、继续履行、补救措施、赔偿损失和违约金调整的一般规则。 +2. 最高人民法院关于民法典合同编通则的司法解释中与违约责任、损失赔偿和违约金相关的规则。 + +## 审核提示 + +1. 违约条款应明确违约事件、宽限期、补救期限、责任形式、计算公式和证据要求。 +2. 违约金明显高于或低于实际损失时,存在被调整风险,应提示人工复核。 +3. 对关键义务可以设置分层责任:继续履行、补救、扣款、违约金、赔偿、解除。 + +## 回答边界 + +本卡只能提供违约责任条款的结构化审核方向。是否支持具体金额、比例或赔偿范围,需要结合交易金额、实际损失、履约证据和司法裁量,由法务复核。 + +## 复核状态 + +待法务确认具体条款号、违约金调整口径和司法解释引用范围。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-CONTRACT-FORM-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-CONTRACT-FORM-001.md new file mode 100644 index 00000000..6a6e62ea --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-CONTRACT-FORM-001.md @@ -0,0 +1,40 @@ +# 合同形式与电子数据形式 + +知识卡编号:KC-CIVIL-CONTRACT-FORM-001 + +绑定法源:LAW-CIVIL-001;LAW-E-SIGN-001 + +## 法律问题 + +企业签订合同时,纸质合同、电子合同、电子邮件、系统订单、平台确认记录等是否可以作为合同形式和履约证据。 + +## 适用场景 + +1. 采购合同、服务合同、软件与软件即服务合同使用线上签署或电子确认。 +2. 双方通过邮件、企业系统、订单页面或电子签名平台确认合同内容。 +3. 审核合同中关于签署方式、通知方式、电子证据、数据电文保存的条款。 + +## 不适用场景 + +1. 法律、行政法规或监管规则明确要求特定形式、审批或登记的合同。 +2. 涉及不动产、特殊资质、行政许可或强监管场景的合同形式判断。 +3. 需要确认具体电子签名平台合规性的技术审计。 + +## 依据范围 + +1. 《中华人民共和国民法典》关于合同书面形式、数据电文形式、合同成立和合同内容的一般规则。 +2. 《中华人民共和国电子签名法》关于可靠电子签名、数据电文和电子签约效力的规则。 + +## 审核提示 + +1. 合同应明确电子签署、电子邮件、系统通知或平台确认是否具有书面通知和签署效力。 +2. 电子签署场景应关注签署人身份认证、签署权限、签署时间、签署文件完整性和留痕方式。 +3. 如合同使用线上订单或系统确认,应补充订单内容、确认方式、变更记录和证据保存规则。 + +## 回答边界 + +本卡只能说明中国大陆合同形式和电子数据形式的一般规则。若涉及特定行业监管、强制登记、行政审批、跨境签署或电子认证服务资质,应提示法务或专业机构进一步复核。 + +## 复核状态 + +待法务确认具体条款号、现行有效状态和电子签名场景适用边界。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-RESCISSION-NOTICE-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-RESCISSION-NOTICE-001.md new file mode 100644 index 00000000..4321a5fd --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-RESCISSION-NOTICE-001.md @@ -0,0 +1,39 @@ +# 合同解除条件与通知留痕 + +知识卡编号:KC-CIVIL-RESCISSION-NOTICE-001 + +绑定法源:LAW-CIVIL-001;LAW-CONTRACT-001 + +## 法律问题 + +合同约定解除权、单方解除、通知送达和解除后处理时,应如何设置条件和留痕要求。 + +## 适用场景 + +1. 合同中约定任意解除、违约解除、逾期解除、服务暂停后解除。 +2. 双方约定解除通知方式、送达地址、电子通知和解除生效时间。 +3. 审核合同解除后费用结算、资料返还、保密义务、知识产权和数据处理安排。 + +## 不适用场景 + +1. 劳动合同解除、消费者合同解除、行政许可相关合同解除等特殊规则。 +2. 已发生争议,需要判断解除是否有效的个案。 + +## 依据范围 + +1. 《中华人民共和国民法典》关于协商解除、法定解除、解除通知和解除后果的一般规则。 +2. 最高人民法院关于民法典合同编通则的司法解释中与解除权行使和合同后果相关的规则。 + +## 审核提示 + +1. 解除条件应清楚,避免只写“严重违约”而不说明判断标准。 +2. 通知条款应明确送达方式、送达地址、联系人、电子通知效力和视为送达规则。 +3. 解除后条款应覆盖价款结算、已交付成果、资料返还、保密义务、数据删除或返还。 + +## 回答边界 + +本卡不能直接判断某次解除是否有效。涉及解除通知是否送达、违约程度是否达到解除条件、解除后的损失计算时,应提示人工复核。 + +## 复核状态 + +待法务确认具体条款号、通知送达规则和解除后果适用边界。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-STANDARD-CLAUSES-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-STANDARD-CLAUSES-001.md new file mode 100644 index 00000000..f6610f92 --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/KC-CIVIL-STANDARD-CLAUSES-001.md @@ -0,0 +1,39 @@ +# 格式条款提示说明与效力边界 + +知识卡编号:KC-CIVIL-STANDARD-CLAUSES-001 + +绑定法源:LAW-CIVIL-001;LAW-CONTRACT-001 + +## 法律问题 + +平台模板、标准合同、采购订单、服务条款中的格式条款,如何提示对方注意并避免无效或被调整风险。 + +## 适用场景 + +1. 一方重复使用预先拟定的合同文本。 +2. 合同中存在免除或减轻己方责任、加重对方责任、限制对方主要权利的条款。 +3. 平台服务协议、软件服务协议、保密协议和采购标准条款审核。 + +## 不适用场景 + +1. 双方逐条协商且已有充分谈判记录的非格式条款。 +2. 需要判断具体格式条款是否无效的诉讼或仲裁案件。 + +## 依据范围 + +1. 《中华人民共和国民法典》关于格式条款提供方提示说明义务、格式条款解释和无效情形的规则。 +2. 最高人民法院关于民法典合同编通则的司法解释中与格式条款、合同成立、效力和解释相关的规则。 + +## 审核提示 + +1. 高风险格式条款应使用醒目方式提示,并保留对方确认记录。 +2. 免除己方主要责任、排除对方主要权利或明显失衡的条款,应触发高风险审核。 +3. 模板合同应为格式条款准备替代版本和人工复核提示。 + +## 回答边界 + +本卡用于识别格式条款风险和提示审核方向,不能替代对单个条款效力的个案法律判断。若条款涉及消费者、劳动者、金融服务或平台规则,应进入人工复核。 + +## 复核状态 + +待法务确认具体条款号、司法解释适用范围和高风险条款清单。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-COMPANY-AUTHORIZATION-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-COMPANY-AUTHORIZATION-001.md new file mode 100644 index 00000000..e1510b65 --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-COMPANY-AUTHORIZATION-001.md @@ -0,0 +1,39 @@ +# 签约主体资格与授权代表核验 + +知识卡编号:KC-COMPANY-AUTHORIZATION-001 + +绑定法源:LAW-COMPANY-001;LAW-CIVIL-001 + +## 法律问题 + +合同签署前,如何核验公司主体资格、签约代表权限、盖章授权和代理风险。 + +## 适用场景 + +1. 与公司、分支机构、个体工商户或其他组织签订采购、服务、技术开发合同。 +2. 合同由业务人员、项目负责人、代理人或分支机构签署。 +3. 审核合同中的主体信息、统一社会信用代码、注册地址、授权委托书和盖章要求。 + +## 不适用场景 + +1. 境外主体、上市公司重大交易、国有资产交易或强监管主体资质审查。 +2. 需要判断表见代理、越权代表或内部决议效力的具体争议。 + +## 依据范围 + +1. 《中华人民共和国公司法》关于公司主体、法定代表人、公司治理和对外交易的一般规则。 +2. 《中华人民共和国民法典》关于民事主体、代理、合同效力和相对人合理信赖的一般规则。 + +## 审核提示 + +1. 合同应完整填写主体名称、统一社会信用代码、住所、法定代表人或负责人。 +2. 非法定代表人签署时,应要求授权委托书、岗位授权或其他可验证授权材料。 +3. 分支机构、项目部、业务部门签署合同时,应提示主体资格和责任承担风险。 + +## 回答边界 + +本卡仅用于合同签署前的主体与授权核验提示。涉及公司章程限制、内部决议、越权代表、表见代理或重大资产交易,应提示人工复核。 + +## 复核状态 + +待法务确认具体条款号、授权材料清单和特殊主体核验规则。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-DISPUTE-ARBITRATION-LITIGATION-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-DISPUTE-ARBITRATION-LITIGATION-001.md new file mode 100644 index 00000000..10b13b46 --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-DISPUTE-ARBITRATION-LITIGATION-001.md @@ -0,0 +1,40 @@ +# 仲裁与诉讼争议解决条款选择 + +知识卡编号:KC-DISPUTE-ARBITRATION-LITIGATION-001 + +绑定法源:LAW-ARBITRATION-001;LAW-CIVIL-PROCEDURE-001;LAW-CIVIL-001 + +## 法律问题 + +合同争议解决条款中,如何选择仲裁或诉讼,并确保争议机构、管辖地点和适用范围清楚。 + +## 适用场景 + +1. 采购、服务、保密、技术开发、软件服务合同设置争议解决条款。 +2. 合同中同时出现仲裁和法院管辖,或机构名称、地点表述不清。 +3. 审核争议解决、送达地址、管辖法院、仲裁委员会和适用法律条款。 + +## 不适用场景 + +1. 涉外合同、海事海商、劳动争议、消费者争议或专属管辖事项。 +2. 已进入诉讼或仲裁阶段的管辖异议和仲裁协议效力争议。 + +## 依据范围 + +1. 《中华人民共和国仲裁法》关于仲裁协议、仲裁机构和仲裁事项的一般规则。 +2. 《中华人民共和国民事诉讼法》关于民事管辖、协议管辖和送达的一般规则。 +3. 《中华人民共和国民法典》关于合同争议解决和合同解释的一般规则。 + +## 审核提示 + +1. 仲裁条款应明确唯一仲裁机构,避免机构名称错误或同时约定多个互相冲突的机构。 +2. 诉讼条款应关注协议管辖是否与争议有实际联系,并避免违反专属管辖规则。 +3. 合同应同时设置有效通知地址和电子送达规则,方便后续维权。 + +## 回答边界 + +本卡不能判断具体仲裁协议或管辖条款最终效力。涉及涉外、专属管辖、劳动争议、消费者争议或已发生争议,应提示律师复核。 + +## 复核状态 + +待法务确认具体条款号、常用仲裁机构名称校验规则和争议解决条款模板。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-E-SIGN-EVIDENCE-RETENTION-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-E-SIGN-EVIDENCE-RETENTION-001.md new file mode 100644 index 00000000..f582b05c --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/KC-E-SIGN-EVIDENCE-RETENTION-001.md @@ -0,0 +1,40 @@ +# 电子签名与电子合同证据留存 + +知识卡编号:KC-E-SIGN-EVIDENCE-RETENTION-001 + +绑定法源:LAW-E-SIGN-001;LAW-CIVIL-001;LAW-CIVIL-PROCEDURE-001 + +## 法律问题 + +电子合同签署后,如何保存签署证据、身份认证记录、时间戳、签署文件和后续履约记录。 + +## 适用场景 + +1. 使用电子签名平台、企业系统、邮件或在线订单完成合同签署。 +2. 合同审核中需要判断电子签署、电子通知、电子证据保存条款是否完整。 +3. 合同生成模板需要默认加入电子签署和证据留存条款。 + +## 不适用场景 + +1. 法律规定不得适用电子文书或要求特殊纸质形式的场景。 +2. 需要对具体电子签名服务机构、证书链、时间戳或取证流程做技术鉴定。 + +## 依据范围 + +1. 《中华人民共和国电子签名法》关于数据电文、可靠电子签名和电子签名效力的一般规则。 +2. 《中华人民共和国民法典》关于合同形式、数据电文和合同成立的一般规则。 +3. 《中华人民共和国民事诉讼法》关于电子数据证据的一般规则。 + +## 审核提示 + +1. 电子签署条款应明确签署平台、签署身份、签署文件版本、签署完成时间和证据保管方。 +2. 合同应约定电子通知、系统记录、邮件记录、订单记录等可作为履约和争议证据。 +3. 对关键交易,应保留签署证书、哈希值、时间戳、登录日志、发送记录和对方确认记录。 + +## 回答边界 + +本卡不能判断某一份电子签名是否达到可靠电子签名标准。涉及证据能力、证明力或技术鉴定,应提示法务和电子签名服务机构共同复核。 + +## 复核状态 + +待法务确认具体条款号、电子数据证据规则和技术留痕清单。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/data-privacy/KC-DATA-PI-PROCESSING-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/data-privacy/KC-DATA-PI-PROCESSING-001.md new file mode 100644 index 00000000..6064392a --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/data-privacy/KC-DATA-PI-PROCESSING-001.md @@ -0,0 +1,40 @@ +# 个人信息处理与委托处理条款边界 + +知识卡编号:KC-DATA-PI-PROCESSING-001 + +绑定法源:LAW-DATA-001;LAW-DATA-002;LAW-DATA-003 + +## 法律问题 + +合同涉及客户、员工、联系人、用户账号、日志、设备信息等个人信息时,如何约定处理目的、处理范围、授权、委托处理和安全义务。 + +## 适用场景 + +1. 软件与软件即服务合同、数据处理协议、外包服务协议、平台服务协议。 +2. 服务商代客户处理个人信息,或双方共享、传输、存储个人信息。 +3. 审核合同中的隐私、数据安全、账号管理、日志留存、数据返还和删除条款。 + +## 不适用场景 + +1. 出境个人信息处理、重要数据、关键信息基础设施、行业监管数据等高风险场景。 +2. 需要做个人信息保护影响评估、数据安全评估或跨境合规申报的事项。 + +## 依据范围 + +1. 《中华人民共和国个人信息保护法》关于个人信息处理原则、合法基础、告知同意、委托处理、安全保障和个人权利的规则。 +2. 《中华人民共和国数据安全法》关于数据处理活动安全管理和风险防控的规则。 +3. 《中华人民共和国网络安全法》关于网络运营者安全保护和个人信息保护的一般规则。 + +## 审核提示 + +1. 合同应明确个人信息处理目的、范围、方式、保存期限、双方角色和安全责任。 +2. 委托处理场景应约定受托方不得超目的处理,不得擅自转委托,并应按约定返还、删除或协助处理个人信息。 +3. 涉及敏感个人信息、未成年人信息、跨境传输或大规模数据处理时,应触发高风险人工复核。 + +## 回答边界 + +本卡只用于合同条款层面的初步识别。凡涉及数据出境、安全评估、个人信息保护影响评估、监管备案或行业特殊规则,必须提示专业合规复核。 + +## 复核状态 + +待法务确认具体条款号、委托处理条款模板和高风险数据处理边界。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/intellectual-property/KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/intellectual-property/KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md new file mode 100644 index 00000000..54d67790 --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/intellectual-property/KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001.md @@ -0,0 +1,40 @@ +# 软件成果著作权归属与许可边界 + +知识卡编号:KC-IP-SOFTWARE-COPYRIGHT-OWNERSHIP-001 + +绑定法源:LAW-IP-001;LAW-CIVIL-001;LAW-TECH-001 + +## 法律问题 + +软件开发、技术服务、系统实施或定制开发合同中,如何约定软件成果、源代码、文档、接口、已有知识产权和新成果的归属与使用许可。 + +## 适用场景 + +1. 技术开发合同、软件开发合同、软件实施合同、软件与软件即服务合同。 +2. 合同涉及源代码交付、二次开发、接口文档、算法模型、数据库结构、技术文档。 +3. 审核知识产权归属、授权范围、使用期限、地域、转授权和侵权担保条款。 + +## 不适用场景 + +1. 专利申请权归属、商标授权、开源软件合规或商业秘密侵权的复杂专项判断。 +2. 涉及职务作品、委托作品、合作开发成果争议的个案。 + +## 依据范围 + +1. 《中华人民共和国著作权法》关于作品权利、许可使用、转让和侵权责任的一般规则。 +2. 《中华人民共和国民法典》关于技术合同、成果归属、许可使用和违约责任的规则。 +3. 最高人民法院关于技术合同纠纷的司法解释中与技术成果和合同纠纷处理相关的规则。 + +## 审核提示 + +1. 合同应区分甲方既有资料、乙方既有技术、第三方组件、开源组件和本项目新增成果。 +2. 若约定成果归客户所有,应明确源代码、文档、部署脚本、测试材料和知识产权登记协助义务。 +3. 若仅授权使用,应明确授权范围、期限、地域、用户数量、部署环境、转授权和终止后的使用边界。 + +## 回答边界 + +本卡不能直接判断某项软件成果的权属。涉及开源许可证、专利、商业秘密、职务作品或共同开发成果争议时,应提示知识产权专业复核。 + +## 复核状态 + +待法务确认具体条款号、技术合同司法解释适用范围和开源软件专项边界。 diff --git a/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/labor-employment/KC-LABOR-CONTRACT-TERM-PROBATION-001.md b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/labor-employment/KC-LABOR-CONTRACT-TERM-PROBATION-001.md new file mode 100644 index 00000000..3ca358cd --- /dev/null +++ b/project-docs/phase13-legal-knowledge-template-library/knowledge-cards/labor-employment/KC-LABOR-CONTRACT-TERM-PROBATION-001.md @@ -0,0 +1,39 @@ +# 劳动合同订立、期限与试用期边界 + +知识卡编号:KC-LABOR-CONTRACT-TERM-PROBATION-001 + +绑定法源:LAW-LABOR-001;LAW-LABOR-002 + +## 法律问题 + +企业与员工签署劳动合同时,如何约定合同期限、岗位地点、试用期、工资和社会保险,避免把劳动关系误做成普通民商事合同。 + +## 适用场景 + +1. 企业与个人建立劳动关系。 +2. 劳动合同模板、试用期条款、岗位地点条款和工资条款审核。 +3. 识别劳动合同与劳务合同、承揽合同、顾问合同之间的边界风险。 + +## 不适用场景 + +1. 退休返聘、灵活用工、外包用工、平台用工等复杂劳动关系认定。 +2. 已发生劳动争议、工伤、竞业限制或经济补偿争议的案件。 + +## 依据范围 + +1. 《中华人民共和国劳动合同法》关于劳动合同订立、合同期限、试用期、劳动报酬、社会保险和用人单位义务的规则。 +2. 《中华人民共和国劳动法》关于劳动者权益保护、工作时间、工资和劳动保护的一般规则。 + +## 审核提示 + +1. 劳动合同必须关注签署时间、合同期限、工作内容、工作地点、劳动报酬、社会保险和劳动保护。 +2. 试用期约定应与劳动合同期限匹配,不能重复约定或违法延长。 +3. 若合同实质上由企业管理个人劳动过程、支付劳动报酬并形成从属性,应提示劳动关系风险。 + +## 回答边界 + +本卡不能直接认定是否存在劳动关系,也不能计算解除赔偿。涉及劳动争议、竞业限制、社保补缴、经济补偿或工伤,应提示由人力资源负责人和法务共同复核。 + +## 复核状态 + +待法务确认具体条款号、试用期规则和劳动关系边界。 diff --git a/project-docs/阶段13-法律知识库与合同模板库建设闭环方案-2026-05-01.md b/project-docs/阶段13-法律知识库与合同模板库建设闭环方案-2026-05-01.md index 288e81af..f4ab73e5 100644 --- a/project-docs/阶段13-法律知识库与合同模板库建设闭环方案-2026-05-01.md +++ b/project-docs/阶段13-法律知识库与合同模板库建设闭环方案-2026-05-01.md @@ -385,15 +385,18 @@ project-docs/phase13-legal-knowledge-template-library/ ## 八、下一步立即执行 -下一步最合适进入阶段 13.0 和 13.1: +阶段 13 已完成第一批和第二批工程化交付,后续继续沿本方案推进。 -1. 创建 `project-docs/phase13-legal-knowledge-template-library/` 目录。 -2. 创建第一批清单 CSV。 -3. 创建法源采集字段字典和资料状态规则。 -4. 建立第一批官方法源清单。 -5. 实现 `scripts/run-legal-knowledge-library-gate.ps1` 的第一版,只做结构、字段、法源白名单和敏感信息门禁。 -6. 第一版门禁通过后,再开始填充法源、知识卡、规则、条款和模板正文。 +下一步最合适进入阶段 `13.3 合同审核规则库` 和 `13.4 标准条款库`: + +1. 从 10 张知识卡中抽取高频审核规则。 +2. 优先建立违约责任、格式条款、解除通知、主体授权、个人信息处理和争议解决 6 类规则。 +3. 为每条规则绑定知识卡编号、法源编号、严重等级、触发条件和修改建议。 +4. 生成对应标准条款初稿,仍保持 `LEGAL_REVIEW`。 +5. 用 `scripts/import-phase13-library.ps1 -Mode Validate` 和阶段 13 门禁持续校验资料包。 阶段 13 当前状态:`IN_PROGRESS`。 当前第一批执行结果:`13.0` 和 `13.1` 已完成工程化底座,资料包、清单字段结构、第一批 `20` 条官方法源采集任务和 `scripts/run-legal-knowledge-library-gate.ps1` 已落地。门禁状态为 `PASS_WITH_LEGAL_REVIEW_REQUIRED`,所有法源在法务复核前不得作为生产确定性依据。 + +当前第二批执行结果:`13.2` 第一批中文法律知识卡已建立,共 `10` 张;`13.7` 第一版一键导入脚本 `scripts/import-phase13-library.ps1` 已落地。导入脚本支持 `Validate`、`Review`、`Production` 三种模式,默认不改系统;生产导入只允许已复核且生产就绪资料。门禁状态仍为 `PASS_WITH_LEGAL_REVIEW_REQUIRED`,因为法源和知识卡均需法务复核后才能成为生产确定性依据。 diff --git a/project-docs/阶段13-法律知识库与合同模板库建设闭环第二批执行记录-2026-05-01.md b/project-docs/阶段13-法律知识库与合同模板库建设闭环第二批执行记录-2026-05-01.md new file mode 100644 index 00000000..ea68226b --- /dev/null +++ b/project-docs/阶段13-法律知识库与合同模板库建设闭环第二批执行记录-2026-05-01.md @@ -0,0 +1,106 @@ +# AI合同平台 阶段 13 法律知识库与合同模板库建设闭环第二批执行记录(2026-05-01) + +## 一、阶段结论 + +本批次进入 `13.2 法律知识卡建设` 和 `13.7 入库与自动化门禁` 的组合开发,当前状态为 `PASS_WITH_LEGAL_REVIEW_REQUIRED`。 + +本批次完成了第一批中文法律知识卡和一键导入脚本,但所有知识卡仍保持 `LEGAL_REVIEW`。在法务确认具体条款号、有效状态和适用边界前,不得作为生产确定性依据。 + +## 二、本批次交付 + +新增资料: + +1. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/README.md` +2. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/civil-code/*.md` +3. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/labor-employment/*.md` +4. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/data-privacy/*.md` +5. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/intellectual-property/*.md` +6. `project-docs/phase13-legal-knowledge-template-library/knowledge-cards/company-commercial/*.md` +7. `scripts/import-phase13-library.ps1` + +更新资料: + +1. `inventories/legal-knowledge-card-inventory.csv` +2. `scripts/run-legal-knowledge-library-gate.ps1` + +## 三、第一批知识卡范围 + +本批次新增 10 张中文法律知识卡: + +1. 合同形式与电子数据形式。 +2. 格式条款提示说明与效力边界。 +3. 违约责任与违约金调整边界。 +4. 合同解除条件与通知留痕。 +5. 劳动合同订立、期限与试用期边界。 +6. 个人信息处理与委托处理条款边界。 +7. 软件成果著作权归属与许可边界。 +8. 签约主体资格与授权代表核验。 +9. 仲裁与诉讼争议解决条款选择。 +10. 电子签名与电子合同证据留存。 + +这些知识卡均为中文资料,且仅绑定中国大陆官方法源清单中的编号。 + +## 四、一键导入脚本 + +新增脚本: + +```powershell +powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts\import-phase13-library.ps1 -Mode Validate +``` + +脚本模式: + +| 模式 | 作用 | 是否改系统 | +|---|---|---| +| Validate | 只校验资料包、清单、法源编号和文件路径 | 否 | +| Review | 导入到“阶段13法律知识库(待法务复核)” | 是 | +| Production | 只导入 `APPROVED` 或 `PUBLISHED` 且 `production_ready=true` 的资料 | 是 | + +非 `Validate` 模式需要管理员登录。密码不得写入脚本或资料包,应通过命令参数或环境变量 `AICP_ADMIN_PASSWORD` 提供。 + +## 五、自动化门禁结果 + +导入脚本离线校验: + +```text +PHASE13_IMPORT_PASS D:\ai-contract-platform\project-docs\qa-artifacts\phase13-import\2026-05-01T21-24-01-632 +``` + +阶段 13 资料门禁: + +```text +PHASE13_LEGAL_KNOWLEDGE_LIBRARY_GATE_PASS_WITH_LEGAL_REVIEW_REQUIRED D:\ai-contract-platform\project-docs\qa-artifacts\phase13-legal-knowledge-library-gate\2026-05-01T21-26-35-765 +``` + +门禁统计: + +| 指标 | 结果 | +|---|---:| +| 法源 | 20 | +| 法律知识卡 | 10 | +| 清单文件 | 9 | +| 知识卡字段与路径校验 | 通过 | +| 知识卡法源可追溯 | 通过 | +| 未复核知识卡禁止生产就绪 | 通过 | +| 仍需法务复核的法源 | 20 | +| 仍需法务复核的知识卡 | 10 | + +## 六、当前保留项 + +| 保留项 | 状态 | 说明 | +|---|---|---| +| 法源详情页确认 | LEGAL_REVIEW | 当前仍需法务确认官方详情页、施行日期和有效状态 | +| 知识卡条款号确认 | LEGAL_REVIEW | 当前只记录依据范围和适用边界,具体条款号需法务确认 | +| 生产知识库导入 | BLOCKED_BY_REVIEW | 未复核资料不得导入生产确定性知识库 | +| 企业内部模板 | WAITING_FOR_BUSINESS_INPUT | 用户当前暂无内部资料,后续找到后再补入企业模板层 | + +## 七、下一步 + +下一批建议继续阶段 `13.3 合同审核规则库` 和 `13.4 标准条款库`: + +1. 从 10 张知识卡中抽取高频审核规则。 +2. 先做违约责任、格式条款、解除通知、主体授权、个人信息处理和争议解决 6 类规则。 +3. 为每条规则绑定知识卡编号、法源编号、严重等级、触发条件和修改建议。 +4. 同步生成标准条款初稿,仍保持 `LEGAL_REVIEW`。 + +阶段 13 第二批当前状态:`PASS_WITH_LEGAL_REVIEW_REQUIRED`。 diff --git a/scripts/import-phase13-library.ps1 b/scripts/import-phase13-library.ps1 new file mode 100644 index 00000000..a69eedfb --- /dev/null +++ b/scripts/import-phase13-library.ps1 @@ -0,0 +1,657 @@ +param( + [ValidateSet("Validate", "Review", "Production")] + [string]$Mode = "Validate", + [string]$ApiBaseUrl = "http://127.0.0.1:8000/api/v1", + [string]$LibraryRoot = "", + [string]$ArtifactRoot = "", + [string]$AdminEmail = "admin@example.com", + [string]$AdminPassword = "", + [string]$KnowledgeBaseName = "", + [switch]$ForceReupload, + [switch]$SkipTemplates, + [switch]$SkipReviewRules +) + +$ErrorActionPreference = "Stop" + +Add-Type -AssemblyName System.Net.Http + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path +$timestamp = Get-Date -Format "yyyy-MM-ddTHH-mm-ss-fff" + +if ([string]::IsNullOrWhiteSpace($LibraryRoot)) { + $LibraryRoot = Join-Path $repoRoot "project-docs\phase13-legal-knowledge-template-library" +} +if (-not [System.IO.Path]::IsPathRooted($LibraryRoot)) { + $LibraryRoot = Join-Path $repoRoot $LibraryRoot +} + +if ([string]::IsNullOrWhiteSpace($ArtifactRoot)) { + $ArtifactRoot = Join-Path $repoRoot "project-docs\qa-artifacts\phase13-import" +} +if (-not [System.IO.Path]::IsPathRooted($ArtifactRoot)) { + $ArtifactRoot = Join-Path $repoRoot $ArtifactRoot +} + +$artifactDir = Join-Path $ArtifactRoot $timestamp +New-Item -ItemType Directory -Force -Path $artifactDir | Out-Null + +$summaryJson = Join-Path $artifactDir "phase13-import-summary.json" +$summaryMd = Join-Path $artifactDir "phase13-import-summary.md" + +$ApiBaseUrl = $ApiBaseUrl.TrimEnd("/") + +if ([string]::IsNullOrWhiteSpace($KnowledgeBaseName)) { + if ($Mode -eq "Production") { + $KnowledgeBaseName = "AI合同平台法律知识库(生产)" + } else { + $KnowledgeBaseName = "阶段13法律知识库(待法务复核)" + } +} + +$checks = New-Object System.Collections.Generic.List[object] +$assetReport = New-Object System.Collections.Generic.List[object] +$importReport = New-Object System.Collections.Generic.List[object] + +function Add-Check { + param( + [string]$Key, + [string]$Label, + [ValidateSet("pass", "fail", "warn", "skip", "blocked")] + [string]$Status, + [string]$Detail, + [bool]$Required = $true, + [hashtable]$Meta = @{} + ) + + $checks.Add([ordered]@{ + key = $Key + label = $Label + status = $Status + required = $Required + detail = $Detail + meta = $Meta + }) | Out-Null +} + +function Save-Json { + param([string]$Path, [object]$Value) + $Value | ConvertTo-Json -Depth 30 | Set-Content -Encoding UTF8 -Path $Path +} + +function Import-CsvRows { + param([string]$Path) + if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { + return @() + } + return @(Import-Csv -LiteralPath $Path) +} + +function Test-RequiredFlag { + param([string]$Value) + if ([string]::IsNullOrWhiteSpace($Value)) { + return $false + } + return @("true", "yes", "1", "required") -contains $Value.ToLowerInvariant() +} + +function Test-PendingReviewer { + param([string]$Value) + if ([string]::IsNullOrWhiteSpace($Value)) { + return $true + } + return @("pending", "待法务复核", "待业务复核", "待复核") -contains $Value.Trim() +} + +function Test-ProductionReadyAsset { + param([object]$Row) + $statusAllowed = @("APPROVED", "PUBLISHED") -contains $Row.status + $ready = Test-RequiredFlag -Value $Row.production_ready + $reviewed = -not (Test-PendingReviewer -Value $Row.legal_reviewer) + return ($statusAllowed -and $ready -and $reviewed) +} + +function Resolve-LibraryPath { + param([string]$RelativePath) + return Join-Path $LibraryRoot ($RelativePath -replace "/", "\") +} + +function Get-ResponseData { + param([object]$Response) + if ($null -eq $Response) { + return $null + } + if ($Response.PSObject.Properties.Name -contains "data") { + return $Response.data + } + return $Response +} + +function Invoke-ApiJson { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + [object]$Body = $null + ) + + $args = @{ + Method = $Method + Uri = $Url + Headers = $Headers + ErrorAction = "Stop" + } + if ($null -ne $Body) { + $args["ContentType"] = "application/json; charset=utf-8" + $args["Body"] = ($Body | ConvertTo-Json -Depth 20) + } + return Invoke-RestMethod @args +} + +function Invoke-FormRequest { + param( + [string]$Method, + [string]$Url, + [hashtable]$Headers = @{}, + [hashtable]$Fields = @{}, + [string]$FileField = "", + [string]$FileName = "", + [byte[]]$FileContent = $null, + [string]$FileContentType = "text/markdown; charset=utf-8" + ) + + $client = [System.Net.Http.HttpClient]::new() + try { + foreach ($headerName in $Headers.Keys) { + $client.DefaultRequestHeaders.Remove($headerName) | Out-Null + $client.DefaultRequestHeaders.Add($headerName, [string]$Headers[$headerName]) + } + + $form = [System.Net.Http.MultipartFormDataContent]::new() + try { + foreach ($fieldName in $Fields.Keys) { + $value = [string]$Fields[$fieldName] + $stringContent = [System.Net.Http.StringContent]::new($value, [System.Text.Encoding]::UTF8) + $form.Add($stringContent, $fieldName) + } + + if ($FileContent -ne $null -and -not [string]::IsNullOrWhiteSpace($FileField)) { + $byteContent = [System.Net.Http.ByteArrayContent]::new($FileContent) + $byteContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($FileContentType) + $form.Add($byteContent, $FileField, $FileName) + } + + $request = [System.Net.Http.HttpRequestMessage]::new([System.Net.Http.HttpMethod]::new($Method), $Url) + $request.Content = $form + $response = $client.SendAsync($request).GetAwaiter().GetResult() + $body = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult() + if (-not $response.IsSuccessStatusCode) { + throw "API 请求失败:$Method $Url,状态码=$([int]$response.StatusCode),响应=$body" + } + if ([string]::IsNullOrWhiteSpace($body)) { + return $null + } + return $body | ConvertFrom-Json + } finally { + if ($null -ne $form) { + $form.Dispose() + } + } + } finally { + $client.Dispose() + } +} + +function Get-PagedApiItems { + param( + [string]$Url, + [hashtable]$Headers + ) + + $items = New-Object System.Collections.Generic.List[object] + $page = 1 + $pageSize = 100 + while ($true) { + $separator = if ($Url.Contains("?")) { "&" } else { "?" } + $response = Invoke-ApiJson -Method "GET" -Url "$Url${separator}page=$page&page_size=$pageSize" -Headers $Headers + $data = Get-ResponseData -Response $response + if ($null -eq $data -or $null -eq $data.items) { + break + } + foreach ($item in @($data.items)) { + $items.Add($item) | Out-Null + } + if ($items.Count -ge [int]$data.total -or @($data.items).Count -eq 0) { + break + } + $page += 1 + } + return $items.ToArray() +} + +function Get-AuthHeaders { + param([string]$Token) + return @{ Authorization = "Bearer $Token" } +} + +function Get-AccessToken { + if ($Mode -eq "Validate") { + return "" + } + + $password = $AdminPassword + if ([string]::IsNullOrWhiteSpace($password)) { + $password = $env:AICP_ADMIN_PASSWORD + } + if ([string]::IsNullOrWhiteSpace($password)) { + throw "非 Validate 模式需要通过 -AdminPassword 或环境变量 AICP_ADMIN_PASSWORD 提供管理员密码。" + } + + $response = Invoke-ApiJson -Method "POST" -Url "$ApiBaseUrl/auth/login" -Body @{ + account = $AdminEmail + password = $password + } + $data = Get-ResponseData -Response $response + if ($null -eq $data -or [string]::IsNullOrWhiteSpace($data.access_token)) { + throw "登录成功响应中缺少 access_token。" + } + return [string]$data.access_token +} + +function Ensure-KnowledgeBase { + param([hashtable]$Headers) + + $items = Get-PagedApiItems -Url "$ApiBaseUrl/knowledge-bases" -Headers $Headers + $existing = @($items | Where-Object { $_.name -eq $KnowledgeBaseName }) | Select-Object -First 1 + if ($existing) { + return $existing + } + + $response = Invoke-FormRequest -Method "POST" -Url "$ApiBaseUrl/knowledge-bases" -Headers $Headers -Fields @{ + name = $KnowledgeBaseName + description = "阶段 13 法律知识卡导入知识库;资料未经法务复核前仅用于内部复核和试点验证。" + } + return Get-ResponseData -Response $response +} + +function Get-KnowledgeBaseDocuments { + param([hashtable]$Headers, [string]$KnowledgeBaseId) + return Get-PagedApiItems -Url "$ApiBaseUrl/knowledge-bases/$KnowledgeBaseId/documents" -Headers $Headers +} + +function Import-KnowledgeCard { + param( + [hashtable]$Headers, + [string]$KnowledgeBaseId, + [object]$Card, + [string]$AbsolutePath, + [object[]]$ExistingDocuments + ) + + $fileName = "$($Card.knowledge_card_id).md" + $existing = @($ExistingDocuments | Where-Object { $_.file_name -eq $fileName }) | Select-Object -First 1 + $bytes = [System.IO.File]::ReadAllBytes($AbsolutePath) + $note = "阶段13知识卡导入;编号=$($Card.knowledge_card_id);状态=$($Card.status);法源=$($Card.source_ids)。" + + if ($existing -and -not $ForceReupload) { + return [ordered]@{ + asset_type = "knowledge_card" + asset_id = $Card.knowledge_card_id + action = "skip_existing" + status = "skipped" + target_id = $existing.id + detail = "同名知识卡文档已存在,未重复上传。" + } + } + + if ($existing -and $ForceReupload) { + $response = Invoke-FormRequest -Method "POST" -Url "$ApiBaseUrl/knowledge-bases/$KnowledgeBaseId/documents/$($existing.id)/retry" -Headers $Headers -Fields @{ + note = $note + } -FileField "file" -FileName $fileName -FileContent $bytes + $data = Get-ResponseData -Response $response + return [ordered]@{ + asset_type = "knowledge_card" + asset_id = $Card.knowledge_card_id + action = "retry_existing" + status = $data.status + target_id = $data.id + detail = $data.status_detail + } + } + + $response = Invoke-FormRequest -Method "POST" -Url "$ApiBaseUrl/knowledge-bases/$KnowledgeBaseId/documents" -Headers $Headers -Fields @{ + note = $note + } -FileField "file" -FileName $fileName -FileContent $bytes + $data = Get-ResponseData -Response $response + return [ordered]@{ + asset_type = "knowledge_card" + asset_id = $Card.knowledge_card_id + action = "upload" + status = $data.status + target_id = $data.id + detail = $data.status_detail + } +} + +function Get-TemplateVariablesJson { + param([string]$VariableSchemaPath) + if ([string]::IsNullOrWhiteSpace($VariableSchemaPath)) { + return $null + } + $absolutePath = Resolve-LibraryPath -RelativePath $VariableSchemaPath + if (-not (Test-Path -LiteralPath $absolutePath -PathType Leaf)) { + return $null + } + return Get-Content -LiteralPath $absolutePath -Raw -Encoding UTF8 +} + +function Import-TemplateAsset { + param([hashtable]$Headers, [object]$Template, [object[]]$ExistingTemplates) + $templatePath = Resolve-LibraryPath -RelativePath $Template.template_path + $content = Get-Content -LiteralPath $templatePath -Raw -Encoding UTF8 + $variablesJson = Get-TemplateVariablesJson -VariableSchemaPath $Template.variable_schema_path + $fields = @{ + name = $Template.template_name + contract_type = $Template.contract_type + description = $Template.notes + content = $content + enabled = "true" + } + if (-not [string]::IsNullOrWhiteSpace($variablesJson)) { + $fields["variables_json"] = $variablesJson + } + + $existing = @($ExistingTemplates | Where-Object { $_.name -eq $Template.template_name }) | Select-Object -First 1 + if ($existing) { + $response = Invoke-FormRequest -Method "PUT" -Url "$ApiBaseUrl/templates/$($existing.id)" -Headers $Headers -Fields $fields + $data = Get-ResponseData -Response $response + return [ordered]@{ asset_type = "template"; asset_id = $Template.template_id; action = "update"; status = "upserted"; target_id = $data.id; detail = "模板已更新。" } + } + + $response = Invoke-FormRequest -Method "POST" -Url "$ApiBaseUrl/templates" -Headers $Headers -Fields $fields + $created = Get-ResponseData -Response $response + return [ordered]@{ asset_type = "template"; asset_id = $Template.template_id; action = "create"; status = "created"; target_id = $created.id; detail = "模板已创建。" } +} + +function Import-ReviewRuleAsset { + param([hashtable]$Headers, [object]$Rule, [object[]]$ExistingRules) + $fields = @{ + name = $Rule.risk_name + keyword = $Rule.trigger_condition + contract_type = "all" + risk_level = $Rule.severity.ToLowerInvariant() + description = $Rule.review_output_template + suggestion = $Rule.modification_suggestion_path + legal_basis = $Rule.source_ids + is_active = "true" + } + $existing = @($ExistingRules | Where-Object { $_.name -eq $Rule.risk_name -or $_.keyword -eq $Rule.trigger_condition }) | Select-Object -First 1 + if ($existing) { + $response = Invoke-FormRequest -Method "PUT" -Url "$ApiBaseUrl/review-rules/$($existing.id)" -Headers $Headers -Fields $fields + $data = Get-ResponseData -Response $response + return [ordered]@{ asset_type = "review_rule"; asset_id = $Rule.rule_id; action = "update"; status = "upserted"; target_id = $data.id; detail = "审核规则已更新。" } + } + $response = Invoke-FormRequest -Method "POST" -Url "$ApiBaseUrl/review-rules" -Headers $Headers -Fields $fields + $created = Get-ResponseData -Response $response + return [ordered]@{ asset_type = "review_rule"; asset_id = $Rule.rule_id; action = "create"; status = "created"; target_id = $created.id; detail = "审核规则已创建。" } +} + +if (-not (Test-Path "$HOME\.Codex\skills\gstack\bin")) { + Add-Check -Key "gstack" -Label "gstack 前置检查" -Status "fail" -Detail "gstack 缺失" +} else { + Add-Check -Key "gstack" -Label "gstack 前置检查" -Status "pass" -Detail "GSTACK_OK" +} + +if (Test-Path -LiteralPath $LibraryRoot -PathType Container) { + Add-Check -Key "library_root" -Label "阶段 13 资料包根目录" -Status "pass" -Detail "资料包根目录存在" -Meta @{ root = $LibraryRoot } +} else { + Add-Check -Key "library_root" -Label "阶段 13 资料包根目录" -Status "fail" -Detail "资料包根目录缺失" -Meta @{ root = $LibraryRoot } +} + +$legalSourceInventoryPath = Join-Path $LibraryRoot "inventories\legal-source-inventory.csv" +$knowledgeCardInventoryPath = Join-Path $LibraryRoot "inventories\legal-knowledge-card-inventory.csv" +$templateInventoryPath = Join-Path $LibraryRoot "inventories\contract-template-inventory.csv" +$reviewRuleInventoryPath = Join-Path $LibraryRoot "inventories\review-risk-rule-inventory.csv" + +$sourceRows = Import-CsvRows -Path $legalSourceInventoryPath +$sourceIdSet = @{} +foreach ($source in $sourceRows) { + if (-not [string]::IsNullOrWhiteSpace($source.source_id)) { + $sourceIdSet[$source.source_id] = $true + } +} + +$knowledgeCards = Import-CsvRows -Path $knowledgeCardInventoryPath +$templates = Import-CsvRows -Path $templateInventoryPath +$reviewRules = Import-CsvRows -Path $reviewRuleInventoryPath + +if ($knowledgeCards.Count -gt 0) { + Add-Check -Key "knowledge_card_inventory" -Label "法律知识卡清单" -Status "pass" -Detail "知识卡数量=$($knowledgeCards.Count)" +} else { + Add-Check -Key "knowledge_card_inventory" -Label "法律知识卡清单" -Status "warn" -Required $false -Detail "知识卡清单为空" +} + +$validationFailures = 0 +$eligibleKnowledgeCards = New-Object System.Collections.Generic.List[object] +foreach ($card in $knowledgeCards) { + $absolutePath = Resolve-LibraryPath -RelativePath $card.summary_path + $missing = New-Object System.Collections.Generic.List[string] + foreach ($field in @("knowledge_card_id", "title", "source_ids", "summary_path", "status", "owner", "legal_reviewer")) { + if ([string]::IsNullOrWhiteSpace($card.$field)) { + $missing.Add($field) | Out-Null + } + } + + $unknownSources = @() + foreach ($sourceId in @($card.source_ids -split ";" | ForEach-Object { $_.Trim() } | Where-Object { $_ })) { + if (-not $sourceIdSet.ContainsKey($sourceId)) { + $unknownSources += $sourceId + } + } + if ($unknownSources.Count -gt 0) { + $missing.Add("unknown_source_ids=$($unknownSources -join ';')") | Out-Null + } + if (-not (Test-Path -LiteralPath $absolutePath -PathType Leaf)) { + $missing.Add("summary_path_missing") | Out-Null + } + + $productionReady = Test-ProductionReadyAsset -Row $card + $reviewEligible = @("LEGAL_REVIEW", "BUSINESS_REVIEW", "APPROVED", "PUBLISHED") -contains $card.status + $eligible = if ($Mode -eq "Production") { $productionReady } elseif ($Mode -eq "Review") { $reviewEligible } else { $reviewEligible -or $productionReady } + + if ($missing.Count -gt 0) { + $validationFailures += 1 + } elseif ($eligible -and ($Mode -ne "Production" -or $productionReady)) { + $eligibleKnowledgeCards.Add($card) | Out-Null + } + + $assetReport.Add([ordered]@{ + asset_type = "knowledge_card" + asset_id = $card.knowledge_card_id + title = $card.title + status = $card.status + production_ready = $card.production_ready + legal_reviewer = $card.legal_reviewer + eligible_for_mode = $eligible + validation_status = if ($missing.Count -eq 0) { "pass" } else { "fail" } + validation_detail = if ($missing.Count -eq 0) { "字段、法源和文件路径通过" } else { "问题:" + ($missing -join ";") } + summary_path = $card.summary_path + }) | Out-Null +} + +if ($validationFailures -eq 0) { + Add-Check -Key "knowledge_card_validation" -Label "知识卡字段与路径校验" -Status "pass" -Detail "知识卡字段、法源编号和摘要文件路径通过" +} else { + Add-Check -Key "knowledge_card_validation" -Label "知识卡字段与路径校验" -Status "fail" -Detail "存在 $validationFailures 张知识卡未通过校验" +} + +$token = "" +$headers = @{} +$targetKnowledgeBase = $null +if ($Mode -ne "Validate" -and $validationFailures -eq 0) { + $token = Get-AccessToken + $headers = Get-AuthHeaders -Token $token + $targetKnowledgeBase = Ensure-KnowledgeBase -Headers $headers + Add-Check -Key "api_login" -Label "管理员登录与知识库确认" -Status "pass" -Detail "目标知识库:$($targetKnowledgeBase.name)" -Meta @{ knowledge_base_id = $targetKnowledgeBase.id } +} elseif ($Mode -eq "Validate") { + Add-Check -Key "api_login" -Label "管理员登录与知识库确认" -Status "skip" -Required $false -Detail "Validate 模式不调用系统 API" +} + +if ($Mode -ne "Validate" -and $validationFailures -eq 0) { + $existingDocs = Get-KnowledgeBaseDocuments -Headers $headers -KnowledgeBaseId $targetKnowledgeBase.id + foreach ($card in $eligibleKnowledgeCards) { + $absolutePath = Resolve-LibraryPath -RelativePath $card.summary_path + try { + $result = Import-KnowledgeCard -Headers $headers -KnowledgeBaseId $targetKnowledgeBase.id -Card $card -AbsolutePath $absolutePath -ExistingDocuments $existingDocs + $importReport.Add($result) | Out-Null + } catch { + $importReport.Add([ordered]@{ + asset_type = "knowledge_card" + asset_id = $card.knowledge_card_id + action = "upload" + status = "failed" + target_id = "" + detail = $_.Exception.Message + }) | Out-Null + } + } + + if (-not $SkipTemplates -and $templates.Count -gt 0) { + $existingTemplates = Get-PagedApiItems -Url "$ApiBaseUrl/templates" -Headers $headers + foreach ($template in $templates) { + if (-not (Test-ProductionReadyAsset -Row $template)) { + continue + } + try { + $importReport.Add((Import-TemplateAsset -Headers $headers -Template $template -ExistingTemplates $existingTemplates)) | Out-Null + } catch { + $importReport.Add([ordered]@{ asset_type = "template"; asset_id = $template.template_id; action = "upsert"; status = "failed"; target_id = ""; detail = $_.Exception.Message }) | Out-Null + } + } + } + + if (-not $SkipReviewRules -and $reviewRules.Count -gt 0) { + $existingRules = Get-PagedApiItems -Url "$ApiBaseUrl/review-rules" -Headers $headers + foreach ($rule in $reviewRules) { + if (-not (Test-ProductionReadyAsset -Row $rule)) { + continue + } + try { + $importReport.Add((Import-ReviewRuleAsset -Headers $headers -Rule $rule -ExistingRules $existingRules)) | Out-Null + } catch { + $importReport.Add([ordered]@{ asset_type = "review_rule"; asset_id = $rule.rule_id; action = "upsert"; status = "failed"; target_id = ""; detail = $_.Exception.Message }) | Out-Null + } + } + } +} + +$importFailures = @($importReport | Where-Object { $_.status -eq "failed" }).Count +$blockedByReview = @($assetReport | Where-Object { $_.asset_type -eq "knowledge_card" -and -not $_.eligible_for_mode }).Count +$importedOrSkipped = @($importReport | Where-Object { $_.status -ne "failed" }).Count + +if ($Mode -eq "Validate") { + Add-Check -Key "import_execution" -Label "导入执行" -Status "skip" -Required $false -Detail "Validate 模式只完成资料校验" +} elseif ($importFailures -eq 0) { + Add-Check -Key "import_execution" -Label "导入执行" -Status "pass" -Detail "导入或跳过成功数量=$importedOrSkipped" +} else { + Add-Check -Key "import_execution" -Label "导入执行" -Status "fail" -Detail "导入失败数量=$importFailures" +} + +$failedRequired = @($checks | Where-Object { $_.required -and $_.status -eq "fail" }).Count +$warnings = @($checks | Where-Object { $_.status -eq "warn" }).Count + +$overallStatus = if ($failedRequired -gt 0 -or $validationFailures -gt 0 -or $importFailures -gt 0) { + "FAIL" +} elseif ($Mode -eq "Production" -and $blockedByReview -gt 0) { + "PASS_WITH_REVIEW_BLOCKED_ASSETS" +} elseif ($warnings -gt 0) { + "WARN" +} else { + "PASS" +} + +$summary = [ordered]@{ + name = "phase13-library-import" + mode = $Mode + status = $overallStatus + generated_at = (Get-Date).ToUniversalTime().ToString("o") + api_base_url = $ApiBaseUrl + artifact_dir = $artifactDir + library_root = $LibraryRoot + knowledge_base_name = $KnowledgeBaseName + knowledge_base_id = if ($targetKnowledgeBase) { $targetKnowledgeBase.id } else { "" } + checks = $checks.ToArray() + assets = $assetReport.ToArray() + imports = $importReport.ToArray() + totals = [ordered]@{ + legal_sources = $sourceRows.Count + knowledge_cards = $knowledgeCards.Count + eligible_knowledge_cards = $eligibleKnowledgeCards.Count + templates = $templates.Count + review_rules = $reviewRules.Count + validation_failures = $validationFailures + import_failures = $importFailures + blocked_by_review = $blockedByReview + } +} +Save-Json -Path $summaryJson -Value $summary + +$md = New-Object System.Collections.Generic.List[string] +$md.Add("# 阶段 13 资料导入报告") | Out-Null +$md.Add("") | Out-Null +$md.Add("- 模式:$Mode") | Out-Null +$md.Add("- 状态:$overallStatus") | Out-Null +$md.Add("- 生成时间:$($summary.generated_at)") | Out-Null +$md.Add("- 接口地址:$ApiBaseUrl") | Out-Null +$md.Add("- 资料包:$LibraryRoot") | Out-Null +$md.Add("- 目标知识库:$KnowledgeBaseName") | Out-Null +if ($targetKnowledgeBase) { + $md.Add("- 目标知识库编号:$($targetKnowledgeBase.id)") | Out-Null +} +$md.Add("") | Out-Null +$md.Add("## 统计") | Out-Null +$md.Add("") | Out-Null +$md.Add("| 指标 | 数量 |") | Out-Null +$md.Add("|---|---:|") | Out-Null +$md.Add("| 法源 | $($sourceRows.Count) |") | Out-Null +$md.Add("| 知识卡 | $($knowledgeCards.Count) |") | Out-Null +$md.Add("| 当前模式可导入知识卡 | $($eligibleKnowledgeCards.Count) |") | Out-Null +$md.Add("| 合同模板 | $($templates.Count) |") | Out-Null +$md.Add("| 审核规则 | $($reviewRules.Count) |") | Out-Null +$md.Add("| 校验失败 | $validationFailures |") | Out-Null +$md.Add("| 导入失败 | $importFailures |") | Out-Null +$md.Add("| 当前模式阻塞资料 | $blockedByReview |") | Out-Null +$md.Add("") | Out-Null +$md.Add("## 检查项") | Out-Null +$md.Add("") | Out-Null +$md.Add("| 检查项 | 必需 | 状态 | 说明 |") | Out-Null +$md.Add("|---|---:|---|---|") | Out-Null +foreach ($check in $checks) { + $requiredText = if ($check.required) { "是" } else { "否" } + $detail = ([string]$check.detail).Replace("|", "/") + $md.Add("| $($check.label) | $requiredText | $($check.status) | $detail |") | Out-Null +} +$md.Add("") | Out-Null +$md.Add("## 导入结果") | Out-Null +$md.Add("") | Out-Null +if ($importReport.Count -eq 0) { + $md.Add("本次未执行 API 导入。") | Out-Null +} else { + $md.Add("| 类型 | 编号 | 动作 | 状态 | 说明 |") | Out-Null + $md.Add("|---|---|---|---|---|") | Out-Null + foreach ($item in $importReport) { + $detail = ([string]$item.detail).Replace("|", "/") + $md.Add("| $($item.asset_type) | $($item.asset_id) | $($item.action) | $($item.status) | $detail |") | Out-Null + } +} +$md.Add("") | Out-Null +$md.Add("本地产物:") | Out-Null +$md.Add("") | Out-Null +$md.Add('- `phase13-import-summary.json`') | Out-Null +$md.Add('- `phase13-import-summary.md`') | Out-Null +$md | Set-Content -Encoding UTF8 -Path $summaryMd + +Write-Host "PHASE13_IMPORT_$overallStatus $artifactDir" +if ($overallStatus -eq "FAIL") { + throw "阶段 13 资料导入失败。查看:$summaryMd" +} diff --git a/scripts/run-legal-knowledge-library-gate.ps1 b/scripts/run-legal-knowledge-library-gate.ps1 index 2f5e1d9a..d5cb65c9 100644 --- a/scripts/run-legal-knowledge-library-gate.ps1 +++ b/scripts/run-legal-knowledge-library-gate.ps1 @@ -237,6 +237,10 @@ function Test-SecretLeak { if (Test-Path -LiteralPath $scriptPath -PathType Leaf) { $files += Get-Item -LiteralPath $scriptPath } + $importScriptPath = Join-Path $repoRoot "scripts\import-phase13-library.ps1" + if (Test-Path -LiteralPath $importScriptPath -PathType Leaf) { + $files += Get-Item -LiteralPath $importScriptPath + } foreach ($file in $files) { $match = Select-String -LiteralPath $file.FullName -Pattern $adminPasswordLiteral -List -ErrorAction SilentlyContinue if ($match) { @@ -288,6 +292,7 @@ $requiredDirs = @( "project-docs\phase13-legal-knowledge-template-library\clause-library\common", "project-docs\phase13-legal-knowledge-template-library\contract-templates\purchase", "project-docs\phase13-legal-knowledge-template-library\qa-samples\review", + "project-docs\phase13-legal-knowledge-template-library\knowledge-cards", "project-docs\phase13-legal-knowledge-template-library\evidence" ) @@ -301,7 +306,8 @@ if ($missingDirs.Count -eq 0) { $commonDocFiles = @( "project-docs\phase13-legal-knowledge-template-library\README.md", "project-docs\phase13-legal-knowledge-template-library\governance-rules.md", - "project-docs\phase13-legal-knowledge-template-library\field-dictionary.md" + "project-docs\phase13-legal-knowledge-template-library\field-dictionary.md", + "scripts\import-phase13-library.ps1" ) foreach ($docPath in $commonDocFiles) { $absoluteDocPath = Join-Path $repoRoot $docPath @@ -324,7 +330,7 @@ $kbQaSampleColumns = @("sample_id", "question", "expected_answer_boundary", "exp $expertReviewColumns = @("review_id", "asset_type", "asset_id", "reviewer", "reviewer_role", "review_date", "review_result", "required_changes", "follow_up_owner", "evidence_path", "status", "notes") $legalSourceRows = Add-RequiredFileCheck -Key "inventory_legal_sources" -Label "法源清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\legal-source-inventory.csv" -Columns $legalSourceColumns -Add-RequiredFileCheck -Key "inventory_knowledge_cards" -Label "法律知识卡清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\legal-knowledge-card-inventory.csv" -Columns $knowledgeCardColumns | Out-Null +$knowledgeCardRows = Add-RequiredFileCheck -Key "inventory_knowledge_cards" -Label "法律知识卡清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\legal-knowledge-card-inventory.csv" -Columns $knowledgeCardColumns Add-RequiredFileCheck -Key "inventory_risk_rules" -Label "审核风险规则清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\review-risk-rule-inventory.csv" -Columns $riskRuleColumns | Out-Null Add-RequiredFileCheck -Key "inventory_clauses" -Label "标准条款库清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\clause-library-inventory.csv" -Columns $clauseColumns | Out-Null Add-RequiredFileCheck -Key "inventory_templates" -Label "合同模板清单" -RelativePath "project-docs\phase13-legal-knowledge-template-library\inventories\contract-template-inventory.csv" -Columns $templateColumns | Out-Null @@ -393,6 +399,83 @@ if ($invalidStatuses.Count -eq 0) { Add-Check -Key "legal_source_status_values" -Label "法源状态值" -Status "fail" -Detail "以下法源状态无效:$($invalidStatuses -join ',')" -Meta @{ rows = $invalidStatuses; allowed = $statusValues } } +$legalSourceIdMap = @{} +foreach ($sourceRow in $legalSourceRows) { + if (-not [string]::IsNullOrWhiteSpace($sourceRow.source_id)) { + $legalSourceIdMap[$sourceRow.source_id] = $true + } +} + +$duplicateKnowledgeCardIds = @($knowledgeCardRows | Group-Object knowledge_card_id | Where-Object { $_.Count -gt 1 } | Select-Object -ExpandProperty Name) +if ($duplicateKnowledgeCardIds.Count -eq 0) { + Add-Check -Key "knowledge_card_ids_unique" -Label "知识卡编号唯一性" -Status "pass" -Detail "未发现重复知识卡编号" +} else { + Add-Check -Key "knowledge_card_ids_unique" -Label "知识卡编号唯一性" -Status "fail" -Detail "重复编号:$($duplicateKnowledgeCardIds -join ',')" -Meta @{ duplicates = $duplicateKnowledgeCardIds } +} + +$knowledgeCardMissingFields = @($knowledgeCardRows | Where-Object { + [string]::IsNullOrWhiteSpace($_.knowledge_card_id) -or + [string]::IsNullOrWhiteSpace($_.title) -or + [string]::IsNullOrWhiteSpace($_.source_ids) -or + [string]::IsNullOrWhiteSpace($_.summary_path) -or + [string]::IsNullOrWhiteSpace($_.status) -or + [string]::IsNullOrWhiteSpace($_.owner) -or + [string]::IsNullOrWhiteSpace($_.legal_reviewer) +} | Select-Object -ExpandProperty knowledge_card_id) +if ($knowledgeCardMissingFields.Count -eq 0) { + Add-Check -Key "knowledge_card_required_fields" -Label "知识卡必填字段" -Status "pass" -Detail "必填字段均已填写" +} else { + Add-Check -Key "knowledge_card_required_fields" -Label "知识卡必填字段" -Status "fail" -Detail "以下知识卡缺少必填字段:$($knowledgeCardMissingFields -join ',')" -Meta @{ rows = $knowledgeCardMissingFields } +} + +$knowledgeCardMissingFiles = @($knowledgeCardRows | Where-Object { + [string]::IsNullOrWhiteSpace($_.summary_path) -or + -not (Test-Path -LiteralPath (Join-Path $LibraryRoot ($_.summary_path -replace "/", "\")) -PathType Leaf) +} | Select-Object -ExpandProperty knowledge_card_id) +if ($knowledgeCardMissingFiles.Count -eq 0) { + Add-Check -Key "knowledge_card_files" -Label "知识卡摘要文件" -Status "pass" -Detail "知识卡摘要文件均存在" +} else { + Add-Check -Key "knowledge_card_files" -Label "知识卡摘要文件" -Status "fail" -Detail "以下知识卡缺少摘要文件:$($knowledgeCardMissingFiles -join ',')" -Meta @{ rows = $knowledgeCardMissingFiles } +} + +$knowledgeCardUnknownSources = @() +foreach ($cardRow in $knowledgeCardRows) { + foreach ($sourceId in @($cardRow.source_ids -split ";" | ForEach-Object { $_.Trim() } | Where-Object { $_ })) { + if (-not $legalSourceIdMap.ContainsKey($sourceId)) { + $knowledgeCardUnknownSources += "$($cardRow.knowledge_card_id):$sourceId" + } + } +} +if ($knowledgeCardUnknownSources.Count -eq 0) { + Add-Check -Key "knowledge_card_source_traceability" -Label "知识卡法源可追溯" -Status "pass" -Detail "知识卡绑定法源均存在于法源清单" +} else { + Add-Check -Key "knowledge_card_source_traceability" -Label "知识卡法源可追溯" -Status "fail" -Detail "以下知识卡绑定了未知法源:$($knowledgeCardUnknownSources -join ',')" -Meta @{ rows = $knowledgeCardUnknownSources } +} + +$invalidKnowledgeCardStatuses = @($knowledgeCardRows | Where-Object { $statusValues -notcontains $_.status } | Select-Object -ExpandProperty knowledge_card_id) +if ($invalidKnowledgeCardStatuses.Count -eq 0) { + Add-Check -Key "knowledge_card_status_values" -Label "知识卡状态值" -Status "pass" -Detail "知识卡状态均在允许范围内" +} else { + Add-Check -Key "knowledge_card_status_values" -Label "知识卡状态值" -Status "fail" -Detail "以下知识卡状态无效:$($invalidKnowledgeCardStatuses -join ',')" -Meta @{ rows = $invalidKnowledgeCardStatuses; allowed = $statusValues } +} + +$knowledgeCardsReadyWithoutReview = @($knowledgeCardRows | Where-Object { + (Test-RequiredFlag -Value $_.production_ready) -and + ([string]::IsNullOrWhiteSpace($_.legal_reviewer) -or @("pending", "待法务复核", "待复核") -contains $_.legal_reviewer -or @("APPROVED", "PUBLISHED") -notcontains $_.status) +} | Select-Object -ExpandProperty knowledge_card_id) +if ($knowledgeCardsReadyWithoutReview.Count -eq 0) { + Add-Check -Key "knowledge_card_no_unreviewed_production" -Label "未复核知识卡禁止生产就绪" -Status "pass" -Detail "未发现未经复核即标记生产就绪的知识卡" +} else { + Add-Check -Key "knowledge_card_no_unreviewed_production" -Label "未复核知识卡禁止生产就绪" -Status "fail" -Detail "以下知识卡未完成复核却标记生产就绪:$($knowledgeCardsReadyWithoutReview -join ',')" -Meta @{ rows = $knowledgeCardsReadyWithoutReview } +} + +$knowledgeCardsNeedingReview = @($knowledgeCardRows | Where-Object { $_.status -eq "LEGAL_REVIEW" -or (Test-RequiredFlag -Value $_.review_required) } | Select-Object -ExpandProperty knowledge_card_id) +if ($knowledgeCardsNeedingReview.Count -gt 0) { + Add-Check -Key "knowledge_card_review_required" -Label "知识卡法务复核要求" -Status "warn" -Required $false -Detail "仍有 $($knowledgeCardsNeedingReview.Count) 张知识卡需要法务复核" -Meta @{ rows = $knowledgeCardsNeedingReview } +} else { + Add-Check -Key "knowledge_card_review_required" -Label "知识卡法务复核要求" -Status "pass" -Detail "知识卡已完成复核" +} + $domainsCovered = @($legalSourceRows | Select-Object -ExpandProperty knowledge_domain -Unique) $requiredDomains = @("civil-code", "judicial-interpretations", "company-commercial", "labor-employment", "data-privacy", "intellectual-property", "procurement-tendering") $missingKnowledgeDomains = @($requiredDomains | Where-Object { $domainsCovered -notcontains $_ }) @@ -406,7 +489,7 @@ if ($missingKnowledgeDomains.Count -eq 0) { $secretHits = Test-SecretLeak -Root $LibraryRoot if ($secretHits.Count -eq 0) { - Add-Check -Key "secret_scan" -Label "敏感信息扫描" -Status "pass" -Detail "阶段 13 资料包和门禁脚本中未发现管理员密码明文" + Add-Check -Key "secret_scan" -Label "敏感信息扫描" -Status "pass" -Detail "阶段 13 资料包、门禁脚本和导入脚本中未发现管理员密码明文" } else { Add-Check -Key "secret_scan" -Label "敏感信息扫描" -Status "fail" -Detail "发现敏感明文" -Meta @{ hits = $secretHits } } @@ -452,9 +535,11 @@ $summary = [ordered]@{ checks = $checks.ToArray() metrics = [ordered]@{ legal_sources = $legalSourceRows.Count + knowledge_cards = $knowledgeCardRows.Count allowed_domains = $allowedDomains.Count knowledge_domains = $domainsCovered.Count legal_review_required = $legalReviewRequired + knowledge_cards_review_required = $knowledgeCardsNeedingReview.Count inventory_files = $inventoryReport.Count } artifacts = [ordered]@{ @@ -488,10 +573,12 @@ $md.Add("") | Out-Null $md.Add("| 指标 | 数量 |") | Out-Null $md.Add("|---|---:|") | Out-Null $md.Add("| 官方法源 | $($legalSourceRows.Count) |") | Out-Null +$md.Add("| 法律知识卡 | $($knowledgeCardRows.Count) |") | Out-Null $md.Add("| 允许的官方域名 | $($allowedDomains.Count) |") | Out-Null $md.Add("| 知识领域 | $($domainsCovered.Count) |") | Out-Null $md.Add("| 清单文件 | $($inventoryReport.Count) |") | Out-Null $md.Add("| 仍需法务复核的法源 | $legalReviewRequired |") | Out-Null +$md.Add("| 仍需法务复核的知识卡 | $($knowledgeCardsNeedingReview.Count) |") | Out-Null $md.Add("") | Out-Null $md.Add("## 检查项") | Out-Null $md.Add("") | Out-Null