pomaster 0.3.0 → 0.5.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.
- package/README.md +57 -22
- package/catalog/archetypes/archetype.frontend.error_taxonomy.json +13 -5
- package/catalog/archetypes/archetype.frontend.feature_oriented.json +1 -1
- package/catalog/archetypes/archetype.state.async_command.json +4 -4
- package/catalog/catalog-lock.draft.json +1120 -104
- package/catalog/gates/gate.be.api.contract_checks.json +2 -1
- package/catalog/gates/gate.be.chg.contract_change_checks.json +2 -1
- package/catalog/gates/gate.chg.prechange_checks.json +2 -1
- package/catalog/gates/gate.web.api.request_checks.json +2 -1
- package/catalog/gates/gate.web.grid.checks.json +2 -1
- package/catalog/knowledge/knowledge.api.example_stable_error_code.json +2 -1
- package/catalog/knowledge/knowledge.chg.example_compat_window.json +2 -1
- package/catalog/knowledge/knowledge.chg.example_prop_migration.json +2 -1
- package/catalog/knowledge/knowledge.fp.api.field_drift_no_contract.json +2 -1
- package/catalog/knowledge/knowledge.fp.api.per_page_http_client.json +2 -1
- package/catalog/knowledge/knowledge.fp.be.contract_drift.json +2 -1
- package/catalog/knowledge/knowledge.fp.chg.page_local_padding.json +2 -1
- package/catalog/knowledge/knowledge.fp.grid.global_td_width.json +2 -1
- package/catalog/knowledge/knowledge.web.api.example_get_entity_list.json +2 -1
- package/catalog/knowledge/knowledge.web.grid.example_column_preset.json +2 -1
- package/catalog/policies/authority.be.api_contract_ownership.json +2 -1
- package/catalog/policies/authority.be.contract_ownership.json +2 -1
- package/catalog/policies/authority.chg.change_owners.json +2 -1
- package/catalog/policies/authority.web.api.request_owners.json +2 -1
- package/catalog/policies/authority.web.grid.ownership.json +2 -1
- package/catalog/policies/policy.ai.change_plan_first.json +91 -0
- package/catalog/policies/policy.ai.fact_inference_separation.json +91 -0
- package/catalog/policies/policy.ai.read_search_verify_before_write.json +92 -0
- package/catalog/policies/policy.ai.rule_relaxation_approval.json +91 -0
- package/catalog/policies/policy.api.backward_compat_defaults.json +2 -1
- package/catalog/policies/policy.api.contract_impl_consistency.json +2 -1
- package/catalog/policies/policy.api.no_informal_contract.json +2 -1
- package/catalog/policies/policy.arch.adr_immutable_history.json +91 -0
- package/catalog/policies/policy.arch.decision_tradeoff_record.json +2 -1
- package/catalog/policies/policy.arch.no_convenience_over_boundary.json +93 -0
- package/catalog/policies/policy.arch.prefer_verifiable_option.json +92 -0
- package/catalog/policies/policy.authz.no_gating_proxy_trust.json +99 -0
- package/catalog/policies/policy.authz.permission_scope_expansion_gate.json +99 -0
- package/catalog/policies/policy.authz.server_five_factor_verification.json +101 -0
- package/catalog/policies/policy.be.conc.prefer_db_constraints.json +97 -0
- package/catalog/policies/policy.be.db.expand_migrate_contract.json +97 -0
- package/catalog/policies/policy.be.idem.key_payload_conflict.json +97 -0
- package/catalog/policies/policy.be.model.single_boundary_conversion.json +97 -0
- package/catalog/policies/policy.be.sql.index_for_known_queries.json +97 -0
- package/catalog/policies/policy.be.state.single_rule_source.json +97 -0
- package/catalog/policies/policy.be.txn.short_locks_compensation.json +96 -0
- package/catalog/policies/policy.bound.search_first_entry_only.json +91 -0
- package/catalog/policies/policy.boundary.validate_in_encode_out.json +92 -0
- package/catalog/policies/policy.cache.failure_mode_guards.json +93 -0
- package/catalog/policies/policy.cache.lifecycle_definition.json +2 -1
- package/catalog/policies/policy.cache.schema_versioning.json +91 -0
- package/catalog/policies/policy.cfg.config_attribute_completeness.json +95 -0
- package/catalog/policies/policy.cfg.key_rename_dual_read.json +92 -0
- package/catalog/policies/policy.cfg.no_secret_dispersal.json +90 -0
- package/catalog/policies/policy.cfg.production_safe_defaults.json +92 -0
- package/catalog/policies/policy.cfg.schema_backed_config.json +92 -0
- package/catalog/policies/policy.chg.affect_templates.json +2 -1
- package/catalog/policies/policy.chg.breaking_versioning.json +2 -1
- package/catalog/policies/policy.chg.compat_migration_rollback.json +2 -1
- package/catalog/policies/policy.chg.deprecate_before_delete.json +2 -1
- package/catalog/policies/policy.chg.fix_at_root_cause_level.json +2 -1
- package/catalog/policies/policy.chg.no_unrelated_changes.json +91 -0
- package/catalog/policies/policy.chg.observable_evolution.json +2 -1
- package/catalog/policies/policy.chg.prechange_consumer_scan.json +2 -1
- package/catalog/policies/policy.chg.staged_rollout.json +2 -1
- package/catalog/policies/policy.chg.sync_contract_docs_tests.json +2 -1
- package/catalog/policies/policy.conflict.priority_ladder.json +2 -1
- package/catalog/policies/policy.contract.no_invented_facts.json +93 -0
- package/catalog/policies/policy.dep.admission_six_dimension_check.json +2 -1
- package/catalog/policies/policy.dep.build_path_supply_chain.json +93 -0
- package/catalog/policies/policy.dep.change_surface_review.json +2 -1
- package/catalog/policies/policy.dep.introduction_review.json +2 -1
- package/catalog/policies/policy.dep.no_untrusted_source_no_lock_bypass.json +92 -0
- package/catalog/policies/policy.dep.time_boxed_urgent_exception.json +91 -0
- package/catalog/policies/policy.deploy.no_dev_env_as_production_fact.json +91 -0
- package/catalog/policies/policy.deploy.operational_capabilities.json +93 -0
- package/catalog/policies/policy.deploy.runtime_fact_record.json +97 -0
- package/catalog/policies/policy.derived.single_implementation.json +2 -1
- package/catalog/policies/policy.err.failure_five_part_mapping.json +101 -0
- package/catalog/policies/policy.err.no_internal_detail_exposure.json +97 -0
- package/catalog/policies/policy.err.published_code_immutable.json +98 -0
- package/catalog/policies/policy.evid.acceptance_binds_verifiable_evidence.json +92 -0
- package/catalog/policies/policy.evid.no_silent_gate_removal.json +90 -0
- package/catalog/policies/policy.evid.no_unverifiable_pass.json +92 -0
- package/catalog/policies/policy.flag.cleanup_after_full_rollout.json +94 -0
- package/catalog/policies/policy.flag.consistent_off_state.json +92 -0
- package/catalog/policies/policy.flag.kill_switch.json +91 -0
- package/catalog/policies/policy.flag.lifecycle_metadata.json +93 -0
- package/catalog/policies/policy.flag.not_a_permission.json +92 -0
- package/catalog/policies/policy.gate.p0_non_bypassable.json +92 -0
- package/catalog/policies/policy.gate.risk_factors_confirmed.json +93 -0
- package/catalog/policies/policy.guard.no_check_weakening.json +92 -0
- package/catalog/policies/policy.integration.call_definition_minimum.json +95 -0
- package/catalog/policies/policy.integration.fault_containment.json +94 -0
- package/catalog/policies/policy.job.lifecycle_definition.json +96 -0
- package/catalog/policies/policy.job.no_unmanaged_execution.json +92 -0
- package/catalog/policies/policy.job.operational_features.json +93 -0
- package/catalog/policies/policy.obs.actionable_signals.json +93 -0
- package/catalog/policies/policy.obs.alert_with_owner.json +91 -0
- package/catalog/policies/policy.obs.context_field_baseline.json +91 -0
- package/catalog/policies/policy.obs.correlation_context_minimum.json +2 -1
- package/catalog/policies/policy.obs.no_sensitive_or_unbounded_logging.json +92 -0
- package/catalog/policies/policy.obs.no_sensitive_raw_values.json +93 -0
- package/catalog/policies/policy.obs.rum_dimension_whitelist.json +2 -1
- package/catalog/policies/policy.obs.signal_change_impact.json +91 -0
- package/catalog/policies/policy.obs.source_map_access_control.json +92 -0
- package/catalog/policies/policy.obs.telemetry_lifecycle_declared.json +93 -0
- package/catalog/policies/policy.obs.trace_correlation.json +91 -0
- package/catalog/policies/policy.perf.budget_change_retest.json +91 -0
- package/catalog/policies/policy.perf.evidence_binding.json +95 -0
- package/catalog/policies/policy.perf.observation_dimensions.json +94 -0
- package/catalog/policies/policy.proc.checklist_change_policy.json +91 -0
- package/catalog/policies/policy.proc.pre_code_declaration.json +2 -1
- package/catalog/policies/policy.proc.scope_drift_reclassify.json +91 -0
- package/catalog/policies/policy.prv.processing_scope_re_review.json +97 -0
- package/catalog/policies/policy.prv.sensitive_data_six_facts.json +102 -0
- package/catalog/policies/policy.registry.human_fields_validated_decorrelated.json +93 -0
- package/catalog/policies/policy.rel.no_irreversible_unmonitored_full_release.json +91 -0
- package/catalog/policies/policy.rel.observability_before_ship.json +91 -0
- package/catalog/policies/policy.rel.pre_release_confirmation.json +2 -1
- package/catalog/policies/policy.rel.process_change_needs_drill_audit.json +91 -0
- package/catalog/policies/policy.rel.traceable_build.json +93 -0
- package/catalog/policies/policy.role.domain_decision_authority.json +2 -1
- package/catalog/policies/policy.role.human_signs_for_ai.json +93 -0
- package/catalog/policies/policy.sec.authn_policy_unified.json +91 -0
- package/catalog/policies/policy.sec.no_client_side_trust.json +95 -0
- package/catalog/policies/policy.sec.no_longterm_security_disable.json +91 -0
- package/catalog/policies/policy.sec.no_script_readable_credentials.json +91 -0
- package/catalog/policies/policy.sec.no_secrets_in_client_surface.json +91 -0
- package/catalog/policies/policy.sec.relaxation_approval.json +92 -0
- package/catalog/policies/policy.sec.security_relaxation_gate.json +95 -0
- package/catalog/policies/policy.sec.third_party_execution_register.json +2 -1
- package/catalog/policies/policy.sec.trust_boundary_enforcement.json +96 -0
- package/catalog/policies/policy.sec.upload_download_server_recheck.json +91 -0
- package/catalog/policies/policy.sec.url_source_allowlist.json +91 -0
- package/catalog/policies/policy.spec.admission_criteria.json +2 -1
- package/catalog/policies/policy.spec.derived_view_regeneration.json +2 -1
- package/catalog/policies/policy.spec.draft_not_baseline.json +2 -1
- package/catalog/policies/policy.spec.family_conflict_precedence.json +93 -0
- package/catalog/policies/policy.spec.file_structure_contract.json +2 -1
- package/catalog/policies/policy.spec.freeze_before_use.json +93 -0
- package/catalog/policies/policy.spec.metadata_required.json +2 -1
- package/catalog/policies/policy.spec.post_dev_backfill_classify.json +2 -1
- package/catalog/policies/policy.spec.primary_source_basis.json +93 -0
- package/catalog/policies/policy.spec.procedural_record_not_surrogate.json +2 -1
- package/catalog/policies/policy.spec.semantic_identity.json +2 -1
- package/catalog/policies/policy.spec.unresolved_ledger_gate.json +2 -1
- package/catalog/policies/policy.stack.derived_store_not_authority.json +93 -0
- package/catalog/policies/policy.stack.dual_web_stack_boundary.json +93 -0
- package/catalog/policies/policy.stack.entry_chain_recorded.json +93 -0
- package/catalog/policies/policy.stack.entry_limits_aligned.json +94 -0
- package/catalog/policies/policy.stack.local_form_not_prod_fact.json +93 -0
- package/catalog/policies/policy.stack.multi_datastore_ownership.json +93 -0
- package/catalog/policies/policy.stack.no_implicit_selection.json +2 -1
- package/catalog/policies/policy.stack.persistence_coexistence_scope.json +93 -0
- package/catalog/policies/policy.stack.toolchain_versions_pinned.json +95 -0
- package/catalog/policies/policy.stack.upgrade_compat_verified.json +93 -0
- package/catalog/policies/policy.struct.module_entry_dependency_declared.json +92 -0
- package/catalog/policies/policy.struct.no_unexplained_top_level_dir.json +91 -0
- package/catalog/policies/policy.struct.reuse_proven_structure.json +91 -0
- package/catalog/policies/policy.test.control_nondeterminism_keep_diagnosis.json +91 -0
- package/catalog/policies/policy.test.isolation_and_cleanup.json +93 -0
- package/catalog/policies/policy.test.no_synthetic_stability.json +92 -0
- package/catalog/policies/policy.test.pyramid_and_ci_matrix.json +92 -0
- package/catalog/policies/policy.test.removal_justification.json +91 -0
- package/catalog/policies/policy.test.removal_needs_substitute_evidence.json +91 -0
- package/catalog/policies/policy.test.risk_driven_plan.json +92 -0
- package/catalog/policies/policy.test.stable_observable_assertions.json +92 -0
- package/catalog/policies/policy.tool.discoverable_toolchain.json +92 -0
- package/catalog/policies/policy.tool.no_hand_edit_generated_no_ci_drift.json +91 -0
- package/catalog/policies/policy.tool.no_vendored_body_edits.json +94 -0
- package/catalog/policies/policy.tool.scoped_scan_boundary.json +2 -1
- package/catalog/policies/policy.tool.upgrade_verify_lock_rollback.json +92 -0
- package/catalog/policies/policy.web.api.auth_app_client_split.json +2 -1
- package/catalog/policies/policy.web.api.client_change_impact.json +2 -1
- package/catalog/policies/policy.web.api.domain_api_only.json +2 -1
- package/catalog/policies/policy.web.api.error_normalization.json +2 -1
- package/catalog/policies/policy.web.api.generated_client.json +2 -1
- package/catalog/policies/policy.web.api.late_result_guard.json +2 -1
- package/catalog/policies/policy.web.api.mutation_idempotency.json +2 -1
- package/catalog/policies/policy.web.api.no_network_optimism.json +2 -1
- package/catalog/policies/policy.web.api.query_cancel_stale_drop.json +2 -1
- package/catalog/policies/policy.web.api.request_infrastructure.json +2 -1
- package/catalog/policies/policy.web.api.retry_discipline.json +2 -1
- package/catalog/policies/policy.web.api.session_recovery_split.json +2 -1
- package/catalog/policies/policy.web.api.single_http_client.json +2 -1
- package/catalog/policies/policy.web.api.single_loading_source.json +2 -1
- package/catalog/policies/policy.web.api.transport_vs_business.json +2 -1
- package/catalog/policies/policy.web.api.trusted_endpoint_source.json +2 -1
- package/catalog/policies/policy.web.api.typed_domain_naming.json +2 -1
- package/catalog/policies/policy.web.arch.layer_isolation.json +2 -1
- package/catalog/policies/policy.web.arch.naming_conventions.json +2 -1
- package/catalog/policies/policy.web.arch.public_api_barrel.json +2 -1
- package/catalog/policies/policy.web.chg.controlled_change_triggers.json +2 -1
- package/catalog/policies/policy.web.comp.no_trivial_or_god_component.json +91 -0
- package/catalog/policies/policy.web.comp.public_contract_completeness.json +93 -0
- package/catalog/policies/policy.web.copy.action_object_clarity.json +92 -0
- package/catalog/policies/policy.web.copy.enumerable_placement.json +91 -0
- package/catalog/policies/policy.web.copy.error_next_step.json +92 -0
- package/catalog/policies/policy.web.copy.suppression_ledger_discipline.json +2 -1
- package/catalog/policies/policy.web.grid.column_schema_fields.json +2 -1
- package/catalog/policies/policy.web.grid.config_isolation.json +2 -1
- package/catalog/policies/policy.web.grid.freeze_key_columns.json +2 -1
- package/catalog/policies/policy.web.grid.interaction_registry.json +2 -1
- package/catalog/policies/policy.web.grid.keyboard_clipboard.json +2 -1
- package/catalog/policies/policy.web.grid.schema_driven_shell.json +2 -1
- package/catalog/policies/policy.web.grid.schema_versioning.json +2 -1
- package/catalog/policies/policy.web.grid.server_ops_virtualization.json +2 -1
- package/catalog/policies/policy.web.grid.shell_change_matrix.json +2 -1
- package/catalog/policies/policy.web.grid.width_fix_ladder.json +2 -1
- package/catalog/policies/policy.web.handoff.state_matrix_full.json +94 -0
- package/catalog/policies/policy.web.i18n.copy_key_discipline.json +92 -0
- package/catalog/policies/policy.web.i18n.raw_value_for_compute.json +91 -0
- package/catalog/policies/policy.web.page.region_consistency.json +93 -0
- package/catalog/policies/policy.web.perf.budget_skeleton.json +2 -1
- package/catalog/policies/policy.web.style.ownership_matrix.json +2 -1
- package/catalog/policies/policy.web.track.attempt_result_correlation.json +91 -0
- package/catalog/policies/policy.web.track.consent_lifecycle.json +2 -1
- package/catalog/policies/policy.web.track.no_synthetic_actions.json +92 -0
- package/catalog/policies/policy.web.track.privacy_default_deny.json +2 -1
- package/catalog/policies/policy.web.track.stable_event_keys.json +2 -1
- package/catalog/policies/policy.web.track.typed_client_validation.json +91 -0
- package/catalog/policies/policy.web.uiux.provider_evidence_not_business_truth.json +2 -1
- package/catalog/policies/policy.wf.no_planned_as_verified.json +91 -0
- package/catalog/policies/policy.wf.task_facts_preconfirm.json +94 -0
- package/catalog/policies/profile.baseline.java_enterprise_default.json +96 -0
- package/catalog/sensors/sensor.browser.deterministic.json +2 -1
- package/catalog/sensors/sensor.browser.interactive.json +2 -1
- package/catalog/sensors/sensor.build.static.json +2 -1
- package/catalog/sensors/sensor.contract.conformance.json +2 -1
- package/catalog/sensors/sensor.performance.budget.json +2 -1
- package/catalog/sensors/sensor.production.metric.json +2 -1
- package/catalog/tools/seed_b6b_frontend.py +1424 -0
- package/catalog/tools/seed_b6c_backend.py +1495 -0
- package/catalog/tools/seed_b6d_baseline.py +620 -0
- package/catalog/tools/seed_b6e_evidence.py +1305 -0
- package/catalog/tools/seed_d3_review.py +1105 -0
- package/catalog/tools/seed_v06_batch2_materials.py +27 -18
- package/dist/bin.js +20514 -10735
- package/package.json +2 -1
- package/seeds/aggregation-manifest.json +691 -0
- package/seeds/baseline/backend/api-contract.md +26 -0
- package/seeds/baseline/backend/architecture.md +31 -0
- package/seeds/baseline/backend/data-access.md +31 -0
- package/seeds/baseline/backend/directory-structure.md +11 -0
- package/seeds/baseline/backend/integration-runtime.md +21 -0
- package/seeds/baseline/backend/quality.md +31 -0
- package/seeds/baseline/backend/stack.yaml +13 -0
- package/seeds/baseline/backend/transaction-concurrency.md +26 -0
- package/seeds/baseline/data/lineage.md +11 -0
- package/seeds/baseline/data/migration.md +11 -0
- package/seeds/baseline/data/model.md +31 -0
- package/seeds/baseline/data/precision-units.md +31 -0
- package/seeds/baseline/data/quality.md +31 -0
- package/seeds/baseline/frontend/api-and-error.md +21 -0
- package/seeds/baseline/frontend/architecture.md +26 -0
- package/seeds/baseline/frontend/design-system.md +21 -0
- package/seeds/baseline/frontend/directory-structure.md +16 -0
- package/seeds/baseline/frontend/quality.md +26 -0
- package/seeds/baseline/frontend/stack.yaml +17 -0
- package/seeds/baseline/frontend/state-and-data.md +26 -0
- package/seeds/baseline/manifest.yaml +32 -0
- package/seeds/baseline/platform/delivery.md +36 -0
- package/seeds/baseline/platform/environment.md +11 -0
- package/seeds/baseline/platform/observability.md +31 -0
- package/seeds/baseline/platform/security.md +26 -0
- package/seeds/manifest.json +1429 -0
- package/seeds/specs/evidence/accessibility.md +89 -0
- package/seeds/specs/evidence/architecture.md +89 -0
- package/seeds/specs/evidence/browser-e2e.md +91 -0
- package/seeds/specs/evidence/build.md +91 -0
- package/seeds/specs/evidence/business-acceptance.md +89 -0
- package/seeds/specs/evidence/complexity-crap.md +97 -0
- package/seeds/specs/evidence/contract.md +89 -0
- package/seeds/specs/evidence/coverage.md +91 -0
- package/seeds/specs/evidence/data-migration.md +91 -0
- package/seeds/specs/evidence/dead-code-duplicate.md +89 -0
- package/seeds/specs/evidence/dependency-supply-chain.md +89 -0
- package/seeds/specs/evidence/index.md +55 -0
- package/seeds/specs/evidence/mutation.md +89 -0
- package/seeds/specs/evidence/performance.md +89 -0
- package/seeds/specs/evidence/release.md +91 -0
- package/seeds/specs/evidence/runtime-observability.md +91 -0
- package/seeds/specs/evidence/security.md +89 -0
- package/seeds/specs/evidence/typecheck-lint.md +91 -0
- package/seeds/specs/evidence/unit-component-integration.md +91 -0
- package/seeds/specs/evidence/visual-regression.md +89 -0
- package/seeds/specs/hard/stacks/antdesign/antdesign-ui-overlay.md +48 -0
- package/seeds/specs/hard/stacks/antdesign/index.md +20 -0
- package/seeds/specs/hard/stacks/css/css-system-overlay.md +52 -0
- package/seeds/specs/hard/stacks/css/index.md +20 -0
- package/seeds/specs/hard/stacks/geist/geist-design-system-overlay.md +48 -0
- package/seeds/specs/hard/stacks/geist/index.md +20 -0
- package/seeds/specs/hard/stacks/java/index.md +20 -0
- package/seeds/specs/hard/stacks/java/java-language-overlay.md +35 -0
- package/seeds/specs/hard/stacks/jpa/index.md +20 -0
- package/seeds/specs/hard/stacks/jpa/jpa-persistence-overlay.md +35 -0
- package/seeds/specs/hard/stacks/kubernetes-ingress/index.md +20 -0
- package/seeds/specs/hard/stacks/kubernetes-ingress/kubernetes-ingress-overlay.md +35 -0
- package/seeds/specs/hard/stacks/messaging/index.md +20 -0
- package/seeds/specs/hard/stacks/messaging/messaging-reliability-overlay.md +35 -0
- package/seeds/specs/hard/stacks/mybatis/index.md +20 -0
- package/seeds/specs/hard/stacks/mybatis/mybatis-persistence-overlay.md +35 -0
- package/seeds/specs/hard/stacks/mysql/index.md +20 -0
- package/seeds/specs/hard/stacks/mysql/mysql-database-overlay.md +35 -0
- package/seeds/specs/hard/stacks/nginx/index.md +20 -0
- package/seeds/specs/hard/stacks/nginx/nginx-proxy-overlay.md +35 -0
- package/seeds/specs/hard/stacks/postgresql/index.md +20 -0
- package/seeds/specs/hard/stacks/postgresql/postgresql-database-overlay.md +35 -0
- package/seeds/specs/hard/stacks/redis/index.md +20 -0
- package/seeds/specs/hard/stacks/redis/redis-cache-overlay.md +35 -0
- package/seeds/specs/hard/stacks/spring-batch/index.md +20 -0
- package/seeds/specs/hard/stacks/spring-batch/spring-batch-job-overlay.md +35 -0
- package/seeds/specs/hard/stacks/spring-boot/index.md +20 -0
- package/seeds/specs/hard/stacks/spring-boot/spring-boot-application-overlay.md +35 -0
- package/seeds/specs/hard/stacks/spring-mvc/index.md +20 -0
- package/seeds/specs/hard/stacks/spring-mvc/spring-mvc-web-overlay.md +35 -0
- package/seeds/specs/hard/stacks/spring-webflux/index.md +20 -0
- package/seeds/specs/hard/stacks/spring-webflux/spring-webflux-reactive-overlay.md +35 -0
- package/seeds/specs/hard/stacks/tomcat/index.md +20 -0
- package/seeds/specs/hard/stacks/tomcat/tomcat-runtime-overlay.md +35 -0
- package/seeds/specs/hard/stacks/vue3/index.md +20 -0
- package/seeds/specs/hard/stacks/vue3/vue3-framework-overlay.md +71 -0
- package/seeds/specs/hard/themes/ai-generated-code.md +171 -0
- package/seeds/specs/hard/themes/api-contract-and-error-semantics.md +532 -0
- package/seeds/specs/hard/themes/architecture-and-module-boundaries.md +323 -0
- package/seeds/specs/hard/themes/data-and-transactions.md +582 -0
- package/seeds/specs/hard/themes/engineering-toolchain-and-dependencies.md +333 -0
- package/seeds/specs/hard/themes/environment-and-configuration.md +196 -0
- package/seeds/specs/hard/themes/frontend-state-and-client-data.md +342 -0
- package/seeds/specs/hard/themes/index.md +374 -0
- package/seeds/specs/hard/themes/integration-and-async-runtime.md +331 -0
- package/seeds/specs/hard/themes/internationalization-and-copywriting.md +350 -0
- package/seeds/specs/hard/themes/observability-and-analytics.md +305 -0
- package/seeds/specs/hard/themes/page-composition-and-browser-environment.md +554 -0
- package/seeds/specs/hard/themes/performance-and-capacity.md +226 -0
- package/seeds/specs/hard/themes/permission-and-authorization.md +168 -0
- package/seeds/specs/hard/themes/privacy-and-data-lifecycle.md +176 -0
- package/seeds/specs/hard/themes/release-and-feature-flags.md +237 -0
- package/seeds/specs/hard/themes/security.md +372 -0
- package/seeds/specs/hard/themes/task-governance-and-acceptance.md +554 -0
- package/seeds/specs/hard/themes/testing-and-verification.md +266 -0
- package/seeds/specs/hard/themes/ui-presentation-and-design.md +670 -0
- package/seeds/specs/hard/themes/value-semantics-and-domain-data.md +339 -0
|
@@ -0,0 +1,1495 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""B6c BE 协议 33 + stack overlays 28+profile 移植工具(播种资产 + provenance pin +
|
|
3
|
+
D5 精选 policies + TECHNOLOGY_PROFILE 分类面)。
|
|
4
|
+
|
|
5
|
+
输入(只读):
|
|
6
|
+
- pomaster/components/backend-hard-spec/assets/universal/ vendor BE 播种源(33 文件分母)
|
|
7
|
+
- pomaster/components/backend-hard-spec/assets/stacks/ vendor stacks 源(14 目录
|
|
8
|
+
×2 文件 + profiles/java-enterprise-default.yaml = 29 文件分母;profile 不播种)
|
|
9
|
+
- corpus/spec-knowledge/candidates/consolidated-pool.yaml SPEC-D 汇总池(卡分母=MASTer)
|
|
10
|
+
- corpus/spec-knowledge/candidates/{BE-G1..BE-G5}.yaml 候选组卡
|
|
11
|
+
- packages/cli/seeds/manifest.json B6b 两批清单(原样保留并入)
|
|
12
|
+
|
|
13
|
+
输出:
|
|
14
|
+
- packages/cli/seeds/specs/hard/backend/*.md BE 播种件(统一 frontmatter +
|
|
15
|
+
vendor frontmatter 保留字段 + 正文逐字节)
|
|
16
|
+
- packages/cli/seeds/specs/hard/stacks/<slug>/{index,<slug>-overlay}.md
|
|
17
|
+
stacks 播种件(28 份)
|
|
18
|
+
- packages/cli/seeds/manifest.json 播种清单单源(B6b 两批条目
|
|
19
|
+
原样保留 + B6C 61 条追加;107 条全量分母)
|
|
20
|
+
- catalog/policies/policy.*.json / profile.*.json D5 精选 25 条 policies
|
|
21
|
+
(22 required + 3 advisory)+ TECHNOLOGY_PROFILE 分类面 10 条(9 STACK + 1 PROFILE)
|
|
22
|
+
|
|
23
|
+
移植形态定案(ADR-lite,Owner 裁定 B5/D20 框架内;B6b 先例延伸):
|
|
24
|
+
- BE frontmatter 兼容处理(本批新形态):BE vendor 文件自带 6 字段 frontmatter
|
|
25
|
+
(id/criticality/injection_mode/stages/triggers/requires)——播种件 = 统一
|
|
26
|
+
frontmatter(PRD §8.2 字段位减 id,B6b 同款 9 字段)+ vendor frontmatter 保留
|
|
27
|
+
字段(原字段名原值文本级保留;唯 id 改形 legacy_id——backend:/backend-stack:
|
|
28
|
+
前缀为旧包内部语义 ID 词形,非 governed 前缀,R6 以 no-governed-id 回避,值
|
|
29
|
+
如实保留供 index 路由表引用可溯);正文(vendor 去原 frontmatter)逐字节忠实
|
|
30
|
+
(构建两遍逐字节断言)。R8 授权依据(porting-design-proposal R8):injection_mode
|
|
31
|
+
类字段降级为 info 性 frontmatter 注记(A1 档位信息性裁定对齐),不引入执行语义;
|
|
32
|
+
- stacks 子目录守卫机制(本批 ADR,候选三选一):
|
|
33
|
+
① SEEDABLE_STORE_DIRS 登记叶的直接子目录(14 slug 显式登记);
|
|
34
|
+
② manifest 条目声明子目录;
|
|
35
|
+
③ stacks 目录扁平化词形。
|
|
36
|
+
定案取 ①:最小改动(seeds.ts 仅数据增加,精确匹配机制零改动)+ 守卫语义最
|
|
37
|
+
完整(allowlist 保持封闭集合精确匹配,无通配语义;未登记 slug 一律拒绝)。
|
|
38
|
+
slug 集 == vendor stacks 分母 == manifest B6C stacks 条目派生集合,由测试
|
|
39
|
+
三面对账(漂移即爆);新 stack slug 属内容演进批次(Owner 授权后扩常量);
|
|
40
|
+
- profile 分类落位(本批 ADR):vendor profiles/java-enterprise-default.yaml
|
|
41
|
+
**不播种**(提案 §1 矩阵播种面只列 28 文件;旧档位注入机制物在 vNext 无消费者)
|
|
42
|
+
——按提案落 TECHNOLOGY_PROFILE 分类面:池卡 PROFILE.BASELINE.JAVA_ENTERPRISE_
|
|
43
|
+
DEFAULT(BE-G5 backlog,锚 L1-13)物化为 classification=TECHNOLOGY_PROFILE 条目,
|
|
44
|
+
includes 9 项组合为信息性参考(A1 档位信息性裁定:等价物 = baseline stack.yaml
|
|
45
|
+
显式选型 [B6d 落位] + 起步值可预填该组合,非强制)。A1 判档词形(MINIMAL/LIGHT/
|
|
46
|
+
STANDARD)vendor 全资产 grep 零命中(工具断言)——清洗登记为空集;
|
|
47
|
+
- catalog 双面(D5 上限 25/批内执行;D6 口径见裁决 12① 注记):BE universal 33
|
|
48
|
+
分母 → policy 面 25 条(required 22 + advisory 3,BE-G1..G4 池;kind=policy +
|
|
49
|
+
UNIVERSAL_POLICY,enforcement 轴纪律与逆向规则测试扩展到 B6c 分母);stacks
|
|
50
|
+
28+profile 分母 → TECHNOLOGY_PROFILE 面 10 条(BE-G5 池 9 条未物化 POLICY.STACK.*
|
|
51
|
+
ELIGIBLE 卡 + 1 条 PROFILE backlog 卡;classification=TECHNOLOGY_PROFILE 不混入
|
|
52
|
+
policy 强度面——TECHNOLOGY_PROFILE 是 §92.5 激活输入非被激活规则本体,enforcement
|
|
53
|
+
禁 required:9 STACK 池判 required 降级 advisory[强度只降不升],PROFILE 卡池判
|
|
54
|
+
deterministic_where_possible 原样);批合计 35 = policy 面 25(D5 上限)+ TP 面
|
|
55
|
+
10(**Owner 追认例外**——裁决 12①:B6c 已落 10 条 TP 维持现状不改写;未来批
|
|
56
|
+
TP 面与 policy 面合并计入 25/批上限,不再豁免,恰等断言 +
|
|
57
|
+
catalog-b6-porting.spec.ts D6 describe 钉);
|
|
58
|
+
- provenance 双锚(R1,B6b 同款收紧):清单逐条 vendor sha256+bytes(播种分母);
|
|
59
|
+
BE 08/12(spec-inventory pilot_verification 钉死 byte_identical)pin 全等对账
|
|
60
|
+
(取材确为 vendor 字节);vendor↔MASTer 32/33 逐字节一致(唯一漂移 index.md,
|
|
61
|
+
实测;index 卡天然无 12 段锚,required/advisory 池按锚证据保守排除——漂移不
|
|
62
|
+
影响池分母);池卡行号锚按 MASTer 消费树忠实执行(LCS 审计阈值 20 字 fail-closed);
|
|
63
|
+
- 卡层锚词形适配(BE 池杂拼形态,B6b 单一词形的扩展):BE-G1..G4 卡 source 有
|
|
64
|
+
三种词形——{ref,lines,section} / {protocol,sha256,anchor='## X 段(LN-M)'} / null。
|
|
65
|
+
required 池锚证据:section 词形或 anchor 解析段名,且与行号在 MASTer 文件的
|
|
66
|
+
实际段交叉验证(卡声明段 ≠ 行锚实际段 = 分母漂移即爆);source=null → 锚证据
|
|
67
|
+
不足保守排除留池待复核(B6b 先例:不猜 Owner 意图)。advisory 池锚证据:池行
|
|
68
|
+
source_lines(BE 池行统一拍有),MASTer 12 段映射全落 {SHOULD, Change Policy}
|
|
69
|
+
方入选(行锚缺席/非建议段保守排除)。
|
|
70
|
+
|
|
71
|
+
用法:
|
|
72
|
+
python seed_b6c_backend.py # 物化(write_if_changed 幂等)
|
|
73
|
+
python seed_b6c_backend.py --verify # 只读重演(字节逐等比对)
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
import hashlib
|
|
77
|
+
import io
|
|
78
|
+
import json
|
|
79
|
+
import os
|
|
80
|
+
import re
|
|
81
|
+
import sys
|
|
82
|
+
|
|
83
|
+
import yaml
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
try:
|
|
87
|
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
HERE = os.path.dirname(os.path.abspath(__file__)) # .../POMaster_VNext/catalog/tools
|
|
92
|
+
VNEXT = os.path.dirname(os.path.dirname(HERE)) # .../POMaster_VNext
|
|
93
|
+
REPO = os.path.dirname(VNEXT) # d:/Vscode Documents/po-master
|
|
94
|
+
BE_VENDOR_DIR = os.path.join(REPO, "pomaster", "components", "backend-hard-spec",
|
|
95
|
+
"assets", "universal")
|
|
96
|
+
STACKS_VENDOR_DIR = os.path.join(REPO, "pomaster", "components", "backend-hard-spec",
|
|
97
|
+
"assets", "stacks")
|
|
98
|
+
# 池卡行号锚的分母是 MASTer 消费树(SPEC-D 分解只读源)——段映射与 LCS 审计按
|
|
99
|
+
# MASTer 行号忠实执行;vendor 侧只承载播种字节 pin(R1 双分母如实标注,B6b 同款)。
|
|
100
|
+
MASTER_BE_DIR = os.path.join(os.path.dirname(REPO), "MASTer_master", ".trellis", "spec",
|
|
101
|
+
"backend")
|
|
102
|
+
SEEDS_DIR = os.path.join(VNEXT, "packages", "cli", "seeds")
|
|
103
|
+
BE_ASSET_DIR = os.path.join(SEEDS_DIR, "specs", "hard", "backend")
|
|
104
|
+
STACKS_ASSET_DIR = os.path.join(SEEDS_DIR, "specs", "hard", "stacks")
|
|
105
|
+
MANIFEST_PATH = os.path.join(SEEDS_DIR, "manifest.json")
|
|
106
|
+
POOL_PATH = os.path.join(VNEXT, "corpus", "spec-knowledge", "candidates",
|
|
107
|
+
"consolidated-pool.yaml")
|
|
108
|
+
CAND_DIR = os.path.join(VNEXT, "corpus", "spec-knowledge", "candidates")
|
|
109
|
+
POLICY_DIR = os.path.join(VNEXT, "catalog", "policies")
|
|
110
|
+
INVENTORY_PATH = os.path.join(VNEXT, "corpus", "spec-knowledge", "spec-inventory.yaml")
|
|
111
|
+
|
|
112
|
+
BATCH = "B6C"
|
|
113
|
+
MANIFEST_SCHEMA = "pomaster.seed-manifest/1"
|
|
114
|
+
BATCH_SCOPE = ("B6c:BE universal 33 文件(32 编号协议 + index)+ stacks 28 文件"
|
|
115
|
+
"(14 目录 × index+overlay)全量播种 + profile 1 份走 catalog "
|
|
116
|
+
"TECHNOLOGY_PROFILE 分类面不播种(B6b 两批 FE 46 条在册——清单合并承载全量分母)")
|
|
117
|
+
PLANTED_TOTAL = 107
|
|
118
|
+
BE_LANES = "backend"
|
|
119
|
+
STACK_SLUGS = ["java", "jpa", "kubernetes-ingress", "messaging", "mybatis", "mysql",
|
|
120
|
+
"nginx", "postgresql", "redis", "spring-batch", "spring-boot", "spring-mvc",
|
|
121
|
+
"spring-webflux", "tomcat"]
|
|
122
|
+
|
|
123
|
+
AUTHORITY_SCOPE = "mixed_required_and_advisory"
|
|
124
|
+
|
|
125
|
+
# R1 漂移对账锚:spec-inventory pilot_verification 钉死 BE 08/12 的 vendor sha256
|
|
126
|
+
# (byte_identical 钉值)——启动时 load_pilot_pins() 读取,build_seed_assets 全等对账。
|
|
127
|
+
# B6b-II 收紧的同款全等断言:截断回退已移除,取材分母漂移在工具侧即爆。
|
|
128
|
+
PILOT_PINNED_FILES = ["08-contract-change-protocol.md", "12-api-contract-protocol.md"]
|
|
129
|
+
|
|
130
|
+
# A1 档位词形(判档叙述零移植——A1 裁定;vendor 全资产零命中断言 = 空集登记)。
|
|
131
|
+
A1_GRADE_PATTERN = re.compile(r"\b(MINIMAL|LIGHT|STANDARD)\b")
|
|
132
|
+
|
|
133
|
+
# R8 词形清洗台账(裁决 12/D5 授权内容演进批次,2026-09-05 执行):
|
|
134
|
+
# - frontmatter 保留字段注记(NOTE_FRONTMATTER)为移植形态登记(info 性字段保留
|
|
135
|
+
# 决策),非清洗对象——维持原样;
|
|
136
|
+
# - BE 32 编号协议正文实测零命中(finish/.trellis/Trellis 词形零命中)——清洗表为
|
|
137
|
+
# 空集;index.md 品牌词 + 注入机制叙述段已清洗(BE_INDEX_R8_CLEANLINES 整行替换
|
|
138
|
+
# + 计数断言;前后对照在 porting_notes)。
|
|
139
|
+
NOTE_FRONTMATTER = (
|
|
140
|
+
"R8 词形登记:vendor frontmatter criticality/injection_mode/stages/triggers 为旧包"
|
|
141
|
+
"注入机制词形,vNext 无注入器机制——以 info 性 frontmatter 注记字段保留(A1 档位"
|
|
142
|
+
"信息性裁定对齐),不引入执行语义;id 字段改形 legacy_id(backend: 前缀为旧包内部"
|
|
143
|
+
"语义 ID,非 governed 词形,no-governed-id 默认)"
|
|
144
|
+
)
|
|
145
|
+
PORTING_NOTES = {
|
|
146
|
+
"index.md": [
|
|
147
|
+
NOTE_FRONTMATTER,
|
|
148
|
+
"R8 词形清洗(已执行,裁决 12/D5,2026-09-05):'任务 Trigger 矩阵'段尾句整行"
|
|
149
|
+
"改写——'矩阵只产生候选 trigger;注入器必须对结果继续执行 stage、injection "
|
|
150
|
+
"mode、显式 reference、Overlay 依赖与冲突校验,并在 Trellis context reason 中"
|
|
151
|
+
"记录 semantic ID、stage、命中原因和 provider hash。' → '矩阵只产生候选特征;"
|
|
152
|
+
"实际纳入由 pomaster context compile --role <role> 投影承载(Overlay 依赖与冲突"
|
|
153
|
+
"按「冲突与责任边界」收窄),纳入/排除决策可经 pomaster context explain 逐条"
|
|
154
|
+
"审计。'(旧包注入器/Trellis context reason/provider hash 机制叙述删除;"
|
|
155
|
+
"pomaster 命令面真实存在——context compile/explain)。原登记(B6c):旧包任务"
|
|
156
|
+
"机制词形保留待授权清洗(已由本批清洗收口)",
|
|
157
|
+
"R8 词形清洗(已执行,裁决 12/D5,2026-09-05):'使用规则/默认注入基线/任务 "
|
|
158
|
+
"Trigger 矩阵'三段 vNext 化改写——注入顺序叙述 → init 播种(seed-once)+ "
|
|
159
|
+
"pomaster context compile 投影激活语义;段名 '默认注入基线'→'默认激活基线'、"
|
|
160
|
+
"'任务 Trigger 矩阵'→'任务命中矩阵'(维护段交叉引用随改);表列 '实际默认加载'"
|
|
161
|
+
"→'建议纳入上下文'、'always 协议'→'基线协议'、'建议 Trigger'→'建议命中的协议"
|
|
162
|
+
"特征';'重跑注入'→'重跑播种(init)'(seed-once 语义句保留——原登记注记的"
|
|
163
|
+
"一致面)。协议清单/矩阵行数据零触碰。原登记(B6c):旧包注入机制叙述保留待"
|
|
164
|
+
"授权清洗(已由本批清洗收口)",
|
|
165
|
+
"R8 词形注记:正文 'stacks/<slug>/<slug>-overlay.md' 相对词形(L18/L54)在 "
|
|
166
|
+
"vNext 播种面(.pomaster/specs/hard/)下自洽指向 specs/hard/stacks/<slug>/"
|
|
167
|
+
"<slug>-overlay.md——零改写保留原文",
|
|
168
|
+
"R8 词形清洗(已执行,裁决 12/D5 同类授权延伸,裁定批 F,2026-09-05):BE index "
|
|
169
|
+
"注入机制叙述残留 2 行 vNext 化——引言行 '不表示 criticality 或注入优先级'→"
|
|
170
|
+
"'激活优先级';维护规则段 '同步索引、模板、注入器测试和 provider bytes/hash'→"
|
|
171
|
+
"'同步索引、模板、播种清单与 catalog 锁校验'(vNext 对应物 = seeds manifest "
|
|
172
|
+
"source sha256/bytes pin + catalog relock)。'注入防护'(协议目录 10 号安全协议"
|
|
173
|
+
"行)为安全领域词(SQL/脚本注入防护语义)非旧包注入机制词形——零改写保留原文;"
|
|
174
|
+
"frontmatter injection_mode 保留字段与协议目录表 always/triggered 行数据为既登记 "
|
|
175
|
+
"info 性注记/零触碰面,维持不动。原登记(B6c):残留注入词形留待授权清洗(本批"
|
|
176
|
+
"收口)",
|
|
177
|
+
],
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# R8 词形清洗表(裁决 12/D5 授权内容演进批次,2026-09-05 执行):整行替换 + 逐条
|
|
181
|
+
# 计数断言(vendor 漂移即爆,禁静默零替换);只动登记过的词形/段('使用规则/默认
|
|
182
|
+
# 注入基线/任务 Trigger 矩阵'三段 + 尾句品牌词 + 段名交叉引用一致性),其余正文
|
|
183
|
+
# 仍逐字节 == vendor 去原 frontmatter。对照记录在 PORTING_NOTES;测试镜像钉在
|
|
184
|
+
# packages/cli/tests/seed-manifest.spec.ts(清洗后基线)。
|
|
185
|
+
BE_INDEX_R8_CLEANLINES = [
|
|
186
|
+
("注入顺序固定为:按当前 stage 过滤、加入 always 基线、加入命中 trigger 的 "
|
|
187
|
+
"triggered 协议、加入显式请求的 reference 协议,最后去重并校验依赖。`criticality`"
|
|
188
|
+
" 只决定违规严重度,不参与默认选择。\n",
|
|
189
|
+
"本目录协议由 init 一次性播种到 `.pomaster/specs/hard/backend/`(seed-once:缺席"
|
|
190
|
+
"才写、在座零触碰);开发/验收上下文的协议激活由 `pomaster context compile --role "
|
|
191
|
+
"<role>` 投影承载(frontmatter 的 injection_mode/stages/triggers 为移植保留的 "
|
|
192
|
+
"info 性注记,非执行语义)。`criticality` 只决定违规严重度,不参与默认选择。\n",
|
|
193
|
+
1),
|
|
194
|
+
("下方「协议目录」与「任务 Trigger 矩阵」,保持双向索引完整。\n",
|
|
195
|
+
"下方「协议目录」与「任务命中矩阵」,保持双向索引完整。\n", 1),
|
|
196
|
+
("重跑注入默认只补齐缺失文件、不覆盖已存在的协议,所以就地维护不会被覆盖。\n",
|
|
197
|
+
"重跑播种(init)默认只补齐缺失文件、不覆盖已存在的协议,所以就地维护不会被覆盖。\n",
|
|
198
|
+
1),
|
|
199
|
+
("## 默认注入基线\n", "## 默认激活基线\n", 1),
|
|
200
|
+
("候选基线严格只有以下 5 个短协议和索引;实际选择继续接受 stage 过滤。\n",
|
|
201
|
+
"默认激活面严格只有以下 5 个短协议和索引;实际命中按任务特征(见「任务命中矩阵」)"
|
|
202
|
+
"继续收窄。\n", 1),
|
|
203
|
+
("| Stage | 实际默认加载 |\n", "| Stage | 建议纳入上下文 |\n", 1),
|
|
204
|
+
("| check | index 加全部 5 个 always 协议 |\n",
|
|
205
|
+
"| check | index 加全部 5 个基线协议 |\n", 1),
|
|
206
|
+
("## 任务 Trigger 矩阵\n", "## 任务命中矩阵\n", 1),
|
|
207
|
+
("| 任务特征 | 建议 Trigger |\n", "| 任务特征 | 建议命中的协议特征 |\n", 1),
|
|
208
|
+
("矩阵只产生候选 trigger;注入器必须对结果继续执行 stage、injection mode、显式 "
|
|
209
|
+
"reference、Overlay 依赖与冲突校验,并在 Trellis context reason 中记录 semantic "
|
|
210
|
+
"ID、stage、命中原因和 provider hash。\n",
|
|
211
|
+
"矩阵只产生候选特征;实际纳入由 `pomaster context compile --role <role>` 投影承载"
|
|
212
|
+
"(Overlay 依赖与冲突按「冲突与责任边界」收窄),纳入/排除决策可经 `pomaster "
|
|
213
|
+
"context explain` 逐条审计。\n", 1),
|
|
214
|
+
# ---- 裁定批 F(D5 同类授权延伸,2026-09-05):BE index 注入机制叙述残留 2 行
|
|
215
|
+
# vNext 化;'注入防护'(协议目录 10 号行)为安全领域词非机制词形——零改写(注记在
|
|
216
|
+
# PORTING_NOTES)。
|
|
217
|
+
("本目录包含 32 个编号协议和本索引。语义 ID、编号和 canonical filename 是稳定地址;"
|
|
218
|
+
"编号只追加,不表示 criticality 或注入优先级。协议正文只定义跨项目治理,不保存项目 "
|
|
219
|
+
"endpoint、table、column、业务状态、环境阈值或责任人。\n",
|
|
220
|
+
"本目录包含 32 个编号协议和本索引。语义 ID、编号和 canonical filename 是稳定地址;"
|
|
221
|
+
"编号只追加,不表示 criticality 或激活优先级。协议正文只定义跨项目治理,不保存项目 "
|
|
222
|
+
"endpoint、table、column、业务状态、环境阈值或责任人。\n", 1),
|
|
223
|
+
("协议编号、语义 ID 与 canonical filename 只追加不重排。新增或修改规则必须同步索引、"
|
|
224
|
+
"模板、注入器测试和 provider bytes/hash;废弃规则必须提供替代 ID、兼容窗口和迁移"
|
|
225
|
+
"说明。\n",
|
|
226
|
+
"协议编号、语义 ID 与 canonical filename 只追加不重排。新增或修改规则必须同步索引、"
|
|
227
|
+
"模板、播种清单与 catalog 锁校验;废弃规则必须提供替代 ID、兼容窗口和迁移说明。\n", 1),
|
|
228
|
+
]
|
|
229
|
+
DEFAULT_BE_NOTES = [NOTE_FRONTMATTER]
|
|
230
|
+
STACK_OVERLAY_NOTE = (
|
|
231
|
+
"B6c 移植注记:本 overlay 随 14 组全量播种(installed=true);bound(选中态)由 "
|
|
232
|
+
"baseline/backend/stack.yaml 显式选型派生(B6d 落位),不作隐式基线(目录 index "
|
|
233
|
+
"原语义词形)"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def load_pilot_pins():
|
|
238
|
+
"""spec-inventory pilot_verification 钉值 → {文件名: vendor sha256}(BE 08/12)。"""
|
|
239
|
+
doc = yaml.safe_load(open(INVENTORY_PATH, encoding="utf-8"))
|
|
240
|
+
pins = {}
|
|
241
|
+
for f in (doc.get("meta", {}).get("pilot_verification", {}) or {}).get("files", []) or []:
|
|
242
|
+
name = (f.get("pilot_source_ref") or "").split("/")[-1]
|
|
243
|
+
if name:
|
|
244
|
+
pins[name] = f.get("pilot_source_sha256")
|
|
245
|
+
return pins
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# ======================================================================
|
|
249
|
+
# 统一 frontmatter + vendor frontmatter 保留字段(BE 本批新形态)
|
|
250
|
+
# ======================================================================
|
|
251
|
+
def split_vendor_frontmatter(vendor_bytes):
|
|
252
|
+
"""vendor 字节 → (frontmatter 行列表或 None, 正文字节)。
|
|
253
|
+
|
|
254
|
+
vendor BE 文件以 `---\\n` 开头(6 字段 frontmatter);stack index.md 无 frontmatter
|
|
255
|
+
(`#` 标题开头)。正文 = 原 frontmatter 块之后的全部字节(逐字节忠实断言分母)。
|
|
256
|
+
"""
|
|
257
|
+
if not vendor_bytes.startswith(b"---\n"):
|
|
258
|
+
return None, vendor_bytes
|
|
259
|
+
end = vendor_bytes.find(b"\n---\n", 4)
|
|
260
|
+
assert end > 0, "vendor frontmatter 块未闭合"
|
|
261
|
+
block = vendor_bytes[4:end].decode("utf-8")
|
|
262
|
+
body = vendor_bytes[end + 5:]
|
|
263
|
+
return block.split("\n"), body
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def build_unified_frontmatter(source_rel, sha_hex, seed_version, lane, vendor_fm_lines):
|
|
267
|
+
"""统一 9 字段(B6b 词形)+ vendor frontmatter 保留字段(原行文本级保留)。
|
|
268
|
+
|
|
269
|
+
保留规则(BE frontmatter 兼容 ADR):id 行改形 legacy_id;applies_to 行并入统一
|
|
270
|
+
字段(overlay applies_to: [backend] 与统一字段值恰同——单行承载);其余行原样
|
|
271
|
+
保留(criticality/injection_mode/stages/triggers/requires/capability/conflicts/
|
|
272
|
+
coexistence——R8 降级 info 注记,词形零重排)。
|
|
273
|
+
"""
|
|
274
|
+
kept = []
|
|
275
|
+
if vendor_fm_lines is not None:
|
|
276
|
+
for line in vendor_fm_lines:
|
|
277
|
+
if line.startswith("id:"):
|
|
278
|
+
kept.append("legacy_id: " + line[len("id:"):].strip())
|
|
279
|
+
elif line.startswith("applies_to:"):
|
|
280
|
+
continue
|
|
281
|
+
else:
|
|
282
|
+
kept.append(line)
|
|
283
|
+
lines = [
|
|
284
|
+
"---",
|
|
285
|
+
f"seed_source: {source_rel}",
|
|
286
|
+
f"seed_source_sha256: {sha_hex}",
|
|
287
|
+
f"seed_version: {seed_version}",
|
|
288
|
+
f"lane: {lane}",
|
|
289
|
+
"status: CURRENT",
|
|
290
|
+
f"authority_scope: {AUTHORITY_SCOPE}",
|
|
291
|
+
f"applies_to: [{lane}]",
|
|
292
|
+
"related_evidence_specs: []",
|
|
293
|
+
"related_tools: []",
|
|
294
|
+
] + kept + [
|
|
295
|
+
"---",
|
|
296
|
+
"",
|
|
297
|
+
]
|
|
298
|
+
return ("\n".join(lines) + "\n").encode("utf-8")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def apply_r8_cleanups(body, cleanlines):
|
|
302
|
+
"""R8 清洗(裁决 12/D5 授权内容演进批次,2026-09-05):整行替换 + 逐条计数断言
|
|
303
|
+
(vendor 漂移即爆,禁静默零替换);最小改写——未列词形/段零触碰。"""
|
|
304
|
+
for old, new, expect_count in cleanlines:
|
|
305
|
+
old_b, new_b = old.encode("utf-8"), new.encode("utf-8")
|
|
306
|
+
found = body.count(old_b)
|
|
307
|
+
assert found == expect_count, (
|
|
308
|
+
f"R8 清洗锚点计数漂移:{old[:36]!r}… 预期 {expect_count} 处,实测 {found} 处")
|
|
309
|
+
body = body.replace(old_b, new_b)
|
|
310
|
+
return body
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def seed_body_for(vendor_bytes, source_rel, sha_hex, seed_version, lane,
|
|
314
|
+
r8_cleanlines=None):
|
|
315
|
+
"""统一 frontmatter + 正文;正文逐字节 == vendor 去原 frontmatter(构建两遍同构;
|
|
316
|
+
r8_cleanlines 在座时施加 R8 清洗整行替换——裁决 12/D5,仅登记面)。"""
|
|
317
|
+
fm_lines, vendor_body = split_vendor_frontmatter(vendor_bytes)
|
|
318
|
+
body = apply_r8_cleanups(vendor_body, r8_cleanlines) if r8_cleanlines else vendor_body
|
|
319
|
+
fm = build_unified_frontmatter(source_rel, sha_hex, seed_version, lane, fm_lines)
|
|
320
|
+
seeded = fm + body
|
|
321
|
+
assert seeded[len(fm):] == body
|
|
322
|
+
_, vendor_body_again = split_vendor_frontmatter(vendor_bytes)
|
|
323
|
+
assert vendor_body_again == vendor_body
|
|
324
|
+
return seeded
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
# ======================================================================
|
|
328
|
+
# 播种资产构建(BE 33 + stacks 28;profile 不播种——ADR)
|
|
329
|
+
# ======================================================================
|
|
330
|
+
def vendor_be_name(num_or_index):
|
|
331
|
+
"""批分母项('01'..'32'/'index')→ vendor 文件名(分母漂移即爆)。"""
|
|
332
|
+
if num_or_index == "index":
|
|
333
|
+
name = "index.md"
|
|
334
|
+
assert os.path.isfile(os.path.join(BE_VENDOR_DIR, name)), "vendor BE index.md 缺席"
|
|
335
|
+
return name
|
|
336
|
+
names = [n for n in os.listdir(BE_VENDOR_DIR)
|
|
337
|
+
if n.startswith(num_or_index + "-") and n.endswith(".md")]
|
|
338
|
+
assert len(names) == 1, f"vendor BE 分母漂移({num_or_index}-* 命中 {names})"
|
|
339
|
+
return names[0]
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def build_seed_assets(pilot_pins):
|
|
343
|
+
"""61 份播种件字节 + manifest 文档(B6b 两批条目原样保留 + B6C 61 条追加)。"""
|
|
344
|
+
assets = {}
|
|
345
|
+
b6c_entries = []
|
|
346
|
+
b6c_targets = []
|
|
347
|
+
# A1 判档词形零命中断言(vendor 全资产——BE universal + stacks 树含 profile)。
|
|
348
|
+
for root in (BE_VENDOR_DIR, STACKS_VENDOR_DIR):
|
|
349
|
+
for base, _dirs, files in os.walk(root):
|
|
350
|
+
for fn in files:
|
|
351
|
+
text = open(os.path.join(base, fn), encoding="utf-8").read()
|
|
352
|
+
hit = A1_GRADE_PATTERN.search(text)
|
|
353
|
+
assert hit is None, f"A1 判档词形命中 {fn}: {hit.group(0)}(清洗登记非空集——停)"
|
|
354
|
+
# BE universal 33(32 编号协议 + index)。
|
|
355
|
+
for num in [f"{n:02d}" for n in range(1, 33)] + ["index"]:
|
|
356
|
+
name = vendor_be_name(num)
|
|
357
|
+
vendor_bytes = open(os.path.join(BE_VENDOR_DIR, name), "rb").read()
|
|
358
|
+
sha_hex = hashlib.sha256(vendor_bytes).hexdigest()
|
|
359
|
+
if name in pilot_pins:
|
|
360
|
+
expected = pilot_pins[name]
|
|
361
|
+
assert expected and sha_hex == expected, (
|
|
362
|
+
f"R1 pin 对账失败:{name} vendor sha 与 pilot_verification 钉死值不符 "
|
|
363
|
+
f"(取材分母漂移?): {sha_hex} vs {expected}")
|
|
364
|
+
source_rel = f"pomaster/components/backend-hard-spec/assets/universal/{name}"
|
|
365
|
+
body = seed_body_for(vendor_bytes, source_rel, sha_hex, BATCH, BE_LANES,
|
|
366
|
+
r8_cleanlines=BE_INDEX_R8_CLEANLINES
|
|
367
|
+
if name == "index.md" else None)
|
|
368
|
+
rel = f"specs/hard/backend/{name}"
|
|
369
|
+
assets[rel] = body
|
|
370
|
+
target = f".pomaster/{rel}"
|
|
371
|
+
b6c_targets.append(target)
|
|
372
|
+
b6c_entries.append({
|
|
373
|
+
"target": target,
|
|
374
|
+
"asset": rel,
|
|
375
|
+
"seed_version": BATCH,
|
|
376
|
+
"lane": BE_LANES,
|
|
377
|
+
"source_path": source_rel,
|
|
378
|
+
"source_sha256": sha_hex,
|
|
379
|
+
"source_bytes": len(vendor_bytes),
|
|
380
|
+
"porting_notes": list(PORTING_NOTES.get(name, DEFAULT_BE_NOTES)),
|
|
381
|
+
})
|
|
382
|
+
# stacks 14 目录 ×2(index.md 无 vendor frontmatter → 纯统一 9 字段;overlay 同
|
|
383
|
+
# BE 混合形态;slug 集封闭——vendor 目录实数对账,漂移即爆)。
|
|
384
|
+
actual_slugs = sorted(d for d in os.listdir(STACKS_VENDOR_DIR)
|
|
385
|
+
if os.path.isdir(os.path.join(STACKS_VENDOR_DIR, d))
|
|
386
|
+
and d != "profiles")
|
|
387
|
+
assert actual_slugs == sorted(STACK_SLUGS), (
|
|
388
|
+
f"stacks slug 分母漂移: {actual_slugs} vs {sorted(STACK_SLUGS)}")
|
|
389
|
+
for slug in STACK_SLUGS:
|
|
390
|
+
slug_dir = os.path.join(STACKS_VENDOR_DIR, slug)
|
|
391
|
+
names = sorted(os.listdir(slug_dir))
|
|
392
|
+
overlays = [n for n in names if n.startswith(slug) and n.endswith("-overlay.md")]
|
|
393
|
+
assert names == sorted(["index.md", overlays[0]]) and len(overlays) == 1, \
|
|
394
|
+
f"stack {slug} 目录文件集漂移: {names}"
|
|
395
|
+
for name in ("index.md", overlays[0]):
|
|
396
|
+
vendor_bytes = open(os.path.join(slug_dir, name), "rb").read()
|
|
397
|
+
sha_hex = hashlib.sha256(vendor_bytes).hexdigest()
|
|
398
|
+
source_rel = (f"pomaster/components/backend-hard-spec/assets/stacks/"
|
|
399
|
+
f"{slug}/{name}")
|
|
400
|
+
body = seed_body_for(vendor_bytes, source_rel, sha_hex, BATCH, BE_LANES)
|
|
401
|
+
rel = f"specs/hard/stacks/{slug}/{name}"
|
|
402
|
+
assets[rel] = body
|
|
403
|
+
target = f".pomaster/{rel}"
|
|
404
|
+
b6c_targets.append(target)
|
|
405
|
+
notes = [STACK_OVERLAY_NOTE] if name.endswith("-overlay.md") else []
|
|
406
|
+
b6c_entries.append({
|
|
407
|
+
"target": target,
|
|
408
|
+
"asset": rel,
|
|
409
|
+
"seed_version": BATCH,
|
|
410
|
+
"lane": BE_LANES,
|
|
411
|
+
"source_path": source_rel,
|
|
412
|
+
"source_sha256": sha_hex,
|
|
413
|
+
"source_bytes": len(vendor_bytes),
|
|
414
|
+
"porting_notes": notes,
|
|
415
|
+
})
|
|
416
|
+
# profile 不播种(ADR:TECHNOLOGY_PROFILE 分类面承载——catalog 侧条目)。
|
|
417
|
+
profile_path = os.path.join(STACKS_VENDOR_DIR, "profiles", "java-enterprise-default.yaml")
|
|
418
|
+
assert os.path.isfile(profile_path), "vendor profile 缺席"
|
|
419
|
+
|
|
420
|
+
# manifest(merge_preserving——裁定批 F 工具-目录漂移修复 ADR:磁盘清单为多批
|
|
421
|
+
# 合并单源,本工具重演只重算 B6C 名单与条目;其余批(B6b 两批/B6D/B6E…)的批次
|
|
422
|
+
# 名单、条目与磁盘头部字段(batch/generated_by/denominator/seed_semantics/
|
|
423
|
+
# authority_scope)**原样保留**——原 kept 硬编码 B6b 两批 + 头部纯重建形态会把
|
|
424
|
+
# B6d/B6e 追加内容覆写掉(清单漂移源),同类语义收口;本批重算与磁盘逐字差异
|
|
425
|
+
# 由 --verify 字节比对如实暴露)。
|
|
426
|
+
old_doc = json.loads(open(MANIFEST_PATH, encoding="utf-8").read())
|
|
427
|
+
assert old_doc["schema"] == MANIFEST_SCHEMA
|
|
428
|
+
old_entries = old_doc["entries"]
|
|
429
|
+
old_batches = old_doc.get("batches") or {}
|
|
430
|
+
assert BATCH in old_batches, "磁盘清单缺 B6C 批名单"
|
|
431
|
+
# 原位替换(磁盘键序/条目序恒保持——merge 收敛性:B6b/B6c 交替重演不漂移)。
|
|
432
|
+
by_target = {e["target"]: e for e in b6c_entries}
|
|
433
|
+
merged_entries = []
|
|
434
|
+
seen = set()
|
|
435
|
+
for e in old_entries:
|
|
436
|
+
if e["target"] in by_target:
|
|
437
|
+
merged_entries.append(by_target[e["target"]])
|
|
438
|
+
seen.add(e["target"])
|
|
439
|
+
else:
|
|
440
|
+
merged_entries.append(e)
|
|
441
|
+
missing = set(by_target) - seen
|
|
442
|
+
assert not missing, f"本批条目在磁盘清单缺席(名单漂移): {sorted(missing)}"
|
|
443
|
+
batch_targets = {}
|
|
444
|
+
for k, v in old_batches.items():
|
|
445
|
+
batch_targets[k] = list(b6c_targets) if k == BATCH else list(v)
|
|
446
|
+
manifest_doc = dict(old_doc)
|
|
447
|
+
manifest_doc["batches"] = batch_targets
|
|
448
|
+
manifest_doc["entries"] = merged_entries
|
|
449
|
+
assert len(manifest_doc["entries"]) == old_doc["denominator"]["planted"], \
|
|
450
|
+
"manifest 合并分母与磁盘 denominator.planted 漂移"
|
|
451
|
+
return assets, manifest_doc, b6c_entries
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
# ======================================================================
|
|
455
|
+
# 池选取(policy 22+3;TECHNOLOGY_PROFILE 9+1)
|
|
456
|
+
# ======================================================================
|
|
457
|
+
GROUPS = ["BE-G1", "BE-G2", "BE-G3", "BE-G4", "BE-G5"]
|
|
458
|
+
LCS_THRESHOLD = 20
|
|
459
|
+
REQUIRED_CAP = 22
|
|
460
|
+
ADVISORY_CAP = 3
|
|
461
|
+
CURATED_CAP = REQUIRED_CAP + ADVISORY_CAP # 25 = D5 上限(policy 强度面)
|
|
462
|
+
# D6 TP 口径(Owner 裁决 12①,2026-09-05):D5 上限 25/批自此对 TECHNOLOGY_PROFILE
|
|
463
|
+
# 登记面一并计入——未来批 TP+policy 合并判卷,不再豁免。B6c 已落 10 条 TP 为
|
|
464
|
+
# **Owner 追认例外**维持现状不改写:批合计 = 25(policy 面)+ 10(TP 追认例外),
|
|
465
|
+
# 恰等断言钉死(select_curated);测试钉 = tests/integration/catalog-b6-porting.
|
|
466
|
+
# spec.ts D6 describe(追认例外恰等 + 未来批合并上限守卫)。
|
|
467
|
+
D5_CAP_PER_BATCH = 25 # D5 保守上限(裁决 12① 起 = policy + TP 合并口径)
|
|
468
|
+
GRANDFATHERED_TP_B6C = 10 # B6c TP 面 Owner 追认例外(裁决 12①)
|
|
469
|
+
POOL_REL = "POMaster_VNext/corpus/spec-knowledge/candidates/consolidated-pool.yaml"
|
|
470
|
+
CLEAN_ROOM_NOTE = ("independently rewritten from SPEC-D decomposition candidate cards; "
|
|
471
|
+
"zero verbatim copy")
|
|
472
|
+
|
|
473
|
+
# x-vocab-pr resolution 转正词形(裁定批 B/D4=vocab PR-0009 落地,2026-09-05;裁定批 F
|
|
474
|
+
# 工具-目录漂移修复纳入 builder 常量——ADR:常量纳编而非 merge_preserving,保工具单源
|
|
475
|
+
# 重演语义,最小改动;与 catalog/policies 在册条目 resolution 逐字节一致。policy 面
|
|
476
|
+
# 与 TECHNOLOGY_PROFILE 面两词形——TP 面含 classification/PROFILE/BASELINE 专段)。
|
|
477
|
+
VOCAB_PR_RESOLUTION_POLICY = (
|
|
478
|
+
"2026-09-05 vocab PR-0009 收编落地(vocab-lock@v0.8-resolved,三镜像同 commit;"
|
|
479
|
+
"Owner 裁定 D4=(a) 2026-09-05):kind='policy' 是 catalog 物料分类词形"
|
|
480
|
+
"(catalog_layer_vocab.catalog_kind 在册——PR-0006,不受 kinds_registry.truth_bodies "
|
|
481
|
+
"闭包管辖),POLICY. 前缀为 governed 闭包既有前缀,id 域段词形随 "
|
|
482
|
+
"catalog_layer_vocab.policy_id_domains / policy_web_domains 收编;本 pending 注记就此"
|
|
483
|
+
"转正(finding/proposal/locked_vocab_untouched 为创建时点历史记录原样保留——"
|
|
484
|
+
"mcp_eyes 先例)"
|
|
485
|
+
)
|
|
486
|
+
VOCAB_PR_RESOLUTION_TP = (
|
|
487
|
+
"2026-09-05 vocab PR-0009 收编落地(vocab-lock@v0.8-resolved,三镜像同 commit;"
|
|
488
|
+
"Owner 裁定 D4=(a) 2026-09-05):kind='policy' 是 catalog 物料分类词形"
|
|
489
|
+
"(catalog_layer_vocab.catalog_kind 在册——PR-0006);classification=TECHNOLOGY_PROFILE "
|
|
490
|
+
"为 §93.4 十二值现成词形(零扩值);PROFILE 前缀为 governed 闭包既有前缀,BASELINE "
|
|
491
|
+
"域段随 catalog_layer_vocab.authority_knowledge_profile_domains 收编;本 pending 注记"
|
|
492
|
+
"就此转正(finding/proposal/locked_vocab_untouched 为创建时点历史记录原样保留)"
|
|
493
|
+
)
|
|
494
|
+
POOL_SELF_ANCHOR = {
|
|
495
|
+
"eligible": 180,
|
|
496
|
+
"canonical": 895,
|
|
497
|
+
"absorbed": 175,
|
|
498
|
+
"total": 1070,
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
TWELVE_SECTION_NAMES = {"Scope", "Non-Scope", "Terms", "MUST", "MUST NOT", "SHOULD",
|
|
502
|
+
"Contract", "Checklist", "Examples", "Anti-patterns",
|
|
503
|
+
"Ownership", "Change Policy"}
|
|
504
|
+
OVERLAY_SECTION_NAMES = {"Scope", "Rules", "Checklist"}
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def load_raw_cards():
|
|
508
|
+
cards = {}
|
|
509
|
+
|
|
510
|
+
def walk(node, out):
|
|
511
|
+
if isinstance(node, dict):
|
|
512
|
+
if "proposed_id" in node:
|
|
513
|
+
out.append(node)
|
|
514
|
+
return
|
|
515
|
+
for v in node.values():
|
|
516
|
+
walk(v, out)
|
|
517
|
+
elif isinstance(node, list):
|
|
518
|
+
for v in node:
|
|
519
|
+
walk(v, out)
|
|
520
|
+
|
|
521
|
+
for group in GROUPS:
|
|
522
|
+
path = os.path.join(CAND_DIR, group + ".yaml")
|
|
523
|
+
doc = yaml.safe_load(open(path, encoding="utf-8"))
|
|
524
|
+
found = []
|
|
525
|
+
walk(doc, found)
|
|
526
|
+
for c in found:
|
|
527
|
+
cid = c.get("proposed_id")
|
|
528
|
+
if cid:
|
|
529
|
+
assert cid not in cards, f"跨组 id 撞名: {cid}"
|
|
530
|
+
cards[cid] = {"group": group, "raw": c}
|
|
531
|
+
return cards
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def _norm_ws(s):
|
|
535
|
+
return re.sub(r"\s+", "", s)
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def _lcs_len(a, b):
|
|
539
|
+
if not a or not b:
|
|
540
|
+
return 0
|
|
541
|
+
prev = [0] * (len(b) + 1)
|
|
542
|
+
best = 0
|
|
543
|
+
for i in range(1, len(a) + 1):
|
|
544
|
+
cur = [0] * (len(b) + 1)
|
|
545
|
+
ca = a[i - 1]
|
|
546
|
+
for j in range(1, len(b) + 1):
|
|
547
|
+
if ca == b[j - 1]:
|
|
548
|
+
cur[j] = prev[j - 1] + 1
|
|
549
|
+
if cur[j] > best:
|
|
550
|
+
best = cur[j]
|
|
551
|
+
prev = cur
|
|
552
|
+
return best
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def parse_line_anchors(lines_str):
|
|
556
|
+
"""行锚词形 → (起,止) 行列表。两种源词形兼容:
|
|
557
|
+
L 前缀形("L20"/"L23-25"/"L1-13"——BE-G4 anchor/BE-G5 卡)与纯数字形
|
|
558
|
+
("25"/"25-27"/"25,27"——BE-G1 ref 卡 lines)。"""
|
|
559
|
+
s = (lines_str or "").strip()
|
|
560
|
+
if not s:
|
|
561
|
+
return []
|
|
562
|
+
out = []
|
|
563
|
+
matched = False
|
|
564
|
+
for m in re.finditer(r"[Ll](\d+)(?:\s*-\s*[Ll]?(\d+))?", s):
|
|
565
|
+
matched = True
|
|
566
|
+
a = int(m.group(1))
|
|
567
|
+
b = int(m.group(2)) if m.group(2) else a
|
|
568
|
+
out.append((min(a, b), max(a, b)))
|
|
569
|
+
if not matched:
|
|
570
|
+
for m in re.finditer(r"(\d+)(?:\s*-\s*(\d+))?", s):
|
|
571
|
+
a = int(m.group(1))
|
|
572
|
+
b = int(m.group(2)) if m.group(2) else a
|
|
573
|
+
out.append((min(a, b), max(a, b)))
|
|
574
|
+
return out
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def master_sections(rel_path):
|
|
578
|
+
"""MASTer 文件(相对 backend/ 词形,含 stacks/ 子树)→ ('## ' 段名, 行号) 列表 + 行列表。"""
|
|
579
|
+
path = os.path.join(MASTER_BE_DIR, rel_path)
|
|
580
|
+
assert os.path.isfile(path), f"MASTer 源文件不存在: {rel_path}"
|
|
581
|
+
lines = open(path, encoding="utf-8").read().splitlines()
|
|
582
|
+
marks = []
|
|
583
|
+
for i, line in enumerate(lines, 1):
|
|
584
|
+
m = re.match(r"^## (.+?)\s*$", line)
|
|
585
|
+
if m:
|
|
586
|
+
marks.append((i, m.group(1)))
|
|
587
|
+
return marks, lines
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def sections_for_lines(marks, lines, lines_str):
|
|
591
|
+
""""L23, L32" → 按行段映射去重后的段名数组(保序;段外行不计)。"""
|
|
592
|
+
names = []
|
|
593
|
+
for (a, _b) in parse_line_anchors(lines_str):
|
|
594
|
+
for idx, (ln, name) in enumerate(marks):
|
|
595
|
+
end = marks[idx + 1][0] - 1 if idx + 1 < len(marks) else len(lines)
|
|
596
|
+
if ln <= a <= end and name not in names:
|
|
597
|
+
names.append(name)
|
|
598
|
+
return names
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def card_anchor_sections(card):
|
|
602
|
+
"""BE 卡层 source 三词形 → {sections: 12 段闭包内段名, extra: 段外词形, lines}。
|
|
603
|
+
|
|
604
|
+
词形 1 {ref, lines, section}:section 声明段名 + 行号段映射交叉验证;
|
|
605
|
+
词形 2 {protocol, sha256, anchor='## X 段(LN-M)'}:anchor 解析段名 + 行号交叉验证;
|
|
606
|
+
词形 3 null / 无行号:锚证据不足(sections 空)→ 调用方保守排除。
|
|
607
|
+
"""
|
|
608
|
+
src = card.get("source")
|
|
609
|
+
if not isinstance(src, dict):
|
|
610
|
+
return {"sections": [], "extra": [], "lines": ""}
|
|
611
|
+
ref = src.get("ref") or src.get("protocol") or ""
|
|
612
|
+
if not ref:
|
|
613
|
+
return {"sections": [], "extra": [], "lines": ""}
|
|
614
|
+
rel = ref.split("spec/backend/")[-1]
|
|
615
|
+
marks, file_lines = master_sections(rel)
|
|
616
|
+
lines = str(src.get("lines") or "")
|
|
617
|
+
declared = []
|
|
618
|
+
if src.get("section"):
|
|
619
|
+
declared = [str(src["section"]).strip()]
|
|
620
|
+
elif src.get("anchor"):
|
|
621
|
+
m = re.match(r"^##\s*(.+?)\s*段", str(src["anchor"]))
|
|
622
|
+
declared = [m.group(1).strip()] if m else []
|
|
623
|
+
if not lines.strip():
|
|
624
|
+
# 词形 2 无 lines 键——行号住 anchor 词形('## X 段(LN-M)'),提取承载。
|
|
625
|
+
parts = [f"L{a}" if a == b else f"L{a}-L{b}"
|
|
626
|
+
for (a, b) in parse_line_anchors(str(src["anchor"]))]
|
|
627
|
+
lines = ", ".join(parts)
|
|
628
|
+
mapped = sections_for_lines(marks, file_lines, lines)
|
|
629
|
+
if declared and mapped:
|
|
630
|
+
# 交叉验证:卡声明段 ∈ 行锚实际段(锚声明与行号漂移即爆——分母如实)。
|
|
631
|
+
assert declared[0] in mapped, (
|
|
632
|
+
f"卡锚交叉验证失败: {ref} 声明段 {declared} vs 行锚实际段 {mapped}")
|
|
633
|
+
twelve = [n for n in mapped if n in TWELVE_SECTION_NAMES]
|
|
634
|
+
extra = [n for n in mapped if n not in TWELVE_SECTION_NAMES]
|
|
635
|
+
return {"sections": twelve, "extra": extra, "lines": lines}
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
def keywords_of(card):
|
|
639
|
+
kw = card.get("statement_en_keywords")
|
|
640
|
+
if isinstance(kw, str):
|
|
641
|
+
return [p.strip() for p in kw.split(",") if p.strip()]
|
|
642
|
+
return list(kw or [])
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def density(stmt, lane):
|
|
646
|
+
s = _norm_ws(stmt)
|
|
647
|
+
cardinals = len(re.findall(r"[一二三四五六七八九十0-9]+\s*(项|件|类|条|元|要素|成分|维度|件事)", s))
|
|
648
|
+
score = min(len(s), 160) / 16.0
|
|
649
|
+
score += 8.0 * cardinals
|
|
650
|
+
score += 30.0 if lane == "any" else 0.0
|
|
651
|
+
return round(score, 2)
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
def disk_state():
|
|
655
|
+
"""磁盘 catalog 分桶:existing_b6(本批条目幂等收编)+ materialized(池排除)。"""
|
|
656
|
+
existing_b6 = {}
|
|
657
|
+
materialized = set()
|
|
658
|
+
for section in ("policies", "knowledge", "gates", "sensors", "archetypes"):
|
|
659
|
+
sdir = os.path.join(VNEXT, "catalog", section)
|
|
660
|
+
if not os.path.isdir(sdir):
|
|
661
|
+
continue
|
|
662
|
+
for fn in os.listdir(sdir):
|
|
663
|
+
if not fn.endswith(".json"):
|
|
664
|
+
continue
|
|
665
|
+
try:
|
|
666
|
+
d = json.load(open(os.path.join(sdir, fn), encoding="utf-8"))
|
|
667
|
+
except Exception:
|
|
668
|
+
continue
|
|
669
|
+
if not isinstance(d, dict):
|
|
670
|
+
continue
|
|
671
|
+
note = d.get("x-b6-porting")
|
|
672
|
+
if isinstance(note, dict) and note.get("batch") == BATCH:
|
|
673
|
+
existing_b6[d["id"]] = d.get("enforcement")
|
|
674
|
+
continue
|
|
675
|
+
m = d.get("x-spec-d-materialization")
|
|
676
|
+
if isinstance(m, dict) and m.get("candidate_id"):
|
|
677
|
+
materialized.add(m["candidate_id"])
|
|
678
|
+
return existing_b6, materialized
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
def clean_room_audit(cid, statement, rel_path, lines_str):
|
|
682
|
+
"""LCS 审计(MASTer 行段——池卡行号锚的分母;阈值 20 字 fail-closed)。"""
|
|
683
|
+
path = os.path.join(MASTER_BE_DIR, rel_path)
|
|
684
|
+
assert os.path.isfile(path), f"MASTer 源文件不存在: {rel_path} ({cid})"
|
|
685
|
+
raw_lines = open(path, encoding="utf-8").readlines()
|
|
686
|
+
segs = []
|
|
687
|
+
for (a, b) in parse_line_anchors(lines_str):
|
|
688
|
+
a = max(a, 1)
|
|
689
|
+
b = min(b, len(raw_lines))
|
|
690
|
+
if a <= b:
|
|
691
|
+
segs.append("".join(raw_lines[a - 1:b]))
|
|
692
|
+
ref_text = _norm_ws("".join(segs))
|
|
693
|
+
stmt = _norm_ws(statement)
|
|
694
|
+
worst = _lcs_len(stmt, ref_text) if ref_text else 0
|
|
695
|
+
assert worst < LCS_THRESHOLD, f"clean-room LCS 审计失败({worst}>=20 字): {cid}"
|
|
696
|
+
return worst
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
# ======================================================================
|
|
700
|
+
# catalog 条目构建(materialize-curated 同款模式 + x-b6-porting 注记)
|
|
701
|
+
# ======================================================================
|
|
702
|
+
def id_to_path(cid):
|
|
703
|
+
return "policies/" + cid.lower() + ".json"
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
CURATED_RULE = (
|
|
707
|
+
"B6c 分母(BE universal 33:32 编号协议 + index)required 池(ELIGIBLE 未物化 + "
|
|
708
|
+
"卡层锚落 MUST/MUST NOT 且与 MASTer 行锚交叉验证)按池密度序取前 22 + advisory 池"
|
|
709
|
+
"(SHOULD 源 backlog policy 卡 + 行锚全落建议段闭包)按同公式密度序取前 3 = 25"
|
|
710
|
+
"(D5 上限/批内执行);UNIVERSAL + UNIVERSAL_POLICY + 无 uncertainty + 非 "
|
|
711
|
+
"project_scope + 非重复"
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def rel_of_protocol(source_ref):
|
|
716
|
+
return source_ref.split("spec/backend/")[-1]
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def vendor_pin_for(rel_path):
|
|
720
|
+
"""MASTer 相对路径 → vendor 同名文件 pin(BE universal ↔ stacks 树双候选)。"""
|
|
721
|
+
if rel_path.startswith("stacks/"):
|
|
722
|
+
path = os.path.join(STACKS_VENDOR_DIR, rel_path[len("stacks/"):])
|
|
723
|
+
rel = f"pomaster/components/backend-hard-spec/assets/stacks/{rel_path[len('stacks/'):]}"
|
|
724
|
+
|
|
725
|
+
else:
|
|
726
|
+
path = os.path.join(BE_VENDOR_DIR, rel_path)
|
|
727
|
+
rel = f"pomaster/components/backend-hard-spec/assets/universal/{rel_path}"
|
|
728
|
+
data = open(path, "rb").read()
|
|
729
|
+
return {"path": rel, "sha256": hashlib.sha256(data).hexdigest(), "bytes": len(data)}
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def seeded_spec_for(rel_path):
|
|
733
|
+
"""MASTer 相对路径 → 播种件目标(stacks 子目录守卫 ADR 的 catalog↔播种锚)。"""
|
|
734
|
+
if rel_path.startswith("stacks/"):
|
|
735
|
+
return ".pomaster/specs/hard/stacks/" + rel_path[len("stacks/"):]
|
|
736
|
+
return ".pomaster/specs/hard/backend/" + rel_path
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def build_policy_entry(pool_rec, card, statement, sections, extra_sections):
|
|
740
|
+
cid = pool_rec["candidate_id"]
|
|
741
|
+
group = card["group"]
|
|
742
|
+
r = card["raw"]
|
|
743
|
+
src = r.get("source") or {}
|
|
744
|
+
ref = src.get("ref") or src.get("protocol") or ""
|
|
745
|
+
rel = rel_of_protocol(ref)
|
|
746
|
+
lines = str(src.get("lines") or "")
|
|
747
|
+
pin = vendor_pin_for(rel)
|
|
748
|
+
seeded = seeded_spec_for(rel)
|
|
749
|
+
locator = {
|
|
750
|
+
"candidate": cid,
|
|
751
|
+
"source_protocol": ref,
|
|
752
|
+
"lines": lines,
|
|
753
|
+
}
|
|
754
|
+
new_segments = NEW_ID_SEGMENTS.get(cid, [])
|
|
755
|
+
seg_note = (";新 id 域段待登记:" + "/".join(new_segments)) if new_segments else ""
|
|
756
|
+
condition = (r.get("applies_when") or {}).get("condition", "")
|
|
757
|
+
lane = (r.get("applies_when") or {}).get("lane", "any")
|
|
758
|
+
return {
|
|
759
|
+
"x-vocab-pr": {
|
|
760
|
+
"status": "vocab_pr_candidate",
|
|
761
|
+
"finding": "kind='policy' 不在 vocab-lock kinds_registry.truth_bodies(POLICY. 前缀已冻结注册,closed-world)" + seg_note,
|
|
762
|
+
"proposal": "词汇表 PR 登记 policy kind 及新域段;或 Owner 裁决 policy 条目住 catalog/ 而非 truth/objects 正文层(与前批 45+25+9 条同因同请,合并进同一 vocab PR)",
|
|
763
|
+
"locked_vocab_untouched": True,
|
|
764
|
+
"resolution": VOCAB_PR_RESOLUTION_POLICY,
|
|
765
|
+
},
|
|
766
|
+
"x-spec-d-materialization": {
|
|
767
|
+
"status": "PROPOSAL",
|
|
768
|
+
"package": f"B6c BE 播种移植(SPEC-D 池卡复用;分母=MASTer 池卡 + "
|
|
769
|
+
"vendor 播种字节双锚)",
|
|
770
|
+
"human_review_required": True,
|
|
771
|
+
"evidence": "PLANNED",
|
|
772
|
+
"provenance": POOL_REL,
|
|
773
|
+
"group": group,
|
|
774
|
+
"candidate_id": cid,
|
|
775
|
+
"density_rank": pool_rec.get("sort"),
|
|
776
|
+
"density_score": density(statement, lane),
|
|
777
|
+
"pool_statement_sha16": pool_rec.get("statement_sha16"),
|
|
778
|
+
"curated_rule": CURATED_RULE,
|
|
779
|
+
"denominator": "MASTer(池卡 source 锚)",
|
|
780
|
+
},
|
|
781
|
+
"x-b6-porting": {
|
|
782
|
+
"status": "PROPOSAL",
|
|
783
|
+
"batch": BATCH,
|
|
784
|
+
"human_review_required": True,
|
|
785
|
+
"classification_face": "policy",
|
|
786
|
+
"enforcement_axis": {
|
|
787
|
+
"source_sections": sections,
|
|
788
|
+
"rule": "SHOULD/Change Policy 源条目 enforcement 必须 advisory(禁升 required);"
|
|
789
|
+
"MUST/MUST NOT 源条目 enforcement 必须 required_when_applicable(降级合法)",
|
|
790
|
+
"asserted_by": "packages/cli/tests/catalog-b6-porting.spec.ts",
|
|
791
|
+
},
|
|
792
|
+
"extra_master_sections": extra_sections,
|
|
793
|
+
"denominator": "vendor",
|
|
794
|
+
"vendor_pin": pin,
|
|
795
|
+
"seeded_spec": seeded,
|
|
796
|
+
"seed_manifest": "packages/cli/seeds/manifest.json",
|
|
797
|
+
},
|
|
798
|
+
"id": cid,
|
|
799
|
+
"kind": "policy",
|
|
800
|
+
"axis_profile": "policy_default",
|
|
801
|
+
"classification": "UNIVERSAL_POLICY",
|
|
802
|
+
"axes": {
|
|
803
|
+
"lifecycle": "PROPOSED",
|
|
804
|
+
"confidence": "UNRESOLVED",
|
|
805
|
+
"evidence": "PLANNED",
|
|
806
|
+
"change": "STABLE",
|
|
807
|
+
},
|
|
808
|
+
"title_zh": TITLES[cid],
|
|
809
|
+
"statement_zh": statement,
|
|
810
|
+
"statement_en_keywords": keywords_of(r),
|
|
811
|
+
"applies_when": {
|
|
812
|
+
"lane": lane,
|
|
813
|
+
"condition": condition,
|
|
814
|
+
"applicability_note": condition,
|
|
815
|
+
},
|
|
816
|
+
"enforcement": pool_rec["enforcement"],
|
|
817
|
+
"authority": {
|
|
818
|
+
"owner": "HUMAN_OWNER",
|
|
819
|
+
"delegates": [],
|
|
820
|
+
"write_policy": "EVOLUTION_CHANNEL",
|
|
821
|
+
"escalation_hint": "catalog-spec-decomposition",
|
|
822
|
+
},
|
|
823
|
+
"origin": "ingested",
|
|
824
|
+
"origin_note": (
|
|
825
|
+
f"B6c BE 播种移植物化;statement 沿用 SPEC-D 候选卡独立措辞(clean-room),"
|
|
826
|
+
"零逐字拷贝上游源文本;播种分母=vendor 字节(x-b6-porting.vendor_pin),"
|
|
827
|
+
"分解分母=MASTer 池卡(x-spec-d-materialization)"
|
|
828
|
+
),
|
|
829
|
+
"sources": [
|
|
830
|
+
{
|
|
831
|
+
"type": "design_seed",
|
|
832
|
+
"ref": "POMaster_VNext/corpus/spec-knowledge/candidates/%s.yaml" % group,
|
|
833
|
+
"captured_by": "agent:claude/spec-d-consolidation",
|
|
834
|
+
"locator": locator,
|
|
835
|
+
"clean_room_note": CLEAN_ROOM_NOTE,
|
|
836
|
+
}
|
|
837
|
+
],
|
|
838
|
+
"review_notes": list(REVIEW_NOTES[cid]),
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
PROFILE_NOTES = [
|
|
843
|
+
"A1 档位裁定登记:旧包 profile(java-enterprise-default)为注入档位机制物料,"
|
|
844
|
+
"vNext 档位机制零移植(PRD A1 档位信息性裁定)——本条目为 TECHNOLOGY_PROFILE "
|
|
845
|
+
"信息性登记,includes 9 项组合可作 baseline/backend/stack.yaml 起步预填参考"
|
|
846
|
+
"(信息性,非强制),选中态由 stack.yaml 显式选型承载(B6d 落位)",
|
|
847
|
+
"A1 清洗登记:vendor profile 文件零 MINIMAL/LIGHT/STANDARD 判档词形(grep 实测"
|
|
848
|
+
"零命中)——判档叙述清洗登记为空集;profile 文件本体不播种(提案 §1 矩阵播种面"
|
|
849
|
+
"只列 28 文件)",
|
|
850
|
+
]
|
|
851
|
+
|
|
852
|
+
TP_CURATED_RULE = (
|
|
853
|
+
"B6c stacks 分母(14 目录 × index+overlay = 28 + profile 1)TECHNOLOGY_PROFILE "
|
|
854
|
+
"分类面:BE-G5 池 9 条未物化 POLICY.STACK.* ELIGIBLE 卡(池序全量)+ 1 条 "
|
|
855
|
+
"PROFILE backlog 卡;classification=TECHNOLOGY_PROFILE 不混入 policy 强度面"
|
|
856
|
+
"(§92.5 激活输入非被激活规则本体——enforcement 禁 required:STACK 卡池判 "
|
|
857
|
+
"required 降级 advisory[强度只降不升],PROFILE 卡池判 deterministic_where_"
|
|
858
|
+
"possible 原样)"
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
def build_tp_entry(pool_rec, card, statement, sections, extra_sections, seeded_spec,
|
|
863
|
+
notes):
|
|
864
|
+
cid = pool_rec["candidate_id"]
|
|
865
|
+
group = card["group"]
|
|
866
|
+
r = card["raw"]
|
|
867
|
+
src = r.get("source") or {}
|
|
868
|
+
ref = src.get("ref") or src.get("protocol") or ""
|
|
869
|
+
rel = rel_of_protocol(ref)
|
|
870
|
+
lines = str(src.get("lines") or "")
|
|
871
|
+
pin = vendor_pin_for(rel)
|
|
872
|
+
condition = (r.get("applies_when") or {}).get("condition", "")
|
|
873
|
+
lane = (r.get("applies_when") or {}).get("lane", "any")
|
|
874
|
+
is_profile = cid == "PROFILE.BASELINE.JAVA_ENTERPRISE_DEFAULT"
|
|
875
|
+
pool_kind_note = (str(r.get("kind") or "").strip())
|
|
876
|
+
entry = {
|
|
877
|
+
"x-vocab-pr": {
|
|
878
|
+
"status": "vocab_pr_candidate",
|
|
879
|
+
"finding": "kind='policy' 不在 vocab-lock kinds_registry.truth_bodies(POLICY. 前缀已冻结注册,closed-world);classification=TECHNOLOGY_PROFILE 为 §93.4 十二值现成词形(零扩值);PROFILE 前缀 id 域段待登记",
|
|
880
|
+
"proposal": "词汇表 PR 登记 policy kind 及 PROFILE 前缀域段;或 Owner 裁决 policy 条目住 catalog/ 而非 truth/objects 正文层(与前批 45+25+9 条同因同请,合并进同一 vocab PR)",
|
|
881
|
+
"locked_vocab_untouched": True,
|
|
882
|
+
"resolution": VOCAB_PR_RESOLUTION_TP,
|
|
883
|
+
},
|
|
884
|
+
"x-spec-d-materialization": {
|
|
885
|
+
"status": "PROPOSAL",
|
|
886
|
+
"package": "B6c stacks 播种移植(SPEC-D 池卡复用;分母=MASTer 池卡 + "
|
|
887
|
+
"vendor 播种字节双锚)",
|
|
888
|
+
"human_review_required": True,
|
|
889
|
+
"evidence": "PLANNED",
|
|
890
|
+
"provenance": POOL_REL,
|
|
891
|
+
"group": group,
|
|
892
|
+
"candidate_id": cid,
|
|
893
|
+
"density_rank": pool_rec.get("sort"),
|
|
894
|
+
"density_score": density(statement, lane),
|
|
895
|
+
"pool_statement_sha16": pool_rec.get("statement_sha16"),
|
|
896
|
+
"curated_rule": TP_CURATED_RULE,
|
|
897
|
+
"denominator": "MASTer(池卡 source 锚)",
|
|
898
|
+
**({"pool_kind_note": pool_kind_note} if pool_kind_note and
|
|
899
|
+
pool_kind_note != "policy" else {}),
|
|
900
|
+
},
|
|
901
|
+
"x-b6-porting": {
|
|
902
|
+
"status": "PROPOSAL",
|
|
903
|
+
"batch": BATCH,
|
|
904
|
+
"human_review_required": True,
|
|
905
|
+
"classification_face": "technology_profile",
|
|
906
|
+
"enforcement_axis": {
|
|
907
|
+
"source_sections": sections,
|
|
908
|
+
"rule": "TECHNOLOGY_PROFILE 面禁 required_when_applicable(§92.5 激活"
|
|
909
|
+
"输入非被激活规则本体;STACK 卡池判 required 降级 advisory,"
|
|
910
|
+
"PROFILE 卡池判 deterministic_where_possible 原样——强度只降不升)",
|
|
911
|
+
"asserted_by": "packages/cli/tests/catalog-b6-porting.spec.ts",
|
|
912
|
+
},
|
|
913
|
+
"extra_master_sections": extra_sections,
|
|
914
|
+
"denominator": "vendor",
|
|
915
|
+
"vendor_pin": pin,
|
|
916
|
+
"seeded_spec": seeded_spec,
|
|
917
|
+
"seed_manifest": "packages/cli/seeds/manifest.json",
|
|
918
|
+
"notes": list(notes),
|
|
919
|
+
},
|
|
920
|
+
"id": cid,
|
|
921
|
+
"kind": "policy",
|
|
922
|
+
"axis_profile": "policy_default",
|
|
923
|
+
"classification": "TECHNOLOGY_PROFILE",
|
|
924
|
+
"axes": {
|
|
925
|
+
"lifecycle": "PROPOSED",
|
|
926
|
+
"confidence": "UNRESOLVED",
|
|
927
|
+
"evidence": "PLANNED",
|
|
928
|
+
"change": "STABLE",
|
|
929
|
+
},
|
|
930
|
+
"title_zh": TITLES[cid],
|
|
931
|
+
"statement_zh": statement,
|
|
932
|
+
"statement_en_keywords": keywords_of(r),
|
|
933
|
+
"applies_when": {
|
|
934
|
+
"lane": lane,
|
|
935
|
+
"condition": condition,
|
|
936
|
+
"applicability_note": condition,
|
|
937
|
+
},
|
|
938
|
+
"enforcement": "advisory" if not is_profile else "deterministic_where_possible",
|
|
939
|
+
"authority": {
|
|
940
|
+
"owner": "HUMAN_OWNER",
|
|
941
|
+
"delegates": [],
|
|
942
|
+
"write_policy": "EVOLUTION_CHANNEL",
|
|
943
|
+
"escalation_hint": "catalog-spec-decomposition",
|
|
944
|
+
},
|
|
945
|
+
"origin": "ingested",
|
|
946
|
+
"origin_note": (
|
|
947
|
+
"B6c stacks 播种移植物化(TECHNOLOGY_PROFILE 分类面——提案 §1 矩阵 "
|
|
948
|
+
"TECHNOLOGY_OVERLAY 落位,不混入 policy 强度面);statement 沿用 SPEC-D "
|
|
949
|
+
"候选卡独立措辞(clean-room),零逐字拷贝上游源文本;播种分母=vendor 字节"
|
|
950
|
+
"(x-b6-porting.vendor_pin),分解分母=MASTer 池卡"
|
|
951
|
+
"(x-spec-d-materialization)"
|
|
952
|
+
),
|
|
953
|
+
"sources": [
|
|
954
|
+
{
|
|
955
|
+
"type": "design_seed",
|
|
956
|
+
"ref": "POMaster_VNext/corpus/spec-knowledge/candidates/%s.yaml" % group,
|
|
957
|
+
"captured_by": "agent:claude/spec-d-consolidation",
|
|
958
|
+
"locator": {
|
|
959
|
+
"candidate": cid,
|
|
960
|
+
"source_protocol": ref,
|
|
961
|
+
"lines": lines,
|
|
962
|
+
},
|
|
963
|
+
"clean_room_note": CLEAN_ROOM_NOTE,
|
|
964
|
+
}
|
|
965
|
+
],
|
|
966
|
+
"review_notes": list(REVIEW_NOTES[cid]),
|
|
967
|
+
}
|
|
968
|
+
return entry
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
# ======================================================================
|
|
972
|
+
# 人工审定 clean-room 常量(title / review_notes / 新 id 域段)
|
|
973
|
+
# ======================================================================
|
|
974
|
+
TITLES = {
|
|
975
|
+
# ---- B6c policy 面(required 22)----
|
|
976
|
+
"POLICY.PERF.EVIDENCE_BINDING": "性能结论五要素绑定",
|
|
977
|
+
"POLICY.ARCH.NO_CONVENIENCE_OVER_BOUNDARY": "禁以便利越过边界分析",
|
|
978
|
+
"POLICY.WF.TASK_FACTS_PRECONFIRM": "动手前任务事实预确认",
|
|
979
|
+
"POLICY.STRUCT.MODULE_ENTRY_DEPENDENCY_DECLARED": "模块三要素齐备方成立",
|
|
980
|
+
"POLICY.AI.READ_SEARCH_VERIFY_BEFORE_WRITE": "写前读规范检索并验证",
|
|
981
|
+
"POLICY.BOUND.SEARCH_FIRST_ENTRY_ONLY": "改前检索且只依赖公开入口",
|
|
982
|
+
"POLICY.TOOL.DISCOVERABLE_TOOLCHAIN": "工具链可发现可复现",
|
|
983
|
+
"POLICY.OBS.NO_SENSITIVE_OR_UNBOUNDED_LOGGING": "观测输出禁敏感与无界字段",
|
|
984
|
+
"POLICY.DEPLOY.NO_DEV_ENV_AS_PRODUCTION_FACT": "禁以开发形态当生产事实",
|
|
985
|
+
"POLICY.TEST.RISK_DRIVEN_PLAN": "测试计划按风险覆盖",
|
|
986
|
+
"POLICY.EVID.ACCEPTANCE_BINDS_VERIFIABLE_EVIDENCE": "验收绑定可复核证据",
|
|
987
|
+
"POLICY.TOOL.NO_HAND_EDIT_GENERATED_NO_CI_DRIFT": "禁手改产物与门禁双标",
|
|
988
|
+
"POLICY.STRUCT.NO_UNEXPLAINED_TOP_LEVEL_DIR": "禁无职责顶层目录",
|
|
989
|
+
"POLICY.DEP.NO_UNTRUSTED_SOURCE_NO_LOCK_BYPASS": "禁不可信源与锁绕过",
|
|
990
|
+
"POLICY.TEST.NO_SYNTHETIC_STABILITY": "禁人造测试稳定假象",
|
|
991
|
+
"POLICY.EVID.NO_UNVERIFIABLE_PASS": "禁不可复核通过依据",
|
|
992
|
+
"POLICY.WF.NO_PLANNED_AS_VERIFIED": "禁计划态表述为已验证",
|
|
993
|
+
"POLICY.REL.NO_IRREVERSIBLE_UNMONITORED_FULL_RELEASE": "禁不可逆无监控全量发布",
|
|
994
|
+
"POLICY.DEPLOY.RUNTIME_FACT_RECORD": "交付记录七类运行时事实",
|
|
995
|
+
"POLICY.INTEGRATION.CALL_DEFINITION_MINIMUM": "外部调用五要素定义",
|
|
996
|
+
"POLICY.JOB.LIFECYCLE_DEFINITION": "异步任务七要素定义",
|
|
997
|
+
"POLICY.JOB.NO_UNMANAGED_EXECUTION": "关键任务禁无监管载体",
|
|
998
|
+
# ---- advisory 3 ----
|
|
999
|
+
"POLICY.STRUCT.REUSE_PROVEN_STRUCTURE": "优先沿用已验证结构",
|
|
1000
|
+
"POLICY.TEST.CONTROL_NONDETERMINISM_KEEP_DIAGNOSIS": "管控不确定因素并留诊断",
|
|
1001
|
+
"POLICY.ARCH.PREFER_VERIFIABLE_OPTION": "优先可验证方案",
|
|
1002
|
+
# ---- TECHNOLOGY_PROFILE 面 10 ----
|
|
1003
|
+
"POLICY.STACK.UPGRADE_COMPAT_VERIFIED": "升级兼容全链验证",
|
|
1004
|
+
"POLICY.STACK.DERIVED_STORE_NOT_AUTHORITY": "派生存储非事实权威",
|
|
1005
|
+
"POLICY.STACK.LOCAL_FORM_NOT_PROD_FACT": "本地形态非生产事实",
|
|
1006
|
+
"POLICY.STACK.ENTRY_LIMITS_ALIGNED": "入口限制与应用对齐",
|
|
1007
|
+
"POLICY.STACK.TOOLCHAIN_VERSIONS_PINNED": "工具链版本冻结登记",
|
|
1008
|
+
"POLICY.STACK.DUAL_WEB_STACK_BOUNDARY": "双 Web 执行模型边界登记",
|
|
1009
|
+
"POLICY.STACK.PERSISTENCE_COEXISTENCE_SCOPE": "多持久化方案显式划界",
|
|
1010
|
+
"POLICY.STACK.ENTRY_CHAIN_RECORDED": "入口链路责任登记",
|
|
1011
|
+
"POLICY.STACK.MULTI_DATASTORE_OWNERSHIP": "多存储所有权声明",
|
|
1012
|
+
"PROFILE.BASELINE.JAVA_ENTERPRISE_DEFAULT": "Java 企业默认组合参考清单",
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
# 新 id 域段(既有 catalog id 词面外;vocab-pr 登记诉求,照 materialize-curated 先例)。
|
|
1016
|
+
NEW_ID_SEGMENTS = {
|
|
1017
|
+
"POLICY.PERF.EVIDENCE_BINDING": ["PERF"],
|
|
1018
|
+
"POLICY.ARCH.NO_CONVENIENCE_OVER_BOUNDARY": [],
|
|
1019
|
+
"POLICY.WF.TASK_FACTS_PRECONFIRM": ["WF"],
|
|
1020
|
+
"POLICY.STRUCT.MODULE_ENTRY_DEPENDENCY_DECLARED": ["STRUCT"],
|
|
1021
|
+
"POLICY.AI.READ_SEARCH_VERIFY_BEFORE_WRITE": [],
|
|
1022
|
+
"POLICY.BOUND.SEARCH_FIRST_ENTRY_ONLY": ["BOUND"],
|
|
1023
|
+
"POLICY.TOOL.DISCOVERABLE_TOOLCHAIN": [],
|
|
1024
|
+
"POLICY.OBS.NO_SENSITIVE_OR_UNBOUNDED_LOGGING": [],
|
|
1025
|
+
"POLICY.DEPLOY.NO_DEV_ENV_AS_PRODUCTION_FACT": ["DEPLOY"],
|
|
1026
|
+
"POLICY.TEST.RISK_DRIVEN_PLAN": [],
|
|
1027
|
+
"POLICY.EVID.ACCEPTANCE_BINDS_VERIFIABLE_EVIDENCE": ["EVID"],
|
|
1028
|
+
"POLICY.TOOL.NO_HAND_EDIT_GENERATED_NO_CI_DRIFT": [],
|
|
1029
|
+
"POLICY.STRUCT.NO_UNEXPLAINED_TOP_LEVEL_DIR": ["STRUCT"],
|
|
1030
|
+
"POLICY.DEP.NO_UNTRUSTED_SOURCE_NO_LOCK_BYPASS": [],
|
|
1031
|
+
"POLICY.TEST.NO_SYNTHETIC_STABILITY": [],
|
|
1032
|
+
"POLICY.EVID.NO_UNVERIFIABLE_PASS": ["EVID"],
|
|
1033
|
+
"POLICY.WF.NO_PLANNED_AS_VERIFIED": ["WF"],
|
|
1034
|
+
"POLICY.REL.NO_IRREVERSIBLE_UNMONITORED_FULL_RELEASE": [],
|
|
1035
|
+
"POLICY.DEPLOY.RUNTIME_FACT_RECORD": ["DEPLOY"],
|
|
1036
|
+
"POLICY.INTEGRATION.CALL_DEFINITION_MINIMUM": ["INTEGRATION"],
|
|
1037
|
+
"POLICY.JOB.LIFECYCLE_DEFINITION": ["JOB"],
|
|
1038
|
+
"POLICY.JOB.NO_UNMANAGED_EXECUTION": ["JOB"],
|
|
1039
|
+
"POLICY.STRUCT.REUSE_PROVEN_STRUCTURE": ["STRUCT"],
|
|
1040
|
+
"POLICY.TEST.CONTROL_NONDETERMINISM_KEEP_DIAGNOSIS": [],
|
|
1041
|
+
"POLICY.ARCH.PREFER_VERIFIABLE_OPTION": [],
|
|
1042
|
+
"POLICY.STACK.UPGRADE_COMPAT_VERIFIED": [],
|
|
1043
|
+
"POLICY.STACK.DERIVED_STORE_NOT_AUTHORITY": [],
|
|
1044
|
+
"POLICY.STACK.LOCAL_FORM_NOT_PROD_FACT": [],
|
|
1045
|
+
"POLICY.STACK.ENTRY_LIMITS_ALIGNED": [],
|
|
1046
|
+
"POLICY.STACK.TOOLCHAIN_VERSIONS_PINNED": [],
|
|
1047
|
+
"POLICY.STACK.DUAL_WEB_STACK_BOUNDARY": [],
|
|
1048
|
+
"POLICY.STACK.PERSISTENCE_COEXISTENCE_SCOPE": [],
|
|
1049
|
+
"POLICY.STACK.ENTRY_CHAIN_RECORDED": [],
|
|
1050
|
+
"POLICY.STACK.MULTI_DATASTORE_OWNERSHIP": [],
|
|
1051
|
+
"PROFILE.BASELINE.JAVA_ENTERPRISE_DEFAULT": ["PROFILE"],
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
REVIEW_NOTES = {
|
|
1055
|
+
# ---- B6c policy 面(required 22;零语义重复判定基准=B6b-II 落地后的 193 条)----
|
|
1056
|
+
"POLICY.PERF.EVIDENCE_BINDING": [
|
|
1057
|
+
"性能结论证据绑定在既有 193 条中无对应条目(B6b-II REL.OBSERVABILITY_BEFORE_SHIP 管"
|
|
1058
|
+
"监控前置物,不管结论要素绑定),零语义重复。",
|
|
1059
|
+
],
|
|
1060
|
+
"POLICY.ARCH.NO_CONVENIENCE_OVER_BOUNDARY": [
|
|
1061
|
+
"便利性不得替代边界影响评估在既有 193 条中无对应条目(BOUNDARY.VALIDATE_IN_ENCODE_OUT "
|
|
1062
|
+
"管数据边界,非结构决策轴),零语义重复。",
|
|
1063
|
+
],
|
|
1064
|
+
"POLICY.WF.TASK_FACTS_PRECONFIRM": [
|
|
1065
|
+
"与既有 POLICY.AI.CHANGE_PLAN_FIRST(B6b-I:AI 编码先出变更计划)语义相邻不同轴——"
|
|
1066
|
+
"彼管 AI 变更计划产出义务,本管任何执行体启动前的任务事实确认六要素,互引不合并。",
|
|
1067
|
+
],
|
|
1068
|
+
"POLICY.STRUCT.MODULE_ENTRY_DEPENDENCY_DECLARED": [
|
|
1069
|
+
"模块成立三要素在既有 193 条中无对应条目(B6b-I FLAG/COMP 族为前端组件轴),零语义"
|
|
1070
|
+
"重复;与 POLICY.STRUCT.NO_UNEXPLAINED_TOP_LEVEL_DIR(本批)正交(成立条件 vs "
|
|
1071
|
+
"目录禁令),互引。",
|
|
1072
|
+
],
|
|
1073
|
+
"POLICY.AI.READ_SEARCH_VERIFY_BEFORE_WRITE": [
|
|
1074
|
+
"与既有 POLICY.AI.CHANGE_PLAN_FIRST、POLICY.PROC.PRE_CODE_DECLARATION 相邻不同轴——"
|
|
1075
|
+
"彼两条管计划/声明产出,本管写前读规范-检索复用-风险检查三步义务,互引不合并。",
|
|
1076
|
+
],
|
|
1077
|
+
"POLICY.BOUND.SEARCH_FIRST_ENTRY_ONLY": [
|
|
1078
|
+
"与既有 POLICY.AI.READ_SEARCH_VERIFY_BEFORE_WRITE(本批)为通则与依赖方向特例:"
|
|
1079
|
+
"彼管写前三步,本管依赖只指向声明公开入口,互引不合并;零语义重复。",
|
|
1080
|
+
],
|
|
1081
|
+
"POLICY.TOOL.DISCOVERABLE_TOOLCHAIN": [
|
|
1082
|
+
"工具链可发现性在既有 193 条中无对应条目(TOOL.NO_VENDORED_BODY_EDITS 管第三方"
|
|
1083
|
+
"工具正文),零语义重复。",
|
|
1084
|
+
],
|
|
1085
|
+
"POLICY.OBS.NO_SENSITIVE_OR_UNBOUNDED_LOGGING": [
|
|
1086
|
+
"与既有 POLICY.OBS.NO_SENSITIVE_RAW_VALUES(B6b-II:遥测不携带敏感原值)同域相邻——"
|
|
1087
|
+
"彼管前端遥测载荷,本管服务端观测输出并加高基数无界字段禁令,互引不合并;服务端侧"
|
|
1088
|
+
"在既有 193 条中无对应条目。",
|
|
1089
|
+
],
|
|
1090
|
+
"POLICY.DEPLOY.NO_DEV_ENV_AS_PRODUCTION_FACT": [
|
|
1091
|
+
"开发环境不得当生产事实在既有 193 条中无对应条目(CFG.PRODUCTION_SAFE_DEFAULTS 管"
|
|
1092
|
+
"默认态配置,非事实认定轴),零语义重复;与 POLICY.STACK.LOCAL_FORM_NOT_PROD_FACT"
|
|
1093
|
+
"(本批 TP 面)互引——协议通用语境 vs overlay 运行时语境。",
|
|
1094
|
+
],
|
|
1095
|
+
"POLICY.TEST.RISK_DRIVEN_PLAN": [
|
|
1096
|
+
"测试计划风险覆盖在既有 193 条中无对应条目(TEST.PYRAMID_AND_CI_MATRIX 管形态与 "
|
|
1097
|
+
"CI 矩阵),零语义重复。",
|
|
1098
|
+
],
|
|
1099
|
+
"POLICY.EVID.ACCEPTANCE_BINDS_VERIFIABLE_EVIDENCE": [
|
|
1100
|
+
"验收证据绑定在既有 193 条中无对应条目(GATE.RISK_FACTORS_CONFIRMED 管放行风险"
|
|
1101
|
+
"确认,非验收证据绑定),零语义重复。",
|
|
1102
|
+
],
|
|
1103
|
+
"POLICY.TOOL.NO_HAND_EDIT_GENERATED_NO_CI_DRIFT": [
|
|
1104
|
+
"生成产物禁手改与门禁一致性在既有 193 条中无对应条目(REGISTRY.HUMAN_FIELDS_"
|
|
1105
|
+
"VALIDATED_DECORRELATED 的 generator decoupled assertion 为登记表轴),零语义重复。",
|
|
1106
|
+
],
|
|
1107
|
+
"POLICY.STRUCT.NO_UNEXPLAINED_TOP_LEVEL_DIR": [
|
|
1108
|
+
"顶层目录职责禁令在既有 193 条中无对应条目,零语义重复;与 "
|
|
1109
|
+
"POLICY.STRUCT.MODULE_ENTRY_DEPENDENCY_DECLARED(本批)正交互引。",
|
|
1110
|
+
],
|
|
1111
|
+
"POLICY.DEP.NO_UNTRUSTED_SOURCE_NO_LOCK_BYPASS": [
|
|
1112
|
+
"与既有 POLICY.DEP.* 族(准入/引入/变更 + B6b-I BUILD_PATH_SUPPLY_CHAIN)不同轴——"
|
|
1113
|
+
"彼族管构建链路与依赖治理过程,本管下载执行来源与锁文件绕过禁令,零语义重复。",
|
|
1114
|
+
],
|
|
1115
|
+
"POLICY.TEST.NO_SYNTHETIC_STABILITY": [
|
|
1116
|
+
"与既有 POLICY.TEST.STABLE_OBSERVABLE_ASSERTIONS(B6b-II)相邻不同轴——彼管断言"
|
|
1117
|
+
"对象可观察,本管稳定性手段禁令(固定休眠/共享脏数据/只测成功路径),零语义重复。",
|
|
1118
|
+
],
|
|
1119
|
+
"POLICY.EVID.NO_UNVERIFIABLE_PASS": [
|
|
1120
|
+
"门禁通过依据可复核性在既有 193 条中无对应条目(EVID.NO_SILENT_GATE_REMOVAL 留池;"
|
|
1121
|
+
"GATE.P0_NON_BYPASSABLE 管绕过禁令),零语义重复。",
|
|
1122
|
+
],
|
|
1123
|
+
"POLICY.WF.NO_PLANNED_AS_VERIFIED": [
|
|
1124
|
+
"执行状态词形纪律在既有 193 条中无对应条目(ROLE.HUMAN_SIGNS_FOR_AI 管签核权),"
|
|
1125
|
+
"零语义重复。",
|
|
1126
|
+
],
|
|
1127
|
+
"POLICY.REL.NO_IRREVERSIBLE_UNMONITORED_FULL_RELEASE": [
|
|
1128
|
+
"不可逆发布前置条件在既有 193 条中无对应条目;与 POLICY.GATE.RISK_FACTORS_CONFIRMED"
|
|
1129
|
+
"(B6b-I 放行面)相邻——彼管阶段放行确认,本管全量发布方式禁令,互引不合并。",
|
|
1130
|
+
],
|
|
1131
|
+
"POLICY.DEPLOY.RUNTIME_FACT_RECORD": [
|
|
1132
|
+
"运行时事实七类记录在既有 193 条中无对应条目(CFG.SCHEMA_BACKED_CONFIG 管配置"
|
|
1133
|
+
"结构化),零语义重复。",
|
|
1134
|
+
],
|
|
1135
|
+
"POLICY.INTEGRATION.CALL_DEFINITION_MINIMUM": [
|
|
1136
|
+
"外部调用五要素在既有 193 条中无对应条目(INTEGRATION 词形未用),零语义重复。",
|
|
1137
|
+
],
|
|
1138
|
+
"POLICY.JOB.LIFECYCLE_DEFINITION": [
|
|
1139
|
+
"异步任务生命周期七要素在既有 193 条中无对应条目(JOB 词形未用),零语义重复。",
|
|
1140
|
+
],
|
|
1141
|
+
"POLICY.JOB.NO_UNMANAGED_EXECUTION": [
|
|
1142
|
+
"与 POLICY.JOB.LIFECYCLE_DEFINITION(本批)同域正交——彼管任务定义要素,本管执行"
|
|
1143
|
+
"载体禁令,零语义重复。",
|
|
1144
|
+
],
|
|
1145
|
+
# ---- advisory 3(SHOULD 源——advisory 落点,enforcement 轴断言钉)----
|
|
1146
|
+
"POLICY.STRUCT.REUSE_PROVEN_STRUCTURE": [
|
|
1147
|
+
"advisory 物化(SHOULD 源):新增结构前检索沿用已验证同型结构,源段 SHOULD——按八"
|
|
1148
|
+
"分类矩阵落 advisory 不升 required;卡自带 related 指向 "
|
|
1149
|
+
"POLICY.BOUND.SEARCH_FIRST_ENTRY_ONLY(本批 required),互引;enforcement 轴"
|
|
1150
|
+
"断言钉(catalog-b6-porting.spec)。",
|
|
1151
|
+
],
|
|
1152
|
+
"POLICY.TEST.CONTROL_NONDETERMINISM_KEEP_DIAGNOSIS": [
|
|
1153
|
+
"advisory 物化(SHOULD 源):测试不确定因素管控与失败诊断保留,源段 SHOULD——"
|
|
1154
|
+
"advisory 落点;与 TEST.NO_SYNTHETIC_STABILITY(本批 required)正交(稳定性手段"
|
|
1155
|
+
"禁令 vs 不确定因素管控),互引;enforcement 轴断言钉。",
|
|
1156
|
+
],
|
|
1157
|
+
"POLICY.ARCH.PREFER_VERIFIABLE_OPTION": [
|
|
1158
|
+
"advisory 物化(SHOULD 源):方案取舍优先可验证选项,源段 SHOULD——advisory 落点;"
|
|
1159
|
+
"与 ARCH.DECISION_TRADEOFF_RECORD(ELIGIBLE 池未物化)同域不同时点,零语义重复;"
|
|
1160
|
+
"enforcement 轴断言钉。",
|
|
1161
|
+
],
|
|
1162
|
+
# ---- TECHNOLOGY_PROFILE 面 10(激活输入非规则本体——强度降级登记)----
|
|
1163
|
+
"POLICY.STACK.UPGRADE_COMPAT_VERIFIED": [
|
|
1164
|
+
"TECHNOLOGY_PROFILE 物化(提案 §1 矩阵 TECHNOLOGY_OVERLAY 落位):池判 required "
|
|
1165
|
+
"降级 advisory——TECHNOLOGY_PROFILE 是 §92.5 激活输入非被激活规则本体,强度只降"
|
|
1166
|
+
"不升;锚 java overlay Rules 段(be-g5 池 ELIGIBLE 未物化)。",
|
|
1167
|
+
],
|
|
1168
|
+
"POLICY.STACK.DERIVED_STORE_NOT_AUTHORITY": [
|
|
1169
|
+
"TECHNOLOGY_PROFILE 物化:与既有 POLICY.STACK.NO_IMPLICIT_SELECTION(正本,"
|
|
1170
|
+
"UNIVERSAL_POLICY 已物化)不同轴——彼管跨层隐式推断禁令,本管派生副本权威声明,"
|
|
1171
|
+
"互引不合并;锚 redis overlay Rules 段。",
|
|
1172
|
+
],
|
|
1173
|
+
"POLICY.STACK.LOCAL_FORM_NOT_PROD_FACT": [
|
|
1174
|
+
"TECHNOLOGY_PROFILE 物化:与 POLICY.DEPLOY.NO_DEV_ENV_AS_PRODUCTION_FACT(本批 "
|
|
1175
|
+
"policy 面)互引——协议通用语境 vs tomcat overlay 运行时语境,池层判零重复"
|
|
1176
|
+
"(cross_group_merged=0);强度降级同上。",
|
|
1177
|
+
],
|
|
1178
|
+
"POLICY.STACK.ENTRY_LIMITS_ALIGNED": [
|
|
1179
|
+
"TECHNOLOGY_PROFILE 物化:统摄 nginx/tomcat/k8s 三 overlay 限制对齐条款族,正本"
|
|
1180
|
+
"锚 nginx 侧(池卡 notes 如实);强度降级同上。",
|
|
1181
|
+
],
|
|
1182
|
+
"POLICY.STACK.TOOLCHAIN_VERSIONS_PINNED": [
|
|
1183
|
+
"TECHNOLOGY_PROFILE 物化:与 POLICY.STACK.UPGRADE_COMPAT_VERIFIED(本批)正交——"
|
|
1184
|
+
"彼管升级验证,本管选定后冻结登记;Checklist 证据面随本条吸收(池卡 notes);"
|
|
1185
|
+
"强度降级同上。",
|
|
1186
|
+
],
|
|
1187
|
+
"POLICY.STACK.DUAL_WEB_STACK_BOUNDARY": [
|
|
1188
|
+
"TECHNOLOGY_PROFILE 物化:spring-mvc/webflux 镜像表述正本锚 spring-mvc 侧(池卡"
|
|
1189
|
+
"notes);强度降级同上。",
|
|
1190
|
+
],
|
|
1191
|
+
"POLICY.STACK.PERSISTENCE_COEXISTENCE_SCOPE": [
|
|
1192
|
+
"TECHNOLOGY_PROFILE 物化:jpa/mybatis 镜像表述正本锚 jpa 侧(池卡 notes);强度"
|
|
1193
|
+
"降级同上。",
|
|
1194
|
+
],
|
|
1195
|
+
"POLICY.STACK.ENTRY_CHAIN_RECORDED": [
|
|
1196
|
+
"TECHNOLOGY_PROFILE 物化:nginx/k8s 镜像表述正本锚 nginx 侧(池卡 notes);强度"
|
|
1197
|
+
"降级同上。",
|
|
1198
|
+
],
|
|
1199
|
+
"POLICY.STACK.MULTI_DATASTORE_OWNERSHIP": [
|
|
1200
|
+
"TECHNOLOGY_PROFILE 物化:mysql/postgresql 镜像表述正本锚 mysql 侧(池卡 notes);"
|
|
1201
|
+
"与 POLICY.STACK.DERIVED_STORE_NOT_AUTHORITY(本批)正交(多存储边界 vs 派生"
|
|
1202
|
+
"权威),强度降级同上。",
|
|
1203
|
+
],
|
|
1204
|
+
"PROFILE.BASELINE.JAVA_ENTERPRISE_DEFAULT": [
|
|
1205
|
+
"TECHNOLOGY_PROFILE 物化(profile 分类落位 ADR):池卡词形 project_baseline_"
|
|
1206
|
+
"template(catalog 层,非 truth 信封实例)——物化 kind 按词表闭包落 policy、"
|
|
1207
|
+
"classification=TECHNOLOGY_PROFILE 承载 profile 语义;池判 "
|
|
1208
|
+
"deterministic_where_possible 原样(includes/excludes 机器可核清单);A1 档位"
|
|
1209
|
+
"机制零移植,本条目为信息性登记(notes 详见 x-b6-porting.notes)。",
|
|
1210
|
+
],
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
# ======================================================================
|
|
1215
|
+
# 池选取主逻辑
|
|
1216
|
+
# ======================================================================
|
|
1217
|
+
def select_curated(pool, raw):
|
|
1218
|
+
ident = pool["identity"]
|
|
1219
|
+
assert ident["total_candidates"] == POOL_SELF_ANCHOR["total"], "池候选总数漂移"
|
|
1220
|
+
assert ident["canonical_total"] == POOL_SELF_ANCHOR["canonical"], "池正本数漂移"
|
|
1221
|
+
assert ident["absorbed_total"] == POOL_SELF_ANCHOR["absorbed"], "池 absorbed 数漂移"
|
|
1222
|
+
assert pool["d5_screen_summary"]["eligible_pool"] == POOL_SELF_ANCHOR["eligible"], \
|
|
1223
|
+
"ELIGIBLE 池漂移"
|
|
1224
|
+
|
|
1225
|
+
existing_b6, materialized = disk_state()
|
|
1226
|
+
|
|
1227
|
+
def in_backend_universal(sp):
|
|
1228
|
+
return "/backend/" in sp and "stacks/" not in sp
|
|
1229
|
+
|
|
1230
|
+
# required 池:ELIGIBLE 未物化 + 卡层锚落 MUST/MUST NOT(交叉验证在
|
|
1231
|
+
# card_anchor_sections 内)按池序取前 22。矛盾排除:池 enforcement=required 但锚
|
|
1232
|
+
# 不落 MUST/MUST NOT(Change Policy 源 / index.md 卡 / source=null)保守排除——
|
|
1233
|
+
# 不猜 Owner 意图,留池待复核(强度只降不升,B6b 同款)。
|
|
1234
|
+
required = []
|
|
1235
|
+
excluded = []
|
|
1236
|
+
for r in pool["eligible_ranked"]:
|
|
1237
|
+
sp = r["source_protocol"]
|
|
1238
|
+
if not in_backend_universal(sp):
|
|
1239
|
+
continue
|
|
1240
|
+
if len(required) >= REQUIRED_CAP:
|
|
1241
|
+
break
|
|
1242
|
+
cid = r["candidate_id"]
|
|
1243
|
+
if cid in existing_b6:
|
|
1244
|
+
if existing_b6[cid] == "required_when_applicable":
|
|
1245
|
+
required.append(r)
|
|
1246
|
+
continue
|
|
1247
|
+
if cid in materialized:
|
|
1248
|
+
continue
|
|
1249
|
+
card = raw.get(cid, {}).get("raw", {})
|
|
1250
|
+
anchors = card_anchor_sections(card)
|
|
1251
|
+
if not any(s in ("MUST", "MUST NOT") for s in anchors["sections"]):
|
|
1252
|
+
reason = (
|
|
1253
|
+
"卡层 source=null(锚证据不足),保守排除待复核"
|
|
1254
|
+
if not anchors["sections"] else
|
|
1255
|
+
"行锚段映射非 MUST/MUST NOT(池 enforcement 判定矛盾,保守排除待复核)"
|
|
1256
|
+
)
|
|
1257
|
+
excluded.append({"pool": "required", "candidate_id": cid, "reason": reason,
|
|
1258
|
+
"sections": anchors["sections"], "extra": anchors["extra"]})
|
|
1259
|
+
continue
|
|
1260
|
+
required.append(r)
|
|
1261
|
+
assert len(required) == REQUIRED_CAP, f"required 池不足: {len(required)}"
|
|
1262
|
+
|
|
1263
|
+
# advisory 池:SHOULD 源 canonical_backlog policy 卡(backend universal 树)按密度
|
|
1264
|
+
# 序取前 3;行锚(池行 source_lines)MASTer 12 段映射全落 {SHOULD, Change Policy}
|
|
1265
|
+
# 方入选;行锚缺席/非建议段保守排除(B6b 同款收紧)。
|
|
1266
|
+
adv_rows = []
|
|
1267
|
+
for r in pool["canonical_backlog"]:
|
|
1268
|
+
sp = r.get("source_protocol", "")
|
|
1269
|
+
if not in_backend_universal(sp):
|
|
1270
|
+
continue
|
|
1271
|
+
if r.get("enforcement") != "advisory" or r.get("kind") != "policy":
|
|
1272
|
+
continue
|
|
1273
|
+
cid = r["candidate_id"]
|
|
1274
|
+
if cid in existing_b6:
|
|
1275
|
+
if existing_b6[cid] == "advisory":
|
|
1276
|
+
card = raw.get(cid, {}).get("raw", {})
|
|
1277
|
+
stmt = card.get("statement_zh", "")
|
|
1278
|
+
adv_rows.append(dict(r, _density=density(stmt, r.get("applies_lane", "any"))))
|
|
1279
|
+
continue
|
|
1280
|
+
if cid in materialized:
|
|
1281
|
+
continue
|
|
1282
|
+
lines = str(r.get("source_lines") or "")
|
|
1283
|
+
if not lines.strip():
|
|
1284
|
+
excluded.append({"pool": "advisory", "candidate_id": cid,
|
|
1285
|
+
"reason": "池行行锚缺席(锚证据不足,保守排除待复核)",
|
|
1286
|
+
"sections": [], "extra": []})
|
|
1287
|
+
continue
|
|
1288
|
+
rel = rel_of_protocol(sp)
|
|
1289
|
+
marks, file_lines = master_sections(rel)
|
|
1290
|
+
mapped = [n for n in sections_for_lines(marks, file_lines, lines)
|
|
1291
|
+
if n in TWELVE_SECTION_NAMES]
|
|
1292
|
+
if not mapped or not all(s in ("SHOULD", "Change Policy") for s in mapped):
|
|
1293
|
+
excluded.append({"pool": "advisory", "candidate_id": cid,
|
|
1294
|
+
"reason": "行锚段映射非纯建议段(池 advisory 判定矛盾,保守排除待复核)",
|
|
1295
|
+
"sections": mapped, "extra": []})
|
|
1296
|
+
continue
|
|
1297
|
+
card = raw.get(cid, {}).get("raw", {})
|
|
1298
|
+
stmt = card.get("statement_zh", "")
|
|
1299
|
+
assert stmt, f"advisory 卡缺 statement: {cid}"
|
|
1300
|
+
adv_rows.append(dict(r, _density=density(stmt, r.get("applies_lane", "any"))))
|
|
1301
|
+
adv_rows.sort(key=lambda x: (-x["_density"], GROUPS.index(x["group"]), x["candidate_id"]))
|
|
1302
|
+
advisory = adv_rows[:ADVISORY_CAP]
|
|
1303
|
+
|
|
1304
|
+
# TECHNOLOGY_PROFILE 面:BE-G5 池 stacks 树 9 条未物化 POLICY.STACK.* ELIGIBLE 卡
|
|
1305
|
+
# (池序全量——9 < 上限,无精选压力)+ 1 条 PROFILE backlog 卡。
|
|
1306
|
+
tp_rows = []
|
|
1307
|
+
for r in pool["eligible_ranked"]:
|
|
1308
|
+
sp = r["source_protocol"]
|
|
1309
|
+
if "/stacks/" not in sp or "profiles/" in sp:
|
|
1310
|
+
continue
|
|
1311
|
+
cid = r["candidate_id"]
|
|
1312
|
+
if cid in existing_b6:
|
|
1313
|
+
tp_rows.append(r) # 重演名单锁定(TP 面条目原位收编)。
|
|
1314
|
+
continue
|
|
1315
|
+
if cid in materialized:
|
|
1316
|
+
continue
|
|
1317
|
+
assert cid.startswith("POLICY.STACK."), f"TP 面意外 id 词形: {cid}"
|
|
1318
|
+
tp_rows.append(r)
|
|
1319
|
+
assert len(tp_rows) == 9, f"TP STACK 池漂移: {len(tp_rows)}"
|
|
1320
|
+
profile_row = [r for r in pool["canonical_backlog"]
|
|
1321
|
+
if r.get("candidate_id") == "PROFILE.BASELINE.JAVA_ENTERPRISE_DEFAULT"]
|
|
1322
|
+
assert len(profile_row) == 1, "PROFILE 池卡漂移"
|
|
1323
|
+
|
|
1324
|
+
ids = [r["candidate_id"] for r in required] + \
|
|
1325
|
+
[r["candidate_id"] for r in advisory] + \
|
|
1326
|
+
[r["candidate_id"] for r in tp_rows] + \
|
|
1327
|
+
[profile_row[0]["candidate_id"]]
|
|
1328
|
+
# D6 口径(裁决 12①):本批合计恰 = D5 上限 25 + TP 追认例外 10(零第三形态——
|
|
1329
|
+
# 未来批 TP+policy 合并计入 25/批,不再走追认例外)。
|
|
1330
|
+
assert len(set(ids)) == D5_CAP_PER_BATCH + GRANDFATHERED_TP_B6C, (
|
|
1331
|
+
"精选集 id 重复或 D6 口径漂移(policy 25 + TP 追认例外 10 恰等被破坏)")
|
|
1332
|
+
return required, advisory, tp_rows, profile_row[0], excluded
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
def overlay_anchor_sections(card):
|
|
1336
|
+
"""BE-G5 卡(source.protocol+lines)→ overlay 段映射(Scope/Rules/Checklist 闭包)。"""
|
|
1337
|
+
src = card.get("source") or {}
|
|
1338
|
+
ref = src.get("protocol") or ""
|
|
1339
|
+
rel = rel_of_protocol(ref)
|
|
1340
|
+
marks, file_lines = master_sections(rel)
|
|
1341
|
+
lines = str(src.get("lines") or "")
|
|
1342
|
+
mapped = sections_for_lines(marks, file_lines, lines)
|
|
1343
|
+
return {"sections": mapped, "lines": lines, "rel": rel}
|
|
1344
|
+
|
|
1345
|
+
|
|
1346
|
+
def profile_anchor_sections(card):
|
|
1347
|
+
"""PROFILE 卡(yaml 无 ## 段)→ 行段词形(L1-13 锚原词形承载)。"""
|
|
1348
|
+
src = card.get("source") or {}
|
|
1349
|
+
ref = src.get("protocol") or ""
|
|
1350
|
+
rel = rel_of_protocol(ref)
|
|
1351
|
+
lines = str(src.get("lines") or "")
|
|
1352
|
+
return {"sections": [lines], "lines": lines, "rel": rel}
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
# ======================================================================
|
|
1356
|
+
# 主流程
|
|
1357
|
+
# ======================================================================
|
|
1358
|
+
def build_all():
|
|
1359
|
+
pilot_pins = load_pilot_pins()
|
|
1360
|
+
for name in PILOT_PINNED_FILES:
|
|
1361
|
+
assert pilot_pins.get(name), f"pilot 钉值缺席: {name}"
|
|
1362
|
+
|
|
1363
|
+
assets, manifest_doc, b6c_entries = build_seed_assets(pilot_pins)
|
|
1364
|
+
pool = yaml.safe_load(open(POOL_PATH, encoding="utf-8"))
|
|
1365
|
+
raw = load_raw_cards()
|
|
1366
|
+
required, advisory, tp_rows, profile_row, excluded = select_curated(pool, raw)
|
|
1367
|
+
|
|
1368
|
+
entry_bytes = {}
|
|
1369
|
+
audits = []
|
|
1370
|
+
# policy 面(required + advisory)。
|
|
1371
|
+
for rec in required + advisory:
|
|
1372
|
+
cid = rec["candidate_id"]
|
|
1373
|
+
card = raw[cid]
|
|
1374
|
+
r = card["raw"]
|
|
1375
|
+
statement = r["statement_zh"]
|
|
1376
|
+
pool_stmt = rec.get("statement_zh")
|
|
1377
|
+
if pool_stmt is not None:
|
|
1378
|
+
assert _norm_ws(statement) == _norm_ws(pool_stmt), \
|
|
1379
|
+
f"卡 statement 与池不一致: {cid}"
|
|
1380
|
+
assert statement and statement.strip(), f"卡缺 statement: {cid}"
|
|
1381
|
+
anchors = card_anchor_sections(r)
|
|
1382
|
+
sections = anchors["sections"]
|
|
1383
|
+
assert sections, f"行段无法映射到 12 段: {cid}"
|
|
1384
|
+
# enforcement 轴(工具级自我断言——物化前先自证,测试面二次钉):多锚卡按最强
|
|
1385
|
+
# 段定强度;纯建议段卡禁升 required(MUST 通胀守卫核心语义,B6b 同款)。
|
|
1386
|
+
adv_ok = all(s in ("SHOULD", "Change Policy") for s in sections)
|
|
1387
|
+
assert (rec["enforcement"] == "advisory") == adv_ok, (
|
|
1388
|
+
f"enforcement 轴映射违例: {cid} sections={sections} enforcement={rec['enforcement']}")
|
|
1389
|
+
rel = rel_of_protocol(r.get("source", {}).get("ref") or r.get("source", {}).get("protocol"))
|
|
1390
|
+
worst = clean_room_audit(cid, statement, rel, anchors["lines"])
|
|
1391
|
+
audits.append({"id": cid, "lcs_max": worst, "sections": sections})
|
|
1392
|
+
entry = build_policy_entry(rec, card, statement, sections, anchors["extra"])
|
|
1393
|
+
entry_bytes[id_to_path(cid)] = serialize(entry).encode("utf-8")
|
|
1394
|
+
|
|
1395
|
+
# TECHNOLOGY_PROFILE 面(9 STACK + 1 PROFILE)。
|
|
1396
|
+
for rec in tp_rows:
|
|
1397
|
+
cid = rec["candidate_id"]
|
|
1398
|
+
card = raw[cid]
|
|
1399
|
+
r = card["raw"]
|
|
1400
|
+
statement = r["statement_zh"]
|
|
1401
|
+
assert statement and statement.strip(), f"卡缺 statement: {cid}"
|
|
1402
|
+
anchors = overlay_anchor_sections(r)
|
|
1403
|
+
sections = anchors["sections"]
|
|
1404
|
+
assert sections and all(s in OVERLAY_SECTION_NAMES for s in sections), (
|
|
1405
|
+
f"overlay 段映射越闭包: {cid} {sections}")
|
|
1406
|
+
rel = anchors["rel"]
|
|
1407
|
+
worst = clean_room_audit(cid, statement, rel, anchors["lines"])
|
|
1408
|
+
audits.append({"id": cid, "lcs_max": worst, "sections": sections})
|
|
1409
|
+
seeded = seeded_spec_for(rel)
|
|
1410
|
+
entry = build_tp_entry(rec, card, statement, sections, [], seeded, [])
|
|
1411
|
+
entry_bytes[id_to_path(cid)] = serialize(entry).encode("utf-8")
|
|
1412
|
+
|
|
1413
|
+
cid = profile_row["candidate_id"]
|
|
1414
|
+
card = raw[cid]
|
|
1415
|
+
r = card["raw"]
|
|
1416
|
+
statement = r["statement_zh"]
|
|
1417
|
+
anchors = profile_anchor_sections(r)
|
|
1418
|
+
worst = clean_room_audit(cid, statement, anchors["rel"], "L1-13")
|
|
1419
|
+
audits.append({"id": cid, "lcs_max": worst, "sections": anchors["sections"]})
|
|
1420
|
+
entry = build_tp_entry(profile_row, card, statement, anchors["sections"], [],
|
|
1421
|
+
None, PROFILE_NOTES)
|
|
1422
|
+
entry_bytes[id_to_path(cid)] = serialize(entry).encode("utf-8")
|
|
1423
|
+
|
|
1424
|
+
return {
|
|
1425
|
+
"assets": assets,
|
|
1426
|
+
"manifest": manifest_doc,
|
|
1427
|
+
"entry_bytes": entry_bytes,
|
|
1428
|
+
"audits": audits,
|
|
1429
|
+
"counts": {"required": len(required), "advisory": len(advisory),
|
|
1430
|
+
"technology_profile": len(tp_rows) + 1},
|
|
1431
|
+
"excluded": excluded,
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
def serialize(obj):
|
|
1436
|
+
return json.dumps(obj, ensure_ascii=False, indent=2) + "\n"
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
def write_if_changed(path, data):
|
|
1440
|
+
if os.path.isfile(path):
|
|
1441
|
+
if open(path, "rb").read() == data:
|
|
1442
|
+
return False
|
|
1443
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
1444
|
+
open(path, "wb").write(data)
|
|
1445
|
+
return True
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
def main():
|
|
1449
|
+
built = build_all()
|
|
1450
|
+
outputs = {}
|
|
1451
|
+
for rel, data in built["assets"].items():
|
|
1452
|
+
if rel.startswith("specs/hard/backend/"):
|
|
1453
|
+
outputs[os.path.join(BE_ASSET_DIR, *rel.split("/")[3:])] = data
|
|
1454
|
+
else:
|
|
1455
|
+
# rel = specs/hard/stacks/<slug>/<file> → STACKS_ASSET_DIR/<slug>/<file>。
|
|
1456
|
+
outputs[os.path.join(STACKS_ASSET_DIR, *rel.split("/")[3:])] = data
|
|
1457
|
+
outputs[MANIFEST_PATH] = serialize(built["manifest"]).encode("utf-8")
|
|
1458
|
+
for rel, data in built["entry_bytes"].items():
|
|
1459
|
+
outputs[os.path.join(POLICY_DIR, *rel.split("/")[1:])] = data
|
|
1460
|
+
|
|
1461
|
+
if "--verify" in sys.argv:
|
|
1462
|
+
drifts = []
|
|
1463
|
+
for path, data in outputs.items():
|
|
1464
|
+
if not os.path.isfile(path):
|
|
1465
|
+
drifts.append({"path": path, "error": "missing"})
|
|
1466
|
+
elif open(path, "rb").read() != data:
|
|
1467
|
+
drifts.append({"path": path, "error": "bytes_differ"})
|
|
1468
|
+
if drifts:
|
|
1469
|
+
for d in drifts:
|
|
1470
|
+
print("DRIFT:", d)
|
|
1471
|
+
sys.exit(1)
|
|
1472
|
+
print(f"[seed_b6c_backend] verify ok: {len(built['assets'])} seeds + "
|
|
1473
|
+
f"{len(built['entry_bytes'])} catalog entries(字节逐等)")
|
|
1474
|
+
return
|
|
1475
|
+
|
|
1476
|
+
changed = 0
|
|
1477
|
+
for path, data in sorted(outputs.items()):
|
|
1478
|
+
if write_if_changed(path, data):
|
|
1479
|
+
changed += 1
|
|
1480
|
+
print("WROTE:", os.path.relpath(path, VNEXT))
|
|
1481
|
+
print(f"[seed_b6c_backend] ok: {len(outputs)} outputs({changed} changed / "
|
|
1482
|
+
f"{len(outputs) - changed} unchanged);seeds={len(built['assets'])} "
|
|
1483
|
+
f"catalog={len(built['entry_bytes'])} "
|
|
1484
|
+
f"(required={built['counts']['required']}, advisory={built['counts']['advisory']}, "
|
|
1485
|
+
f"technology_profile={built['counts']['technology_profile']})")
|
|
1486
|
+
print("LCS audits max:", max(a["lcs_max"] for a in built["audits"]))
|
|
1487
|
+
if built["excluded"]:
|
|
1488
|
+
print("保守排除留池待复核:")
|
|
1489
|
+
for e in built["excluded"]:
|
|
1490
|
+
print(f" - [{e['pool']}] {e['candidate_id']}: {e['reason']}")
|
|
1491
|
+
print("下一步:corepack pnpm pomaster catalog relock(193→228)")
|
|
1492
|
+
|
|
1493
|
+
|
|
1494
|
+
if __name__ == "__main__":
|
|
1495
|
+
main()
|