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
69 changes: 52 additions & 17 deletions internal/app/authoring_input_guide_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ func TestAuthoringInputGuideBootstrapCLI(t *testing.T) {
}
canonical = help
}
if !strings.Contains(canonical, "Order authoringRefs by refId, strictly ascending and without duplicates.") {
t.Fatal("authoring help omits multi-reference ordering")
}
parts := strings.Split(canonical, "```json\n")
if len(parts) != 2 {
t.Fatal("authoring help must contain one template, not duplicate source examples")
Expand All @@ -54,25 +57,57 @@ func TestAuthoringInputGuideBootstrapCLI(t *testing.T) {
t.Fatal("authoring template fabricated its source or candidate")
}
packet["currentRequirementSource"], update["candidateRequirement"] = empty, candidate
for _, mode := range []string{"retrospective_baseline", "pull_request_design"} {
packet["mode"] = mode
report := runAdoptionHelpCLI(t, adoptionHelpJSON(t, packet), args...)
if report["planKind"] != "proofkit.requirement-authoring-plan" || report["state"] != "passed" || report["mode"] != mode {
t.Fatalf("wrong authoring report: %v", report)
}
preview := report["nonAuthoritativeAdmissionPreview"].(map[string]any)
if preview["candidateOnly"] != true || preview["ownerReviewRequired"] != true || preview["authority"] != "candidate_only" {
t.Fatal("admitted bootstrap became product approval")
}
if !reflect.DeepEqual(preview["requirementSourcePreview"], source) {
t.Fatalf("bootstrap source mismatch:\ngot: %s\nwant: %s", adoptionHelpJSON(t, preview["requirementSourcePreview"]), adoptionHelpJSON(t, source))
}
materialization["requirementSources"] = []any{preview["requirementSourcePreview"]}
plan := runAdoptionHelpCLI(t, adoptionHelpJSON(t, materialization), "adopt", "materialize", "plan", "--input", "-", "--repo-root", root)
if plan["state"] != "ready" || plan["sourceIntent"] != "audit-from-code" {
t.Fatal("bootstrap preview cannot feed the existing materialization route")
firstRef := packet["authoringRefs"].([]any)[0].(map[string]any)
secondRef := decodeCLIJSON(t, string(adoptionHelpJSON(t, firstRef))).(map[string]any)
secondRef["refId"] = "example.observation.z"
secondRef["kind"] = "test_summary"
secondRef["path"] = "tests/request_test.go"
secondRef["digest"] = "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
secondRef["nonClaims"] = []any{"Separate synthetic test observation; execution is not authenticated."}
secondRef["summary"] = "A second independent observation remains pending owner review."
refs := []any{firstRef, secondRef}
refIDs := []any{firstRef["refId"], secondRef["refId"]}
for _, count := range []int{1, 2} {
packet["authoringRefs"] = refs[:count]
update["sourceRefIds"] = refIDs[:count]
for _, mode := range []string{"retrospective_baseline", "pull_request_design"} {
packet["mode"] = mode
report := runAdoptionHelpCLI(t, adoptionHelpJSON(t, packet), args...)
if report["planKind"] != "proofkit.requirement-authoring-plan" || report["state"] != "passed" || report["mode"] != mode {
t.Fatalf("wrong authoring report: %v", report)
}
if !reflect.DeepEqual(report["authoringRefs"], packet["authoringRefs"]) {
t.Fatal("authoring projection lost or changed a complete reference record")
}
preview := report["nonAuthoritativeAdmissionPreview"].(map[string]any)
if preview["candidateOnly"] != true || preview["ownerReviewRequired"] != true || preview["authority"] != "candidate_only" {
t.Fatal("admitted bootstrap became product approval")
}
if !reflect.DeepEqual(preview["requirementSourcePreview"], source) {
t.Fatalf("bootstrap source mismatch:\ngot: %s\nwant: %s", adoptionHelpJSON(t, preview["requirementSourcePreview"]), adoptionHelpJSON(t, source))
}
materialization["requirementSources"] = []any{preview["requirementSourcePreview"]}
plan := runAdoptionHelpCLI(t, adoptionHelpJSON(t, materialization), "adopt", "materialize", "plan", "--input", "-", "--repo-root", root)
if plan["state"] != "ready" || plan["sourceIntent"] != "audit-from-code" {
t.Fatal("bootstrap preview cannot feed the existing materialization route")
}
}
}
for _, mutation := range []string{"unsorted", "duplicate"} {
t.Run(mutation+" authoring refs", func(t *testing.T) {
invalid := decodeCLIJSON(t, string(adoptionHelpJSON(t, packet))).(map[string]any)
refs := invalid["authoringRefs"].([]any)
if mutation == "unsorted" {
refs[0], refs[1] = refs[1], refs[0]
} else {
refs[1] = refs[0]
}
status, stdout, stderr := executeAgentWorkflowCLI(t, args, bytes.NewReader(adoptionHelpJSON(t, invalid)), PresentationCapabilities{})
if status != 1 || stdout != "" || !strings.Contains(stderr, "authoringRef ids must be sorted and unique") {
t.Fatalf("invalid ref order: status=%d stdout=%q stderr=%q", status, stdout, stderr)
}
})
}

// A source containing the candidate must not be treated as empty bootstrap.
packet["currentRequirementSource"] = source
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 = "4c40a20ac5333efddf7e9a4b36991ddf5b732fbd357a1538f60b887d6c73c447"
cliContractPublicABISHA256 = "0969a1577b6e76ede1e6b8c71a12e7d479d2a159a53f999c4580bfe1cf987757"
maxAggregateFileReadBytesForContractTest = 64 << 20
maxPackageManifestBytesForContractTest = 256 << 10
maxSourceFileBytesForContractTest = 8 << 20
Expand Down
4 changes: 2 additions & 2 deletions internal/app/command_contract_generated.go

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

4 changes: 4 additions & 0 deletions internal/command/requirementauthoringplan/input_guide.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const inputGuide = `Requirement authoring input guide:
Use retrospective_baseline for reviewed code-derived candidates, or
pull_request_design for proposed design changes. Neither mode grants approval.

Order authoringRefs by refId, strictly ascending and without duplicates.
Move each complete reference record with its ID; do not sort IDs separately
from their paths, digests, summaries or nonClaims.

Authoring template (two object operands must be supplied):
` + "```json\n" + `{
"schemaVersion": 1,
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.

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

var currentAdditions = []Change{
{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."},
{ChangeID: "proofkit.authoring.reference-order-guidance", Summary: "Clarify in lazy requirement-authoring help that authoringRefs are strictly sorted by unique refId values while complete reference records stay together. Exercise two distinct references through authoring and materialization planning; preserve their exact fields and reject unsorted or duplicate references. 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 @@ -220,7 +220,7 @@ func validateCurrentChangeRecord(record Record, notes string) error {

func currentExpectedReleaseNotes() string {
lines := []string{
"# @research-engineering/agentic-proofkit 0.14.6",
"# @research-engineering/agentic-proofkit 0.14.7",
"",
"## Breaking Contract Changes",
"",
Expand Down Expand Up @@ -273,7 +273,7 @@ func currentExpectedReleaseNotes() string {
"Primary npm channel:",
"",
"```bash",
"npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.6",
"npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.7",
"```",
"",
"Pre-1.0 npm consumers must keep this dependency exact-pinned.",
Expand All @@ -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.5 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.5`.",
"- Pin npm consumers to the previous admitted version 0.14.6 with `npm install --save-dev --save-exact @research-engineering/agentic-proofkit@0.14.6`.",
"- 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.6",
"version": "0.14.7",
"type": "module",
"license": "MIT",
"sideEffects": false,
Expand Down
4 changes: 2 additions & 2 deletions proofkit/cli-contract.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -4653,7 +4653,7 @@
"rootDefinitionDigest": "sha256:86f8f4913b5316caa63c40d79125199b282d108cbd8b9711db21c2023d1a4ca4",
"nativeSource": {
"path": "internal/command/requirementauthoringplan",
"canonicalDigest": "sha256:8f6b7c3cbac7c379f8f0534489961d49a8a0ee5e9c737f0d2d8fc9826b747f19",
"canonicalDigest": "sha256:c9df82eae1d9b8a7dd475b2510616d1d3cd851306f83dd5f1bb7983e7effb792",
"evidenceClass": "source_checkout"
},
"nativeAdmissionWitnessSelector": {
Expand Down Expand Up @@ -4681,7 +4681,7 @@
"rootDefinitionDigest": "sha256:c2264058757e40789005b7cf7417906461f064b9b9bca0c5ddda86704e3b36cc",
"nativeSource": {
"path": "internal/command/requirementauthoringplan",
"canonicalDigest": "sha256:8f6b7c3cbac7c379f8f0534489961d49a8a0ee5e9c737f0d2d8fc9826b747f19",
"canonicalDigest": "sha256:c9df82eae1d9b8a7dd475b2510616d1d3cd851306f83dd5f1bb7983e7effb792",
"evidenceClass": "source_checkout"
},
"nativeOutputWitnessSelector": {
Expand Down
8 changes: 4 additions & 4 deletions release/change-record.v2.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"schemaVersion": 2,
"previousVersion": "0.14.5",
"version": "0.14.6",
"previousVersion": "0.14.6",
"version": "0.14.7",
"changeClass": "compatible",
"breakingChanges": [],
"additions": [
{
"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."
"changeId": "proofkit.authoring.reference-order-guidance",
"summary": "Clarify in lazy requirement-authoring help that authoringRefs are strictly sorted by unique refId values while complete reference records stay together. Exercise two distinct references through authoring and materialization planning; preserve their exact fields and reject unsorted or duplicate references. Refresh source-bound contract digests and the ABI fingerprint. Accepted input semantics, request/report kinds, schema versions, authority denials and platform requirements are unchanged."
}
],
"migration": {
Expand Down
Loading