pomaster 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/COMMERCIAL_LICENSE.md +35 -0
  2. package/LICENSE +83 -0
  3. package/README.md +396 -0
  4. package/SECURITY.md +22 -0
  5. package/TRADEMARKS.md +12 -0
  6. package/catalog/candidates/candidates-draft.json +198 -0
  7. package/catalog/candidates/rejected.json +422 -0
  8. package/catalog/catalog-lock.draft.json +822 -0
  9. package/catalog/gates/gate.be.api.contract_checks.json +138 -0
  10. package/catalog/gates/gate.be.chg.contract_change_checks.json +138 -0
  11. package/catalog/gates/gate.chg.prechange_checks.json +155 -0
  12. package/catalog/gates/gate.web.api.request_checks.json +149 -0
  13. package/catalog/gates/gate.web.grid.checks.json +149 -0
  14. package/catalog/knowledge/knowledge.api.example_stable_error_code.json +80 -0
  15. package/catalog/knowledge/knowledge.chg.example_compat_window.json +87 -0
  16. package/catalog/knowledge/knowledge.chg.example_prop_migration.json +87 -0
  17. package/catalog/knowledge/knowledge.fp.api.field_drift_no_contract.json +83 -0
  18. package/catalog/knowledge/knowledge.fp.api.per_page_http_client.json +83 -0
  19. package/catalog/knowledge/knowledge.fp.be.contract_drift.json +87 -0
  20. package/catalog/knowledge/knowledge.fp.chg.page_local_padding.json +88 -0
  21. package/catalog/knowledge/knowledge.fp.grid.global_td_width.json +87 -0
  22. package/catalog/knowledge/knowledge.web.api.example_get_entity_list.json +83 -0
  23. package/catalog/knowledge/knowledge.web.grid.example_column_preset.json +83 -0
  24. package/catalog/policies/authority.be.api_contract_ownership.json +77 -0
  25. package/catalog/policies/authority.be.contract_ownership.json +73 -0
  26. package/catalog/policies/authority.chg.change_owners.json +75 -0
  27. package/catalog/policies/authority.web.api.request_owners.json +82 -0
  28. package/catalog/policies/authority.web.grid.ownership.json +78 -0
  29. package/catalog/policies/policy.api.backward_compat_defaults.json +83 -0
  30. package/catalog/policies/policy.api.contract_impl_consistency.json +81 -0
  31. package/catalog/policies/policy.api.no_informal_contract.json +82 -0
  32. package/catalog/policies/policy.arch.decision_tradeoff_record.json +78 -0
  33. package/catalog/policies/policy.cache.lifecycle_definition.json +79 -0
  34. package/catalog/policies/policy.chg.affect_templates.json +79 -0
  35. package/catalog/policies/policy.chg.breaking_versioning.json +81 -0
  36. package/catalog/policies/policy.chg.compat_migration_rollback.json +82 -0
  37. package/catalog/policies/policy.chg.deprecate_before_delete.json +82 -0
  38. package/catalog/policies/policy.chg.fix_at_root_cause_level.json +78 -0
  39. package/catalog/policies/policy.chg.observable_evolution.json +78 -0
  40. package/catalog/policies/policy.chg.prechange_consumer_scan.json +83 -0
  41. package/catalog/policies/policy.chg.staged_rollout.json +79 -0
  42. package/catalog/policies/policy.chg.sync_contract_docs_tests.json +81 -0
  43. package/catalog/policies/policy.conflict.priority_ladder.json +79 -0
  44. package/catalog/policies/policy.dep.admission_six_dimension_check.json +84 -0
  45. package/catalog/policies/policy.dep.change_surface_review.json +82 -0
  46. package/catalog/policies/policy.dep.introduction_review.json +83 -0
  47. package/catalog/policies/policy.derived.single_implementation.json +77 -0
  48. package/catalog/policies/policy.obs.correlation_context_minimum.json +81 -0
  49. package/catalog/policies/policy.obs.rum_dimension_whitelist.json +77 -0
  50. package/catalog/policies/policy.proc.pre_code_declaration.json +78 -0
  51. package/catalog/policies/policy.rel.pre_release_confirmation.json +77 -0
  52. package/catalog/policies/policy.role.domain_decision_authority.json +77 -0
  53. package/catalog/policies/policy.sec.third_party_execution_register.json +78 -0
  54. package/catalog/policies/policy.spec.admission_criteria.json +79 -0
  55. package/catalog/policies/policy.spec.derived_view_regeneration.json +79 -0
  56. package/catalog/policies/policy.spec.draft_not_baseline.json +77 -0
  57. package/catalog/policies/policy.spec.file_structure_contract.json +76 -0
  58. package/catalog/policies/policy.spec.metadata_required.json +76 -0
  59. package/catalog/policies/policy.spec.post_dev_backfill_classify.json +74 -0
  60. package/catalog/policies/policy.spec.procedural_record_not_surrogate.json +76 -0
  61. package/catalog/policies/policy.spec.semantic_identity.json +77 -0
  62. package/catalog/policies/policy.spec.unresolved_ledger_gate.json +79 -0
  63. package/catalog/policies/policy.stack.no_implicit_selection.json +77 -0
  64. package/catalog/policies/policy.tool.scoped_scan_boundary.json +78 -0
  65. package/catalog/policies/policy.web.api.auth_app_client_split.json +93 -0
  66. package/catalog/policies/policy.web.api.client_change_impact.json +86 -0
  67. package/catalog/policies/policy.web.api.domain_api_only.json +84 -0
  68. package/catalog/policies/policy.web.api.error_normalization.json +82 -0
  69. package/catalog/policies/policy.web.api.generated_client.json +82 -0
  70. package/catalog/policies/policy.web.api.late_result_guard.json +80 -0
  71. package/catalog/policies/policy.web.api.mutation_idempotency.json +84 -0
  72. package/catalog/policies/policy.web.api.no_network_optimism.json +82 -0
  73. package/catalog/policies/policy.web.api.query_cancel_stale_drop.json +80 -0
  74. package/catalog/policies/policy.web.api.request_infrastructure.json +95 -0
  75. package/catalog/policies/policy.web.api.retry_discipline.json +87 -0
  76. package/catalog/policies/policy.web.api.session_recovery_split.json +94 -0
  77. package/catalog/policies/policy.web.api.single_http_client.json +88 -0
  78. package/catalog/policies/policy.web.api.single_loading_source.json +81 -0
  79. package/catalog/policies/policy.web.api.transport_vs_business.json +81 -0
  80. package/catalog/policies/policy.web.api.trusted_endpoint_source.json +82 -0
  81. package/catalog/policies/policy.web.api.typed_domain_naming.json +79 -0
  82. package/catalog/policies/policy.web.arch.layer_isolation.json +376 -0
  83. package/catalog/policies/policy.web.arch.naming_conventions.json +207 -0
  84. package/catalog/policies/policy.web.arch.public_api_barrel.json +134 -0
  85. package/catalog/policies/policy.web.chg.controlled_change_triggers.json +79 -0
  86. package/catalog/policies/policy.web.copy.suppression_ledger_discipline.json +78 -0
  87. package/catalog/policies/policy.web.grid.column_schema_fields.json +78 -0
  88. package/catalog/policies/policy.web.grid.config_isolation.json +78 -0
  89. package/catalog/policies/policy.web.grid.freeze_key_columns.json +77 -0
  90. package/catalog/policies/policy.web.grid.interaction_registry.json +80 -0
  91. package/catalog/policies/policy.web.grid.keyboard_clipboard.json +79 -0
  92. package/catalog/policies/policy.web.grid.schema_driven_shell.json +81 -0
  93. package/catalog/policies/policy.web.grid.schema_versioning.json +78 -0
  94. package/catalog/policies/policy.web.grid.server_ops_virtualization.json +81 -0
  95. package/catalog/policies/policy.web.grid.shell_change_matrix.json +76 -0
  96. package/catalog/policies/policy.web.grid.width_fix_ladder.json +79 -0
  97. package/catalog/policies/policy.web.perf.budget_skeleton.json +110 -0
  98. package/catalog/policies/policy.web.style.ownership_matrix.json +207 -0
  99. package/catalog/policies/policy.web.track.consent_lifecycle.json +78 -0
  100. package/catalog/policies/policy.web.track.privacy_default_deny.json +81 -0
  101. package/catalog/policies/policy.web.track.stable_event_keys.json +78 -0
  102. package/catalog/policies/policy.web.uiux.provider_evidence_not_business_truth.json +86 -0
  103. package/catalog/projection-presets/registry-tree.yaml +307 -0
  104. package/catalog/sensors/sensor.browser.deterministic.json +53 -0
  105. package/catalog/sensors/sensor.browser.interactive.json +58 -0
  106. package/catalog/sensors/sensor.build.static.json +45 -0
  107. package/catalog/sensors/sensor.contract.conformance.json +47 -0
  108. package/catalog/sensors/sensor.performance.budget.json +46 -0
  109. package/catalog/sensors/sensor.production.metric.json +44 -0
  110. package/catalog/tools/apply_human_review_pilot_0001.py +488 -0
  111. package/catalog/tools/materialize_batch4_uplift.py +776 -0
  112. package/catalog/tools/materialize_catalog_pilot.py +784 -0
  113. package/dist/bin.js +52362 -0
  114. package/legal/THIRD_PARTY_NOTICES.md +336 -0
  115. package/package.json +36 -0
@@ -0,0 +1,488 @@
1
+ # -*- coding: utf-8 -*-
2
+ """pilot-0001 · Human Review 落账脚本(2026-08-28,一次性执行,留档审计)。
3
+
4
+ 依据: docs/catalog-pilot-report.md §8 Human Review Checklist(Owner 授权「按机器建议分布全批」
5
+ ACCEPT 41/ADJUST 24/REJECT 17 预填 + 7 项管线级裁决照建议执行)。
6
+ 实际逐行实数: ACCEPT 42 / ADJUST 23 / REJECT 17(与报告预填统计差 1,见 meta.human_review_application.note)。
7
+
8
+ 动作:
9
+ 1. candidates-draft.json 每卡写入 review 处置字段(disposition/seq/ref [+absorbed_duplicates/duplicate_of/reject_reason])
10
+ 2. ADJUST 内容修改(M1–M4 合并稿 / R-B / R-C=b / R-D / R-E 专名剥离 / R-F 上提 / T1 优先级 / §3.4·M5·M6·M7 互引登记)
11
+ 3. 17 条 REJECT 留档 catalog/candidates/rejected.json(带 reject 理由引用报告行 + duplicate_of 指针)
12
+ 4. meta 增加 human_review_application 块 + stats 分类计数随 R-F 上提同步
13
+
14
+ 纪律: FROZEN 词表不动(V1–V9 只登记不执行);逐行手术式编辑,未触碰卡片行 byte-identical;
15
+ 物化文件由 catalog/tools/materialize_catalog_pilot.py 从本输入重生成。
16
+ """
17
+ import hashlib
18
+ import json
19
+ import os
20
+ import sys
21
+
22
+ try:
23
+ sys.stdout.reconfigure(encoding="utf-8")
24
+ except Exception:
25
+ pass
26
+
27
+ ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # .../catalog
28
+ DRAFT = os.path.join(ROOT, "candidates", "candidates-draft.json")
29
+ REJECTED = os.path.join(ROOT, "candidates", "rejected.json")
30
+ REPORT = os.path.join(os.path.dirname(ROOT), "docs", "catalog-pilot-report.md")
31
+
32
+ SEQ = "pilot-0001"
33
+
34
+ # ---------------------------------------------------------------- 82 条处置表(逐行 = 报告 §8.1–§8.5)
35
+ # (seq, candidate_id, disposition)
36
+ DISPOSITIONS = [
37
+ (1, "POLICY.CHG.PRECHANGE_CONSUMER_SCAN", "ACCEPT"),
38
+ (2, "POLICY.CHG.COMPAT_MIGRATION_ROLLBACK", "ADJUST"),
39
+ (3, "POLICY.CHG.SYNC_CONTRACT_DOCS_TESTS", "ACCEPT"),
40
+ (4, "POLICY.CHG.DEPRECATE_BEFORE_DELETE", "ACCEPT"),
41
+ (5, "POLICY.CHG.FIX_AT_ROOT_CAUSE_LEVEL", "ACCEPT"),
42
+ (6, "POLICY.SPEC.METADATA_REQUIRED", "ADJUST"),
43
+ (7, "POLICY.WEB.CHG.CONTROLLED_CHANGE_TRIGGERS", "ACCEPT"),
44
+ (8, "POLICY.SPEC.POST_DEV_BACKFILL_CLASSIFY", "ACCEPT"),
45
+ (9, "POLICY.CHG.NO_SILENT_DEFAULT", "REJECT"),
46
+ (10, "POLICY.CHG.NO_SINGLE_CONSUMER_API", "REJECT"),
47
+ (11, "POLICY.CHG.NO_LOCAL_MASK_FIX", "REJECT"),
48
+ (12, "POLICY.CHG.NO_DELETE_WITHOUT_MIGRATION", "REJECT"),
49
+ (13, "POLICY.SPEC.DRAFT_NOT_BASELINE", "ADJUST"),
50
+ (14, "POLICY.SPEC.DRAFT_NOT_BASELINE_2", "REJECT"),
51
+ (15, "POLICY.CHG.AFFECT_TEMPLATES", "ACCEPT"),
52
+ (16, "POLICY.CHG.STAGED_ROLLOUT", "ACCEPT"),
53
+ (17, "POLICY.TPL.CHG_RECORD", "ADJUST"),
54
+ (18, "GATE.CHG.PRECHANGE_CHECKS", "ADJUST"),
55
+ (19, "KNOWLEDGE.CHG.EXAMPLE_PROP_MIGRATION", "ADJUST"),
56
+ (20, "KNOWLEDGE.FP.CHG.PAGE_LOCAL_PADDING", "ACCEPT"),
57
+ (21, "AUTHORITY.CHG.CHANGE_OWNERS", "ADJUST"),
58
+ (22, "POLICY.CHG.BREAKING_VERSIONING", "ACCEPT"),
59
+ (23, "POLICY.WEB.API.DOMAIN_API_ONLY", "ACCEPT"),
60
+ (24, "POLICY.WEB.API.SINGLE_HTTP_CLIENT", "ACCEPT"),
61
+ (25, "POLICY.WEB.API.TYPED_DOMAIN_NAMING", "ACCEPT"),
62
+ (26, "POLICY.WEB.API.QUERY_CANCEL_STALE_DROP", "ACCEPT"),
63
+ (27, "POLICY.WEB.API.MUTATION_IDEMPOTENCY", "ACCEPT"),
64
+ (28, "POLICY.WEB.API.ERROR_NORMALIZATION", "ACCEPT"),
65
+ (29, "POLICY.WEB.API.TRANSPORT_VS_BUSINESS", "ADJUST"),
66
+ (30, "POLICY.WEB.API.RETRY_DISCIPLINE", "ACCEPT"),
67
+ (31, "POLICY.WEB.API.LATE_RESULT_GUARD", "ACCEPT"),
68
+ (32, "POLICY.WEB.API.TRUSTED_ENDPOINT_SOURCE", "ACCEPT"),
69
+ (33, "POLICY.WEB.API.NO_RAW_FETCH", "REJECT"),
70
+ (34, "POLICY.WEB.API.NO_LOGIC_DUPLICATION", "REJECT"),
71
+ (35, "POLICY.WEB.API.NO_AUTO_RETRY_NONIDEM", "REJECT"),
72
+ (36, "POLICY.WEB.API.NO_ENVELOPE_IN_COMPONENT", "REJECT"),
73
+ (37, "POLICY.WEB.API.NO_NETWORK_OPTIMISM", "ADJUST"),
74
+ (38, "POLICY.WEB.API.GENERATED_CLIENT", "ACCEPT"),
75
+ (39, "POLICY.WEB.API.SINGLE_LOADING_SOURCE", "ACCEPT"),
76
+ (40, "POLICY.TPL.API_FUNCTION_CONTRACT", "ADJUST"),
77
+ (41, "GATE.WEB.API.REQUEST_CHECKS", "ACCEPT"),
78
+ (42, "KNOWLEDGE.WEB.API.EXAMPLE_GET_ENTITY_LIST", "ACCEPT"),
79
+ (43, "KNOWLEDGE.FP.API.PER_PAGE_HTTP_CLIENT", "ACCEPT"),
80
+ (44, "AUTHORITY.WEB.API.REQUEST_OWNERS", "ADJUST"),
81
+ (45, "POLICY.WEB.API.CLIENT_CHANGE_IMPACT", "ADJUST"),
82
+ (46, "POLICY.WEB.GRID.SCHEMA_DRIVEN_SHELL", "ACCEPT"),
83
+ (47, "POLICY.WEB.GRID.COLUMN_SCHEMA_FIELDS", "ACCEPT"),
84
+ (48, "POLICY.WEB.GRID.SERVER_OPS_VIRTUALIZATION", "ADJUST"),
85
+ (49, "POLICY.WEB.GRID.CONFIG_ISOLATION", "ACCEPT"),
86
+ (50, "POLICY.WEB.GRID.WIDTH_FIX_LADDER", "ACCEPT"),
87
+ (51, "POLICY.WEB.GRID.SHELL_CHANGE_MATRIX", "ACCEPT"),
88
+ (52, "POLICY.WEB.GRID.INTERACTION_REGISTRY", "ADJUST"),
89
+ (53, "POLICY.WEB.GRID.NO_TEMPLATE_COLUMNS", "REJECT"),
90
+ (54, "POLICY.WEB.GRID.NO_GLOBAL_WIDTH_CSS", "REJECT"),
91
+ (55, "POLICY.WEB.GRID.NO_SHARED_CONFIG_KEYS", "REJECT"),
92
+ (56, "POLICY.WEB.GRID.NO_FAKE_PAGINATION", "REJECT"),
93
+ (57, "POLICY.WEB.GRID.FREEZE_KEY_COLUMNS", "ACCEPT"),
94
+ (58, "POLICY.WEB.GRID.KEYBOARD_CLIPBOARD", "ACCEPT"),
95
+ (59, "POLICY.TPL.GRID_CONTRACT", "ADJUST"),
96
+ (60, "GATE.WEB.GRID.CHECKS", "ACCEPT"),
97
+ (61, "KNOWLEDGE.WEB.GRID.EXAMPLE_COLUMN_PRESET", "ACCEPT"),
98
+ (62, "KNOWLEDGE.FP.GRID.GLOBAL_TD_WIDTH", "ADJUST"),
99
+ (63, "AUTHORITY.WEB.GRID.OWNERSHIP", "ADJUST"),
100
+ (64, "POLICY.WEB.GRID.SCHEMA_VERSIONING", "ACCEPT"),
101
+ (65, "POLICY.CHG.PRECHANGE_SCAN_BE", "REJECT"),
102
+ (66, "POLICY.CHG.NO_DELETE_NO_MIGRATION_BE", "REJECT"),
103
+ (67, "POLICY.CHG.OBSERVABLE_EVOLUTION", "ACCEPT"),
104
+ (68, "POLICY.TPL.CHG_RECORD_BE", "ADJUST"),
105
+ (69, "GATE.BE.CHG.CONTRACT_CHANGE_CHECKS", "ACCEPT"),
106
+ (70, "KNOWLEDGE.CHG.EXAMPLE_COMPAT_WINDOW", "ADJUST"),
107
+ (71, "KNOWLEDGE.FP.BE.CONTRACT_DRIFT", "ACCEPT"),
108
+ (72, "AUTHORITY.BE.CONTRACT_OWNERSHIP", "ADJUST"),
109
+ (73, "POLICY.CHG.BREAKING_VERSIONING_BE", "REJECT"),
110
+ (74, "POLICY.API.CONTRACT_IMPL_CONSISTENCY", "ACCEPT"),
111
+ (75, "POLICY.API.NO_INFORMAL_CONTRACT", "ACCEPT"),
112
+ (76, "POLICY.API.BACKWARD_COMPAT_DEFAULTS", "ACCEPT"),
113
+ (77, "POLICY.TPL.OPERATION_CONTRACT_FIELDS", "ADJUST"),
114
+ (78, "GATE.BE.API.CONTRACT_CHECKS", "ADJUST"),
115
+ (79, "KNOWLEDGE.API.EXAMPLE_STABLE_ERROR_CODE", "ACCEPT"),
116
+ (80, "KNOWLEDGE.FP.API.FIELD_DRIFT_NO_CONTRACT", "ACCEPT"),
117
+ (81, "AUTHORITY.BE.API_CONTRACT_OWNERSHIP", "ADJUST"),
118
+ (82, "POLICY.API.DELEGATE_TO_CHG_PROTOCOL", "REJECT"),
119
+ ]
120
+
121
+ SECTION_OF = {**{n: "8.1" for n in range(1, 23)}, **{n: "8.2" for n in range(23, 46)},
122
+ **{n: "8.3" for n in range(46, 65)}, **{n: "8.4" for n in range(65, 74)},
123
+ **{n: "8.5" for n in range(74, 83)}}
124
+
125
+ # ---------------------------------------------------------------- ADJUST 内容修改(合并稿/裁决落法)
126
+ STATEMENTS = {
127
+ # M1:BE08 六要素(消费方/兼容窗口/迁移/回滚/版本策略)并入单一 UNIVERSAL 正本
128
+ "POLICY.CHG.PRECHANGE_CONSUMER_SCAN":
129
+ "修改被多方依赖的公共能力前,必须先枚举直接与间接消费方及其受影响场景,形成影响面清单;"
130
+ "契约/接口类变更还须同时明确兼容窗口、迁移方案、回滚路径与版本策略,与消费方影响面共同构成完整的前置扫描。",
131
+ # M2:BE08 MUST NOT 并入禁止形态段
132
+ "POLICY.CHG.DEPRECATE_BEFORE_DELETE":
133
+ "公共能力删除前必须先进入 deprecated 状态,并确认已无使用方后方可移除;"
134
+ "禁止形态:无迁移说明不得删除、重命名或改变已发布语义。",
135
+ # M3:BE08 两增量子句(显式审批 + 可执行回退)并入正本
136
+ "POLICY.CHG.BREAKING_VERSIONING":
137
+ "Breaking Change 必须版本化并经显式审批,且附可执行回退方案;"
138
+ "紧急修复可豁免前置流程但不豁免事后补齐影响、通知与迁移记录。",
139
+ # R-D(T2 同批):转机器派生
140
+ "POLICY.SPEC.METADATA_REQUIRED":
141
+ "各级 spec(项目级/需求级/公共组件/接口)必须具备状态、版本、Owner、更新时间与生效范围元数据;"
142
+ "vNext 信封形态下由 authority/axes 字段结构性派生承载,以机器预检字段存在性为准。",
143
+ # §5 补充要求(Checklist 行 48):阈值供给声明入正本
144
+ "POLICY.WEB.GRID.SERVER_OPS_VIRTUALIZATION":
145
+ "大数据量表必须采用服务端分页/筛选/排序并启用虚拟化渲染;"
146
+ "『大数据量』阈值参数由 Project Baseline 供给,Catalog 正本不内置默认阈值。",
147
+ }
148
+
149
+ NOTES = {
150
+ "POLICY.CHG.PRECHANGE_CONSUMER_SCAN":
151
+ "pilot-0001 M1 合并执行:BE 08 PRECHANGE_SCAN_BE 六要素(消费方/兼容窗口/迁移/回滚/版本策略)已并入本正本,"
152
+ "作为单一 UNIVERSAL 正本供两 lane 引用;兼容/迁移/回滚细则与 COMPAT_MIGRATION_ROLLBACK 互引",
153
+ "POLICY.CHG.COMPAT_MIGRATION_ROLLBACK":
154
+ "pilot-0001 M1 裁决执行:与正本 POLICY.CHG.PRECHANGE_CONSUMER_SCAN 保持互引"
155
+ "(本条承载兼容窗口/迁移方案/回滚路径细则),不并条不删除(原注『跨车道合并候选:BE 08 MUST 同构』已执行完毕)",
156
+ "POLICY.CHG.SYNC_CONTRACT_DOCS_TESTS":
157
+ "BE 08 反模式(只改实现不更新 OpenAPI/变更记录)即本条缺位的失败形态;"
158
+ "pilot-0001 互引:GATE.BE.API.CONTRACT_CHECKS(同步清单两口径重叠约 60%,口径统一留 Owner 后续裁决,§3.4)、"
159
+ "KNOWLEDGE.FP.BE.CONTRACT_DRIFT(M7 配对)",
160
+ "POLICY.CHG.DEPRECATE_BEFORE_DELETE":
161
+ "pilot-0001 M2 合并执行:BE 08 NO_DELETE_NO_MIGRATION_BE 禁止形态(无迁移说明不得删除/重命名/改变已发布语义)已并入本正本禁止形态段",
162
+ "POLICY.SPEC.METADATA_REQUIRED":
163
+ "pilot-0001 R-D 裁决(T2 同批):转机器派生——元数据由信封 authority/axes 结构性派生承载,人工重复登记义务解除;"
164
+ "联动 GATE.CHG.PRECHANGE_CHECKS 检查项⑤已改写为机器预检表述",
165
+ "POLICY.SPEC.DRAFT_NOT_BASELINE":
166
+ "带宪法级气质(认识论 fail-closed),保守留 UNIVERSAL_POLICY,是否升 CONSTITUTION 交 Human Review;"
167
+ "pilot-0001 R-B 裁决:维持 UNIVERSAL_POLICY,升格诉求登记挂起(待 vocab-pr V6 十二分类轴落地后由 Owner 专项裁决)",
168
+ "POLICY.CHG.STAGED_ROLLOUT":
169
+ "SHOULD 正确降级 advisory;pilot-0001 T1 precedence 声明:与 POLICY.CHG.BREAKING_VERSIONING 并读时紧急修复豁免优先"
170
+ "(豁免前置流程但不豁免事后补齐),三阶段建议不溯及约束 hotfix",
171
+ "POLICY.TPL.CHG_RECORD":
172
+ "pilot-0001 M4 裁决执行:与 POLICY.TPL.CHG_RECORD_BE 不硬合并,审阅为统一 CHANGE_RECORD 模板的两个 lane profile"
173
+ "(FE profile 承载 SpecStatus/Rollback),互引登记;R-C=b:模板暂留 candidates-draft,"
174
+ "catalog/templates/ 落点与 TEMPLATE. 前缀(V8)挂起至 vocab-pr/GATE 前缀收编后",
175
+ "GATE.CHG.PRECHANGE_CHECKS":
176
+ "GATE. 前缀需 vocab PR(见 meta.vocab_findings);检查项④⑤可机判;"
177
+ "pilot-0001 R-D 联动:检查项⑤已按 T2 处方改写为『机器预检元数据字段存在』(转机器派生)",
178
+ "KNOWLEDGE.CHG.EXAMPLE_PROP_MIGRATION":
179
+ "源文件自标『内容示例,可删除』;降级 advisory 知识;pilot-0001 M5:与 KNOWLEDGE.CHG.EXAMPLE_COMPAT_WINDOW"
180
+ "(BE 08 同型)互引,合并为一条跨 lane 知识登记为候选,留后续批次",
181
+ "AUTHORITY.CHG.CHANGE_OWNERS":
182
+ "落地为 Authority Map 条目(B7:registry 级粗起步);AUTHORITY. 前缀已冻结;"
183
+ "pilot-0001 M6:与本批其余 4 条 AUTHORITY.* 结构同型(提供/消费/仲裁三层默认值),"
184
+ "登记 Universal『领域分层所有权默认值』模板上提审阅(5→1+N),留后续批次",
185
+ "POLICY.WEB.API.TRANSPORT_VS_BUSINESS":
186
+ "语义上跨车道通用(任何 client 侧);pilot-0001 R-F:已上提 UNIVERSAL_POLICY"
187
+ "(判据:语句实体——传输/业务成功判定——可跨 lane 存在;applies_when.lane 维持不动,待 V7 lane 轴登记后再议)",
188
+ "POLICY.WEB.API.RETRY_DISCIPLINE":
189
+ "pilot-0001 R-F 对照样本:维持 LANE_POLICY——含 HTTP 专有词元 Retry-After,上提会失真;"
190
+ "作为上提判据(语句实体是否可跨 lane 存在)的反例保留",
191
+ "POLICY.WEB.API.TRUSTED_ENDPOINT_SOURCE":
192
+ "安全相关;与 BE 12『正式契约=OpenAPI 权威』构成跨车道契约链;pilot-0001 互引:POLICY.API.NO_INFORMAL_CONTRACT",
193
+ "POLICY.WEB.API.NO_NETWORK_OPTIMISM":
194
+ "独有内容(破除隐含假设),非既有条款极性反转;pilot-0001 R-F:已上提 UNIVERSAL_POLICY"
195
+ "(lane 中性:『在线即成功』假设破除在任何 client 侧成立)",
196
+ "POLICY.TPL.API_FUNCTION_CONTRACT":
197
+ "pilot-0001 R-C=b:暂留 candidates-draft;GATE.WEB.API.REQUEST_CHECKS 检查项③原引用本模板的悬空引用已改为"
198
+ "内联字段清单(StatusPolicy/Cancellation/Retry/RetryAfter/Idempotency);TEMPLATE. 前缀(V8)挂起 vocab-pr",
199
+ "GATE.WEB.API.REQUEST_CHECKS":
200
+ "GATE. 前缀需 vocab PR;pilot-0001 R-C=b 联动:检查项③原『见 POLICY.TPL.API_FUNCTION_CONTRACT 模板』悬空引用已改为内联字段清单",
201
+ "AUTHORITY.WEB.API.REQUEST_OWNERS":
202
+ "AUTHORITY. 前缀已冻结;control-plane 落地;pilot-0001 M6:同型上提审阅登记(见 AUTHORITY.CHG.CHANGE_OWNERS),留后续批次",
203
+ "POLICY.WEB.API.CLIENT_CHANGE_IMPACT":
204
+ "引用 POLICY.CHG.* 族而非自建流程;pilot-0001 ADJUST:M1 合并出单一 UNIVERSAL 正本后,"
205
+ "本条登记为指针条款候选(避免与 CHG 族双写),留后续批次改写",
206
+ "POLICY.WEB.GRID.SERVER_OPS_VIRTUALIZATION":
207
+ "PRD §93.5 自举例:本条应拆两半——Catalog Policy(大数据→服务端操作+虚拟化)+ Project Baseline(阈值与适用表格清单);"
208
+ "『大数据』判据属项目基线;pilot-0001 ADJUST:正本已显式声明阈值由 Project Baseline 供给(§93.5 拆两半)",
209
+ "POLICY.WEB.GRID.INTERACTION_REGISTRY":
210
+ "opt-in 语义保留:registry 文件不存在时 gate 应报 not-configured 而非静默通过(四态语义,T3——升 MUST 时不得剥离该条件);"
211
+ "pilot-0001 R-E:po-master 决议编号引用已剥离,不入 global 正本",
212
+ "POLICY.TPL.GRID_CONTRACT":
213
+ "与 M4 GRID.* capability 对象生成直接对接;pilot-0001 R-C=b:暂留 candidates-draft,落点挂起至 vocab-pr V8/GATE 前缀收编后",
214
+ "KNOWLEDGE.FP.GRID.GLOBAL_TD_WIDTH":
215
+ "可与项目侧 CSS 扫描器联动检测全局列宽规则(pilot-0001 R-E:旧包工具专名引用已剥离为通用表述;statement 本身通用,无需降级)",
216
+ "AUTHORITY.WEB.GRID.OWNERSHIP":
217
+ "三层例外结构恰是 vNext『Universal/Project/Lane 分离』的微缩模型;"
218
+ "pilot-0001 M6:同型上提审阅登记(见 AUTHORITY.CHG.CHANGE_OWNERS),留后续批次",
219
+ "POLICY.TPL.CHG_RECORD_BE":
220
+ "pilot-0001 M4 裁决执行:统一 CHANGE_RECORD 模板第二 lane profile(BE profile 承载旧行为/新行为/影响面/兼容判断/验证证据),"
221
+ "互引 POLICY.TPL.CHG_RECORD;R-C=b:暂留 candidates-draft,落点挂起同上",
222
+ "KNOWLEDGE.CHG.EXAMPLE_COMPAT_WINDOW":
223
+ "与 FE06 EXAMPLE_PROP_MIGRATION 同型(跨车道知识同构,Catalog 可合并为一条);"
224
+ "pilot-0001 M5:互引已建立,合并候选留后续批次",
225
+ "KNOWLEDGE.FP.BE.CONTRACT_DRIFT":
226
+ "B3 failure-pattern 附带池成员;正是 vNext Contract Gate(openapi 对账)的对症场景;"
227
+ "pilot-0001 M7 互引:POLICY.CHG.SYNC_CONTRACT_DOCS_TESTS(本失败模式即其缺位形态)",
228
+ "AUTHORITY.BE.CONTRACT_OWNERSHIP":
229
+ "与 FE06 AUTHORITY.CHG.CHANGE_OWNERS 结构同型(提供/消费/仲裁三方);"
230
+ "pilot-0001 M6:同型上提审阅登记(5→1+N),留后续批次",
231
+ "POLICY.API.NO_INFORMAL_CONTRACT":
232
+ "与 vocab source_types 禁 ai_invention 的 fail-closed 出处纪律同构;mock_contract 的存在恰为该条款的合规出口;"
233
+ "pilot-0001 互引:POLICY.WEB.API.TRUSTED_ENDPOINT_SOURCE(跨车道契约链)",
234
+ "POLICY.TPL.OPERATION_CONTRACT_FIELDS":
235
+ "与 02 信封 contract_operation payload(request_need/response_need)对接审阅;pilot-0001 R-C=b:暂留 candidates-draft,"
236
+ "落点挂起同上,对接审留后续批次",
237
+ "GATE.BE.API.CONTRACT_CHECKS":
238
+ "GATE. 前缀需 vocab PR;与 M4 Contract Gate vNext 检查集对照;pilot-0001 §3.4 互指:与 POLICY.CHG.SYNC_CONTRACT_DOCS_TESTS "
239
+ "同步清单对象不同、重叠约 60%(契约/示例/测试/文档/通知 vs 契约/实现/生成客户端/测试/handoff),两口径统一留 Owner 后续裁决",
240
+ "AUTHORITY.BE.API_CONTRACT_OWNERSHIP":
241
+ "frontend-only + 已发布外部契约型项目须叠加边界条款(契约提供方为外部系统时不做 owner 审批仪式,改为消费侧确认联调结果)"
242
+ "——防止项目特例固化进 global 正本的反例示范(pilot-0001 R-E:项目专名已改写为通用边界模式描述);"
243
+ "M6:五条 authority 结构同型,5→1+N 上提审阅登记,留后续批次",
244
+ }
245
+
246
+ # R-F 上提(分类变更)
247
+ CLASSIFICATION_CHANGE = {
248
+ "POLICY.WEB.API.TRANSPORT_VS_BUSINESS": "UNIVERSAL_POLICY",
249
+ "POLICY.WEB.API.NO_NETWORK_OPTIMISM": "UNIVERSAL_POLICY",
250
+ }
251
+
252
+ # 正本吸收指针(与 rejected.json duplicate_of 互为镜像)
253
+ ABSORBED = {
254
+ "POLICY.CHG.PRECHANGE_CONSUMER_SCAN": ["POLICY.CHG.NO_SINGLE_CONSUMER_API", "POLICY.CHG.PRECHANGE_SCAN_BE"],
255
+ "POLICY.CHG.COMPAT_MIGRATION_ROLLBACK": ["POLICY.CHG.NO_SILENT_DEFAULT"],
256
+ "POLICY.CHG.FIX_AT_ROOT_CAUSE_LEVEL": ["POLICY.CHG.NO_LOCAL_MASK_FIX", "POLICY.CHG.NO_SINGLE_CONSUMER_API"],
257
+ "POLICY.CHG.DEPRECATE_BEFORE_DELETE": ["POLICY.CHG.NO_DELETE_WITHOUT_MIGRATION", "POLICY.CHG.NO_DELETE_NO_MIGRATION_BE"],
258
+ "POLICY.SPEC.DRAFT_NOT_BASELINE": ["POLICY.SPEC.DRAFT_NOT_BASELINE_2"],
259
+ "POLICY.CHG.BREAKING_VERSIONING": ["POLICY.CHG.BREAKING_VERSIONING_BE", "POLICY.API.DELEGATE_TO_CHG_PROTOCOL"],
260
+ "POLICY.WEB.API.DOMAIN_API_ONLY": ["POLICY.WEB.API.NO_RAW_FETCH", "POLICY.WEB.API.NO_ENVELOPE_IN_COMPONENT"],
261
+ "POLICY.WEB.API.SINGLE_HTTP_CLIENT": ["POLICY.WEB.API.NO_RAW_FETCH", "POLICY.WEB.API.NO_LOGIC_DUPLICATION"],
262
+ "POLICY.WEB.API.MUTATION_IDEMPOTENCY": ["POLICY.WEB.API.NO_AUTO_RETRY_NONIDEM"],
263
+ "POLICY.WEB.API.ERROR_NORMALIZATION": ["POLICY.WEB.API.NO_ENVELOPE_IN_COMPONENT"],
264
+ "POLICY.WEB.API.RETRY_DISCIPLINE": ["POLICY.WEB.API.NO_AUTO_RETRY_NONIDEM"],
265
+ "POLICY.WEB.GRID.SCHEMA_DRIVEN_SHELL": ["POLICY.WEB.GRID.NO_TEMPLATE_COLUMNS"],
266
+ "POLICY.WEB.GRID.WIDTH_FIX_LADDER": ["POLICY.WEB.GRID.NO_GLOBAL_WIDTH_CSS"],
267
+ "POLICY.WEB.GRID.CONFIG_ISOLATION": ["POLICY.WEB.GRID.NO_SHARED_CONFIG_KEYS"],
268
+ "POLICY.WEB.GRID.SERVER_OPS_VIRTUALIZATION": ["POLICY.WEB.GRID.NO_FAKE_PAGINATION"],
269
+ }
270
+
271
+ # REJECT 留档元数据:id -> (duplicate_of, secondary_or_None, reject_reason)
272
+ DUP_META = {
273
+ "POLICY.CHG.NO_SILENT_DEFAULT": ("POLICY.CHG.COMPAT_MIGRATION_ROLLBACK", None,
274
+ "极性反转 DUPLICATE:并入正本禁止形态段(报告 §8.1 #9;§3.1 表)"),
275
+ "POLICY.CHG.NO_SINGLE_CONSUMER_API": ("POLICY.CHG.PRECHANGE_CONSUMER_SCAN", "POLICY.CHG.FIX_AT_ROOT_CAUSE_LEVEL",
276
+ "极性反转 DUPLICATE:由正本与根因修复条款联合覆盖(报告 §8.1 #10;§3.1 表)"),
277
+ "POLICY.CHG.NO_LOCAL_MASK_FIX": ("POLICY.CHG.FIX_AT_ROOT_CAUSE_LEVEL", None,
278
+ "极性反转 DUPLICATE:正本禁止形态(报告 §8.1 #11;§3.1 表)"),
279
+ "POLICY.CHG.NO_DELETE_WITHOUT_MIGRATION": ("POLICY.CHG.DEPRECATE_BEFORE_DELETE", None,
280
+ "极性反转 DUPLICATE:正本 FE 具体形态(报告 §8.1 #12;§3.1 表)"),
281
+ "POLICY.SPEC.DRAFT_NOT_BASELINE_2": ("POLICY.SPEC.DRAFT_NOT_BASELINE", None,
282
+ "源内逐字重复实证(源协议 37/38 行同文)(报告 §8.1 #14;§3.1)"),
283
+ "POLICY.WEB.API.NO_RAW_FETCH": ("POLICY.WEB.API.DOMAIN_API_ONLY", "POLICY.WEB.API.SINGLE_HTTP_CLIENT",
284
+ "极性反转 DUPLICATE:两正本联合覆盖(报告 §8.2 #33;§3.1 表)"),
285
+ "POLICY.WEB.API.NO_LOGIC_DUPLICATION": ("POLICY.WEB.API.SINGLE_HTTP_CLIENT", None,
286
+ "极性反转 DUPLICATE:单点统一的症候表述(报告 §8.2 #34;§3.1 表)"),
287
+ "POLICY.WEB.API.NO_AUTO_RETRY_NONIDEM": ("POLICY.WEB.API.RETRY_DISCIPLINE", "POLICY.WEB.API.MUTATION_IDEMPOTENCY",
288
+ "极性反转 DUPLICATE:与幂等条款并读,合并后消除 T4 表面冲突(报告 §8.2 #35;§3.1 表)"),
289
+ "POLICY.WEB.API.NO_ENVELOPE_IN_COMPONENT": ("POLICY.WEB.API.DOMAIN_API_ONLY", "POLICY.WEB.API.ERROR_NORMALIZATION",
290
+ "极性反转 DUPLICATE:越层禁止形态(报告 §8.2 #36;§3.1 表)"),
291
+ "POLICY.WEB.GRID.NO_TEMPLATE_COLUMNS": ("POLICY.WEB.GRID.SCHEMA_DRIVEN_SHELL", None,
292
+ "极性反转 DUPLICATE:正本禁止形态(报告 §8.3 #53;§3.1 表)"),
293
+ "POLICY.WEB.GRID.NO_GLOBAL_WIDTH_CSS": ("POLICY.WEB.GRID.WIDTH_FIX_LADDER", None,
294
+ "极性反转 DUPLICATE:正本禁止形态(报告 §8.3 #54;§3.1 表)"),
295
+ "POLICY.WEB.GRID.NO_SHARED_CONFIG_KEYS": ("POLICY.WEB.GRID.CONFIG_ISOLATION", None,
296
+ "极性反转 DUPLICATE:正本禁止形态(报告 §8.3 #55;§3.1 表)"),
297
+ "POLICY.WEB.GRID.NO_FAKE_PAGINATION": ("POLICY.WEB.GRID.SERVER_OPS_VIRTUALIZATION", None,
298
+ "极性反转 DUPLICATE:正本禁止形态(报告 §8.3 #56;§3.1 表)"),
299
+ "POLICY.CHG.PRECHANGE_SCAN_BE": ("POLICY.CHG.PRECHANGE_CONSUMER_SCAN", None,
300
+ "M1 让位副本:六要素已并入正本(报告 §8.4 #65;§3.2 M1 合并稿)"),
301
+ "POLICY.CHG.NO_DELETE_NO_MIGRATION_BE": ("POLICY.CHG.DEPRECATE_BEFORE_DELETE", None,
302
+ "M2 让位:BE 禁止形态已并入正本(报告 §8.4 #66;§3.2 M2 合并稿)"),
303
+ "POLICY.CHG.BREAKING_VERSIONING_BE": ("POLICY.CHG.BREAKING_VERSIONING", None,
304
+ "M3 让位:显式审批+可执行回退两子句已并入正本(报告 §8.4 #73;§3.2 M3 合并稿)"),
305
+ "POLICY.API.DELEGATE_TO_CHG_PROTOCOL": ("POLICY.CHG.BREAKING_VERSIONING", None,
306
+ "指针条款并入 BREAKING_VERSIONING,无独立语义(报告 §8.5 #82)"),
307
+ }
308
+
309
+ META_APPLICATION = {
310
+ "seq": SEQ,
311
+ "date": "2026-08-28",
312
+ "authority": "Owner 授权:按机器建议分布全批(报告预填 ACCEPT 41 / ADJUST 24 / REJECT 17)+ 7 项管线级裁决照建议执行",
313
+ "applied": {"ACCEPT": 42, "ADJUST": 23, "REJECT": 17},
314
+ "note": "逐行实数 ACCEPT 42 / ADJUST 23 / REJECT 17 与报告预填统计(41/24/17)差 1:预填行自身归类与 §8 逐行表不一致"
315
+ "(与 §3.1/§6.2 口径差 1 注记同类),落账以逐行表为准",
316
+ "pipeline_rulings": {
317
+ "R-A": "跨车道合并 M1–M4 全采纳:M1 六要素并入 PRECHANGE_CONSUMER_SCAN 单一 UNIVERSAL 正本(COMPAT_MIGRATION_ROLLBACK 互引);"
318
+ "M2 BE 禁止形态并入 DEPRECATE_BEFORE_DELETE;M3 显式审批+可执行回退并入 BREAKING_VERSIONING;"
319
+ "M4 CHG_RECORD/CHG_RECORD_BE 不硬合并,审阅为统一 CHANGE_RECORD 模板两 lane profile",
320
+ "R-B": "留 UNIVERSAL_POLICY:升 CONSTITUTION 诉求登记挂起(报告未给出升格建议,保守处置;待 vocab-pr V6 分类轴落地后 Owner 专项裁决)",
321
+ "R-C": "方案 b:5 条 CONTRACT_TEMPLATE 暂留 candidates-draft;gate.web.api.request_checks 检查项③悬空引用已改为内联字段清单;"
322
+ "catalog/templates/ 落点挂起至 vocab-pr V8/GATE 前缀收编后",
323
+ "R-D": "转机器派生(T2 同批裁决):METADATA_REQUIRED 改为信封 authority/axes 结构性派生承载 + 机器预检字段存在性;"
324
+ "GATE.CHG.PRECHANGE_CHECKS 检查项⑤同步改写",
325
+ "R-E": "授权改写:GLOBAL_TD_WIDTH / INTERACTION_REGISTRY notes 专名剥离;API_CONTRACT_OWNERSHIP notes 改写为通用边界模式",
326
+ "R-F": "部分采纳:TRANSPORT_VS_BUSINESS 与 NO_NETWORK_OPTIMISM 上提 UNIVERSAL_POLICY;RETRY_DISCIPLINE 维持 LANE(上提边界对照样本);"
327
+ "AUTHORITY 5 条 M6 合并审登记留后续批次",
328
+ "R-G": "V1–V9 原则批准为 vocab-pr 草案段落,本批只登记不执行(FROZEN 词表未动)",
329
+ },
330
+ }
331
+
332
+
333
+ def build_report_lines():
334
+ with open(REPORT, encoding="utf-8") as f:
335
+ return f.read().split("\n")
336
+
337
+
338
+ def locate_row(report_lines, seq, cid):
339
+ needle = "| " + str(seq) + " | " + cid + " |"
340
+ for i, l in enumerate(report_lines, start=1):
341
+ if l.startswith(needle):
342
+ return i
343
+ raise SystemExit("报告行未定位: " + cid)
344
+
345
+
346
+ def main():
347
+ report_lines = build_report_lines()
348
+ seq_by_id = {cid: (seq, disp) for seq, cid, disp in DISPOSITIONS}
349
+
350
+ # 校验处置表完整性
351
+ counts = {"ACCEPT": 0, "ADJUST": 0, "REJECT": 0}
352
+ for _, _, d in DISPOSITIONS:
353
+ counts[d] += 1
354
+ assert counts == {"ACCEPT": 42, "ADJUST": 23, "REJECT": 17}, counts
355
+ for cid in ABSORBED:
356
+ assert seq_by_id[cid][1] in ("ACCEPT", "ADJUST"), cid
357
+ for cid in DUP_META:
358
+ assert seq_by_id[cid][1] == "REJECT", cid
359
+ for cid in CLASSIFICATION_CHANGE:
360
+ assert seq_by_id[cid][1] == "ADJUST", cid
361
+
362
+ with open(DRAFT, encoding="utf-8") as f:
363
+ raw = f.read()
364
+ lines = raw.split("\n")
365
+
366
+ meta_close_idx = None
367
+ out = []
368
+ stats_fixes = 0
369
+ rejected_cards = []
370
+ modified_cards = 0
371
+ seen = set()
372
+
373
+ for line in lines:
374
+ stripped = line.strip()
375
+ if line == " }," and meta_close_idx is None:
376
+ # meta 对象的收尾行(首个出现)
377
+ meta_close_idx = len(out)
378
+ if stripped.startswith("{\"candidate_id\":"):
379
+ had_comma = stripped.endswith(",")
380
+ body = stripped[:-1] if had_comma else stripped
381
+ card = json.loads(body)
382
+ cid = card["candidate_id"]
383
+ assert cid not in seen, cid
384
+ seen.add(cid)
385
+ assert cid in seq_by_id, "处置表缺卡: " + cid
386
+ seq, disp = seq_by_id[cid]
387
+ lineno = locate_row(report_lines, seq, cid)
388
+ ref = "docs/catalog-pilot-report.md:L%d(§%s #%d)" % (lineno, SECTION_OF[seq], seq)
389
+
390
+ original_compact = json.dumps(card, ensure_ascii=False)
391
+ assert original_compact == body, "卡片行 round-trip 失败: " + cid
392
+
393
+ review = {"disposition": disp, "seq": SEQ, "ref": ref}
394
+ if disp == "REJECT":
395
+ dup, dup2, reason = DUP_META[cid]
396
+ review["reject_reason"] = reason
397
+ review["duplicate_of"] = dup
398
+ if dup2:
399
+ review["duplicate_of_secondary"] = dup2
400
+ else:
401
+ if cid in ABSORBED:
402
+ review["absorbed_duplicates"] = ABSORBED[cid]
403
+ if cid in NOTES:
404
+ card["notes"] = NOTES[cid]
405
+ if cid in STATEMENTS:
406
+ card["statement_zh"] = STATEMENTS[cid]
407
+ if cid in CLASSIFICATION_CHANGE:
408
+ card["classification"] = CLASSIFICATION_CHANGE[cid]
409
+ card["review"] = review
410
+
411
+ if disp == "REJECT":
412
+ rejected_cards.append(card)
413
+ new_line = " " + json.dumps(card, ensure_ascii=False) + ("," if had_comma else "")
414
+ if new_line != line:
415
+ modified_cards += 1
416
+ out.append(new_line)
417
+ continue
418
+ # meta 统计计数随 R-F 上提同步(UNIVERSAL 20→22, LANE 25→23)
419
+ if line == ' "UNIVERSAL_POLICY": 20,':
420
+ out.append(' "UNIVERSAL_POLICY": 22,')
421
+ stats_fixes += 1
422
+ continue
423
+ if line == ' "LANE_POLICY": 25,':
424
+ out.append(' "LANE_POLICY": 23,')
425
+ stats_fixes += 1
426
+ continue
427
+ if "本批 UNIVERSAL_POLICY 20 条" in line:
428
+ out.append(line.replace("本批 UNIVERSAL_POLICY 20 条", "本批 UNIVERSAL_POLICY 22 条(含 R-F 上提 2 条)"))
429
+ stats_fixes += 1
430
+ continue
431
+ out.append(line)
432
+
433
+ assert len(seen) == 82, len(seen)
434
+ assert len(rejected_cards) == 17
435
+ assert meta_close_idx is not None
436
+ assert stats_fixes == 3, stats_fixes
437
+
438
+ # meta 末尾插入 human_review_application 块(文本手术,保持原格式不动)
439
+ blk = json.dumps(META_APPLICATION, ensure_ascii=False, indent=2)
440
+ blk = " \"human_review_application\": " + blk.replace("\n", "\n ") # meta 末位成员,不带尾逗号
441
+ # meta 收尾行 ' },' 之前的 ' ]' 行需要补逗号
442
+ insert_at = meta_close_idx
443
+ assert out[insert_at - 1] == " ]", out[insert_at - 1]
444
+ out[insert_at - 1] = " ],"
445
+ out.insert(insert_at, blk)
446
+
447
+ new_raw = "\n".join(out)
448
+ data = json.loads(new_raw) # 解析自检
449
+ cards = [x for x in data if "candidate_id" in x]
450
+ assert len(cards) == 82
451
+ disp_count = {"ACCEPT": 0, "ADJUST": 0, "REJECT": 0}
452
+ for c in cards:
453
+ disp_count[c["review"]["disposition"]] += 1
454
+ assert disp_count == {"ACCEPT": 42, "ADJUST": 23, "REJECT": 17}, disp_count
455
+ # 全量卡可 JSON 序列化(隐含)+ 上提结果核验
456
+ for cid, cls in CLASSIFICATION_CHANGE.items():
457
+ assert next(c for c in cards if c["candidate_id"] == cid)["classification"] == cls
458
+
459
+ with open(DRAFT, "w", encoding="utf-8", newline="\n") as f:
460
+ f.write(new_raw)
461
+
462
+ rejected_doc = {
463
+ "_record_type": "rejected_archive",
464
+ "seq": SEQ,
465
+ "date": "2026-08-28",
466
+ "generated_by": "catalog/tools/apply_human_review_pilot_0001.py(pilot-0001 Human Review 落账)",
467
+ "basis": "docs/catalog-pilot-report.md §8 Human Review Checklist 逐行 REJECT + §3.1/§3.2 合并表;"
468
+ "REJECT 语义=驳回独立入册(合并指针维持于正本 review.absorbed_duplicates),非丢弃内容;"
469
+ "本档案为留档副本,条目仍保留于 candidates-draft.json(含 disposition=REJECT)",
470
+ "count": len(rejected_cards),
471
+ "rejected": rejected_cards,
472
+ }
473
+ rej_data = json.dumps(rejected_doc, ensure_ascii=False, indent=2) + "\n"
474
+ with open(REJECTED, "w", encoding="utf-8", newline="\n") as f:
475
+ f.write(rej_data)
476
+
477
+ print(json.dumps({
478
+ "applied": disp_count,
479
+ "cards_modified": modified_cards,
480
+ "rejected_archived": len(rejected_cards),
481
+ "absorbed_pointers": sum(len(v) for v in ABSORBED.values()),
482
+ "stats_fixes": stats_fixes,
483
+ "draft_sha256": "sha256:" + hashlib.sha256(new_raw.encode("utf-8")).hexdigest(),
484
+ }, ensure_ascii=False, indent=2))
485
+
486
+
487
+ if __name__ == "__main__":
488
+ main()