Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions internal/app/adoption_input_guide_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestAdoptionInputGuideCLI(t *testing.T) {
if !reflect.DeepEqual(commands, expectedMaterializationGuideCommands()) {
t.Fatalf("published carrier command operands drifted: %v", commands)
}
for _, denial := range []string{"NOT an additive patch", "binding's specPath must equal its source's requirementsPath", "durability_unknown", "not an execution"} {
for _, denial := range []string{"NOT an additive patch", "binding's specPath must equal its source's requirementsPath", "durability_unknown", "not an execution", "Sort unique ID/path lists and every nonClaims list lexicographically.", "Do not sort argv; its token order is meaningful."} {
if !strings.Contains(guide, denial) {
t.Fatalf("guide lost required boundary: %s", denial)
}
Expand All @@ -96,6 +96,16 @@ func TestAdoptionInputGuideWholeChain(t *testing.T) {
t.Run(intent, func(t *testing.T) {
root := t.TempDir()
packet := adoptionHelpPacket(t, root, intent)
nonClaims := []any{"Candidate meaning requires owner review.", "Witness execution is not proven."}
packet["nonClaims"] = nonClaims
source := packet["requirementSources"].([]any)[0].(map[string]any)
source["nonClaims"] = nonClaims
adoptionHelpRequirement(packet)["nonClaims"] = nonClaims
binding := packet["requirementProofBinding"].(map[string]any)["record"].(map[string]any)
binding["nonClaims"] = nonClaims
binding["requirements"].([]any)[0].(map[string]any)["nonClaims"] = nonClaims
packet["testEvidenceInventory"].(map[string]any)["record"].(map[string]any)["nonClaims"] = nonClaims
adoptionHelpEntry(packet)["nonClaims"] = nonClaims
payload := adoptionHelpJSON(t, packet)
_, help, _ := executeAgentWorkflowCLI(t, []string{"adopt", "materialize", "plan", "--help"}, panicReader{}, PresentationCapabilities{})
commands := guideCommands(t, help, "Materialization input guide:", cliexec.PathRenderer())
Expand Down Expand Up @@ -137,8 +147,19 @@ func TestAdoptionInputGuideWholeChain(t *testing.T) {
if err != nil {
t.Fatal(err)
}
binding := decodeCLIJSON(t, string(bindingBytes)).(map[string]any)
route := binding["bindings"].([]any)[0].(map[string]any)
materializedBinding := decodeCLIJSON(t, string(bindingBytes)).(map[string]any)
if !reflect.DeepEqual(materializedBinding["requirements"].([]any)[0].(map[string]any)["nonClaims"], nonClaims) {
t.Fatal("materialization lost ordered requirement nonClaims")
}
inventoryBytes, err := os.ReadFile(filepath.Join(root, "proofkit/test-evidence-inventory.json"))
if err != nil {
t.Fatal(err)
}
materializedInventory := decodeCLIJSON(t, string(inventoryBytes)).(map[string]any)
if !reflect.DeepEqual(materializedInventory["entries"].([]any)[0].(map[string]any)["nonClaims"], nonClaims) {
t.Fatal("materialization lost ordered inventory entry nonClaims")
}
route := materializedBinding["bindings"].([]any)[0].(map[string]any)
if route["scenarioId"] != "example.requests.empty" || route["witnessId"] != "example.witness.empty" || route["requirementId"] != "REQ-EXAMPLE-001" {
t.Fatal("materialization lost the scenario/requirement/witness edge")
}
Expand All @@ -151,6 +172,38 @@ func TestAdoptionInputGuideWholeChain(t *testing.T) {
}
}

func TestAdoptionInputGuideNonClaimsOrdering(t *testing.T) {
for _, scope := range []string{"packet", "source", "requirement", "inventory", "entry"} {
for _, invalid := range []struct {
name string
values []any
}{
{"unsorted", []any{"Witness execution is not proven.", "Candidate meaning requires owner review."}},
{"duplicate", []any{"Witness execution is not proven.", "Witness execution is not proven."}},
} {
t.Run(scope+"/"+invalid.name, func(t *testing.T) {
root := t.TempDir()
packet := adoptionHelpPacket(t, root, "fresh")
owners := map[string]map[string]any{
"packet": packet,
"source": packet["requirementSources"].([]any)[0].(map[string]any),
"requirement": adoptionHelpRequirement(packet),
"inventory": packet["testEvidenceInventory"].(map[string]any)["record"].(map[string]any),
"entry": adoptionHelpEntry(packet),
}
owners[scope]["nonClaims"] = invalid.values
status, stdout, stderr := executeAgentWorkflowCLI(t, []string{"adopt", "materialize", "plan", "--input", "-", "--repo-root", root}, bytes.NewReader(adoptionHelpJSON(t, packet)), PresentationCapabilities{})
if status != 1 || stdout != "" || !strings.Contains(stderr, "nonClaims") || !strings.Contains(stderr, "sorted") || !strings.Contains(stderr, "unique") {
t.Fatalf("wrong rejection: status=%d stdout=%q stderr=%q", status, stdout, stderr)
}
if entries, err := os.ReadDir(root); err != nil || len(entries) != 0 {
t.Fatal("noncanonical nonClaims planning mutated the repository")
}
})
}
}
}

func TestAdoptionInputGuideRejectsBrokenEdges(t *testing.T) {
for _, mutation := range []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion internal/app/cli_contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

const (
cliContractPublicABISHA256 = "bf5359d40ce87aa1ad95ba0c8dec8a61413590e2051ca5b534ba8821a29963fc"
cliContractPublicABISHA256 = "4c40a20ac5333efddf7e9a4b36991ddf5b732fbd357a1538f60b887d6c73c447"
maxAggregateFileReadBytesForContractTest = 64 << 20
maxPackageManifestBytesForContractTest = 256 << 10
maxSourceFileBytesForContractTest = 8 << 20
Expand Down
8 changes: 4 additions & 4 deletions internal/app/command_contract_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions internal/command/adoptionmaterialization/input_guide.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ const inputGuide = `Materialization input guide:
requirementSources are requirement-source-admission inputs, not source reports.
Binding and inventory record fields are raw owner inputs, not passed reports.
Paths are repository-relative; stable IDs and ID lists must obey admission.
Sort unique ID/path lists. Preserve identical requirementId, ownerId,
claimLevel and nonClaims across the source and binding projection.
Sort unique ID/path lists and every nonClaims list lexicographically.
Do not sort argv; its token order is meaningful. Preserve identical
requirementId, ownerId, claimLevel and nonClaims across the source and binding
projection.
The binding's specPath must equal its source's requirementsPath; the source
does not have a specPath field.
Each inventory entry's requirementRefs, witnessRefs, commandRefs and sourcePath
Expand Down
2 changes: 1 addition & 1 deletion internal/command/stackpreset/preset_ids_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions internal/tools/releasechange/record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ func TestCurrentChangeRecordNamesReviewedSemanticChanges(t *testing.T) {
var currentBreakingChanges = []Change{}

var currentAdditions = []Change{
{ChangeID: "proofkit.adoption.cli-input-guidance", Summary: "Expose a connected requirement, scenario, witness and test-inventory example through on-demand CLI help. Source, binding and inventory help route to exact input pointers instead of requiring package documentation. Authoring help explains empty-source bootstrap, candidate-only previews and lifecycle owners without duplicating the source template. Guidance preserves full desired-state materialization, trust declarations, exact write approval and recovery distinctions; no consumer policy or native execution is introduced."},
{ChangeID: "proofkit.adoption.guide-contract-witnesses", Summary: "Distinguish direct inventory schemaVersion 1 from aggregate contract v2 and projection-specific versions in input help. Check actual published source-plan and continuation operands, original authoring mode, installed launcher rendering and connected examples through native and installed-carrier witnesses. Preserve accepted input semantics and platform requirements; a declared test route still does not prove execution, approval or complete coverage."},
{ChangeID: "proofkit.adoption.nonclaims-input-guidance", Summary: "Clarify in lazy materialization input help that nonClaims lists are sorted and unique, while argv token order is preserved. Exercise ordered multi-item nonClaims through planning, approved materialization and stored re-admission; reject unsorted and duplicate lists at packet, source, requirement, inventory and entry boundaries. Refresh source-bound contract digests and the ABI fingerprint. Accepted input semantics, request/report kinds, schema versions, authority denials and platform requirements are unchanged."},
}

var currentMigrationSteps = []string{}
Expand All @@ -221,7 +220,7 @@ func validateCurrentChangeRecord(record Record, notes string) error {

func currentExpectedReleaseNotes() string {
lines := []string{
"# @research-engineering/agentic-proofkit 0.14.5",
"# @research-engineering/agentic-proofkit 0.14.6",
"",
"## Breaking Contract Changes",
"",
Expand Down Expand Up @@ -274,7 +273,7 @@ func currentExpectedReleaseNotes() string {
"Primary npm channel:",
"",
"```bash",
"npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.5",
"npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.6",
"```",
"",
"Pre-1.0 npm consumers must keep this dependency exact-pinned.",
Expand All @@ -286,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.4 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.4`.",
"- Pin npm consumers to the previous admitted version 0.14.5 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.5`.",
"- Treat local package artifacts as candidates until registry identity is proven.",
)
return strings.Join(lines, "\n") + "\n"
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@research-engineering/agentic-proofkit",
"description": "Reusable proof profile, report, graph, and witness-planning primitives.",
"version": "0.14.5",
"version": "0.14.6",
"type": "module",
"license": "MIT",
"sideEffects": false,
Expand Down
10 changes: 5 additions & 5 deletions proofkit/cli-contract.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"rootDefinitionDigest": "sha256:3dbf760a8f8b0a4093c1dd4edc23367c5ef8027b31c18a01490afb657fcc03ad",
"nativeSource": {
"path": "internal/command/adoptionmaterialization",
"canonicalDigest": "sha256:60d2a22d78bde9016931c03b85f3ccd41f83e6569d44cc9216fb561093846591",
"canonicalDigest": "sha256:a4899baa2f5e2958552aa1046262248bffdedb4edf4a002db7310de9925ac95d",
"evidenceClass": "source_checkout"
},
"nativeAdmissionWitnessSelector": {
Expand Down Expand Up @@ -148,7 +148,7 @@
},
{
"path": "internal/command/adoptionmaterialization",
"canonicalDigest": "sha256:60d2a22d78bde9016931c03b85f3ccd41f83e6569d44cc9216fb561093846591",
"canonicalDigest": "sha256:a4899baa2f5e2958552aa1046262248bffdedb4edf4a002db7310de9925ac95d",
"evidenceClass": "source_checkout"
},
{
Expand Down Expand Up @@ -251,7 +251,7 @@
"rootDefinitionDigest": "sha256:c18995fb310dbde102bea231d83ec3756ffdf863199acbc88237471d06278c9e",
"nativeSource": {
"path": "internal/command/adoptionmaterialization",
"canonicalDigest": "sha256:60d2a22d78bde9016931c03b85f3ccd41f83e6569d44cc9216fb561093846591",
"canonicalDigest": "sha256:a4899baa2f5e2958552aa1046262248bffdedb4edf4a002db7310de9925ac95d",
"evidenceClass": "source_checkout"
},
"nativeAdmissionWitnessSelector": {
Expand Down Expand Up @@ -287,7 +287,7 @@
},
{
"path": "internal/command/adoptionmaterialization",
"canonicalDigest": "sha256:60d2a22d78bde9016931c03b85f3ccd41f83e6569d44cc9216fb561093846591",
"canonicalDigest": "sha256:a4899baa2f5e2958552aa1046262248bffdedb4edf4a002db7310de9925ac95d",
"evidenceClass": "source_checkout"
},
{
Expand Down Expand Up @@ -401,7 +401,7 @@
},
{
"path": "internal/command/adoptionmaterialization",
"canonicalDigest": "sha256:60d2a22d78bde9016931c03b85f3ccd41f83e6569d44cc9216fb561093846591",
"canonicalDigest": "sha256:a4899baa2f5e2958552aa1046262248bffdedb4edf4a002db7310de9925ac95d",
"evidenceClass": "source_checkout"
},
{
Expand Down
Loading
Loading