PTSIP 0.3.8b3__py3-none-win_amd64.whl
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.
- agent_contracts/__init__.py +5 -0
- agent_contracts/actions/analyze-source-profile.yaml +13 -0
- agent_contracts/actions/apply-adoption.yaml +12 -0
- agent_contracts/actions/apply-profile-transition.yaml +11 -0
- agent_contracts/actions/build-adoption-plan.yaml +10 -0
- agent_contracts/actions/build-transition-plan.yaml +10 -0
- agent_contracts/actions/capture-repository-snapshot.yaml +13 -0
- agent_contracts/actions/collect-conformance-evidence.yaml +13 -0
- agent_contracts/actions/compare-profile-authority.yaml +10 -0
- agent_contracts/actions/emit-conformance-result.yaml +10 -0
- agent_contracts/actions/evaluate-conformance-rules.yaml +10 -0
- agent_contracts/actions/map-profile-target.yaml +10 -0
- agent_contracts/actions/project-authority-winner.yaml +13 -0
- agent_contracts/actions/read-relevant-authority.yaml +13 -0
- agent_contracts/actions/resolve-adoption-facts.yaml +11 -0
- agent_contracts/actions/resolve-profile-schema.yaml +14 -0
- agent_contracts/actions/resolve-reconciliation-state.yaml +10 -0
- agent_contracts/actions/validate-profile-structure.yaml +10 -0
- agent_contracts/actions/validate-responsibility-map-semantics.yaml +10 -0
- agent_contracts/bindings/current.yaml +125 -0
- agent_contracts/candidate.py +383 -0
- agent_contracts/canonicalization/ptsip-canonical-json-v1.json +81 -0
- agent_contracts/conditions/adopt-apply-requested.yaml +10 -0
- agent_contracts/conditions/adopt-authority-fresh.yaml +10 -0
- agent_contracts/conditions/adopt-facts-resolved.yaml +10 -0
- agent_contracts/conditions/adopt-profile-fresh.yaml +10 -0
- agent_contracts/conditions/adopt-repository-fresh.yaml +10 -0
- agent_contracts/conditions/adopt-snapshot-identified.yaml +10 -0
- agent_contracts/conditions/adopt-write-authorized.yaml +10 -0
- agent_contracts/conditions/authority-authority-fresh.yaml +10 -0
- agent_contracts/conditions/authority-coordination-available.yaml +10 -0
- agent_contracts/conditions/authority-profile-fresh.yaml +10 -0
- agent_contracts/conditions/authority-projection-required.yaml +10 -0
- agent_contracts/conditions/authority-semantic-conflict-absent.yaml +10 -0
- agent_contracts/conditions/authority-write-authorized.yaml +10 -0
- agent_contracts/conditions/conform-profile-ready.yaml +10 -0
- agent_contracts/conditions/conform-snapshot-identified.yaml +10 -0
- agent_contracts/conditions/migrate-apply-requested.yaml +10 -0
- agent_contracts/conditions/migrate-source-fresh.yaml +10 -0
- agent_contracts/conditions/migrate-source-profile-identified.yaml +10 -0
- agent_contracts/conditions/migrate-target-contract-resolved.yaml +10 -0
- agent_contracts/conditions/migrate-target-fresh.yaml +10 -0
- agent_contracts/conditions/migrate-write-authorized.yaml +10 -0
- agent_contracts/conditions/validate-contract-resolved.yaml +10 -0
- agent_contracts/conditions/validate-profile-selected.yaml +10 -0
- agent_contracts/conformance/current.json +987 -0
- agent_contracts/contracts/current.json +3978 -0
- agent_contracts/digests/policy-v1.json +7746 -0
- agent_contracts/digests/projection-v1.json +7698 -0
- agent_contracts/gates/adoption-write.yaml +18 -0
- agent_contracts/gates/authority-projection-write.yaml +18 -0
- agent_contracts/gates/profile-transition-write.yaml +15 -0
- agent_contracts/index.json +427 -0
- agent_contracts/index.yaml +113 -0
- agent_contracts/machine_resolver.py +81 -0
- agent_contracts/operations/adopt.yaml +99 -0
- agent_contracts/operations/conform.yaml +57 -0
- agent_contracts/operations/migrate-profile.yaml +85 -0
- agent_contracts/operations/reconcile-authority.yaml +87 -0
- agent_contracts/operations/validate.yaml +53 -0
- agent_contracts/promotion/current.json +50 -0
- agent_contracts/promotion/index.json +13 -0
- agent_contracts/promotion/specification-contract.json +49 -0
- agent_contracts/resolver.py +253 -0
- agent_contracts/schemas/candidate-group.schema.json +107 -0
- agent_contracts/schemas/candidate-index.schema.json +246 -0
- agent_contracts/schemas/candidate-vectors.schema.json +49 -0
- agent_contracts/schemas/contracts/action.schema.json +21 -0
- agent_contracts/schemas/contracts/binding.schema.json +32 -0
- agent_contracts/schemas/contracts/condition.schema.json +25 -0
- agent_contracts/schemas/contracts/index.schema.json +27 -0
- agent_contracts/schemas/contracts/io.schema.json +12 -0
- agent_contracts/schemas/contracts/mutation-gate.schema.json +17 -0
- agent_contracts/schemas/contracts/operation.schema.json +259 -0
- agent_contracts/schemas/contracts/promotion.schema.json +81 -0
- agent_contracts/schemas/contracts/spec.schema.json +13 -0
- agent_contracts/schemas/contracts/vocabulary.schema.json +11 -0
- agent_contracts/schemas/io/adopt-request.schema.json +8 -0
- agent_contracts/schemas/io/adopt-result.schema.json +6 -0
- agent_contracts/schemas/io/adopt-state.schema.json +12 -0
- agent_contracts/schemas/io/authority-request.schema.json +8 -0
- agent_contracts/schemas/io/authority-result.schema.json +6 -0
- agent_contracts/schemas/io/authority-state.schema.json +13 -0
- agent_contracts/schemas/io/conform-request.schema.json +6 -0
- agent_contracts/schemas/io/conform-result.schema.json +6 -0
- agent_contracts/schemas/io/conform-state.schema.json +6 -0
- agent_contracts/schemas/io/migrate-request.schema.json +11 -0
- agent_contracts/schemas/io/migrate-result.schema.json +6 -0
- agent_contracts/schemas/io/migrate-state.schema.json +11 -0
- agent_contracts/schemas/io/validate-request.schema.json +6 -0
- agent_contracts/schemas/io/validate-result.schema.json +6 -0
- agent_contracts/schemas/io/validate-state.schema.json +6 -0
- agent_contracts/spec/adoption-procedure.yaml +148 -0
- agent_contracts/spec/adoption.yaml +33 -0
- agent_contracts/spec/agent-behavior.yaml +148 -0
- agent_contracts/spec/authority.yaml +40 -0
- agent_contracts/spec/classification.yaml +64 -0
- agent_contracts/spec/conformance-detail.yaml +120 -0
- agent_contracts/spec/conformance.yaml +43 -0
- agent_contracts/spec/core.yaml +29 -0
- agent_contracts/spec/governance.yaml +30 -0
- agent_contracts/spec/profile-transition-detail.yaml +78 -0
- agent_contracts/spec/profile-transition.yaml +30 -0
- agent_contracts/spec/repository-boundaries.yaml +148 -0
- agent_contracts/spec/responsibility-map-detail.yaml +92 -0
- agent_contracts/spec/responsibility-map.yaml +36 -0
- agent_contracts/spec/specification-governance.yaml +91 -0
- agent_contracts/validator.py +723 -0
- agent_contracts/vocabulary/authority.yaml +20 -0
- agent_contracts/vocabulary/diagnostics.yaml +23 -0
- agent_contracts/vocabulary/lifecycle.yaml +20 -0
- agent_contracts/vocabulary/outcomes.yaml +26 -0
- agent_contracts/vocabulary/terminology.yaml +428 -0
- ptsip/__init__.py +5 -0
- ptsip/__main__.py +4 -0
- ptsip/adoption.py +225 -0
- ptsip/agent_contracts/__init__.py +12 -0
- ptsip/agent_contracts/bindings/current.yaml +38 -0
- ptsip/agent_contracts/index.yaml +53 -0
- ptsip/agent_contracts/operations/adopt.yaml +49 -0
- ptsip/agent_contracts/operations/conform.yaml +42 -0
- ptsip/agent_contracts/operations/migrate-profile.yaml +45 -0
- ptsip/agent_contracts/operations/reconcile-authority.yaml +40 -0
- ptsip/agent_contracts/operations/validate.yaml +36 -0
- ptsip/agent_contracts/runtime.py +102 -0
- ptsip/agent_contracts/schemas/binding.schema.json +151 -0
- ptsip/agent_contracts/schemas/index.schema.json +51 -0
- ptsip/agent_contracts/schemas/operation.schema.json +122 -0
- ptsip/agent_contracts/schemas/spec.schema.json +96 -0
- ptsip/agent_contracts/schemas/vocabulary.schema.json +50 -0
- ptsip/agent_contracts/spec/adoption.yaml +23 -0
- ptsip/agent_contracts/spec/authority.yaml +32 -0
- ptsip/agent_contracts/spec/classification.yaml +31 -0
- ptsip/agent_contracts/spec/conformance.yaml +27 -0
- ptsip/agent_contracts/spec/core.yaml +21 -0
- ptsip/agent_contracts/spec/governance.yaml +17 -0
- ptsip/agent_contracts/spec/profile-transition.yaml +27 -0
- ptsip/agent_contracts/spec/responsibility-map.yaml +26 -0
- ptsip/agent_contracts/validator.py +195 -0
- ptsip/agent_contracts/vocabulary/authority.yaml +8 -0
- ptsip/agent_contracts/vocabulary/diagnostics.yaml +7 -0
- ptsip/agent_contracts/vocabulary/lifecycle.yaml +9 -0
- ptsip/agent_contracts/vocabulary/outcomes.yaml +8 -0
- ptsip/app/__init__.py +5 -0
- ptsip/app/client.py +53 -0
- ptsip/app/github_authority.py +659 -0
- ptsip/app/github_client.py +200 -0
- ptsip/app/github_reconciliation.py +405 -0
- ptsip/app/local_client.py +129 -0
- ptsip/app/server.py +130 -0
- ptsip/app/service.py +345 -0
- ptsip/app/store.py +283 -0
- ptsip/artifact_evidence.py +150 -0
- ptsip/build_resolution.py +315 -0
- ptsip/clarification/__init__.py +6 -0
- ptsip/clarification/generator.py +345 -0
- ptsip/clarification/generator_core.py +87 -0
- ptsip/clarification/i18n.py +110 -0
- ptsip/clarification/model.py +32 -0
- ptsip/clarification/render.py +79 -0
- ptsip/clarification/resolution/__init__.py +34 -0
- ptsip/clarification/resolution/model.py +90 -0
- ptsip/clarification/resolution/parser.py +97 -0
- ptsip/clarification/resolution/profile_projection.py +467 -0
- ptsip/clarification/resolution/resolver.py +72 -0
- ptsip/clarification/transports/__init__.py +1 -0
- ptsip/clarification/transports/github_issue.py +162 -0
- ptsip/cli.py +1181 -0
- ptsip/conformance.py +627 -0
- ptsip/conformance_audit.py +143 -0
- ptsip/conformance_engine.py +409 -0
- ptsip/constants.py +9 -0
- ptsip/context_plane.py +687 -0
- ptsip/dependency_analysis.py +232 -0
- ptsip/dependency_cache.py +110 -0
- ptsip/dependency_reconciliation.py +248 -0
- ptsip/dependency_review.py +174 -0
- ptsip/dependency_validation.py +106 -0
- ptsip/doctor.py +33 -0
- ptsip/engine_installation.py +191 -0
- ptsip/engines/context/Cargo.lock +792 -0
- ptsip/engines/context/Cargo.toml +16 -0
- ptsip/engines/context/contract.json +218 -0
- ptsip/engines/context/contracts/1.0.0.json +86 -0
- ptsip/engines/context/execution-bindings.json +19 -0
- ptsip/engines/context/manifest.json +22 -0
- ptsip/engines/context/runtime-contracts.json +34 -0
- ptsip/engines/context/src/loading.rs +15 -0
- ptsip/engines/context/src/main.rs +126 -0
- ptsip/engines/context/src/source.rs +185 -0
- ptsip/engines/context/transport.json +113 -0
- ptsip/engines/context/version.yaml +3 -0
- ptsip/engines/contracts/capability-owner-map.json +94 -0
- ptsip/engines/contracts/context-projection-handoff.json +12 -0
- ptsip/engines/contracts/dependency-graph.json +47 -0
- ptsip/engines/contracts/installation-plan.json +126 -0
- ptsip/engines/contracts/native-runtime.json +21 -0
- ptsip/engines/contracts/schemas/attempt-result.schema.json +87 -0
- ptsip/engines/contracts/schemas/capability-contract.schema.json +100 -0
- ptsip/engines/contracts/schemas/consumer-handoff.schema.json +135 -0
- ptsip/engines/contracts/schemas/contract-relation.schema.json +123 -0
- ptsip/engines/contracts/schemas/core-manifest.schema.json +148 -0
- ptsip/engines/contracts/schemas/dependency-graph.schema.json +130 -0
- ptsip/engines/contracts/schemas/derived-state.schema.json +64 -0
- ptsip/engines/contracts/schemas/effect-evidence.schema.json +58 -0
- ptsip/engines/contracts/schemas/execution-binding.schema.json +73 -0
- ptsip/engines/contracts/schemas/federated-source.schema.json +97 -0
- ptsip/engines/contracts/schemas/impact-result.schema.json +60 -0
- ptsip/engines/contracts/schemas/native-invocation-registry.schema.json +206 -0
- ptsip/engines/contracts/schemas/registry-snapshot.schema.json +163 -0
- ptsip/engines/contracts/schemas/registry-verification-input.schema.json +32 -0
- ptsip/engines/contracts/schemas/runtime-authority-consumption.schema.json +120 -0
- ptsip/engines/contracts/schemas/stop-ack.schema.json +28 -0
- ptsip/engines/contracts/schemas/stop-request.schema.json +25 -0
- ptsip/engines/contracts/schemas/stop-result.schema.json +61 -0
- ptsip/engines/contracts/schemas/storage-mediation.schema.json +73 -0
- ptsip/engines/contracts/schemas/transport-binding.schema.json +49 -0
- ptsip/engines/contracts/stdio-transport.json +113 -0
- ptsip/engines/contracts/vpms-caller-transition-plan.json +224 -0
- ptsip/engines/contracts/vpms-handoff.json +84 -0
- ptsip/engines/contracts/vpms-scope-mapping.json +116 -0
- ptsip/engines/contracts/work-item-bindings.json +292 -0
- ptsip/engines/discovery/Cargo.lock +792 -0
- ptsip/engines/discovery/Cargo.toml +16 -0
- ptsip/engines/discovery/contract.json +611 -0
- ptsip/engines/discovery/contracts/1.0.0.json +172 -0
- ptsip/engines/discovery/contracts/2.0.0.json +481 -0
- ptsip/engines/discovery/execution-bindings.json +19 -0
- ptsip/engines/discovery/manifest.json +22 -0
- ptsip/engines/discovery/runtime-contracts.json +232 -0
- ptsip/engines/discovery/src/invocation.rs +17 -0
- ptsip/engines/discovery/src/main.rs +129 -0
- ptsip/engines/discovery/src/registry.rs +358 -0
- ptsip/engines/discovery/src/source.rs +305 -0
- ptsip/engines/discovery/transport.json +113 -0
- ptsip/engines/discovery/version.yaml +3 -0
- ptsip/engines/execution/Cargo.lock +792 -0
- ptsip/engines/execution/Cargo.toml +16 -0
- ptsip/engines/execution/contract.json +607 -0
- ptsip/engines/execution/contracts/1.0.0.json +356 -0
- ptsip/engines/execution/contracts/2.0.0.json +361 -0
- ptsip/engines/execution/execution-bindings.json +19 -0
- ptsip/engines/execution/manifest.json +22 -0
- ptsip/engines/execution/runtime-contracts.json +428 -0
- ptsip/engines/execution/src/authority.rs +99 -0
- ptsip/engines/execution/src/effect.rs +66 -0
- ptsip/engines/execution/src/invocation.rs +163 -0
- ptsip/engines/execution/src/main.rs +185 -0
- ptsip/engines/execution/src/source.rs +305 -0
- ptsip/engines/execution/transport.json +113 -0
- ptsip/engines/execution/version.yaml +3 -0
- ptsip/engines/index.json +178 -0
- ptsip/engines/planning/Cargo.lock +792 -0
- ptsip/engines/planning/Cargo.toml +16 -0
- ptsip/engines/planning/contract.json +535 -0
- ptsip/engines/planning/contracts/1.0.0.json +95 -0
- ptsip/engines/planning/contracts/2.0.0.json +346 -0
- ptsip/engines/planning/execution-bindings.json +19 -0
- ptsip/engines/planning/manifest.json +22 -0
- ptsip/engines/planning/runtime-contracts.json +282 -0
- ptsip/engines/planning/src/impact.rs +217 -0
- ptsip/engines/planning/src/installation.rs +195 -0
- ptsip/engines/planning/src/main.rs +179 -0
- ptsip/engines/planning/src/preparation.rs +58 -0
- ptsip/engines/planning/src/source.rs +302 -0
- ptsip/engines/planning/transport.json +113 -0
- ptsip/engines/planning/version.yaml +3 -0
- ptsip/engines/projection/Cargo.lock +792 -0
- ptsip/engines/projection/Cargo.toml +16 -0
- ptsip/engines/projection/contract.json +226 -0
- ptsip/engines/projection/contracts/1.0.0.json +92 -0
- ptsip/engines/projection/execution-bindings.json +19 -0
- ptsip/engines/projection/manifest.json +22 -0
- ptsip/engines/projection/runtime-contracts.json +62 -0
- ptsip/engines/projection/src/main.rs +149 -0
- ptsip/engines/projection/src/rendering.rs +70 -0
- ptsip/engines/projection/src/source.rs +185 -0
- ptsip/engines/projection/transport.json +113 -0
- ptsip/engines/projection/version.yaml +3 -0
- ptsip/engines/registries/derived-snapshot.json +135 -0
- ptsip/engines/registries/official-execution.json +34 -0
- ptsip/engines/registries/official-static.json +35 -0
- ptsip/engines/storage/Cargo.lock +792 -0
- ptsip/engines/storage/Cargo.toml +16 -0
- ptsip/engines/storage/contract.json +382 -0
- ptsip/engines/storage/contracts/1.0.0.json +138 -0
- ptsip/engines/storage/contracts/2.0.0.json +116 -0
- ptsip/engines/storage/execution-bindings.json +19 -0
- ptsip/engines/storage/manifest.json +22 -0
- ptsip/engines/storage/provider-registry.json +8 -0
- ptsip/engines/storage/runtime-contracts.json +282 -0
- ptsip/engines/storage/src/main.rs +123 -0
- ptsip/engines/storage/src/native.rs +233 -0
- ptsip/engines/storage/src/provider.rs +145 -0
- ptsip/engines/storage/src/source.rs +198 -0
- ptsip/engines/storage/transport.json +113 -0
- ptsip/engines/storage/version.yaml +3 -0
- ptsip/engines/validation/Cargo.lock +792 -0
- ptsip/engines/validation/Cargo.toml +16 -0
- ptsip/engines/validation/contract.json +1241 -0
- ptsip/engines/validation/contracts/1.0.0.json +356 -0
- ptsip/engines/validation/contracts/2.0.0.json +683 -0
- ptsip/engines/validation/execution-bindings.json +19 -0
- ptsip/engines/validation/manifest.json +22 -0
- ptsip/engines/validation/runtime-contracts.json +216 -0
- ptsip/engines/validation/src/cases.rs +102 -0
- ptsip/engines/validation/src/composition.rs +104 -0
- ptsip/engines/validation/src/handoff.rs +215 -0
- ptsip/engines/validation/src/main.rs +201 -0
- ptsip/engines/validation/src/source.rs +185 -0
- ptsip/engines/validation/transport.json +113 -0
- ptsip/engines/validation/version.yaml +3 -0
- ptsip/evidence/__init__.py +33 -0
- ptsip/evidence/adapters.py +486 -0
- ptsip/evidence/contract.py +230 -0
- ptsip/evidence/normalization.py +173 -0
- ptsip/governance/__init__.py +45 -0
- ptsip/governance/authority.py +714 -0
- ptsip/governance/authorization.py +55 -0
- ptsip/governance/model.py +232 -0
- ptsip/governance/subject_matching.py +78 -0
- ptsip/governance/support_assets.py +91 -0
- ptsip/inspection/__init__.py +1 -0
- ptsip/inspection/candidate_evidence.py +537 -0
- ptsip/inspection/components.py +74 -0
- ptsip/inspection/dependencies.py +502 -0
- ptsip/inspection/dependencies_030.py +69 -0
- ptsip/inspection/dotnet.py +188 -0
- ptsip/inspection/go.py +157 -0
- ptsip/inspection/inventory.py +161 -0
- ptsip/inspection/javascript.py +376 -0
- ptsip/inspection/lexing.py +121 -0
- ptsip/inspection/python_resolution.py +164 -0
- ptsip/inspection/source_adapters.py +60 -0
- ptsip/lifecycle_evidence.py +310 -0
- ptsip/migration/__init__.py +156 -0
- ptsip/migration/analysis/__init__.py +20 -0
- ptsip/migration/analysis/analyzer.py +160 -0
- ptsip/migration/analysis/direct/__init__.py +5 -0
- ptsip/migration/analysis/direct/convergence.py +133 -0
- ptsip/migration/analysis/direct/result.py +91 -0
- ptsip/migration/analysis/direct/source_projection.py +42 -0
- ptsip/migration/analysis/direct/target_projection.py +71 -0
- ptsip/migration/analysis/findings/__init__.py +0 -0
- ptsip/migration/analysis/findings/architecture.py +29 -0
- ptsip/migration/analysis/findings/lifecycle.py +28 -0
- ptsip/migration/analysis/findings/work_requirements.py +103 -0
- ptsip/migration/analysis/issue.py +12 -0
- ptsip/migration/analysis/result.py +69 -0
- ptsip/migration/analysis/source/__init__.py +0 -0
- ptsip/migration/analysis/source/binding_validation.py +43 -0
- ptsip/migration/analysis/source/evidence_correlation.py +40 -0
- ptsip/migration/analysis/source/projection.py +252 -0
- ptsip/migration/analysis/source/repository_resolution.py +96 -0
- ptsip/migration/analysis/target/__init__.py +0 -0
- ptsip/migration/analysis/target/compatibility.py +142 -0
- ptsip/migration/analysis/target/relationship_findings.py +20 -0
- ptsip/migration/analysis/target/semantics.py +159 -0
- ptsip/migration/execution/__init__.py +5 -0
- ptsip/migration/execution/authorization/__init__.py +4 -0
- ptsip/migration/execution/authorization/binding.py +160 -0
- ptsip/migration/execution/authorization/preconditions.py +71 -0
- ptsip/migration/execution/authorization/proof.py +80 -0
- ptsip/migration/execution/direct/__init__.py +9 -0
- ptsip/migration/execution/direct/identity_plan.py +133 -0
- ptsip/migration/execution/direct/identity_rewrite.py +322 -0
- ptsip/migration/execution/direct/promotion.py +180 -0
- ptsip/migration/execution/direct/verification.py +118 -0
- ptsip/migration/execution/error.py +2 -0
- ptsip/migration/execution/guard/__init__.py +3 -0
- ptsip/migration/execution/guard/mutation.py +104 -0
- ptsip/migration/execution/guard/repository_snapshot.py +47 -0
- ptsip/migration/execution/ledger/__init__.py +3 -0
- ptsip/migration/execution/ledger/record.py +149 -0
- ptsip/migration/execution/ledger/store.py +113 -0
- ptsip/migration/execution/mutation/__init__.py +5 -0
- ptsip/migration/execution/mutation/asynchronous.py +41 -0
- ptsip/migration/execution/mutation/delta.py +243 -0
- ptsip/migration/execution/mutation/finalization.py +90 -0
- ptsip/migration/execution/mutation/source.py +57 -0
- ptsip/migration/execution/promotion/__init__.py +4 -0
- ptsip/migration/execution/promotion/mutation.py +55 -0
- ptsip/migration/execution/promotion/preparation.py +79 -0
- ptsip/migration/execution/promotion/verification.py +87 -0
- ptsip/migration/execution/recovery.py +93 -0
- ptsip/migration/execution/state/__init__.py +3 -0
- ptsip/migration/execution/state/phase.py +17 -0
- ptsip/migration/execution/state/promotion.py +25 -0
- ptsip/migration/execution/state/recovery.py +31 -0
- ptsip/migration/execution/state/source_steps.py +78 -0
- ptsip/migration/planning/__init__.py +12 -0
- ptsip/migration/planning/convergence/__init__.py +0 -0
- ptsip/migration/planning/convergence/builder.py +324 -0
- ptsip/migration/planning/convergence/final_state.py +132 -0
- ptsip/migration/planning/convergence/reconciliation.py +175 -0
- ptsip/migration/planning/direct/__init__.py +3 -0
- ptsip/migration/planning/direct/builder.py +346 -0
- ptsip/migration/planning/direct/reference.py +26 -0
- ptsip/migration/planning/proposal_derivation.py +137 -0
- ptsip/migration/planning/result.py +106 -0
- ptsip/migration/proposal/__init__.py +9 -0
- ptsip/migration/proposal/bundle.py +207 -0
- ptsip/migration/proposal/semantic_identity.py +40 -0
- ptsip/migration/proposal/source_set.py +50 -0
- ptsip/migration/proposal/target_delta.py +88 -0
- ptsip/model.py +165 -0
- ptsip/package-composition.json +266 -0
- ptsip/package-distribution.json +16 -0
- ptsip/pilot/__init__.py +1 -0
- ptsip/pilot/runner.py +170 -0
- ptsip/profiles/__init__.py +1 -0
- ptsip/profiles/catalog.py +157 -0
- ptsip/profiles/compatibility.py +184 -0
- ptsip/profiles/contracts.py +100 -0
- ptsip/profiles/example.ptsip.yaml +149 -0
- ptsip/profiles/hybrid-python-package.ptsip.yaml +40 -0
- ptsip/profiles/identity.py +314 -0
- ptsip/profiles/index.yaml +22 -0
- ptsip/profiles/metadata.py +61 -0
- ptsip/profiles/template-python-package.ptsip.yaml +18 -0
- ptsip/proposed_component.py +128 -0
- ptsip/remediation/__init__.py +77 -0
- ptsip/remediation/domain/__init__.py +39 -0
- ptsip/remediation/domain/model.py +417 -0
- ptsip/remediation/escalation/__init__.py +37 -0
- ptsip/remediation/escalation/contract.py +388 -0
- ptsip/remediation/escalation/engine.py +212 -0
- ptsip/remediation/rules/__init__.py +23 -0
- ptsip/remediation/rules/contract.py +276 -0
- ptsip/repository/__init__.py +1 -0
- ptsip/repository/discover.py +68 -0
- ptsip/repository/namespace.py +86 -0
- ptsip/repository/profile_convergence.py +409 -0
- ptsip/repository/profile_path.py +97 -0
- ptsip/repository/profile_transition.py +377 -0
- ptsip/repository/remote.py +54 -0
- ptsip/repository/schemas/engine-state.schema.json +1 -0
- ptsip/repository/schemas/repository-index.schema.json +104 -0
- ptsip/repository/snapshot.py +173 -0
- ptsip/review_evidence.py +406 -0
- ptsip/source_compat/__init__.py +56 -0
- ptsip/source_compat/integrity.py +131 -0
- ptsip/source_compat/model.py +260 -0
- ptsip/source_compat/reader.py +336 -0
- ptsip/spec_identity.py +24 -0
- ptsip/specdata/project-profile-contracts.yaml +36 -0
- ptsip/specdata/ptsip-agent-classification.schema.json +57 -0
- ptsip/specdata/ptsip-artifact-evidence.schema.json +68 -0
- ptsip/specdata/ptsip-diagnostic.schema.json +58 -0
- ptsip/specdata/ptsip-normalized-evidence.schema.json +126 -0
- ptsip/specdata/ptsip-profile-pp-1.01.schema.json +309 -0
- ptsip/specdata/ptsip-profile-pp-1.02.schema.json +604 -0
- ptsip/specdata/ptsip-profile.schema.json +296 -0
- ptsip/specdata/ptsip-registry.yaml +333 -0
- ptsip/specdata/ptsip-source-profile-0.3.4.schema.json +55 -0
- ptsip/specdata/ptsip-source-profile-0.3.6.schema.json +35 -0
- ptsip/specification_binding.py +246 -0
- ptsip/storage/__init__.py +1 -0
- ptsip/storage/local_state.py +40 -0
- ptsip/support/policy/ARCH/SFP-ARCH-0001.yaml +131 -0
- ptsip/support/policy/ARCH/SFP-ARCH-0002.yaml +46 -0
- ptsip/support/policy/ARCH/SFP-ARCH-0003.yaml +39 -0
- ptsip/support/policy/ARCH/SFP-ARCH-0004.yaml +1215 -0
- ptsip/support/policy/ARCH/SFP-ARCH-0005.yaml +76 -0
- ptsip/support/policy/ASSURE/SFP-ASSURE-0001.yaml +45 -0
- ptsip/support/policy/ASSURE/SFP-ASSURE-0002.yaml +45 -0
- ptsip/support/policy/ASSURE/SFP-ASSURE-0003.yaml +46 -0
- ptsip/support/policy/ASSURE/SFP-ASSURE-0004.yaml +148 -0
- ptsip/support/policy/ASSURE/SFP-ASSURE-0005.yaml +115 -0
- ptsip/support/policy/CHANGE/SFP-CHANGE-0001.yaml +256 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0001.yaml +242 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0002.yaml +44 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0003.yaml +54 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0004.yaml +47 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0005.yaml +1772 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0006.yaml +131 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0007.yaml +146 -0
- ptsip/support/policy/CNTR/SFP-CNTR-0008.yaml +57 -0
- ptsip/support/policy/CTRL/SFP-CTRL-0001.yaml +95 -0
- ptsip/support/policy/CTRL/SFP-CTRL-0002.yaml +415 -0
- ptsip/support/policy/CTRL/SFP-CTRL-0003.yaml +715 -0
- ptsip/support/policy/GOV/SFP-GOV-0001.yaml +55 -0
- ptsip/support/policy/GOV/SFP-GOV-0002.yaml +93 -0
- ptsip/support/policy/INFO/SFP-INFO-0001.yaml +271 -0
- ptsip/support/policy/INFO/SFP-INFO-0002.yaml +42 -0
- ptsip/support/policy/INFO/SFP-INFO-0003.yaml +41 -0
- ptsip/support/policy/INFO/SFP-INFO-0004.yaml +133 -0
- ptsip/support/policy/INFO/SFP-INFO-0005.yaml +135 -0
- ptsip/support/policy/INFO/SFP-INFO-0006.yaml +67 -0
- ptsip/support/policy/INFO/SFP-INFO-0007.yaml +256 -0
- ptsip/support/policy/INFO/SFP-INFO-0008.yaml +99 -0
- ptsip/support/policy/INFO/SFP-INFO-0009.yaml +56 -0
- ptsip/support/policy/INTENT/SFP-INTENT-0001.yaml +39 -0
- ptsip/support/policy/NORM/SFP-NORM-0001.yaml +45 -0
- ptsip/support/policy/NORM/SFP-NORM-0002.yaml +38 -0
- ptsip/support/policy/OPS/SFP-OPS-0001.yaml +40 -0
- ptsip/support/policy/OPS/SFP-OPS-0002.yaml +270 -0
- ptsip/support/policy/REAL/SFP-REAL-0001.yaml +47 -0
- ptsip/support/policy/RECORD/SFP-RECORD-0001.yaml +39 -0
- ptsip/support/policy/RECORD/SFP-RECORD-0002.yaml +40 -0
- ptsip/support/policy/RECORD/SFP-RECORD-0003.yaml +403 -0
- ptsip/support/policy/RECORD/SFP-RECORD-0004.yaml +186 -0
- ptsip/support/policy/RISK/SFP-RISK-0001.yaml +34 -0
- ptsip/support/policy/SUPPLY/SFP-SUPPLY-0001.yaml +43 -0
- ptsip/support/policy/index.yaml +183 -0
- ptsip/support/policy/legacy/SFP-0001.yaml +28 -0
- ptsip/support/policy/legacy/SFP-0002.yaml +28 -0
- ptsip/support/policy/legacy/SFP-0003.yaml +27 -0
- ptsip/support/policy/legacy/SFP-0004.yaml +53 -0
- ptsip/support/policy/legacy/SFP-0005.yaml +32 -0
- ptsip/support/policy/legacy/SFP-0006.yaml +43 -0
- ptsip/support/policy/legacy/SFP-0007.yaml +52 -0
- ptsip/support/policy/legacy/SFP-0008.yaml +66 -0
- ptsip/support/policy/legacy/SFP-0009.yaml +54 -0
- ptsip/support/policy/legacy/SFP-0010.yaml +40 -0
- ptsip/support/policy/legacy/SFP-0011.yaml +42 -0
- ptsip/support/policy/legacy/SFP-0012.yaml +38 -0
- ptsip/support/policy/legacy/SFP-0013.yaml +38 -0
- ptsip/support/policy/legacy/SFP-0014.yaml +46 -0
- ptsip/support/policy/legacy/SFP-0015.yaml +52 -0
- ptsip/support/policy/legacy/SFP-0016.yaml +52 -0
- ptsip/support/policy/legacy/SFP-0017.yaml +23 -0
- ptsip/support/policy/legacy/SFP-0018.yaml +41 -0
- ptsip/support/policy/legacy/SFP-0019.yaml +40 -0
- ptsip/support/policy/legacy/SFP-0020.yaml +34 -0
- ptsip/support/policy/legacy/SFP-0021.yaml +44 -0
- ptsip/support/policy/legacy/SFP-0022.yaml +53 -0
- ptsip/support/policy/legacy/SFP-0023.yaml +20 -0
- ptsip/support/policy/legacy/SFP-0024.yaml +118 -0
- ptsip/support/registries/ptsip-support-authority-role-registry.yaml +319 -0
- ptsip/support/registries/ptsip-support-authority-schema-registry.yaml +239 -0
- ptsip/support/registries/ptsip-support-authority-subject-registry.yaml +68 -0
- ptsip/support/registries/ptsip-support-authorization-registry.yaml +14 -0
- ptsip/support/registries/root-family-migration.json +3097 -0
- ptsip/support/registries/root-family-projection-module-admission.json +23 -0
- ptsip/support/registries/root-family-projection.module.json +201 -0
- ptsip/support/schemas/ptsip-support-authority-eligibility-result.schema.json +114 -0
- ptsip/support/schemas/ptsip-support-authority-role.schema.json +126 -0
- ptsip/support/schemas/ptsip-support-authority-semantics.schema.json +378 -0
- ptsip/support/schemas/ptsip-support-feature-policy-index.schema.json +57 -0
- ptsip/support/schemas/ptsip-support-feature-policy.schema.json +186 -0
- ptsip/support/schemas/ptsip-support-governance-registry.schema.json +28 -0
- ptsip/support/schemas/ptsip-support-project-authority-record.schema.json +136 -0
- ptsip/support/schemas/ptsip-support-root-family-policy.schema.json +206 -0
- ptsip/support/schemas/ptsip-support-subject-binding.schema.json +60 -0
- ptsip/support/schemas/root-family-migration.schema.json +240 -0
- ptsip/support/schemas/root-family-projection-module.schema.json +276 -0
- ptsip/topology.py +747 -0
- ptsip/validation/__init__.py +1 -0
- ptsip/validation/components.py +357 -0
- ptsip/validation/handoff.py +75 -0
- ptsip/validation/profile.py +514 -0
- ptsip/validation/rules.py +186 -0
- ptsip/validation/specification.py +60 -0
- ptsip/validation/templates.py +767 -0
- ptsip/validation_capture.py +168 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-context.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-discovery.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-execution.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-planning.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-projection.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-storage.exe +0 -0
- ptsip-0.3.8b3.data/scripts/ptsip-engine-validation.exe +0 -0
- ptsip-0.3.8b3.dist-info/METADATA +361 -0
- ptsip-0.3.8b3.dist-info/RECORD +600 -0
- ptsip-0.3.8b3.dist-info/WHEEL +4 -0
- ptsip-0.3.8b3.dist-info/entry_points.txt +3 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/COMMERCIAL-USE.md +301 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/LICENSE-GUIDE.md +159 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/LICENSE-HISTORY.md +15 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/LICENSE.md +414 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/NOTICE.md +22 -0
- ptsip-0.3.8b3.dist-info/licenses/License-Authority/license-authority.yaml +133 -0
- ptsip-0.3.8b3.dist-info/ptsip-engines.json +78 -0
- vpms/__init__.py +70 -0
- vpms/contract_runtime.py +124 -0
- vpms/contracts/execution-composition.json +1 -0
- vpms/contracts/identity-registry.json +69 -0
- vpms/contracts/index.json +1 -0
- vpms/contracts/invariants.json +27 -0
- vpms/contracts/protocol.json +1 -0
- vpms/contracts/schemas/catalog.schema.json +80 -0
- vpms/contracts/schemas/product-contract.schema.json +572 -0
- vpms/contracts/schemas/selection-request.schema.json +47 -0
- vpms/contracts/schemas/selection-result.schema.json +79 -0
- vpms/contracts/schemas/selection-rule.schema.json +31 -0
- vpms/contracts/selection.json +1 -0
- vpms/domain/__init__.py +1 -0
- vpms/domain/model.py +88 -0
- vpms/domain/registry.py +350 -0
- vpms/domain/snapshot.py +118 -0
- vpms/execution/__init__.py +1 -0
- vpms/execution/adapters/__init__.py +1 -0
- vpms/execution/adapters/command.py +67 -0
- vpms/execution/composition.py +58 -0
- vpms/execution/runner.py +69 -0
- vpms/integration/__init__.py +1 -0
- vpms/integration/ptsip_bridge.py +156 -0
- vpms/selection/__init__.py +4 -0
- vpms/selection/resolver.py +130 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Bounded, read-only evidence packages for unresolved support-contract review."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import tokenize
|
|
9
|
+
|
|
10
|
+
from .repository.snapshot import capture_snapshot, git_tracked_files
|
|
11
|
+
from .storage.local_state import ptsip_home, repository_fingerprint
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _serialized(value: object) -> str:
|
|
15
|
+
return json.dumps(value, ensure_ascii=False, sort_keys=True, indent=2)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _size(value: object) -> int:
|
|
19
|
+
return len(_serialized(value).encode("utf-8"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _snippet(root: Path, path: str, line: int, kind: str) -> dict[str, object] | None:
|
|
23
|
+
candidate = root / path
|
|
24
|
+
if not candidate.resolve().is_relative_to(root) or candidate.is_symlink():
|
|
25
|
+
return None
|
|
26
|
+
try:
|
|
27
|
+
with tokenize.open(candidate) as source:
|
|
28
|
+
lines = source.read().splitlines()
|
|
29
|
+
except (OSError, UnicodeError, SyntaxError):
|
|
30
|
+
return None
|
|
31
|
+
if not 1 <= line <= len(lines):
|
|
32
|
+
return None
|
|
33
|
+
start = max(1, line - 3)
|
|
34
|
+
end = min(len(lines), start + 6)
|
|
35
|
+
selected = "\n".join(lines[start - 1:end])
|
|
36
|
+
return {
|
|
37
|
+
"path": path, "line": line, "start_line": start, "end_line": end,
|
|
38
|
+
"kind": kind, "text": selected[:1200], "truncated": len(selected) > 1200,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _callers(report: dict, item: dict, max_files: int) -> list[dict]:
|
|
43
|
+
source = item["dependency"]["source"]
|
|
44
|
+
candidates = item.get("callers")
|
|
45
|
+
if candidates is None:
|
|
46
|
+
candidates = [
|
|
47
|
+
{"path": edge["dependency"]["source"], "line": edge["dependency"].get("line"),
|
|
48
|
+
"evidence_id": edge["evidence_id"], "semantics": "OBSERVED_FILE_DEPENDENCY"}
|
|
49
|
+
for edge in report["items"] if edge["dependency"].get("resolved_path") == source
|
|
50
|
+
]
|
|
51
|
+
selected, files = [], {source}
|
|
52
|
+
for caller in sorted(candidates, key=lambda value: (
|
|
53
|
+
value.get("path", ""), value.get("line") or 0, value.get("evidence_id", "")
|
|
54
|
+
)):
|
|
55
|
+
path = caller.get("path")
|
|
56
|
+
if not path or (path not in files and len(files) >= max_files):
|
|
57
|
+
continue
|
|
58
|
+
files.add(path)
|
|
59
|
+
selected.append({**{key: caller.get(key) for key in ("path", "line", "evidence_id")},
|
|
60
|
+
"semantics": caller.get("semantics") or caller.get("kind")})
|
|
61
|
+
if len(selected) >= 4:
|
|
62
|
+
break
|
|
63
|
+
return selected
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def build_review_pack(
|
|
67
|
+
report: dict, *, max_items: int = 8, max_context_bytes_per_item: int = 12000,
|
|
68
|
+
max_source_files_per_item: int = 4,
|
|
69
|
+
) -> dict:
|
|
70
|
+
"""Select only REVIEW_REQUIRED items; never invoke an AI or assert authority."""
|
|
71
|
+
if max_items < 0 or max_context_bytes_per_item < 1 or max_source_files_per_item < 1:
|
|
72
|
+
raise ValueError("Review budgets require nonnegative max-items and positive byte/file caps")
|
|
73
|
+
if report.get("status") != "RAN":
|
|
74
|
+
raise ValueError("Review Pack requires stable analysis with a valid selected profile")
|
|
75
|
+
root = Path(report["repository"]["root"]).resolve()
|
|
76
|
+
eligible = sorted((item for item in report["items"] if item["actionability"] == "REVIEW_REQUIRED"),
|
|
77
|
+
key=lambda item: item["evidence_id"])
|
|
78
|
+
reviews, deferred = [], []
|
|
79
|
+
for item in eligible:
|
|
80
|
+
if len(reviews) >= max_items:
|
|
81
|
+
deferred.append({"evidence_id": item["evidence_id"], "reason": "ITEM_BUDGET"})
|
|
82
|
+
continue
|
|
83
|
+
usage = deepcopy(item.get("usage", {}))
|
|
84
|
+
fallback = usage.pop("fallback", {"detected": False, "semantics": "NO_SYNTAX_EVIDENCE"})
|
|
85
|
+
callers = _callers(report, item, max_source_files_per_item)
|
|
86
|
+
review = {
|
|
87
|
+
"review_id": "review:" + item["evidence_id"], "evidence_id": item["evidence_id"],
|
|
88
|
+
"actionability": "REVIEW_REQUIRED", "reason": item["reason"],
|
|
89
|
+
"dependency": deepcopy(item["dependency"]), "component": deepcopy(item["component"]),
|
|
90
|
+
"target_component": item.get("target_component"),
|
|
91
|
+
"declaration": deepcopy(item.get("declaration", {})), "usage": usage,
|
|
92
|
+
"fallback": fallback, "callers": callers, "snippets": [],
|
|
93
|
+
"question": "What support contract governs this dependency, and is its fallback sufficient for that contract?",
|
|
94
|
+
"authority": "REVIEW_PROPOSAL_ONLY",
|
|
95
|
+
}
|
|
96
|
+
if _size(review) > max_context_bytes_per_item:
|
|
97
|
+
deferred.append({"evidence_id": item["evidence_id"], "reason": "BASE_EVIDENCE_EXCEEDS_BYTE_BUDGET"})
|
|
98
|
+
continue
|
|
99
|
+
source = item["dependency"]["source"]
|
|
100
|
+
references = [(source, item["dependency"].get("line"), "IMPORT")]
|
|
101
|
+
references += [(source, line, "GUARD") for line in usage.get("guard_lines", [])[:4]]
|
|
102
|
+
references += [(value.get("path", source), value.get("line"), "FALLBACK")
|
|
103
|
+
for value in fallback.get("evidence", [])[:4]]
|
|
104
|
+
references += [(source, line, "USAGE") for line in usage.get("usage_lines", [])[:8]]
|
|
105
|
+
references += [(value["path"], value["line"], "INCOMING_FILE_DEPENDENCY") for value in callers]
|
|
106
|
+
files, seen = set(), set()
|
|
107
|
+
for path, line, kind in references:
|
|
108
|
+
if not isinstance(path, str) or not isinstance(line, int) or (path, line) in seen:
|
|
109
|
+
continue
|
|
110
|
+
if path not in files and len(files) >= max_source_files_per_item:
|
|
111
|
+
continue
|
|
112
|
+
seen.add((path, line))
|
|
113
|
+
snippet = _snippet(root, path, line, kind)
|
|
114
|
+
if snippet is None:
|
|
115
|
+
continue
|
|
116
|
+
review["snippets"].append(snippet)
|
|
117
|
+
if _size(review) > max_context_bytes_per_item:
|
|
118
|
+
review["snippets"].pop()
|
|
119
|
+
else:
|
|
120
|
+
files.add(path)
|
|
121
|
+
if not any(snippet["kind"] == "IMPORT" for snippet in review["snippets"]):
|
|
122
|
+
deferred.append({"evidence_id": item["evidence_id"],
|
|
123
|
+
"reason": "IMPORT_CONTEXT_UNAVAILABLE_WITHIN_BUDGET"})
|
|
124
|
+
continue
|
|
125
|
+
reviews.append(review)
|
|
126
|
+
return {
|
|
127
|
+
"format": "ptsip-dependency-review-pack/v1", "repository": deepcopy(report["repository"]),
|
|
128
|
+
"component": report.get("component"), "snapshot": deepcopy(report.get("snapshot", {})),
|
|
129
|
+
"summary": {"review_required_total": len(eligible), "selected_for_review": len(reviews),
|
|
130
|
+
"deferred": len(deferred), "ai_reviewed_items": 0},
|
|
131
|
+
"budget": {"only": ["REVIEW_REQUIRED"], "max_items": max_items,
|
|
132
|
+
"max_context_bytes_per_item": max_context_bytes_per_item,
|
|
133
|
+
"max_source_files_per_item": max_source_files_per_item,
|
|
134
|
+
"byte_measure": "UTF-8 serialized standalone review object, ensure_ascii=false, indent=2, sort_keys=true"},
|
|
135
|
+
"reviews": reviews, "deferred": deferred,
|
|
136
|
+
"authority": "ADVISORY_ONLY", "conformance_evaluated": False,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def write_review_pack(report: dict, output: str | Path | None = None, **budgets) -> tuple[dict, Path]:
|
|
141
|
+
root = Path(report["repository"]["root"]).resolve()
|
|
142
|
+
pack = build_review_pack(report, **budgets)
|
|
143
|
+
observed = capture_snapshot(root).as_dict()
|
|
144
|
+
expected = report.get("snapshot", {}).get("after", {})
|
|
145
|
+
identity = ("is_git", "head", "status_fingerprint", "tracked_content_fingerprint", "tracked_files")
|
|
146
|
+
if not expected or observed["observation_errors"] or any(observed[key] != expected.get(key) for key in identity):
|
|
147
|
+
raise RuntimeError("Repository changed after dependency analysis; regenerate the Review Pack")
|
|
148
|
+
data = json.dumps(pack, ensure_ascii=False, sort_keys=True, separators=(",", ":")) + "\n"
|
|
149
|
+
if output is None:
|
|
150
|
+
destination = (ptsip_home() / "dependency-reviews" / repository_fingerprint(root)
|
|
151
|
+
/ (hashlib.sha256(data.encode("utf-8")).hexdigest()[:20] + ".json")).resolve()
|
|
152
|
+
if destination.is_relative_to(root):
|
|
153
|
+
raise ValueError("Default Review Pack state must stay outside the Consumer Repository")
|
|
154
|
+
else:
|
|
155
|
+
destination = Path(output).expanduser().resolve()
|
|
156
|
+
if destination.suffix.lower() != ".json":
|
|
157
|
+
raise ValueError("Review Pack output must be a JSON report path")
|
|
158
|
+
if destination.is_relative_to(root):
|
|
159
|
+
tracked, errors = git_tracked_files(root)
|
|
160
|
+
if observed["is_git"] and errors:
|
|
161
|
+
raise RuntimeError("Cannot verify Review Pack output against tracked files")
|
|
162
|
+
protected = {str((root / rel).resolve()).casefold() for rel in tracked}
|
|
163
|
+
if str(destination).casefold() in protected:
|
|
164
|
+
raise ValueError("Review Pack output must not overwrite a tracked repository path")
|
|
165
|
+
if any(part in {".git", "src"} for part in destination.relative_to(root).parts):
|
|
166
|
+
raise ValueError("Review Pack output must not be written into source or Git state")
|
|
167
|
+
if destination.exists():
|
|
168
|
+
if destination.read_bytes() != data.encode("utf-8"):
|
|
169
|
+
raise FileExistsError("Review Pack output already exists; choose a new report path")
|
|
170
|
+
return pack, destination
|
|
171
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
172
|
+
with destination.open("x", encoding="utf-8", newline="\n") as stream:
|
|
173
|
+
stream.write(data)
|
|
174
|
+
return pack, destination
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Advisory validation selection from declared ownership and observed imports."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import re
|
|
6
|
+
import tomllib
|
|
7
|
+
|
|
8
|
+
from .validation.components import partition_components, selector_matches_path
|
|
9
|
+
from .validation.profile import validate_profile
|
|
10
|
+
from .repository.snapshot import capture_snapshot, compare_snapshots
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validation_plan(root, report, *, changed_paths=()):
|
|
14
|
+
before = capture_snapshot(root)
|
|
15
|
+
expected = report.get("snapshot", {}).get("after", {})
|
|
16
|
+
if any(before.as_dict()[key] != expected.get(key) for key in (
|
|
17
|
+
"head", "status_fingerprint", "tracked_content_fingerprint")):
|
|
18
|
+
return {"status": "BLOCKED", "reason": "STALE_ANALYSIS", "steps": []}
|
|
19
|
+
result = _validation_plan(root, report, changed_paths=changed_paths)
|
|
20
|
+
if not compare_snapshots(before, capture_snapshot(root)).stable:
|
|
21
|
+
return {"status": "BLOCKED", "reason": "SNAPSHOT_CHANGED", "steps": []}
|
|
22
|
+
return result
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _validation_plan(root, report, *, changed_paths=()):
|
|
26
|
+
root = Path(root).resolve()
|
|
27
|
+
validation = validate_profile(root, report.get("profile_path"))
|
|
28
|
+
if not validation.valid or not validation.resolved_profile or report["status"] != "RAN":
|
|
29
|
+
return {"status": "BLOCKED", "reason": "VALID_PROFILE_AND_SNAPSHOT_REQUIRED", "steps": []}
|
|
30
|
+
payload = validation.resolved_profile.effective_payload
|
|
31
|
+
components = {item["id"]: item for item in payload["components"]}
|
|
32
|
+
partition = partition_components(root, list(components.values()))
|
|
33
|
+
owners = {item.path: item.component_id for item in partition.assignments}
|
|
34
|
+
changed = sorted(set(str(path).replace("\\", "/").removeprefix("./") for path in changed_paths))
|
|
35
|
+
if any(path not in owners for path in changed):
|
|
36
|
+
return {"status": "BLOCKED", "reason": "CHANGED_PATH_OWNERSHIP_REQUIRED", "steps": []}
|
|
37
|
+
affected = {owners[path] for path in changed}
|
|
38
|
+
if not changed:
|
|
39
|
+
affected = {item["component"]["id"] for item in report["items"]
|
|
40
|
+
if item["actionability"] != "AUTO_RESOLVED"}
|
|
41
|
+
links = {(item["from"], item["to"]) for item in payload.get("relationships", [])
|
|
42
|
+
if item.get("type") == "VERIFIES"}
|
|
43
|
+
selected = {key for key, meta in components.items() if "VERIFICATION" in meta.get("roles", [])
|
|
44
|
+
and (key in affected or any((key, target) in links for target in affected)
|
|
45
|
+
or any(selector_matches_path(path, pattern) for path in changed
|
|
46
|
+
for pattern in meta.get("analysis_inputs", [])))}
|
|
47
|
+
tests = sorted(path for path, owner in owners.items() if owner in selected
|
|
48
|
+
and Path(path).name.startswith("test_") and path.endswith(".py"))
|
|
49
|
+
runner_evidence = []
|
|
50
|
+
for item in report["items"]:
|
|
51
|
+
edge = item["dependency"]
|
|
52
|
+
if edge["source"] in tests and edge["target"] == "pytest":
|
|
53
|
+
runner_evidence.append(item["evidence_id"])
|
|
54
|
+
try:
|
|
55
|
+
project = tomllib.loads((root / "pyproject.toml").read_text(encoding="utf-8-sig")).get("project", {})
|
|
56
|
+
if not isinstance(project, dict):
|
|
57
|
+
raise ValueError("Project metadata must be a table")
|
|
58
|
+
requirements = project.get("dependencies", [])
|
|
59
|
+
optional = project.get("optional-dependencies", {})
|
|
60
|
+
if not isinstance(requirements, list) or not isinstance(optional, dict):
|
|
61
|
+
raise ValueError("Dependency metadata has an invalid shape")
|
|
62
|
+
requirements = requirements + [value for group in optional.values() if isinstance(group, list) for value in group]
|
|
63
|
+
if any(isinstance(value, str) and re.match(r"^pytest(?:\s|[<>=!~\[;@]|$)", value.strip())
|
|
64
|
+
for value in requirements):
|
|
65
|
+
runner_evidence.append("manifest:pyproject.toml:pytest")
|
|
66
|
+
except (OSError, ValueError, TypeError):
|
|
67
|
+
pass
|
|
68
|
+
if not tests or not runner_evidence:
|
|
69
|
+
return {"status": "REVIEW_REQUIRED", "reason": "VERIFICATION_EXECUTION_EVIDENCE_REQUIRED",
|
|
70
|
+
"verification_components": sorted(selected), "steps": [], "authority": "ADVISORY_ONLY"}
|
|
71
|
+
graph = {}
|
|
72
|
+
for item in report["items"]:
|
|
73
|
+
edge = item["dependency"]
|
|
74
|
+
if edge.get("resolved_path"):
|
|
75
|
+
graph.setdefault(edge["source"], set()).add(edge["resolved_path"])
|
|
76
|
+
def reaches_change(path):
|
|
77
|
+
visited, pending = set(), [path]
|
|
78
|
+
while pending:
|
|
79
|
+
current = pending.pop()
|
|
80
|
+
if current in changed:
|
|
81
|
+
return True
|
|
82
|
+
if current not in visited:
|
|
83
|
+
visited.add(current)
|
|
84
|
+
pending.extend(graph.get(current, ()))
|
|
85
|
+
return False
|
|
86
|
+
focused = [path for path in tests if reaches_change(path)]
|
|
87
|
+
steps = []
|
|
88
|
+
if focused:
|
|
89
|
+
steps.append({"scope": "focused", "command": ["python", "-m", "pytest", *focused, "-q"],
|
|
90
|
+
"run_when": "focused_change", "basis": "OBSERVED_IMPORT_REACHABILITY_OR_CHANGED_TEST"})
|
|
91
|
+
# Only collapse to a directory if every tracked test in it belongs to the
|
|
92
|
+
# selected verification components; never broaden to unrelated tests.
|
|
93
|
+
parents = sorted({str(Path(path).parent).replace("\\", "/") for path in tests})
|
|
94
|
+
targets = []
|
|
95
|
+
for parent in parents:
|
|
96
|
+
peers = [path for path in owners if path.startswith(parent + "/")
|
|
97
|
+
and Path(path).name.startswith("test_") and path.endswith(".py")]
|
|
98
|
+
targets.extend([parent] if all(path in tests for path in peers)
|
|
99
|
+
else [path for path in tests if str(Path(path).parent).replace("\\", "/") == parent])
|
|
100
|
+
steps.append({"scope": "component", "command": ["python", "-m", "pytest", *targets, "-q", "--maxfail=10"],
|
|
101
|
+
"run_when": "batch_complete", "basis": "DECLARED_VERIFICATION_OWNERSHIP"})
|
|
102
|
+
return {"format": "ptsip-dependency-validation-plan/v1", "status": "PROPOSED",
|
|
103
|
+
"changed_paths": changed, "verification_components": sorted(selected),
|
|
104
|
+
"runner_evidence": sorted(runner_evidence), "steps": steps,
|
|
105
|
+
"authority": "ADVISORY_ONLY", "executed": False,
|
|
106
|
+
"checkpoint": "Run the repository-declared full regression and strict conform at a WU checkpoint"}
|
ptsip/doctor.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .storage.local_state import ptsip_home
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def doctor(path: str | Path = ".") -> dict[str, object]:
|
|
11
|
+
target = Path(path).expanduser().resolve()
|
|
12
|
+
current_minor = (sys.version_info.major, sys.version_info.minor)
|
|
13
|
+
metadata_supported = current_minor >= (3, 11)
|
|
14
|
+
ci_verified = (3, 11) <= current_minor <= (3, 14)
|
|
15
|
+
github_cli = shutil.which("gh")
|
|
16
|
+
return {
|
|
17
|
+
"python": sys.version.split()[0],
|
|
18
|
+
"python_ok": metadata_supported,
|
|
19
|
+
"python_supported_by_metadata": metadata_supported,
|
|
20
|
+
"python_ci_verified": ci_verified,
|
|
21
|
+
"python_ci_verified_range": "3.11-3.14",
|
|
22
|
+
"python_support_note": (
|
|
23
|
+
"This interpreter is within the current CI-verified range."
|
|
24
|
+
if ci_verified
|
|
25
|
+
else "Package metadata allows this interpreter, but this minor version is outside the current CI matrix."
|
|
26
|
+
),
|
|
27
|
+
"git": shutil.which("git"),
|
|
28
|
+
"github_cli": github_cli,
|
|
29
|
+
"github_issue_publish_available": github_cli is not None,
|
|
30
|
+
"target": str(target),
|
|
31
|
+
"target_exists": target.exists(),
|
|
32
|
+
"ptsip_home": str(ptsip_home()),
|
|
33
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Read-only consumer diagnostics for the seven independently packaged engines.
|
|
2
|
+
|
|
3
|
+
Installation is delegated to the authorized package-manager transaction.
|
|
4
|
+
Presence or self-reported wheel provenance never grants runtime authority.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import platform
|
|
12
|
+
import re
|
|
13
|
+
import sys
|
|
14
|
+
import sysconfig
|
|
15
|
+
from importlib import metadata, resources
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
HOST_TARGETS = {
|
|
20
|
+
("win32", "amd64"): "x86_64-pc-windows-msvc",
|
|
21
|
+
("win32", "x86_64"): "x86_64-pc-windows-msvc",
|
|
22
|
+
("linux", "x86_64"): "x86_64-unknown-linux-gnu",
|
|
23
|
+
("darwin", "arm64"): "aarch64-apple-darwin",
|
|
24
|
+
("darwin", "aarch64"): "aarch64-apple-darwin",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _load(relative: str) -> dict[str, Any]:
|
|
29
|
+
resource = resources.files("ptsip").joinpath("engines", *relative.split("/"))
|
|
30
|
+
return json.loads(resource.read_text(encoding="utf-8"))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _sha256(path: Path) -> str:
|
|
34
|
+
digest = hashlib.sha256()
|
|
35
|
+
with path.open("rb") as stream:
|
|
36
|
+
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
|
|
37
|
+
digest.update(chunk)
|
|
38
|
+
return digest.hexdigest()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _bundle(items: list[dict[str, Any]]) -> tuple[Any, dict[str, Any]] | None:
|
|
42
|
+
"""A broken installed bundle must not fall back to another distribution."""
|
|
43
|
+
try:
|
|
44
|
+
distribution = metadata.distribution("PTSIP")
|
|
45
|
+
except metadata.PackageNotFoundError:
|
|
46
|
+
return None
|
|
47
|
+
text = distribution.read_text("ptsip-engines.json")
|
|
48
|
+
if text is None:
|
|
49
|
+
return None
|
|
50
|
+
try:
|
|
51
|
+
bundle = json.loads(text)
|
|
52
|
+
origins = bundle["engines"]
|
|
53
|
+
if (
|
|
54
|
+
bundle["schema_version"] != "ptsip-bundled-engine-origins/v1"
|
|
55
|
+
or bundle["package_version"] != distribution.version
|
|
56
|
+
or bundle["execution_authorized"] is not False
|
|
57
|
+
or set(origins) != {entry["kind"].lower() for entry in items}
|
|
58
|
+
or len(origins) != len(items)
|
|
59
|
+
):
|
|
60
|
+
raise ValueError("incomplete or incompatible PTSIP engine bundle")
|
|
61
|
+
for entry in items:
|
|
62
|
+
origin = origins[entry["kind"].lower()]
|
|
63
|
+
if (
|
|
64
|
+
origin["schema_version"] != "ptsip-independent-wheel-origin/v1"
|
|
65
|
+
or origin["engine_id"] != entry["engine_id"]
|
|
66
|
+
or origin["engine_version"] != entry["version"]
|
|
67
|
+
or origin["execution_authorized"] is not False
|
|
68
|
+
or re.fullmatch(r"[0-9a-f]{40}", origin["source_sha"]) is None
|
|
69
|
+
):
|
|
70
|
+
raise ValueError("PTSIP bundled engine identity differs")
|
|
71
|
+
return distribution, bundle
|
|
72
|
+
except (KeyError, TypeError, json.JSONDecodeError) as exc:
|
|
73
|
+
raise ValueError("PTSIP bundled engine metadata is invalid") from exc
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def inspect(
|
|
77
|
+
*,
|
|
78
|
+
index: dict[str, Any] | None = None,
|
|
79
|
+
plan: dict[str, Any] | None = None,
|
|
80
|
+
bindings: dict[str, dict[str, Any]] | None = None,
|
|
81
|
+
scripts: Path | None = None,
|
|
82
|
+
host_target: str | None = None,
|
|
83
|
+
) -> dict[str, Any]:
|
|
84
|
+
index = index if index is not None else _load("index.json")
|
|
85
|
+
plan = plan if plan is not None else _load("contracts/installation-plan.json")
|
|
86
|
+
items = index["official_engine_entries"]
|
|
87
|
+
packages = {p["engine_id"]: p for p in plan["packages"]}
|
|
88
|
+
if (
|
|
89
|
+
len(items) != 7 or len(packages) != 7
|
|
90
|
+
or len({i["engine_id"] for i in items}) != 7
|
|
91
|
+
or set(packages) != {i["engine_id"] for i in items}
|
|
92
|
+
or set(plan["default_available_engine_ids"]) != set(packages)
|
|
93
|
+
):
|
|
94
|
+
raise ValueError("official engine index or installation registry incomplete/ambiguous")
|
|
95
|
+
host_target = host_target or HOST_TARGETS.get(
|
|
96
|
+
(sys.platform, platform.machine().lower())
|
|
97
|
+
)
|
|
98
|
+
scripts = scripts or Path(sysconfig.get_path("scripts"))
|
|
99
|
+
bundled = _bundle(items)
|
|
100
|
+
entries: list[dict[str, Any]] = []
|
|
101
|
+
for entry in items:
|
|
102
|
+
kind, engine_id, version = entry["kind"], entry["engine_id"], entry["version"]
|
|
103
|
+
pkg = packages[engine_id]
|
|
104
|
+
package_name = "ptsip-engine-" + kind.lower()
|
|
105
|
+
if (
|
|
106
|
+
pkg["distribution"] != "INDEPENDENT_VERSIONED_NATIVE_WHEEL"
|
|
107
|
+
or pkg["package_distribution"] != package_name
|
|
108
|
+
or pkg["installation"] != "AUTO_INSTALL_AS_PTSIP_PACKAGE_DEPENDENCY"
|
|
109
|
+
or pkg["version"] != version
|
|
110
|
+
or pkg["permission_from_availability"] is not False
|
|
111
|
+
):
|
|
112
|
+
raise ValueError("outdated or incompatible official engine installation contract")
|
|
113
|
+
b = bindings[kind] if bindings is not None else _load(
|
|
114
|
+
f"{kind.lower()}/execution-bindings.json"
|
|
115
|
+
)
|
|
116
|
+
candidates = b["bindings"]
|
|
117
|
+
if len(candidates) != 1:
|
|
118
|
+
raise ValueError("ambiguous registered engine executable")
|
|
119
|
+
binding = candidates[0]
|
|
120
|
+
if binding["entrypoint"] != package_name or binding["engine_id"] != engine_id or binding["engine_version"] != version:
|
|
121
|
+
raise ValueError("registered engine entrypoint mismatch")
|
|
122
|
+
row: dict[str, Any] = {
|
|
123
|
+
"engine": kind, "engine_id": engine_id, "expected_version": version,
|
|
124
|
+
"package": package_name, "host_target": host_target,
|
|
125
|
+
"status": "NOT_INSTALLED", "execution_authorized": False,
|
|
126
|
+
}
|
|
127
|
+
if host_target not in pkg["build_targets"]:
|
|
128
|
+
row["status"] = "UNSUPPORTED_HOST"
|
|
129
|
+
entries.append(row)
|
|
130
|
+
continue
|
|
131
|
+
if bundled is not None:
|
|
132
|
+
distribution, bundle = bundled
|
|
133
|
+
origin = bundle["engines"][kind.lower()]
|
|
134
|
+
row["package"] = "PTSIP"
|
|
135
|
+
row["package_version"] = distribution.version
|
|
136
|
+
row["installed_version"] = origin["engine_version"]
|
|
137
|
+
else:
|
|
138
|
+
try:
|
|
139
|
+
distribution = metadata.distribution(package_name)
|
|
140
|
+
except metadata.PackageNotFoundError:
|
|
141
|
+
entries.append(row)
|
|
142
|
+
continue
|
|
143
|
+
row["installed_version"] = distribution.version
|
|
144
|
+
if row["installed_version"] != version:
|
|
145
|
+
row["status"] = "VERSION_MISMATCH"
|
|
146
|
+
entries.append(row)
|
|
147
|
+
continue
|
|
148
|
+
extension = ".exe" if host_target and "windows" in host_target else ""
|
|
149
|
+
executable = scripts / (binding["entrypoint"] + extension)
|
|
150
|
+
if executable.is_symlink() or not executable.is_file():
|
|
151
|
+
row["status"] = "EXECUTABLE_MISSING_OR_UNTRUSTED_PATH"
|
|
152
|
+
entries.append(row)
|
|
153
|
+
continue
|
|
154
|
+
try:
|
|
155
|
+
if bundled is None:
|
|
156
|
+
origin_text = distribution.read_text("ptsip-origin.json")
|
|
157
|
+
origin = json.loads(origin_text or "")
|
|
158
|
+
if (
|
|
159
|
+
origin["engine_id"] != engine_id
|
|
160
|
+
or origin["engine_version"] != version
|
|
161
|
+
or origin["host_target"] != host_target
|
|
162
|
+
or origin["entrypoint"] != executable.name
|
|
163
|
+
or not isinstance(origin["source_sha"], str)
|
|
164
|
+
or len(origin["source_sha"]) != 40
|
|
165
|
+
or origin["binary_sha256"] != _sha256(executable)
|
|
166
|
+
):
|
|
167
|
+
row["status"] = "ARTIFACT_IDENTITY_MISMATCH"
|
|
168
|
+
else:
|
|
169
|
+
row["status"] = "INSTALLED_UNATTESTED_RELEASE"
|
|
170
|
+
row["binary_sha256"] = origin["binary_sha256"]
|
|
171
|
+
row["source_sha"] = origin["source_sha"]
|
|
172
|
+
except (OSError, json.JSONDecodeError, KeyError, TypeError, ValueError):
|
|
173
|
+
row["status"] = "ORIGIN_PROOF_MISSING_OR_INVALID"
|
|
174
|
+
entries.append(row)
|
|
175
|
+
return {
|
|
176
|
+
"schema_version": "ptsip-official-engine-consumer-status/v1",
|
|
177
|
+
"host_target": host_target,
|
|
178
|
+
"distribution": "SINGLE_PROJECT_PLATFORM_BUNDLES" if bundled else "AUTO_INSTALLED_INDEPENDENT_PACKAGES_ONLY",
|
|
179
|
+
"entries": entries,
|
|
180
|
+
"all_installed": all(e["status"] == "INSTALLED_UNATTESTED_RELEASE" for e in entries),
|
|
181
|
+
"release_attested": False,
|
|
182
|
+
"execution_authorized": False,
|
|
183
|
+
"status": "AWAITING_OFFICIAL_RELEASE_ATTESTATION"
|
|
184
|
+
if all(e["status"] == "INSTALLED_UNATTESTED_RELEASE" for e in entries)
|
|
185
|
+
else "INCOMPLETE",
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def emit_status() -> tuple[dict[str, Any], int]:
|
|
190
|
+
payload = inspect()
|
|
191
|
+
return payload, 0 if payload["all_installed"] else 4
|