diff --git a/ADOPTION.md b/ADOPTION.md index e935807b..be9ea8be 100644 --- a/ADOPTION.md +++ b/ADOPTION.md @@ -333,6 +333,8 @@ agentic-proofkit requirement-authoring-plan --help agentic-proofkit native-evidence-guidance --help agentic-proofkit proof-receipt-admission --help agentic-proofkit spec-proof-bundle-admission --help +agentic-proofkit requirement-coverage-input-compose --help +agentic-proofkit receipt-currentness-scope --help ``` The authoring guide connects candidate materialization; native guidance names @@ -388,6 +390,15 @@ discovery, receipt admission and reverse-impact review without a documentation lookup or a new runner. Normal JSON and text guidance stay bounded to their existing slots; the longer recipe is loaded only on explicit help. +The coverage guide connects the original source, binding and inventory inputs +to the coverage composer and then its exact output to the view. Composer success +does not mean coverage passed: retain the downstream failures, unmapped tests +and declared dead zones. Currentness has a separate input guide that binds the +original receipt's recorded subjects to independently captured current subjects. +It does not discover files or authenticate supplied hashes; an inapplicable +scope is not a current passing test. Both templates deliberately reject until +the consumer supplies their missing operands. + Start with one owner-reviewed promise, such as rejecting an empty request. The connected `adopt materialize plan --help` example supplies its requirement, scenario and witness records. Replace fictional paths, selectors, command and diff --git a/internal/app/cli_contract_test.go b/internal/app/cli_contract_test.go index 72afd138..b913826e 100644 --- a/internal/app/cli_contract_test.go +++ b/internal/app/cli_contract_test.go @@ -24,7 +24,7 @@ import ( ) const ( - cliContractPublicABISHA256 = "147318e2449fd7f6cf51e81cba35d16a20c95fd82ab45ba4feadc1ced45eb67d" + cliContractPublicABISHA256 = "2867ea2c8caf03e5b88fa46cabee0697e781452af2a8049e70660796730d0b66" maxAggregateFileReadBytesForContractTest = 64 << 20 maxPackageManifestBytesForContractTest = 256 << 10 maxSourceFileBytesForContractTest = 8 << 20 diff --git a/internal/app/command_contract_generated.go b/internal/app/command_contract_generated.go index 2f0aca3d..cf3f8318 100644 --- a/internal/app/command_contract_generated.go +++ b/internal/app/command_contract_generated.go @@ -1,7 +1,7 @@ // Code generated by internal/tools/commandcontractgen; DO NOT EDIT. package app -const commandContractSourceSHA256 = "18144447341a97e4d498f99839fb45b252fedd1e98429e6f16c3a0f5b7a6ba94" +const commandContractSourceSHA256 = "40e21bb074eea37dba970d08cf06e1c5ee0ec1c1d7404fad1e7e28490a3924c4" type generatedCommandContractMetadata struct { InputContractSHA256 string @@ -12,15 +12,15 @@ type generatedCommandContractMetadata struct { } var generatedCommandContractMetadataByName = map[string]generatedCommandContractMetadata{ - "adopt-materialize-apply": {InputContractSHA256: "sha256:ff3aee6b2420c04d19afdf3a72ef2a73b731f25cc1abcb0f3fe1ffd0fc9ed06b", InputSchemaSummary: []string{"schemaVersion=1", "owner-admitted adoption plan, requirement sources, proof bindings, and direct test inventory", "root-shape-only definition proofkit.adoption-materialization.apply-input.v1.root-shape; nested fields, types, cardinalities, and cross-record closure remain native-owner claims"}, OutputContractSHA256: "sha256:84d40be39bab36983222afcde7d31115346262fa437d7d9eede390bc64aa0a69", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "apply"}}, - "adopt-materialize-plan": {InputContractSHA256: "sha256:484d8d867ff1080d14f14c9b82c9e02ce0bb10ded7713b8098b5a2f5128fefc2", InputSchemaSummary: []string{"schemaVersion=1", "owner-admitted adoption plan, requirement sources, proof bindings, and direct test inventory", "root-shape-only definition proofkit.adoption-materialization.plan-input.v1.root-shape; nested fields, types, cardinalities, and cross-record closure remain native-owner claims"}, OutputContractSHA256: "sha256:fbc9e87bd9794e1e2c15da9704a1a87eed1512f720033193237fb73a373f7c6c", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "plan"}}, - "adopt-materialize-recover": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:ed3a270b6a7256d59e59c4fb1af60dcb91097acc34e3d50fa44d47b78532d738", FlagChoices: map[string][]string{"--action": []string{"resume", "rollback"}, "--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "recover"}}, + "adopt-materialize-apply": {InputContractSHA256: "sha256:ff3aee6b2420c04d19afdf3a72ef2a73b731f25cc1abcb0f3fe1ffd0fc9ed06b", InputSchemaSummary: []string{"schemaVersion=1", "owner-admitted adoption plan, requirement sources, proof bindings, and direct test inventory", "root-shape-only definition proofkit.adoption-materialization.apply-input.v1.root-shape; nested fields, types, cardinalities, and cross-record closure remain native-owner claims"}, OutputContractSHA256: "sha256:0b6422c73221f2d45ab30c523bd467f8ca7e5871ad299ef4a4a65d2bb2d3f2b6", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "apply"}}, + "adopt-materialize-plan": {InputContractSHA256: "sha256:484d8d867ff1080d14f14c9b82c9e02ce0bb10ded7713b8098b5a2f5128fefc2", InputSchemaSummary: []string{"schemaVersion=1", "owner-admitted adoption plan, requirement sources, proof bindings, and direct test inventory", "root-shape-only definition proofkit.adoption-materialization.plan-input.v1.root-shape; nested fields, types, cardinalities, and cross-record closure remain native-owner claims"}, OutputContractSHA256: "sha256:96f5947637a274bd4995989da657b7091ca3c6a3dea4b4839da61ed727537cd5", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "plan"}}, + "adopt-materialize-recover": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:7f4260b4997bcefefee18a1a43b02f9955e064026e034c20fde641f163d07a9e", FlagChoices: map[string][]string{"--action": []string{"resume", "rollback"}, "--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"adopt", "materialize", "recover"}}, "adopt-plan": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:ba2bb3ce147ac37bde035334e0058820339b36de2a0ae270a9e5dbe00e6a3e6d", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}, "--mode": []string{"audit-from-code", "code-baseline", "fresh"}, "--stack": []string{"agentic_runtime_repo", "generated_docs_contract_repo", "python_service", "python_typescript_service", "typescript_monorepo", "typescript_workspace"}}, RouteTokens: []string{"adopt", "plan"}}, "adoption-checklist": {InputContractSHA256: "sha256:4e6c4c9b369279837a5894c0b3f842a411dce529b91c91cb2d4ec63eb5ee4c2c", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.adoption-checklist.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:9d0d0e60f0935407fd31007d8502459663eb4c7228dc5e3c7727ae2c9907bdc9", FlagChoices: map[string][]string{}, RouteTokens: []string{"adoption-checklist"}}, "adoption-contract-envelope": {InputContractSHA256: "sha256:c310214676ff4b6f536a5bc9d687f681a7e71f73d7a03ac932707d8cd3905cdf", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.adoption-contract-envelope.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:3efb2c5161fee16fd8ac6a40dcb6d9c41fbc23e468f60621436ae9e8076e0950", FlagChoices: map[string][]string{}, RouteTokens: []string{"adoption-contract-envelope"}}, "adoption-doctor": {InputContractSHA256: "sha256:efa9acfe32bff07f56d9dc9902530df2979794289bc2f7f547f7a108a7dd0f35", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.adoption-doctor.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:8fdfc6608f197e633f042f20031ae1014872a90aa3daa66885ffcaddca994766", FlagChoices: map[string][]string{}, RouteTokens: []string{"adoption-doctor"}}, "adoption-workflow-plan": {InputContractSHA256: "sha256:b32ae67179d7b6dcf1ea66cb6b2b2691c8367ce2e2be367619b65973166da55c", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.adoption-workflow-plan.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:8d64cb53ebd0307e3cebc3435286a3d2a1ee8a0ad6f7514fc0fb3285db0f565b", FlagChoices: map[string][]string{}, RouteTokens: []string{"adoption-workflow-plan"}}, - "agent-route": {InputContractSHA256: "sha256:c00e832b4e9eac6b858eec46e810431c0a5c9f56c5c50f055f39ee024f50014c", InputSchemaSummary: []string{"availableInputs", "browserMode", "goal", "knownChangedPaths", "mode", "nonClaims", "observedReports", "openBrowser", "routeId", "schemaVersion", "root-shape-only definition proofkit.agent-route.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:ec7f56330ac44ec879dfaa3a8ee92eb7f9165f77adab8892452400789012fde3", FlagChoices: map[string][]string{}, RouteTokens: []string{"agent-route"}}, + "agent-route": {InputContractSHA256: "sha256:c00e832b4e9eac6b858eec46e810431c0a5c9f56c5c50f055f39ee024f50014c", InputSchemaSummary: []string{"availableInputs", "browserMode", "goal", "knownChangedPaths", "mode", "nonClaims", "observedReports", "openBrowser", "routeId", "schemaVersion", "root-shape-only definition proofkit.agent-route.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:92f47b1f6d2a90d67a98242df788cb857a07c74267bdff2d99638ecd319e3122", FlagChoices: map[string][]string{}, RouteTokens: []string{"agent-route"}}, "binding-partition": {InputContractSHA256: "sha256:366ad082045af52b2ac6604f18626d0f285b2db73b45d9a82687b8d3b0d2b3fd", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.binding-partition.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:52840879e13a00ef9a4abaad6cdb33000511674d5f9003fb56f387fdf58fadc8", FlagChoices: map[string][]string{}, RouteTokens: []string{"binding-partition"}}, "branch-authority": {InputContractSHA256: "sha256:8a3ed74978898593fbdbf1f7fa684dae450fbd9019edcd60d07f818d63363ed4", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.branch-authority.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:3c7dc74842299b92cd5baf57cc8666e9415963091359e5faf654e28da89561f1", FlagChoices: map[string][]string{}, RouteTokens: []string{"branch-authority"}}, "capability-map-admission": {InputContractSHA256: "sha256:36025145e1be04f8da9baccd2161b4ccf04f5426e95084d9cccc01802970e29d", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.capability-map-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:5100e56075f50435605264c6a835a60f24f6790479e2b4c623d359f1e7e78690", FlagChoices: map[string][]string{}, RouteTokens: []string{"capability-map-admission"}}, @@ -38,25 +38,25 @@ var generatedCommandContractMetadataByName = map[string]generatedCommandContract "gradual-adoption-guidance": {InputContractSHA256: "sha256:4752cbac81c864cb3e18a39facfd666a9707314233d54798c7f71e67d7f2800c", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.gradual-adoption-guidance.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:171fed4bb8d32a47fc5ec49796f5b0b55ed666feaccc2fbbfeb12da31d80ecc9", FlagChoices: map[string][]string{}, RouteTokens: []string{"gradual-adoption-guidance"}}, "help": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "", FlagChoices: map[string][]string{}, RouteTokens: []string{"help"}}, "impact": {InputContractSHA256: "sha256:41d3107414837955ee408d5ce94949a4c1a6b76f6949e6c1dc224bd06f6b09bc", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.impact.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:73066e9a5ca48f21936111ffb7223900fb629875997f4e7b16d7fef9c4177972", FlagChoices: map[string][]string{}, RouteTokens: []string{"impact"}}, - "integration-apply": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:af4aa081d8630bb31adc58c74952020709388a8978421f4819aeb57b4be46876", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}, "--operation": []string{"install", "remove", "update"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "apply"}}, - "integration-check": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:ae27e65745504494a4c748ab26d03264e77bf0b7db69cd8927378be5eda478e4", FlagChoices: map[string][]string{"--format": []string{"json", "text"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "check"}}, - "integration-plan": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:8b0f9e9253afc70aa9e0ec0567b86c54576feb319d7ed3eddda7574f1126b3af", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}, "--operation": []string{"install", "remove", "update"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "plan"}}, - "integration-recover": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:8be9cb5de470e32dc82e19836dccd51284e32f0f45da2105a5c2786e9a2fadd5", FlagChoices: map[string][]string{"--action": []string{"resume", "rollback"}, "--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"integration", "recover"}}, - "integration-source": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:fb566a960ef2a319d4790cb1fb9cb7ffc078560e6744ca93cbdea5ea901b01cf", FlagChoices: map[string][]string{"--format": []string{"json", "text"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "source"}}, + "integration-apply": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:65af409248c6413f9ce22e436cde242b3875451dcd8d761ea9d464f61c740a1a", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}, "--operation": []string{"install", "remove", "update"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "apply"}}, + "integration-check": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:447db19dd53276746654d272f300fd819e54ce037382d6bf983b0c07b524b66b", FlagChoices: map[string][]string{"--format": []string{"json", "text"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "check"}}, + "integration-plan": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:76359c885ae29c964c96f59fd626d7c576d1d75fb851f3993de841b9cdc2cee9", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}, "--operation": []string{"install", "remove", "update"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "plan"}}, + "integration-recover": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:880c85b05aa164985d4eee01352414d6a938b50bf46cdd1e31483ed609571d2b", FlagChoices: map[string][]string{"--action": []string{"resume", "rollback"}, "--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"integration", "recover"}}, + "integration-source": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:128d4a199f97dee063766b42156493eb19d267455df83f07613e3b052daf3f4c", FlagChoices: map[string][]string{"--format": []string{"json", "text"}, "--tool": []string{"claude", "codex"}}, RouteTokens: []string{"integration", "source"}}, "json-report-cli-adapter-source": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:6c3dd1c8507a90e055cf2c886089446d8560ff3e0d3ca9cc6360a3377d2d85da", FlagChoices: map[string][]string{}, RouteTokens: []string{"json-report-cli-adapter-source"}}, "migration-parity-admission": {InputContractSHA256: "sha256:0b36c0e68da3b857dac4b13e7b3bd523052459106133aa8c908a4352682e6c05", InputSchemaSummary: []string{"schemaVersion=1", "paritySetId", "sourceProofOwners[]", "targetProofkitRefs[]", "parityRecords[]", "nonClaims[]", "root-shape-only definition proofkit.migration-parity-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:8e0f8af2b205817f018b0fe133fe789661caa29007695e036bfcab63c1830f47", FlagChoices: map[string][]string{}, RouteTokens: []string{"migration-parity-admission"}}, "migration-plan": {InputContractSHA256: "sha256:58a62759a634101ce2ca9218184175134bbe5633328e1b23797b94c19fc9b11a", InputSchemaSummary: []string{"schemaVersion=1", "migrationId", "sourceProofOwners[]", "targetProofkitRefs[]", "parityEvidenceRefs[]", "retainedOwners[]", "retirementCandidates[]", "followUpCommands[]", "nonClaims[]", "root-shape-only definition proofkit.migration-plan.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:f14f0381e9dc241357c346315b95b03ef5b23f1d1bbc3b00f111fbe1515ed3ff", FlagChoices: map[string][]string{}, RouteTokens: []string{"migration-plan"}}, - "native-evidence-guidance": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:81810202f3bb4379ed29a9195eaab84b1a9f8ef6327206199723d97d7ef49af9", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"native-evidence-guidance"}}, + "native-evidence-guidance": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:fe02404bbd97a6fc56911441688e74db4a45f3acacfbcbcfe22b5f1073758640", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"native-evidence-guidance"}}, "next": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:7394789ca6a1a275662109980d82d58f3586e6afb2689d0b3e54acb14d067c21", FlagChoices: map[string][]string{"--color": []string{"auto", "never"}, "--format": []string{"json", "text"}}, RouteTokens: []string{"next"}}, "obligation-decision": {InputContractSHA256: "sha256:1dea2ed5c5066451d6d49b815cea99df2cdae2ef05d42fed16c8aeb45eb7f445", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.obligation-decision.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:96dc074f611bcc12e511bc803c548e4df623e2de869d3add29a3ea6386e04330", FlagChoices: map[string][]string{}, RouteTokens: []string{"obligation-decision"}}, "package-runtime-dependency-admission": {InputContractSHA256: "sha256:fc85887af9b8fcd899d245f0db30b2f2f68609822fc268126bf999082bb4115f", InputSchemaSummary: []string{"schemaVersion=1", "reportId", "expectedDependencySpec", "expectedLockfileIntegrity", "expectedPackageName", "expectedPackageVersion", "admissibleLocations{}", "packageResolution{}", "nonClaims[]", "root-shape-only definition proofkit.package-runtime-dependency-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:c012032e8c8212fd50bc2e85669cc610609ca2124ebc992c9e88f44a1ad2d5fc", FlagChoices: map[string][]string{}, RouteTokens: []string{"package-runtime-dependency-admission"}}, - "pilot-admission": {InputContractSHA256: "sha256:a1d9116ce619f7d705349ff4ae44c0f4399a281ebaa9e7d62ea304ac57af59ba", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.pilot-admission.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:b8e07ba46ce0b76f2627cd5c2eebcd07d23bc4a0001e51133a1003e90cf758a1", FlagChoices: map[string][]string{}, RouteTokens: []string{"pilot-admission"}}, + "pilot-admission": {InputContractSHA256: "sha256:a1d9116ce619f7d705349ff4ae44c0f4399a281ebaa9e7d62ea304ac57af59ba", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.pilot-admission.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:66c6995438128545e05d535484e399c5bf11fb0b257e156cf389505fdcc73025", FlagChoices: map[string][]string{}, RouteTokens: []string{"pilot-admission"}}, "producer-policy-self-proof": {InputContractSHA256: "sha256:d48e18826000c8d415f3c44b6c686e1da6ed962ef7ca36c9f705de8c68d034f9", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.producer-policy-self-proof.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:e82a3989a743f8babc6069f7af82b1dd1ea62bad8dbb18d95e105b36f74e4276", FlagChoices: map[string][]string{}, RouteTokens: []string{"producer-policy-self-proof"}}, "proof-obligation-algebra": {InputContractSHA256: "sha256:4f176b6bc9bdbd0d96d65c071d66447d246665bda7a23269e7927f1d0b80b043", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.proof-obligation-algebra.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:f9ee9e56b349756c55856a2dab198e1ad85db70a468c38e3aeca73cfe2ed66f6", FlagChoices: map[string][]string{}, RouteTokens: []string{"proof-obligation-algebra"}}, "proof-receipt-admission": {InputContractSHA256: "sha256:8ba257066e276a48de661e52cabd3be194cba31a8a45e082f3b013a5c9a9120c", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.proof-receipt-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:40fd1426468aae342029e10dcc950e6a24142f9a09f0b3d4513622c7a2bff75c", FlagChoices: map[string][]string{}, RouteTokens: []string{"proof-receipt-admission"}}, "proof-slice": {InputContractSHA256: "sha256:eb057ad276f0dd19929a1d425cd3d7f3d6d36e71888041bc7da0652c5efcac2a", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.proof-slice.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:6750b4d516fff1c37e542b68884ad8ac3da65dd3d56d10596e801bc0965021c7", FlagChoices: map[string][]string{}, RouteTokens: []string{"proof-slice"}}, "readiness-closeout": {InputContractSHA256: "sha256:4f427c1d0cefb00133d0d9fdb15f75ca9d12a26746632914e82bf72710883b9b", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.readiness-closeout.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:427a227aa59d60739bc7bdea03363ece95070520dc154fff1f063e174027cc5e", FlagChoices: map[string][]string{}, RouteTokens: []string{"readiness-closeout"}}, - "receipt-currentness-scope": {InputContractSHA256: "sha256:a3787eaacabc8902e90a39fe7fa179df3464a93829991006f720d2bd30572f06", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.receipt-currentness-scope.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:007e38673d5e8bb4a5c9447a835a7692e544b0f6e1f077d6f4f109fd08e3bf2a", FlagChoices: map[string][]string{}, RouteTokens: []string{"receipt-currentness-scope"}}, + "receipt-currentness-scope": {InputContractSHA256: "sha256:2e2d3ea6aafa28e7f195217e4d262c41919a54531ce6ab9d1b9c74fa1f1f0f77", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.receipt-currentness-scope.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:879ae88369ab28e8db6bd94ffa61e42e550f094edc5a593e3b32ea131483f81b", FlagChoices: map[string][]string{}, RouteTokens: []string{"receipt-currentness-scope"}}, "receipt-producer-admission": {InputContractSHA256: "sha256:676aa03b2331a094e287dd3f2dfad3a74403b6f8dadb17e420b446aac0b3592c", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.receipt-producer-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:626b910bb8110901d6769c0ec2a14d216d9ca422aaf2f73ef5fc851c60b0847a", FlagChoices: map[string][]string{}, RouteTokens: []string{"receipt-producer-admission"}}, "receipt-trust-class": {InputContractSHA256: "sha256:be11e398a8e138243a0440a57fafb2b8b47faff7daefb2727da16af3e0c9d649", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.receipt-trust-class.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:7eeba48696ce232f9d7af48cf90ad57705bdcfade5a8d8837704ae2f06f5a76e", FlagChoices: map[string][]string{}, RouteTokens: []string{"receipt-trust-class"}}, "registry-consumer": {InputContractSHA256: "sha256:b4c71b63507b262b84d510573aa094592ea94579c4f332833f787f1719fa012b", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.registry-consumer.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:0b557f1db529d4527807513a97ebaedc4ae0b3d61b4445647ccd77667674db4b", FlagChoices: map[string][]string{}, RouteTokens: []string{"registry-consumer"}}, @@ -70,7 +70,7 @@ var generatedCommandContractMetadataByName = map[string]generatedCommandContract "requirement-browser-server": {InputContractSHA256: "sha256:557d9f1e6919a6f40b831fb910340f85cdc0a0619d0c4895098308939a262e6e", InputSchemaSummary: []string{"workspace mode: schemaVersion=2", "workspace mode: workspaceId", "workspace mode: context=proofkit.requirement-context schemaVersion=2 with strict v1 adapter", "workspace mode: diffInput=proofkit.requirement-semantic-diff-input schemaVersion=2 (optional)", "workspace mode: graphInput=proofkit.requirement-traceability-graph-input schemaVersion=2 (optional)", "--session-mode values: browse|one-shot-question", "one-shot-question requires --view workspace --serve --open", "--session-timeout-seconds is 1..7200 and requires one-shot-question", "source|proof|coverage|spec-tree modes retain their owner input contracts", "root-shape-only definition proofkit.requirement-browser-server.input.v3.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:40a4ac0312d4fb921d572817331a73c629ed807caed789296f992f1482e0d932", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-browser-server"}}, "requirement-context-compose": {InputContractSHA256: "sha256:0b8d5eace6247fd8fa01ad7372f0395ea6fa10e7f0aa9fe5bab2ff4ed8a69384", InputSchemaSummary: []string{"schemaVersion=1", "catalogId", "specTree.path", "requirementSources[] (non-empty)", "requirementSources[].nodeId", "requirementSources[].path", "expectedSourceDigest (optional sha256 ref)", "proofBinding.path (optional)", "coverage.path (optional)", "exact catalog paths only; no discovery", "root-shape-only definition proofkit.requirement-context-compose.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:dd08c6e3e66349019a349049345e64fca3d31459e42fe634e98e9a9ade8101f4", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-context-compose"}}, "requirement-context-slice": {InputContractSHA256: "sha256:a97c99d2c36bdf90aa6f3f55adf3afff7d3576093ae3ed79bbde5aaccaf1249c", InputSchemaSummary: []string{"schemaVersion=1", "sliceId", "context=proofkit.requirement-context schemaVersion=2 with strict v1 adapter, or schemaVersion=3 closed captured project origin", "Project-origin v3 replay validates the exact canonical project and role/source partition; it does not reread live files or reinterpret the existing v1/v2 identities.", "query.profile=routing|specification|proof|coverage|review", "query.nodeIds[]|requirementIds[]|ownerIds[]|lifecycleStates[]", "query.maxDepth=0..512", "query.maxNodes=1..4096", "query.maxRequirements=1..16384", "root-shape-only definition proofkit.requirement-context-slice.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:f9dfb92adc6548f7e8171ad0e7261cf5d7ce3112f6ecd989acc8d1fb9ff5dd31", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-context-slice"}}, - "requirement-coverage-input-compose": {InputContractSHA256: "sha256:1980d1fc5c3c3cfe08f557e3c55f7128de5bae0d9b25bd2a46d7c6e47db73faa", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.requirement-coverage-input-compose.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:3a8686e91f3a229b273531d9c03cb6ce86ec76b66f8c35c6ca7f361b6e5eeaff", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-coverage-input-compose"}}, + "requirement-coverage-input-compose": {InputContractSHA256: "sha256:3b4fd5dd444259db4de81c4a0b5800e8106e6ce61fa91fb00419ce56c4f493fa", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.requirement-coverage-input-compose.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:bfc779b40b581207000080149d0876c1f90cf41080a83039af09ac71ced18682", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-coverage-input-compose"}}, "requirement-coverage-view": {InputContractSHA256: "sha256:202dfbf2b9929a9244ba067a6a57af361e8f7da245625d3d53f13d73e04f14e3", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.requirement-coverage-view.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:b5784b98b903ef9bf9ddbac047592c32baeda96a83c3e426dee51d64d3846269", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-coverage-view"}}, "requirement-impact-input-compose": {InputContractSHA256: "sha256:c80c57489205004f92603fec541ce3d36dd0d9b65109dcfefb97bcfb07b90679", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.requirement-impact-input-compose.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:b0b689f4d0b5bafc52c6041a2aa3583c9c8628aa0f13a0f0d7c42a610ed1a0d6", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-impact-input-compose"}}, "requirement-proof-resolver": {InputContractSHA256: "sha256:7ffedf651fbeda57f11f780373ae8f2b15dd587ce3aaddf739a092bc4835f2c5", InputSchemaSummary: []string{"schemaVersion=2", "root-shape-only definition proofkit.requirement-proof-resolver.input.v2.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:d6b1fbbf4a7fe3624c64f88c8e316fd927df8f35355198962110dab41113bc94", FlagChoices: map[string][]string{}, RouteTokens: []string{"requirement-proof-resolver"}}, @@ -89,7 +89,7 @@ var generatedCommandContractMetadataByName = map[string]generatedCommandContract "selective-gate-evidence": {InputContractSHA256: "sha256:8aa178ab7ca7c475c23707bc4e15fd3f9f8d57acf6f6dcf279677e7769a45586", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.selective-gate-evidence.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:723569262bb85d9674b2a78d3bcb6e9f4cab229b71e8c784ff1b804a7fcade71", FlagChoices: map[string][]string{}, RouteTokens: []string{"selective-gate-evidence"}}, "selective-gate-obligation-decision-input": {InputContractSHA256: "sha256:85761fcbc0ea94239d55bf379d0592a6ca814e6612a2d609a651f6cdaf8ca10a", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.selective-gate-obligation-decision-input.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:ab9dddabe975238d7019266c43350afa2df1a61d4c2eb7bc23afd520b588a2da", FlagChoices: map[string][]string{}, RouteTokens: []string{"selective-gate-obligation-decision-input"}}, "selective-gate-plan": {InputContractSHA256: "sha256:5293a5a4c7d8426cf637e6f8d252095ca0eb1714365bb89bec83307b778c678a", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.selective-gate-plan.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:d7bffed853af5595af08b03859be01c283a3bdff1b3502d94ddc190889977647", FlagChoices: map[string][]string{}, RouteTokens: []string{"selective-gate-plan"}}, - "self-check": {InputContractSHA256: "sha256:f91bf07b924dfce56c5d742783ad28e77af65a9a2ab0609d9fbf9cf298fa758d", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.self-check.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:22499f6cadfec5abf5d5ae706ddf503ec129902d8cffe2b0cf862af98b17ff86", FlagChoices: map[string][]string{}, RouteTokens: []string{"self-check"}}, + "self-check": {InputContractSHA256: "sha256:092ea3fb5c79214b1ed8e8573b59f90bd736fa62797a19f55da92fdaaa519eb6", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.self-check.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:455db6d1517cd174d84534473375c2f45e8b4ce4dcd78db89da46a5bd215cea8", FlagChoices: map[string][]string{}, RouteTokens: []string{"self-check"}}, "spec-overview-claims": {InputContractSHA256: "sha256:2490dcd34ba7485e13f8f33e8a288a0463c4c52cc6b0d82c57777466927e49a4", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.spec-overview-claims.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:554f3a7020e9820ccb90672629fd769c52b2f298f356040aa3b0a817666cbfbf", FlagChoices: map[string][]string{}, RouteTokens: []string{"spec-overview-claims"}}, "spec-proof-bundle-admission": {InputContractSHA256: "sha256:2dd04eb5ad2bd26758b434c2f427347efd491dab5a50b1197c8a9f98113be1b5", InputSchemaSummary: []string{"schemaVersion=1", "root-shape-only definition proofkit.spec-proof-bundle-admission.input.v1.root-shape; nested fields, types, and cardinalities are non-claims"}, OutputContractSHA256: "sha256:a6ac0c69d19caf97e9a8c95808b83cdb3f908720923739aa59ef646d27c90870", FlagChoices: map[string][]string{}, RouteTokens: []string{"spec-proof-bundle-admission"}}, "stack-preset": {InputContractSHA256: "", InputSchemaSummary: []string(nil), OutputContractSHA256: "sha256:ef5920f363a4a96dcac308ea8412260a06e64ba4876460a369aefb8983130a9d", FlagChoices: map[string][]string{"--preset": []string{"agentic_runtime_repo", "generated_docs_contract_repo", "python_service", "python_typescript_service", "typescript_monorepo", "typescript_workspace"}}, RouteTokens: []string{"stack-preset"}}, diff --git a/internal/app/command_help.go b/internal/app/command_help.go index 29051e71..72265230 100644 --- a/internal/app/command_help.go +++ b/internal/app/command_help.go @@ -9,7 +9,9 @@ import ( "github.com/research-engineering/agentic-proofkit/internal/command/capabilitymapadmission" "github.com/research-engineering/agentic-proofkit/internal/command/nativeevidenceguidance" "github.com/research-engineering/agentic-proofkit/internal/command/proofreceiptadmission" + "github.com/research-engineering/agentic-proofkit/internal/command/receiptcurrentnessscope" "github.com/research-engineering/agentic-proofkit/internal/command/requirementauthoringplan" + "github.com/research-engineering/agentic-proofkit/internal/command/requirementcoverageinput" "github.com/research-engineering/agentic-proofkit/internal/command/specproofbundleadmission" "github.com/research-engineering/agentic-proofkit/internal/kernel/cliexec" ) @@ -130,6 +132,12 @@ func commandUsageWithRenderer(descriptor commandDescriptor, renderer cliexec.Ren if descriptor.name == "native-evidence-guidance" { lines = append(lines, "", strings.TrimSuffix(nativeevidenceguidance.TraceabilityGuide(renderer), "\n")) } + if descriptor.name == "requirement-coverage-input-compose" { + lines = append(lines, "", strings.TrimSuffix(requirementcoverageinput.InputGuide(renderer), "\n")) + } + if descriptor.name == "receipt-currentness-scope" { + lines = append(lines, "", strings.TrimSuffix(receiptcurrentnessscope.InputGuide(renderer), "\n")) + } if pointer := adoptionGuidePointer(descriptor.name); pointer != "" { lines = append(lines, "", "CLI authoring continuation:", " "+renderer.DisplayCommand("adopt", "materialize", "plan", "--help"), diff --git a/internal/app/currentness_input_guide_test.go b/internal/app/currentness_input_guide_test.go new file mode 100644 index 00000000..7b53b1ee --- /dev/null +++ b/internal/app/currentness_input_guide_test.go @@ -0,0 +1,165 @@ +package app + +import ( + "crypto/sha256" + "fmt" + "os" + "path/filepath" + "reflect" + "slices" + "testing" + + "github.com/research-engineering/agentic-proofkit/internal/kernel/cliexec" +) + +// This is the fixture consumer's mapping policy, not a public receipt adapter. +func checkCurrentnessGuideReceiptHandoff(t *testing.T, receipts, binding map[string]any, root string) { + t.Helper() + input, help := receiptHelpTemplate(t, "receipt-currentness-scope") + args := fillGuideOperands(t, guideCommands(t, help, "Receipt currentness input guide:", cliexec.PathRenderer())[0], map[string]string{"": "-"}) + r := receipt(receipts) + var bound map[string]any + for _, raw := range binding["bindings"].([]any) { + row := raw.(map[string]any) + if slices.Contains(row["commandIds"].([]any), r["receiptKind"]) && slices.Contains(r["witnessSelectors"].([]any), row["scenarioId"]) { + bound = row + break + } + } + if bound == nil { + t.Fatal("fixture has no qualified binding for the receipt") + } + var owner any + for _, raw := range binding["requirements"].([]any) { + row := raw.(map[string]any) + if row["requirementId"] == bound["requirementId"] { + owner = row["ownerId"] + } + } + input["admissionId"] = "example.currentness" + item := input["obligationReceipts"].([]any)[0].(map[string]any) + identity := map[string]any{ + "receiptId": r["receiptId"], "requirementId": bound["requirementId"], "proofRouteRef": r["receiptKind"], + "owner": owner, "obligationId": "example.obligation", + } + for key, value := range identity { + item[key] = value + } + item["reason"] = "Compare retained fixture subjects under explicit consumer policy." + item["evidenceRefs"] = r["evidenceRefs"] + checks := []any{} + recorded := map[string]any{} + fields := []string{"commandDigest", "environmentDigest", "preconditionDigest", "proofBindingDigest", "toolchainDigest", "witnessSelectorDigest"} + for index, field := range fields { + data, err := os.ReadFile(filepath.Join(root, field+".json")) + if err != nil { + t.Fatal(err) + } + actual := fmt.Sprintf("sha256:%x", sha256.Sum256(data)) + if actual != r[field] { + t.Fatal("retained bytes are not the receipt's recorded subject: " + field) + } + checks = append(checks, map[string]any{ + "checkId": fmt.Sprintf("example.check.%d", index), "checkClass": field, + "recordedDigest": r[field], "currentDigest": actual, + "evidenceRefs": []any{field + ".json"}, "nonClaims": []any{"Synthetic consumer capture is not authenticated."}, + }) + recorded[field] = r[field] + } + item["currentnessChecks"] = checks + scope := item["scopeChecks"].([]any)[0].(map[string]any) + for key, value := range map[string]any{ + "checkId": "example.scope", "scopeClass": "binding_scope", "admissionState": "admitted_current_scope", + "recordedScopeDigest": r["proofBindingDigest"], "currentScopeDigest": r["proofBindingDigest"], + "reason": "The fixture retains the same admitted binding scope.", "evidenceRefs": []any{"proofBindingDigest.json"}, + } { + scope[key] = value + } + if !currentnessGuideHandoffMatches(item, identity, recorded) { + t.Fatal("receipt-to-currentness handoff lost identity or recorded operands") + } + for _, mutation := range []string{"receipt", "recorded"} { + wrong := cloneMap(t, item) + if mutation == "receipt" { + wrong["receiptId"] = "example.other-receipt" + } else { + wrong["currentnessChecks"].([]any)[0].(map[string]any)["recordedDigest"] = fmt.Sprintf("sha256:%x", sha256.Sum256([]byte("foreign recorded subject"))) + } + if currentnessGuideHandoffMatches(wrong, identity, recorded) { + t.Fatalf("consumer mapping accepted a substituted %s", mutation) + } + } + positive := currentnessGuideReport(t, args, input, 0) + assertGuideCount(t, positive, "currentReceiptCount", 1) + assertGuideCount(t, positive, "staleReceiptCount", 0) + for index, field := range fields { + data, err := os.ReadFile(filepath.Join(root, field+".json")) + if err != nil { + t.Fatal(err) + } + changed := cloneMap(t, input) + current := changed["obligationReceipts"].([]any)[0].(map[string]any)["currentnessChecks"].([]any)[index].(map[string]any) + subject := decodeCLIJSON(t, string(data)) + switch field { + case "commandDigest": + subject.(map[string]any)["cwd"] = root + "-changed" + case "environmentDigest": + subject.(map[string]any)["class"] = "ci-go" + case "preconditionDigest": + subject.(map[string]any)["syntheticPolicy"] = false + case "proofBindingDigest": + subject.(map[string]any)["bindingId"] = "example.changed-binding" + case "toolchainDigest", "witnessSelectorDigest": + subject.([]any)[0] = "example.changed" + } + current["currentDigest"] = fmt.Sprintf("sha256:%x", sha256.Sum256(adoptionHelpJSON(t, subject))) + result := currentnessGuideReport(t, args, changed, 1) + assertGuideCount(t, result, "staleReceiptCount", 1) + assertGuideCount(t, result, "scopeFindingCount", 0) + } + for _, state := range []string{"not_admitted_current_scope", "unknown_current_scope", "not_applicable", "scope_digest"} { + changed := cloneMap(t, input) + changedScope := changed["obligationReceipts"].([]any)[0].(map[string]any)["scopeChecks"].([]any)[0].(map[string]any) + wantCode := 1 + if state == "scope_digest" { + changedScope["currentScopeDigest"] = fmt.Sprintf("sha256:%x", sha256.Sum256([]byte("independent changed scope"))) + } else { + changedScope["admissionState"] = state + } + if state == "not_applicable" { + wantCode = 0 + } + result := currentnessGuideReport(t, args, changed, wantCode) + assertGuideCount(t, result, "staleReceiptCount", 0) + if state == "not_applicable" { + assertGuideCount(t, result, "notApplicableCount", 1) + if result["ruleResults"].([]any)[0].(map[string]any)["status"] != "skipped" { + t.Fatal("inapplicability became a passing rule") + } + } else { + assertGuideCount(t, result, "unknownScopeCount", 1) + assertGuideCount(t, result, "scopeFindingCount", 1) + } + } + if restored := currentnessGuideReport(t, args, input, 0); !reflect.DeepEqual(positive, restored) { + t.Fatal("restored subjects did not recover the positive result") + } +} + +func currentnessGuideHandoffMatches(item, identity, recorded map[string]any) bool { + for key, value := range identity { + if !reflect.DeepEqual(item[key], value) { + return false + } + } + actual := map[string]any{} + for _, raw := range item["currentnessChecks"].([]any) { + check := raw.(map[string]any) + class := check["checkClass"].(string) + if _, exists := actual[class]; exists { + return false + } + actual[class] = check["recordedDigest"] + } + return reflect.DeepEqual(actual, recorded) +} diff --git a/internal/app/evidence_completion_guide_test.go b/internal/app/evidence_completion_guide_test.go new file mode 100644 index 00000000..7abb4573 --- /dev/null +++ b/internal/app/evidence_completion_guide_test.go @@ -0,0 +1,181 @@ +package app + +import ( + "bytes" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/research-engineering/agentic-proofkit/internal/kernel/cliexec" +) + +func TestEvidenceCompletionGuidesAreLazyAndCarrierBound(t *testing.T) { + for _, item := range []struct { + command, marker string + commands [][]string + }{ + {"requirement-coverage-input-compose", "Declaration coverage input guide:", [][]string{ + {"requirement-coverage-input-compose", "--input", ""}, + {"requirement-coverage-view", "--input", "", "--format", "json"}, + }}, + {"receipt-currentness-scope", "Receipt currentness input guide:", [][]string{ + {"receipt-currentness-scope", "--input", ""}, + }}, + } { + t.Run(item.command, func(t *testing.T) { + packet, _ := receiptHelpTemplate(t, item.command) + code, output, diagnostic := executeAgentWorkflowCLI(t, []string{item.command, "--input", "-"}, bytes.NewReader(adoptionHelpJSON(t, packet)), PresentationCapabilities{}) + if code != 1 || output != "" || diagnostic == "" { + t.Fatal("unfilled template must not invent admissible evidence") + } + for _, carrier := range []struct{ profile, python string }{ + {cliexec.ProfilePath, ""}, {cliexec.ProfileNPMOffline, ""}, {cliexec.ProfilePythonModule, "/example/python 3"}, + } { + renderer, err := cliexec.AdmitLauncherProfile(carrier.profile, carrier.python) + if err != nil { + t.Fatal(err) + } + descriptor, _ := commandDescriptorFor(item.command) + if got := guideCommands(t, commandUsageWithRenderer(descriptor, renderer), item.marker, renderer); !reflect.DeepEqual(got, item.commands) { + t.Fatalf("guide argv differs: %v", got) + } + } + for _, args := range [][]string{{"help"}, {"help", "families"}, {"native-evidence-guidance"}, {"native-evidence-guidance", "--help"}, {"changed-path-set", "--help"}} { + _, output, _ := executeAgentWorkflowCLI(t, args, panicReader{}, PresentationCapabilities{}) + if strings.Contains(output, item.marker) { + t.Fatalf("nested recipe must stay lazy: %v", args) + } + } + }) + } +} + +func TestCoverageGuideComposesActualInputsAndRetainsGaps(t *testing.T) { + input, help := receiptHelpTemplate(t, "requirement-coverage-input-compose") + materialization := adoptionHelpPacket(t, t.TempDir(), "fresh") + input["composerInputId"], input["viewInputId"] = "example.compose", "example.view" + input["selectedOwnerIds"] = []any{"example.backend"} + input["requirementSource"] = materialization["requirementSources"].([]any)[0] + input["requirementProofBinding"] = materialization["requirementProofBinding"].(map[string]any)["record"] + input["testEvidenceInventory"] = materialization["testEvidenceInventory"].(map[string]any)["record"] + universe := input["coverageUniverse"].(map[string]any) + universe["universeId"], universe["completenessDeclaration"] = "example.universe", "selected_owner_surfaces" + universe["ownerIds"] = []any{"example.backend"} + universe["commandRefs"] = []any{"example.test.requests"} + universe["codeSurfaces"] = []any{map[string]any{"surfaceId": "example.code", "ownerId": "example.backend", "path": "src"}} + universe["specSurfaces"] = []any{map[string]any{"surfaceId": "example.spec", "ownerId": "example.backend", "path": "docs/specs/requests/requirements.v1.json"}} + universe["testSurfaces"] = []any{map[string]any{"surfaceId": "example.test", "ownerId": "example.backend", "path": "src/request_test.go"}} + commands := guideCommands(t, help, "Declaration coverage input guide:", cliexec.PathRenderer()) + composeArgs := fillGuideOperands(t, commands[0], map[string]string{"": "-"}) + viewArgs := fillGuideOperands(t, commands[1], map[string]string{"": "-"}) + for _, variant := range []string{"complete", "missing", "unmapped", "restored"} { + t.Run(variant, func(t *testing.T) { + candidate := decodeCLIJSON(t, string(adoptionHelpJSON(t, input))).(map[string]any) + inventory := candidate["testEvidenceInventory"].(map[string]any) + if variant == "missing" { + inventory["entries"] = []any{} + } + if variant == "unmapped" { + inventory["entries"] = append(inventory["entries"].([]any), map[string]any{ + "testId": "example.test.unmapped", "ownerId": "example.backend", "sourcePath": "src/unmapped_test.go", + "selector": "src/unmapped_test.go::TestUnmapped", "evidenceClass": "helper_or_testkit", + "requirementRefs": []any{}, "ownerInvariantRefs": []any{}, "commandRefs": []any{}, "witnessRefs": []any{}, + "falsifier": nil, "oracle": nil, "nonClaims": []any{"Unmapped fixture is not a declared semantic test."}, + }) + } + code, wire, diagnostic := executeAgentWorkflowCLI(t, composeArgs, bytes.NewReader(adoptionHelpJSON(t, candidate)), PresentationCapabilities{}) + if code != 0 || diagnostic != "" { + t.Fatalf("compose failed before downstream: %d %s", code, diagnostic) + } + composed := decodeCLIJSON(t, wire).(map[string]any) + if !equalCLIJSON(t, composed["requirementSource"], candidate["requirementSource"]) { + t.Fatal("composer lost source operands") + } + binding := composed["requirementProofBinding"].(map[string]any)["bindings"].([]any)[0].(map[string]any) + for field, want := range map[string]any{ + "requirementId": "REQ-EXAMPLE-001", "scenarioId": "example.requests.empty", "witnessId": "example.witness.empty", + "witnessPath": "src/request_test.go", "commandIds": []any{"example.test.requests"}, "environmentClasses": []any{"local-go"}, + } { + if !reflect.DeepEqual(binding[field], want) { + t.Fatalf("composer changed qualified %s: %v", field, binding[field]) + } + } + composedUniverse := composed["coverageUniverse"].(map[string]any) + for _, field := range []string{"ownerIds", "codeSurfaces", "specSurfaces", "commandRefs", "completenessDeclaration", "nonClaims"} { + if !reflect.DeepEqual(composedUniverse[field], universe[field]) { + t.Fatalf("composer changed declared universe %s", field) + } + } + // Consume the actual wire bytes, not a manually rebuilt view input. + code, output, diagnostic := executeAgentWorkflowCLI(t, viewArgs, strings.NewReader(wire), PresentationCapabilities{}) + if diagnostic != "" { + t.Fatalf("view input did not round trip: %s", diagnostic) + } + view := decodeCLIJSON(t, output).(map[string]any) + wantCode, wantState := 0, "passed" + if variant == "missing" { + wantCode, wantState = 1, "failed" + } + if code != wantCode || view["state"] != wantState || view["authority"] != "lookup_only" || view["viewKind"] != "proofkit.requirement-coverage-view" { + t.Fatalf("view outcome differs: %d %v", code, view) + } + row := view["requirementCoverage"].([]any)[0].(map[string]any) + wantIDs := []any{"example.test.empty"} + if variant == "missing" { + wantIDs = []any{} + } + if row["requirementId"] != "REQ-EXAMPLE-001" || row["ownerId"] != "example.backend" || row["specPath"] != "docs/specs/requests/requirements.v1.json" || !reflect.DeepEqual(row["testIds"], wantIDs) { + t.Fatalf("view changed identity or test linkage: %v", row) + } + if variant == "missing" && !reflect.DeepEqual(view["deadZones"], []any{map[string]any{ + "deadZoneKind": "unbound_test_surface", "ownerId": "example.backend", "path": "src/request_test.go", "surfaceId": "example.test", + }}) { + t.Fatalf("missing test lost its declared coordinates: %v", view["deadZones"]) + } + unmapped := view["unmappedTests"].([]any) + if variant == "unmapped" { + if len(unmapped) != 1 || unmapped[0].(map[string]any)["testId"] != "example.test.unmapped" { + t.Fatalf("unmapped test disappeared: %v", unmapped) + } + } else if len(unmapped) != 0 { + t.Fatalf("unexpected unmapped tests: %v", unmapped) + } + }) + } + for _, field := range []string{"compactProofContract", "normalizedTestEvidenceInventory"} { + candidate := cloneMap(t, input) + candidate[field] = nil + code, output, diagnostic := executeAgentWorkflowCLI(t, composeArgs, bytes.NewReader(adoptionHelpJSON(t, candidate)), PresentationCapabilities{}) + if code != 1 || output != "" || diagnostic == "" { + t.Fatal("direct-mode foreign key must be absent, not null: " + field) + } + } +} + +func currentnessGuideReport(t *testing.T, args []string, input map[string]any, wantCode int) map[string]any { + t.Helper() + code, output, diagnostic := executeAgentWorkflowCLI(t, args, bytes.NewReader(adoptionHelpJSON(t, input)), PresentationCapabilities{}) + if code != wantCode || diagnostic != "" { + t.Fatalf("currentness result differs: %d %q", code, diagnostic) + } + result := decodeCLIJSON(t, output).(map[string]any) + if result["reportKind"] != "proofkit.receipt-currentness-scope-admission" || result["reportId"] != "example.currentness" { + t.Fatalf("currentness report identity differs: %v", result) + } + wantState := "passed" + if wantCode != 0 { + wantState = "failed" + } + if result["state"] != wantState { + t.Fatalf("currentness state differs: %v", result["state"]) + } + return result +} + +func assertGuideCount(t *testing.T, result map[string]any, field string, want int) { + t.Helper() + if got := fmt.Sprint(result["summary"].(map[string]any)[field]); got != fmt.Sprint(want) { + t.Fatalf("%s=%s, want %d", field, got, want) + } +} diff --git a/internal/app/receipt_input_guide_test.go b/internal/app/receipt_input_guide_test.go index 955f05f4..9de4feb8 100644 --- a/internal/app/receipt_input_guide_test.go +++ b/internal/app/receipt_input_guide_test.go @@ -90,12 +90,21 @@ func TestReceiptInputGuideNativeHelper(t *testing.T) { return } switch os.Args[len(os.Args)-1] { - case "passed": + case "passed", "failed": + accept := func(request string) bool { return request != "" } + if os.Args[len(os.Args)-1] == "failed" { + accept = func(string) bool { return true } + } + if !accept("valid") { + fmt.Fprintln(os.Stderr, "nonempty control rejected") + os.Exit(2) + } + if accept("") { + fmt.Print("empty input accepted\n") + os.Exit(1) + } fmt.Print("empty input rejected\n") os.Exit(0) - case "failed": - fmt.Print("empty input accepted\n") - os.Exit(1) default: os.Exit(2) } @@ -226,6 +235,7 @@ func TestReceiptInputGuideExecutionAndBundleChain(t *testing.T) { if !bytes.Equal(payload, adoptionHelpJSON(t, packet)) { t.Fatal("composition modified the source receipt") } + checkCurrentnessGuideReceiptHandoff(t, packet, binding, root) checkReceiptGuideMutations(t, packet, bundle) }) } @@ -315,7 +325,7 @@ func TestNativeTraceabilityGuideIsLazyAndCarrierBound(t *testing.T) { actualLazy = append(actualLazy, line) } } - for _, command := range [][]string{{"adopt", "materialize", "plan", "--help"}, {"requirement-authoring-plan", "--help"}, {"proof-receipt-admission", "--help"}, {"spec-proof-bundle-admission", "--help"}, {"requirement-impact-input-compose", "--help"}} { + for _, command := range [][]string{{"adopt", "materialize", "plan", "--help"}, {"requirement-authoring-plan", "--help"}, {"requirement-coverage-input-compose", "--help"}, {"proof-receipt-admission", "--help"}, {"spec-proof-bundle-admission", "--help"}, {"receipt-currentness-scope", "--help"}, {"requirement-impact-input-compose", "--help"}} { expectedLazy = append(expectedLazy, " "+renderer.DisplayCommand(command...)) code, output, diagnostic := executeAgentWorkflowCLI(t, command, panicReader{}, PresentationCapabilities{}) if code != 0 || output == "" || diagnostic != "" { diff --git a/internal/command/nativeevidenceguidance/guidance.go b/internal/command/nativeevidenceguidance/guidance.go index 173c6991..279fb22e 100644 --- a/internal/command/nativeevidenceguidance/guidance.go +++ b/internal/command/nativeevidenceguidance/guidance.go @@ -77,6 +77,8 @@ Repository-specific adapter template (implement under consumer authority): Map requirementRefs, witnessRefs and commandRefs from the same matched rows; preserve unbound rows for review. Admission of separate ID sets is not proof of a valid qualified edge. Use currentness and native execution separately. + Inspect declaration coverage with the connected direct-input recipe: + {{cli}} requirement-coverage-input-compose --help 5. Run an independent positive control and a behavior-breaking near miss using approved argv, root, environment and bounds from the evidence-guidance slots. Also remove a discovered test, add an unmapped test, and replay evidence @@ -87,6 +89,7 @@ Repository-specific adapter template (implement under consumer authority): structurally valid failed/not-run receipt into a successful native result: {{cli}} proof-receipt-admission --help {{cli}} spec-proof-bundle-admission --help + {{cli}} receipt-currentness-scope --help Declaration coverage, actual execution, currentness, producer trust and merge approval are separate predicates. No step here grants those powers. 7. For a changed requirement, test, binding, command or environment, retain diff --git a/internal/command/receiptcurrentnessscope/input_guide.go b/internal/command/receiptcurrentnessscope/input_guide.go new file mode 100644 index 00000000..0cfac53e --- /dev/null +++ b/internal/command/receiptcurrentnessscope/input_guide.go @@ -0,0 +1,94 @@ +package receiptcurrentnessscope + +import ( + "strings" + + "github.com/research-engineering/agentic-proofkit/internal/kernel/cliexec" +) + +// InputGuide explains caller-owned capture without claiming file discovery. +func InputGuide(renderer cliexec.Renderer) string { + return strings.ReplaceAll(inputGuide, "{{cli}}", renderer.DisplayCommand()) +} + +const inputGuide = `Receipt currentness input guide: + Currentness compares caller-supplied identities. It does not read files, + compute receipt age, authenticate a producer, execute tests or approve merge. + First retain the original receipt input and the exact subjects it recorded: + {{cli}} proof-receipt-admission --help + Do not substitute that admission report for the receipt. Preserve receiptId; + select requirementId and proofRouteRef from its admitted binding route, and + obligationId/owner from the consumer's obligation policy. Check the qualified + relation, not separate sets of IDs. This command cannot verify that mapping + against an external receipt or detect deliberately invented equal digests. + + For every dependency relevant to reuse, supply a uniquely identified + currentnessChecks entry. Copy recordedDigest from the corresponding receipt + subject (binding, command, environment, precondition, selectors, toolchain, + or applicable dependency/lockfile). Independently capture current bytes with + the same encoding/version; calculate currentDigest from those actual bytes. + Never copy the old digest into both fields to obtain a pass. If a required + subject is unavailable, stop: this template cannot establish its currentness. + Keep sanitized source bytes/encoding and evidenceRefs for independent replay. + Do not claim whole-repository freshness from an incomplete dependency list. + + Every obligation needs nonempty currentnessChecks and scopeChecks. Check and + obligation IDs must be unique; checkClass/scopeClass name consumer-owned rules. + Choose scope admission from evidence: admitted_current_scope, + not_admitted_current_scope, unknown_current_scope, or not_applicable. + Include both recordedScopeDigest and currentScopeDigest keys. Admission allows + null values, but null does not prove equal scope. This reuse recipe requires + both observed digests for an equal-scope claim; otherwise use unknown scope + or a separately justified consumer policy. Digests are sha256:<64 lowercase + hex digits>. Paths are repository-relative; sort unique evidenceRefs and + nonClaims. Every evidenceRefs and nonClaims array must be nonempty; fill it + from retained evidence and actual limitations. Never include secrets. + +Currentness template (required null operands deliberately reject admission): +` + "```json\n" + `{ + "schemaVersion": 1, + "admissionId": null, + "obligationReceipts": [{ + "obligationId": null, + "requirementId": null, + "proofRouteRef": null, + "receiptId": null, + "owner": null, + "reason": null, + "currentnessChecks": [{ + "checkId": null, + "checkClass": null, + "recordedDigest": null, + "currentDigest": null, + "evidenceRefs": null, + "nonClaims": ["Consumer declarations require independent evidence."] + }], + "scopeChecks": [{ + "checkId": null, + "scopeClass": null, + "admissionState": null, + "recordedScopeDigest": null, + "currentScopeDigest": null, + "reason": null, + "evidenceRefs": null, + "nonClaims": ["Consumer declarations require independent evidence."] + }], + "evidenceRefs": null, + "nonClaims": ["Current subjects and scope are supplied by the consumer."] + }], + "nonClaims": ["Currentness is not producer authentication or merge approval."] +} +` + "```\n" + ` + Replace with the completed packet path, or - for stdin: + {{cli}} receipt-currentness-scope --input + Preserve stdout, stderr and exit independently. Malformed input exits1 with + a diagnostic; stale or unknown/not-admitted scope exits1 with a failed JSON + report. Inspect receiptCurrentnessScope diagnostics and ruleResults: digest + mismatch yields stale_receipt; scope mismatch yields unknown_scope. + An all-not_applicable scope can exit0 with skipped ruleResults: this is not + current execution evidence. Even current inputs may describe a failed or + not-run receipt; retain the original receipt status and separate trust policy. + Restore recorded subjects to test recovery, or run fresh approved checks for + intentionally changed subjects. Never replace historical evidence with + fabricated success or treat this comparison as automatic filesystem capture. +` diff --git a/internal/command/requirementcoverageinput/input_guide.go b/internal/command/requirementcoverageinput/input_guide.go new file mode 100644 index 00000000..2d0e1bdc --- /dev/null +++ b/internal/command/requirementcoverageinput/input_guide.go @@ -0,0 +1,84 @@ +package requirementcoverageinput + +import ( + "strings" + + "github.com/research-engineering/agentic-proofkit/internal/kernel/cliexec" +) + +// InputGuide owns the direct-mode recipe, not the child schemas or test policy. +func InputGuide(renderer cliexec.Renderer) string { + return strings.ReplaceAll(inputGuide, "{{cli}}", renderer.DisplayCommand()) +} + +const inputGuide = `Declaration coverage input guide: + This recipe uses direct inputs, not compact proof contracts or source sets. + Obtain connected source, binding and inventory shapes without writing files: + {{cli}} adopt materialize plan --help + Copy whole input records from that packet, not their admission reports: + requirementSource <- /requirementSources/0 + requirementProofBinding <- /requirementProofBinding/record + testEvidenceInventory <- /testEvidenceInventory/record + Its sourcePlan may stay null for this read-only operation. The inventory must + use caller_owned_inventory. Do not include compactProofContract or + normalizedTestEvidenceInventory, even as null, in this direct-mode input. + + Fill required nulls from reviewed records and actual native discovery. + selectedOwnerIds must equal coverageUniverse.ownerIds; every inventory entry + must belong to those owners. Choose full_repository only with a complete + repository inventory; selected_owner_surfaces makes declared gaps failures; + selected_paths_advisory keeps dead-zone findings advisory, not completeness. + Do not narrow scope just to hide an absent test. The CLI does not scan files. + Give each surface a stable surfaceId, ownerId and repository-relative path. + Include the required test surfaces independently of discovered entries so a + missing test remains visible. Include expected command IDs in commandRefs. + The composer adds inventory paths/commands; omission is not proof of absence. + Sort unique owner/command IDs and nonClaims; preserve source/binding identity. + For another source repeat this operation with its exact matching inputs. + +Coverage template (required null operands deliberately reject admission): +` + "```json\n" + `{ + "schemaVersion": 2, + "composerInputId": null, + "viewInputId": null, + "selectedOwnerIds": null, + "requirementSource": null, + "requirementProofBinding": null, + "testEvidenceInventory": null, + "coverageUniverse": { + "schemaVersion": 1, + "universeId": null, + "authority": "caller_owned_inventory", + "completenessDeclaration": null, + "ownerIds": null, + "codeSurfaces": [], + "specSurfaces": [], + "testSurfaces": [], + "commandRefs": [], + "nonClaims": ["Declared scope does not prove discovery or test execution."] + }, + "ownerInvariantRegistry": null, + "localEnvironmentPolicy": null, + "options": null +} +` + "```\n" + ` + Empty surface arrays are placeholders, not a claim that no surfaces exist. + A surface is {"surfaceId":"","ownerId":"","path":""}. + ownerInvariantRegistry may stay null when no ownerInvariantRefs are used. + localEnvironmentPolicy may stay null in direct mode; when supplied it is + {"authority":"caller_provided","localEnvironmentClasses":[""]}. + options may stay null. Never insert secrets into paths, records or diagnostics. + + Store the completed input at . Capture the first command's + stdout bytes as only after exit0, preserving stderr separately: + {{cli}} requirement-coverage-input-compose --input + {{cli}} requirement-coverage-view --input --format json + Do not pass the compose request to the view or rebuild its output by hand. + Composer exit0 proves downstream input admission, not coverage success. + The view may exit1 with JSON state failed; retain failures, warnings, + unmappedTests and deadZones. An unmapped test can be reported without causing + exit1: the consumer decides whether it blocks. A declared route is not a + proved assertion or executed test. Do not relabel these observations as pass. + Native execution and receipt/currentness/trust admission are separate: + {{cli}} native-evidence-guidance --help +` diff --git a/internal/command/stackpreset/preset_ids_generated.go b/internal/command/stackpreset/preset_ids_generated.go index bcff4727..b2f19a99 100644 --- a/internal/command/stackpreset/preset_ids_generated.go +++ b/internal/command/stackpreset/preset_ids_generated.go @@ -1,6 +1,6 @@ // Code generated by internal/tools/commandcontractgen; DO NOT EDIT. package stackpreset -const presetContractSourceSHA256 = "18144447341a97e4d498f99839fb45b252fedd1e98429e6f16c3a0f5b7a6ba94" +const presetContractSourceSHA256 = "40e21bb074eea37dba970d08cf06e1c5ee0ec1c1d7404fad1e7e28490a3924c4" var presetIDs = []string{"agentic_runtime_repo", "generated_docs_contract_repo", "python_service", "python_typescript_service", "typescript_monorepo", "typescript_workspace"} diff --git a/internal/tools/releasechange/record_test.go b/internal/tools/releasechange/record_test.go index 2ec00b9a..f11f352e 100644 --- a/internal/tools/releasechange/record_test.go +++ b/internal/tools/releasechange/record_test.go @@ -197,7 +197,7 @@ func TestCurrentChangeRecordNamesReviewedSemanticChanges(t *testing.T) { var currentBreakingChanges = []Change{} var currentAdditions = []Change{ - {ChangeID: "proofkit.readme.workflow-clarity", Summary: "Simplify the README overview while preserving repository-owned specification, execution and approval boundaries. Link to the existing connected materialization help, clarify declaration-only browsing and align the first input explanation with requirement-source admission. Protected runnable examples, runtime behavior, dependencies, supported platforms and public CLI contracts are unchanged."}, + {ChangeID: "proofkit.guidance.coverage-currentness", Summary: "Connect lazy CLI input recipes for declaration coverage and receipt currentness to the native traceability cookbook. Preserve composer-to-view handoff, original receipt subjects, scope decisions and separate execution, currentness and trust predicates. Add causal recipe tests and refresh source-checkout provenance digests without changing runtime admission, ordinary guidance outputs, machine schema semantics, dependencies or supported platforms."}, } var currentMigrationSteps = []string{} @@ -220,7 +220,7 @@ func validateCurrentChangeRecord(record Record, notes string) error { func currentExpectedReleaseNotes() string { lines := []string{ - "# @research-engineering/agentic-proofkit 0.14.16", + "# @research-engineering/agentic-proofkit 0.14.17", "", "## Breaking Contract Changes", "", @@ -273,7 +273,7 @@ func currentExpectedReleaseNotes() string { "Primary npm channel:", "", "```bash", - "npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.16", + "npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.17", "```", "", "Pre-1.0 npm consumers must keep this dependency exact-pinned.", @@ -285,7 +285,7 @@ func currentExpectedReleaseNotes() string { "## Rollback", "", "- First follow the migration and persistent-state compatibility restrictions above; changing a package pin does not roll back repository state.", - "- Pin npm consumers to the previous admitted version 0.14.15 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.15`.", + "- Pin npm consumers to the previous admitted version 0.14.16 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.16`.", "- Treat local package artifacts as candidates until registry identity is proven.", ) return strings.Join(lines, "\n") + "\n" diff --git a/package-lock.json b/package-lock.json index e8f3a1d4..35b1b1a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@research-engineering/agentic-proofkit", - "version": "0.14.16", + "version": "0.14.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@research-engineering/agentic-proofkit", - "version": "0.14.16", + "version": "0.14.17", "cpu": [ "arm64", "x64" diff --git a/package.json b/package.json index 43f47cf5..97e02a1a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@research-engineering/agentic-proofkit", "description": "Reusable proof profile, report, graph, and witness-planning primitives.", - "version": "0.14.16", + "version": "0.14.17", "type": "module", "license": "MIT", "sideEffects": false, diff --git a/proofkit/cli-contract.v2.json b/proofkit/cli-contract.v2.json index 010841ec..edd2b330 100644 --- a/proofkit/cli-contract.v2.json +++ b/proofkit/cli-contract.v2.json @@ -143,7 +143,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -282,7 +282,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -396,7 +396,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -1187,7 +1187,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -2506,7 +2506,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -2612,7 +2612,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -2740,7 +2740,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -2867,7 +2867,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -2965,7 +2965,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -3281,7 +3281,7 @@ "rootDefinitionDigest": "sha256:218011a133540f57ef74f8748747e00d33b6757c9f77725ecef39f45fb19423f", "nativeSource": { "path": "internal/command/nativeevidenceguidance", - "canonicalDigest": "sha256:09c65c50c3b953691d3839400ba5739d386d7fab725fcd0aa3bbffce199ed9e2", + "canonicalDigest": "sha256:c94f5f4634ab6eb92f35da4069f294cea82999006faa8804afd7b173ae7cb19f", "evidenceClass": "source_checkout" }, "nativeOutputWitnessSelector": { @@ -3640,7 +3640,7 @@ "nativeSources": [ { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, { @@ -4035,7 +4035,7 @@ "rootDefinitionDigest": "sha256:912f60b637aa0ca917b1c90d4caa4e3e65ec60ad0c5529d0da9d815fc766c5f5", "nativeSource": { "path": "internal/command/receiptcurrentnessscope", - "canonicalDigest": "sha256:64fe8dfe45c5af89533bcc3bd7448977cf51b446df18eff11bf4dd3a8815c1d0", + "canonicalDigest": "sha256:2c66b3309cdd8d3ce6d0743c99ca2a526597bc85b87a5f47b9a629ddcc65654e", "evidenceClass": "source_checkout" }, "nativeAdmissionWitnessSelector": { @@ -4062,7 +4062,7 @@ "rootDefinitionDigest": "sha256:30a1b7ef616c1e44bbdbebc6e511231166a2d1ea600d8d5954484fe8c0e7cdf4", "nativeSource": { "path": "internal/command/receiptcurrentnessscope", - "canonicalDigest": "sha256:64fe8dfe45c5af89533bcc3bd7448977cf51b446df18eff11bf4dd3a8815c1d0", + "canonicalDigest": "sha256:2c66b3309cdd8d3ce6d0743c99ca2a526597bc85b87a5f47b9a629ddcc65654e", "evidenceClass": "source_checkout" }, "nativeOutputWitnessSelector": { @@ -5239,7 +5239,7 @@ "rootDefinitionDigest": "sha256:f6300d6d0f80f5066fe4079433978132ee2bb1df75e602e59cf3dc37a385d3ce", "nativeSource": { "path": "internal/command/requirementcoverageinput", - "canonicalDigest": "sha256:ca685e4dd96bcd3981443471bcb9ef6f2a74ca2d8c2f9926aba2662bf7876ab4", + "canonicalDigest": "sha256:e771d00233614e6a91fe27c35a84a23f7e26cb91dcb4d7b0f9b197489b4c6e66", "evidenceClass": "source_checkout" }, "nativeAdmissionWitnessSelector": { @@ -5287,7 +5287,7 @@ "rootDefinitionDigest": "sha256:0f264c996a058fb8aff102e42b95a4610d3a584b35687cc870b3d16c9589cfed", "nativeSource": { "path": "internal/command/requirementcoverageinput", - "canonicalDigest": "sha256:ca685e4dd96bcd3981443471bcb9ef6f2a74ca2d8c2f9926aba2662bf7876ab4", + "canonicalDigest": "sha256:e771d00233614e6a91fe27c35a84a23f7e26cb91dcb4d7b0f9b197489b4c6e66", "evidenceClass": "source_checkout" }, "nativeOutputWitnessSelector": { @@ -6935,7 +6935,7 @@ "rootDefinitionDigest": "sha256:3c842174dff5361e7f83166469b832805e05aa314b073c16234b5b64e346281e", "nativeSource": { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, "nativeAdmissionWitnessSelector": { @@ -6964,7 +6964,7 @@ "rootDefinitionDigest": "sha256:0ea95e277ebe44cd2de42c29b47c38686ac0b6b390d8965367437b3fe138e209", "nativeSource": { "path": "internal/app", - "canonicalDigest": "sha256:a1b281f736785bdc5b054f72c7f7467236e1b7226c691de8cec88ef83bc0cf5d", + "canonicalDigest": "sha256:c02f14fe65c88c21f7f6b867311d61def37378939dec88015abf9a085c4b93a7", "evidenceClass": "source_checkout" }, "nativeOutputWitnessSelector": { diff --git a/release/change-record.v2.json b/release/change-record.v2.json index d826d037..8659292a 100644 --- a/release/change-record.v2.json +++ b/release/change-record.v2.json @@ -1,13 +1,13 @@ { "schemaVersion": 2, - "previousVersion": "0.14.15", - "version": "0.14.16", + "previousVersion": "0.14.16", + "version": "0.14.17", "changeClass": "compatible", "breakingChanges": [], "additions": [ { - "changeId": "proofkit.readme.workflow-clarity", - "summary": "Simplify the README overview while preserving repository-owned specification, execution and approval boundaries. Link to the existing connected materialization help, clarify declaration-only browsing and align the first input explanation with requirement-source admission. Protected runnable examples, runtime behavior, dependencies, supported platforms and public CLI contracts are unchanged." + "changeId": "proofkit.guidance.coverage-currentness", + "summary": "Connect lazy CLI input recipes for declaration coverage and receipt currentness to the native traceability cookbook. Preserve composer-to-view handoff, original receipt subjects, scope decisions and separate execution, currentness and trust predicates. Add causal recipe tests and refresh source-checkout provenance digests without changing runtime admission, ordinary guidance outputs, machine schema semantics, dependencies or supported platforms." } ], "migration": {