pomaster 0.3.0 → 0.4.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 (393) hide show
  1. package/README.md +9 -10
  2. package/catalog/archetypes/archetype.frontend.error_taxonomy.json +13 -5
  3. package/catalog/archetypes/archetype.frontend.feature_oriented.json +1 -1
  4. package/catalog/archetypes/archetype.state.async_command.json +4 -4
  5. package/catalog/catalog-lock.draft.json +1120 -104
  6. package/catalog/gates/gate.be.api.contract_checks.json +2 -1
  7. package/catalog/gates/gate.be.chg.contract_change_checks.json +2 -1
  8. package/catalog/gates/gate.chg.prechange_checks.json +2 -1
  9. package/catalog/gates/gate.web.api.request_checks.json +2 -1
  10. package/catalog/gates/gate.web.grid.checks.json +2 -1
  11. package/catalog/knowledge/knowledge.api.example_stable_error_code.json +2 -1
  12. package/catalog/knowledge/knowledge.chg.example_compat_window.json +2 -1
  13. package/catalog/knowledge/knowledge.chg.example_prop_migration.json +2 -1
  14. package/catalog/knowledge/knowledge.fp.api.field_drift_no_contract.json +2 -1
  15. package/catalog/knowledge/knowledge.fp.api.per_page_http_client.json +2 -1
  16. package/catalog/knowledge/knowledge.fp.be.contract_drift.json +2 -1
  17. package/catalog/knowledge/knowledge.fp.chg.page_local_padding.json +2 -1
  18. package/catalog/knowledge/knowledge.fp.grid.global_td_width.json +2 -1
  19. package/catalog/knowledge/knowledge.web.api.example_get_entity_list.json +2 -1
  20. package/catalog/knowledge/knowledge.web.grid.example_column_preset.json +2 -1
  21. package/catalog/policies/authority.be.api_contract_ownership.json +2 -1
  22. package/catalog/policies/authority.be.contract_ownership.json +2 -1
  23. package/catalog/policies/authority.chg.change_owners.json +2 -1
  24. package/catalog/policies/authority.web.api.request_owners.json +2 -1
  25. package/catalog/policies/authority.web.grid.ownership.json +2 -1
  26. package/catalog/policies/policy.ai.change_plan_first.json +91 -0
  27. package/catalog/policies/policy.ai.fact_inference_separation.json +91 -0
  28. package/catalog/policies/policy.ai.read_search_verify_before_write.json +92 -0
  29. package/catalog/policies/policy.ai.rule_relaxation_approval.json +91 -0
  30. package/catalog/policies/policy.api.backward_compat_defaults.json +2 -1
  31. package/catalog/policies/policy.api.contract_impl_consistency.json +2 -1
  32. package/catalog/policies/policy.api.no_informal_contract.json +2 -1
  33. package/catalog/policies/policy.arch.adr_immutable_history.json +91 -0
  34. package/catalog/policies/policy.arch.decision_tradeoff_record.json +2 -1
  35. package/catalog/policies/policy.arch.no_convenience_over_boundary.json +93 -0
  36. package/catalog/policies/policy.arch.prefer_verifiable_option.json +92 -0
  37. package/catalog/policies/policy.authz.no_gating_proxy_trust.json +99 -0
  38. package/catalog/policies/policy.authz.permission_scope_expansion_gate.json +99 -0
  39. package/catalog/policies/policy.authz.server_five_factor_verification.json +101 -0
  40. package/catalog/policies/policy.be.conc.prefer_db_constraints.json +97 -0
  41. package/catalog/policies/policy.be.db.expand_migrate_contract.json +97 -0
  42. package/catalog/policies/policy.be.idem.key_payload_conflict.json +97 -0
  43. package/catalog/policies/policy.be.model.single_boundary_conversion.json +97 -0
  44. package/catalog/policies/policy.be.sql.index_for_known_queries.json +97 -0
  45. package/catalog/policies/policy.be.state.single_rule_source.json +97 -0
  46. package/catalog/policies/policy.be.txn.short_locks_compensation.json +96 -0
  47. package/catalog/policies/policy.bound.search_first_entry_only.json +91 -0
  48. package/catalog/policies/policy.boundary.validate_in_encode_out.json +92 -0
  49. package/catalog/policies/policy.cache.failure_mode_guards.json +93 -0
  50. package/catalog/policies/policy.cache.lifecycle_definition.json +2 -1
  51. package/catalog/policies/policy.cache.schema_versioning.json +91 -0
  52. package/catalog/policies/policy.cfg.config_attribute_completeness.json +95 -0
  53. package/catalog/policies/policy.cfg.key_rename_dual_read.json +92 -0
  54. package/catalog/policies/policy.cfg.no_secret_dispersal.json +90 -0
  55. package/catalog/policies/policy.cfg.production_safe_defaults.json +92 -0
  56. package/catalog/policies/policy.cfg.schema_backed_config.json +92 -0
  57. package/catalog/policies/policy.chg.affect_templates.json +2 -1
  58. package/catalog/policies/policy.chg.breaking_versioning.json +2 -1
  59. package/catalog/policies/policy.chg.compat_migration_rollback.json +2 -1
  60. package/catalog/policies/policy.chg.deprecate_before_delete.json +2 -1
  61. package/catalog/policies/policy.chg.fix_at_root_cause_level.json +2 -1
  62. package/catalog/policies/policy.chg.no_unrelated_changes.json +91 -0
  63. package/catalog/policies/policy.chg.observable_evolution.json +2 -1
  64. package/catalog/policies/policy.chg.prechange_consumer_scan.json +2 -1
  65. package/catalog/policies/policy.chg.staged_rollout.json +2 -1
  66. package/catalog/policies/policy.chg.sync_contract_docs_tests.json +2 -1
  67. package/catalog/policies/policy.conflict.priority_ladder.json +2 -1
  68. package/catalog/policies/policy.contract.no_invented_facts.json +93 -0
  69. package/catalog/policies/policy.dep.admission_six_dimension_check.json +2 -1
  70. package/catalog/policies/policy.dep.build_path_supply_chain.json +93 -0
  71. package/catalog/policies/policy.dep.change_surface_review.json +2 -1
  72. package/catalog/policies/policy.dep.introduction_review.json +2 -1
  73. package/catalog/policies/policy.dep.no_untrusted_source_no_lock_bypass.json +92 -0
  74. package/catalog/policies/policy.dep.time_boxed_urgent_exception.json +91 -0
  75. package/catalog/policies/policy.deploy.no_dev_env_as_production_fact.json +91 -0
  76. package/catalog/policies/policy.deploy.operational_capabilities.json +93 -0
  77. package/catalog/policies/policy.deploy.runtime_fact_record.json +97 -0
  78. package/catalog/policies/policy.derived.single_implementation.json +2 -1
  79. package/catalog/policies/policy.err.failure_five_part_mapping.json +101 -0
  80. package/catalog/policies/policy.err.no_internal_detail_exposure.json +97 -0
  81. package/catalog/policies/policy.err.published_code_immutable.json +98 -0
  82. package/catalog/policies/policy.evid.acceptance_binds_verifiable_evidence.json +92 -0
  83. package/catalog/policies/policy.evid.no_silent_gate_removal.json +90 -0
  84. package/catalog/policies/policy.evid.no_unverifiable_pass.json +92 -0
  85. package/catalog/policies/policy.flag.cleanup_after_full_rollout.json +94 -0
  86. package/catalog/policies/policy.flag.consistent_off_state.json +92 -0
  87. package/catalog/policies/policy.flag.kill_switch.json +91 -0
  88. package/catalog/policies/policy.flag.lifecycle_metadata.json +93 -0
  89. package/catalog/policies/policy.flag.not_a_permission.json +92 -0
  90. package/catalog/policies/policy.gate.p0_non_bypassable.json +92 -0
  91. package/catalog/policies/policy.gate.risk_factors_confirmed.json +93 -0
  92. package/catalog/policies/policy.guard.no_check_weakening.json +92 -0
  93. package/catalog/policies/policy.integration.call_definition_minimum.json +95 -0
  94. package/catalog/policies/policy.integration.fault_containment.json +94 -0
  95. package/catalog/policies/policy.job.lifecycle_definition.json +96 -0
  96. package/catalog/policies/policy.job.no_unmanaged_execution.json +92 -0
  97. package/catalog/policies/policy.job.operational_features.json +93 -0
  98. package/catalog/policies/policy.obs.actionable_signals.json +93 -0
  99. package/catalog/policies/policy.obs.alert_with_owner.json +91 -0
  100. package/catalog/policies/policy.obs.context_field_baseline.json +91 -0
  101. package/catalog/policies/policy.obs.correlation_context_minimum.json +2 -1
  102. package/catalog/policies/policy.obs.no_sensitive_or_unbounded_logging.json +92 -0
  103. package/catalog/policies/policy.obs.no_sensitive_raw_values.json +93 -0
  104. package/catalog/policies/policy.obs.rum_dimension_whitelist.json +2 -1
  105. package/catalog/policies/policy.obs.signal_change_impact.json +91 -0
  106. package/catalog/policies/policy.obs.source_map_access_control.json +92 -0
  107. package/catalog/policies/policy.obs.telemetry_lifecycle_declared.json +93 -0
  108. package/catalog/policies/policy.obs.trace_correlation.json +91 -0
  109. package/catalog/policies/policy.perf.budget_change_retest.json +91 -0
  110. package/catalog/policies/policy.perf.evidence_binding.json +95 -0
  111. package/catalog/policies/policy.perf.observation_dimensions.json +94 -0
  112. package/catalog/policies/policy.proc.checklist_change_policy.json +91 -0
  113. package/catalog/policies/policy.proc.pre_code_declaration.json +2 -1
  114. package/catalog/policies/policy.proc.scope_drift_reclassify.json +91 -0
  115. package/catalog/policies/policy.prv.processing_scope_re_review.json +97 -0
  116. package/catalog/policies/policy.prv.sensitive_data_six_facts.json +102 -0
  117. package/catalog/policies/policy.registry.human_fields_validated_decorrelated.json +93 -0
  118. package/catalog/policies/policy.rel.no_irreversible_unmonitored_full_release.json +91 -0
  119. package/catalog/policies/policy.rel.observability_before_ship.json +91 -0
  120. package/catalog/policies/policy.rel.pre_release_confirmation.json +2 -1
  121. package/catalog/policies/policy.rel.process_change_needs_drill_audit.json +91 -0
  122. package/catalog/policies/policy.rel.traceable_build.json +93 -0
  123. package/catalog/policies/policy.role.domain_decision_authority.json +2 -1
  124. package/catalog/policies/policy.role.human_signs_for_ai.json +93 -0
  125. package/catalog/policies/policy.sec.authn_policy_unified.json +91 -0
  126. package/catalog/policies/policy.sec.no_client_side_trust.json +92 -0
  127. package/catalog/policies/policy.sec.no_longterm_security_disable.json +91 -0
  128. package/catalog/policies/policy.sec.no_script_readable_credentials.json +91 -0
  129. package/catalog/policies/policy.sec.no_secrets_in_client_surface.json +91 -0
  130. package/catalog/policies/policy.sec.relaxation_approval.json +92 -0
  131. package/catalog/policies/policy.sec.security_relaxation_gate.json +92 -0
  132. package/catalog/policies/policy.sec.third_party_execution_register.json +2 -1
  133. package/catalog/policies/policy.sec.trust_boundary_enforcement.json +93 -0
  134. package/catalog/policies/policy.sec.upload_download_server_recheck.json +91 -0
  135. package/catalog/policies/policy.sec.url_source_allowlist.json +91 -0
  136. package/catalog/policies/policy.spec.admission_criteria.json +2 -1
  137. package/catalog/policies/policy.spec.derived_view_regeneration.json +2 -1
  138. package/catalog/policies/policy.spec.draft_not_baseline.json +2 -1
  139. package/catalog/policies/policy.spec.family_conflict_precedence.json +93 -0
  140. package/catalog/policies/policy.spec.file_structure_contract.json +2 -1
  141. package/catalog/policies/policy.spec.freeze_before_use.json +93 -0
  142. package/catalog/policies/policy.spec.metadata_required.json +2 -1
  143. package/catalog/policies/policy.spec.post_dev_backfill_classify.json +2 -1
  144. package/catalog/policies/policy.spec.primary_source_basis.json +93 -0
  145. package/catalog/policies/policy.spec.procedural_record_not_surrogate.json +2 -1
  146. package/catalog/policies/policy.spec.semantic_identity.json +2 -1
  147. package/catalog/policies/policy.spec.unresolved_ledger_gate.json +2 -1
  148. package/catalog/policies/policy.stack.derived_store_not_authority.json +93 -0
  149. package/catalog/policies/policy.stack.dual_web_stack_boundary.json +93 -0
  150. package/catalog/policies/policy.stack.entry_chain_recorded.json +93 -0
  151. package/catalog/policies/policy.stack.entry_limits_aligned.json +94 -0
  152. package/catalog/policies/policy.stack.local_form_not_prod_fact.json +93 -0
  153. package/catalog/policies/policy.stack.multi_datastore_ownership.json +93 -0
  154. package/catalog/policies/policy.stack.no_implicit_selection.json +2 -1
  155. package/catalog/policies/policy.stack.persistence_coexistence_scope.json +93 -0
  156. package/catalog/policies/policy.stack.toolchain_versions_pinned.json +95 -0
  157. package/catalog/policies/policy.stack.upgrade_compat_verified.json +93 -0
  158. package/catalog/policies/policy.struct.module_entry_dependency_declared.json +92 -0
  159. package/catalog/policies/policy.struct.no_unexplained_top_level_dir.json +91 -0
  160. package/catalog/policies/policy.struct.reuse_proven_structure.json +91 -0
  161. package/catalog/policies/policy.test.control_nondeterminism_keep_diagnosis.json +91 -0
  162. package/catalog/policies/policy.test.isolation_and_cleanup.json +93 -0
  163. package/catalog/policies/policy.test.no_synthetic_stability.json +92 -0
  164. package/catalog/policies/policy.test.pyramid_and_ci_matrix.json +92 -0
  165. package/catalog/policies/policy.test.removal_justification.json +91 -0
  166. package/catalog/policies/policy.test.removal_needs_substitute_evidence.json +91 -0
  167. package/catalog/policies/policy.test.risk_driven_plan.json +92 -0
  168. package/catalog/policies/policy.test.stable_observable_assertions.json +92 -0
  169. package/catalog/policies/policy.tool.discoverable_toolchain.json +92 -0
  170. package/catalog/policies/policy.tool.no_hand_edit_generated_no_ci_drift.json +91 -0
  171. package/catalog/policies/policy.tool.no_vendored_body_edits.json +94 -0
  172. package/catalog/policies/policy.tool.scoped_scan_boundary.json +2 -1
  173. package/catalog/policies/policy.tool.upgrade_verify_lock_rollback.json +92 -0
  174. package/catalog/policies/policy.web.api.auth_app_client_split.json +2 -1
  175. package/catalog/policies/policy.web.api.client_change_impact.json +2 -1
  176. package/catalog/policies/policy.web.api.domain_api_only.json +2 -1
  177. package/catalog/policies/policy.web.api.error_normalization.json +2 -1
  178. package/catalog/policies/policy.web.api.generated_client.json +2 -1
  179. package/catalog/policies/policy.web.api.late_result_guard.json +2 -1
  180. package/catalog/policies/policy.web.api.mutation_idempotency.json +2 -1
  181. package/catalog/policies/policy.web.api.no_network_optimism.json +2 -1
  182. package/catalog/policies/policy.web.api.query_cancel_stale_drop.json +2 -1
  183. package/catalog/policies/policy.web.api.request_infrastructure.json +2 -1
  184. package/catalog/policies/policy.web.api.retry_discipline.json +2 -1
  185. package/catalog/policies/policy.web.api.session_recovery_split.json +2 -1
  186. package/catalog/policies/policy.web.api.single_http_client.json +2 -1
  187. package/catalog/policies/policy.web.api.single_loading_source.json +2 -1
  188. package/catalog/policies/policy.web.api.transport_vs_business.json +2 -1
  189. package/catalog/policies/policy.web.api.trusted_endpoint_source.json +2 -1
  190. package/catalog/policies/policy.web.api.typed_domain_naming.json +2 -1
  191. package/catalog/policies/policy.web.arch.layer_isolation.json +2 -1
  192. package/catalog/policies/policy.web.arch.naming_conventions.json +2 -1
  193. package/catalog/policies/policy.web.arch.public_api_barrel.json +2 -1
  194. package/catalog/policies/policy.web.chg.controlled_change_triggers.json +2 -1
  195. package/catalog/policies/policy.web.comp.no_trivial_or_god_component.json +91 -0
  196. package/catalog/policies/policy.web.comp.public_contract_completeness.json +93 -0
  197. package/catalog/policies/policy.web.copy.action_object_clarity.json +92 -0
  198. package/catalog/policies/policy.web.copy.enumerable_placement.json +91 -0
  199. package/catalog/policies/policy.web.copy.error_next_step.json +92 -0
  200. package/catalog/policies/policy.web.copy.suppression_ledger_discipline.json +2 -1
  201. package/catalog/policies/policy.web.grid.column_schema_fields.json +2 -1
  202. package/catalog/policies/policy.web.grid.config_isolation.json +2 -1
  203. package/catalog/policies/policy.web.grid.freeze_key_columns.json +2 -1
  204. package/catalog/policies/policy.web.grid.interaction_registry.json +2 -1
  205. package/catalog/policies/policy.web.grid.keyboard_clipboard.json +2 -1
  206. package/catalog/policies/policy.web.grid.schema_driven_shell.json +2 -1
  207. package/catalog/policies/policy.web.grid.schema_versioning.json +2 -1
  208. package/catalog/policies/policy.web.grid.server_ops_virtualization.json +2 -1
  209. package/catalog/policies/policy.web.grid.shell_change_matrix.json +2 -1
  210. package/catalog/policies/policy.web.grid.width_fix_ladder.json +2 -1
  211. package/catalog/policies/policy.web.handoff.state_matrix_full.json +94 -0
  212. package/catalog/policies/policy.web.i18n.copy_key_discipline.json +92 -0
  213. package/catalog/policies/policy.web.i18n.raw_value_for_compute.json +91 -0
  214. package/catalog/policies/policy.web.page.region_consistency.json +93 -0
  215. package/catalog/policies/policy.web.perf.budget_skeleton.json +2 -1
  216. package/catalog/policies/policy.web.style.ownership_matrix.json +2 -1
  217. package/catalog/policies/policy.web.track.attempt_result_correlation.json +91 -0
  218. package/catalog/policies/policy.web.track.consent_lifecycle.json +2 -1
  219. package/catalog/policies/policy.web.track.no_synthetic_actions.json +92 -0
  220. package/catalog/policies/policy.web.track.privacy_default_deny.json +2 -1
  221. package/catalog/policies/policy.web.track.stable_event_keys.json +2 -1
  222. package/catalog/policies/policy.web.track.typed_client_validation.json +91 -0
  223. package/catalog/policies/policy.web.uiux.provider_evidence_not_business_truth.json +2 -1
  224. package/catalog/policies/policy.wf.no_planned_as_verified.json +91 -0
  225. package/catalog/policies/policy.wf.task_facts_preconfirm.json +94 -0
  226. package/catalog/policies/profile.baseline.java_enterprise_default.json +96 -0
  227. package/catalog/sensors/sensor.browser.deterministic.json +2 -1
  228. package/catalog/sensors/sensor.browser.interactive.json +2 -1
  229. package/catalog/sensors/sensor.build.static.json +2 -1
  230. package/catalog/sensors/sensor.contract.conformance.json +2 -1
  231. package/catalog/sensors/sensor.performance.budget.json +2 -1
  232. package/catalog/sensors/sensor.production.metric.json +2 -1
  233. package/catalog/tools/seed_b6b_frontend.py +1424 -0
  234. package/catalog/tools/seed_b6c_backend.py +1495 -0
  235. package/catalog/tools/seed_b6d_baseline.py +620 -0
  236. package/catalog/tools/seed_b6e_evidence.py +1305 -0
  237. package/catalog/tools/seed_d3_review.py +1105 -0
  238. package/catalog/tools/seed_v06_batch2_materials.py +27 -18
  239. package/dist/bin.js +23026 -16635
  240. package/package.json +2 -1
  241. package/seeds/baseline/backend/api-contract.md +26 -0
  242. package/seeds/baseline/backend/architecture.md +31 -0
  243. package/seeds/baseline/backend/data-access.md +31 -0
  244. package/seeds/baseline/backend/directory-structure.md +11 -0
  245. package/seeds/baseline/backend/integration-runtime.md +21 -0
  246. package/seeds/baseline/backend/quality.md +31 -0
  247. package/seeds/baseline/backend/stack.yaml +13 -0
  248. package/seeds/baseline/backend/transaction-concurrency.md +26 -0
  249. package/seeds/baseline/data/lineage.md +11 -0
  250. package/seeds/baseline/data/migration.md +11 -0
  251. package/seeds/baseline/data/model.md +31 -0
  252. package/seeds/baseline/data/precision-units.md +31 -0
  253. package/seeds/baseline/data/quality.md +31 -0
  254. package/seeds/baseline/frontend/api-and-error.md +21 -0
  255. package/seeds/baseline/frontend/architecture.md +26 -0
  256. package/seeds/baseline/frontend/design-system.md +21 -0
  257. package/seeds/baseline/frontend/directory-structure.md +16 -0
  258. package/seeds/baseline/frontend/quality.md +26 -0
  259. package/seeds/baseline/frontend/stack.yaml +17 -0
  260. package/seeds/baseline/frontend/state-and-data.md +26 -0
  261. package/seeds/baseline/manifest.yaml +32 -0
  262. package/seeds/baseline/platform/delivery.md +36 -0
  263. package/seeds/baseline/platform/environment.md +11 -0
  264. package/seeds/baseline/platform/observability.md +31 -0
  265. package/seeds/baseline/platform/security.md +26 -0
  266. package/seeds/manifest.json +2006 -0
  267. package/seeds/specs/evidence/accessibility.md +89 -0
  268. package/seeds/specs/evidence/architecture.md +89 -0
  269. package/seeds/specs/evidence/browser-e2e.md +91 -0
  270. package/seeds/specs/evidence/build.md +91 -0
  271. package/seeds/specs/evidence/business-acceptance.md +89 -0
  272. package/seeds/specs/evidence/complexity-crap.md +97 -0
  273. package/seeds/specs/evidence/contract.md +89 -0
  274. package/seeds/specs/evidence/coverage.md +91 -0
  275. package/seeds/specs/evidence/data-migration.md +91 -0
  276. package/seeds/specs/evidence/dead-code-duplicate.md +89 -0
  277. package/seeds/specs/evidence/dependency-supply-chain.md +89 -0
  278. package/seeds/specs/evidence/index.md +55 -0
  279. package/seeds/specs/evidence/mutation.md +89 -0
  280. package/seeds/specs/evidence/performance.md +89 -0
  281. package/seeds/specs/evidence/release.md +91 -0
  282. package/seeds/specs/evidence/runtime-observability.md +91 -0
  283. package/seeds/specs/evidence/security.md +89 -0
  284. package/seeds/specs/evidence/typecheck-lint.md +91 -0
  285. package/seeds/specs/evidence/unit-component-integration.md +91 -0
  286. package/seeds/specs/evidence/visual-regression.md +89 -0
  287. package/seeds/specs/hard/backend/01-architecture-governance-protocol.md +68 -0
  288. package/seeds/specs/hard/backend/02-project-structure-governance-protocol.md +68 -0
  289. package/seeds/specs/hard/backend/03-directory-boundary-protocol.md +68 -0
  290. package/seeds/specs/hard/backend/04-layering-architecture-protocol.md +68 -0
  291. package/seeds/specs/hard/backend/05-task-workflow-protocol.md +68 -0
  292. package/seeds/specs/hard/backend/06-ai-generated-code-protocol.md +68 -0
  293. package/seeds/specs/hard/backend/07-evidence-acceptance-protocol.md +68 -0
  294. package/seeds/specs/hard/backend/08-contract-change-protocol.md +68 -0
  295. package/seeds/specs/hard/backend/09-role-responsibility-protocol.md +68 -0
  296. package/seeds/specs/hard/backend/10-security-protocol.md +68 -0
  297. package/seeds/specs/hard/backend/11-environment-configuration-protocol.md +67 -0
  298. package/seeds/specs/hard/backend/12-api-contract-protocol.md +68 -0
  299. package/seeds/specs/hard/backend/13-privacy-data-lifecycle-protocol.md +68 -0
  300. package/seeds/specs/hard/backend/14-business-rules-state-protocol.md +68 -0
  301. package/seeds/specs/hard/backend/15-data-model-protocol.md +68 -0
  302. package/seeds/specs/hard/backend/16-error-code-protocol.md +68 -0
  303. package/seeds/specs/hard/backend/17-permission-authorization-protocol.md +68 -0
  304. package/seeds/specs/hard/backend/18-database-schema-migration-protocol.md +68 -0
  305. package/seeds/specs/hard/backend/19-query-index-sql-protocol.md +68 -0
  306. package/seeds/specs/hard/backend/20-transaction-boundary-protocol.md +68 -0
  307. package/seeds/specs/hard/backend/21-concurrency-locking-protocol.md +68 -0
  308. package/seeds/specs/hard/backend/22-idempotency-protocol.md +68 -0
  309. package/seeds/specs/hard/backend/23-cache-redis-consistency-protocol.md +68 -0
  310. package/seeds/specs/hard/backend/24-external-integration-resilience-protocol.md +68 -0
  311. package/seeds/specs/hard/backend/25-async-job-scheduler-protocol.md +68 -0
  312. package/seeds/specs/hard/backend/26-engineering-tooling-protocol.md +68 -0
  313. package/seeds/specs/hard/backend/27-dependency-supply-chain-protocol.md +68 -0
  314. package/seeds/specs/hard/backend/28-testing-protocol.md +68 -0
  315. package/seeds/specs/hard/backend/29-observability-logging-tracing-protocol.md +68 -0
  316. package/seeds/specs/hard/backend/30-performance-capacity-protocol.md +68 -0
  317. package/seeds/specs/hard/backend/31-runtime-deployment-protocol.md +68 -0
  318. package/seeds/specs/hard/backend/32-release-versioning-rollback-protocol.md +68 -0
  319. package/seeds/specs/hard/backend/index.md +177 -0
  320. package/seeds/specs/hard/frontend/01-development-checklist-protocol.md +86 -0
  321. package/seeds/specs/hard/frontend/02-ai-generated-code-protocol.md +82 -0
  322. package/seeds/specs/hard/frontend/03-acceptance-gate-protocol.md +86 -0
  323. package/seeds/specs/hard/frontend/04-security-protocol.md +283 -0
  324. package/seeds/specs/hard/frontend/05-environment-configuration-protocol.md +80 -0
  325. package/seeds/specs/hard/frontend/06-change-governance-protocol.md +90 -0
  326. package/seeds/specs/hard/frontend/07-frontend-backend-communication-protocol.md +219 -0
  327. package/seeds/specs/hard/frontend/08-role-responsibility-protocol.md +80 -0
  328. package/seeds/specs/hard/frontend/09-module-boundary-protocol.md +81 -0
  329. package/seeds/specs/hard/frontend/10-engineering-tooling-protocol.md +89 -0
  330. package/seeds/specs/hard/frontend/11-dependency-package-management-protocol.md +87 -0
  331. package/seeds/specs/hard/frontend/12-business-rules-protocol.md +79 -0
  332. package/seeds/specs/hard/frontend/13-monetary-precision-protocol.md +81 -0
  333. package/seeds/specs/hard/frontend/14-data-model-protocol.md +85 -0
  334. package/seeds/specs/hard/frontend/15-request-api-protocol.md +87 -0
  335. package/seeds/specs/hard/frontend/16-error-handling-protocol.md +79 -0
  336. package/seeds/specs/hard/frontend/17-permission-protocol.md +79 -0
  337. package/seeds/specs/hard/frontend/18-state-management-protocol.md +88 -0
  338. package/seeds/specs/hard/frontend/19-cache-protocol.md +79 -0
  339. package/seeds/specs/hard/frontend/20-testing-protocol.md +88 -0
  340. package/seeds/specs/hard/frontend/21-design-system-protocol.md +79 -0
  341. package/seeds/specs/hard/frontend/22-theme-protocol.md +79 -0
  342. package/seeds/specs/hard/frontend/23-accessibility-protocol.md +189 -0
  343. package/seeds/specs/hard/frontend/24-component-protocol.md +80 -0
  344. package/seeds/specs/hard/frontend/25-page-structure-protocol.md +79 -0
  345. package/seeds/specs/hard/frontend/26-style-layout-protocol.md +80 -0
  346. package/seeds/specs/hard/frontend/27-rendering-state-protocol.md +81 -0
  347. package/seeds/specs/hard/frontend/28-form-protocol.md +88 -0
  348. package/seeds/specs/hard/frontend/29-routing-url-protocol.md +79 -0
  349. package/seeds/specs/hard/frontend/30-data-grid-protocol.md +83 -0
  350. package/seeds/specs/hard/frontend/31-performance-protocol.md +137 -0
  351. package/seeds/specs/hard/frontend/32-file-import-export-protocol.md +80 -0
  352. package/seeds/specs/hard/frontend/33-release-versioning-protocol.md +79 -0
  353. package/seeds/specs/hard/frontend/34-monitoring-logging-protocol.md +128 -0
  354. package/seeds/specs/hard/frontend/35-mock-protocol.md +97 -0
  355. package/seeds/specs/hard/frontend/36-feature-flag-protocol.md +79 -0
  356. package/seeds/specs/hard/frontend/37-browser-device-compatibility-protocol.md +83 -0
  357. package/seeds/specs/hard/frontend/38-internationalization-protocol.md +243 -0
  358. package/seeds/specs/hard/frontend/39-copywriting-protocol.md +79 -0
  359. package/seeds/specs/hard/frontend/40-analytics-protocol.md +98 -0
  360. package/seeds/specs/hard/frontend/41-design-handoff-protocol.md +80 -0
  361. package/seeds/specs/hard/frontend/42-browser-runtime-lifecycle-protocol.md +86 -0
  362. package/seeds/specs/hard/frontend/43-time-temporal-protocol.md +86 -0
  363. package/seeds/specs/hard/frontend/44-privacy-data-lifecycle-protocol.md +87 -0
  364. package/seeds/specs/hard/frontend/45-browser-storage-protocol.md +87 -0
  365. package/seeds/specs/hard/frontend/index.md +308 -0
  366. package/seeds/specs/hard/stacks/java/index.md +20 -0
  367. package/seeds/specs/hard/stacks/java/java-language-overlay.md +35 -0
  368. package/seeds/specs/hard/stacks/jpa/index.md +20 -0
  369. package/seeds/specs/hard/stacks/jpa/jpa-persistence-overlay.md +35 -0
  370. package/seeds/specs/hard/stacks/kubernetes-ingress/index.md +20 -0
  371. package/seeds/specs/hard/stacks/kubernetes-ingress/kubernetes-ingress-overlay.md +35 -0
  372. package/seeds/specs/hard/stacks/messaging/index.md +20 -0
  373. package/seeds/specs/hard/stacks/messaging/messaging-reliability-overlay.md +35 -0
  374. package/seeds/specs/hard/stacks/mybatis/index.md +20 -0
  375. package/seeds/specs/hard/stacks/mybatis/mybatis-persistence-overlay.md +35 -0
  376. package/seeds/specs/hard/stacks/mysql/index.md +20 -0
  377. package/seeds/specs/hard/stacks/mysql/mysql-database-overlay.md +35 -0
  378. package/seeds/specs/hard/stacks/nginx/index.md +20 -0
  379. package/seeds/specs/hard/stacks/nginx/nginx-proxy-overlay.md +35 -0
  380. package/seeds/specs/hard/stacks/postgresql/index.md +20 -0
  381. package/seeds/specs/hard/stacks/postgresql/postgresql-database-overlay.md +35 -0
  382. package/seeds/specs/hard/stacks/redis/index.md +20 -0
  383. package/seeds/specs/hard/stacks/redis/redis-cache-overlay.md +35 -0
  384. package/seeds/specs/hard/stacks/spring-batch/index.md +20 -0
  385. package/seeds/specs/hard/stacks/spring-batch/spring-batch-job-overlay.md +35 -0
  386. package/seeds/specs/hard/stacks/spring-boot/index.md +20 -0
  387. package/seeds/specs/hard/stacks/spring-boot/spring-boot-application-overlay.md +35 -0
  388. package/seeds/specs/hard/stacks/spring-mvc/index.md +20 -0
  389. package/seeds/specs/hard/stacks/spring-mvc/spring-mvc-web-overlay.md +35 -0
  390. package/seeds/specs/hard/stacks/spring-webflux/index.md +20 -0
  391. package/seeds/specs/hard/stacks/spring-webflux/spring-webflux-reactive-overlay.md +35 -0
  392. package/seeds/specs/hard/stacks/tomcat/index.md +20 -0
  393. package/seeds/specs/hard/stacks/tomcat/tomcat-runtime-overlay.md +35 -0
@@ -0,0 +1,1105 @@
1
+ # -*- coding: utf-8 -*-
2
+ """裁定批 F/G——D3 排除卡逐卡复核物化工具(Owner 2026-09-05 裁定 D3=逐卡复核;台账
3
+ corpus/master/cutover/owner-adjudications.md 裁决 13 + 裁决 14)。
4
+
5
+ 背景:B6b-I/B6b-II/B6c 播种移植批按「不猜 Owner 意图」保守排除 72 张池卡留池待复核
6
+ (B6b-I 3 + B6b-II 9 + B6c 60)。本工具执行 D3 逐卡复核全部两轮结论:
7
+ - 维持排除 30 张:Ownership 段锚族(锚行=权责归属默认分配陈述,「X Owner 维护 Y」
8
+ 词形,零行为规范成分;归属语义由 catalog authority 轴/owner_registry 既有机制与
9
+ 播种件正文承载,不入 policy 强度面)——D3_EXCLUDED_KEEP 常量在册;
10
+ - 入册 25 张(D3-R1 轮,裁定批 F 物化):required 9(D3b 补锚 MUST/MUST NOT)+
11
+ advisory 16(Change Policy 锚 14 张降 advisory[行内容含「必须」行为规范、强度只降
12
+ 不升] + 密度序前 2 张:REGISTRY 扩展段锚 / FE04 Change Policy 锚);
13
+ - 入册 17 张(D3-R2 轮,裁定批 G 物化):R1 后按池密度序余量 17 张 advisory 全量
14
+ 入册——SHOULD 锚 13(卡层行锚缺席,复核回 MASTer 源取得行级证据:B6c BE-G4 六 +
15
+ BE-G3 七)+ 非 12 段锚 4(B6b-II FE index 2 / B6c BE index 冲突优先序 1[extra_
16
+ master_sections 如实登记] + B6b-I FE20 Change Policy 锚 1);17 ≤ D6 合并上限
17
+ 25/批满足。
18
+
19
+ 输入(只读):
20
+ - corpus/spec-knowledge/candidates/consolidated-pool.yaml SPEC-D 汇总池(池行对账)
21
+ - corpus/spec-knowledge/candidates/{BE-G1,BE-G2,BE-G3,BE-G4,FE-G1}.yaml 候选组卡
22
+ - MASTer_master/.trellis/spec/{frontend,backend}/ 池卡行锚分母(锚核验+LCS)
23
+ - pomaster/components/{frontend,backend}-hard-spec/assets/ vendor 播种字节(pin)
24
+
25
+ 输出:
26
+ - catalog/policies/policy.*.json D3-R1 25 + D3-R2 17(x-b6-porting
27
+ batch="D3-R1"/"D3-R2" + d3_review 复核注记);R1 轮 8 条 AUTHZ/PRV/ERR 的 x-vocab-pr
28
+ 候选注记已随 PR-0010 转正(resolution 注记,v0.9-resolved);R2 轮新用域段 BE 的 7 条
29
+ 带新 x-vocab-pr 候选注记(PR-0010 后新段沿用候选注记先例,词汇表 PR 增补)
30
+
31
+ 用法:
32
+ python seed_d3_review.py # 物化(write_if_changed 幂等)
33
+ python seed_d3_review.py --verify # 只读重演(字节逐等比对)
34
+ """
35
+
36
+ import hashlib
37
+ import io
38
+ import json
39
+ import os
40
+ import re
41
+ import sys
42
+
43
+ import yaml
44
+
45
+ if __name__ == "__main__":
46
+ try:
47
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
48
+ except Exception:
49
+ pass
50
+
51
+ HERE = os.path.dirname(os.path.abspath(__file__))
52
+ VNEXT = os.path.dirname(os.path.dirname(HERE))
53
+ REPO = os.path.dirname(VNEXT)
54
+ MASTER_FE = os.path.join(os.path.dirname(REPO), "MASTer_master", ".trellis", "spec",
55
+ "frontend")
56
+ MASTER_BE = os.path.join(os.path.dirname(REPO), "MASTer_master", ".trellis", "spec",
57
+ "backend")
58
+ FE_VENDOR = os.path.join(REPO, "pomaster", "components", "frontend-hard-spec",
59
+ "assets", "universal")
60
+ BE_VENDOR = os.path.join(REPO, "pomaster", "components", "backend-hard-spec",
61
+ "assets", "universal")
62
+ CAND_DIR = os.path.join(VNEXT, "corpus", "spec-knowledge", "candidates")
63
+ POOL_PATH = os.path.join(CAND_DIR, "consolidated-pool.yaml")
64
+ POLICY_DIR = os.path.join(VNEXT, "catalog", "policies")
65
+
66
+ BATCH = "D3-R1"
67
+ BATCH_R2 = "D3-R2"
68
+ BATCH_LABEL = "裁定批 F/D3-R1"
69
+ BATCH_LABEL_R2 = "裁定批 G/D3-R2"
70
+ CURATED_RULE = (
71
+ "D3 逐卡复核批(Owner 2026-09-05 裁定 D3=逐卡复核;72 张保守排除卡逐卡核锚):"
72
+ "required 9(D3b source=null 补锚落 MUST/MUST NOT 且与 MASTer 行锚交叉验证)+ "
73
+ "advisory 16(Change Policy 锚 14 张降 advisory[行内容含「必须」行为规范、强度只降"
74
+ "不升] + 池密度序前 2)= 25(D6 合并上限 policy+TP 合计 25/批内执行;超出 17 张 "
75
+ "advisory 留 D3-R2 轮次台账);维持排除 30(Ownership 归属说明族)"
76
+ )
77
+ CURATED_RULE_R2 = (
78
+ "D3 逐卡复核批 R2 轮(Owner 2026-09-05 裁定 D3=逐卡复核;裁定批 G 收尾批):"
79
+ "R1 入册 25(required 9 + advisory 16)后余量 17 张 advisory 全量入册——SHOULD 锚 13"
80
+ "(卡层行锚缺席,复核回 MASTer 源取得行级证据:B6c BE-G4 六 + BE-G3 七)+ 非 12 段锚 "
81
+ "4(B6b-II FE index 2 / B6c BE index 冲突优先序 1 / B6b-I FE20 Change Policy 锚 1,"
82
+ "extra_master_sections 如实登记);全部 advisory(池判 required 卡强度只降不升);"
83
+ "D6 合并口径 ≤25/批满足(17 ≤ 25);72 张总账=R1 25 + R2 17 + 维持排除 30"
84
+ )
85
+ POOL_REL = "POMaster_VNext/corpus/spec-knowledge/candidates/consolidated-pool.yaml"
86
+ CLEAN_ROOM_NOTE = ("independently rewritten from SPEC-D decomposition candidate cards; "
87
+ "zero verbatim copy")
88
+ LCS_THRESHOLD = 20
89
+ D5_CAP_PER_BATCH = 25
90
+
91
+ # PR-0009 已收编 policy id 域段(vocab-lock@v0.8-resolved catalog_layer_vocab.
92
+ # policy_id_domains 32 段 + policy_web_domains 13 段)。D3-R1 新用域段(AUTHZ/PRV/ERR)
93
+ # 的 8 条候选注记已随 PR-0010 转正(vocab-lock@v0.9-resolved 35 段——裁定批 G);
94
+ # D3-R2 新用域段(BE)走 x-vocab-pr 候选注记(B6b/B6c/D3-R1 先例——新段待词汇表 PR 增补)。
95
+ REGISTERED_DOMAINS = {
96
+ "AI", "API", "ARCH", "BOUND", "BOUNDARY", "CACHE", "CFG", "CHG", "CONFLICT",
97
+ "CONTRACT", "DEP", "DEPLOY", "DERIVED", "EVID", "FLAG", "GATE", "GUARD",
98
+ "INTEGRATION", "JOB", "OBS", "PERF", "PROC", "REL", "ROLE", "SEC", "SPEC",
99
+ "STACK", "STRUCT", "TEST", "TOOL", "WEB", "WF",
100
+ # PR-0010(vocab-lock@v0.9-resolved,裁定批 G)收编 D3-R1 三域段。
101
+ "AUTHZ", "PRV", "ERR",
102
+ }
103
+ NEW_DOMAINS_IN_BATCH_R1 = {"AUTHZ", "PRV", "ERR"} # 已随 PR-0010 转正(resolution 注记)。
104
+ NEW_DOMAINS_IN_BATCH_R2 = {"BE"} # R2 新用域段——候选注记在册待词汇表 PR。
105
+
106
+ # PR-0010 转正词形(裁定批 G;与 b6b/b6c 工具 VOCAB_PR_RESOLUTION_* 同款常量纳编先例——
107
+ # 保工具单源重演语义;与 catalog/policies 在册 8 条 resolution 逐字节一致)。
108
+ VOCAB_PR_0010_RESOLUTION = (
109
+ "2026-09-05 vocab PR-0010 增补落地(vocab-lock@v0.9-resolved,append-only 纯增量;"
110
+ "Owner 2026-09-05 第二轮裁定开放项 2 全做——裁定批 G 收尾批):AUTHZ/PRV/ERR 三 id "
111
+ "域段随 catalog_layer_vocab.policy_id_domains 扩值收编(32→35 段,与 PR-0009 同轴"
112
+ "追加,词值零改动);本 pending 注记就此转正(finding/proposal/locked_vocab_untouched "
113
+ "为创建时点历史记录原样保留——mcp_eyes 先例)"
114
+ )
115
+
116
+ D3_EXCLUSION_NOTE = (
117
+ "D3 逐卡复核(Owner 2026-09-05 裁定 D3=逐卡复核,裁定批 F 落地 2026-09-05):本卡"
118
+ "原属 {origin} 保守排除留池(排除理由:{reason});复核补锚回 vendor/MASTer 源取得"
119
+ "行级证据,锚段={sections},按强度入册({basis})"
120
+ )
121
+ D3_EXCLUSION_NOTE_FE = (
122
+ "D3 逐卡复核(Owner 2026-09-05 裁定 D3=逐卡复核,裁定批 F 落地 2026-09-05):本卡"
123
+ "原属 B6B-1 保守排除留池(排除理由:{reason});复核按锚行内容裁定 advisory 入册"
124
+ "({basis})"
125
+ )
126
+ # R2 轮(裁定批 G)复核注记——R1 模板字节冻结不动(在册 25 条重演恒等),R2 用独立模板。
127
+ D3_R2_EXCLUSION_NOTE = (
128
+ "D3 逐卡复核 R2 轮(Owner 2026-09-05 裁定 D3=逐卡复核,裁定批 G 落地 2026-09-05):"
129
+ "本卡原属 {origin} 保守排除留池(排除理由:{reason});复核补锚回 MASTer 源取得行级"
130
+ "证据,锚段={sections},按强度入册({basis})"
131
+ )
132
+ D3_R2_EXCLUSION_NOTE_FE = (
133
+ "D3 逐卡复核 R2 轮(Owner 2026-09-05 裁定 D3=逐卡复核,裁定批 G 落地 2026-09-05):"
134
+ "本卡原属 {origin} 保守排除留池(排除理由:{reason});复核按锚行内容裁定 advisory "
135
+ "入册({basis})"
136
+ )
137
+
138
+ # ----------------------------------------------------------------------
139
+ # D3-R1 入册 25 张(逐卡复核结论单源;section/lines = 复核锚,禁止凭印象——
140
+ # 工具启动时对每张卡做 MASTer 行锚 ↔ 声明段交叉验证 + 锚行原文在座断言)。
141
+ # 元组:(id, group, origin_batch, master_file, lines, sections, reason_key, title);
142
+ # enforcement 由 sections 推导(MUST/MUST NOT 锚 = required,其余 = advisory)。
143
+ # ----------------------------------------------------------------------
144
+ # ---- required 9(D3b source=null 补锚:MUST/MUST NOT 段行锚)----
145
+ _D3_REQUIRED = [
146
+ ("POLICY.SEC.TRUST_BOUNDARY_ENFORCEMENT", "BE-G2", "B6C",
147
+ "10-security-protocol.md", "25", ["MUST"], "source_null",
148
+ "信任边界服务端四动作"),
149
+ ("POLICY.SEC.NO_CLIENT_SIDE_TRUST", "BE-G2", "B6C",
150
+ "10-security-protocol.md", "29", ["MUST NOT"], "source_null",
151
+ "客户端信号不作授权依据"),
152
+ ("POLICY.CFG.CONFIG_ATTRIBUTE_COMPLETENESS", "BE-G2", "B6C",
153
+ "11-environment-configuration-protocol.md", "25", ["MUST"], "source_null",
154
+ "配置登记六要素齐备"),
155
+ ("POLICY.CFG.NO_SECRET_DISPERSAL", "BE-G2", "B6C",
156
+ "11-environment-configuration-protocol.md", "29", ["MUST NOT"], "source_null",
157
+ "机密不落五类持久化面"),
158
+ ("POLICY.AUTHZ.SERVER_FIVE_FACTOR_VERIFICATION", "BE-G2", "B6C",
159
+ "17-permission-authorization-protocol.md", "25", ["MUST"], "source_null",
160
+ "受保护操作五元核验"),
161
+ ("POLICY.AUTHZ.NO_GATING_PROXY_TRUST", "BE-G2", "B6C",
162
+ "17-permission-authorization-protocol.md", "29", ["MUST NOT"], "source_null",
163
+ "门禁表象不作授权凭据"),
164
+ ("POLICY.PRV.SENSITIVE_DATA_SIX_FACTS", "BE-G2", "B6C",
165
+ "13-privacy-data-lifecycle-protocol.md", "25", ["MUST"], "source_null",
166
+ "敏感数据入场六事实登记"),
167
+ ("POLICY.ERR.FAILURE_FIVE_PART_MAPPING", "BE-G2", "B6C",
168
+ "16-error-code-protocol.md", "25", ["MUST"], "source_null",
169
+ "失败响应五成分构成"),
170
+ ("POLICY.ERR.NO_INTERNAL_DETAIL_EXPOSURE", "BE-G2", "B6C",
171
+ "16-error-code-protocol.md", "29", ["MUST NOT"], "source_null",
172
+ "错误响应禁内部细节泄露"),
173
+ ]
174
+ # ---- advisory 14(Change Policy 锚:行内容含「必须」行为规范,强度只降不升)----
175
+ _D3_CP_ADVISORY = [
176
+ ("POLICY.OBS.SIGNAL_CHANGE_IMPACT", "BE-G4", "B6C",
177
+ "29-observability-logging-tracing-protocol.md", "57", ["Change Policy"],
178
+ "change_policy", "观测信号变更先评影响"),
179
+ ("POLICY.PERF.BUDGET_CHANGE_RETEST", "BE-G4", "B6C",
180
+ "30-performance-capacity-protocol.md", "57", ["Change Policy"],
181
+ "change_policy", "性能预算变更须复测"),
182
+ ("POLICY.CACHE.SCHEMA_VERSIONING", "BE-G4", "B6C",
183
+ "23-cache-redis-consistency-protocol.md", "57", ["Change Policy"],
184
+ "change_policy", "缓存结构变更版本化"),
185
+ ("POLICY.ARCH.ADR_IMMUTABLE_HISTORY", "BE-G1", "B6C",
186
+ "01-architecture-governance-protocol.md", "57", ["Change Policy"],
187
+ "change_policy", "架构结论禁静默改写"),
188
+ ("POLICY.TOOL.UPGRADE_VERIFY_LOCK_ROLLBACK", "BE-G1", "B6C",
189
+ "26-engineering-tooling-protocol.md", "57", ["Change Policy"],
190
+ "change_policy", "工具升级验证与回退"),
191
+ ("POLICY.EVID.NO_SILENT_GATE_REMOVAL", "BE-G1", "B6C",
192
+ "07-evidence-acceptance-protocol.md", "57", ["Change Policy"],
193
+ "change_policy", "证据要求降级走受控例外"),
194
+ ("POLICY.REL.PROCESS_CHANGE_NEEDS_DRILL_AUDIT", "BE-G1", "B6C",
195
+ "32-release-versioning-rollback-protocol.md", "57", ["Change Policy"],
196
+ "change_policy", "发布流程变化先演练审计"),
197
+ ("POLICY.DEP.TIME_BOXED_URGENT_EXCEPTION", "BE-G1", "B6C",
198
+ "27-dependency-supply-chain-protocol.md", "57", ["Change Policy"],
199
+ "change_policy", "紧急漏洞例外限时追踪"),
200
+ ("POLICY.TEST.REMOVAL_NEEDS_SUBSTITUTE_EVIDENCE", "BE-G1", "B6C",
201
+ "28-testing-protocol.md", "57", ["Change Policy"],
202
+ "change_policy", "测试删除须替代证据"),
203
+ ("POLICY.PRV.PROCESSING_SCOPE_RE_REVIEW", "BE-G2", "B6C",
204
+ "13-privacy-data-lifecycle-protocol.md", "57", ["Change Policy"],
205
+ "source_null", "处理扩围重履三评审"),
206
+ ("POLICY.AUTHZ.PERMISSION_SCOPE_EXPANSION_GATE", "BE-G2", "B6C",
207
+ "17-permission-authorization-protocol.md", "57", ["Change Policy"],
208
+ "source_null", "权限扩围三道手续"),
209
+ ("POLICY.SEC.SECURITY_RELAXATION_GATE", "BE-G2", "B6C",
210
+ "10-security-protocol.md", "57", ["Change Policy"],
211
+ "source_null", "安全放宽三重手续"),
212
+ ("POLICY.CFG.KEY_RENAME_DUAL_READ", "BE-G2", "B6C",
213
+ "11-environment-configuration-protocol.md", "57", ["Change Policy"],
214
+ "source_null", "配置键更名双读过渡"),
215
+ ("POLICY.ERR.PUBLISHED_CODE_IMMUTABLE", "BE-G2", "B6C",
216
+ "16-error-code-protocol.md", "57", ["Change Policy"],
217
+ "source_null", "已发布错误码不复用"),
218
+ ]
219
+ # ---- advisory 2(池密度序前 2:32.88 / 32.31;B6B-1 原排除卡)----
220
+ _D3_ADVISORY_B6B = [
221
+ ("POLICY.REGISTRY.HUMAN_FIELDS_VALIDATED_DECORRELATED", "FE-G1", "B6B-1",
222
+ "10-engineering-tooling-protocol.md", "L71-L74",
223
+ ["本地 ESLint 规则与 Registry 校验"], "extra_section",
224
+ "人工裁决字段独立校验"),
225
+ ("POLICY.SEC.RELAXATION_APPROVAL", "FE-G1", "B6B-1",
226
+ "04-security-protocol.md", "L84", ["Change Policy"], "change_policy",
227
+ "安全放宽三要素与优先级"),
228
+ ]
229
+ D3_REGISTERED = _D3_REQUIRED + _D3_CP_ADVISORY + _D3_ADVISORY_B6B
230
+ D3_REQUIRED_CAP = 9
231
+
232
+
233
+ def registered_enforcement(sections):
234
+ if any(s in ("MUST", "MUST NOT") for s in sections):
235
+ return "required_when_applicable"
236
+ return "advisory"
237
+
238
+
239
+ # 逐卡人工审定 clean-room 审注(零语义重复判定基准 = B6c 落地后的 228 条现目)。
240
+ REVIEW_NOTES = {
241
+ "POLICY.SEC.TRUST_BOUNDARY_ENFORCEMENT": [
242
+ "信任边界四动作义务在既有 228 条中无对应条目(B6b-I BOUNDARY.VALIDATE_IN_ENCODE_OUT "
243
+ "管数据入口校验/出口编码通则,本管跨信任域提权的四动作闭环),零语义重复;与 "
244
+ "BOUNDARY.VALIDATE_IN_ENCODE_OUT 互引(通则/专项)。",
245
+ "D3b 补锚:卡层 source=null,复核回 MASTer 10-security-protocol.md L25(MUST 段)"
246
+ "取得行级证据,required 入册(强度沿池判原样)。",
247
+ ],
248
+ "POLICY.SEC.NO_CLIENT_SIDE_TRUST": [
249
+ "客户端信号不可作授权依据在既有 228 条中无对应条目(B6b-I SEC 族管秘密可见面与"
250
+ "凭据介质);与同批 AUTHZ.NO_GATING_PROXY_TRUST 同域相邻——彼管门禁表象(路由/"
251
+ "按钮),本管数据归属判定依据面,互引不合并。",
252
+ "D3b 补锚:MASTer 10-security-protocol.md L29(MUST NOT 段),required 入册。",
253
+ ],
254
+ "POLICY.CFG.CONFIG_ATTRIBUTE_COMPLETENESS": [
255
+ "配置登记六要素在既有 228 条中无对应条目;与 POLICY.CFG.SCHEMA_BACKED_CONFIG"
256
+ "(B6b-I:配置结构化定义与环境矩阵)相邻——彼管配置结构形态,本管逐项登记要素"
257
+ "完备性,互引不合并。",
258
+ "D3b 补锚:MASTer 11-environment-configuration-protocol.md L25(MUST 段)。",
259
+ ],
260
+ "POLICY.CFG.NO_SECRET_DISPERSAL": [
261
+ "secret 五类持久化面禁令在既有 228 条中无对应条目;与 B6b-I "
262
+ "SEC.NO_SECRETS_IN_CLIENT_SURFACE(客户端可见面)、SEC.NO_SCRIPT_READABLE_"
263
+ "CREDENTIALS(存储介质脚本可读性)互引(前端面/介质轴 vs 后端持久化面轴)。",
264
+ "D3b 补锚:MASTer 11-environment-configuration-protocol.md L29(MUST NOT 段)。",
265
+ ],
266
+ "POLICY.AUTHZ.SERVER_FIVE_FACTOR_VERIFICATION": [
267
+ "服务端五元核验在既有 228 条中无对应条目(AUTHZ 域段本批新用,待词汇表 PR);"
268
+ "与同批 NO_GATING_PROXY_TRUST 正交(正面核验义务 vs 客户端表象禁令),互引。",
269
+ "D3b 补锚:MASTer 17-permission-authorization-protocol.md L25(MUST 段)。",
270
+ ],
271
+ "POLICY.AUTHZ.NO_GATING_PROXY_TRUST": [
272
+ "客户端门禁表象禁令在既有 228 条中无对应条目;与同批 "
273
+ "SERVER_FIVE_FACTOR_VERIFICATION 互引(正反两面)。",
274
+ "D3b 补锚:MASTer 17-permission-authorization-protocol.md L29(MUST NOT 段)。",
275
+ ],
276
+ "POLICY.PRV.SENSITIVE_DATA_SIX_FACTS": [
277
+ "敏感数据六事实登记在既有 228 条中无对应条目(PRV 域段本批新用,待词汇表 PR;"
278
+ "B6b-II OBS.NO_SENSITIVE_RAW_VALUES 管遥测载荷不同轴)。",
279
+ "D3b 补锚:MASTer 13-privacy-data-lifecycle-protocol.md L25(MUST 段)。",
280
+ ],
281
+ "POLICY.ERR.FAILURE_FIVE_PART_MAPPING": [
282
+ "失败响应五成分在既有 228 条中无对应条目(ERR 域段本批新用,待词汇表 PR;"
283
+ "knowledge.api.example_stable_error_code 为示例知识非规则本体);与同批 "
284
+ "NO_INTERNAL_DETAIL_EXPOSURE 同协议正交(响应构成 vs 泄露禁令),互引。",
285
+ "D3b 补锚:MASTer 16-error-code-protocol.md L25(MUST 段)。",
286
+ ],
287
+ "POLICY.ERR.NO_INTERNAL_DETAIL_EXPOSURE": [
288
+ "内部细节泄露禁令在既有 228 条中无对应条目;与同批 FAILURE_FIVE_PART_MAPPING "
289
+ "互引。",
290
+ "D3b 补锚:MASTer 16-error-code-protocol.md L29(MUST NOT 段)。",
291
+ ],
292
+ "POLICY.OBS.SIGNAL_CHANGE_IMPACT": [
293
+ "观测信号变更影响评估在既有 228 条中无对应条目;与 POLICY.CHG.* 族不同轴——彼管"
294
+ "业务变更过程协同,本管观测信号 schema/采样/保留自身的变更纪律。",
295
+ "Change Policy 锚(MASTer 29 L57,行内容含「必须」行为规范)——D3 复核按裁定"
296
+ "精神降 advisory 入册(池判 required 强度只降不升)。",
297
+ ],
298
+ "POLICY.PERF.BUDGET_CHANGE_RETEST": [
299
+ "性能预算变更复测在既有 228 条中无对应条目;与 B6b-II REL.OBSERVABILITY_BEFORE_"
300
+ "SHIP(监控前置物)互引不同时点。",
301
+ "Change Policy 锚(MASTer 30 L57)——降 advisory 入册(强度只降不升)。",
302
+ ],
303
+ "POLICY.CACHE.SCHEMA_VERSIONING": [
304
+ "缓存结构变更版本化与存量清退在既有 228 条中无对应条目;与 B6b-II "
305
+ "FLAG.CLEANUP_AFTER_FULL_ROLLOUT(存量清退语义)互引。",
306
+ "Change Policy 锚(MASTer 23 L57)——降 advisory 入册。",
307
+ ],
308
+ "POLICY.ARCH.ADR_IMMUTABLE_HISTORY": [
309
+ "决策记录禁静默改写在既有 228 条中无对应条目;与 kernel decision-graph 冻结纪律"
310
+ "(投影指纹 human_touch forbidden)语义呼应不同层。",
311
+ "Change Policy 锚(MASTer 01 L57)——降 advisory 入册。",
312
+ ],
313
+ "POLICY.TOOL.UPGRADE_VERIFY_LOCK_ROLLBACK": [
314
+ "工具升级四验证(兼容/锁文件/生成差异/回退)在既有 228 条中无对应条目;与 "
315
+ "POLICY.DEP.BUILD_PATH_SUPPLY_CHAIN(B6b-I 构建链路供应链)互引(升级时点专项)。",
316
+ "Change Policy 锚(MASTer 26 L57)——降 advisory 入册。",
317
+ ],
318
+ "POLICY.EVID.NO_SILENT_GATE_REMOVAL": [
319
+ "证据要求降低须受控例外在既有 228 条中无对应条目;与 B6b-I GATE.P0_NON_BYPASSABLE"
320
+ "(绕过禁令)、同批 REL.PROCESS_CHANGE_NEEDS_DRILL_AUDIT(发布门禁变化)构成门禁"
321
+ "变更三域族,互引不合并。",
322
+ "Change Policy 锚(MASTer 07 L57)——降 advisory 入册。",
323
+ ],
324
+ "POLICY.REL.PROCESS_CHANGE_NEEDS_DRILL_AUDIT": [
325
+ "发布流程变化先演练审计在既有 228 条中无对应条目;与 GATE.P0_NON_BYPASSABLE、"
326
+ "同批 NO_SILENT_GATE_REMOVAL 门禁变更三域族互引。",
327
+ "Change Policy 锚(MASTer 32 L57)——降 advisory 入册。",
328
+ ],
329
+ "POLICY.DEP.TIME_BOXED_URGENT_EXCEPTION": [
330
+ "紧急漏洞例外时限在既有 228 条中无对应条目;与 B6b-I SEC.NO_LONGTERM_SECURITY_"
331
+ "DISABLE(安全机制关闭须有期限)同族互引(依赖侧紧急例外 vs 安全机制临时关闭)。",
332
+ "Change Policy 锚(MASTer 27 L57)——降 advisory 入册。",
333
+ ],
334
+ "POLICY.TEST.REMOVAL_NEEDS_SUBSTITUTE_EVIDENCE": [
335
+ "测试删除须替代证据在既有 228 条中无对应条目;与 B6b-I TEST.STABLE_OBSERVABLE_"
336
+ "ASSERTIONS 不同轴(断言对象 vs 删除纪律);FE 侧同族卡 POLICY.TEST."
337
+ "REMOVAL_JUSTIFICATION 留 D3-R2(前后端同族互引随 R2 登记)。",
338
+ "Change Policy 锚(MASTer 28 L57)——降 advisory 入册。",
339
+ ],
340
+ "POLICY.PRV.PROCESSING_SCOPE_RE_REVIEW": [
341
+ "处理范围扩大重评审在既有 228 条中无对应条目;与同批 SENSITIVE_DATA_SIX_FACTS "
342
+ "同协议正交(入场登记 vs 扩围重评审),互引。",
343
+ "Change Policy 锚(MASTer 13 L57)——降 advisory 入册。",
344
+ ],
345
+ "POLICY.AUTHZ.PERMISSION_SCOPE_EXPANSION_GATE": [
346
+ "权限扩围三道手续在既有 228 条中无对应条目;与同批 SERVER_FIVE_FACTOR_"
347
+ "VERIFICATION 正交(运行时核验 vs 扩围准入),互引。",
348
+ "Change Policy 锚(MASTer 17 L57)——降 advisory 入册。",
349
+ ],
350
+ "POLICY.SEC.SECURITY_RELAXATION_GATE": [
351
+ "安全放宽三重手续在既有 228 条中无对应条目;与 B6b-I AI.RULE_RELAXATION_APPROVAL"
352
+ "(AI 禁令放宽)、同批 FE 侧 SEC.RELAXATION_APPROVAL(前端 lane)构成放宽批准"
353
+ "三域族,互引不合并。",
354
+ "Change Policy 锚(MASTer 10 L57)——降 advisory 入册。",
355
+ ],
356
+ "POLICY.CFG.KEY_RENAME_DUAL_READ": [
357
+ "配置键更名双读过渡在既有 228 条中无对应条目;与 POLICY.CHG.COMPAT_MIGRATION_"
358
+ "ROLLBACK(通用兼容迁移)不同轴(配置键专项),互引。",
359
+ "Change Policy 锚(MASTer 11 L57)——降 advisory 入册。",
360
+ ],
361
+ "POLICY.ERR.PUBLISHED_CODE_IMMUTABLE": [
362
+ "已发布错误码不复用在既有 228 条中无对应条目;与 B6b-II WEB.COPY.ERROR_NEXT_STEP"
363
+ "(错误文案三要素)不同轴;废弃兼容窗口与 knowledge.chg.example_compat_window "
364
+ "示例知识不同层。",
365
+ "Change Policy 锚(MASTer 16 L57)——降 advisory 入册。",
366
+ ],
367
+ "POLICY.REGISTRY.HUMAN_FIELDS_VALIDATED_DECORRELATED": [
368
+ "人工字段独立校验在既有 228 条中无对应条目;与 POLICY.TOOL."
369
+ "NO_HAND_EDIT_GENERATED_NO_CI_DRIFT(B6c:生成产物禁手改与门禁双标)相邻——彼管"
370
+ "产物手改禁令,本管人工字段与生成器解耦的独立校验义务,互引不合并。",
371
+ "锚落 MASTer 项目扩展段(本地 ESLint 规则与 Registry 校验,FE10 L71-L74)——"
372
+ "D3 复核按锚行内容行为规范(生成器覆盖/清空人工字段时独立校验即失败的断言义务)"
373
+ "advisory 入册,extra_master_sections 如实登记(池密度序 32.88 为 advisory 补位"
374
+ "第 1)。",
375
+ ],
376
+ "POLICY.SEC.RELAXATION_APPROVAL": [
377
+ "前端安全放宽三要素在既有 228 条中无对应条目;与 B6b-I AI.RULE_RELAXATION_"
378
+ "APPROVAL、本批 SECURITY_RELAXATION_GATE(BE)放宽批准三域族互引不合并。",
379
+ "Change Policy 锚(FE04 L84,行内容含「必须」)——advisory 落点(池密度序 32.31 "
380
+ "为 advisory 补位第 2)。",
381
+ ],
382
+ # ---- D3-R2 轮 17 张(裁定批 G)----
383
+ "POLICY.CACHE.FAILURE_MODE_GUARDS": [
384
+ "缓存穿透/击穿/雪崩/热 key 限制与观测在既有 228 条中无对应条目;与 POLICY.CACHE."
385
+ "LIFECYCLE_DEFINITION(B6b-I:缓存生命周期定义)及同批 SCHEMA_VERSIONING(变更"
386
+ "纪律)不同轴——彼管结构形态/演进,本管失效模式防护设计面,互引不合并。",
387
+ "D3-R2 补锚:卡层 source_lines=null,复核回 MASTer 23 L31-33(SHOULD 段)取得"
388
+ "行级证据,advisory 原样(池判一致)。",
389
+ ],
390
+ "POLICY.INTEGRATION.FAULT_CONTAINMENT": [
391
+ "隔离/熔断/限流/降级/对账控散在既有 228 条中无对应条目;与 POLICY.INTEGRATION."
392
+ "CALL_DEFINITION_MINIMUM(B6b-II:外部调用最小定义面)不同轴(声明面 vs 故障"
393
+ "控制面),互引。",
394
+ "D3-R2 补锚:MASTer 24 L31-33(SHOULD 段),advisory 原样(池判一致)。",
395
+ ],
396
+ "POLICY.JOB.OPERATIONAL_FEATURES": [
397
+ "异步任务进度/心跳/并发限制/失败恢复/过期清理在既有 228 条中无对应条目;与 "
398
+ "POLICY.JOB.LIFECYCLE_DEFINITION、JOB.NO_UNMANAGED_EXECUTION(B6c:任务生命周期"
399
+ "与托管禁令)不同轴——彼管登记纪律,本管运维能力设计面,互引。",
400
+ "D3-R2 补锚:MASTer 25 L31-33(SHOULD 段),advisory 原样(池判一致)。",
401
+ ],
402
+ "POLICY.OBS.ACTIONABLE_SIGNALS": [
403
+ "关键失败/延迟/容量/依赖的可行动指标与告警在既有 228 条中无对应条目;与 "
404
+ "POLICY.OBS.ALERT_WITH_OWNER(B6b-II:告警必须有属主)互引(告警存在性/可行动性 "
405
+ "vs 属主指派);与同批 SIGNAL_CHANGE_IMPACT 变更轴正交。",
406
+ "D3-R2 补锚:MASTer 29 L31-33(SHOULD 段),advisory 原样(池判一致)。",
407
+ ],
408
+ "POLICY.PERF.OBSERVATION_DIMENSIONS": [
409
+ "尾延迟/错误率/资源/排队/背压/依赖瓶颈六维观测在既有 228 条中无对应条目;与 "
410
+ "POLICY.PERF.EVIDENCE_BINDING、BUDGET_CHANGE_RETEST 不同轴——彼管证据绑定与"
411
+ "变更复测,本管观测维度完备性,互引。",
412
+ "D3-R2 补锚:MASTer 30 L31-33(SHOULD 段),advisory 原样(池判一致)。",
413
+ ],
414
+ "POLICY.DEPLOY.OPERATIONAL_CAPABILITIES": [
415
+ "优雅启停/健康检查/滚动发布/最小权限/故障隔离在既有 228 条中无对应条目;与 "
416
+ "POLICY.DEPLOY.NO_DEV_ENV_AS_PRODUCTION_FACT、RUNTIME_FACT_RECORD(B6b-I:部署"
417
+ "事实登记)不同轴——彼管事实记录,本管部署单元能力设计面,互引。",
418
+ "D3-R2 补锚:MASTer 31 L31-33(SHOULD 段),advisory 原样(池判一致)。",
419
+ ],
420
+ "POLICY.BE.STATE.SINGLE_RULE_SOURCE": [
421
+ "同一权威规则集中表达在既有 228 条中无对应条目;与 POLICY.DERIVED."
422
+ "SINGLE_IMPLEMENTATION(B6b-I:单一实现)相邻不同轴——彼管实现派生面,本管业务"
423
+ "规则表达唯一权威源;边界与非法转移测试义务与同批 MODEL.SINGLE_BOUNDARY_CONVERSION "
424
+ "的 round-trip 验证正交,互引。",
425
+ "D3-R2 补锚:MASTer 14 L33(SHOULD 段),advisory 原样(池判一致)。",
426
+ ],
427
+ "POLICY.BE.MODEL.SINGLE_BOUNDARY_CONVERSION": [
428
+ "边界单次转换+契约/round-trip 验证在既有 228 条中无对应条目;与 POLICY.DERIVED."
429
+ "SINGLE_IMPLEMENTATION 互引不同轴(实现唯一 vs 转换次数唯一);与 WEB.API."
430
+ "TRANSPORT_VS_BUSINESS(B6b-I:传输与业务模型分界)正交互补。",
431
+ "D3-R2 补锚:MASTer 15 L33(SHOULD 段),advisory 原样(池判一致)。",
432
+ ],
433
+ "POLICY.BE.DB.EXPAND_MIGRATE_CONTRACT": [
434
+ "expand/migrate/contract 三阶段在既有 228 条中无对应条目;与 POLICY.CHG."
435
+ "COMPAT_MIGRATION_ROLLBACK(B6b-I:通用兼容迁移回滚)、FLAG.CLEANUP_AFTER_FULL_"
436
+ "ROLLOUT(存量清退)互引——本卡管库表结构并行的专项时序,应用侧迁移通用纪律不重复。",
437
+ "D3-R2 补锚:MASTer 18 L33(SHOULD 段),advisory 原样(池判一致)。",
438
+ ],
439
+ "POLICY.BE.SQL.INDEX_FOR_KNOWN_QUERIES": [
440
+ "索引服务已知查询+写放大/存储取舍记录在既有 228 条中无对应条目;与 POLICY.PERF.* "
441
+ "族不同轴(观测/预算 vs 索引设计取真理);「取舍记录」义务与 ARCH."
442
+ "DECISION_TRADEOFF_RECORD(决策取舍留痕)语义呼应不同层。",
443
+ "D3-R2 补锚:MASTer 19 L33(SHOULD 段),advisory 原样(池判一致)。",
444
+ ],
445
+ "POLICY.BE.TXN.SHORT_LOCKS_COMPENSATION": [
446
+ "短锁持有+外部副作用可重试/可补偿在既有 228 条中无对应条目;与同批 INTEGRATION."
447
+ "FAULT_CONTAINMENT 互引(事务边界时序 vs 集成故障隔离);与 REL."
448
+ "NO_IRREVERSIBLE_UNMONITORED_FULL_RELEASE 不同轴。",
449
+ "D3-R2 补锚:MASTer 20 L33(SHOULD 段),advisory 原样(池判一致)。",
450
+ ],
451
+ "POLICY.BE.CONC.PREFER_DB_CONSTRAINTS": [
452
+ "数据库约束/版本条件原子更新优先在既有 228 条中无对应条目;与同批 TXN."
453
+ "SHORT_LOCKS_COMPENSATION 同协议正交(不变量保护机制选型 vs 锁时长设计),互引;"
454
+ "与 STACK.* 池卡不同层(通用并发纪律 vs 技术栈登记)。",
455
+ "D3-R2 补锚:MASTer 21 L33(SHOULD 段),advisory 原样(池判一致)。",
456
+ ],
457
+ "POLICY.BE.IDEM.KEY_PAYLOAD_CONFLICT": [
458
+ "相同 key 不同 payload 稳定冲突响应在既有 228 条中无对应条目;与 POLICY.WEB.API."
459
+ "MUTATION_IDEMPOTENCY(B6b-I:前端变更幂等)前后端同族互引——彼管客户端重试面,"
460
+ "本管服务端键语义,不合并。",
461
+ "D3-R2 补锚:MASTer 22 L33(SHOULD 段),advisory 原样(池判一致)。",
462
+ ],
463
+ "POLICY.SPEC.PRIMARY_SOURCE_BASIS": [
464
+ "规则依据一手来源在既有 228 条中无对应条目;与 POLICY.AI.READ_SEARCH_VERIFY_"
465
+ "BEFORE_WRITE(B6c:先读后写)相邻不同轴——彼管检索-核实流程,本管依据来源资格"
466
+ "(官方标准/官方文档/一手仓库,二手仅检索线索);与 SPEC.* 族登记纪律互补。",
467
+ "锚落 MASTer FE index 自有段「通用规则准入与维护来源」(L20/L23-L31,index 卡"
468
+ "天然无 12 段锚)——D3 复核按锚行行为规范成分 advisory 入册(池判 required 强度"
469
+ "只降不升;标准源清单 L23-L31 为参考列表 annex 不入正本语句),extra_master_"
470
+ "sections 如实登记。",
471
+ ],
472
+ "POLICY.SPEC.FREEZE_BEFORE_USE": [
473
+ "规格消费前冻结时点在既有 228 条中无对应条目;与 POLICY.SPEC.DRAFT_NOT_BASELINE、"
474
+ "SPEC.ADMISSION_CRITERIA(B6b-I:草稿非基线/准入判据)同族互引——彼管草稿状态"
475
+ "判定与准入,本管逐类规格的冻结时点安排(「可作开发依据」非「永不修改」,修改走"
476
+ "受控变更)。",
477
+ "锚落 MASTer FE index 自有段「Spec 生命周期」(L63-L68)——D3 复核按锚行内容 "
478
+ "advisory 入册(池判 advisory 原样),extra_master_sections 如实登记。",
479
+ ],
480
+ "POLICY.SPEC.FAMILY_CONFLICT_PRECEDENCE": [
481
+ "协议族冲突裁决优先序在既有 228 条中无对应条目(CONFLICT.PRIORITY_LADDER 管跨域"
482
+ "冲突优先阶梯——本管协议族内语义冲突的整序裁决,互引不合并;「正式契约优先」子句"
483
+ "与 API.NO_INFORMAL_CONTRACT 互补);卡自带 uncertainty 注记「本卡价值在整序」"
484
+ "如实承袭。",
485
+ "锚落 MASTer BE index 自有段「冲突与责任边界」(L158-163)——D3 复核按锚行内容 "
486
+ "advisory 入册(池判 advisory 原样;定义性优先序声明无段级强度词形),extra_"
487
+ "master_sections 如实登记。",
488
+ ],
489
+ "POLICY.TEST.REMOVAL_JUSTIFICATION": [
490
+ "测试删除证明与门禁降级审批在既有 228 条中无对应条目;与 D3-R1 同域卡 TEST."
491
+ "REMOVAL_NEEDS_SUBSTITUTE_EVIDENCE(BE28 锚)前后端同族互引——彼管替代证据义务,"
492
+ "本管删除证明+降级审批双要件;R1 注记预告的「前后端同族互引随 R2 登记」就此闭合。",
493
+ "Change Policy 锚(MASTer FE20 L76,行内容含「必须」行为规范)——D3 复核按裁定"
494
+ "精神降 advisory 入册(池判 required 强度只降不升)。",
495
+ ],
496
+ }
497
+
498
+ # ----------------------------------------------------------------------
499
+ # 维持排除 30 张(Ownership 归属说明族——锚行=权责归属默认分配陈述,零行为规范
500
+ # 成分;归属语义由 catalog authority 轴/owner_registry 与播种件正文承载)。
501
+ # ----------------------------------------------------------------------
502
+ D3_EXCLUDED_KEEP = [
503
+ # B6b-II 7(AUTHORITY.WEB.*.OWNERS)
504
+ "AUTHORITY.WEB.COMP.OWNERS", "AUTHORITY.WEB.PAGE.OWNERS",
505
+ "AUTHORITY.WEB.STYLE.OWNERS", "AUTHORITY.WEB.I18N.OWNERS",
506
+ "AUTHORITY.WEB.COPY.OWNERS", "AUTHORITY.WEB.TRACK.OWNERS",
507
+ "AUTHORITY.WEB.HANDOFF.OWNERS",
508
+ # B6c 17(AUTHORITY.*——Ownership 段 L53)
509
+ "AUTHORITY.ARCH.DECISION_OWNERS", "AUTHORITY.STRUCT.MODULE_OWNERS",
510
+ "AUTHORITY.BOUND.ENTRY_CHANGE_APPROVAL", "AUTHORITY.LAYER.LAYERING_OWNERS",
511
+ "AUTHORITY.WF.EXECUTION_REVIEW_SPLIT", "AUTHORITY.AI.AGENT_USER_DECISION_BOUNDARY",
512
+ "AUTHORITY.EVID.IMPLEMENTER_PROVIDER_REVIEWER_JUDGE",
513
+ "AUTHORITY.ROLE.MODEL_VS_PROJECT_BINDING", "AUTHORITY.TOOL.TOOLCHAIN_OWNERS",
514
+ "AUTHORITY.DEP.ADMISSION_AND_BLOCK_OWNERS", "AUTHORITY.TEST.CHANGE_TEST_OWNERS",
515
+ "AUTHORITY.REL.RELEASE_GATE_OWNERS", "AUTHORITY.SEC.SECURITY_OWNERSHIP",
516
+ "AUTHORITY.CFG.CONFIG_OWNERSHIP", "AUTHORITY.PRV.DATA_OWNERSHIP",
517
+ "AUTHORITY.ERR.ERROR_REGISTRY_OWNERSHIP",
518
+ "AUTHORITY.AUTHZ.PERMISSION_SEMANTICS_OWNERSHIP",
519
+ # B6c 6(AUTHORITY.BE.*_OWNERSHIP——overlay Ownership 段 L51-53)
520
+ "AUTHORITY.BE.CACHE_OWNERSHIP", "AUTHORITY.BE.INTEGRATION_OWNERSHIP",
521
+ "AUTHORITY.BE.JOB_OWNERSHIP", "AUTHORITY.BE.OBS_OWNERSHIP",
522
+ "AUTHORITY.BE.PERF_OWNERSHIP", "AUTHORITY.BE.DEPLOY_OWNERSHIP",
523
+ ]
524
+ assert len(D3_EXCLUDED_KEEP) == 30
525
+
526
+ # ----------------------------------------------------------------------
527
+ # D3-R2 轮入册 17 张(裁定批 G;R1 后按池密度序余量,全部 advisory——裁决 13 留账
528
+ # 双锚[密度序 32.25×2/30.0×8/0.0×7] + 裁决 14 同口径入册。锚行=复核回 MASTer 源
529
+ # 实证的行级证据,禁止凭印象——同一锚核验+LCS 机制逐卡执行)。
530
+ # 元组同 R1:(id, group, origin_batch, master_file, lines, sections, reason_key, title)。
531
+ # reason_key 新增三值对应原排除词形:anchor_missing(池行行锚缺席)/ extra_section_
532
+ # advisory(advisory 池扩展段变体)/ not_advisory_section(锚段映射非纯建议段)。
533
+ # ----------------------------------------------------------------------
534
+ # ---- SHOULD 锚 6(B6c BE-G4:卡层 source_lines=null,复核回 MASTer L31-33 SHOULD 段)----
535
+ _D3_R2_BEG4_SHOULD = [
536
+ ("POLICY.CACHE.FAILURE_MODE_GUARDS", "BE-G4", "B6C",
537
+ "23-cache-redis-consistency-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
538
+ "缓存失效模式防护"),
539
+ ("POLICY.INTEGRATION.FAULT_CONTAINMENT", "BE-G4", "B6C",
540
+ "24-external-integration-resilience-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
541
+ "外部集成故障隔离"),
542
+ ("POLICY.JOB.OPERATIONAL_FEATURES", "BE-G4", "B6C",
543
+ "25-async-job-scheduler-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
544
+ "异步任务运维能力"),
545
+ ("POLICY.OBS.ACTIONABLE_SIGNALS", "BE-G4", "B6C",
546
+ "29-observability-logging-tracing-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
547
+ "可行动指标与告警"),
548
+ ("POLICY.PERF.OBSERVATION_DIMENSIONS", "BE-G4", "B6C",
549
+ "30-performance-capacity-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
550
+ "性能观测六维"),
551
+ ("POLICY.DEPLOY.OPERATIONAL_CAPABILITIES", "BE-G4", "B6C",
552
+ "31-runtime-deployment-protocol.md", "L31-L33", ["SHOULD"], "anchor_missing",
553
+ "部署运行能力六项"),
554
+ ]
555
+ # ---- SHOULD 锚 7(B6c BE-G3 overlay 卡:卡层 source_lines=null,复核回 MASTer L33)----
556
+ _D3_R2_BEG3_SHOULD = [
557
+ ("POLICY.BE.STATE.SINGLE_RULE_SOURCE", "BE-G3", "B6C",
558
+ "14-business-rules-state-protocol.md", "L33", ["SHOULD"], "anchor_missing",
559
+ "权威规则单点表达"),
560
+ ("POLICY.BE.MODEL.SINGLE_BOUNDARY_CONVERSION", "BE-G3", "B6C",
561
+ "15-data-model-protocol.md", "L33", ["SHOULD"], "anchor_missing",
562
+ "模型边界单次转换"),
563
+ ("POLICY.BE.DB.EXPAND_MIGRATE_CONTRACT", "BE-G3", "B6C",
564
+ "18-database-schema-migration-protocol.md", "L33", ["SHOULD"], "anchor_missing",
565
+ "结构变更三阶段并行部署"),
566
+ ("POLICY.BE.SQL.INDEX_FOR_KNOWN_QUERIES", "BE-G3", "B6C",
567
+ "19-query-index-sql-protocol.md", "L33", ["SHOULD"], "anchor_missing",
568
+ "索引服务已知查询"),
569
+ ("POLICY.BE.TXN.SHORT_LOCKS_COMPENSATION", "BE-G3", "B6C",
570
+ "20-transaction-boundary-protocol.md", "L33", ["SHOULD"], "anchor_missing",
571
+ "短锁持有与副作用补偿"),
572
+ ("POLICY.BE.CONC.PREFER_DB_CONSTRAINTS", "BE-G3", "B6C",
573
+ "21-concurrency-locking-protocol.md", "L33", ["SHOULD"], "anchor_missing",
574
+ "不变量保护优先数据库约束"),
575
+ ("POLICY.BE.IDEM.KEY_PAYLOAD_CONFLICT", "BE-G3", "B6C",
576
+ "22-idempotency-protocol.md", "L33", ["SHOULD"], "anchor_missing",
577
+ "幂等键冲突稳定响应"),
578
+ ]
579
+ # ---- 非 12 段锚 4(MASTer 扩展段/Change Policy 锚——extra_master_sections 如实登记)----
580
+ _D3_R2_EXTRA_ANCHOR = [
581
+ # B6b-II FE index 2(index 卡天然无 12 段锚——锚落 index 自有段,池 advisory/required 混合)。
582
+ ("POLICY.SPEC.PRIMARY_SOURCE_BASIS", "FE-G1", "B6B-2",
583
+ "index.md", "L20, L23-L31", ["通用规则准入与维护来源"], "extra_section",
584
+ "规则依据一手来源"),
585
+ ("POLICY.SPEC.FREEZE_BEFORE_USE", "FE-G1", "B6B-2",
586
+ "index.md", "L63-L68", ["Spec 生命周期"], "extra_section_advisory",
587
+ "规格消费前冻结"),
588
+ # B6c BE index 冲突优先序 1(裁决 13:BE index 冲突与责任边界段 L158-163)。
589
+ ("POLICY.SPEC.FAMILY_CONFLICT_PRECEDENCE", "BE-G1", "B6C",
590
+ "index.md", "158-163", ["冲突与责任边界"], "not_advisory_section",
591
+ "协议冲突裁决优先序"),
592
+ # B6b-I FE20 Change Policy 锚 1(锚行含「必须」行为规范——池判 required 降 advisory)。
593
+ ("POLICY.TEST.REMOVAL_JUSTIFICATION", "FE-G1", "B6B-1",
594
+ "20-testing-protocol.md", "L76", ["Change Policy"], "change_policy",
595
+ "测试删除证明与降级审批"),
596
+ ]
597
+ D3_R2_REGISTERED = _D3_R2_BEG4_SHOULD + _D3_R2_BEG3_SHOULD + _D3_R2_EXTRA_ANCHOR
598
+ assert len(D3_R2_REGISTERED) == 17
599
+
600
+ # FE 卡人工英文关键词(FE 候选卡不带 statement_en_keywords 字段——B6b 先例人工审定)。
601
+ FE_KEYWORDS = {
602
+ "POLICY.REGISTRY.HUMAN_FIELDS_VALIDATED_DECORRELATED": [
603
+ "human fields independent validation", "generator decoupled assertion",
604
+ "no silent overwrite",
605
+ ],
606
+ "POLICY.SEC.RELAXATION_APPROVAL": [
607
+ "security relaxation approval", "risk assessment", "approver and expiry",
608
+ "fix over convenience",
609
+ ],
610
+ "POLICY.TEST.REMOVAL_JUSTIFICATION": [
611
+ "test removal justification", "behavior deleted or equivalent coverage",
612
+ "gate test downgrade approval",
613
+ ],
614
+ "POLICY.SPEC.PRIMARY_SOURCE_BASIS": [
615
+ "primary source basis", "official standards and documentation",
616
+ "second-hand articles as search leads only",
617
+ ],
618
+ "POLICY.SPEC.FREEZE_BEFORE_USE": [
619
+ "freeze before use", "requirement spec frozen before development",
620
+ "baseline after first vertical slice",
621
+ ],
622
+ }
623
+
624
+ # 原排除理由(种子工具排除记录词形,d3_review 注记引用;R2 轮新增三值对应
625
+ # B6b/B6c advisory 池与扩展段变体——词形与原工具排除记录逐字一致)。
626
+ ORIGIN_REASON = {
627
+ "source_null": "卡层 source=null(锚证据不足),保守排除待复核",
628
+ "change_policy": "行锚段映射非 MUST/MUST NOT(池 enforcement 判定矛盾,保守排除待复核)",
629
+ "extra_section": "行锚全落 MASTer 项目扩展段(12 段闭包外),无源强度证据,保守排除待复核",
630
+ "anchor_missing": "池行行锚缺席(锚证据不足,保守排除待复核)",
631
+ "extra_section_advisory": "行锚全落 MASTer 项目扩展段(12 段闭包外),无源段证据,保守排除待复核",
632
+ "not_advisory_section": "行锚段映射非纯建议段(池 advisory 判定矛盾,保守排除待复核)",
633
+ }
634
+
635
+
636
+ # ======================================================================
637
+ # 锚核验(MASTer 行锚 ↔ 声明段交叉验证 + 锚行原文在座断言)
638
+ # ======================================================================
639
+ def _norm_ws(s):
640
+ return re.sub(r"\s+", "", s)
641
+
642
+
643
+ def _lcs_len(a, b):
644
+ if not a or not b:
645
+ return 0
646
+ prev = [0] * (len(b) + 1)
647
+ best = 0
648
+ for i in range(1, len(a) + 1):
649
+ cur = [0] * (len(b) + 1)
650
+ ca = a[i - 1]
651
+ for j in range(1, len(b) + 1):
652
+ if ca == b[j - 1]:
653
+ cur[j] = prev[j - 1] + 1
654
+ if cur[j] > best:
655
+ best = cur[j]
656
+ prev = cur
657
+ return best
658
+
659
+
660
+ def parse_line_anchors(lines_str):
661
+ """"57" / "L71-L74" → [(57,57)] / [(71,74)]。"""
662
+ s = (lines_str or "").strip()
663
+ out = []
664
+ for m in re.finditer(r"[Ll]?(\d+)(?:\s*-\s*[Ll]?(\d+))?", s):
665
+ a = int(m.group(1))
666
+ b = int(m.group(2)) if m.group(2) else a
667
+ out.append((min(a, b), max(a, b)))
668
+ return out
669
+
670
+
671
+ def master_marks_and_lines(base, name):
672
+ path = os.path.join(base, name)
673
+ assert os.path.isfile(path), f"MASTer 源文件不存在: {name}"
674
+ lines = open(path, encoding="utf-8").read().splitlines()
675
+ marks = []
676
+ for i, line in enumerate(lines, 1):
677
+ m = re.match(r"^## (.+?)\s*$", line)
678
+ if m:
679
+ marks.append((i, m.group(1)))
680
+ return marks, lines
681
+
682
+
683
+ def sections_for_lines(marks, lines, lines_str):
684
+ names = []
685
+ for (a, _b) in parse_line_anchors(lines_str):
686
+ for idx, (ln, name) in enumerate(marks):
687
+ end = marks[idx + 1][0] - 1 if idx + 1 < len(marks) else len(lines)
688
+ if ln <= a <= end and name not in names:
689
+ names.append(name)
690
+ return names
691
+
692
+
693
+ def clean_room_audit(cid, statement, base, name, lines_str):
694
+ """LCS 审计(MASTer 行段;阈值 20 字 fail-closed)。"""
695
+ _marks, raw_lines = master_marks_and_lines(base, name)
696
+ segs = []
697
+ for (a, b) in parse_line_anchors(lines_str):
698
+ a = max(a, 1)
699
+ b = min(b, len(raw_lines))
700
+ if a <= b:
701
+ segs.append("".join(raw_lines[a - 1:b]))
702
+ ref_text = _norm_ws("".join(segs))
703
+ stmt = _norm_ws(statement)
704
+ worst = _lcs_len(stmt, ref_text) if ref_text else 0
705
+ assert worst < LCS_THRESHOLD, f"clean-room LCS 审计失败({worst}>=20 字): {cid}"
706
+ return worst
707
+
708
+
709
+ def verify_anchors():
710
+ """逐卡锚核验(R1+R2 全量):行锚落声明段 + 锚行原文在座(禁凭印象)。返回 {cid: 锚行原文}。"""
711
+ out = {}
712
+ for (cid, group, _o, name, lines_str, sections, _rk, _title) in \
713
+ D3_REGISTERED + D3_R2_REGISTERED:
714
+ # lane 判定按卡组(FE/BE 两树同名文件并存——index.md 双侧在座,禁按文件名判)。
715
+ base = MASTER_FE if group.startswith("FE") else MASTER_BE
716
+ marks, raw_lines = master_marks_and_lines(base, name)
717
+ mapped = sections_for_lines(marks, raw_lines, lines_str)
718
+ for s in sections:
719
+ assert s in mapped, (
720
+ f"D3 锚交叉验证失败: {cid} 声明段 {s} 不在行锚实际段 {mapped}")
721
+ for (a, _b) in parse_line_anchors(lines_str):
722
+ # 区间锚只断言首行在座(区间内空行为源文合法结构——FE10 L71-L74 含 L72 空)。
723
+ assert raw_lines[a - 1].strip(), f"D3 锚行空: {cid} {name} L{a}"
724
+ snippet = " / ".join(
725
+ raw_lines[ln - 1].strip()
726
+ for (a, b) in parse_line_anchors(lines_str)
727
+ for ln in [a])
728
+ out[cid] = snippet
729
+ return out
730
+
731
+
732
+ FE_MASTER_FILES = {c[3] for c in D3_REGISTERED + D3_R2_REGISTERED
733
+ if c[1].startswith("FE")}
734
+
735
+
736
+ # ======================================================================
737
+ # 池行对账 + 候选卡装载
738
+ # ======================================================================
739
+ def load_raw_cards():
740
+ cards = {}
741
+
742
+ def walk(node, out):
743
+ if isinstance(node, dict):
744
+ if "proposed_id" in node:
745
+ out.append(node)
746
+ return
747
+ for v in node.values():
748
+ walk(v, out)
749
+ elif isinstance(node, list):
750
+ for v in node:
751
+ walk(v, out)
752
+
753
+ for group in ("BE-G1", "BE-G2", "BE-G3", "BE-G4", "FE-G1"):
754
+ doc = yaml.safe_load(open(os.path.join(CAND_DIR, group + ".yaml"),
755
+ encoding="utf-8"))
756
+ found = []
757
+ walk(doc, found)
758
+ for c in found:
759
+ cid = c.get("proposed_id")
760
+ if cid:
761
+ cards[cid] = {"group": group, "raw": c}
762
+ return cards
763
+
764
+
765
+ def load_pool_rows():
766
+ pool = yaml.safe_load(open(POOL_PATH, encoding="utf-8"))
767
+ rows = {}
768
+ for section in ("eligible_ranked", "canonical_backlog"):
769
+ for r in pool[section]:
770
+ rows.setdefault(r["candidate_id"], r)
771
+ return rows
772
+
773
+
774
+ def keywords_of(card_raw):
775
+ kw = card_raw.get("statement_en_keywords")
776
+ if isinstance(kw, str):
777
+ return [p.strip() for p in kw.split(",") if p.strip()]
778
+ return list(kw or [])
779
+
780
+
781
+ # ======================================================================
782
+ # catalog 条目构建
783
+ # ======================================================================
784
+ def id_to_path(cid):
785
+ return "policies/" + cid.lower() + ".json"
786
+
787
+
788
+ def vendor_pin_for(lane, name):
789
+ base = FE_VENDOR if lane == "frontend" else BE_VENDOR
790
+ data = open(os.path.join(base, name), "rb").read()
791
+ rel = (f"pomaster/components/frontend-hard-spec/assets/universal/{name}"
792
+ if lane == "frontend" else
793
+ f"pomaster/components/backend-hard-spec/assets/universal/{name}")
794
+ return {"path": rel, "sha256": hashlib.sha256(data).hexdigest(), "bytes": len(data)}
795
+
796
+
797
+ def seeded_spec_for(lane, name):
798
+ return f".pomaster/specs/hard/{lane}/{name}"
799
+
800
+
801
+ def domain_of(cid):
802
+ return cid.split(".")[1]
803
+
804
+
805
+ def build_entry(rec, card, statement, anchor_snippet, sections, extra_sections):
806
+ cid = rec["cid"]
807
+ group = card["group"]
808
+ r = card["raw"]
809
+ lane_name = rec["master_file"]
810
+ lane = "frontend" if rec["group"].startswith("FE") else "backend"
811
+ pin = vendor_pin_for(lane, lane_name)
812
+ ref = (f".trellis/spec/{lane}/{lane_name}")
813
+ locator = {
814
+ "candidate": cid,
815
+ "source_protocol": ref,
816
+ "lines": rec["lines"],
817
+ }
818
+ batch = rec["batch"]
819
+ is_r2 = batch == BATCH_R2
820
+ new_domains = sorted({domain_of(cid)} & (NEW_DOMAINS_IN_BATCH_R2 if is_r2
821
+ else NEW_DOMAINS_IN_BATCH_R1))
822
+ if new_domains:
823
+ if is_r2:
824
+ vocab_block = {
825
+ "status": "vocab_pr_candidate",
826
+ "finding": "id 域段待登记:" + "/".join(new_domains)
827
+ + "(vocab-lock@v0.9-resolved policy_id_domains 35 段未含——PR-0010 "
828
+ "后新用域段沿用候选注记先例,词汇表 PR 增补)",
829
+ "proposal": "词汇表 PR 增补新 id 域段至 catalog_layer_vocab.policy_id_domains"
830
+ "(与 PR-0009/PR-0010 同轴追加,append-only)",
831
+ "locked_vocab_untouched": True,
832
+ }
833
+ else:
834
+ vocab_block = {
835
+ "status": "vocab_pr_candidate",
836
+ "finding": "id 域段待登记:" + "/".join(new_domains)
837
+ + "(vocab-lock@v0.8-resolved policy_id_domains 32 段未含——PR-0009 "
838
+ "后新用域段沿用候选注记先例,词汇表 PR 增补)",
839
+ "proposal": "词汇表 PR 增补新 id 域段至 catalog_layer_vocab.policy_id_domains"
840
+ "(与 PR-0009 同轴追加,append-only)",
841
+ "locked_vocab_untouched": True,
842
+ "resolution": VOCAB_PR_0010_RESOLUTION,
843
+ }
844
+ else:
845
+ vocab_block = None
846
+ origin_reason = ORIGIN_REASON[rec["reason_key"]]
847
+ if rec["enforcement"] == "required_when_applicable":
848
+ basis = "MUST/MUST NOT 行锚 required 原样"
849
+ elif rec["sections"] == ["Change Policy"]:
850
+ basis = ("行内容含「必须」行为规范、Change Policy 段 advisory 落点(强度只降"
851
+ "不升)")
852
+ elif is_r2 and rec["sections"] == ["SHOULD"]:
853
+ basis = "SHOULD 行锚 advisory 原样(池判一致;复核行锚补证)"
854
+ else:
855
+ basis = "锚行行为规范成分、无段级强度词形 advisory 落点"
856
+ if is_r2:
857
+ adjudication = (
858
+ D3_R2_EXCLUSION_NOTE_FE.format(origin=rec["origin_batch"],
859
+ reason=origin_reason, basis=basis)
860
+ if rec["origin_batch"].startswith("B6B") else
861
+ D3_R2_EXCLUSION_NOTE.format(origin=rec["origin_batch"],
862
+ reason=origin_reason,
863
+ sections="/".join(rec["sections"]),
864
+ basis=basis)
865
+ )
866
+ materialized_package = ("裁定批 G/D3-R2 排除卡逐卡复核物化·R2 轮(SPEC-D 池卡复用;"
867
+ "分母=MASTer 池卡 + vendor 播种字节双锚)")
868
+ curated = CURATED_RULE_R2
869
+ origin_note = (
870
+ f"{BATCH_LABEL_R2} D3 逐卡复核物化·R2 轮(原 {rec['origin_batch']} 保守排除卡"
871
+ "补锚收编);statement 沿用 SPEC-D 候选卡独立措辞(clean-room),零逐字拷贝上游"
872
+ "源文本;播种分母=vendor 字节(x-b6-porting.vendor_pin),分解分母=MASTer 池卡"
873
+ "(x-spec-d-materialization)"
874
+ )
875
+ else:
876
+ adjudication = (
877
+ D3_EXCLUSION_NOTE_FE.format(reason=origin_reason, basis=basis)
878
+ if rec["origin_batch"] == "B6B-1" else
879
+ D3_EXCLUSION_NOTE.format(origin=rec["origin_batch"],
880
+ reason=origin_reason,
881
+ sections="/".join(rec["sections"]),
882
+ basis=basis)
883
+ )
884
+ materialized_package = ("裁定批 F/D3-R1 排除卡逐卡复核物化(SPEC-D 池卡复用;分母="
885
+ "MASTer 池卡 + vendor 播种字节双锚)")
886
+ curated = CURATED_RULE
887
+ origin_note = (
888
+ f"{BATCH_LABEL} D3 逐卡复核物化(原 {rec['origin_batch']} 保守排除卡补锚收编);"
889
+ "statement 沿用 SPEC-D 候选卡独立措辞(clean-room),零逐字拷贝上游源文本;"
890
+ "播种分母=vendor 字节(x-b6-porting.vendor_pin),分解分母=MASTer 池卡"
891
+ "(x-spec-d-materialization)"
892
+ )
893
+ entry = {
894
+ "x-spec-d-materialization": {
895
+ "status": "PROPOSAL",
896
+ "package": materialized_package,
897
+ "human_review_required": True,
898
+ "evidence": "PLANNED",
899
+ "provenance": POOL_REL,
900
+ "group": group,
901
+ "candidate_id": cid,
902
+ "pool_statement_sha16": rec["pool_row"].get("statement_sha16"),
903
+ "curated_rule": curated,
904
+ "denominator": "MASTer(池卡锚)",
905
+ },
906
+ "x-b6-porting": {
907
+ "status": "PROPOSAL",
908
+ "batch": batch,
909
+ "human_review_required": True,
910
+ "classification_face": "policy",
911
+ "enforcement_axis": {
912
+ "source_sections": sections,
913
+ "rule": "SHOULD/Change Policy 源条目 enforcement 必须 advisory(禁升 required);"
914
+ "MUST/MUST NOT 源条目 enforcement 必须 required_when_applicable(降级合法)",
915
+ "asserted_by": "packages/cli/tests/catalog-b6-porting.spec.ts",
916
+ },
917
+ "extra_master_sections": extra_sections,
918
+ "denominator": "vendor",
919
+ "vendor_pin": pin,
920
+ "seeded_spec": seeded_spec_for(lane, lane_name),
921
+ "seed_manifest": "packages/cli/seeds/manifest.json",
922
+ "d3_review": {
923
+ "excluded_from_batch": rec["origin_batch"],
924
+ "exclusion_reason_at_seed": origin_reason,
925
+ "adjudication": adjudication,
926
+ "anchor_evidence": f"MASTer {rec['master_file']} {rec['lines']}「{anchor_snippet}」",
927
+ "pool_enforcement_at_seed": rec["pool_row"].get("enforcement"),
928
+ },
929
+ },
930
+ "id": cid,
931
+ "kind": "policy",
932
+ "axis_profile": "policy_default",
933
+ "classification": "UNIVERSAL_POLICY",
934
+ "axes": {
935
+ "lifecycle": "PROPOSED",
936
+ "confidence": "UNRESOLVED",
937
+ "evidence": "PLANNED",
938
+ "change": "STABLE",
939
+ },
940
+ "title_zh": rec["title"],
941
+ "statement_zh": statement,
942
+ "statement_en_keywords": (FE_KEYWORDS[cid] if rec["group"].startswith("FE")
943
+ else keywords_of(r)),
944
+ "applies_when": {
945
+ "lane": (r.get("applies_when") or {}).get("lane", "any"),
946
+ "condition": (r.get("applies_when") or {}).get("condition", ""),
947
+ "applicability_note": (r.get("applies_when") or {}).get("condition", ""),
948
+ },
949
+ "enforcement": rec["enforcement"],
950
+ "authority": {
951
+ "owner": "HUMAN_OWNER",
952
+ "delegates": [],
953
+ "write_policy": "EVOLUTION_CHANNEL",
954
+ "escalation_hint": "catalog-spec-decomposition",
955
+ },
956
+ "origin": "ingested",
957
+ "origin_note": origin_note,
958
+ "sources": [
959
+ {
960
+ "type": "design_seed",
961
+ "ref": "POMaster_VNext/corpus/spec-knowledge/candidates/%s.yaml" % group,
962
+ "captured_by": "agent:claude/spec-d-consolidation",
963
+ "locator": locator,
964
+ "clean_room_note": CLEAN_ROOM_NOTE,
965
+ }
966
+ ],
967
+ "review_notes": list(REVIEW_NOTES[cid]),
968
+ }
969
+ if vocab_block is not None:
970
+ entry = {"x-vocab-pr": vocab_block, **entry}
971
+ return entry
972
+
973
+
974
+ def sections_in_twelve(sections):
975
+ twelve = {"Scope", "Non-Scope", "Terms", "MUST", "MUST NOT", "SHOULD", "Contract",
976
+ "Checklist", "Examples", "Anti-patterns", "Ownership", "Change Policy"}
977
+ return all(s in twelve for s in sections)
978
+
979
+
980
+ def serialize(obj):
981
+ return json.dumps(obj, ensure_ascii=False, indent=2) + "\n"
982
+
983
+
984
+ def write_if_changed(path, data):
985
+ if os.path.isfile(path):
986
+ if open(path, "rb").read() == data:
987
+ return False
988
+ os.makedirs(os.path.dirname(path), exist_ok=True)
989
+ open(path, "wb").write(data)
990
+ return True
991
+
992
+
993
+ # ======================================================================
994
+ # 主流程
995
+ # ======================================================================
996
+ def build_all():
997
+ # D6 合并口径(裁决 12①)逐批守卫:R1 恰等 25;R2 = 17 ≤ 25(收尾轮余量全量入册)。
998
+ assert len(D3_REGISTERED) == D5_CAP_PER_BATCH, (
999
+ f"D6 合并上限漂移(R1): {len(D3_REGISTERED)} != {D5_CAP_PER_BATCH}/批")
1000
+ assert len(D3_R2_REGISTERED) <= D5_CAP_PER_BATCH, (
1001
+ f"D6 合并上限漂移(R2): {len(D3_R2_REGISTERED)} > {D5_CAP_PER_BATCH}/批")
1002
+ required_n = sum(1 for c in D3_REGISTERED
1003
+ if any(s in ("MUST", "MUST NOT") for s in c[5]))
1004
+ assert required_n == D3_REQUIRED_CAP, "required 分母漂移"
1005
+ for c in D3_REGISTERED + D3_R2_REGISTERED:
1006
+ assert registered_enforcement(c[5]) in ("required_when_applicable", "advisory"), \
1007
+ f"enforcement 推导越界: {c[0]}"
1008
+ # R2 轮全量 advisory(裁决 13 留账口径:required 已在 R1 全量入册,余量全为 advisory)。
1009
+ r2_required = sum(1 for c in D3_R2_REGISTERED
1010
+ if any(s in ("MUST", "MUST NOT") for s in c[5]))
1011
+ assert r2_required == 0, "R2 轮混入 required 卡(强度只降不升越界)"
1012
+ # 排除集与两轮入册集两两不交;72 张总账三集恰等(R1 25 + R2 17 + 排除 30)。
1013
+ reg = {c[0] for c in D3_REGISTERED}
1014
+ reg_r2 = {c[0] for c in D3_R2_REGISTERED}
1015
+ assert not (reg & set(D3_EXCLUDED_KEEP)), "入册/排除集相交"
1016
+ assert not (reg_r2 & set(D3_EXCLUDED_KEEP)), "R2 入册/排除集相交"
1017
+ assert not (reg & reg_r2), "R1/R2 入册集相交"
1018
+ assert len(reg | reg_r2) == 72 - len(D3_EXCLUDED_KEEP), "72 张总账漂移"
1019
+
1020
+ anchors = verify_anchors()
1021
+ raw = load_raw_cards()
1022
+ pool_rows = load_pool_rows()
1023
+
1024
+ entry_bytes = {}
1025
+ audits = []
1026
+ for batch, cards in ((BATCH, D3_REGISTERED), (BATCH_R2, D3_R2_REGISTERED)):
1027
+ for c in cards:
1028
+ cid, group, _origin, name, lines_str, sections, reason_key, title = c
1029
+ card = raw.get(cid)
1030
+ assert card is not None, f"候选卡缺席: {cid}"
1031
+ row = pool_rows.get(cid)
1032
+ assert row is not None, f"池行缺席: {cid}"
1033
+ r = card["raw"]
1034
+ statement = r["statement_zh"]
1035
+ assert statement and statement.strip(), f"卡缺 statement: {cid}"
1036
+ rec = {
1037
+ "cid": cid, "group": group, "origin_batch": _origin,
1038
+ "master_file": name, "lines": lines_str, "sections": sections,
1039
+ "enforcement": registered_enforcement(sections), "title": title,
1040
+ "reason_key": reason_key, "pool_row": row,
1041
+ "batch": batch,
1042
+ }
1043
+ # 池行对账:statement 与池一致(词形规范化)。
1044
+ pool_stmt = row.get("statement_zh")
1045
+ if pool_stmt is not None:
1046
+ assert _norm_ws(statement) == _norm_ws(pool_stmt), \
1047
+ f"卡 statement 与池不一致: {cid}"
1048
+ base = MASTER_FE if group.startswith("FE") else MASTER_BE
1049
+ extra = [] if sections_in_twelve(sections) else list(sections)
1050
+ worst = clean_room_audit(cid, statement, base, name, lines_str)
1051
+ audits.append({"id": cid, "lcs_max": worst})
1052
+ entry = build_entry(rec, card, statement, anchors[cid], sections, extra)
1053
+ entry_bytes[id_to_path(cid)] = serialize(entry).encode("utf-8")
1054
+
1055
+ return {
1056
+ "entry_bytes": entry_bytes,
1057
+ "audits": audits,
1058
+ "counts": {
1059
+ "registered": len(D3_REGISTERED),
1060
+ "required": required_n,
1061
+ "advisory": len(D3_REGISTERED) - required_n,
1062
+ "registered_r2": len(D3_R2_REGISTERED),
1063
+ "excluded_keep": len(D3_EXCLUDED_KEEP),
1064
+ },
1065
+ }
1066
+
1067
+
1068
+ def main():
1069
+ built = build_all()
1070
+ outputs = {}
1071
+ for rel, data in built["entry_bytes"].items():
1072
+ outputs[os.path.join(POLICY_DIR, *rel.split("/")[1:])] = data
1073
+
1074
+ if "--verify" in sys.argv:
1075
+ drifts = []
1076
+ for path, data in outputs.items():
1077
+ if not os.path.isfile(path):
1078
+ drifts.append({"path": path, "error": "missing"})
1079
+ elif open(path, "rb").read() != data:
1080
+ drifts.append({"path": path, "error": "bytes_differ"})
1081
+ if drifts:
1082
+ for d in drifts:
1083
+ print("DRIFT:", d)
1084
+ sys.exit(1)
1085
+ print(f"[seed_d3_review] verify ok: {len(built['entry_bytes'])} policies"
1086
+ f"(字节逐等)")
1087
+ return
1088
+
1089
+ changed = 0
1090
+ for path, data in sorted(outputs.items()):
1091
+ if write_if_changed(path, data):
1092
+ changed += 1
1093
+ print("WROTE:", os.path.relpath(path, VNEXT))
1094
+ counts = built["counts"]
1095
+ print(f"[seed_d3_review] ok: {len(outputs)} outputs({changed} changed / "
1096
+ f"{len(outputs) - changed} unchanged);r1={counts['registered']}"
1097
+ f"(required={counts['required']}, advisory={counts['advisory']})、"
1098
+ f"r2={counts['registered_r2']}(advisory 全量)、"
1099
+ f"excluded_keep={counts['excluded_keep']}")
1100
+ print("LCS audits max:", max(a["lcs_max"] for a in built["audits"]))
1101
+ print("下一步:corepack pnpm pomaster catalog relock(253→270)")
1102
+
1103
+
1104
+ if __name__ == "__main__":
1105
+ main()