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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ node_modules/
playwright-report/
test-results/
*.tgz
!internal/kernel/requirementsourcecodec/testdata/screen-v3.tgz
.DS_Store

.env
Expand Down
1 change: 0 additions & 1 deletion BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ records, generated release manifests, or the owning docs named above.

| Status | ID | Scope | Completion condition |
|---|---|---|---|
| NEXT | SOURCE-CODEC-01 | Select at most one compact source codec without creating dual authority. | After `SOURCE-MODEL-01`, one versioned experiment manifest freezes disjoint role sets: the flat-v1 baseline control, grouped-model ablations, and exactly complete grouped-JSON plus at most one complete restricted-DSL codec candidate over the same model. Only codec candidates can win the predeclared replacement relation; controls and ablations measure causality and cannot become production grammars. A newly discovered candidate requires a new manifest version and complete experiment. A frozen corpus and strict `Replace(candidate, grouped-json)` predicate cover grammar completeness, safety, semantic parity, diagnostics, canonical bytes, review accuracy, token cost, diff amplification, parse/format cost, and unknowns. Every metric is classified exactly once by a versioned registry with role, direction, baseline pair, aggregation, material threshold, primary decision requirement, and missing-observation semantics; duplicate or unclassified metrics fail admission, hard constraints cannot trade off, report-only metrics cannot decide replacement, promised byte/token reductions must be materially better, and bounded diff/parse costs must be noninferior. If grouped JSON fails its hard gate, retain the current flat v1 source and perform no v2 cutover; otherwise select the restricted text candidate only when it is the unique strict replacement, while a tie, unknown, incomparability, or non-material improvement selects grouped JSON. The losing parser and formatter are deleted before experiment closeout, and production admits exactly one grammar. |
| BLOCKED | SOURCE-CUTOVER-01 | Migrate self-hosted requirement sources only after one codec, the typed v2 model, nested structural contracts, and the complete evidence counterfeit corpus pass their gates. | The `REQ-PROOFKIT-QUALITY-010` execution-backed command-oracle closure and `SCHEMA-01` are complete; a digest-bound clause ledger proves representation-only equality or owner-reviewed semantic decomposition for every legacy requirement; all bindings/scenarios/contracts/context/diff/graph/browser owners cut over atomically; v1 admission and the losing codec are removed; and active-v1 inventory is zero. |
| BLOCKED | SCHEMA-01 | Replace root-shape-only public contracts with one independent complete nested structural-contract owner. | A versioned schema owner covers nested fields, variants, cardinalities, bounds, enums, defaults, duplicate and unknown-field policy, and cross-field constraints; generated artifacts pass parity against an independently authored completeness manifest and mutant corpus without becoming semantic or policy authority. |
| BLOCKED | SOURCE-PILOT-01 | Validate the selected source-v2 model and agent routing against heterogeneous external repositories without mutating them. | At least two independent repository classes complete no-push dual runs whose frozen inputs compare incumbent and candidate mapping, diagnostics, token cost, authoring accuracy, proof-route gaps, and rollback; unresolved parity or authority gaps keep incumbent owners active. |
Expand Down
14 changes: 14 additions & 0 deletions docs/specs/proofkit-spec-proof-core/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,20 @@ execution receipts, and merge policy.
package, field, representation, variant, and positive/negative relation
coverage without attributing correlated edits to independent field
causality, selecting a codec, or changing a public source boundary.
- `REQ-PROOFKIT-SPEC-025`: a versioned disjoint-role experiment selects one
admitted private v2 source-grammar owner record, grouped JSON with an
entity-local hybrid layout;
its strict bounded codec delegates meaning to the representation-neutral
model, binds each collection to one model-limit owner, preserves every
projection, metadata-presence state, and lexical source location, and emits
deterministic nondisclosing diagnostics. A bounded single-member traversal-,
symlink-, duplicate-, and trailing-data-closed archive byte-binds the exact
V3 screen, while independent
field, limit, selection, mutant, round-trip, fuzz-seed, package, and
admitted grammar-owner-record and package-inventory witnesses close the
selected owner boundary without migrating current sources, exposing a new
public CLI, proving open-world absence of undeclared equivalent parsers, or
claiming that no future owner-approved grammar can be added.

## Non-Claims

Expand Down
13 changes: 13 additions & 0 deletions docs/specs/proofkit-spec-proof-core/requirements.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,19 @@
"lifecycle": {"state": "active", "replacementRequirementIds": [], "evidenceRefs": []},
"deferral": null,
"updatePolicy": {"reviewOwnerId": "proofkit.spec-proof-core", "requiresImpactDeclaration": true, "requiresProofBindingReview": true}
},
{
"requirementId": "REQ-PROOFKIT-SPEC-025",
"ownerId": "proofkit.spec-proof-core",
"invariant": "A private requirement-source codec selection admits grouped JSON with the frozen entity-local hybrid layout through one admitted v2 persisted-grammar owner record for internal/kernel/requirementsourcecodec after a versioned disjoint-role screen rejects compact and pretty JSON layouts for edit-locality failure and admits no YAML, TOML, or restricted-text parser authority. The selection record byte-binds a bounded single-member traversal-, symlink-, duplicate-, and trailing-data-closed binary archive and the exact extracted V3 evidence tree, including its method sources, fixture corpus, rendered candidates, independent token reports, review results, validation, edit rows, and decision, and its metric registry, layout order, thresholds, observations, and evaluator have exact decision closure. The selected codec maps bounded UTF-8 bytes through duplicate-, case-, unknown-, missing-, null-, integer-, and Unicode-scalar-closed structural admission into exactly one requirementsourcemodel.NormalizeWithLimits call; each wire collection names one model-limit owner; immutable atomic, authoring-layout, typed-reference, and lexical source-map projections preserve metadata absence, present-null deferral, present-record deferral, ordered actions, sorted dynamic maps, and caller wire order; and formatting re-admits the semantic model before emitting fixed-order entity-local canonical JSON with exact unsafe-scalar escaping and one final line feed. Raw-byte, UTF-8, lexical-token, nesting, representation-cardinality, model-resource, model-semantic, and canonical-output failures have fixed precedence, while diagnostic paths contain only canonical field names, numeric indexes, or placeholders and resolve synthetic model identities to exact wire spans. Independently authored field, limit-coefficient, selection, and executable mutant manifests close DTO fields and cardinalities, structural schema, resource formula, candidate roles, decision, diagnostic paths, and losing-grammar dependencies; round-trip, idempotence, source-span replay, exact-limit, fuzz-seed, admitted grammar-owner record, and exact package-inventory witnesses close the currently selected owner boundary without claiming open-world absence of undeclared semantically equivalent parsers or a ban on future owner-approved grammars.",
"claimLevel": "blocking",
"riskClass": "high",
"proofBindingRefs": ["proofkit/requirement-bindings.json"],
"nonClaimRefs": ["NC-PROOFKIT-SPEC-025"],
"nonClaims": ["This private codec does not migrate or rewrite current requirement sources, expose a public source extension or CLI command, retain a normalized mirror, authenticate requirement meaning or derivation provenance, generalize the frozen formatter screen beyond its byte-bound corpus, prove the open-world absence of undeclared semantically equivalent parsers, prevent a future owner-approved grammar from being added, execute native witnesses, approve merge or release, or establish rollout or production readiness."],
"lifecycle": {"state": "active", "replacementRequirementIds": [], "evidenceRefs": []},
"deferral": null,
"updatePolicy": {"reviewOwnerId": "proofkit.spec-proof-core", "requiresImpactDeclaration": true, "requiresProofBindingReview": true}
}
],
"nonClaims": [
Expand Down
36 changes: 12 additions & 24 deletions internal/app/agent_workflow_version_edge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
"slices"
"testing"

"github.com/research-engineering/agentic-proofkit/internal/command/jsonreportcliadaptersource"
"github.com/research-engineering/agentic-proofkit/internal/kernel/admission"
"github.com/research-engineering/agentic-proofkit/internal/tools/releasechange"
)

const agentWorkflowVersionEdgePath = "internal/app/testdata/v0.5-wire-observations.json"
Expand Down Expand Up @@ -40,11 +38,7 @@ type agentWorkflowCommandContract struct {

func TestAgentWorkflowVersionEdgeClosesPublicWireAdditions(t *testing.T) {
record := readAgentWorkflowVersionEdge(t)
releaseRecord, err := releasechange.Read(filepath.Join(repoRoot(t), releasechange.RecordPath))
if err != nil {
t.Fatal(err)
}
if err := validateAgentWorkflowVersionEdge(record, releaseRecord); err != nil {
if err := validateAgentWorkflowVersionEdge(record); err != nil {
t.Fatal(err)
}

Expand Down Expand Up @@ -74,7 +68,7 @@ func TestAgentWorkflowVersionEdgeClosesPublicWireAdditions(t *testing.T) {
t.Run(mutant.name, func(t *testing.T) {
value := cloneAgentWorkflowVersionEdge(record)
mutant.mutate(&value)
if err := validateAgentWorkflowVersionEdge(value, releaseRecord); err == nil {
if err := validateAgentWorkflowVersionEdge(value); err == nil {
t.Fatal("version-edge mutant was admitted")
}
})
Expand Down Expand Up @@ -114,38 +108,32 @@ func readAgentWorkflowVersionEdge(t *testing.T) agentWorkflowVersionEdge {
return decoded
}

func validateAgentWorkflowVersionEdge(record agentWorkflowVersionEdge, releaseRecord releasechange.Record) error {
func validateAgentWorkflowVersionEdge(record agentWorkflowVersionEdge) error {
if record.SchemaVersion != 1 || record.EdgeID != "proofkit.public-wire.0.4.0-to-0.5.0" || record.EvidenceClass != "owner_authored_frozen_version_edge_observation" {
return fmt.Errorf("version-edge identity is invalid")
}
if record.PreviousVersion != releaseRecord.PreviousVersion || record.Version != releaseRecord.Version {
if record.PreviousVersion != "0.4.0" || record.Version != "0.5.0" {
return fmt.Errorf("version-edge release identity is stale")
}
if record.PreviousPublicABISHA256 != "sha256:fc03740aea9e7f525a4388e5d7f557cde07e11b0db0c05101fe937c28a1129d9" || record.CurrentPublicABISHA256 != "sha256:"+cliContractPublicABISHA256 || record.PreviousPublicABISHA256 == record.CurrentPublicABISHA256 {
if record.PreviousPublicABISHA256 != "sha256:fc03740aea9e7f525a4388e5d7f557cde07e11b0db0c05101fe937c28a1129d9" || record.CurrentPublicABISHA256 != "sha256:9ecd2c3d2f3f360088409f7e91cce406fc1d1d6edda1b404fce119985c4fb623" || record.PreviousPublicABISHA256 == record.CurrentPublicABISHA256 {
return fmt.Errorf("version-edge ABI identity is invalid")
}
if record.PreviousTypeScriptGeneratorID != "proofkit.json-report-cli-adapter-source.typescript.v1" || record.CurrentTypeScriptGeneratorID != jsonreportcliadaptersource.TypeScriptGeneratorID || record.PreviousTypeScriptGeneratorID == record.CurrentTypeScriptGeneratorID {
if record.PreviousTypeScriptGeneratorID != "proofkit.json-report-cli-adapter-source.typescript.v1" || record.CurrentTypeScriptGeneratorID != "proofkit.json-report-cli-adapter-source.typescript.v2" || record.PreviousTypeScriptGeneratorID == record.CurrentTypeScriptGeneratorID {
return fmt.Errorf("version-edge TypeScript generator identity is invalid")
}
expectedCommands := []agentWorkflowCommandContract{
{Command: "change-workflow-plan", InputContractSHA256: generatedCommandContractMetadataByName["change-workflow-plan"].InputContractSHA256, OutputContractSHA256: generatedCommandContractMetadataByName["change-workflow-plan"].OutputContractSHA256},
{Command: "native-evidence-guidance", InputContractSHA256: generatedCommandContractMetadataByName["native-evidence-guidance"].InputContractSHA256, OutputContractSHA256: generatedCommandContractMetadataByName["native-evidence-guidance"].OutputContractSHA256},
{Command: "change-workflow-plan", InputContractSHA256: "sha256:e3124fc636b7f66b24daf8e1435cea11da15a741abeabe0cc3d3890b13c71625", OutputContractSHA256: "sha256:cd035e9b71d83c341b1a937a18699fd727cb4b0d694983d715b064292ae4d8bd"},
{Command: "native-evidence-guidance", InputContractSHA256: "", OutputContractSHA256: "sha256:c1d23df574e948ea7160931f53790a6d133ae12eeceefe9e5fa15430d653ff7e"},
}
if !slices.Equal(record.AddedCommandContracts, expectedCommands) {
return fmt.Errorf("version-edge added command contracts are not exact")
}
additions := make([]string, 0, len(releaseRecord.Additions))
for _, change := range releaseRecord.Additions {
additions = append(additions, change.ChangeID)
}
if !slices.Equal(record.AdditionChangeIDs, additions) {
expectedAdditions := []string{"proofkit.agent-workflow.change-planner", "proofkit.agent-workflow.native-evidence-guidance", "proofkit.release.cross-carrier-binary-identity"}
if !slices.Equal(record.AdditionChangeIDs, expectedAdditions) {
return fmt.Errorf("version-edge addition owners are not exact")
}
breaking := make([]string, 0, len(releaseRecord.BreakingChanges))
for _, change := range releaseRecord.BreakingChanges {
breaking = append(breaking, change.ChangeID)
}
if !slices.Equal(record.BreakingChangeIDs, breaking) {
expectedBreaking := []string{"proofkit.agent-envelope.local-identity-closure", "proofkit.diagnostic.bounded-error-boundary", "proofkit.stable-json.unicode-scalar-v2"}
if !slices.Equal(record.BreakingChangeIDs, expectedBreaking) {
return fmt.Errorf("version-edge breaking change owners are not exact")
}
if !slices.Equal(record.NonClaims, []string{"This owner-authored version-edge observation binds reviewed public contract identities; it does not authenticate Git history, registry publication, provider ingestion, native witness truth, rollout, or production readiness."}) {
Expand Down
Loading
Loading