From 558df435bbc50fc872b14aceecae1d482b45898d Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:35:28 -0400 Subject: [PATCH 1/6] Add explicit proposed-draft Policy candidate format Serve the pinned, unadopted 1.0.0 review candidate through the shared offline Policy engine, preserving prototype bytes, provenance and default reports. Add explicit contract discovery, candidate-only portable check results, ordered material registration, retained-format isolation and 104 portable vectors. Document the proposed ADR, source pin and unchanged private transport ceilings. Focused Policy CLI/MCP tests and package vet pass; full Policy and MCP package tests pass. The broader CLI run requires loopback sockets unavailable in the local sandbox. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- NOTICE | 7 + README.md | 59 + .../0060-explicit-policy-candidate-format.md | 99 + docs/adr/README.md | 1 + docs/architecture.md | 20 + docs/mcp-clients.md | 39 + internal/cli/policy.go | 68 +- internal/cli/policy_candidate_test.go | 188 + internal/mcp/policy.go | 86 +- internal/mcp/policy_test.go | 18 + .../policy/candidate/0023-policy-companion.md | 362 + internal/policy/candidate/LICENSE | 202 + internal/policy/candidate/MIGRATION.md | 56 + internal/policy/candidate/NOTICE | 5 + internal/policy/candidate/README.md | 318 + internal/policy/candidate/capabilities.json | 74 + internal/policy/candidate/common.schema.json | 186 + .../examples/data-access/adoption.json | 75 + .../examples/data-access/consumer-pack.json | 62 + .../examples/data-access/fixture.json | 58 + .../examples/data-access/interpretation.txt | 4 + .../examples/data-access/narrative.txt | 10 + .../examples/data-access/policy.json | 76 + .../candidate/examples/data-access/source.txt | 5 + .../examples/procurement/adoption.json | 97 + .../examples/procurement/consumer-pack.json | 68 + .../examples/procurement/fixture.json | 58 + .../examples/procurement/interpretation.txt | 5 + .../examples/procurement/narrative.txt | 16 + .../examples/procurement/policy.json | 106 + .../candidate/examples/procurement/source.txt | 7 + .../candidate/examples/refunds/adoption.json | 87 + .../examples/refunds/consumer-pack.json | 76 + .../candidate/examples/refunds/fixture.json | 58 + .../examples/refunds/interpretation.txt | 4 + .../candidate/examples/refunds/narrative.txt | 13 + .../candidate/examples/refunds/policy.json | 91 + .../candidate/examples/refunds/source.txt | 6 + internal/policy/candidate/fixture.schema.json | 67 + .../candidate/governing-adoption.schema.json | 265 + internal/policy/candidate/policy.schema.json | 147 + .../policy/candidate/prototype-0.0.2-pin.json | 33 + internal/policy/candidate/provenance.json | 867 +++ internal/policy/candidate/vectors.schema.json | 203 + internal/policy/candidate/vectors/README.md | 87 + .../vectors/documents/aggregate-max.json | 25 + .../vectors/documents/aggregate-over.json | 25 + .../aggregate-shared-media-counted-once.json | 25 + .../vectors/documents/anchor-empty-range.json | 76 + .../documents/anchor-outside-narrative.json | 76 + .../vectors/documents/anchor-over-bound.json | 76 + .../documents/anchor-stale-digest.json | 76 + .../vectors/documents/anchor-utf8-split.json | 76 + .../vectors/documents/approval-field.json | 77 + .../vectors/documents/artifact-build.json | 76 + .../documents/artifact-independent.json | 76 + .../documents/artifact-leading-zero.json | 76 + .../vectors/documents/artifact-max-256.json | 76 + .../vectors/documents/artifact-newline.json | 76 + .../vectors/documents/artifact-number.json | 76 + .../vectors/documents/artifact-over-256.json | 76 + .../documents/artifact-two-components.json | 76 + .../candidate/vectors/documents/bom.json | 1 + .../vectors/documents/companion-float.json | 1 + .../documents/companion-unsafe-integer.json | 1 + .../consumer-fallback-unknown-pack.json | 62 + .../documents/consumer-fallback-unknown.json | 71 + .../vectors/documents/consumer-graph.json | 75 + .../consumer-rule-id-duplicate-pack.json | 74 + .../documents/consumer-rule-id-duplicate.json | 71 + .../documents/core-decimal-raw-pack.json | 67 + .../vectors/documents/core-decimal-raw.json | 71 + .../core-decimal-requested-canon-pack.json | 67 + .../core-decimal-requested-canon.json | 75 + .../documents/core-exponent-308-pack.json | 67 + .../vectors/documents/core-exponent-308.json | 71 + .../documents/core-exponent-over-pack.json | 67 + .../vectors/documents/core-exponent-over.json | 71 + .../documents/core-number-128-pack.json | 67 + .../vectors/documents/core-number-128.json | 71 + .../documents/core-number-over-128-pack.json | 67 + .../documents/core-number-over-128.json | 71 + .../documents/core-unsafe-int-raw-pack.json | 67 + .../documents/core-unsafe-int-raw.json | 71 + .../core-unsafe-int-requested-canon-pack.json | 67 + .../core-unsafe-int-requested-canon.json | 75 + .../vectors/documents/coverage-duplicate.json | 75 + .../vectors/documents/coverage-omitted.json | 70 + .../vectors/documents/coverage-outside.json | 75 + .../candidate/vectors/documents/depth-32.json | 1 + .../candidate/vectors/documents/depth-33.json | 1 + .../documents/desk-managed-alias-refused.json | 76 + .../vectors/documents/document-max-bytes.json | 76 + .../vectors/documents/duplicate-json.json | 1 + .../documents/duplicate-policy-identity.json | 128 + .../candidate/vectors/documents/format-0.json | 76 + .../candidate/vectors/documents/format-2.json | 76 + .../documents/format-before-canon.json | 1 + .../documents/format-before-shape.json | 4 + .../vectors/documents/format-bool.json | 76 + .../vectors/documents/format-int.json | 76 + .../documents/format-leading-zero.json | 76 + .../vectors/documents/format-missing.json | 75 + .../vectors/documents/format-newline.json | 76 + .../vectors/documents/format-patch.json | 76 + .../vectors/documents/format-short.json | 76 + .../vectors/documents/format-suffix.json | 76 + .../vectors/documents/format-unicode.json | 76 + .../vectors/documents/format-v-prefix.json | 76 + .../vectors/documents/informational-max.json | 82 + .../vectors/documents/informational-over.json | 82 + .../vectors/documents/invalid-utf8.json | 1 + .../vectors/documents/kind-id-confusion.json | 75 + .../limited-scope-missing-basis.json | 92 + .../documents/limited-scope-unknown.json | 98 + .../documents/malformed-over-depth.json | 1 + .../documents/missing-governing-policy.json | 21 + .../vectors/documents/missing-narrative.json | 76 + .../vectors/documents/multiple-json.json | 1 + .../documents/multiple-policy-identities.json | 128 + .../vectors/documents/narrative-max.json | 40 + .../vectors/documents/narrative-over.json | 40 + .../vectors/documents/nonfinite.json | 1 + .../documents/number-literal-over-128.json | 1 + .../vectors/documents/opaque-original.json | 76 + .../vectors/documents/opaque-original.pdf | Bin 0 -> 16 bytes .../vectors/documents/original-max.json | 76 + .../vectors/documents/original-over.json | 76 + .../vectors/documents/permission-field.json | 77 + .../vectors/documents/policy-canon-stale.json | 75 + .../documents/policy-identity-stale.json | 75 + .../documents/policy-version-ref-stale.json | 75 + .../documents/prototype-selector-refused.json | 81 + .../documents/registration-count-16.json | 76 + .../documents/registration-count-17.json | 76 + .../vectors/documents/requirements-field.json | 77 + .../vectors/documents/review-max.json | 75 + .../vectors/documents/review-over.json | 75 + .../vectors/documents/second-policy.json | 76 + .../documents/section-id-duplicate.json | 76 + .../shared-bytes-multiple-media-types.json | 76 + .../vectors/documents/signature-field.json | 77 + .../vectors/documents/singleton-with-id.json | 68 + .../vectors/documents/source-id-unknown.json | 76 + .../documents/stale-material-hash.json | 76 + .../documents/stale-material-length.json | 76 + .../vectors/documents/standalone-policy.json | 76 + .../vectors/documents/surrogate.json | 1 + .../unknown-kind-registration-over.json | 1 + .../vectors/documents/unknown-rule.json | 75 + .../documents/unregistered-media-type.json | 76 + .../documents/unsupported-element.json | 68 + .../vectors/documents/uri-invalid.json | 76 + .../policy/candidate/vectors/manifest.json | 6197 +++++++++++++++++ internal/policy/candidate_schema.go | 85 + internal/policy/candidate_test.go | 260 + internal/policy/check.go | 153 +- internal/policy/document.go | 29 +- internal/policy/format.go | 298 + internal/policy/materials.go | 159 +- internal/policy/references.go | 2 +- internal/policy/schema.go | 45 +- 162 files changed, 18290 insertions(+), 107 deletions(-) create mode 100644 docs/adr/0060-explicit-policy-candidate-format.md create mode 100644 internal/cli/policy_candidate_test.go create mode 100644 internal/policy/candidate/0023-policy-companion.md create mode 100644 internal/policy/candidate/LICENSE create mode 100644 internal/policy/candidate/MIGRATION.md create mode 100644 internal/policy/candidate/NOTICE create mode 100644 internal/policy/candidate/README.md create mode 100644 internal/policy/candidate/capabilities.json create mode 100644 internal/policy/candidate/common.schema.json create mode 100644 internal/policy/candidate/examples/data-access/adoption.json create mode 100644 internal/policy/candidate/examples/data-access/consumer-pack.json create mode 100644 internal/policy/candidate/examples/data-access/fixture.json create mode 100644 internal/policy/candidate/examples/data-access/interpretation.txt create mode 100644 internal/policy/candidate/examples/data-access/narrative.txt create mode 100644 internal/policy/candidate/examples/data-access/policy.json create mode 100644 internal/policy/candidate/examples/data-access/source.txt create mode 100644 internal/policy/candidate/examples/procurement/adoption.json create mode 100644 internal/policy/candidate/examples/procurement/consumer-pack.json create mode 100644 internal/policy/candidate/examples/procurement/fixture.json create mode 100644 internal/policy/candidate/examples/procurement/interpretation.txt create mode 100644 internal/policy/candidate/examples/procurement/narrative.txt create mode 100644 internal/policy/candidate/examples/procurement/policy.json create mode 100644 internal/policy/candidate/examples/procurement/source.txt create mode 100644 internal/policy/candidate/examples/refunds/adoption.json create mode 100644 internal/policy/candidate/examples/refunds/consumer-pack.json create mode 100644 internal/policy/candidate/examples/refunds/fixture.json create mode 100644 internal/policy/candidate/examples/refunds/interpretation.txt create mode 100644 internal/policy/candidate/examples/refunds/narrative.txt create mode 100644 internal/policy/candidate/examples/refunds/policy.json create mode 100644 internal/policy/candidate/examples/refunds/source.txt create mode 100644 internal/policy/candidate/fixture.schema.json create mode 100644 internal/policy/candidate/governing-adoption.schema.json create mode 100644 internal/policy/candidate/policy.schema.json create mode 100644 internal/policy/candidate/prototype-0.0.2-pin.json create mode 100644 internal/policy/candidate/provenance.json create mode 100644 internal/policy/candidate/vectors.schema.json create mode 100644 internal/policy/candidate/vectors/README.md create mode 100644 internal/policy/candidate/vectors/documents/aggregate-max.json create mode 100644 internal/policy/candidate/vectors/documents/aggregate-over.json create mode 100644 internal/policy/candidate/vectors/documents/aggregate-shared-media-counted-once.json create mode 100644 internal/policy/candidate/vectors/documents/anchor-empty-range.json create mode 100644 internal/policy/candidate/vectors/documents/anchor-outside-narrative.json create mode 100644 internal/policy/candidate/vectors/documents/anchor-over-bound.json create mode 100644 internal/policy/candidate/vectors/documents/anchor-stale-digest.json create mode 100644 internal/policy/candidate/vectors/documents/anchor-utf8-split.json create mode 100644 internal/policy/candidate/vectors/documents/approval-field.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-build.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-independent.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-leading-zero.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-max-256.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-newline.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-number.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-over-256.json create mode 100644 internal/policy/candidate/vectors/documents/artifact-two-components.json create mode 100644 internal/policy/candidate/vectors/documents/bom.json create mode 100644 internal/policy/candidate/vectors/documents/companion-float.json create mode 100644 internal/policy/candidate/vectors/documents/companion-unsafe-integer.json create mode 100644 internal/policy/candidate/vectors/documents/consumer-fallback-unknown-pack.json create mode 100644 internal/policy/candidate/vectors/documents/consumer-fallback-unknown.json create mode 100644 internal/policy/candidate/vectors/documents/consumer-graph.json create mode 100644 internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate-pack.json create mode 100644 internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate.json create mode 100644 internal/policy/candidate/vectors/documents/core-decimal-raw-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-decimal-raw.json create mode 100644 internal/policy/candidate/vectors/documents/core-decimal-requested-canon-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-decimal-requested-canon.json create mode 100644 internal/policy/candidate/vectors/documents/core-exponent-308-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-exponent-308.json create mode 100644 internal/policy/candidate/vectors/documents/core-exponent-over-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-exponent-over.json create mode 100644 internal/policy/candidate/vectors/documents/core-number-128-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-number-128.json create mode 100644 internal/policy/candidate/vectors/documents/core-number-over-128-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-number-over-128.json create mode 100644 internal/policy/candidate/vectors/documents/core-unsafe-int-raw-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-unsafe-int-raw.json create mode 100644 internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon-pack.json create mode 100644 internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon.json create mode 100644 internal/policy/candidate/vectors/documents/coverage-duplicate.json create mode 100644 internal/policy/candidate/vectors/documents/coverage-omitted.json create mode 100644 internal/policy/candidate/vectors/documents/coverage-outside.json create mode 100644 internal/policy/candidate/vectors/documents/depth-32.json create mode 100644 internal/policy/candidate/vectors/documents/depth-33.json create mode 100644 internal/policy/candidate/vectors/documents/desk-managed-alias-refused.json create mode 100644 internal/policy/candidate/vectors/documents/document-max-bytes.json create mode 100644 internal/policy/candidate/vectors/documents/duplicate-json.json create mode 100644 internal/policy/candidate/vectors/documents/duplicate-policy-identity.json create mode 100644 internal/policy/candidate/vectors/documents/format-0.json create mode 100644 internal/policy/candidate/vectors/documents/format-2.json create mode 100644 internal/policy/candidate/vectors/documents/format-before-canon.json create mode 100644 internal/policy/candidate/vectors/documents/format-before-shape.json create mode 100644 internal/policy/candidate/vectors/documents/format-bool.json create mode 100644 internal/policy/candidate/vectors/documents/format-int.json create mode 100644 internal/policy/candidate/vectors/documents/format-leading-zero.json create mode 100644 internal/policy/candidate/vectors/documents/format-missing.json create mode 100644 internal/policy/candidate/vectors/documents/format-newline.json create mode 100644 internal/policy/candidate/vectors/documents/format-patch.json create mode 100644 internal/policy/candidate/vectors/documents/format-short.json create mode 100644 internal/policy/candidate/vectors/documents/format-suffix.json create mode 100644 internal/policy/candidate/vectors/documents/format-unicode.json create mode 100644 internal/policy/candidate/vectors/documents/format-v-prefix.json create mode 100644 internal/policy/candidate/vectors/documents/informational-max.json create mode 100644 internal/policy/candidate/vectors/documents/informational-over.json create mode 100644 internal/policy/candidate/vectors/documents/invalid-utf8.json create mode 100644 internal/policy/candidate/vectors/documents/kind-id-confusion.json create mode 100644 internal/policy/candidate/vectors/documents/limited-scope-missing-basis.json create mode 100644 internal/policy/candidate/vectors/documents/limited-scope-unknown.json create mode 100644 internal/policy/candidate/vectors/documents/malformed-over-depth.json create mode 100644 internal/policy/candidate/vectors/documents/missing-governing-policy.json create mode 100644 internal/policy/candidate/vectors/documents/missing-narrative.json create mode 100644 internal/policy/candidate/vectors/documents/multiple-json.json create mode 100644 internal/policy/candidate/vectors/documents/multiple-policy-identities.json create mode 100644 internal/policy/candidate/vectors/documents/narrative-max.json create mode 100644 internal/policy/candidate/vectors/documents/narrative-over.json create mode 100644 internal/policy/candidate/vectors/documents/nonfinite.json create mode 100644 internal/policy/candidate/vectors/documents/number-literal-over-128.json create mode 100644 internal/policy/candidate/vectors/documents/opaque-original.json create mode 100644 internal/policy/candidate/vectors/documents/opaque-original.pdf create mode 100644 internal/policy/candidate/vectors/documents/original-max.json create mode 100644 internal/policy/candidate/vectors/documents/original-over.json create mode 100644 internal/policy/candidate/vectors/documents/permission-field.json create mode 100644 internal/policy/candidate/vectors/documents/policy-canon-stale.json create mode 100644 internal/policy/candidate/vectors/documents/policy-identity-stale.json create mode 100644 internal/policy/candidate/vectors/documents/policy-version-ref-stale.json create mode 100644 internal/policy/candidate/vectors/documents/prototype-selector-refused.json create mode 100644 internal/policy/candidate/vectors/documents/registration-count-16.json create mode 100644 internal/policy/candidate/vectors/documents/registration-count-17.json create mode 100644 internal/policy/candidate/vectors/documents/requirements-field.json create mode 100644 internal/policy/candidate/vectors/documents/review-max.json create mode 100644 internal/policy/candidate/vectors/documents/review-over.json create mode 100644 internal/policy/candidate/vectors/documents/second-policy.json create mode 100644 internal/policy/candidate/vectors/documents/section-id-duplicate.json create mode 100644 internal/policy/candidate/vectors/documents/shared-bytes-multiple-media-types.json create mode 100644 internal/policy/candidate/vectors/documents/signature-field.json create mode 100644 internal/policy/candidate/vectors/documents/singleton-with-id.json create mode 100644 internal/policy/candidate/vectors/documents/source-id-unknown.json create mode 100644 internal/policy/candidate/vectors/documents/stale-material-hash.json create mode 100644 internal/policy/candidate/vectors/documents/stale-material-length.json create mode 100644 internal/policy/candidate/vectors/documents/standalone-policy.json create mode 100644 internal/policy/candidate/vectors/documents/surrogate.json create mode 100644 internal/policy/candidate/vectors/documents/unknown-kind-registration-over.json create mode 100644 internal/policy/candidate/vectors/documents/unknown-rule.json create mode 100644 internal/policy/candidate/vectors/documents/unregistered-media-type.json create mode 100644 internal/policy/candidate/vectors/documents/unsupported-element.json create mode 100644 internal/policy/candidate/vectors/documents/uri-invalid.json create mode 100644 internal/policy/candidate/vectors/manifest.json create mode 100644 internal/policy/candidate_schema.go create mode 100644 internal/policy/candidate_test.go create mode 100644 internal/policy/format.go diff --git a/NOTICE b/NOTICE index 30f17565..3bd91ec6 100644 --- a/NOTICE +++ b/NOTICE @@ -13,3 +13,10 @@ the evaluation corpus, its manifest schema, and the pack fixtures it names. The exact embedded revision and per-file SHA-256 digests are recorded in internal/artifacts/jps//lock.json. + +The experimental offline Policy tools also embed unmodified nonnormative RFC +0023 prototype and proposed-draft contract candidate artifacts from that same +Apache-2.0 specification repository. Their separate exact source revisions, +per-file SHA-256 digests, upstream LICENSE and NOTICE are retained under +internal/policy/prototype/ and internal/policy/candidate/. The candidate is not +an adopted specification artifact or a conformance class. diff --git a/README.md b/README.md index 00a56b81..d9f76720 100644 --- a/README.md +++ b/README.md @@ -1136,3 +1136,62 @@ in [MCP clients](docs/mcp-clients.md#experimental-policy-prototype-tools). The RFC, prototype schemas and synthetic fixtures are bundled from specification revision `8a56a95d555c17640d2db4984363b779536b3c2a`, with per-file digests and licensing provenance. They are never fetched at runtime. + +### Proposed draft Policy contract candidate + +The same experimental commands additionally support the **unadopted, +proposed-draft** candidate `formatVersion: "1.0.0"` +([ADR-0060](docs/adr/0060-explicit-policy-candidate-format.md)). It is a review +candidate for RFC 0023, not a stable format, adopted standard or conformance +class. Its artifacts are pinned separately to Spec commit +`4406cec9714ab9bc8e8971237cc79d58682cc904` in +[the candidate provenance manifest](internal/policy/candidate/provenance.json). + +Default `contract` output and all prototype reports keep their existing shape +for strict clients. Explicit discovery returns a separate `registryVersion: "1"` +report; selecting one contract returns that format's provenance and capabilities: + +```bash +jpack experimental policy contract --all-formats --format json +jpack experimental policy contract --format-version 1.0.0 --format json +jpack experimental policy init --kind policy --format-version 1.0.0 --id urn:example:candidate --version 7.3.42 +jpack experimental policy schema --kind governing-adoption --format-version 1.0.0 +jpack experimental policy check candidate-adoption.json --materials retained-materials.json --format json +``` + +`--all-formats` and contract `--format-version` are mutually exclusive. Documents +with `formatVersion` select the candidate grammar explicitly; supported prototype +inputs continue using their exact wrapper. An optional `--format-version 1.0.0` +on canonicalize/digest/validate/check also selects candidate refusal handling for +malformed or selector-less input. It does not insert a missing selector, rewrite +an artifact or migrate bytes. Candidate Policies use `workspace-managed` or +`externally-managed`; `desk-managed` is refused. Artifact `version` remains +independent of the format selector. Candidate adoption requires retained +candidate Policy bytes; prototype Policies cannot satisfy those references. + +Candidate reports identify `formatVersion`, `proposed-draft` maturity, their +exact source pin and `candidateCapabilities`. Only a full candidate `check` +includes `candidateResult`, whose complete value is one of: + +```json +{"status":"valid","formatVersion":"1.0.0","maturity":"proposed-draft"} +{"status":"refused","code":"invalid-selector"} +``` + +The finite refusal codes and phase ordering are defined by the +[pinned candidate contract](internal/policy/candidate/README.md#5-resource-limits-and-refusal-classifications). +Runtime retains exit 0 for success, 1 for invalid content and 2 for unsupported +input; the nested result supplies the portable candidate classification. +Environment failures are operational errors and provide no candidate result. +Canonicalize/digest establish encoding and identity only; validate checks closed +document forms and local references, with retained materials unchecked. Their +reports omit `candidateResult`. + +The Go harness compares all 104 exact portable result objects, acquiring vector +sources lazily and preserving raw Pack numbers and every retained-byte identity. +It uses the shared registration/checking engine directly: valid distinct-byte +bundles can exceed the private 24 MiB JSON/base64 carrier or MCP's 16 MiB request +limit, especially when identical bytes are registered under multiple media +types. Those transport ceilings are unchanged. Agreement with these vectors +supplies no independently authored implementation evidence, approval, current +authority or permission. diff --git a/docs/adr/0060-explicit-policy-candidate-format.md b/docs/adr/0060-explicit-policy-candidate-format.md new file mode 100644 index 00000000..0f6d129c --- /dev/null +++ b/docs/adr/0060-explicit-policy-candidate-format.md @@ -0,0 +1,99 @@ +--- +status: proposed +date: 2026-10-18 +deciders: maintainer +--- + +# Add an explicit Policy contract candidate without changing prototype clients + +## Context and problem statement + +The RFC 0023 Policy contract candidate introduces `formatVersion: "1.0.0"` and +`workspace-managed` ownership intent. It remains proposed at draft maturity, +outside adopted specification and conformance artifacts. Existing Runtime +consumers strictly decode prototype reports; even an additive default field +would break their discovery and authoring flows. + +## Decision drivers + +- Preserve prototype 0.0.2 source bytes, provenance, reports and default discovery. +- Share exact-byte, anchor, material and typed Pack checks across both formats. +- Follow the candidate's finite result codes and ordered refusal phases. +- Keep current authority, source acquisition, signatures and evaluation outside Runtime. + +## Considered options + +- Replace the prototype grammar or silently migrate candidate bytes to it. +- Duplicate the Policy checking engine for the candidate. +- Add explicit dispatch and optional discovery around the shared offline engine. + +## Decision outcome + +Chosen option: explicit format dispatch around the shared engine. Candidate +artifacts are separately vendored from immutable Spec commit +`4406cec9714ab9bc8e8971237cc79d58682cc904`, with a complete per-file provenance +manifest and independent manifest digest test. Prototype files and ADR-0059 +remain unchanged. This record adopts no normative Policy format. + +The no-argument CLI/MCP contract remains exactly the prototype contract. +`contract --all-formats` and MCP `{allFormats:true}` explicitly request a separate +`registryVersion: "1"` report. An optional exact format selector requests a +single contract; the two discovery selectors are mutually exclusive. Init/schema +continue requiring explicit kind and format. Supplied documents dispatch by +their selector; an optional operation selector permits candidate classification +of malformed or missing document selectors without changing legacy refusals. +No document is silently migrated or tried against an older grammar. + +Candidate reports identify their own provenance and `proposed-draft` maturity, +carry the exact candidate capability artifact, and add `formatVersion`. +Candidate full checks alone add `candidateResult`: exactly the portable valid or +refusal object. Canonicalize/digest check encoding and identity; validate checks +document forms and local references. Neither narrower operation claims a full +retained-material check. Runtime retains invalid exit 1 and unsupported exit 2; +the nested candidate result supplies the portable code. Environment failures +produce no candidate result. + +Full checks measure/parse/select/canonicalize the root before registration count +and ordered material registration, then check its kind/schema and semantics. +Retained Policy references require the adopting candidate's exact format. +Resolution checks original raw bytes before parsing or optional canonical +identity, and Core structural validation receives the original Pack bytes. +Source and narrative bytes, registrations under distinct media types, consuming +role bounds and typed Pack references remain shared checks. + +The private Runtime base64 material transport remains separate from portable raw +vector inputs. Its 24 MiB material JSON ceiling and MCP's 16 MiB request-line +ceiling remain unchanged. Repeated registrations of identical large bytes can +fit the candidate's distinct-byte budget while exceeding an encoded transport +ceiling. The portable harness therefore uses the same shared post-parse checks +and raw registration function, acquires sources lazily in declaration order and +stops on the first failure. Passing all 104 vectors promises no larger wire +envelope, authority, conformance or independent implementation agreement. + +### Consequences + +- Existing strict prototype clients retain their default contract and reports. +- Candidate users opt into a proposed contract with explicit provenance and refusal scope. +- Shared checks must preserve format-specific phase ordering as well as byte identity. +- Revisit when RFC review adopts or replaces this candidate and the owning host contracts settle publication and current admission. + +## Material decision and review + +Material-decision impact categories: `public-surface`, `documented-claim`, +`security`, `dependency`. The candidate selector, explicit discovery and typed +results extend a public surface; vendored candidate artifacts add a dependency +boundary; ordered bounded input handling concerns the security posture. + +The maintainer authorized a temporary different-vendor review waiver for this +current Policy work. OpenAI/Codex implementation and any OpenAI/Codex adversarial +review are same-vendor work under that waiver, never different-vendor review or +independently authored interoperability evidence. Review records must identify +the reviewed commit and maintainer dispositions. The waiver changes no standing +repository requirement. This record remains proposed pending that procedural +disposition. + +## More information + +- [Prototype decision](0059-experimental-offline-policy-tools.md) +- [Offline Policy architecture](../architecture.md#experimental-offline-policy-prototype) +- [Candidate source and provenance](../../internal/policy/candidate/provenance.json) diff --git a/docs/adr/README.md b/docs/adr/README.md index 8c5c84f0..79e9be7e 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -155,3 +155,4 @@ authority, and following it confers no conformance status on anything. | [0056](0056-version-3-dialect-authoring.md) | Check supported version-3 Dialect declarations through shared authoring tools | accepted | | [0057](0057-named-dialect-artifact-identity.md) | Share offline tools for named Dialect artifacts | accepted | | [0059](0059-experimental-offline-policy-tools.md) | Prototype Policy document and retained-reference checks offline | accepted | +| [0060](0060-explicit-policy-candidate-format.md) | Add an explicit Policy contract candidate without changing prototype clients | proposed | diff --git a/docs/architecture.md b/docs/architecture.md index df3f5f28..ee653d1a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -48,6 +48,26 @@ number domain. Source/schema/example provenance pins specification revision resource is fetched at runtime. The shared 16 MiB stdio line bound is unchanged, so JSON/base64 overhead reduces the maximum retained material a call can carry. +The proposed-draft, unadopted Policy contract candidate `1.0.0` is an additional +explicit format ([ADR-0060](adr/0060-explicit-policy-candidate-format.md)). Its +schemas, prose, examples and 104 portable vectors are pinned separately to Spec +commit `4406cec9714ab9bc8e8971237cc79d58682cc904`. Format selection, schema and +provenance differ; material identity, UTF-8 anchors and typed Pack coverage use +the same engine. Candidate adoption cannot consume prototype Policy bytes. +No-argument contract discovery and prototype reports retain their exact prior +shape for strict clients. All-format discovery requires explicit CLI +`--all-formats` or MCP `allFormats:true` and returns registry version 1. + +Candidate full checks return a bounded `candidateResult` with exactly the +portable status/code object, separate from Runtime diagnostics and exit status. +Root physical bounds, strict JSON, selection and canonical numeric domain precede +ordered registration; root schema and semantic checks follow registration. +Portable tests defer source acquisition to its phase and use shared raw +registration directly. Duplicate media registrations count bytes once but may +repeat base64 on the wire, so candidate agreement never widens the private +24 MiB material JSON or 16 MiB MCP ceiling. No candidate result establishes +current authority, permission, publication, review trust or independent agreement. + ## Artifact version arithmetic `internal/artifactversion` owns exact three-component parsing, comparison and diff --git a/docs/mcp-clients.md b/docs/mcp-clients.md index b3860294..cf853616 100644 --- a/docs/mcp-clients.md +++ b/docs/mcp-clients.md @@ -499,3 +499,42 @@ limit: base64 expands retained bytes and JSON string escaping, document text and RPC framing consume more space. Consequently, not every bundle under the 16 MiB retained-byte limit fits a single MCP request. A client must bound the complete encoded request; CLI named-file input supports the larger material JSON envelope. + +### Explicit proposed-draft candidate selection + +The seven existing tools also serve the unadopted Policy contract candidate +`1.0.0`, at `proposed-draft` maturity, pinned to Spec commit +`4406cec9714ab9bc8e8971237cc79d58682cc904` +([ADR-0060](adr/0060-explicit-policy-candidate-format.md)). Calling contract +without arguments or with `{}` returns the exact existing prototype report. +`{allFormats:true}` explicitly requests the separate registry version 1; +`{formatVersion:"1.0.0"}` selects the candidate contract. These two arguments +are mutually exclusive. `{formatVersion:"0.0.2"}` selects the prototype contract. + +Init/schema require the exact selected `formatVersion` as before. Document tools +accept an optional `formatVersion` string for explicit dispatch, including +candidate classification of malformed or selector-less bytes. The document +still must carry its own exact selector; no tool inserts or rewrites it. +Without an operation selector, a document carrying `formatVersion` dispatches +to the candidate; existing prototype documents retain their behavior. Candidate +Policies use `workspace-managed` or `externally-managed`, never an alias of the +prototype's `desk-managed`. Candidate adoption requires candidate Policy bytes. + +Candidate reports include their own `formatVersion`, source provenance, maturity +and exact `candidateCapabilities` artifact. Only full candidate checks add +`candidateResult`, exactly the portable valid object +`{status:"valid",formatVersion:"1.0.0",maturity:"proposed-draft"}` or refusal +`{status:"refused",code:"…"}`. Their bounded finite codes follow the +[pinned candidate contract](../internal/policy/candidate/README.md#5-resource-limits-and-refusal-classifications). +Encoding/local validation omit that field; operational failures supply no +candidate result. MCP sets `isError:true` on refusals. Neither result format +asserts current authority, permission, trusted review or standard conformance. + +Candidate physical bounds and strict JSON parsing precede selector/canonical +checks, then ordered registration precedes document schema and reference checks. +Retained artifact byte pins are checked before parsing and optional canonical +identity. Pack bytes go unchanged to Core structural validation. The private +material carrier and the 16 MiB stdio request ceiling remain unchanged; duplicate +base64 registrations can exceed a transport ceiling even when their distinct +retained bytes fit the candidate. Passing portable raw-input vectors therefore +promises no larger encoded envelope or independent interoperability evidence. diff --git a/internal/cli/policy.go b/internal/cli/policy.go index b4a953aa..6976763a 100644 --- a/internal/cli/policy.go +++ b/internal/cli/policy.go @@ -13,8 +13,8 @@ import ( func (a *App) policyCommand() *cobra.Command { group := &cobra.Command{ - Use: "policy", Short: "EXPERIMENTAL: offline nonnormative Policy prototype tools", - Long: "Offline tools for the nonnormative RFC 0023 Policy prototype, exact format 0.0.2. Validate checks document forms and local references. Check also checks the exact supplied retained-material closure and specific Core references; it does not perform full Core semantic validation or evaluate anything. No approval, governing-adoption authority, publication, billing or source access is established. This experimental surface may change without compatibility promise.", + Use: "policy", Short: "EXPERIMENTAL: offline Policy prototype and proposed-draft candidate tools", + Long: "Offline tools for the nonnormative RFC 0023 Policy prototype 0.0.2 and unadopted proposed-draft candidate 1.0.0. Discover candidates explicitly with contract --all-formats; no-argument contract retains the prototype contract. Validate checks document forms and local references. Check also checks the exact supplied retained-material closure and specific Core references; it does not perform full Core semantic validation or evaluate anything. No approval, governing-adoption authority, publication, billing or source access is established. This experimental surface may change without compatibility promise.", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Help() }, } for _, operation := range []string{"contract", "init", "schema", "canonicalize", "digest", "validate", "check"} { @@ -25,18 +25,19 @@ func (a *App) policyCommand() *cobra.Command { func (a *App) policyOperation(operation string) *cobra.Command { format, kind, profileVersion, id, version, materialsPath := "human", "", "", "", "", "" + allFormats := false use, args := operation, cobra.NoArgs if operation == "canonicalize" || operation == "digest" || operation == "validate" || operation == "check" { use += " " args = cobra.ExactArgs(1) } descriptions := map[string]string{ - "contract": "Describe exact prototype capabilities, limits and pinned provenance", + "contract": "Describe capabilities and pinned provenance; opt into candidate discovery explicitly", "init": "Print a starter template; missing retained materials remain unchecked", - "schema": "Print the schema for an explicitly selected prototype kind and format", + "schema": "Print the schema for an explicitly selected Policy kind and format", "canonicalize": "Print canonical document bytes; encoding success is not validation", "digest": "Print the canonical document digest; raw-byte identity is separate", - "validate": "Check prototype document forms and local references offline", + "validate": "Check selected Policy document forms and local references offline", "check": "Check exact supplied retained materials and references offline", } c := &cobra.Command{Use: use, Short: descriptions[operation], Args: args, RunE: func(cmd *cobra.Command, operands []string) error { @@ -53,11 +54,25 @@ func (a *App) policyOperation(operation string) *cobra.Command { if operation == "init" && (!cmd.Flags().Changed("id") || !cmd.Flags().Changed("version")) { return a.operational(command, format, result.ExitInvocation, "JPS-POLICY-IDENTITY", "Init requires explicit --id and --version.") } + if operation == "contract" && cmd.Flags().Changed("all-formats") && cmd.Flags().Changed("format-version") { + return a.operational(command, format, result.ExitInvocation, "JPS-POLICY-SELECTOR", "Use either --all-formats or --format-version.") + } + if cmd.Flags().Changed("format-version") && profileVersion == "" && operation != "init" && operation != "schema" { + return a.operational(command, format, result.ExitInvocation, "JPS-POLICY-SELECTOR", "Provide a nonempty exact format version.") + } var report policy.Report + var registry *policy.Registry code := result.ExitSuccess switch operation { case "contract": - report = policy.Contract(command) + if allFormats { + r := policy.AllFormats(command) + registry = &r + } else if cmd.Flags().Changed("format-version") { + report, code = policy.ContractFormat(command, profileVersion) + } else { + report = policy.Contract(command) + } case "init": report, code = policy.Init(command, kind, profileVersion, id, version) case "schema": @@ -71,11 +86,11 @@ func (a *App) policyOperation(operation string) *cobra.Command { } switch operation { case "canonicalize": - report, code = policy.Canonicalize(command, data) + report, code = policy.CanonicalizeFormat(command, data, profileVersion) case "digest": - report, code = policy.Digest(command, data) + report, code = policy.DigestFormat(command, data, profileVersion) case "validate": - report, code = policy.Validate(command, data) + report, code = policy.ValidateFormat(command, data, profileVersion) case "check": materials, err := a.readInput(materialsPath, policy.MaxMaterialsWireBytes, "retained materials") if errors.Is(err, fssecure.ErrTooLarge) { @@ -83,11 +98,15 @@ func (a *App) policyOperation(operation string) *cobra.Command { } else if err != nil { return a.operational(command, format, result.ExitIO, "JPS-POLICY-MATERIALS-READ", "The retained-material input could not be read as a bounded local regular file or standard input.") } - report, code = policy.Check(command, data, materials, a.engine) + report, code = policy.CheckFormat(command, data, materials, a.engine, profileVersion) } } if format == "json" { - if err := a.writeJSON(report); err != nil { + var payload any = report + if registry != nil { + payload = *registry + } + if err := a.writeJSON(payload); err != nil { return &handledExit{code: result.ExitIO} } } else if code != result.ExitSuccess { @@ -100,15 +119,29 @@ func (a *App) policyOperation(operation string) *cobra.Command { var err error switch operation { case "contract": - _, err = fmt.Fprintf(a.out, "Policy tools · EXPERIMENTAL · nonnormative prototype %s\nSpecification: %s\nKinds: policy, governing-adoption\nOperations: contract, init, schema, canonicalize, digest, validate, check\nValidate checks document forms and local references. Check checks exact supplied retained materials and specific Core references, without full Core semantic validation or evaluation.\nNo approval, governing-adoption authority or standard conformance is established.\n", policy.PrototypeVersion, policy.SpecURL) + if registry != nil { + _, err = fmt.Fprintf(a.out, "Policy format registry 1 · EXPERIMENTAL\n0.0.2 · nonnormative prototype · %s\n1.0.0 · proposed-draft candidate, unadopted · %s\nSelect a format explicitly for init/schema. No authority or conformance is established.\n", policy.SpecURL, policy.CandidateURL) + } else if report.FormatVersion == policy.CandidateVersion { + _, err = fmt.Fprintf(a.out, "Policy candidate %s · EXPERIMENTAL · proposed-draft, unadopted\nSpecification: %s\nKinds: policy, governing-adoption\nNo approval, current authority or standard conformance is established.\n", report.FormatVersion, report.Specification) + } else { + _, err = fmt.Fprintf(a.out, "Policy tools · EXPERIMENTAL · nonnormative prototype %s\nSpecification: %s\nKinds: policy, governing-adoption\nOperations: contract, init, schema, canonicalize, digest, validate, check\nValidate checks document forms and local references. Check checks exact supplied retained materials and specific Core references, without full Core semantic validation or evaluation.\nNo approval, governing-adoption authority or standard conformance is established.\n", policy.PrototypeVersion, policy.SpecURL) + } case "schema": _, err = fmt.Fprint(a.out, report.Resource.Text) case "digest": _, err = fmt.Fprintln(a.out, report.CanonicalDigest) case "validate": - _, err = fmt.Fprintln(a.out, "Prototype document and local-reference checks passed. Retained materials were not checked; no authority is established.") + if report.FormatVersion == policy.CandidateVersion { + _, err = fmt.Fprintln(a.out, "Proposed-draft candidate document and local-reference checks passed. Retained materials were not checked; no authority is established.") + } else { + _, err = fmt.Fprintln(a.out, "Prototype document and local-reference checks passed. Retained materials were not checked; no authority is established.") + } case "check": - _, err = fmt.Fprintln(a.out, "Prototype retained-material and reference checks passed. Full Core semantics and evaluation were not checked; no authority is established.") + if report.FormatVersion == policy.CandidateVersion { + _, err = fmt.Fprintln(a.out, "Proposed-draft candidate retained-material and reference checks passed. Full Core semantics and evaluation were not checked; no authority is established.") + } else { + _, err = fmt.Fprintln(a.out, "Prototype retained-material and reference checks passed. Full Core semantics and evaluation were not checked; no authority is established.") + } case "init": _, err = fmt.Fprintln(a.errOut, "Starter template: retained materials are missing and unchecked; no publication or authority is established.") if err == nil { @@ -129,11 +162,14 @@ func (a *App) policyOperation(operation string) *cobra.Command { c.Flags().StringVar(&format, "format", format, "output format: human or json; JSON includes scope and provenance") if operation == "init" || operation == "schema" { c.Flags().StringVar(&kind, "kind", "", "required exact kind: policy or governing-adoption") - c.Flags().StringVar(&profileVersion, "format-version", "", "required exact nonnormative prototype format: 0.0.2") + } + c.Flags().StringVar(&profileVersion, "format-version", "", "exact format: prototype 0.0.2 or proposed-draft candidate 1.0.0; required for init/schema, optional explicit dispatch otherwise") + if operation == "contract" { + c.Flags().BoolVar(&allFormats, "all-formats", false, "explicitly discover all formats in registry version 1") } if operation == "init" { c.Flags().StringVar(&id, "id", "", "required absolute artifact URI identifier") - c.Flags().StringVar(&version, "version", "", "required exact three-component artifact version; separate from prototype format") + c.Flags().StringVar(&version, "version", "", "required exact three-component artifact version; separate from Policy format") } if operation == "check" { c.Flags().StringVar(&materialsPath, "materials", "", "required retained-material JSON file or -; private Runtime byte transport, not a release envelope") diff --git a/internal/cli/policy_candidate_test.go b/internal/cli/policy_candidate_test.go new file mode 100644 index 00000000..2319e9be --- /dev/null +++ b/internal/cli/policy_candidate_test.go @@ -0,0 +1,188 @@ +package cli + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "os" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/Judgment-Pack/judgment-pack-runtime/internal/conformance" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/mcp" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/policy" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/validation" +) + +func candidateCLIBytes(t *testing.T, name string) string { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "policy", "candidate", "examples", "refunds", name)) + if err != nil { + t.Fatal(err) + } + return string(raw) +} + +func candidateCLIWire(t *testing.T) string { + t.Helper() + var manifest struct { + Materials []struct { + Path string `json:"path"` + Content any `json:"content"` + } `json:"materials"` + } + if err := json.Unmarshal([]byte(candidateCLIBytes(t, "fixture.json")), &manifest); err != nil { + t.Fatal(err) + } + entries := []any{} + for _, entry := range manifest.Materials { + entries = append(entries, map[string]any{"content": entry.Content, "dataBase64": base64.StdEncoding.EncodeToString([]byte(candidateCLIBytes(t, entry.Path)))}) + } + raw, err := json.Marshal(map[string]any{"materials": entries}) + if err != nil { + t.Fatal(err) + } + return string(raw) +} + +func candidateMCPReply(t *testing.T, name string, args map[string]any) (map[string]any, bool) { + t.Helper() + engine, err := validation.NewEngine() + if err != nil { + t.Fatal(err) + } + request, err := json.Marshal(map[string]any{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": map[string]any{"name": name, "arguments": args}}) + if err != nil { + t.Fatal(err) + } + var out, logs bytes.Buffer + if err := mcp.NewServer(engine, conformance.NewRunner(engine)).Serve(bytes.NewReader(append(request, '\n')), &out, &logs); err != nil { + t.Fatal(err) + } + var response struct { + Result struct { + Structured map[string]any `json:"structuredContent"` + IsError bool `json:"isError"` + } `json:"result"` + } + if err := json.Unmarshal(out.Bytes(), &response); err != nil { + t.Fatal(err) + } + return response.Result.Structured, response.Result.IsError +} + +func TestPolicyCandidateCLIAndMCPParity(t *testing.T) { + materialPath := filepath.Join(t.TempDir(), "materials.json") + if err := os.WriteFile(materialPath, []byte(candidateCLIWire(t)), 0600); err != nil { + t.Fatal(err) + } + for _, tc := range []struct { + operation, document, refusal string + exit int + }{ + {"canonicalize", candidateCLIBytes(t, "policy.json"), "", 0}, + {"digest", candidateCLIBytes(t, "adoption.json"), "", 0}, + {"validate", candidateCLIBytes(t, "policy.json"), "", 0}, + {"check", candidateCLIBytes(t, "adoption.json"), "", 0}, + {"check", `{}`, "invalid-selector", 1}, + {"check", `{"formatVersion":"7.0.0","n":1.5}`, "unsupported-format", 2}, + {"check", `{"formatVersion":"1.0.0","n":1.5}`, "invalid-document", 1}, + {"check", strings.Repeat("[", 33), "input-over-bound", 2}, + } { + t.Run(tc.operation+"/"+tc.refusal, func(t *testing.T) { + args := []string{"experimental", "policy", tc.operation, "-", "--format", "json", "--format-version", policy.CandidateVersion} + input := map[string]any{"document": tc.document, "formatVersion": policy.CandidateVersion} + if tc.operation == "check" { + args = append(args, "--materials", materialPath) + input["materials"] = candidateCLIWire(t) + } + exit, stdout, stderr := runTest(t, args, tc.document) + if exit != tc.exit || stderr != "" { + t.Fatalf("exit %d stdout %s stderr %s", exit, stdout, stderr) + } + var actual map[string]any + if err := json.Unmarshal([]byte(stdout), &actual); err != nil { + t.Fatal(err) + } + other, isError := candidateMCPReply(t, "experimental_policy_"+tc.operation, input) + if isError != (exit != 0) { + t.Fatal("MCP error status") + } + delete(actual, "command") + delete(other, "command") + if !reflect.DeepEqual(actual, other) { + t.Fatalf("candidate CLI/MCP mismatch\n%v\n%v", actual, other) + } + if actual["specRevision"] != policy.CandidateRevision || actual["maturity"] != "proposed-draft" { + t.Fatal("candidate provenance") + } + if tc.operation == "check" { + result := actual["candidateResult"].(map[string]any) + if tc.refusal != "" && result["code"] != tc.refusal { + t.Fatal(result) + } + } else if actual["candidateResult"] != nil { + t.Fatal("narrower operation claimed full check") + } + }) + } + for _, operation := range []string{"validate", "check"} { + args := []string{"experimental", "policy", operation, "-"} + if operation == "check" { + args = append(args, "--materials", materialPath) + } + exit, stdout, stderr := runTest(t, args, candidateCLIBytes(t, "policy.json")) + if exit != 0 || stderr != "" || !strings.Contains(stdout, "Proposed-draft candidate") { + t.Fatalf("candidate human output %d %s %s", exit, stdout, stderr) + } + } +} + +func TestPolicyExplicitContractDiscoveryParity(t *testing.T) { + for _, tc := range []struct { + flags []string + input map[string]any + registry bool + }{ + {nil, map[string]any{}, false}, + {[]string{"--all-formats"}, map[string]any{"allFormats": true}, true}, + {[]string{"--format-version", policy.CandidateVersion}, map[string]any{"formatVersion": policy.CandidateVersion}, false}, + } { + args := append([]string{"experimental", "policy", "contract", "--format", "json"}, tc.flags...) + exit, stdout, stderr := runTest(t, args, "") + if exit != 0 || stderr != "" { + t.Fatal(exit, stdout, stderr) + } + var actual map[string]any + if err := json.Unmarshal([]byte(stdout), &actual); err != nil { + t.Fatal(err) + } + other, isError := candidateMCPReply(t, "experimental_get_policy_contract", tc.input) + if isError { + t.Fatal(other) + } + delete(actual, "command") + delete(other, "command") + if tc.registry { + for _, result := range []map[string]any{actual, other} { + for _, format := range result["formats"].([]any) { + delete(format.(map[string]any), "command") + } + } + } + if !reflect.DeepEqual(actual, other) { + t.Fatalf("discovery mismatch %v %v", actual, other) + } + if len(tc.flags) == 0 && (actual["formatVersion"] != nil || actual["candidateCapabilities"] != nil || actual["registryVersion"] != nil || actual["specRevision"] != policy.SpecRevision) { + t.Fatal("legacy contract changed", actual) + } + } + for _, flags := range [][]string{{"--all-formats", "--format-version", "1.0.0"}, {"--format-version", ""}} { + exit, _, _ := runTest(t, append([]string{"experimental", "policy", "contract"}, flags...), "") + if exit != 3 { + t.Fatal("selector conflict accepted") + } + } +} diff --git a/internal/mcp/policy.go b/internal/mcp/policy.go index 28017d28..d2f5a993 100644 --- a/internal/mcp/policy.go +++ b/internal/mcp/policy.go @@ -17,19 +17,19 @@ func policyToolName(operation string) string { func policyDefinition(operation string) map[string]any { descriptions := map[string]string{ - "contract": "Discover the pinned nonnormative RFC 0023 Policy prototype 0.0.2: exact kinds, capabilities and limits. Experimental; no project reads, persistence, evaluation or authority.", - "init": "Return a nonnormative Policy prototype starter template for an explicitly selected kind, format and identity. Retained materials are missing and unchecked. The client saves it; no publication, approval or governing-adoption authority is established.", - "schema": "Return a self-contained Runtime editing schema derived from pinned nonnormative prototype resources for an explicit kind and exact format 0.0.2. Use validate for strict document and local-reference checks. Offline; no project reads or writes.", - "canonicalize": "Return canonical Policy prototype document bytes and separate canonical/raw byte digests. Encoding success is not document validation, retained-material verification or authority. Experimental; no files read or written.", - "digest": "Return the canonical Policy prototype digest and separate raw-byte identity. Encoding success is not validation or authority. Experimental; no files read or written.", - "validate": "Check exact Policy prototype document JSON for strict forms, schema and local references. Does not check retained materials, full Core semantics, evaluation, approval or governing-adoption authority. Experimental; no files read or written.", - "check": fmt.Sprintf("Check the exact supplied Policy prototype document and retained-material closure, raw byte identities, structural Core packs and specific references. Does not run full Core semantic validation, evaluate, fetch sources, publish, approve or establish governing-adoption authority. Both arguments are exact JSON text strings, never paths or URLs. Materials use a private Runtime byte transport, not a portable release envelope. The unchanged %d-byte stdio request limit includes its delimiter and JSON/base64 overhead, so not every bundle under the retained-byte limit fits MCP.", maxMessageBytes), + "contract": "With no selectors, discover the unchanged pinned RFC 0023 prototype 0.0.2. Explicit allFormats:true discovers registry version 1; formatVersion selects one contract, mutually exclusive. Candidate 1.0.0 is proposed-draft and unadopted. Reports exact kinds, capabilities and limits. Experimental; no project reads, persistence, evaluation or authority.", + "init": "Return a nonnormative Policy companion starter template for an explicitly selected kind, format and identity. Retained materials are missing and unchecked. The client saves it; no publication, approval or governing-adoption authority is established.", + "schema": "Return a self-contained Runtime editing schema derived from pinned nonnormative prototype resources for an explicit kind and explicit prototype 0.0.2 or proposed-draft candidate 1.0.0. Use validate for strict document and local-reference checks. Offline; no project reads or writes.", + "canonicalize": "Return canonical Policy companion document bytes and separate canonical/raw byte digests. Encoding success is not document validation, retained-material verification or authority. Experimental; no files read or written.", + "digest": "Return the canonical Policy companion digest and separate raw-byte identity. Encoding success is not validation or authority. Experimental; no files read or written.", + "validate": "Check exact Policy companion document JSON for strict forms, schema and local references. Does not check retained materials, full Core semantics, evaluation, approval or governing-adoption authority. Experimental; no files read or written.", + "check": fmt.Sprintf("Check the exact supplied Policy companion document and retained-material closure, raw byte identities, structural Core packs and specific references. Does not run full Core semantic validation, evaluate, fetch sources, publish, approve or establish governing-adoption authority. Both arguments are exact JSON text strings, never paths or URLs. Materials use a private Runtime byte transport, not a portable release envelope. The unchanged %d-byte stdio request limit includes its delimiter and JSON/base64 overhead, so not every bundle under the retained-byte limit fits MCP.", maxMessageBytes), } properties := map[string]any{} schema := map[string]any{"type": "object", "additionalProperties": false, "properties": properties} if operation == "init" || operation == "schema" { properties["kind"] = map[string]any{"type": "string", "enum": []string{"policy", "governing-adoption"}} - properties["formatVersion"] = map[string]any{"type": "string", "enum": []string{policy.PrototypeVersion}, "description": "Exact nonnormative prototype version; no stable Policy format is selected by default."} + properties["formatVersion"] = map[string]any{"type": "string", "enum": []string{policy.PrototypeVersion, policy.CandidateVersion}, "description": "Exact prototype 0.0.2 or unadopted proposed-draft candidate 1.0.0; no format is selected by default."} schema["required"] = []string{"kind", "formatVersion"} if operation == "init" { properties["id"] = map[string]any{"type": "string", "description": "Explicit absolute artifact URI identifier."} @@ -41,6 +41,12 @@ func policyDefinition(operation string) map[string]any { properties["document"] = map[string]any{"type": "string", "maxLength": policy.MaxDocumentBytes, "description": fmt.Sprintf("Exact document JSON text, never a path. Maximum %d UTF-8 bytes after transport decoding.", policy.MaxDocumentBytes)} schema["required"] = []string{"document"} } + if operation == "contract" { + properties["allFormats"] = map[string]any{"type": "boolean", "description": "Explicit opt-in to registry version 1; mutually exclusive with formatVersion."} + } + if operation != "init" && operation != "schema" { + properties["formatVersion"] = map[string]any{"type": "string", "description": "Optional exact format selection: 0.0.2 prototype or 1.0.0 proposed-draft candidate. Candidate selection also classifies malformed/missing document selectors. No automatic migration."} + } if operation == "check" { properties["materials"] = map[string]any{"type": "string", "maxLength": policy.MaxMaterialsWireBytes, "description": fmt.Sprintf("Exact retained-material JSON text: {materials:[{content:{bytesDigest,byteLength,mediaType},dataBase64}]}. No paths/URLs. Maximum decoded JSON text %d bytes; stdio's %d-byte line limit can be reached first after JSON/base64 overhead.", policy.MaxMaterialsWireBytes, maxMessageBytes)} schema["required"] = []string{"document", "materials"} @@ -54,8 +60,39 @@ func (s *Server) toolPolicy(name string, args json.RawMessage) any { return toolError("Expected an arguments object; null is refused.") } if name == policyToolName("contract") { - if m := noArguments(name, args); m != "" { - return toolError("Policy contract accepts an empty arguments object only.") + if len(args) == 0 { + return toolResult(policy.Contract(command)) + } + if m := exactMembers(name, args, "allFormats", "formatVersion"); m != "" { + return toolError("Policy contract accepts only allFormats or formatVersion, each once.") + } + var input struct { + AllFormats *bool `json:"allFormats"` + FormatVersion *string `json:"formatVersion"` + } + var members map[string]json.RawMessage + if json.Unmarshal(args, &input) != nil || json.Unmarshal(args, &members) != nil || members == nil { + return toolError("Expected a Policy contract arguments object.") + } + if len(members) == 2 { + return toolError("Use either allFormats or formatVersion.") + } + if _, present := members["allFormats"]; present && input.AllFormats == nil { + return toolError("Expected allFormats as a Boolean.") + } + if _, present := members["formatVersion"]; present && input.FormatVersion == nil { + return toolError("Expected formatVersion as a string.") + } + if input.AllFormats != nil && *input.AllFormats { + return toolResult(policy.AllFormats(command)) + } + if input.FormatVersion != nil { + r, code := policy.ContractFormat(command, *input.FormatVersion) + reply := toolResult(r) + if code != 0 { + reply["isError"] = true + } + return reply } return toolResult(policy.Contract(command)) } @@ -87,7 +124,7 @@ func (s *Server) toolPolicy(name string, args json.RawMessage) any { report, code = policy.Init(command, *input.Kind, *input.FormatVersion, *input.ID, *input.Version) } } else { - members := []string{"document"} + members := []string{"document", "formatVersion"} if name == policyToolName("check") { members = append(members, "materials") } @@ -95,24 +132,39 @@ func (s *Server) toolPolicy(name string, args json.RawMessage) any { return toolError("Expected document and, for check, materials as exact JSON text strings only.") } var input struct { - Document *string `json:"document"` - Materials *string `json:"materials"` + Document *string `json:"document"` + FormatVersion *string `json:"formatVersion"` + Materials *string `json:"materials"` } if json.Unmarshal(args, &input) != nil || input.Document == nil { return toolError("Expected document as exact JSON text in a string.") } + var supplied map[string]json.RawMessage + if json.Unmarshal(args, &supplied) != nil { + return toolError("Expected Policy arguments object.") + } + if _, present := supplied["formatVersion"]; present && input.FormatVersion == nil { + return toolError("Expected formatVersion as a string.") + } + format := "" + if input.FormatVersion != nil { + format = *input.FormatVersion + if format == "" { + return toolError("Expected a nonempty exact formatVersion string.") + } + } switch name { case "experimental_policy_canonicalize": - report, code = policy.Canonicalize(command, []byte(*input.Document)) + report, code = policy.CanonicalizeFormat(command, []byte(*input.Document), format) case "experimental_policy_digest": - report, code = policy.Digest(command, []byte(*input.Document)) + report, code = policy.DigestFormat(command, []byte(*input.Document), format) case "experimental_policy_validate": - report, code = policy.Validate(command, []byte(*input.Document)) + report, code = policy.ValidateFormat(command, []byte(*input.Document), format) case "experimental_policy_check": if input.Materials == nil { return toolError("Expected materials as exact retained-material JSON text in a string.") } - report, code = policy.Check(command, []byte(*input.Document), []byte(*input.Materials), s.engine) + report, code = policy.CheckFormat(command, []byte(*input.Document), []byte(*input.Materials), s.engine, format) } } reply := toolResult(report) diff --git a/internal/mcp/policy_test.go b/internal/mcp/policy_test.go index 746c948d..ce2d1615 100644 --- a/internal/mcp/policy_test.go +++ b/internal/mcp/policy_test.go @@ -97,3 +97,21 @@ func TestPolicyWellTypedSelectorRefusals(t *testing.T) { } } } + +func TestPolicyCandidateDiscoveryStrictArguments(t *testing.T) { + for _, args := range []string{ + `{"allFormats":true,"formatVersion":"1.0.0"}`, `{"allFormats":null}`, `{"allFormats":"true"}`, + `{"AllFormats":true}`, `{"allFormats":true,"allFormats":true}`, `{"formatVersion":null}`, + } { + reply := runServer(t, rawToolCall(t, 1, "experimental_get_policy_contract", args))[0]["result"].(map[string]any) + if reply["isError"] != true || reply["structuredContent"] != nil { + t.Fatal(args, reply) + } + } + for _, args := range []string{`{"document":"{}","formatVersion":null}`, `{"document":"{}","FormatVersion":"1.0.0"}`} { + reply := runServer(t, rawToolCall(t, 1, "experimental_policy_validate", args))[0]["result"].(map[string]any) + if reply["isError"] != true || reply["structuredContent"] != nil { + t.Fatal(args, reply) + } + } +} diff --git a/internal/policy/candidate/0023-policy-companion.md b/internal/policy/candidate/0023-policy-companion.md new file mode 100644 index 00000000..7806a417 --- /dev/null +++ b/internal/policy/candidate/0023-policy-companion.md @@ -0,0 +1,362 @@ +# RFC 0023: Policy content and governing adoption + +- Status: Review +- Type: Standards track, proposed companion at draft maturity +- Created: 2026-10-17 +- Issue: [#211](https://github.com/Judgment-Pack/judgment-pack-spec/issues/211) + +This is an open proposal, not part of JPS. It adds no released schema, conformance +class or execution authority. The [candidate contract](policy-companion-contract/README.md) +proposes exact format `1.0.0` at draft maturity; it is not adopted by being written. +The historical [prototype](policy-companion-prototype/README.md) remains explicitly +non-normative and byte-for-byte frozen at proposal `0.0.2`, baseline commit +`8a56a95d555c17640d2db4984363b779536b3c2a`. Host integration guidance below names separate +product responsibilities; acceptance of this RFC would not adopt those products' +protocols on their behalf. + +## Summary + +Propose a small domain-neutral companion for retained policy content and its exact +governing relationship to a consuming pack. Preserve the pack/graph as executable +authority. Policy text, review assertions and adoption describe intent, provenance +and governance; they introduce no condition language and do not change evaluator +precedence. Optional readable structured requirements are deferred from the first +candidate, whose closed grammar refuses a `requirements` member. + +The proposed candidate supports pack consumers only. Composition with graphs needs +the relevant adopted graph contract and supporting hosts; this RFC does not +advertise standard Runner graph-job support. A Framework artifact is not required. +Collections can organize policies without implying dependency or priority. + +## Problem + +A policy may start as a document, be authored collaboratively, or be managed by +another system. It can remain effective while an executable interpretation is +developed or revised. A citation in a pack does not say whether that policy governs +execution, what exact policy version was interpreted, or what clauses remain +manual. A passing test does not establish complete coverage or approval. + +Products can store these relationships privately, but then a second consumer cannot +distinguish a governing dependency from an informational reference or reconstruct +what exact content a review covered. Putting current permissions or mutable +publication state into Core would turn a portable evaluator into a governance +service, and still would not prove that a historical statement remains current. + +The proposed boundary is immutable supplied-document meaning plus explicit limits. +The operational system owns authority and decides whether work may start now. + +## Evidence + +Three design cases motivate a shared form: + +1. **Data access.** A platform team imports a sharing policy, reviews its clauses + and implements release eligibility in a pack. Exact source/narrative bytes and + interpretation must survive export. Policy withdrawal needs a live host gate; + an offline content match cannot enforce it. +2. **Procurement.** An externally managed procurement policy publishes a new file + revision. The consumer retains its existing adoption while reviewing the new + revision. A changed file, missing file or access failure must not be inferred + to mean approved, published or withdrawn. +3. **Refunds.** A local Desk admin authors, reviews and publishes a policy alone. + The audit can truthfully record the same person performing those roles when + the configured workflow permits it. It must not claim independent approval. + Some clauses may remain manual; automated eligibility still lives in a pack. + +The prototype supplies synthetic retained material for these domains. It is +design evidence only: no production policy approval, live enforcement, external +connector run or independent implementation agreement is claimed. + +Existing Core sources/review metadata, retained Runtime/Runner artifacts and +Dialect provenance are prior boundaries to reuse, not proof this companion exists. +[RFC 0011](0011-judgment-currency-anchor.md) already explores retired pack versions +and an offline currency snapshot. It explicitly cannot establish real-time +currency or current authorization. This proposal does not adopt, supersede or move +that Draft's registry; its relationship to policy lifecycle remains a review item. +[RFC 0012](0012-witness-contract.md) and the accepted +[checkpoint witness companion](../spec/checkpoint-witness.md) concern supplied +history comparisons, not policy approval or a current permission to execute. + +## Specification + +### Proposed portable surface + +The surface consists of **Policy content** and **Governing adoption**. The +[review candidate](policy-companion-contract/README.md) supplies self-contained +proposed prose, closed schemas, a bounded offline checker/capability record, +three retained-byte domain examples and reusable static positive/refusal vectors. +Both documents require exact `formatVersion: "1.0.0"`, with `kind: "policy"` or +`kind: "governing-adoption"`. The separate strict `x.y.z` artifact `version` does +not select grammar. No shared-major inference or integer/legacy alias is allowed. +This selector is proposed, not adopted, released or stable. + +The frozen historical prototype uses its closed `prototype` wrapper with profile +`jps-policy-companion-prototype`, proposal `0.0.2` and status `non-normative`. +The candidate refuses that wrapper; no parser migration occurs. The +[explicit migration guide](policy-companion-contract/MIGRATION.md) preserves +source, narrative, interpretation and consumer bytes, requires new immutable +Policy/adoption identities and exact dependent references, retains originals and +requires dependent snapshot re-review. No approval or permission migrates. +The candidate's [prototype pin](policy-companion-contract/prototype-0.0.2-pin.json) +records the unchanged historical bytes. + +A Policy contains: + +- a stable absolute-URI identity, immutable artifact version and title; +- declared publication-management intent (`workspace-managed` or `externally-managed`), + which does not authenticate a publisher or import its authority; +- a reference to exact retained UTF-8 narrative bytes; +- stable section identities anchored by half-open UTF-8 byte ranges in that exact + narrative, plus explicit provenance references; +- retained original source references with provider/account/resource identity, + nullable opaque source revision and original content identity. + +The narrative can be authored directly or derived from original documents. +Original PDF/page/file bytes remain separate. An anchor in the narrative is not +an original-source offset, and a new extraction does not silently rewrite either. +No runtime conditions, live ACLs, publication states or approval booleans belong in +the immutable content. Optional readable structured requirements, including any +section-reference grammar, are deferred pending a concrete authoring/interchange +need and reference-check vectors. They are unsupported in the candidate. Any +future form must remain non-executable and requires an explicit selector change; +it must not introduce a second decision language. + +A Governing adoption contains its own identity/version, the exact consuming pack +reference and one or more exact policy references. Every governing reference +declares whole-policy or explicit section scope, and per-section coverage: + +| Coverage | Required interpretation | +| --- | --- | +| `implemented` | Exact typed consumer element references and retained interpretation/review basis | +| `manual` | Explicit responsible handoff/process | +| `awaiting-interpretation` | Unresolved meaning, with explanation | +| `awaiting-implementation` | Meaning agreed but automation not supplied, with explanation | +| `out-of-scope` | Explicit rationale; never silent omission | + +The candidate resolves `{kind: "rule", id}` to Core `rules[]` and +`{kind: "exception", id}` to Core `exceptions[]`. The singleton references +`{kind: "applicability"}` and `{kind: "fallback"}` identify the actual Core +`applicability` and `fallbackOutcome` members; they have no fabricated ID. Absent +members, unknown IDs, duplicate references within one coverage record and +kind/ID confusion refuse. Fallback must name a declared, uniquely identified +outcome. These references identify supplied elements; they do not prove correct +interpretation or full Core semantic conformance. Evidence requirements, outcomes, +condition subelements and escalation are unsupported coverage kinds, as are graph +consumers. A clause implemented through scope, exception or fallback can reference +that actual element without inventing a dummy rule or a manual process. + +Informational sources are separate and do not create governing dependencies. +Scope and coverage are declarations to be reviewed, not a language for conditional +authorization. Validation cannot prove that an organization declared every +applicable policy or that an interpretation is correct. + +### Identity and offline checks + +The proposed content reference is exact-byte SHA-256, byte length and media type. +Optional canonical document identity names its profile separately. Reuse the +existing [Dialect companion's `canon`](../spec/dialect.md) domain by explicit +reference: do not substitute JCS or preparation canonicalization. Existing pack +bytes are retained unchanged; no reserialization changes a pack's execution pin. + +Artifact versions use the same lexical discipline as +[RFC 0021](0021-dialect-artifact-identity.md): exactly three unsigned decimal +components, no leading zeros except `0`, no suffixes or coercion, and the existing +256-ASCII-character bound. The candidate adds no bump arithmetic, compatibility +inference or version-reservation service. Draft CAS revisions, source revisions, +artifact versions and lifecycle revisions are separate values. + +Readers check supported selectors, closed grammar, resource bounds, exact content +references, unique section identities, anchored UTF-8 boundaries and adoption +references within their declared scope. They refuse incomplete material rather +than silently treating it as approved. Identities are opaque references, not URLs +to fetch. Access and network acquisition require separate authority. + +Candidate bounds retain the prototype's role-specific limits: parsed JSON is at +most 262,144 bytes, retained narrative/review/informational material at most +1,048,576 bytes each, and retained +original source material at most 4,194,304 bytes each. The fixture carrier loads at +most 16,777,216 distinct retained bytes in total; multiple registered media types +for identical bytes count once. An unsupported original size refuses the complete +bundle. Truncation, extraction substitution and silently dropping the original do +not produce a complete bundle. The parsed-document depth limit is 32; number +literals are at most 128 characters +with exponent magnitude at most 308. The candidate declares these limits explicitly; +they are not adopted Core limits or a stable content-size promise. Its refusal +objects use fixed bounded codes, never raw content. A malformed/missing selector +is `invalid-selector`; a well-formed unsupported selector is `unsupported-format`. +Physical/schema resource maxima report `input-over-bound`, separately from +reference, anchor, coverage and other semantic failures. Capability discovery lists +exact candidate format, proposed-draft maturity, features, limits and exclusions. + +Consumer bytes are identified before adoption. A release can then bind the +consumer, adoption and supported dependency closure without circular hashes. +The host derives that closure from its reviewed registration, not from an +execution caller's possibly shortened list. Unsupported required composition +refuses. Policy citations alone cannot be upgraded into governing adoption. + +### Review assertions and trust boundary + +A review assertion needs the exact complete candidate, workflow revision, +reviewed scope/anchors, authenticated subject, decision time and authority basis. +Historical assertions cannot transfer silently to changed candidates. A section +approval does not replace an accountable whole-policy approval. Whether the same +local admin may author and approve is a workflow rule, not a universal spec ban. + +The authentication/signature/export trust profile is unresolved. The candidate +therefore carries an exact interpretation basis, **not** portable proof of an +authorized sign-off. A hash, imported document, test report or model statement +must not be interpreted as that proof. No review-assertion conformance class is +introduced by this draft. + +### Non-normative host integration boundaries + +These are required product design considerations, not APIs standardized here: + +| Boundary | Owning responsibility | +| --- | --- | +| Source observation | Gateway retains content/extraction and raw provider revision/lifecycle evidence; Desk interprets a configured authority mapping | +| Adoption | Desk records an authorized exact interpretation; Runtime checks supplied documents; Runner retains the registered dependency closure | +| Run/action admission | Desk's authoritative governance service decides current eligibility; Runner and actual action executors enforce at dispatch | +| Review/publication | Desk persists exact candidates, scoped sign-offs, immutable publication and idempotent receipts in transactional state | + +Source state needs delivery identity, opaque source revision, observation time, +availability, retained bytes and explicit history completeness. The same bytes +with a new lifecycle assertion are a new observation. Persist snapshots/effects +before advancing cursors; duplicate/out-of-order delivery and cursor loss require +reconciliation. A source update does not overwrite drafts, transfer signatures or +upgrade pinned jobs. An unresolved update known before publication participates in +publication CAS; an update observed afterward creates impact review. + +Publication, effectiveness, supersession, expiry and withdrawal are distinct. +Withdrawal defaults to blocking new dependent starts and later external actions. +The authority serializes withdrawal with start commitment: withdrawal first blocks +the start; commitment first admits the existing attempt. This is a logical +authorization boundary, not atomicity with a remote side effect or instantaneous +knowledge of unobserved upstream changes. Required unavailable/stale authority +holds new governed work. An already dispatched external action may be irreversible. + +An eligibility preview is not a dispatch grant. Executors bind durable attempt, +resource, payload, release and epoch identities before requesting a start. A +recovered receipt is history, not a reusable permission to dispatch. Lost responses, +crashes and restored backups require reconciliation/fencing; uncertain external +operations must not be replayed. Offline pinned snapshots cannot establish these +live guarantees, so the Runtime offline reader does not implement that service. + +Local Desk can be the authority for one admin's complete policy lifecycle. Team +identity, invitations and separate reviewers extend that host mode; they do not +need to be fabricated to enable honest single-person management. Gateway consumes +admission decisions at its action boundary and does not become policy authority. + +## Alternatives + +- **No change/product-only metadata:** sufficient for a private editor but leaves + cross-product policy identity, coverage and governing/citation distinctions + ambiguous. Keep IAM, review routing and live lifecycle product-owned regardless. +- **Core extension/profile:** would couple governance to evaluation and does not + supply a live authority. Existing packs must remain usable without policies. +- **Adopt a universal control format:** OSCAL and other domain formats can support + adapters, but requiring one narrows a domain-neutral product and introduces + unnecessary control semantics. No normative mappings are proposed here. +- **Make readable requirements authoritative:** creates competing execution + semantics. Defer optional readable requirements from this candidate; any later + form must keep the pack/graph authoritative. +- **Use only pack-version currency:** RFC 0011's offline membership question is + useful but different from policy content, adoption scope and current permissions. +- **Mandate frameworks:** organizing collections do not need another release type + or implicit policy priority. Revisit only for a concrete interoperability need. + +## Compatibility + +No Core, Dialect, preparation, graph or released conformance bytes change. The +0.0.2 prototype remains unchanged. Candidate documents are opt-in; unsupported +readers refuse them, and format compatibility cannot be inferred from artifact +version arithmetic. Migrating a citation to a governing +dependency is a reviewed new adoption, never automatic import behavior. + +Published policy content and consuming releases remain immutable. Renaming a +title or moving a folder does not change stored execution pins. A fork has a new +identity and fresh authority; imported approval history does not grant local roles. +Upgrading an existing job is explicit and retains historical runs. Supersession +alone does not declare every older pin ineligible; the adopted host rules decide. + +## Security and privacy + +Content identity does not establish truth, authority, current access or currency. +Prevent ambiguous JSON, oversized material, malformed versions, anchor substitution, +missing governing dependencies, imported approval booleans and cross-tenant +reference disclosure. Bound originals, narrative and interpretation separately. +Enforce current access in indexes, counts, exports and AI retrieval as well as pages. + +Model output can suggest content but cannot sign as an invited reviewer or change +test expectations merely to obtain passing outcomes. Restore of an old local store +cannot prove that no later withdrawal/revocation occurred. An unavailable external +file or failed sync is not itself withdrawal. Cryptographic signatures, if added, +will still need trusted identity and freshness rules; they do not resolve these +questions merely by verifying mathematically. + +## Conformance + +The candidate reader result is limited to supplied-document validity and reference +agreement under exact proposed format `1.0.0`. Its reusable manifest supplies +positive, refusal, boundary and adversarial vectors with exact expected objects, +including malformed/unsupported selectors, independent artifact versions, aliases, +missing or stale byte references, optional canonical identities, section anchors, +UTF-8 boundaries, scope/coverage mismatches and governing-versus-informational +references. Runtime or other ports can execute retained static bytes directly; the +only generation grammar repeats one declared byte for a declared length. + +The candidate and frozen prototype checks are experimental agreement aids, not +released corpus entries. +They must not be scored as proofs of authorization, complete policy coverage, +live admission or independent interoperability. + +Host acceptance tests belong in their owning repositories: source update racing +publication; same bytes with changed lifecycle; revoked reviewer/access after +indexing; dependency omission; withdrawal-before-start; start-before-withdrawal +followed by refused action; lost response recovery; worker fencing; and restore +from a pre-withdrawal backup. A signed historical snapshot cannot satisfy these +live tests by itself. + +## Implementation + +Spec owns the eventual portable companion, exact reference meanings and staged +vectors. Runtime should expose shared offline validation/canonical/reference +tooling only for an explicitly adopted or clearly experimental capability. Desk +owns local/team lifecycle, durable review transactions, sync state, Library and +shared UI/chat handlers. Gateway owns provider observations and execution-boundary +enforcement. Runner owns frozen releases, closure and current start admission. +Exchange can publish reusable definitions only after its entry contract supports +them; it does not store private tenant approvals. Demo and evaluator studies +exercise these boundaries without becoming alternate production services. + +Two plausible independently authored readers are a Runtime-backed local tool and +a separate organizational policy service validating exported bundles without Desk. +They would compare exact retained bytes and declared references and explicitly +decline live-authorization claims. Two language ports by this project's author +would not demonstrate independent authorship. That evidence is not available yet. + +The first product path is single-admin local policy management. Its explicit +review can be self-review; later team deployments can require another reviewer. +Manual and chat actions must share the existing execution/context/approval/CAS +boundaries. No feature-specific model loop, permission inference or retry service +is required by this RFC. + +## Unresolved questions + +1. Adoption/disposition of the exact proposed `1.0.0` selector, declared bounds and + closed reference/coverage grammar after public review; no released schema or + conformance class is assigned here. +2. Trust/signature/export profile for review assertions and cross-workspace adoption. +3. Reconciliation with RFC 0011's proposed pack currency registry without silently + adopting it or treating offline membership as live authorization. +4. First real sync provider and its demonstrable revision/lifecycle/freshness + semantics; document-read support alone is insufficient. +5. Host defaults for self-review versus independent review, quorum changes, + role-revocation effects on old signatures, expiry/grace and scheduled publication. +6. Supported graph/composition closure and its owning execution contract. +7. Independent implementation evidence and any domain-format adapter demand. + +Moving this RFC to `Review` requests public comment; it does not mark it +`Accepted` or waive the public-comment process. The candidate supplies no +cross-vendor adversarial-review record or independent implementation evidence. +Review-assertion trust, Graph support and adoption remain unresolved. This proposal +must not be described as adopted, stable or implementation-complete on that basis. diff --git a/internal/policy/candidate/LICENSE b/internal/policy/candidate/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/internal/policy/candidate/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/internal/policy/candidate/MIGRATION.md b/internal/policy/candidate/MIGRATION.md new file mode 100644 index 00000000..bebc5006 --- /dev/null +++ b/internal/policy/candidate/MIGRATION.md @@ -0,0 +1,56 @@ +# Explicit migration from prototype 0.0.2 + +This is a proposed, breaking migration to the **unadopted draft candidate** +`formatVersion: "1.0.0"`. Neither semver arithmetic nor opening a document consents +to migration. The candidate reader refuses prototype documents; it never upgrades +or reinterprets them. Prototype 0.0.1 needs its own explicit path to 0.0.2 and is +not silently accepted by this guide. + +1. Keep the original 0.0.2 Policy, adoption, fixture and all retained bytes. Record + their exact digests and the original prototype pin. Migration creates new + reviewable artifacts; it does not overwrite history. +2. Obtain explicit author/operator intent to migrate, including which exact Policy + versions, consuming Pack and adoption scope are intended. Explicitly choose + `workspace-managed` for former `desk-managed` content, or retain + `externally-managed` intent. Do not infer intent from an imported source's owner, + publisher, folder, citation, access response or approval history. +3. Preserve the source, narrative, interpretation/review-basis and consumer bytes + **exactly**, with their existing raw digest, length and declared media types. + Preserve anchors, local section/source IDs, opaque provider revisions and Pack + `specVersion`/identity. Do not extract, normalize, reserialize or rewrite those + files just to satisfy migration. Re-extraction or changed meaning is separate + authoring and requires a fresh review. +4. Construct a new Policy by removing the complete `prototype` wrapper and adding + the exact string `formatVersion: "1.0.0"`. Replace `desk-managed` with the + explicitly selected `workspace-managed`. Preserve the rest of the supported + content/provenance/sections. Choose the Policy's new immutable identity/version + explicitly: preserve its stable series ID only with a new artifact version, or + fork to a new ID. Never reuse an existing immutable `(id, version)` with changed + bytes. This offline checker cannot detect historical reuse on its own. +5. Serialize and retain those new Policy bytes. Regenerate the raw content digest + and length and, when requested, the `jps-canon` canonical identity. Update every + dependent adoption's exact Policy reference (ID, artifact version, bytes and + optional canonical digest); a stale old hash must refuse. Keep the exact Pack + bytes/reference; a different Pack is a separate new interpretation. +6. Construct a new adoption with `formatVersion: "1.0.0"` and no prototype wrapper. + Choose its immutable identity/version explicitly. Preserve or deliberately + re-review its exact scope and total coverage; do not fill omissions or upgrade + manual/pending/out-of-scope clauses automatically. Retain new adoption bytes, + regenerate their identities wherever referenced, and validate the full supplied + material under the candidate checker and vectors. +7. Re-review dependent release/registration/export snapshots that pin changed Policy + or adoption bytes. Keep historical snapshots and runs on their original pins. + A new snapshot is an explicit host operation, never a side effect of parsing or + importing a document. Host authority and current admission remain separate. + +No approval, signature, authenticated review assertion, role, permission, lifecycle +state, publication receipt or dispatch grant migrates automatically. Existing +review-basis bytes remain historical explanations only. Even if every narrative +byte and clause ID is unchanged, a host must obtain fresh applicable authorization +for its new candidate and workflow, under its own contract. Informational sources +stay informational; making one governing requires a reviewed new adoption. + +The three candidate examples intentionally use new Policy/adoption IDs and retain +the old consumer/source/narrative/interpretation files unchanged. Their new hashes +are reproducible examples, not migrated organizational approvals. There is no +migration helper or implicit parser fallback in this slice. diff --git a/internal/policy/candidate/NOTICE b/internal/policy/candidate/NOTICE new file mode 100644 index 00000000..da28de4b --- /dev/null +++ b/internal/policy/candidate/NOTICE @@ -0,0 +1,5 @@ +Judgment Pack Specification +Copyright 2026 Brian Jin + +This product includes specification artifacts developed by the Judgment Pack +project (https://github.com/Judgment-Pack/judgment-pack-spec). diff --git a/internal/policy/candidate/README.md b/internal/policy/candidate/README.md new file mode 100644 index 00000000..dbb2c720 --- /dev/null +++ b/internal/policy/candidate/README.md @@ -0,0 +1,318 @@ +# Proposed draft Policy companion contract 1.0.0 + +This is the review candidate for [RFC 0023](../0023-policy-companion.md) and +[Spec #211](https://github.com/Judgment-Pack/judgment-pack-spec/issues/211). +**Proposed only, at draft maturity; not adopted, stable, released, or a JPS +conformance class.** Writing `formatVersion: "1.0.0"` does not adopt a format. +Nothing here establishes approval, current authority, permission, currency, +source access, independent implementation agreement, or production fitness. +The RFC remains open for public comment and disposition under the repository's +process. No cross-vendor review or independent evidence is claimed here. + +The portable candidate consists of this prose, the closed +[Policy](policy.schema.json), [Governing adoption](governing-adoption.schema.json) +and [shared](common.schema.json) schemas, and the agreement +[vectors](vectors/manifest.json). These are deliberately outside the adopted +`spec/`, `schema/` and `conformance/` trees. Schema acceptance alone is insufficient: +the byte, anchor, reference and coverage checks below are also required. A conflict +between prose, schemas or vectors is a candidate defect, never an authorization. + +The historical [0.0.2 prototype](../policy-companion-prototype/README.md) remains +unchanged, including its checker, tests and all retained files. Its exact baseline +is commit `8a56a95d555c17640d2db4984363b779536b3c2a`, recorded file by file in +[prototype-0.0.2-pin.json](prototype-0.0.2-pin.json). This candidate derives the +immutable-content rules from that prototype, with its own schemas and checker. +It never imports prototype code. The [migration guide](MIGRATION.md) describes the +explicit, breaking transition; a reader never silently migrates an input. + +## 1. Exact selectors and immutable artifact identity + +A document has exactly one `formatVersion`, the **string** `"1.0.0"`, and `kind` +`"policy"` or `"governing-adoption"`. No prototype wrapper, `specVersion`, integer +selector, alias, suffix, coercion, or extension member is permitted. The schemas' +URNs identify local candidate schemas, not a network location or an adopted release. +Readers must dispatch on the whole selector before interpreting this grammar. + +The independent `version` names a revision of the immutable artifact, alongside +its absolute-URI `id`. It is exactly three unsigned ASCII decimal components +separated by dots: `0` or a nonzero digit followed by digits, with no leading zeros, +suffix, spaces or final newline, at most 256 characters. `0.0.0` and a 256-character +version are valid. No component arithmetic, bump policy, compatibility, reservation +or historical uniqueness is inferred. In particular, artifact `7.3.42` still uses +format `1.0.0`. Pack artifact references follow the same bounded version grammar; +the retained Pack keeps its own Core `specVersion` unchanged. + +An `id` is an opaque absolute URI, at most 2,048 Unicode characters. Identity is +not permission to fetch it. Local IDs match `[a-z][a-z0-9]*(?:-[a-z0-9]+)*`, at most +128 characters. Required readable text is nonempty and at most 4,096 characters. +Every defined object is closed: unknown members at any level are refused. + +## 2. Exact retained content and optional canonical identity + +A content reference is exactly `{bytesDigest, byteLength, mediaType}`. The digest +is lowercase `sha256:` plus 64 hexadecimal digits over the exact retained bytes, +including whitespace and final newlines. Length is the exact nonnegative integer +byte count, never a Boolean. It never hashes a URL or filename. Media type is a +lowercase token/token string under the shared schema, at most 128 characters, +without parameters. Artifact bytes require `application/json`; a Policy narrative +requires `text/plain` and valid UTF-8. Original bytes may be opaque, including PDF. + +Media type belongs to a reference and its registration, rather than to the digest +alone. Identical bytes can be registered as both `text/plain` narrative and +`text/markdown` original. Each reference must resolve under its declared media +type, hash and length; registering one type does not register another. Conflicting +bytes for one digest refuse. Distinct retained bytes count once toward the total +budget, even with multiple types or roles; each consuming role still applies its +own byte limit. Media-type declarations do not prove the content's actual type. + +An artifact reference is exactly `{kind, id, version, content}` with optional +`canonicalIdentity: {profile: "jps-canon", canonicalDigest}`. The only artifact +reference kinds in this candidate are `policy` and consuming `pack`, in their +specified positions. Exact bytes are always checked, even when canonical identity +is supplied. A canonical match never substitutes for the exact-byte pin. + +`jps-canon` reuses the existing [Dialect canonical form](../../spec/dialect.md), +which in turn references the checkpoint-witness form. It is not JCS or preparation +canonicalization. Objects sort names by Unicode code point; arrays retain order; +strings retain Unicode without normalization, with JSON escaping for quotes, +backslashes and controls; output is UTF-8 without insignificant whitespace. +Only integer JSON number literals whose magnitude is at most `9007199254740991` +are in this domain; `-0` canonically becomes `0`. Fractional or exponent literals +are outside this domain, even when mathematically integral. Companion documents +use this domain before schema checking; they retain their original bytes regardless. + +Core permits other JSON numbers in optional extensions. The checker reads Pack +numbers as raw literals and validates numeric values with exact decimal/integer +values, without binary-float rounding or rewriting execution bytes. A Core-valid +Pack outside `jps-canon` remains usable with its raw content reference alone. If +its reference requests canonical identity, it refuses as +`unsupported-canonical-identity`. Canonical identity is checked only when present. +Pack and companion strict JSON reading share the existing `tools/dialect_verify.py` +reader, including number-literal and nesting bounds; no Core limit or pin changes. + +## 3. Policy content, original provenance and sections + +A Policy requires `formatVersion`, `kind`, `id`, `version`, `title`, +`managementMode`, `content`, `sections` and `sourceProvenance`. +`managementMode` is `workspace-managed` or `externally-managed`. It declares +publication-management intent and authenticates no publisher, approval or role. +It is retained artifact provenance/ownership intent, not current host governance; +changing host management or authority does not mutate historical content. +The old `desk-managed` spelling is refused, not aliased. Importing content as a +local draft requires explicit intent; it does not import the source's approval. + +`content` identifies the exact retained narrative. Each of 1–64 sections has a +unique local `id`, readable `title`, and `anchor: {startByte, endByte, bytesDigest}`. +The anchor is a nonempty, zero-based, half-open range of UTF-8 bytes in **that +narrative**, with SHA-256 of the selected bytes. Both endpoints must be UTF-8 +boundaries and `0 <= startByte < endByte <= narrative length`. Anchors may overlap +and need not partition the narrative. Their validity does not prove that all +meaningful clauses were represented, or that stable IDs preserve meaning after a +revision. These offsets are never original PDF/page/provider-document offsets. + +Each of 0–16 unique original-source records requires a local `id`, +`source: {provider, accountId, resourceId}`, explicit `sourceRevision` and `content`. +The provider/account/resource values are readable opaque provenance, not +credentials or authenticated authority. `sourceRevision` is an opaque nonempty +string or explicit null when unavailable. Original bytes remain separate from +narrative/extraction bytes. The checker neither extracts nor interprets them. +Sections optionally carry 0–16 unique `sourceRefs`, each exactly +`{sourceId, location}`. `sourceId` must resolve to an original-source record; +`location` is a readable citation such as `Clause 2`, not a verified byte offset. + +Newly authored content may have no sources. No executable conditions, lifecycle, +ACLs, roles, publication states, signatures, review assertions or approval Booleans +belong in these immutable documents. Optional structured `requirements` are also +unsupported; even a claimed non-executable form is refused. A later form requires +review and an explicit selector decision, without adding a second decision language. + +## 4. Governing adoption and scoped total coverage + +An adoption requires `formatVersion`, `kind`, `id`, `version`, `consumer` and +`governingPolicies`. The consumer is one exact retained Core `0.2.0-draft` Pack. +The checker validates its existing structural schema and resolves the elements +below. This is no evaluation or full Core semantic-conformance claim. Graph +consumers, graph composition, transitive closure, release envelopes, registration +and cycle handling remain unsupported, pending their owning contracts. + +There are 1–16 governing-policy entries, each exactly `{policy, scope, coverage}`. +One stable Policy identity can occur only once; two versions of the same identity +in one adoption refuse rather than imply precedence. List order never establishes +policy priority. Each Policy reference resolves its exact bytes, ID/version, +optional canonical identity, selector, closed grammar, sources and sections. + +Scope is either `{kind: "whole-policy"}` or +`{kind: "sections", sectionIds, reviewBasis}`. A section list is nonempty, unique, +at most 64 IDs and resolves only declared sections. The limited scope's retained +`reviewBasis` describes that intentional interpretation. Whole scope selects all +declared sections; it does not prove that the author declared every applicable +clause or every applicable policy. + +Coverage contains **exactly one** record per selected section, at most 64 records, +with no duplicate section identities, omissions, unknown IDs or outside-scope +records. The five closed forms are: + +| Status | Required members in addition to `sectionId` and `status` | +| --- | --- | +| `implemented` | Nonempty `consumerElements` (at most 64) and retained `reviewBasis` | +| `manual` | Readable `handoff` naming a responsible process | +| `awaiting-interpretation` | Readable `explanation` of unresolved meaning | +| `awaiting-implementation` | Readable `explanation` of missing implementation | +| `out-of-scope` | Readable `rationale` for this selected clause's exclusion | + +A clause excluded from limited scope has no coverage record; a selected clause +marked `out-of-scope` has the explicit rationale above. Partial automation is +valid and never asserts complete automation or permission to run. Both kinds of +`reviewBasis` are retained explanatory bytes, not proof of a reviewer's identity, +whole-policy approval or authorized sign-off. Manual handoff text grants no role. + +The typed `consumerElements` forms are exactly: + +| Reference | Actual Core target | +| --- | --- | +| `{kind: "rule", id}` | A declared `rules[]` entry with that ID | +| `{kind: "exception", id}` | A declared `exceptions[]` entry with that ID | +| `{kind: "applicability"}` | The present `applicability` condition | +| `{kind: "fallback"}` | The present `fallbackOutcome`, resolving to a declared outcome | + +Singletons have no fabricated ID. Kind/ID confusion, absent/unknown targets and +repeated references within one coverage record refuse. Rule and exception IDs +occupy separate namespaces. The checker also requires unique rule, exception and +outcome IDs, resolves fallback, and resolves each exception's optional target-rule +and outcome references. It does not implement all Core semantic checks or prove +that a condition correctly interprets a clause. Outcomes, evidence requirements, +condition subelements and escalation are unsupported coverage kinds. + +Optional `informationalSources` is at most 16 unique content references. These +bytes remain citations; they never create governing dependencies, review +assertions, authority or permissions. The checker cannot upgrade one into an +adoption, infer natural-language consistency or decide applicability. + +## 5. Resource limits and refusal classifications + +These are candidate offline-reader bounds, not changes to Core or adopted limits. +All maxima are inclusive. Strings are counted after decoding in Unicode +characters unless the table specifies bytes. The closed schemas state all field +maxima; the capability record exposes them for discovery. + +| Resource | Maximum | +| --- | --- | +| Any parsed companion/Pack/carrier JSON document | 262,144 exact bytes | +| JSON nesting, each object/array one level from zero | 32 | +| JSON number literal | 128 characters; exponent magnitude 308 | +| Narrative, interpretation/review basis, informational material | 1,048,576 bytes each | +| Original source material, one carrier registration | 4,194,304 bytes each | +| Distinct retained material across one supplied carrier | 16,777,216 bytes | +| Ordered registrations in the local fixture/vector input carrier | 16 | +| Artifact version | 256 ASCII characters | + +An artifact is also subject to the parsed-document byte limit, even though its +content reference has the general material maximum. Each role is checked +independently. Unsupported original size refuses the whole supplied input; +truncating it, silently dropping it, or substituting narrative extraction is not +a complete input. Registration exceeding a bound changes no material state. + +The reader returns exactly one of these bounded JSON objects (object member order +is irrelevant; no optional messages, paths, content, titles or provider identifiers): + +```json +{"status":"valid","formatVersion":"1.0.0","maturity":"proposed-draft"} +{"status":"refused","code":"invalid-selector"} +``` + +`valid` means supplied-document and reference agreement under this **proposed** +candidate only. A refusal reports no partial coverage or permission. CLI success +exits 0 and refusal exits 1. Environment/setup failures are not document results; +operators must not treat an inability to run as success. + +| Code | Meaning | +| --- | --- | +| `input-over-bound` | Physical bytes/nesting/number limits, schema maxima, role sizes, registration count or aggregate bytes exceeded | +| `invalid-json` | Strict UTF-8 JSON failed: duplicate keys, BOM, nonfinite numbers, unpaired surrogates, multiple values, malformed syntax | +| `invalid-selector` | Root is not an object; selector missing, wrong type, not strict ASCII `x.y.z`, or over 256 characters | +| `unsupported-format` | Selector is well-formed within that bound but is not exactly `1.0.0`; no shared-major inference | +| `invalid-document` | Supported companion fails canonical numeric domain or closed schema; wrong kind, malformed artifact version or unsupported members | +| `missing-material` | A referenced digest, required fixture document or retained local file is absent/unavailable | +| `reference-mismatch` | Raw bytes/hash/length/registered media type, ID/version, or a supported requested canonical digest differs | +| `invalid-anchor` | Narrative UTF-8, section-ID uniqueness, byte range/boundary/hash or source reference fails | +| `invalid-coverage` | Semantic scope, total coverage, policy uniqueness or typed consumer reference fails | +| `invalid-consumer` | Retained Pack fails existing Core schema or the specific ID/fallback/exception checks in §4 | +| `unsupported-canonical-identity` | Requested `jps-canon` identity is outside that existing profile's domain | +| `invalid-carrier` | Synthetic fixture/vector carrier has invalid closed shape or local path usage | + +Bounds on physical document bytes, nesting and number literals are checked before +JSON syntax, including on malformed bytes. Then strict JSON is parsed. Exact +format dispatch occurs before canonical-domain and schema interpretation: +`{"formatVersion":"7.0.0","n":1.5}` is `unsupported-format`. Selector lexical +failures, including the selector's own 256-character limit, are +`invalid-selector`; other schema maxima are `input-over-bound`. Unsupported kinds +under supported format are `invalid-document`. Other-field bounds or validity do +not cause reinterpretation under an unknown format. + +For the portable vector input, parse, select and canonical-domain-check the root +before checking the registration count and registering material in listed order. +Local carrier sources are acquired only after root dispatch and the count check, +one source immediately before its registration. An earlier refusal prevents later +source acquisition. NUL paths and path-normalization failures are `invalid-carrier`. +Then check the root's schema and semantics as implemented in `verify.py`: +Policy narrative, sources, sections in declaration order; adoption consumer then +Policies in declaration order, each reference before its Policy/coverage, then +informational sources. Canonical-domain conversion occurs immediately after root +selection; all schema maxima found at one schema check take priority over other +schema failures. Otherwise a closed-schema failure is `invalid-document` (or +`invalid-consumer` for Core), including structurally identical duplicates rejected +by `uniqueItems`. Semantic duplicate coverage/IDs with distinct records uses the +specific code above. On compound defects the first failing phase wins. Refusals +never render an input-derived diagnostic or exception string. + +## 6. Discovery, examples and independent porting + +[capabilities.json](capabilities.json), also returned by +`verify.py --capabilities`, lists exact candidate selectors, `proposed-draft` +maturity, kinds, supported Core release, features, bounds and explicit exclusions. +Capability discovery is an implementation statement, not adoption, trusted review +or a permission grant. Unsupported format and optional canonical identity are +separate capabilities; no parser tries an older grammar automatically. + +The examples are synthetic retained-byte bundles, derived from 0.0.2 with **source, +narrative, interpretation and consumer files preserved byte-for-byte**. Policy and +adoption identities/bytes are explicitly regenerated. The original consumer URI +is opaque and intentionally retained, even where its spelling mentions prototype. + +| Domain | Coverage | +| --- | --- | +| [Data access](examples/data-access/fixture.json) | Whole policy; rules, fallback, manual requests and pending audit implementation | +| [Procurement](examples/procurement/fixture.json) | Externally managed; applicability-only scope, limited sections, unresolved meaning, explicit exclusion | +| [Refunds](examples/refunds/fixture.json) | Whole policy; rules, exception-only routing, manual inspection, pending implementation | + +[fixture.schema.json](fixture.schema.json) describes a local synthetic carrier, +not a portable release envelope or proof that a dependency closure is complete. +Its files must resolve in the same directory; no network acquisition occurs. +The separate [vector carrier specification](vectors/README.md) defines static +input bytes and expected results for reuse by Go or other implementations. +Only a two-integer byte-repeat generator compresses boundary payloads; there is +no mutation language, implicit migration or dependency on Python transformations. +The current vectors measure agreement by this author's code and reuse its existing +canonicalizer; they supply no independent authorship or cross-vendor evidence. + +Using the repository's pinned `requirements-dev.txt` dependencies on Python 3.12: + +```sh +python rfcs/policy-companion-contract/verify.py --capabilities +python rfcs/policy-companion-contract/verify.py rfcs/policy-companion-contract/examples/refunds +python rfcs/policy-companion-contract/check_vectors.py +python -m unittest discover -s rfcs/policy-companion-contract -p 'test_*.py' -v +``` + +The repository workflow runs the candidate separately from the frozen prototype +and existing Core/Dialect checks. Passing these checks creates no adopted corpus. + +## 7. Remaining decisions and host boundary + +Review/publication transactions, authentication, review-assertion trust, signatures, +source observations and synchronization, current eligibility, run/action admission, +Graph closure and independent implementation evidence remain outside this +candidate. Review assertions cannot be inferred from explanatory bytes or model +test output. No citation, content match, imported history or historical approval +silently becomes local authority or permission. Host publication and admission +require their own adopted contracts and current authenticated decisions. diff --git a/internal/policy/candidate/capabilities.json b/internal/policy/candidate/capabilities.json new file mode 100644 index 00000000..313b4550 --- /dev/null +++ b/internal/policy/candidate/capabilities.json @@ -0,0 +1,74 @@ +{ + "capability": "jps-policy-companion-offline", + "maturity": "proposed-draft", + "formatVersions": [ + "1.0.0" + ], + "consumerSpecVersions": [ + "0.2.0-draft" + ], + "kinds": [ + "policy", + "governing-adoption" + ], + "features": [ + "exact-byte-sha256", + "utf8-section-anchors", + "scoped-total-coverage", + "typed-core-pack-references", + "optional-jps-canon-identity", + "multiple-media-types" + ], + "limits": { + "documentBytes": 262144, + "documentDepth": 32, + "numberLiteralCharacters": 128, + "exponentMagnitude": 308, + "materialBytes": 1048576, + "originalBytes": 4194304, + "distinctRetainedBytes": 16777216, + "materialRegistrations": 16, + "versionCharacters": 256, + "sections": 64, + "sources": 16, + "governingPolicies": 16, + "consumerElementsPerSection": 64, + "textCharacters": 4096, + "uriCharacters": 2048, + "localIdCharacters": 128, + "mediaTypeCharacters": 128, + "sourceRefsPerSection": 16, + "scopeSectionIds": 64, + "coverageRecordsPerPolicy": 64, + "informationalSources": 16, + "canonicalIntegerMagnitude": 9007199254740991 + }, + "excludes": [ + "adopted-or-stable-format", + "graph-consumers", + "evaluation", + "full-core-semantics", + "signatures", + "review-assertion-trust", + "live-authority", + "permissions", + "currency", + "source-fetch", + "automatic-migration", + "independent-interoperability-evidence" + ], + "refusalCodes": [ + "input-over-bound", + "invalid-json", + "invalid-selector", + "unsupported-format", + "invalid-document", + "missing-material", + "reference-mismatch", + "invalid-anchor", + "invalid-coverage", + "invalid-consumer", + "unsupported-canonical-identity", + "invalid-carrier" + ] +} diff --git a/internal/policy/candidate/common.schema.json b/internal/policy/candidate/common.schema.json new file mode 100644 index 00000000..e7c544e8 --- /dev/null +++ b/internal/policy/candidate/common.schema.json @@ -0,0 +1,186 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:jps:proposal:policy-companion:1.0.0:common", + "title": "PROPOSED DRAFT Policy companion 1.0.0: common", + "description": "Proposed draft shared definitions. jps-canon refers to the existing spec/dialect.md canonical profile; this candidate does not adopt or change it.", + "$ref": "#/$defs/retainedContent", + "$defs": { + "version": { + "type": "string", + "minLength": 5, + "maxLength": 256, + "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(?![\\s\\S])" + }, + "text": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "localId": { + "type": "string", + "maxLength": 128, + "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*(?![\\s\\S])" + }, + "uri": { + "type": "string", + "format": "uri", + "minLength": 1, + "maxLength": 2048 + }, + "content": { + "type": "object", + "additionalProperties": false, + "required": [ + "bytesDigest", + "byteLength", + "mediaType" + ], + "properties": { + "bytesDigest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}(?![\\s\\S])" + }, + "byteLength": { + "type": "integer", + "minimum": 0, + "maximum": 1048576 + }, + "mediaType": { + "type": "string", + "maxLength": 128, + "pattern": "^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+(?![\\s\\S])" + } + }, + "description": "Narrative, review basis, artifact and informational material: at most 1 MiB." + }, + "canonicalIdentity": { + "type": "object", + "additionalProperties": false, + "required": [ + "profile", + "canonicalDigest" + ], + "properties": { + "profile": { + "const": "jps-canon" + }, + "canonicalDigest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}(?![\\s\\S])" + } + } + }, + "anchor": { + "type": "object", + "additionalProperties": false, + "required": [ + "startByte", + "endByte", + "bytesDigest" + ], + "properties": { + "startByte": { + "type": "integer", + "minimum": 0, + "maximum": 1048576 + }, + "endByte": { + "type": "integer", + "minimum": 1, + "maximum": 1048576 + }, + "bytesDigest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}(?![\\s\\S])" + } + } + }, + "policyReference": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "id", + "version", + "content" + ], + "properties": { + "kind": { + "const": "policy" + }, + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/uri" + }, + "version": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/version" + }, + "content": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + }, + "canonicalIdentity": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/canonicalIdentity" + } + } + }, + "packReference": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "id", + "version", + "content" + ], + "properties": { + "kind": { + "const": "pack" + }, + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/uri" + }, + "version": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/version" + }, + "content": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + }, + "canonicalIdentity": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/canonicalIdentity" + } + } + }, + "retainedContent": { + "type": "object", + "additionalProperties": false, + "required": [ + "bytesDigest", + "byteLength", + "mediaType" + ], + "properties": { + "bytesDigest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}(?![\\s\\S])" + }, + "byteLength": { + "type": "integer", + "minimum": 0, + "maximum": 4194304 + }, + "mediaType": { + "type": "string", + "maxLength": 128, + "pattern": "^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+(?![\\s\\S])" + } + }, + "description": "Generic fixture-carrier reference; consuming roles impose their own bounds." + }, + "originalContent": { + "description": "Exact retained original source bytes: at most 4 MiB; never a replacement for narrative.", + "$ref": "#/$defs/retainedContent" + }, + "formatVersion": { + "const": "1.0.0" + } + } +} diff --git a/internal/policy/candidate/examples/data-access/adoption.json b/internal/policy/candidate/examples/data-access/adoption.json new file mode 100644 index 00000000..e6e67e2c --- /dev/null +++ b/internal/policy/candidate/examples/data-access/adoption.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/examples/data-access/consumer-pack.json b/internal/policy/candidate/examples/data-access/consumer-pack.json new file mode 100644 index 00000000..a292cbe5 --- /dev/null +++ b/internal/policy/candidate/examples/data-access/consumer-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/examples/data-access/fixture.json b/internal/policy/candidate/examples/data-access/fixture.json new file mode 100644 index 00000000..4d9d3a3f --- /dev/null +++ b/internal/policy/candidate/examples/data-access/fixture.json @@ -0,0 +1,58 @@ +{ + "fixtureVersion": "1", + "synthetic": true, + "scenario": "data-access", + "materials": [ + { + "path": "narrative.txt", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "path": "source.txt", + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "path": "interpretation.txt", + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "path": "consumer-pack.json", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "path": "policy.json", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + }, + { + "path": "adoption.json", + "content": { + "bytesDigest": "sha256:98294b5df0876cc793f236fa5184380aa37f2e459e1f630a5e613237404c2ec0", + "byteLength": 2352, + "mediaType": "application/json" + } + } + ], + "policy": "policy.json", + "consumer": "consumer-pack.json", + "adoption": "adoption.json" +} diff --git a/internal/policy/candidate/examples/data-access/interpretation.txt b/internal/policy/candidate/examples/data-access/interpretation.txt new file mode 100644 index 00000000..4aa6c667 --- /dev/null +++ b/internal/policy/candidate/examples/data-access/interpretation.txt @@ -0,0 +1,4 @@ +SYNTHETIC REVIEW BASIS; no person approved this fixture. +The eligible and ineligible rules interpret the automated eligibility clause. +The fallbackOutcome routes an unmatched classification to review; unknown facts escalate. +Other coverage is stated explicitly. diff --git a/internal/policy/candidate/examples/data-access/narrative.txt b/internal/policy/candidate/examples/data-access/narrative.txt new file mode 100644 index 00000000..bd5e6867 --- /dev/null +++ b/internal/policy/candidate/examples/data-access/narrative.txt @@ -0,0 +1,10 @@ +SYNTHETIC RFC PROTOTYPE — Data access + +Automated release +Only de-identified datasets may be released through this automated path. Identifiable datasets are refused; missing classification goes to a data steward. + +Restricted requests +A data steward reviews restricted requests through the manual access process. This pack cannot grant an exception. + +Quarterly audit +Review the access log quarterly. A separate audit implementation is still needed. diff --git a/internal/policy/candidate/examples/data-access/policy.json b/internal/policy/candidate/examples/data-access/policy.json new file mode 100644 index 00000000..ae2a479e --- /dev/null +++ b/internal/policy/candidate/examples/data-access/policy.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/examples/data-access/source.txt b/internal/policy/candidate/examples/data-access/source.txt new file mode 100644 index 00000000..794f4622 --- /dev/null +++ b/internal/policy/candidate/examples/data-access/source.txt @@ -0,0 +1,5 @@ +SYNTHETIC ORIGINAL SOURCE; NOT AN APPROVED POLICY + +Clause 1: Only de-identified datasets may be released through this automated path. Identifiable datasets are refused; missing classification goes to a data steward. +Clause 2: A data steward reviews restricted requests through the manual access process. This pack cannot grant an exception. +Clause 3: Review the access log quarterly. A separate audit implementation is still needed. diff --git a/internal/policy/candidate/examples/procurement/adoption.json b/internal/policy/candidate/examples/procurement/adoption.json new file mode 100644 index 00000000..9c55f540 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/adoption.json @@ -0,0 +1,97 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/procurement/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/procurement/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "byteLength": 1725, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:205a2afdc68ebd46d5b022256fadec6bd071bc8e34faff481f288c20df008f60" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/procurement/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:539587356d8c0942f6e2c98ec09311e9c55fc4efcc6b9f8845e58db817a8dc58", + "byteLength": 2793, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:f0ef6fe0bb4703eaf6b2c1edf2f12712dffc139e887317c46fc82d83dba71275" + } + }, + "scope": { + "kind": "sections", + "sectionIds": [ + "eligibility", + "conflict-review", + "invoice-payment", + "purchase-scope" + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + { + "sectionId": "conflict-review", + "status": "awaiting-interpretation", + "explanation": "Synthetic open work item: agree the conflict threshold before implementation." + }, + { + "sectionId": "invoice-payment", + "status": "out-of-scope", + "rationale": "This pack assesses eligibility only; treasury payment reconciliation is a separate process." + }, + { + "sectionId": "purchase-scope", + "status": "implemented", + "consumerElements": [ + { + "kind": "applicability" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + } + ] + } + ] +} diff --git a/internal/policy/candidate/examples/procurement/consumer-pack.json b/internal/policy/candidate/examples/procurement/consumer-pack.json new file mode 100644 index 00000000..0745b386 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/consumer-pack.json @@ -0,0 +1,68 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/procurement/pack", + "version": "1.0.0", + "title": "Procurement — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/procurement/competitiveProcedureDocumented", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/procurement/competitiveProcedureDocumented", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "applicability": { + "op": "fact", + "path": "/request/kind", + "operator": "equals", + "value": "purchase" + } +} diff --git a/internal/policy/candidate/examples/procurement/fixture.json b/internal/policy/candidate/examples/procurement/fixture.json new file mode 100644 index 00000000..2bb9dd50 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/fixture.json @@ -0,0 +1,58 @@ +{ + "fixtureVersion": "1", + "synthetic": true, + "scenario": "procurement", + "materials": [ + { + "path": "narrative.txt", + "content": { + "bytesDigest": "sha256:993a73c70afdc16c94368982d1e951c85c90838d1f750a7001c2942dc9834b94", + "byteLength": 621, + "mediaType": "text/plain" + } + }, + { + "path": "source.txt", + "content": { + "bytesDigest": "sha256:4681b36d52396d3faef09e4a7c551d829920362beb47a1bfb32c2d6c4d82763b", + "byteLength": 591, + "mediaType": "text/plain" + } + }, + { + "path": "interpretation.txt", + "content": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + { + "path": "consumer-pack.json", + "content": { + "bytesDigest": "sha256:d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "byteLength": 1725, + "mediaType": "application/json" + } + }, + { + "path": "policy.json", + "content": { + "bytesDigest": "sha256:539587356d8c0942f6e2c98ec09311e9c55fc4efcc6b9f8845e58db817a8dc58", + "byteLength": 2793, + "mediaType": "application/json" + } + }, + { + "path": "adoption.json", + "content": { + "bytesDigest": "sha256:e9c871b2e7dc7448e46b2d4d347beb504bbe0a691be11df4283a95a693208703", + "byteLength": 3055, + "mediaType": "application/json" + } + } + ], + "policy": "policy.json", + "consumer": "consumer-pack.json", + "adoption": "adoption.json" +} diff --git a/internal/policy/candidate/examples/procurement/interpretation.txt b/internal/policy/candidate/examples/procurement/interpretation.txt new file mode 100644 index 00000000..cc2bd1f5 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/interpretation.txt @@ -0,0 +1,5 @@ +SYNTHETIC REVIEW BASIS; no person approved this fixture. +The eligible and ineligible rules interpret the competitive-procedure clause. +The applicability condition alone implements purchase scope; it is not a rule ID. +Missing facts need review. Other coverage is stated explicitly. +The selected scope includes eligibility, conflict review, invoice payment and purchase scope; public notice is excluded. diff --git a/internal/policy/candidate/examples/procurement/narrative.txt b/internal/policy/candidate/examples/procurement/narrative.txt new file mode 100644 index 00000000..646937a8 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/narrative.txt @@ -0,0 +1,16 @@ +SYNTHETIC RFC PROTOTYPE — Procurement + +Competitive procedure +Automated eligibility requires a documented competitive procedure. A missing record requires a procurement reviewer. + +Supplier conflicts +Supplier relationships require a conflict review. The threshold for a material relationship needs clarification. + +Invoice payment +Treasury performs payment reconciliation outside this eligibility interpretation. + +Public notice +Publish the award notice through the separate communications process. + +Purchase scope +This eligibility pack applies only to purchase requests; other requests remain outside this automated path. diff --git a/internal/policy/candidate/examples/procurement/policy.json b/internal/policy/candidate/examples/procurement/policy.json new file mode 100644 index 00000000..00b19b27 --- /dev/null +++ b/internal/policy/candidate/examples/procurement/policy.json @@ -0,0 +1,106 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/procurement/policy", + "version": "1.0.0", + "title": "Procurement — synthetic policy content", + "managementMode": "externally-managed", + "content": { + "bytesDigest": "sha256:993a73c70afdc16c94368982d1e951c85c90838d1f750a7001c2942dc9834b94", + "byteLength": 621, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Competitive procedure", + "anchor": { + "startByte": 41, + "endByte": 181, + "bytesDigest": "sha256:a8d58fa560d792bbc0848b517b47a04d01fa928a4315de4be423d9756745714f" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "conflict-review", + "title": "Supplier conflicts", + "anchor": { + "startByte": 181, + "endByte": 314, + "bytesDigest": "sha256:ed53cc9edccb33c00c4692bcc84593e249117f9dbc4045d57e5e8f85458c7c94" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "invoice-payment", + "title": "Invoice payment", + "anchor": { + "startByte": 314, + "endByte": 413, + "bytesDigest": "sha256:f6803f2ffa7356a3aad889d20987a00614d8145193c521107845092745db9d1d" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + }, + { + "id": "public-notice", + "title": "Public notice", + "anchor": { + "startByte": 413, + "endByte": 497, + "bytesDigest": "sha256:b6d68243578efb748244d55bcfe5f7bb730faa1c939c6a910f4e6e26b79b34f9" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 4" + } + ] + }, + { + "id": "purchase-scope", + "title": "Purchase scope", + "anchor": { + "startByte": 498, + "endByte": 621, + "bytesDigest": "sha256:13498f448247cfd988d4d59046ae766abb0559cf902093cdf8f650543f37ed26" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 5" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "procurement-original" + }, + "sourceRevision": "fictional-revision-a", + "content": { + "bytesDigest": "sha256:4681b36d52396d3faef09e4a7c551d829920362beb47a1bfb32c2d6c4d82763b", + "byteLength": 591, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/examples/procurement/source.txt b/internal/policy/candidate/examples/procurement/source.txt new file mode 100644 index 00000000..c5913acb --- /dev/null +++ b/internal/policy/candidate/examples/procurement/source.txt @@ -0,0 +1,7 @@ +SYNTHETIC ORIGINAL SOURCE; NOT AN APPROVED POLICY + +Clause 1: Automated eligibility requires a documented competitive procedure. A missing record requires a procurement reviewer. +Clause 2: Supplier relationships require a conflict review. The threshold for a material relationship needs clarification. +Clause 3: Treasury performs payment reconciliation outside this eligibility interpretation. +Clause 4: Publish the award notice through the separate communications process. +Clause 5: This eligibility pack applies only to purchase requests; other requests remain outside this automated path. diff --git a/internal/policy/candidate/examples/refunds/adoption.json b/internal/policy/candidate/examples/refunds/adoption.json new file mode 100644 index 00000000..6af1ea97 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/adoption.json @@ -0,0 +1,87 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/refunds/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/refunds/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:2a049f10cd8c5d4fc81200976507a8563d0bc1fca19fa9691fc1601507512e38", + "byteLength": 1924, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20723faedbed6ee066dd3330e4b72848702e92dfbeb68b757f6ed0a95e4a2c5" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/refunds/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:8e3a487de4b15a1bc6c824e6dedd2e1b4fe16f4b3c4430a76b46e943ef2565ff", + "byteLength": 2375, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:e287b7208c0e870d1ee04188bc57f614096210f740d0f95fbf11d1324dc93704" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:63f58f37957f808e98c67db11ac9d835286733336e47ae24f28b974d431b9862", + "byteLength": 301, + "mediaType": "text/plain" + } + }, + { + "sectionId": "damaged-goods", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "fraud-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + }, + { + "sectionId": "damaged-routing", + "status": "implemented", + "consumerElements": [ + { + "kind": "exception", + "id": "damaged-routing" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:63f58f37957f808e98c67db11ac9d835286733336e47ae24f28b974d431b9862", + "byteLength": 301, + "mediaType": "text/plain" + } + } + ] + } + ] +} diff --git a/internal/policy/candidate/examples/refunds/consumer-pack.json b/internal/policy/candidate/examples/refunds/consumer-pack.json new file mode 100644 index 00000000..07323779 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/consumer-pack.json @@ -0,0 +1,76 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/refunds/pack", + "version": "1.0.0", + "title": "Refunds — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/purchase/withinReturnWindow", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/purchase/withinReturnWindow", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "exceptions": [ + { + "id": "damaged-routing", + "description": "Route damaged goods to review; this does not perform the manual inspection.", + "when": { + "op": "fact", + "path": "/purchase/damaged", + "operator": "equals", + "value": true + }, + "effect": "escalate", + "onUnknown": "escalate" + } + ] +} diff --git a/internal/policy/candidate/examples/refunds/fixture.json b/internal/policy/candidate/examples/refunds/fixture.json new file mode 100644 index 00000000..e1a86a90 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/fixture.json @@ -0,0 +1,58 @@ +{ + "fixtureVersion": "1", + "synthetic": true, + "scenario": "refunds", + "materials": [ + { + "path": "narrative.txt", + "content": { + "bytesDigest": "sha256:909d57f27b7359c777dfb2ea07d859408a13504bf8dded27807889f7cde52969", + "byteLength": 486, + "mediaType": "text/plain" + } + }, + { + "path": "source.txt", + "content": { + "bytesDigest": "sha256:ae72534013fc75083b184765e7a558b71b5e4674720aa56e8960844fd712c6c0", + "byteLength": 474, + "mediaType": "text/plain" + } + }, + { + "path": "interpretation.txt", + "content": { + "bytesDigest": "sha256:63f58f37957f808e98c67db11ac9d835286733336e47ae24f28b974d431b9862", + "byteLength": 301, + "mediaType": "text/plain" + } + }, + { + "path": "consumer-pack.json", + "content": { + "bytesDigest": "sha256:2a049f10cd8c5d4fc81200976507a8563d0bc1fca19fa9691fc1601507512e38", + "byteLength": 1924, + "mediaType": "application/json" + } + }, + { + "path": "policy.json", + "content": { + "bytesDigest": "sha256:8e3a487de4b15a1bc6c824e6dedd2e1b4fe16f4b3c4430a76b46e943ef2565ff", + "byteLength": 2375, + "mediaType": "application/json" + } + }, + { + "path": "adoption.json", + "content": { + "bytesDigest": "sha256:7c7cd121fc4510fff19b8bcaf120ce1a9cb3f7e60b8e811ce9be917799367bc8", + "byteLength": 2729, + "mediaType": "application/json" + } + } + ], + "policy": "policy.json", + "consumer": "consumer-pack.json", + "adoption": "adoption.json" +} diff --git a/internal/policy/candidate/examples/refunds/interpretation.txt b/internal/policy/candidate/examples/refunds/interpretation.txt new file mode 100644 index 00000000..61258de1 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/interpretation.txt @@ -0,0 +1,4 @@ +SYNTHETIC REVIEW BASIS; no person approved this fixture. +The eligible and ineligible rules interpret the return-window clause. +The damaged-routing exception alone routes damaged goods to a specialist; physical inspection remains manual. +Missing facts need review. Other coverage is stated explicitly. diff --git a/internal/policy/candidate/examples/refunds/narrative.txt b/internal/policy/candidate/examples/refunds/narrative.txt new file mode 100644 index 00000000..1cf4b905 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/narrative.txt @@ -0,0 +1,13 @@ +SYNTHETIC RFC PROTOTYPE — Refunds + +Return window +The automated path accepts only purchases within the published return window. Missing purchase dates require a returns specialist. + +Damaged goods +A returns specialist handles damaged goods through the manual inspection process. + +Fraud review +Potential repeated-claim abuse needs a separate reviewed implementation. + +Damaged goods routing +Damaged goods bypass automated eligibility and go to a returns specialist for manual inspection. diff --git a/internal/policy/candidate/examples/refunds/policy.json b/internal/policy/candidate/examples/refunds/policy.json new file mode 100644 index 00000000..b3531a29 --- /dev/null +++ b/internal/policy/candidate/examples/refunds/policy.json @@ -0,0 +1,91 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/refunds/policy", + "version": "1.0.0", + "title": "Refunds — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:909d57f27b7359c777dfb2ea07d859408a13504bf8dded27807889f7cde52969", + "byteLength": 486, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Return window", + "anchor": { + "startByte": 37, + "endByte": 183, + "bytesDigest": "sha256:838ea4e242523a398e18a4006aa1488cc2032eb23f503f2c2dc2539339cc757a" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "damaged-goods", + "title": "Damaged goods", + "anchor": { + "startByte": 183, + "endByte": 280, + "bytesDigest": "sha256:ac0263d8b10debc2e8fb9090bb1b55c80a5766a4d192f23f0f640062ba5c82d4" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "fraud-review", + "title": "Fraud review", + "anchor": { + "startByte": 280, + "endByte": 366, + "bytesDigest": "sha256:9117339f1340e981a232894965d79f3f2a9f8116ffc347142c7dc7d9bc2631c3" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + }, + { + "id": "damaged-routing", + "title": "Damaged goods routing", + "anchor": { + "startByte": 367, + "endByte": 486, + "bytesDigest": "sha256:a47d45dfa15bb16514328ff9e1de346be10d045a194597e6c44e1f598ab17ab1" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 4" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "refunds-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:ae72534013fc75083b184765e7a558b71b5e4674720aa56e8960844fd712c6c0", + "byteLength": 474, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/examples/refunds/source.txt b/internal/policy/candidate/examples/refunds/source.txt new file mode 100644 index 00000000..614029ef --- /dev/null +++ b/internal/policy/candidate/examples/refunds/source.txt @@ -0,0 +1,6 @@ +SYNTHETIC ORIGINAL SOURCE; NOT AN APPROVED POLICY + +Clause 1: The automated path accepts only purchases within the published return window. Missing purchase dates require a returns specialist. +Clause 2: A returns specialist handles damaged goods through the manual inspection process. +Clause 3: Potential repeated-claim abuse needs a separate reviewed implementation. +Clause 4: Damaged goods bypass automated eligibility and go to a returns specialist for manual inspection. diff --git a/internal/policy/candidate/fixture.schema.json b/internal/policy/candidate/fixture.schema.json new file mode 100644 index 00000000..3d2ec3c7 --- /dev/null +++ b/internal/policy/candidate/fixture.schema.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:jps:proposal:policy-companion:1.0.0:fixture", + "title": "Local synthetic candidate fixture carrier; not a release envelope", + "type": "object", + "additionalProperties": false, + "required": [ + "fixtureVersion", + "synthetic", + "scenario", + "materials", + "policy", + "consumer", + "adoption" + ], + "properties": { + "fixtureVersion": { + "const": "1" + }, + "synthetic": { + "const": true + }, + "scenario": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "materials": { + "type": "array", + "minItems": 1, + "maxItems": 16, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "content" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "content": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/retainedContent" + } + } + } + }, + "policy": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "consumer": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "adoption": { + "type": "string", + "minLength": 1, + "maxLength": 128 + } + } +} diff --git a/internal/policy/candidate/governing-adoption.schema.json b/internal/policy/candidate/governing-adoption.schema.json new file mode 100644 index 00000000..3b8a5204 --- /dev/null +++ b/internal/policy/candidate/governing-adoption.schema.json @@ -0,0 +1,265 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:jps:proposal:policy-companion:1.0.0:governing-adoption", + "title": "PROPOSED DRAFT Policy companion 1.0.0: governing-adoption", + "description": "Immutable interpretation/coverage proposal for one exact pack. No authorization, registration, release envelope, graph support or live eligibility.", + "type": "object", + "additionalProperties": false, + "required": [ + "formatVersion", + "kind", + "id", + "version", + "consumer", + "governingPolicies" + ], + "properties": { + "formatVersion": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/formatVersion" + }, + "kind": { + "const": "governing-adoption" + }, + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/uri" + }, + "version": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/version" + }, + "consumer": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/packReference" + }, + "governingPolicies": { + "type": "array", + "minItems": 1, + "maxItems": 16, + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "policy", + "scope", + "coverage" + ], + "properties": { + "policy": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/policyReference" + }, + "scope": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind" + ], + "properties": { + "kind": { + "const": "whole-policy" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "sectionIds", + "reviewBasis" + ], + "properties": { + "kind": { + "const": "sections" + }, + "sectionIds": { + "type": "array", + "minItems": 1, + "maxItems": 64, + "uniqueItems": true, + "items": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + } + }, + "reviewBasis": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + } + } + } + ] + }, + "coverage": { + "type": "array", + "minItems": 1, + "maxItems": 64, + "uniqueItems": true, + "items": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "sectionId", + "status", + "consumerElements", + "reviewBasis" + ], + "properties": { + "sectionId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "status": { + "const": "implemented" + }, + "consumerElements": { + "type": "array", + "minItems": 1, + "maxItems": 64, + "uniqueItems": true, + "items": { + "$ref": "#/$defs/consumerElement" + } + }, + "reviewBasis": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "sectionId", + "status", + "handoff" + ], + "properties": { + "sectionId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "status": { + "const": "manual" + }, + "handoff": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "sectionId", + "status", + "explanation" + ], + "properties": { + "sectionId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "status": { + "const": "awaiting-interpretation" + }, + "explanation": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "sectionId", + "status", + "explanation" + ], + "properties": { + "sectionId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "status": { + "const": "awaiting-implementation" + }, + "explanation": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "sectionId", + "status", + "rationale" + ], + "properties": { + "sectionId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "status": { + "const": "out-of-scope" + }, + "rationale": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + } + ] + } + } + } + } + }, + "informationalSources": { + "type": "array", + "minItems": 0, + "maxItems": 16, + "uniqueItems": true, + "items": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + } + } + }, + "$defs": { + "consumerElement": { + "description": "Exact declared Core rule/exception by ID, or the present applicability/fallbackOutcome singleton without a fabricated ID. Other element kinds are unsupported.", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "id" + ], + "properties": { + "kind": { + "enum": [ + "rule", + "exception" + ] + }, + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind" + ], + "properties": { + "kind": { + "enum": [ + "applicability", + "fallback" + ] + } + } + } + ] + } + } +} diff --git a/internal/policy/candidate/policy.schema.json b/internal/policy/candidate/policy.schema.json new file mode 100644 index 00000000..c89c6477 --- /dev/null +++ b/internal/policy/candidate/policy.schema.json @@ -0,0 +1,147 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:jps:proposal:policy-companion:1.0.0:policy", + "title": "PROPOSED DRAFT Policy companion 1.0.0: policy", + "description": "Immutable content/provenance proposal only. managementMode declares intended publication ownership; no imported approval, lifecycle, ACL or rule semantics. Optional readable structured requirements are deferred; a requirements member is unsupported.", + "type": "object", + "additionalProperties": false, + "required": [ + "formatVersion", + "kind", + "id", + "version", + "title", + "managementMode", + "content", + "sections", + "sourceProvenance" + ], + "properties": { + "formatVersion": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/formatVersion" + }, + "kind": { + "const": "policy" + }, + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/uri" + }, + "version": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/version" + }, + "title": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + }, + "managementMode": { + "enum": [ + "workspace-managed", + "externally-managed" + ] + }, + "content": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/content" + }, + "sections": { + "type": "array", + "minItems": 1, + "maxItems": 64, + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "title", + "anchor" + ], + "properties": { + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "title": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + }, + "anchor": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/anchor" + }, + "sourceRefs": { + "type": "array", + "minItems": 0, + "maxItems": 16, + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "sourceId", + "location" + ], + "properties": { + "sourceId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "location": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + } + } + } + } + }, + "sourceProvenance": { + "type": "array", + "minItems": 0, + "maxItems": 16, + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "source", + "sourceRevision", + "content" + ], + "properties": { + "id": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/localId" + }, + "source": { + "type": "object", + "additionalProperties": false, + "required": [ + "provider", + "accountId", + "resourceId" + ], + "properties": { + "provider": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + }, + "accountId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + }, + "resourceId": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + } + }, + "sourceRevision": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/text" + } + ] + }, + "content": { + "$ref": "urn:jps:proposal:policy-companion:1.0.0:common#/$defs/originalContent" + } + } + } + } + } +} diff --git a/internal/policy/candidate/prototype-0.0.2-pin.json b/internal/policy/candidate/prototype-0.0.2-pin.json new file mode 100644 index 00000000..24a7b0e9 --- /dev/null +++ b/internal/policy/candidate/prototype-0.0.2-pin.json @@ -0,0 +1,33 @@ +{ + "commit": "8a56a95d555c17640d2db4984363b779536b3c2a", + "proposalVersion": "0.0.2", + "files": { + "README.md": "sha256:031cc9fa743c7d3af5cc482a514cfba106d510e16364febe0e58ce8bf9830e16", + "common.schema.json": "sha256:97d25d9c7778c68bdd94506227a0061923a5ef5fc9bc5f0a101f1ac2449d0d33", + "examples/data-access/adoption.json": "sha256:f6cf887488c12b0ba5331a048f5a9661a557021f5abfc5662a95524915ec1529", + "examples/data-access/consumer-pack.json": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "examples/data-access/fixture.json": "sha256:575edeed43ceb0b72a3a204caacbc51ba10e52075b7cbeea134b02876e550ec8", + "examples/data-access/interpretation.txt": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "examples/data-access/narrative.txt": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "examples/data-access/policy.json": "sha256:75a7659ed5086c7728af95db0b56b15fdc914a51982b16627fc884cfc9dca50d", + "examples/data-access/source.txt": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "examples/procurement/adoption.json": "sha256:b5b94a06dba7d12748fe3f854bdb5e5da9c14736aeff8d7416e94946891fd063", + "examples/procurement/consumer-pack.json": "sha256:d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "examples/procurement/fixture.json": "sha256:241d3fd3f06c0cc0572d5237bcbbae9c88bd688fdfe7b41809bd90497ebfbf4b", + "examples/procurement/interpretation.txt": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "examples/procurement/narrative.txt": "sha256:993a73c70afdc16c94368982d1e951c85c90838d1f750a7001c2942dc9834b94", + "examples/procurement/policy.json": "sha256:e9bbe247d5aa7537aef08c951b88c0881e381046e357abaa05ea255e208ee852", + "examples/procurement/source.txt": "sha256:4681b36d52396d3faef09e4a7c551d829920362beb47a1bfb32c2d6c4d82763b", + "examples/refunds/adoption.json": "sha256:fd474eed584ae6305ea535bf1d044734f8d754fcc907b0d28b65a318b5ea4b5d", + "examples/refunds/consumer-pack.json": "sha256:2a049f10cd8c5d4fc81200976507a8563d0bc1fca19fa9691fc1601507512e38", + "examples/refunds/fixture.json": "sha256:2029192a538db356e9beb137e35377d00db61dda52cb7ba622d3d5e4343b6f22", + "examples/refunds/interpretation.txt": "sha256:63f58f37957f808e98c67db11ac9d835286733336e47ae24f28b974d431b9862", + "examples/refunds/narrative.txt": "sha256:909d57f27b7359c777dfb2ea07d859408a13504bf8dded27807889f7cde52969", + "examples/refunds/policy.json": "sha256:5391763b2d9a72533e7566cce910a43cb5ab740dd0587d7383f3adf153ba9970", + "examples/refunds/source.txt": "sha256:ae72534013fc75083b184765e7a558b71b5e4674720aa56e8960844fd712c6c0", + "governing-adoption.schema.json": "sha256:4108f3ac476b989483affbf0ddfa2e933f7be5c579c472f7b7b3aa976299f779", + "policy.schema.json": "sha256:d653ce7e855dce678aeadebac18de2afbc5bdcb23412fcf52f3d30b5be3d4dbd", + "test_prototype.py": "sha256:bdb05fe954cb75ddc859e58e81ed29c22e7181fb224068dcc55dfb59106858ef", + "verify.py": "sha256:ad6774c7eed831e1a586b9a313c33cb35b471db5cb41ee2212f1643135e27ea0" + } +} diff --git a/internal/policy/candidate/provenance.json b/internal/policy/candidate/provenance.json new file mode 100644 index 00000000..109088f4 --- /dev/null +++ b/internal/policy/candidate/provenance.json @@ -0,0 +1,867 @@ +{ + "sourceRepository": "https://github.com/Judgment-Pack/judgment-pack-spec", + "sourceRevision": "4406cec9714ab9bc8e8971237cc79d58682cc904", + "formatVersion": "1.0.0", + "maturity": "proposed-draft", + "license": "Apache-2.0", + "files": [ + { + "sourcePath": "rfcs/policy-companion-contract/MIGRATION.md", + "path": "MIGRATION.md", + "sha256": "0602a092ae1c6f670e0b440f3df33de1eb4d825bf714af50143151882e674e34", + "byteLength": 3993 + }, + { + "sourcePath": "rfcs/policy-companion-contract/README.md", + "path": "README.md", + "sha256": "fa67bf571088ea7c9a0ce9936558207a0053342e30f7f9dbc7088723c1b8a8e0", + "byteLength": 20590 + }, + { + "sourcePath": "rfcs/policy-companion-contract/capabilities.json", + "path": "capabilities.json", + "sha256": "57977501550cb90de46d9eb88016725949f1eda83be470ff467804e8f393a287", + "byteLength": 1770 + }, + { + "sourcePath": "rfcs/policy-companion-contract/common.schema.json", + "path": "common.schema.json", + "sha256": "1fd3ad3ae5d76f99c82247f8202b6a821e1ab942350f9e0684a83a3b0bdea8c7", + "byteLength": 5003 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/adoption.json", + "path": "examples/data-access/adoption.json", + "sha256": "98294b5df0876cc793f236fa5184380aa37f2e459e1f630a5e613237404c2ec0", + "byteLength": 2352 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/consumer-pack.json", + "path": "examples/data-access/consumer-pack.json", + "sha256": "c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/fixture.json", + "path": "examples/data-access/fixture.json", + "sha256": "95575efc4fc7571089f17b7684c9ea66c7f16d52cb5b7032c0c494f3f73c25db", + "byteLength": 1599 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/interpretation.txt", + "path": "examples/data-access/interpretation.txt", + "sha256": "7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/narrative.txt", + "path": "examples/data-access/narrative.txt", + "sha256": "801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/policy.json", + "path": "examples/data-access/policy.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/data-access/source.txt", + "path": "examples/data-access/source.txt", + "sha256": "9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/adoption.json", + "path": "examples/procurement/adoption.json", + "sha256": "e9c871b2e7dc7448e46b2d4d347beb504bbe0a691be11df4283a95a693208703", + "byteLength": 3055 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/consumer-pack.json", + "path": "examples/procurement/consumer-pack.json", + "sha256": "d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "byteLength": 1725 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/fixture.json", + "path": "examples/procurement/fixture.json", + "sha256": "bd05d532515eff20322a88c8cbb34899849479f4f4fef8a1f2e3d577a2b96205", + "byteLength": 1599 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/interpretation.txt", + "path": "examples/procurement/interpretation.txt", + "sha256": "14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/narrative.txt", + "path": "examples/procurement/narrative.txt", + "sha256": "993a73c70afdc16c94368982d1e951c85c90838d1f750a7001c2942dc9834b94", + "byteLength": 621 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/policy.json", + "path": "examples/procurement/policy.json", + "sha256": "539587356d8c0942f6e2c98ec09311e9c55fc4efcc6b9f8845e58db817a8dc58", + "byteLength": 2793 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/procurement/source.txt", + "path": "examples/procurement/source.txt", + "sha256": "4681b36d52396d3faef09e4a7c551d829920362beb47a1bfb32c2d6c4d82763b", + "byteLength": 591 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/adoption.json", + "path": "examples/refunds/adoption.json", + "sha256": "7c7cd121fc4510fff19b8bcaf120ce1a9cb3f7e60b8e811ce9be917799367bc8", + "byteLength": 2729 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/consumer-pack.json", + "path": "examples/refunds/consumer-pack.json", + "sha256": "2a049f10cd8c5d4fc81200976507a8563d0bc1fca19fa9691fc1601507512e38", + "byteLength": 1924 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/fixture.json", + "path": "examples/refunds/fixture.json", + "sha256": "48b47e5ca483e53ee4c943409f9892b518108cd0f94ead4f2715852d25a74d60", + "byteLength": 1595 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/interpretation.txt", + "path": "examples/refunds/interpretation.txt", + "sha256": "63f58f37957f808e98c67db11ac9d835286733336e47ae24f28b974d431b9862", + "byteLength": 301 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/narrative.txt", + "path": "examples/refunds/narrative.txt", + "sha256": "909d57f27b7359c777dfb2ea07d859408a13504bf8dded27807889f7cde52969", + "byteLength": 486 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/policy.json", + "path": "examples/refunds/policy.json", + "sha256": "8e3a487de4b15a1bc6c824e6dedd2e1b4fe16f4b3c4430a76b46e943ef2565ff", + "byteLength": 2375 + }, + { + "sourcePath": "rfcs/policy-companion-contract/examples/refunds/source.txt", + "path": "examples/refunds/source.txt", + "sha256": "ae72534013fc75083b184765e7a558b71b5e4674720aa56e8960844fd712c6c0", + "byteLength": 474 + }, + { + "sourcePath": "rfcs/policy-companion-contract/fixture.schema.json", + "path": "fixture.schema.json", + "sha256": "70f72c813ecbf988087de1de41d0871b24dec340e79af5bfe8e488a51ce9cd1b", + "byteLength": 1421 + }, + { + "sourcePath": "rfcs/policy-companion-contract/governing-adoption.schema.json", + "path": "governing-adoption.schema.json", + "sha256": "2a6a55c0efdb5fc25a52bc645eda33ca67247e7db83a0de21204ef6a28432dcb", + "byteLength": 8325 + }, + { + "sourcePath": "rfcs/policy-companion-contract/policy.schema.json", + "path": "policy.schema.json", + "sha256": "21c2a3a3f9763cecfb9348938e078384a9abbf3e55fb8126704cf8a55555fcd7", + "byteLength": 4261 + }, + { + "sourcePath": "rfcs/policy-companion-contract/prototype-0.0.2-pin.json", + "path": "prototype-0.0.2-pin.json", + "sha256": "48a264397902303c0373c4ae11e2bde9b55474f7ff76b33e1fdc3f919c70bacb", + "byteLength": 3146 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors.schema.json", + "path": "vectors.schema.json", + "sha256": "4843941ad1884306a896f5ced516dede695cb4a3fb8512973f3a54860d4a1a88", + "byteLength": 6012 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/README.md", + "path": "vectors/README.md", + "sha256": "23afb102f1a3407eb8b53e9859af50339392ecd8af453f64c78647673de1a624", + "byteLength": 5303 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/aggregate-max.json", + "path": "vectors/documents/aggregate-max.json", + "sha256": "356820def6f85b5a73a1b3520dac185ca3413a17a7d1f269009b3109f789be09", + "byteLength": 683 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/aggregate-over.json", + "path": "vectors/documents/aggregate-over.json", + "sha256": "356820def6f85b5a73a1b3520dac185ca3413a17a7d1f269009b3109f789be09", + "byteLength": 683 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/aggregate-shared-media-counted-once.json", + "path": "vectors/documents/aggregate-shared-media-counted-once.json", + "sha256": "356820def6f85b5a73a1b3520dac185ca3413a17a7d1f269009b3109f789be09", + "byteLength": 683 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/anchor-empty-range.json", + "path": "vectors/documents/anchor-empty-range.json", + "sha256": "f57abd537598b6f2d4f21f5531cc8b287cb8a408174b1699afe23ab862bba431", + "byteLength": 2018 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/anchor-outside-narrative.json", + "path": "vectors/documents/anchor-outside-narrative.json", + "sha256": "aa0fed3939d88597f5a2eab96e1a9305f5671c9d9ffc1140c3a79a0a985d24e9", + "byteLength": 2022 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/anchor-over-bound.json", + "path": "vectors/documents/anchor-over-bound.json", + "sha256": "0f10c69c68a792e43de7b56978bce3073f2baba2ef026607d5c21104e113916f", + "byteLength": 2023 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/anchor-stale-digest.json", + "path": "vectors/documents/anchor-stale-digest.json", + "sha256": "f15662d3349adebe3f37358da15f6c1cbea7a531ead7be55b13a83e6fea865f0", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/anchor-utf8-split.json", + "path": "vectors/documents/anchor-utf8-split.json", + "sha256": "dbb8e91eeaaec4ca6afa0b60ed9ab7621fc46b464052181fc15a7207880d8485", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/approval-field.json", + "path": "vectors/documents/approval-field.json", + "sha256": "b6d55b494d997d827ceda4f0c7b0ff4c644171928f22b2c64bff7ba049cdaae6", + "byteLength": 2039 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-build.json", + "path": "vectors/documents/artifact-build.json", + "sha256": "d8e6a2f1de1400d0f93deb768709a79dd2608581a59f3d91c48c0fe46b53da3e", + "byteLength": 2025 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-independent.json", + "path": "vectors/documents/artifact-independent.json", + "sha256": "b29b0d41f9c53df4ccf45b304e4307848a5aca82f9669ce6a6f532ba9eca7efa", + "byteLength": 2020 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-leading-zero.json", + "path": "vectors/documents/artifact-leading-zero.json", + "sha256": "9bac870cd83f3ce25b4d02c820d962d084de92ea0ccdefb1b4a86e194ece3be0", + "byteLength": 2020 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-max-256.json", + "path": "vectors/documents/artifact-max-256.json", + "sha256": "79b1ac4516f3be2234b1a333a09679474c8f0f9d4c8743cf0b552eaaa97ff06c", + "byteLength": 2270 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-newline.json", + "path": "vectors/documents/artifact-newline.json", + "sha256": "7b398d8f7062dc484dd919271c3cb4d090389604a1504b356892cedf06e29431", + "byteLength": 2021 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-number.json", + "path": "vectors/documents/artifact-number.json", + "sha256": "4d81f8abe5de7580d5896bc2538dc7c7bb6eca300a7fb3a8dab7bf8ad9525cb1", + "byteLength": 2013 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-over-256.json", + "path": "vectors/documents/artifact-over-256.json", + "sha256": "eb73ca4e4a698530f0dee89fefdd9a0914ca0af55202c4da478797a9de491278", + "byteLength": 2271 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/artifact-two-components.json", + "path": "vectors/documents/artifact-two-components.json", + "sha256": "9d2d77db996adea115097fd4ef3c4a3ffbe4a08799aaea256d00cf3e94d5969e", + "byteLength": 2017 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/bom.json", + "path": "vectors/documents/bom.json", + "sha256": "aa25e978046d680ef8740d837e6de5bc1e2a2dc6089dbda1012544b538d53f65", + "byteLength": 5 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/companion-float.json", + "path": "vectors/documents/companion-float.json", + "sha256": "eb454acf3392a959782b8b7e53332d65ebd0c6607d77a1f17561f91534987cee", + "byteLength": 33 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/companion-unsafe-integer.json", + "path": "vectors/documents/companion-unsafe-integer.json", + "sha256": "98f3e87d38e17bce0a5e1b2076ae16f78bdf45001dfd192f39be0fe94a50116d", + "byteLength": 46 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/consumer-fallback-unknown-pack.json", + "path": "vectors/documents/consumer-fallback-unknown-pack.json", + "sha256": "8c7a49e4b3b81d1880e64bdee1734c4805a1c4daffc599683ce098d47e0c2011", + "byteLength": 1559 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/consumer-fallback-unknown.json", + "path": "vectors/documents/consumer-fallback-unknown.json", + "sha256": "39fb7ccbef49a24c8f0f2241eb8413c56521df4c4aacd9b75206301718a8aaf4", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/consumer-graph.json", + "path": "vectors/documents/consumer-graph.json", + "sha256": "f380c38339a85ab4ef31c23640b319f85bc7783e8e75c41d11ae741196b604d1", + "byteLength": 2353 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/consumer-rule-id-duplicate-pack.json", + "path": "vectors/documents/consumer-rule-id-duplicate-pack.json", + "sha256": "93560dbc1b0537cf834d02b2607dade6b9a6407c5a37caf36954822762f0c312", + "byteLength": 1828 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/consumer-rule-id-duplicate.json", + "path": "vectors/documents/consumer-rule-id-duplicate.json", + "sha256": "4a1285549c9649cbdd756fe836010d1e4e159f36a0bc9cf7a0ad704c38a38b4a", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-decimal-raw-pack.json", + "path": "vectors/documents/core-decimal-raw-pack.json", + "sha256": "9a2b3c06074ead90e9b34d3213ad9b5665ad05c548dfa9cc3be57e8e9f23634b", + "byteLength": 1648 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-decimal-raw.json", + "path": "vectors/documents/core-decimal-raw.json", + "sha256": "93a8d631bd4244f3b309451071488b35e064ab3618934a76b0d9ebf46cb5e442", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-decimal-requested-canon-pack.json", + "path": "vectors/documents/core-decimal-requested-canon-pack.json", + "sha256": "9a2b3c06074ead90e9b34d3213ad9b5665ad05c548dfa9cc3be57e8e9f23634b", + "byteLength": 1648 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-decimal-requested-canon.json", + "path": "vectors/documents/core-decimal-requested-canon.json", + "sha256": "d4f9c354aaaf6093d5034cf6adcd8c01bb1aa9cbcf32f9ccafdd9aa2790bb737", + "byteLength": 2352 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-exponent-308-pack.json", + "path": "vectors/documents/core-exponent-308-pack.json", + "sha256": "52bd1104aedcc81011f2b0aaac2f5a3e082dc96b7a9c490cf441a005d3e3667e", + "byteLength": 1650 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-exponent-308.json", + "path": "vectors/documents/core-exponent-308.json", + "sha256": "c9275574c422b7520ae07d85bf6491d895b7fc62689308d6338df55180c3cfc0", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-exponent-over-pack.json", + "path": "vectors/documents/core-exponent-over-pack.json", + "sha256": "7d593e7fac09abf836b599e7719f33850381bd60d5aa8c078a7cf2d43c494843", + "byteLength": 1650 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-exponent-over.json", + "path": "vectors/documents/core-exponent-over.json", + "sha256": "0cdf2672ddded5c222e3b18c7a9b7041f0175591be323a39b5bddff6672e5763", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-number-128-pack.json", + "path": "vectors/documents/core-number-128-pack.json", + "sha256": "0a694f57fa21a82551738a128022578c837b332848866db302da838c70b8e3c7", + "byteLength": 1773 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-number-128.json", + "path": "vectors/documents/core-number-128.json", + "sha256": "5e97a1562791b398a9d7e70533c595a568b889c7966c43ea43eeadf751de6417", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-number-over-128-pack.json", + "path": "vectors/documents/core-number-over-128-pack.json", + "sha256": "bceb1d327714090d58fb463516779aeb50168299e0ff0d2a9de21a7ff5421114", + "byteLength": 1774 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-number-over-128.json", + "path": "vectors/documents/core-number-over-128.json", + "sha256": "4372c8016d83883bc944428d5d09510abac11dc10501cc74cbb7d577913a3eec", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-unsafe-int-raw-pack.json", + "path": "vectors/documents/core-unsafe-int-raw-pack.json", + "sha256": "2857116756d73d0babfcd3ede480fd8d462ea95bfcbc234c5e80983b3c4b9910", + "byteLength": 1661 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-unsafe-int-raw.json", + "path": "vectors/documents/core-unsafe-int-raw.json", + "sha256": "880c2b146822bd4ca14b5bb79953f706aa770f0b61afc7c76312ed4a23a1d715", + "byteLength": 2189 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-unsafe-int-requested-canon-pack.json", + "path": "vectors/documents/core-unsafe-int-requested-canon-pack.json", + "sha256": "2857116756d73d0babfcd3ede480fd8d462ea95bfcbc234c5e80983b3c4b9910", + "byteLength": 1661 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/core-unsafe-int-requested-canon.json", + "path": "vectors/documents/core-unsafe-int-requested-canon.json", + "sha256": "f0dbc21fab5b69614e11c9948a897a1ec9f7e3dc3d8bb23e41bbd2521220ff9f", + "byteLength": 2352 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/coverage-duplicate.json", + "path": "vectors/documents/coverage-duplicate.json", + "sha256": "5c804382923831378fd72aa6a4a115cefc5c59357c7fd5ff7fb3b57cec158a0d", + "byteLength": 2347 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/coverage-omitted.json", + "path": "vectors/documents/coverage-omitted.json", + "sha256": "4fad299227c43ff3d3fda7cadd881398f7b908bfa6177abb475e50fe2f3e7c65", + "byteLength": 2146 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/coverage-outside.json", + "path": "vectors/documents/coverage-outside.json", + "sha256": "f53966ceab71d7d1577684d064c52d3515f266da03e811e1444408875757cb5d", + "byteLength": 2348 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/depth-32.json", + "path": "vectors/documents/depth-32.json", + "sha256": "4e04cac422d9ecd4a5f6221653eeb4eaf29077cf3f588cd36bf6dc8ead76971f", + "byteLength": 65 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/depth-33.json", + "path": "vectors/documents/depth-33.json", + "sha256": "eac9bf029c22e177c74309fb891e3351dccfb04f055127ea82dc2dc3136cd899", + "byteLength": 67 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/desk-managed-alias-refused.json", + "path": "vectors/documents/desk-managed-alias-refused.json", + "sha256": "5234fd95d7550559cd2c2147bed06f9ff6f905b2e4607e8eeebfef03a778698c", + "byteLength": 2014 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/document-max-bytes.json", + "path": "vectors/documents/document-max-bytes.json", + "sha256": "515b22dea881243654a2c04aacd1fae4079e914bb63c9fd028a21821c0add188", + "byteLength": 262144 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/duplicate-json.json", + "path": "vectors/documents/duplicate-json.json", + "sha256": "e36957f702ac6bd47232355cad2b9a15a1bc3d6a23f0cbd5bb2d7bf4d33e8288", + "byteLength": 49 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/duplicate-policy-identity.json", + "path": "vectors/documents/duplicate-policy-identity.json", + "sha256": "07f804bccb31243a806fa8bf820089bf5b2328cd68a0a267f00056f0f161b2ed", + "byteLength": 4038 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-0.json", + "path": "vectors/documents/format-0.json", + "sha256": "90e517db584be09a68876e0e12e1fdcfa6bca002cfc249e884f76c009e2646b3", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-2.json", + "path": "vectors/documents/format-2.json", + "sha256": "8c2a26c5f677e592d86b2e216439d45ce1846fd409c66e0b8bc1e827de18e41d", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-before-canon.json", + "path": "vectors/documents/format-before-canon.json", + "sha256": "d945aff06cc556a99fee0d475f16fd5f0fabb96965e74427cb822b465c8b1bf2", + "byteLength": 33 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-before-shape.json", + "path": "vectors/documents/format-before-shape.json", + "sha256": "179cd26a351c7bf45c2fca5bc06ba835aa6eaa1a546cec4aa900706a697598f5", + "byteLength": 51 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-bool.json", + "path": "vectors/documents/format-bool.json", + "sha256": "5dc2e06bd54f5207ecdb5ba27ec2b80f772193a971f06106067aed2ec594bbbd", + "byteLength": 2016 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-int.json", + "path": "vectors/documents/format-int.json", + "sha256": "aff42b4b0a8e641cc5c92c661cdde3537745a2c2466d2b79c7d01e1a6493708b", + "byteLength": 2013 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-leading-zero.json", + "path": "vectors/documents/format-leading-zero.json", + "sha256": "c6a980c290cd29ee4c15883a88e4c80de0f99e4605a5f3e094067bd4a221d3b2", + "byteLength": 2020 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-missing.json", + "path": "vectors/documents/format-missing.json", + "sha256": "4ea51f8934e58095eee944853cc5541124ea94f0b24c09078ac27f465f32d3bc", + "byteLength": 1991 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-newline.json", + "path": "vectors/documents/format-newline.json", + "sha256": "dc41a327f8e1c762c6d2326badcfc829814c970f7afbbbbc54f87d585eea74da", + "byteLength": 2021 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-patch.json", + "path": "vectors/documents/format-patch.json", + "sha256": "dcbac865d354a2865bf1d17a0197c603f5a120326958bb7e8cbd95ca8dc20355", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-short.json", + "path": "vectors/documents/format-short.json", + "sha256": "93f0b639cbb98ad9ec64d16c09d58010f951c5664962e8cf1838da5b030a5769", + "byteLength": 2015 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-suffix.json", + "path": "vectors/documents/format-suffix.json", + "sha256": "debe48d95d872019bc1bdfadff03f645e14dfed66dd034d0d77d95520ca10f5c", + "byteLength": 2024 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-unicode.json", + "path": "vectors/documents/format-unicode.json", + "sha256": "e0ba64d6e3ac4e5f72cbcbea04b9dfe5052747d56244950835feaf08c9db041a", + "byteLength": 2020 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/format-v-prefix.json", + "path": "vectors/documents/format-v-prefix.json", + "sha256": "d18d8d65f5126fde63083e1594ef93f0944e092d98e29d54ee3dfe1cc0d8a66a", + "byteLength": 2020 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/informational-max.json", + "path": "vectors/documents/informational-max.json", + "sha256": "569a5b0680eafb6308c2984912e4a702054e6839a6c484bec7eb68ae0fc8aad8", + "byteLength": 2554 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/informational-over.json", + "path": "vectors/documents/informational-over.json", + "sha256": "361db3f18d7640ac7ecaebfe28e45436ca10bc8ebc806fd23f1ac5145ca3c472", + "byteLength": 2554 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/invalid-utf8.json", + "path": "vectors/documents/invalid-utf8.json", + "sha256": "36781faac995a68b69aab7d540747e0c70efed427e66a608cdf64fc4feaaff12", + "byteLength": 9 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/kind-id-confusion.json", + "path": "vectors/documents/kind-id-confusion.json", + "sha256": "d7f690d0ca4b7962916984ee5ee92b70c3b7464016c0e003b0a3bbf4560127c8", + "byteLength": 2357 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/limited-scope-missing-basis.json", + "path": "vectors/documents/limited-scope-missing-basis.json", + "sha256": "9d9a9b30e6bfa07ca3aa059f14f1011bf2b1dcee92e218d8ea6656b8bad65584", + "byteLength": 2854 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/limited-scope-unknown.json", + "path": "vectors/documents/limited-scope-unknown.json", + "sha256": "670a45f40a0ff1b21a12481f962f50ae63618d79fa30932882e45ed645a64bdd", + "byteLength": 3076 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/malformed-over-depth.json", + "path": "vectors/documents/malformed-over-depth.json", + "sha256": "fdc562409aec5a2549f9a1b1f21155ec3b49c71ce76b3ad080c56ba1d0543a76", + "byteLength": 68 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/missing-governing-policy.json", + "path": "vectors/documents/missing-governing-policy.json", + "sha256": "27f20c087c208144a234684ca1719ab9e0013dad914be4ddf507a546e1d216f8", + "byteLength": 686 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/missing-narrative.json", + "path": "vectors/documents/missing-narrative.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/multiple-json.json", + "path": "vectors/documents/multiple-json.json", + "sha256": "b51f08b698d88d8027a935d9db649774949f5fb41a0c559bfee6a9a13225c72d", + "byteLength": 4 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/multiple-policy-identities.json", + "path": "vectors/documents/multiple-policy-identities.json", + "sha256": "fedf62df6fd02f041a2ea418305804ab5ace22bc0946cd1c876c0063937ce2c5", + "byteLength": 3985 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/narrative-max.json", + "path": "vectors/documents/narrative-max.json", + "sha256": "c1592868007ae1365c18c55e7325d641f82cb4dfcf7ad71ab5cda2fb9a984504", + "byteLength": 1119 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/narrative-over.json", + "path": "vectors/documents/narrative-over.json", + "sha256": "5ec2805842ca8c97450c468d2b78c6063d48c00287a1195da476e23e36c0008f", + "byteLength": 1119 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/nonfinite.json", + "path": "vectors/documents/nonfinite.json", + "sha256": "d5b592c05dc25b5032553f1b27f4139be95e881f73db33b02b05ab20c3f9981e", + "byteLength": 3 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/number-literal-over-128.json", + "path": "vectors/documents/number-literal-over-128.json", + "sha256": "e2eb26c79686e936e6603fbcd49b32881635021917d175c4df147b5e21b44f5c", + "byteLength": 159 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/opaque-original.json", + "path": "vectors/documents/opaque-original.json", + "sha256": "feb70c8c8e2a8f80e634980de161fa1bb092460969707696b5a3b5059ad71df3", + "byteLength": 2023 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/opaque-original.pdf", + "path": "vectors/documents/opaque-original.pdf", + "sha256": "af7777006b9a8e6b9ffd9dbc25f3d4f3c54331e9f74948ba9d1facdf63b1a8be", + "byteLength": 16 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/original-max.json", + "path": "vectors/documents/original-max.json", + "sha256": "78948872a9e1ff6eddff492224fe06858b0f4c0e0f8439553e49d58043abc541", + "byteLength": 2023 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/original-over.json", + "path": "vectors/documents/original-over.json", + "sha256": "990e5847fc18a19f13a1cf7df4dd55b943e6be3c65ba87c25189405ac896c1a0", + "byteLength": 2023 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/permission-field.json", + "path": "vectors/documents/permission-field.json", + "sha256": "87516d167771479d3b14674ddfc747e03e6a3b12175af1a6cbf91daa7ad34069", + "byteLength": 2042 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/policy-canon-stale.json", + "path": "vectors/documents/policy-canon-stale.json", + "sha256": "45fa4fb5f254eeed1037d1374524b49ed6b94bf484a6f7b7af77a28c725c271a", + "byteLength": 2352 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/policy-identity-stale.json", + "path": "vectors/documents/policy-identity-stale.json", + "sha256": "77f758365f4c4b772cde630b45f2045e8434511dc5d5e261c67e41de9db7a78c", + "byteLength": 2320 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/policy-version-ref-stale.json", + "path": "vectors/documents/policy-version-ref-stale.json", + "sha256": "f048ab96431c7a97f44a4339b72dc03a164c0c7747a8d2aa9b95fafa099e4457", + "byteLength": 2352 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/prototype-selector-refused.json", + "path": "vectors/documents/prototype-selector-refused.json", + "sha256": "b537c0a1efb5ebc6e06e8a8e60dca2d0ad3d2c4f5e4eeab091b23c3dff4fa408", + "byteLength": 2152 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/registration-count-16.json", + "path": "vectors/documents/registration-count-16.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/registration-count-17.json", + "path": "vectors/documents/registration-count-17.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/requirements-field.json", + "path": "vectors/documents/requirements-field.json", + "sha256": "397484bcb95f136afcc4b2201a6137ef100d9cdc3c8a0b2326dbc1653d2db62c", + "byteLength": 2043 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/review-max.json", + "path": "vectors/documents/review-max.json", + "sha256": "729e84b3a8c8826638b7cf5f9703429658aee12eb9aafa0a5dde82f50f450718", + "byteLength": 2356 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/review-over.json", + "path": "vectors/documents/review-over.json", + "sha256": "9ca0faef44ae60d277c1744c358a55c219400b15a6365f519ba20059d14d153b", + "byteLength": 2356 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/second-policy.json", + "path": "vectors/documents/second-policy.json", + "sha256": "144558275929f298692344329199afd892f5d74f1bc8aa70bea4bda14e98d627", + "byteLength": 1988 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/section-id-duplicate.json", + "path": "vectors/documents/section-id-duplicate.json", + "sha256": "c63007da9f867e07f68f8a91758f2054436e91263ddb7c50b8bd5dee21cf80be", + "byteLength": 2014 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/shared-bytes-multiple-media-types.json", + "path": "vectors/documents/shared-bytes-multiple-media-types.json", + "sha256": "f4d2bc2c621771b30f3ae984ab3fd05a00891827c047d5a746fc44a3ad23ad1a", + "byteLength": 2022 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/signature-field.json", + "path": "vectors/documents/signature-field.json", + "sha256": "fc4064630a3ef93cbfb46969a22600796a2954256ca42876325673e5d2ef49d1", + "byteLength": 2041 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/singleton-with-id.json", + "path": "vectors/documents/singleton-with-id.json", + "sha256": "232d4bbb79ff949aaf6c9e17292c5c70426595d8e761c6fefecb6d225e7d677a", + "byteLength": 2204 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/source-id-unknown.json", + "path": "vectors/documents/source-id-unknown.json", + "sha256": "e93860ee23385cee86b3bca725e14c3fa4f45aadd3c5cb4fa422ee3d008cd3f1", + "byteLength": 2009 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/stale-material-hash.json", + "path": "vectors/documents/stale-material-hash.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/stale-material-length.json", + "path": "vectors/documents/stale-material-length.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/standalone-policy.json", + "path": "vectors/documents/standalone-policy.json", + "sha256": "6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/surrogate.json", + "path": "vectors/documents/surrogate.json", + "sha256": "8c0c59dd0d275aadcd462a5fe12eb352cbdfeaf961eae4f85a4660521df7d2f5", + "byteLength": 8 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/unknown-kind-registration-over.json", + "path": "vectors/documents/unknown-kind-registration-over.json", + "sha256": "1e2f99280db3d76fbb608f1c13a53be498d2b4bfc46836b2893383895cf076ab", + "byteLength": 43 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/unknown-rule.json", + "path": "vectors/documents/unknown-rule.json", + "sha256": "b4d8bc7e5745d897cda79f121721b388b4da9e1fe125d782dbe161cddd03aa87", + "byteLength": 2351 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/unregistered-media-type.json", + "path": "vectors/documents/unregistered-media-type.json", + "sha256": "1c816a89de90ad710cfeb4b17bad6f0720515395e0af0b35e0394d539e605b30", + "byteLength": 2022 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/unsupported-element.json", + "path": "vectors/documents/unsupported-element.json", + "sha256": "356114c27d81685231f3e6b7aa32305ae890319cf392e652e69d8ce908f5ca90", + "byteLength": 2201 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-invalid.json", + "path": "vectors/documents/uri-invalid.json", + "sha256": "2c8f6c238143c7dfa4381ab81b78365bfd43902a7eea09b872f1ee37ca0789ba", + "byteLength": 1964 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/manifest.json", + "path": "vectors/manifest.json", + "sha256": "7681dfd18be6cb8a251095b67f69d6868693c34b3f68a6ee5e94ac06fdbfae30", + "byteLength": 185434 + }, + { + "sourcePath": "LICENSE", + "path": "LICENSE", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "byteLength": 11358 + }, + { + "sourcePath": "NOTICE", + "path": "NOTICE", + "sha256": "acdae3bd2771acf3a456db3241e33d514c6cfc4ee9ea9cdb05344b6b7a96836e", + "byteLength": 194 + }, + { + "sourcePath": "rfcs/0023-policy-companion.md", + "path": "0023-policy-companion.md", + "sha256": "626e0422f29aaf69db6d3cb47ee3c3232acccf0f7b658d4fbe042c42d3be49ca", + "byteLength": 22215 + } + ] +} diff --git a/internal/policy/candidate/vectors.schema.json b/internal/policy/candidate/vectors.schema.json new file mode 100644 index 00000000..932b6190 --- /dev/null +++ b/internal/policy/candidate/vectors.schema.json @@ -0,0 +1,203 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:jps:proposal:policy-companion:1.0.0:vectors", + "title": "Proposed draft agreement-vector carrier; not a release envelope", + "type": "object", + "additionalProperties": false, + "required": [ + "vectorSuiteVersion", + "maturity", + "synthetic", + "cases" + ], + "properties": { + "vectorSuiteVersion": { + "const": "1" + }, + "maturity": { + "const": "proposed-draft" + }, + "synthetic": { + "const": true + }, + "cases": { + "type": "array", + "minItems": 1, + "maxItems": 128, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "document", + "materials", + "expected" + ], + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 128, + "pattern": "^[a-z][a-z0-9-]*$" + }, + "document": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "repeatByte", + "byteLength" + ], + "properties": { + "repeatByte": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "byteLength": { + "type": "integer", + "minimum": 0, + "maximum": 4194305 + } + } + } + ] + }, + "materials": { + "type": "array", + "maxItems": 17, + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "source", + "content" + ], + "properties": { + "source": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "path" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "repeatByte", + "byteLength" + ], + "properties": { + "repeatByte": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "byteLength": { + "type": "integer", + "minimum": 0, + "maximum": 4194305 + } + } + } + ] + }, + "content": { + "type": "object", + "additionalProperties": false, + "required": [ + "bytesDigest", + "byteLength", + "mediaType" + ], + "properties": { + "bytesDigest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}(?![\\s\\S])" + }, + "byteLength": { + "type": "integer", + "minimum": 0, + "maximum": 4194305 + }, + "mediaType": { + "type": "string", + "maxLength": 128, + "pattern": "^[a-z0-9!#$&^_.+-]+/[a-z0-9!#$&^_.+-]+(?![\\s\\S])" + } + }, + "description": "Generic fixture-carrier reference; consuming roles impose their own bounds." + } + } + } + }, + "expected": { + "oneOf": [ + { + "const": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "code" + ], + "properties": { + "status": { + "const": "refused" + }, + "code": { + "enum": [ + "input-over-bound", + "invalid-json", + "invalid-selector", + "unsupported-format", + "invalid-document", + "missing-material", + "reference-mismatch", + "invalid-anchor", + "invalid-coverage", + "invalid-consumer", + "unsupported-canonical-identity", + "invalid-carrier" + ] + } + } + } + ] + } + } + } + } + } +} diff --git a/internal/policy/candidate/vectors/README.md b/internal/policy/candidate/vectors/README.md new file mode 100644 index 00000000..92530bb0 --- /dev/null +++ b/internal/policy/candidate/vectors/README.md @@ -0,0 +1,87 @@ +# Reusable proposed-draft agreement vectors + +[manifest.json](manifest.json) supplies exact candidate inputs and exact expected +results for independent readers to execute. This is synthetic review material, +not an adopted JPS corpus or independent implementation evidence. No case asserts +approval, live authority, complete organizational coverage or permission. + +The manifest is closed under [vectors.schema.json](../vectors.schema.json). It has +`vectorSuiteVersion: "1"`, `maturity: "proposed-draft"`, `synthetic: true` and +`cases`. This carrier version is local test scaffolding, distinct from the +companion `formatVersion` and artifact `version`; it is not a release envelope. +All paths are relative to **rfcs/policy-companion-contract/**, the candidate root, +regardless of the manifest's location. A path must resolve inside that root, +including after resolving symlinks; absolute paths and escaping paths refuse. +NUL-containing paths and path-normalization failures are `invalid-carrier`. +Do not fetch any URI in a document or reference. + +Each case is exactly `{id, document, materials, expected}`: + +- `id` is a unique readable test identifier. +- `document` describes exact root companion bytes using the source grammar below. +- `materials` is an **ordered** array of `{source, content}` registrations. `source` + yields exact retained bytes; `content` independently declares the raw digest, + byte length and media type. Do not repair a mismatching declaration, normalize + bytes, derive a new declaration, or infer an unregistered media type. +- `expected` is the complete result object to compare with the candidate result. + JSON object member order is irrelevant; names, values and absence of any extra + members must agree. Compare both valid and refusal objects, not only exit codes. + +The complete closed source grammar has only two alternatives: + +```json +{"path":"examples/data-access/policy.json"} +{"repeatByte":120,"byteLength":1048576} +``` + +For `path`, read the file's bytes exactly; no text conversion or newline changes. +For `repeatByte`, allocate **exactly** `byteLength` copies of the unsigned byte +`repeatByte` (integer 0–255), with no prefix, suffix or encoding. `byteLength` is an +integer 0–4,194,305. A value of zero generates empty bytes. There are no mutations, +JSON reserialization instructions, interpolation, automatic reference rebinding or +other generators. One byte above a normal maximum is intentionally representable +to test refusal. Static document files already carry every altered field and exact +reference; readers do not need the Python scripts used during authoring. + +To run a case, first measure/parse/select/canonical-domain-check its root bytes as +[contract §5](../README.md#5-resource-limits-and-refusal-classifications) specifies. +Then check the input's registration count (maximum 16), register materials in list +order (acquiring one source immediately before its registration and checking +declarations and distinct-byte budget), and validate the root +schema and its semantic references. Root bytes themselves are subject to the +262,144-byte limit and count toward the distinct-material budget only when +explicitly registered. A referenced Policy or Pack must be retained in materials; +the carrier does not implicitly register the root or fetch a missing digest. +Return the **first** failing phase's bounded result. Carrier preparation errors +such as an invalid path are `invalid-carrier`; an unavailable file is +`missing-material`. These are never successful document readings. + +The compound transport/ordering vectors intentionally name a missing file +(`vectors/intentionally-missing-transport.bin`) or a NUL-containing path. These +are test harness transport inputs, not absent files that a port should create, +repair or fetch. Some earlier root/registration refusals must prevent acquisition +of those later sources. The `vector-carrier-nul-path` case actually reaches its +malformed path and returns `invalid-carrier`. The result for each case includes +these transport refusals; the harness compares them with `expected` and continues +to the next case. Carrier-manifest schema/setup failures remain harness failures. + +The manifest includes one over-bound registration count and one over-bound +original reference; its own carrier schema permits those counterexamples. No +candidate reader must accept them. Aggregate boundary vectors include separately +registered identical bytes under two media types; both resolve, and the bytes +spend the aggregate budget only once. Every role independently applies its size +limit. Raw Core numeric extensions include fractional, exponent and unsafe integer +literals; expected results distinguish optional canonical identity from raw pins. + +Run the reference harness with the repository's pinned dependencies: + +```sh +python rfcs/policy-companion-contract/check_vectors.py +``` + +Successful harness output is exactly +`{"status":"matched","cases":104,"maturity":"proposed-draft"}`; this is harness +agreement, not the result for an individual document or a conformance claim. Each +refusal vector's exact output is retained in the manifest. The harness and schema +are optional conveniences: another language can read these same bytes and the +source grammar directly, without importing Python or mutable prototype helpers. diff --git a/internal/policy/candidate/vectors/documents/aggregate-max.json b/internal/policy/candidate/vectors/documents/aggregate-max.json new file mode 100644 index 00000000..9a63cd46 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/aggregate-max.json @@ -0,0 +1,25 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881", + "byteLength": 1, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "all", + "title": "All", + "anchor": { + "startByte": 0, + "endByte": 1, + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881" + } + } + ], + "sourceProvenance": [] +} diff --git a/internal/policy/candidate/vectors/documents/aggregate-over.json b/internal/policy/candidate/vectors/documents/aggregate-over.json new file mode 100644 index 00000000..9a63cd46 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/aggregate-over.json @@ -0,0 +1,25 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881", + "byteLength": 1, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "all", + "title": "All", + "anchor": { + "startByte": 0, + "endByte": 1, + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881" + } + } + ], + "sourceProvenance": [] +} diff --git a/internal/policy/candidate/vectors/documents/aggregate-shared-media-counted-once.json b/internal/policy/candidate/vectors/documents/aggregate-shared-media-counted-once.json new file mode 100644 index 00000000..9a63cd46 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/aggregate-shared-media-counted-once.json @@ -0,0 +1,25 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881", + "byteLength": 1, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "all", + "title": "All", + "anchor": { + "startByte": 0, + "endByte": 1, + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881" + } + } + ], + "sourceProvenance": [] +} diff --git a/internal/policy/candidate/vectors/documents/anchor-empty-range.json b/internal/policy/candidate/vectors/documents/anchor-empty-range.json new file mode 100644 index 00000000..562186a1 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/anchor-empty-range.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 41, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/anchor-outside-narrative.json b/internal/policy/candidate/vectors/documents/anchor-outside-narrative.json new file mode 100644 index 00000000..801e4b1a --- /dev/null +++ b/internal/policy/candidate/vectors/documents/anchor-outside-narrative.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 999999, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/anchor-over-bound.json b/internal/policy/candidate/vectors/documents/anchor-over-bound.json new file mode 100644 index 00000000..632c1534 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/anchor-over-bound.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 1048577, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/anchor-stale-digest.json b/internal/policy/candidate/vectors/documents/anchor-stale-digest.json new file mode 100644 index 00000000..6213ac8f --- /dev/null +++ b/internal/policy/candidate/vectors/documents/anchor-stale-digest.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:0000000000000000000000000000000000000000000000000000000000000000" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/anchor-utf8-split.json b/internal/policy/candidate/vectors/documents/anchor-utf8-split.json new file mode 100644 index 00000000..29ccbc02 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/anchor-utf8-split.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 25, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/approval-field.json b/internal/policy/candidate/vectors/documents/approval-field.json new file mode 100644 index 00000000..c282482b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/approval-field.json @@ -0,0 +1,77 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ], + "approved": true +} diff --git a/internal/policy/candidate/vectors/documents/artifact-build.json b/internal/policy/candidate/vectors/documents/artifact-build.json new file mode 100644 index 00000000..3bdf3da3 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-build.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0+build", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-independent.json b/internal/policy/candidate/vectors/documents/artifact-independent.json new file mode 100644 index 00000000..3ac9ae59 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-independent.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "7.3.42", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-leading-zero.json b/internal/policy/candidate/vectors/documents/artifact-leading-zero.json new file mode 100644 index 00000000..a86fd80b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-leading-zero.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.00.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-max-256.json b/internal/policy/candidate/vectors/documents/artifact-max-256.json new file mode 100644 index 00000000..202c6a3b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-max-256.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-newline.json b/internal/policy/candidate/vectors/documents/artifact-newline.json new file mode 100644 index 00000000..33a0dca7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-newline.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0\n", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-number.json b/internal/policy/candidate/vectors/documents/artifact-number.json new file mode 100644 index 00000000..3cfddc4e --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-number.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": 1, + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-over-256.json b/internal/policy/candidate/vectors/documents/artifact-over-256.json new file mode 100644 index 00000000..bf40bfcc --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-over-256.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/artifact-two-components.json b/internal/policy/candidate/vectors/documents/artifact-two-components.json new file mode 100644 index 00000000..4a25db33 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/artifact-two-components.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/bom.json b/internal/policy/candidate/vectors/documents/bom.json new file mode 100644 index 00000000..22fdca1b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/bom.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/companion-float.json b/internal/policy/candidate/vectors/documents/companion-float.json new file mode 100644 index 00000000..e967560d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/companion-float.json @@ -0,0 +1 @@ +{"formatVersion":"1.0.0","n":1.0} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/companion-unsafe-integer.json b/internal/policy/candidate/vectors/documents/companion-unsafe-integer.json new file mode 100644 index 00000000..ea15b97d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/companion-unsafe-integer.json @@ -0,0 +1 @@ +{"formatVersion":"1.0.0","n":9007199254740992} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/consumer-fallback-unknown-pack.json b/internal/policy/candidate/vectors/documents/consumer-fallback-unknown-pack.json new file mode 100644 index 00000000..a10ed874 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/consumer-fallback-unknown-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "unknown", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/consumer-fallback-unknown.json b/internal/policy/candidate/vectors/documents/consumer-fallback-unknown.json new file mode 100644 index 00000000..2db44594 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/consumer-fallback-unknown.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:8c7a49e4b3b81d1880e64bdee1734c4805a1c4daffc599683ce098d47e0c2011", + "byteLength": 1559, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/consumer-graph.json b/internal/policy/candidate/vectors/documents/consumer-graph.json new file mode 100644 index 00000000..95714df7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/consumer-graph.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "graph", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate-pack.json b/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate-pack.json new file mode 100644 index 00000000..ef28391b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate-pack.json @@ -0,0 +1,74 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "different" + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate.json b/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate.json new file mode 100644 index 00000000..85a16d8a --- /dev/null +++ b/internal/policy/candidate/vectors/documents/consumer-rule-id-duplicate.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:93560dbc1b0537cf834d02b2607dade6b9a6407c5a37caf36954822762f0c312", + "byteLength": 1828, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-decimal-raw-pack.json b/internal/policy/candidate/vectors/documents/core-decimal-raw-pack.json new file mode 100644 index 00000000..cc3aa167 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-decimal-raw-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 1.5 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-decimal-raw.json b/internal/policy/candidate/vectors/documents/core-decimal-raw.json new file mode 100644 index 00000000..d825392a --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-decimal-raw.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:9a2b3c06074ead90e9b34d3213ad9b5665ad05c548dfa9cc3be57e8e9f23634b", + "byteLength": 1648, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-decimal-requested-canon-pack.json b/internal/policy/candidate/vectors/documents/core-decimal-requested-canon-pack.json new file mode 100644 index 00000000..cc3aa167 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-decimal-requested-canon-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 1.5 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-decimal-requested-canon.json b/internal/policy/candidate/vectors/documents/core-decimal-requested-canon.json new file mode 100644 index 00000000..ba4e1229 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-decimal-requested-canon.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:9a2b3c06074ead90e9b34d3213ad9b5665ad05c548dfa9cc3be57e8e9f23634b", + "byteLength": 1648, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-exponent-308-pack.json b/internal/policy/candidate/vectors/documents/core-exponent-308-pack.json new file mode 100644 index 00000000..34312ff1 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-exponent-308-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 1e308 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-exponent-308.json b/internal/policy/candidate/vectors/documents/core-exponent-308.json new file mode 100644 index 00000000..cf42a308 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-exponent-308.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:52bd1104aedcc81011f2b0aaac2f5a3e082dc96b7a9c490cf441a005d3e3667e", + "byteLength": 1650, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-exponent-over-pack.json b/internal/policy/candidate/vectors/documents/core-exponent-over-pack.json new file mode 100644 index 00000000..12548437 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-exponent-over-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 1e309 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-exponent-over.json b/internal/policy/candidate/vectors/documents/core-exponent-over.json new file mode 100644 index 00000000..9f9e334a --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-exponent-over.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:7d593e7fac09abf836b599e7719f33850381bd60d5aa8c078a7cf2d43c494843", + "byteLength": 1650, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-number-128-pack.json b/internal/policy/candidate/vectors/documents/core-number-128-pack.json new file mode 100644 index 00000000..c4d31e6d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-number-128-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-number-128.json b/internal/policy/candidate/vectors/documents/core-number-128.json new file mode 100644 index 00000000..8045ac88 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-number-128.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:0a694f57fa21a82551738a128022578c837b332848866db302da838c70b8e3c7", + "byteLength": 1773, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-number-over-128-pack.json b/internal/policy/candidate/vectors/documents/core-number-over-128-pack.json new file mode 100644 index 00000000..3fc39e1b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-number-over-128-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-number-over-128.json b/internal/policy/candidate/vectors/documents/core-number-over-128.json new file mode 100644 index 00000000..be3380c4 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-number-over-128.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:bceb1d327714090d58fb463516779aeb50168299e0ff0d2a9de21a7ff5421114", + "byteLength": 1774, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-unsafe-int-raw-pack.json b/internal/policy/candidate/vectors/documents/core-unsafe-int-raw-pack.json new file mode 100644 index 00000000..72575108 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-unsafe-int-raw-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 9007199254740992 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-unsafe-int-raw.json b/internal/policy/candidate/vectors/documents/core-unsafe-int-raw.json new file mode 100644 index 00000000..230eb4dc --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-unsafe-int-raw.json @@ -0,0 +1,71 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:2857116756d73d0babfcd3ede480fd8d462ea95bfcbc234c5e80983b3c4b9910", + "byteLength": 1661, + "mediaType": "application/json" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon-pack.json b/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon-pack.json new file mode 100644 index 00000000..72575108 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon-pack.json @@ -0,0 +1,67 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + }, + "extensions": { + "com.example.candidate": { + "candidate-number": 9007199254740992 + } + } +} diff --git a/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon.json b/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon.json new file mode 100644 index 00000000..a11d5f73 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/core-unsafe-int-requested-canon.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:2857116756d73d0babfcd3ede480fd8d462ea95bfcbc234c5e80983b3c4b9910", + "byteLength": 1661, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/coverage-duplicate.json b/internal/policy/candidate/vectors/documents/coverage-duplicate.json new file mode 100644 index 00000000..c05cf61d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/coverage-duplicate.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "eligibility", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/coverage-omitted.json b/internal/policy/candidate/vectors/documents/coverage-omitted.json new file mode 100644 index 00000000..b8d4f284 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/coverage-omitted.json @@ -0,0 +1,70 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/coverage-outside.json b/internal/policy/candidate/vectors/documents/coverage-outside.json new file mode 100644 index 00000000..fa81751e --- /dev/null +++ b/internal/policy/candidate/vectors/documents/coverage-outside.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "unknown", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/depth-32.json b/internal/policy/candidate/vectors/documents/depth-32.json new file mode 100644 index 00000000..0d73e241 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/depth-32.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/depth-33.json b/internal/policy/candidate/vectors/documents/depth-33.json new file mode 100644 index 00000000..b9777e0a --- /dev/null +++ b/internal/policy/candidate/vectors/documents/depth-33.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/desk-managed-alias-refused.json b/internal/policy/candidate/vectors/documents/desk-managed-alias-refused.json new file mode 100644 index 00000000..497f3947 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/desk-managed-alias-refused.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "desk-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/document-max-bytes.json b/internal/policy/candidate/vectors/documents/document-max-bytes.json new file mode 100644 index 00000000..b50b49e7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/document-max-bytes.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] + } diff --git a/internal/policy/candidate/vectors/documents/duplicate-json.json b/internal/policy/candidate/vectors/documents/duplicate-json.json new file mode 100644 index 00000000..27e3b357 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/duplicate-json.json @@ -0,0 +1 @@ +{"formatVersion":"1.0.0","formatVersion":"1.0.0"} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/duplicate-policy-identity.json b/internal/policy/candidate/vectors/documents/duplicate-policy-identity.json new file mode 100644 index 00000000..4aefa2b8 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/duplicate-policy-identity.json @@ -0,0 +1,128 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + }, + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access. Extra synthetic note." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-0.json b/internal/policy/candidate/vectors/documents/format-0.json new file mode 100644 index 00000000..a4f77172 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-0.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "0.0.2", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-2.json b/internal/policy/candidate/vectors/documents/format-2.json new file mode 100644 index 00000000..f86d98ec --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-2.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "2.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-before-canon.json b/internal/policy/candidate/vectors/documents/format-before-canon.json new file mode 100644 index 00000000..a56a64b0 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-before-canon.json @@ -0,0 +1 @@ +{"formatVersion":"7.0.0","n":1.5} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/format-before-shape.json b/internal/policy/candidate/vectors/documents/format-before-shape.json new file mode 100644 index 00000000..004c1fcc --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-before-shape.json @@ -0,0 +1,4 @@ +{ + "formatVersion": "7.0.0", + "approved": true +} diff --git a/internal/policy/candidate/vectors/documents/format-bool.json b/internal/policy/candidate/vectors/documents/format-bool.json new file mode 100644 index 00000000..d1fe556d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-bool.json @@ -0,0 +1,76 @@ +{ + "formatVersion": true, + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-int.json b/internal/policy/candidate/vectors/documents/format-int.json new file mode 100644 index 00000000..be645a97 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-int.json @@ -0,0 +1,76 @@ +{ + "formatVersion": 1, + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-leading-zero.json b/internal/policy/candidate/vectors/documents/format-leading-zero.json new file mode 100644 index 00000000..4b3ce9a5 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-leading-zero.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "01.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-missing.json b/internal/policy/candidate/vectors/documents/format-missing.json new file mode 100644 index 00000000..a8bb3dd5 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-missing.json @@ -0,0 +1,75 @@ +{ + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-newline.json b/internal/policy/candidate/vectors/documents/format-newline.json new file mode 100644 index 00000000..caf99a61 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-newline.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0\n", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-patch.json b/internal/policy/candidate/vectors/documents/format-patch.json new file mode 100644 index 00000000..c915f2d9 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-patch.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.1", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-short.json b/internal/policy/candidate/vectors/documents/format-short.json new file mode 100644 index 00000000..0e07cff7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-short.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-suffix.json b/internal/policy/candidate/vectors/documents/format-suffix.json new file mode 100644 index 00000000..673bade3 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-suffix.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0-rc.1", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-unicode.json b/internal/policy/candidate/vectors/documents/format-unicode.json new file mode 100644 index 00000000..2db0c46f --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-unicode.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "١.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/format-v-prefix.json b/internal/policy/candidate/vectors/documents/format-v-prefix.json new file mode 100644 index 00000000..1fdc7fa0 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/format-v-prefix.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "v1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/informational-max.json b/internal/policy/candidate/vectors/documents/informational-max.json new file mode 100644 index 00000000..a51fddb8 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/informational-max.json @@ -0,0 +1,82 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ], + "informationalSources": [ + { + "bytesDigest": "sha256:8f990ba0b577b51cf009ea049368c16bbda1b21e1b93be07a824758bb253c39b", + "byteLength": 1048576, + "mediaType": "text/plain" + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/informational-over.json b/internal/policy/candidate/vectors/documents/informational-over.json new file mode 100644 index 00000000..efe294ef --- /dev/null +++ b/internal/policy/candidate/vectors/documents/informational-over.json @@ -0,0 +1,82 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ], + "informationalSources": [ + { + "bytesDigest": "sha256:154b8ed3c2383ce429058768595935faf7851b5c38db2b1732594be1d88bc05a", + "byteLength": 1048577, + "mediaType": "text/plain" + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/invalid-utf8.json b/internal/policy/candidate/vectors/documents/invalid-utf8.json new file mode 100644 index 00000000..307ff4b1 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/invalid-utf8.json @@ -0,0 +1 @@ +{"x":"ÿ"} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/kind-id-confusion.json b/internal/policy/candidate/vectors/documents/kind-id-confusion.json new file mode 100644 index 00000000..50f4b41e --- /dev/null +++ b/internal/policy/candidate/vectors/documents/kind-id-confusion.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "exception", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/limited-scope-missing-basis.json b/internal/policy/candidate/vectors/documents/limited-scope-missing-basis.json new file mode 100644 index 00000000..048cb7e1 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/limited-scope-missing-basis.json @@ -0,0 +1,92 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/procurement/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/procurement/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "byteLength": 1725, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:205a2afdc68ebd46d5b022256fadec6bd071bc8e34faff481f288c20df008f60" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/procurement/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:539587356d8c0942f6e2c98ec09311e9c55fc4efcc6b9f8845e58db817a8dc58", + "byteLength": 2793, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:f0ef6fe0bb4703eaf6b2c1edf2f12712dffc139e887317c46fc82d83dba71275" + } + }, + "scope": { + "kind": "sections", + "sectionIds": [ + "eligibility", + "conflict-review", + "invoice-payment", + "purchase-scope" + ] + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + { + "sectionId": "conflict-review", + "status": "awaiting-interpretation", + "explanation": "Synthetic open work item: agree the conflict threshold before implementation." + }, + { + "sectionId": "invoice-payment", + "status": "out-of-scope", + "rationale": "This pack assesses eligibility only; treasury payment reconciliation is a separate process." + }, + { + "sectionId": "purchase-scope", + "status": "implemented", + "consumerElements": [ + { + "kind": "applicability" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/limited-scope-unknown.json b/internal/policy/candidate/vectors/documents/limited-scope-unknown.json new file mode 100644 index 00000000..84aac041 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/limited-scope-unknown.json @@ -0,0 +1,98 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/procurement/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/procurement/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:d810d8b3972a4bbc31cd3deb7ada4de965f1ad59bf753cec6748f943213cbcee", + "byteLength": 1725, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:205a2afdc68ebd46d5b022256fadec6bd071bc8e34faff481f288c20df008f60" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/procurement/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:539587356d8c0942f6e2c98ec09311e9c55fc4efcc6b9f8845e58db817a8dc58", + "byteLength": 2793, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:f0ef6fe0bb4703eaf6b2c1edf2f12712dffc139e887317c46fc82d83dba71275" + } + }, + "scope": { + "kind": "sections", + "sectionIds": [ + "eligibility", + "conflict-review", + "invoice-payment", + "purchase-scope", + "unknown" + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + }, + { + "sectionId": "conflict-review", + "status": "awaiting-interpretation", + "explanation": "Synthetic open work item: agree the conflict threshold before implementation." + }, + { + "sectionId": "invoice-payment", + "status": "out-of-scope", + "rationale": "This pack assesses eligibility only; treasury payment reconciliation is a separate process." + }, + { + "sectionId": "purchase-scope", + "status": "implemented", + "consumerElements": [ + { + "kind": "applicability" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:14e401b11a917a3275bc18c2d85f547bfd71cf34a706e160ec54621603b36de2", + "byteLength": 402, + "mediaType": "text/plain" + } + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/malformed-over-depth.json b/internal/policy/candidate/vectors/documents/malformed-over-depth.json new file mode 100644 index 00000000..bd942c38 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/malformed-over-depth.json @@ -0,0 +1 @@ +ÿ[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[0]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/missing-governing-policy.json b/internal/policy/candidate/vectors/documents/missing-governing-policy.json new file mode 100644 index 00000000..f9d2742b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/missing-governing-policy.json @@ -0,0 +1,21 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [] +} diff --git a/internal/policy/candidate/vectors/documents/missing-narrative.json b/internal/policy/candidate/vectors/documents/missing-narrative.json new file mode 100644 index 00000000..ae2a479e --- /dev/null +++ b/internal/policy/candidate/vectors/documents/missing-narrative.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/multiple-json.json b/internal/policy/candidate/vectors/documents/multiple-json.json new file mode 100644 index 00000000..afcb0c48 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/multiple-json.json @@ -0,0 +1 @@ +{}{} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/multiple-policy-identities.json b/internal/policy/candidate/vectors/documents/multiple-policy-identities.json new file mode 100644 index 00000000..3c1da034 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/multiple-policy-identities.json @@ -0,0 +1,128 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/policy-companion-prototype/data-access/pack", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:d20e694ca1f99d0b3c8e239fdec3e5d1122dc875986ef5ed3651a52b3fba2473" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + }, + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/second-policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:144558275929f298692344329199afd892f5d74f1bc8aa70bea4bda14e98d627", + "byteLength": 1988, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:1589cd845a13aa22ceef347d11dcc34d1b7ad27ade2f30c13979a0dc541c0a42" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/narrative-max.json b/internal/policy/candidate/vectors/documents/narrative-max.json new file mode 100644 index 00000000..1654a29c --- /dev/null +++ b/internal/policy/candidate/vectors/documents/narrative-max.json @@ -0,0 +1,40 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:8f990ba0b577b51cf009ea049368c16bbda1b21e1b93be07a824758bb253c39b", + "byteLength": 1048576, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "all", + "title": "All bytes", + "anchor": { + "startByte": 0, + "endByte": 1, + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881" + } + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/narrative-over.json b/internal/policy/candidate/vectors/documents/narrative-over.json new file mode 100644 index 00000000..472bee02 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/narrative-over.json @@ -0,0 +1,40 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:154b8ed3c2383ce429058768595935faf7851b5c38db2b1732594be1d88bc05a", + "byteLength": 1048577, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "all", + "title": "All bytes", + "anchor": { + "startByte": 0, + "endByte": 1, + "bytesDigest": "sha256:2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881" + } + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/nonfinite.json b/internal/policy/candidate/vectors/documents/nonfinite.json new file mode 100644 index 00000000..b955cad2 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/nonfinite.json @@ -0,0 +1 @@ +NaN \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/number-literal-over-128.json b/internal/policy/candidate/vectors/documents/number-literal-over-128.json new file mode 100644 index 00000000..7f06a63b --- /dev/null +++ b/internal/policy/candidate/vectors/documents/number-literal-over-128.json @@ -0,0 +1 @@ +{"formatVersion":"1.0.0","n":999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999} \ No newline at end of file diff --git a/internal/policy/candidate/vectors/documents/opaque-original.json b/internal/policy/candidate/vectors/documents/opaque-original.json new file mode 100644 index 00000000..de7caf77 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/opaque-original.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:af7777006b9a8e6b9ffd9dbc25f3d4f3c54331e9f74948ba9d1facdf63b1a8be", + "byteLength": 16, + "mediaType": "application/pdf" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/opaque-original.pdf b/internal/policy/candidate/vectors/documents/opaque-original.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6e5d30d03fe1de8a86fda3a9ba4184f4c7bca647 GIT binary patch literal 16 XcmY!laB= len("/sourceProvenance") && failure.path[:len("/sourceProvenance")] == "/sourceProvenance" { + return "invalid-document" + } + return "invalid-anchor" + } + return "invalid-coverage" +} diff --git a/internal/policy/candidate_test.go b/internal/policy/candidate_test.go new file mode 100644 index 00000000..f0fa0514 --- /dev/null +++ b/internal/policy/candidate_test.go @@ -0,0 +1,260 @@ +package policy + +import ( + "bytes" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/json" + "io/fs" + "path" + "reflect" + "strings" + "testing" + + "github.com/Judgment-Pack/judgment-pack-runtime/internal/carrier" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/result" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/validation" +) + +func candidateRead(t *testing.T, name string) []byte { + t.Helper() + raw, err := candidate.ReadFile("candidate/" + name) + if err != nil { + t.Fatal(err) + } + return raw +} + +func candidateFixture(t *testing.T, domain string) *fixture { + t.Helper() + base := "examples/" + domain + "/" + manifest := mustMap(t, candidateRead(t, base+"fixture.json")) + f := &fixture{policy: mustMap(t, candidateRead(t, base+"policy.json")), adoption: mustMap(t, candidateRead(t, base+"adoption.json")), raw: map[string][]byte{}} + for _, item := range array(manifest["materials"]) { + entry := object(item) + name := text(entry["path"]) + raw := candidateRead(t, base+name) + f.raw[name] = raw + f.names = append(f.names, name) + f.entries = append(f.entries, wireEntry{Content: object(entry["content"]), DataBase64: encodeMaterial(raw)}) + } + return f +} + +func vectorBytes(source map[string]any) ([]byte, *issue, int) { + if name, ok := source["path"].(string); ok { + if strings.ContainsRune(name, 0) || path.IsAbs(name) || path.Clean(name) != name || strings.HasPrefix(name, "../") { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + raw, err := candidate.ReadFile("candidate/" + name) + if err != nil { + return nil, candidateIssue("missing-material"), result.ExitInvalid + } + return raw, nil, 0 + } + return bytes.Repeat([]byte{byte(number(source["repeatByte"]))}, number(source["byteLength"])), nil, 0 +} + +func TestCandidatePortableVectors(t *testing.T) { + value, failure := carrier.Decode(candidateRead(t, "vectors/manifest.json"), limits()) + if failure != nil { + t.Fatal(failure) + } + manifest := object(value) + cases := array(manifest["cases"]) + if len(cases) != 104 { + t.Fatalf("unexpected vector count %d", len(cases)) + } + for _, value := range cases { + entry := object(value) + t.Run(text(entry["id"]), func(t *testing.T) { + raw, failure, code := vectorBytes(object(entry["document"])) + if failure != nil { + t.Fatalf("root carrier failed: %v %d", failure, code) + } + + r, doc, exit := parseFormat("vectors", raw, CandidateVersion) + if exit == 0 { + r, exit = checkMaterials(r, doc, func() (materialSet, *issue, int) { + registrations := array(entry["materials"]) + if len(registrations) > MaxMaterials { + return nil, candidateIssue("input-over-bound"), result.ExitUnsupported + } + materials := materialSet{} + for _, value := range registrations { + registration := object(value) + retained, failure, code := vectorBytes(object(registration["source"])) + if failure != nil { + return nil, failure, code + } + if err, code := registerCandidateMaterial(object(registration["content"]), retained, materials); err != nil { + return nil, err, code + } + } + return materials, nil, 0 + }, engine(t)) + } else { + r, exit = finishCandidateCheck(r, exit) + } + + actual := mustMap(t, mustJSON(t, r.CandidateResult)) + if !reflect.DeepEqual(actual, object(entry["expected"])) { + t.Fatalf("result %v want %v; exit %d diagnostics %v", actual, entry["expected"], exit, r.Diagnostics) + } + if (exit == 0) != (actual["status"] == "valid") { + t.Fatal("exit/result disagreement") + } + }) + } +} + +func TestCandidateProvenance(t *testing.T) { + raw := candidateRead(t, "provenance.json") + if digest(raw) != "sha256:eb2644703944bd550f954dac3d51124d611867b54465ed1b0f6541018bdfba21" { + t.Fatal("candidate manifest pin changed") + } + manifest := mustMap(t, raw) + if manifest["sourceRevision"] != CandidateRevision || manifest["formatVersion"] != CandidateVersion || manifest["license"] != "Apache-2.0" || manifest["maturity"] != "proposed-draft" { + t.Fatal("incorrect candidate provenance") + } + expected := map[string]bool{"provenance.json": true} + for _, value := range array(manifest["files"]) { + entry := object(value) + name := text(entry["path"]) + raw := candidateRead(t, name) + sum := sha256.Sum256(raw) + if hex.EncodeToString(sum[:]) != entry["sha256"] || len(raw) != int(entry["byteLength"].(float64)) { + t.Fatalf("candidate vendor mismatch: %s", name) + } + expected[name] = true + } + if err := fs.WalkDir(candidate, "candidate", func(name string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() && !expected[strings.TrimPrefix(name, "candidate/")] { + t.Errorf("unmanifested candidate file %s", name) + } + return nil + }); err != nil { + t.Fatal(err) + } +} + +func TestCandidateRawIdentityAndFormatIsolation(t *testing.T) { + f := candidateFixture(t, "refunds") + raw := f.raw["policy.json"] + r, exit := Canonicalize("canon", raw) + if exit != 0 || r.BytesDigest != digest(raw) || r.CanonicalDigest == r.BytesDigest || r.FormatVersion != CandidateVersion || r.SpecRevision != CandidateRevision || r.CandidateResult != nil { + t.Fatalf("candidate identity %+v exit %d", r, exit) + } + if r.Document == "" { + t.Fatal("canonical bytes missing") + } + prototypePolicy := loadFixture(t, "refunds").raw["policy.json"] + f.replace(t, "policy.json", prototypePolicy) + reference := object(object(array(f.adoption["governingPolicies"])[0])["policy"]) + reference["content"] = f.content(t, "policy.json") + reference["id"], reference["version"] = mustMap(t, prototypePolicy)["id"], mustMap(t, prototypePolicy)["version"] + delete(reference, "canonicalIdentity") + r, exit = Check("check", mustJSON(t, f.adoption), f.wire(t), engine(t)) + if exit != result.ExitInvalid || r.CandidateResult == nil || r.CandidateResult.Code != "invalid-selector" { + t.Fatalf("prototype retained Policy accepted: %+v exit %d", r.CandidateResult, exit) + } +} + +func TestCandidateInitSchemaAndExplicitDiscovery(t *testing.T) { + legacyJSON := mustMap(t, mustJSON(t, Contract("contract"))) + for _, key := range []string{"formatVersion", "candidateResult", "candidateCapabilities", "registryVersion"} { + if _, found := legacyJSON[key]; found { + t.Fatal("legacy contract extended", key) + } + } + registry := AllFormats("contract") + if len(registry.Formats) != 2 || !bytes.Equal(mustJSON(t, registry.Formats[0]), mustJSON(t, Contract("contract"))) { + t.Fatal("registry changed legacy entry") + } + for _, kind := range []string{"policy", "governing-adoption"} { + r, exit := Init("init", kind, CandidateVersion, "urn:test:candidate", "7.3.42") + if exit != 0 || r.FormatVersion != CandidateVersion || !r.StarterTemplate { + t.Fatalf("init %+v %d", r, exit) + } + if v, exit := Validate("validate", []byte(r.Document)); exit != 0 { + t.Fatalf("starter shape %+v %d", v, exit) + } + if kind == "policy" && mustMap(t, []byte(r.Document))["managementMode"] != "workspace-managed" { + t.Fatal("old management spelling") + } + schema, exit := Schema("schema", kind, CandidateVersion) + if exit != 0 || schema.Resource == nil || strings.Contains(schema.Resource.Text, "8a56a95") { + t.Fatal("candidate schema provenance") + } + compiled, err := validation.CompileSchema([]byte(schema.Resource.Text), "urn:test:candidate:"+kind) + if err != nil { + t.Fatal(err) + } + if err := compiled.Validate(mustMap(t, []byte(r.Document))); err != nil { + t.Fatal(err) + } + } + var capabilities map[string]any + if json.Unmarshal(registry.Formats[1].CandidateCapabilities, &capabilities) != nil || capabilities["maturity"] != "proposed-draft" { + t.Fatal("candidate discovery") + } +} + +func encodeMaterial(raw []byte) string { return base64.StdEncoding.EncodeToString(raw) } + +func TestCandidateUnicodeTextAndPrivateTransportBounds(t *testing.T) { + f := candidateFixture(t, "refunds") + f.policy["title"] = strings.Repeat("é", 4096) + if r, exit := Validate("validate", mustJSON(t, f.policy)); exit != 0 { + t.Fatalf("Unicode character maximum refused %+v %d", r, exit) + } + f.policy["title"] = strings.Repeat("é", 4097) + if r, exit := Validate("validate", mustJSON(t, f.policy)); exit != result.ExitUnsupported || r.refusalCode != "input-over-bound" { + t.Fatalf("Unicode character maximum accepted %+v %d", r, exit) + } + r, exit := Check("check", f.raw["policy.json"], bytes.Repeat([]byte{' '}, MaxMaterialsWireBytes+1), engine(t)) + if exit != result.ExitUnsupported || r.CandidateResult == nil || r.CandidateResult.Code != "input-over-bound" || r.Capabilities.MaxMaterialsWireBytes != MaxMaterialsWireBytes { + t.Fatalf("private wire limit changed %+v %d", r, exit) + } +} + +func TestCandidateEnvironmentFailureAndSafeRefusal(t *testing.T) { + f := candidateFixture(t, "refunds") + r, exit := Check("check", f.raw["adoption.json"], f.wire(t), nil) + if exit != result.ExitIO || r.CandidateResult != nil { + t.Fatalf("environment failure became candidate result %+v %d", r, exit) + } + f.policy["kind"] = strings.Repeat("private-provider-prose", 4000) + r, exit = Check("check", mustJSON(t, f.policy), f.wire(t), engine(t)) + if exit != result.ExitInvalid || r.CandidateResult == nil || r.CandidateResult.Code != "invalid-document" || bytes.Contains(mustJSON(t, r), []byte("private-provider-prose")) { + t.Fatalf("unknown kind refusal leaked input or used wrong code %d", exit) + } +} + +func TestCandidateAdoptionValidatesRetainedPolicyGrammar(t *testing.T) { + for _, tc := range []struct { + name string + change func(map[string]any) + code string + }{ + {"unknown-approval", func(doc map[string]any) { doc["approved"] = true }, "invalid-document"}, + {"prototype-management-alias", func(doc map[string]any) { doc["managementMode"] = "desk-managed" }, "invalid-document"}, + {"missing-sections", func(doc map[string]any) { delete(doc, "sections") }, "invalid-document"}, + {"wrong-kind", func(doc map[string]any) { doc["kind"] = "governing-adoption" }, "invalid-document"}, + {"section-bound", func(doc map[string]any) { doc["sections"] = make([]any, 65) }, "input-over-bound"}, + } { + t.Run(tc.name, func(t *testing.T) { + f := candidateFixture(t, "refunds") + tc.change(f.policy) + f.retainPolicy(t) + r, exit := Check("check", mustJSON(t, f.adoption), f.wire(t), engine(t)) + if exit == 0 || r.CandidateResult == nil || r.CandidateResult.Code != tc.code { + t.Fatalf("retained Policy grammar bypassed %+v %d", r.CandidateResult, exit) + } + }) + } +} diff --git a/internal/policy/check.go b/internal/policy/check.go index 5e92eead..47268655 100644 --- a/internal/policy/check.go +++ b/internal/policy/check.go @@ -16,45 +16,88 @@ import ( // Check operates only on supplied bytes. The private carrier accepts no paths, // URLs or acquisition instructions. A successful check grants no authority. func Check(command string, data, materialsJSON []byte, engine *validation.Engine) (Report, int) { - r, doc, code := validateDocument(command, data) + return CheckFormat(command, data, materialsJSON, engine, "") +} + +func CheckFormat(command string, data, materialsJSON []byte, engine *validation.Engine, format string) (Report, int) { + r, doc, code := parseFormat(command, data, format) if code != 0 { - return r, code + return finishCandidateCheck(r, code) } - materials, err, code := decodeMaterials(materialsJSON) - if err != nil { - return refused(r, err.code, err.path, err.message, code) + candidateMode := r.FormatVersion == CandidateVersion + if !candidateMode { + r, doc, code = validateDocumentFormat(command, data, ProfileVersion) + if code != 0 { + return r, code + } } - if doc["kind"] == "policy" { - err, code = checkPolicy(doc, materials, "") - } else { - err, code = checkAdoption(doc, materials, engine) + return checkMaterials(r, doc, func() (materialSet, *issue, int) { return decodeMaterialsFormat(materialsJSON, candidateMode) }, engine) +} + +func checkMaterials(r Report, doc map[string]any, load func() (materialSet, *issue, int), engine *validation.Engine) (Report, int) { + candidateMode := r.FormatVersion == CandidateVersion + materials, err, code := load() + if err == nil && candidateMode && r.Kind != "policy" { + err, code = candidateSchema(r.Kind, doc) + } + if err == nil { + if doc["kind"] == "policy" { + err, code = checkPolicy(doc, materials, "", candidateMode) + } else { + err, code = checkAdoption(doc, materials, engine, candidateMode) + } } if err != nil { - return refused(r, err.code, err.path, err.message, code) + if candidateMode && code != result.ExitIO { + r, code = candidateRefused(r, candidateCode(err, code)) + } else { + r, code = refused(r, err.code, err.path, err.message, code) + } + return finishCandidateCheck(r, code) } - r.Status = "references-valid" - r.ValidationScope = r.Capabilities.CheckScope - return r, result.ExitSuccess + r.Status, r.ValidationScope, r.Document = "references-valid", r.Capabilities.CheckScope, "" + return finishCandidateCheck(r, result.ExitSuccess) } -func checkPolicy(doc map[string]any, materials materialSet, base string) (*issue, int) { +func checkPolicy(doc map[string]any, materials materialSet, base string, candidateMode bool) (*issue, int) { + if candidateMode { + if err, code := candidateSchema("policy", doc); err != nil { + return err, code + } + } reference := object(doc["content"]) - if reference["mediaType"] != "text/plain" { + if !candidateMode && reference["mediaType"] != "text/plain" { return problem("JPS-POLICY-NARRATIVE-MEDIA", base+"/content/mediaType", "Policy narrative must be retained as text/plain."), result.ExitInvalid } narrative, err, code := materials.resolve(reference, MaxMaterialBytes, base+"/content") if err != nil { return err, code } + if reference["mediaType"] != "text/plain" { + return candidateIssue("invalid-document"), result.ExitInvalid + } if !utf8.Valid(narrative) { return problem("JPS-POLICY-NARRATIVE-UTF8", base+"/content", "Retained policy narrative must contain valid UTF-8 bytes."), result.ExitInvalid } + var sources map[string]map[string]any + if candidateMode { + var err *issue + sources, err = unique(array(doc["sourceProvenance"]), base+"/sourceProvenance", "source") + if err != nil { + return candidateIssue("invalid-document"), result.ExitInvalid + } + } for i, item := range array(doc["sourceProvenance"]) { _, err, code := materials.resolve(object(object(item)["content"]), MaxOriginalBytes, indexPath(base+"/sourceProvenance", i)+"/content") if err != nil { return err, code } } + if candidateMode { + if _, err := unique(array(doc["sections"]), base+"/sections", "section"); err != nil { + return candidateIssue("invalid-anchor"), result.ExitInvalid + } + } for i, item := range array(doc["sections"]) { section := object(item) anchor := object(section["anchor"]) @@ -69,11 +112,18 @@ func checkPolicy(doc map[string]any, materials materialSet, base string) (*issue if digest(narrative[start:end]) != anchor["bytesDigest"] { return problem("JPS-POLICY-ANCHOR-DIGEST", path+"/bytesDigest", "The exact retained section bytes do not match the anchor digest."), result.ExitInvalid } + if candidateMode { + for _, source := range array(section["sourceRefs"]) { + if _, found := sources[text(object(source)["sourceId"])]; !found { + return candidateIssue("invalid-anchor"), result.ExitInvalid + } + } + } } return nil, result.ExitSuccess } -func checkArtifact(reference map[string]any, kindName string, materials materialSet, path string) (map[string]any, []byte, *issue, int) { +func checkArtifact(reference map[string]any, kindName string, materials materialSet, path string, candidateMode bool) (map[string]any, []byte, *issue, int) { if reference["kind"] != kindName { return nil, nil, problem("JPS-POLICY-ARTIFACT-KIND", path+"/kind", "Retained artifact kind does not match its consuming role."), result.ExitUnsupported } @@ -81,7 +131,7 @@ func checkArtifact(reference map[string]any, kindName string, materials material if content["mediaType"] != "application/json" { return nil, nil, problem("JPS-POLICY-ARTIFACT-MEDIA", path+"/content/mediaType", "Retained artifact documents must use application/json."), result.ExitInvalid } - raw, err, code := materials.resolve(content, MaxMaterialBytes, path+"/content") + raw, err, code := materials.resolve(content, artifactLimit(candidateMode), path+"/content") if err != nil { return nil, nil, err, code } @@ -90,7 +140,17 @@ func checkArtifact(reference map[string]any, kindName string, materials material } var doc map[string]any if kindName == "pack" { - value, failure := carrier.Decode(raw, limits()) + var value any + var failure *carrier.Failure + if candidateMode { + var c string + value, c = candidateJSON(raw) + if c != "" { + return nil, nil, candidateIssue(c), candidateExit(c) + } + } else { + value, failure = carrier.Decode(raw, limits()) + } if failure != nil { code := result.ExitInvalid if failure.Resource { @@ -100,14 +160,29 @@ func checkArtifact(reference map[string]any, kindName string, materials material } doc = object(value) if doc == nil { + if candidateMode { + return nil, nil, candidateIssue("invalid-consumer"), result.ExitInvalid + } return nil, nil, problem("JPS-POLICY-CONSUMER-JSON", path+"/content", "The retained consumer must be a JSON object."), result.ExitInvalid } - if err := coreNumberBounds(value, nil); err != nil { - return nil, nil, prefixed(err, path), result.ExitUnsupported + if !candidateMode { + if err := coreNumberBounds(value, nil); err != nil { + return nil, nil, prefixed(err, path), result.ExitUnsupported + } } } else { - r, parsed, c := validateDocument("retained-policy", raw) + var r Report + var parsed map[string]any + var c int + if candidateMode { + r, parsed, c = parseFormat("retained-policy", raw, CandidateVersion) + } else { + r, parsed, c = validateDocumentFormat("retained-policy", raw, ProfileVersion) + } if c != 0 { + if candidateMode { + return nil, nil, candidateIssue(r.refusalCode), c + } d := r.Diagnostics[0] return nil, nil, problem(d.Code, path+"/content", "Retained Policy does not satisfy the supported closed prototype document and local-reference checks."), c } @@ -167,11 +242,14 @@ func coreNumberBounds(value any, path []string) *issue { return nil } -func checkAdoption(doc map[string]any, materials materialSet, engine *validation.Engine) (*issue, int) { - consumer, raw, err, code := checkArtifact(object(doc["consumer"]), "pack", materials, "/consumer") +func checkAdoption(doc map[string]any, materials materialSet, engine *validation.Engine, candidateMode bool) (*issue, int) { + consumer, raw, err, code := checkArtifact(object(doc["consumer"]), "pack", materials, "/consumer", candidateMode) if err != nil { return err, code } + if candidateMode && consumer["specVersion"] != "0.2.0-draft" { + return candidateIssue("invalid-consumer"), result.ExitInvalid + } if engine == nil { return problem("JPS-POLICY-ENGINE", "/consumer", "A bundled Core structural validation engine is required."), result.ExitIO } @@ -188,14 +266,23 @@ func checkAdoption(doc map[string]any, materials materialSet, engine *validation } rules, err := unique(array(consumer["rules"]), "/consumer/rules", "consumer rule") if err != nil { + if candidateMode { + return candidateIssue("invalid-consumer"), result.ExitInvalid + } return err, result.ExitInvalid } exceptions, err := unique(array(consumer["exceptions"]), "/consumer/exceptions", "consumer exception") if err != nil { + if candidateMode { + return candidateIssue("invalid-consumer"), result.ExitInvalid + } return err, result.ExitInvalid } outcomes, err := unique(array(consumer["outcomes"]), "/consumer/outcomes", "consumer outcome") if err != nil { + if candidateMode { + return candidateIssue("invalid-consumer"), result.ExitInvalid + } return err, result.ExitInvalid } if fallback, present := consumer["fallbackOutcome"]; present { @@ -217,16 +304,24 @@ func checkAdoption(doc map[string]any, materials materialSet, engine *validation } } } + policies := map[string]bool{} for i, item := range array(doc["governingPolicies"]) { governing := object(item) base := indexPath("/governingPolicies", i) - policy, _, err, code := checkArtifact(object(governing["policy"]), "policy", materials, base+"/policy") + policy, _, err, code := checkArtifact(object(governing["policy"]), "policy", materials, base+"/policy", candidateMode) if err != nil { return err, code } - if err, code := checkPolicy(policy, materials, base+"/policy"); err != nil { + if err, code := checkPolicy(policy, materials, base+"/policy", candidateMode); err != nil { return err, code } + if candidateMode { + id := text(object(governing["policy"])["id"]) + if policies[id] { + return candidateIssue("invalid-coverage"), result.ExitInvalid + } + policies[id] = true + } sections, err := unique(array(policy["sections"]), base+"/policy/sections", "section") if err != nil { return err, result.ExitInvalid @@ -254,16 +349,22 @@ func checkAdoption(doc map[string]any, materials materialSet, engine *validation row := object(item) path := indexPath(base+"/coverage", j) id := text(row["sectionId"]) - if !selected[id] { + if !selected[id] || candidateMode && covered[id] { return problem("JPS-POLICY-COVERAGE-SCOPE", path+"/sectionId", "Coverage names a section outside the exact selected policy scope."), result.ExitInvalid } covered[id] = true if row["status"] != "implemented" { continue } + elements := map[string]bool{} for k, item := range array(row["consumerElements"]) { element := object(item) elementPath := indexPath(path+"/consumerElements", k) + key := text(element["kind"]) + ":" + text(element["id"]) + if candidateMode && elements[key] { + return candidateIssue("invalid-coverage"), result.ExitInvalid + } + elements[key] = true found := false switch element["kind"] { case "rule": diff --git a/internal/policy/document.go b/internal/policy/document.go index b9af83b9..298a39a8 100644 --- a/internal/policy/document.go +++ b/internal/policy/document.go @@ -1,5 +1,5 @@ // Package policy supplies bounded offline tools for the explicitly non-normative -// RFC 0023 prototype. It is not a policy authority or an evaluator. +// RFC 0023 prototype and proposed-draft candidate. It is not a policy authority or an evaluator. package policy import ( @@ -7,6 +7,7 @@ import ( "encoding/hex" "encoding/json" "strings" + "unicode/utf8" "github.com/Judgment-Pack/judgment-pack-runtime/internal/artifactversion" "github.com/Judgment-Pack/judgment-pack-runtime/internal/carrier" @@ -33,6 +34,11 @@ const ( ) type Report struct { + FormatVersion string `json:"formatVersion,omitempty"` + CandidateCapabilities json.RawMessage `json:"candidateCapabilities,omitempty"` + CandidateResult *CandidateResult `json:"candidateResult,omitempty"` + refusalCode string + OutputVersion string `json:"outputVersion"` Tool result.Tool `json:"tool"` Command string `json:"command"` @@ -121,7 +127,7 @@ func limits() carrier.Limits { return carrier.Limits{MaxDepth: MaxDepth, MaxNodes: MaxDocumentBytes, MaxStringBytes: MaxDocumentBytes} } -func parse(command string, data []byte) (Report, map[string]any, int) { +func parsePrototype(command string, data []byte) (Report, map[string]any, int) { r := report(command) if len(data) > MaxDocumentBytes { r, c := refused(r, "JPS-POLICY-DOCUMENT-BOUND", "", "Input exceeds this prototype's parsed-document byte support bound.", result.ExitUnsupported) @@ -175,7 +181,7 @@ func parse(command string, data []byte) (Report, map[string]any, int) { // Canonicalize checks strict JSON, the existing canon domain and exact selectors. // Encoded is deliberately distinct from document-valid and references-valid. func Canonicalize(command string, data []byte) (Report, int) { - r, _, code := parse(command, data) + r, _, code := parseFormat(command, data, "") return r, code } func Digest(command string, data []byte) (Report, int) { @@ -188,23 +194,34 @@ func Digest(command string, data []byte) (Report, int) { // placeholders, and the caller must supply its own narrative/pack/policy bytes. func Init(command, kind, profileVersion, id, version string) (Report, int) { r := report(command) + if profileVersion == CandidateVersion { + r = candidateReport(command) + } if code, path, message := selector(kind, profileVersion); code != 0 { return refused(r, "JPS-POLICY-SELECTOR", path, message, code) } if !artifactversion.Valid(version) { return refused(r, "JPS-POLICY-ARTIFACT-VERSION", "/version", "Provide an exact three-component artifact version within the reported byte bound.", result.ExitInvalid) } - if len(id) > 2048 || !validURI(id) { + if (profileVersion == ProfileVersion && len(id) > 2048 || profileVersion == CandidateVersion && utf8.RuneCountInString(id) > 2048) || !validURIFormat(id, profileVersion) { return refused(r, "JPS-POLICY-ID", "/id", "Provide an absolute RFC 3986 URI within the prototype identity bound.", result.ExitInvalid) } content := func(media string) map[string]any { return map[string]any{"bytesDigest": "sha256:" + strings.Repeat("0", 64), "byteLength": 1, "mediaType": media} } proto := map[string]any{"profile": Profile, "proposalVersion": ProfileVersion, "status": "non-normative"} - doc := map[string]any{"prototype": proto, "kind": kind, "id": id, "version": version} + doc := map[string]any{"kind": kind, "id": id, "version": version} + if profileVersion == CandidateVersion { + doc["formatVersion"] = CandidateVersion + } else { + doc["prototype"] = proto + } if kind == "policy" { doc["title"] = "Replace with a policy title" doc["managementMode"] = "desk-managed" + if profileVersion == CandidateVersion { + doc["managementMode"] = "workspace-managed" + } doc["content"] = content("text/plain") doc["sourceProvenance"] = []any{} doc["sections"] = []any{map[string]any{"id": "replace-section", "title": "Replace with a section title", "anchor": map[string]any{"startByte": 0, "endByte": 1, "bytesDigest": "sha256:" + strings.Repeat("0", 64)}}} @@ -229,7 +246,7 @@ func Init(command, kind, profileVersion, id, version string) (Report, int) { } func selector(kind, version string) (int, string, string) { - if version != ProfileVersion { + if version != ProfileVersion && version != CandidateVersion { return result.ExitUnsupported, "/profileVersion", "The exact supported prototype version is 0.0.2." } if kind != "policy" && kind != "governing-adoption" { diff --git a/internal/policy/format.go b/internal/policy/format.go new file mode 100644 index 00000000..ab6470a1 --- /dev/null +++ b/internal/policy/format.go @@ -0,0 +1,298 @@ +package policy + +import ( + "strings" + "unicode/utf8" + + "github.com/Judgment-Pack/judgment-pack-runtime/internal/artifactversion" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/carrier" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/jpscanon" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/result" +) + +const CandidateVersion = "1.0.0" +const CandidateRevision = "4406cec9714ab9bc8e8971237cc79d58682cc904" +const CandidateURL = "https://github.com/Judgment-Pack/judgment-pack-spec/blob/" + CandidateRevision + "/rfcs/policy-companion-contract/README.md" + +type formatDescriptor struct { + version, profile, maturity, revision, url, directory, commonURI string +} + +var prototypeFormat = formatDescriptor{ProfileVersion, Profile, "non-normative", SpecRevision, SpecURL, "prototype", commonID} +var candidateFormat = formatDescriptor{CandidateVersion, "jps-policy-companion", "proposed-draft", CandidateRevision, CandidateURL, "candidate", candidateCommonID} + +// CandidateResult is the complete portable full-check result. It is absent from +// legacy reports and from encoding/local validation, which have narrower scopes. +type CandidateResult struct { + Status string `json:"status"` + Code string `json:"code,omitempty"` + FormatVersion string `json:"formatVersion,omitempty"` + Maturity string `json:"maturity,omitempty"` +} + +// Registry is an explicitly requested discovery surface, separate from the +// unchanged no-argument prototype contract consumed by strict older clients. +type Registry struct { + OutputVersion string `json:"outputVersion"` + Tool result.Tool `json:"tool"` + Command string `json:"command"` + RegistryVersion string `json:"registryVersion"` + Status string `json:"status"` + Formats []Report `json:"formats"` +} + +func AllFormats(command string) Registry { + legacy := Contract(command) + candidate := candidateReport(command) + candidate.Status = "available" + return Registry{result.OutputVersion, result.CurrentTool(), command, "1", "available", []Report{legacy, candidate}} +} + +func ContractFormat(command, version string) (Report, int) { + if version == ProfileVersion { + return Contract(command), 0 + } + r := candidateReport(command) + if !artifactversion.Valid(version) { + return candidateRefused(r, "invalid-selector") + } + if version != CandidateVersion { + return candidateRefused(r, "unsupported-format") + } + r.Status = "available" + return r, 0 +} + +func candidateReport(command string) Report { + r := report(command) + f := candidateFormat + r.Specification, r.SpecRevision = f.url, f.revision + r.Maturity, r.Profile, r.ProfileVersion = f.maturity, f.profile, f.version + r.FormatVersion = f.version + r.Capabilities.ProfileVersions = []string{f.version} + r.Capabilities.Maturity = f.maturity + r.Capabilities.ValidationScope = "closed-candidate-document-and-local-references" + r.Capabilities.CheckScope = "candidate-supplied-exact-bytes-anchors-and-scoped-core-references" + r.CandidateCapabilities, _ = candidate.ReadFile("candidate/capabilities.json") + return r +} + +func candidateRefused(r Report, code string) (Report, int) { + r.refusalCode = code + exit := result.ExitInvalid + if code == "input-over-bound" || code == "unsupported-format" || code == "unsupported-canonical-identity" { + exit = result.ExitUnsupported + } + return refused(r, "JPS-POLICY-CANDIDATE-"+strings.ToUpper(code), "", "Proposed-draft candidate check refused: "+code+".", exit) +} + +// Only a strict object carrying the new selector opts into automatic candidate +// dispatch. Explicit operation format selection also covers malformed/missing +// selector inputs; legacy malformed-input reports remain byte-compatible. +func inputFormat(data []byte) string { + if len(data) <= MaxDocumentBytes { + value, failure := carrier.Decode(data, limits()) + if failure == nil { + if _, named := object(value)["formatVersion"]; named { + return CandidateVersion + } + } + } + return ProfileVersion +} + +func parseFormat(command string, data []byte, format string) (Report, map[string]any, int) { + if format == "" { + format = inputFormat(data) + } + if format == ProfileVersion { + return parsePrototype(command, data) + } + r := candidateReport(command) + refuse := func(code string) (Report, map[string]any, int) { rr, c := candidateRefused(r, code); return rr, nil, c } + if !artifactversion.Valid(format) { + return refuse("invalid-selector") + } + if format != CandidateVersion { + return refuse("unsupported-format") + } + value, code := candidateJSON(data) + if code != "" { + return refuse(code) + } + doc := object(value) + if code := candidateSelector(doc); code != "" { + return refuse(code) + } + var out strings.Builder + if _, ok := jpscanon.Write(&out, value, nil); !ok { + return refuse("invalid-document") + } + kind := text(doc["kind"]) + if kind == "policy" || kind == "governing-adoption" { + r.Kind = kind + } + r.ArtifactID, r.ArtifactVersion = text(doc["id"]), text(doc["version"]) + if utf8.RuneCountInString(r.ArtifactID) > 2048 { + r.ArtifactID = "" + } + if len(r.ArtifactVersion) > artifactversion.MaxVersionBytes { + r.ArtifactVersion = "" + } + r.Document, r.BytesDigest, r.CanonicalDigest = out.String(), digest(data), digest([]byte(out.String())) + return r, doc, 0 +} + +func candidateSelector(doc map[string]any) string { + version, ok := doc["formatVersion"].(string) + if !ok || !artifactversion.Valid(version) { + return "invalid-selector" + } + if version != CandidateVersion { + return "unsupported-format" + } + return "" +} + +// Measure physical bounds before parsing even malformed JSON. Maximal number +// character runs outside strings deliberately match the pinned reader's phase. +func measureCandidate(data []byte, maxBytes, maxDepth int) bool { + if len(data) > maxBytes { + return false + } + depth, inString, escaped := 0, false, false + for i := 0; i < len(data); i++ { + b := data[i] + if inString { + if escaped { + escaped = false + } else if b == '\\' { + escaped = true + } else if b == '"' { + inString = false + } + continue + } + switch b { + case '"': + inString = true + case '[', '{': + depth++ + if depth > maxDepth { + return false + } + case ']', '}': + depth-- + default: + if !numberCharacter(b) { + continue + } + end := i + 1 + for end < len(data) && numberCharacter(data[end]) { + end++ + } + literal := data[i:end] + if len(literal) > 128 { + return false + } + if e := strings.IndexAny(string(literal), "eE"); e >= 0 { + j := e + 1 + if j < len(literal) && (literal[j] == '+' || literal[j] == '-') { + j++ + } + start := j + for j < len(literal) && literal[j] >= '0' && literal[j] <= '9' { + j++ + } + exponent := strings.TrimLeft(string(literal[start:j]), "0") + if len(exponent) > 3 || len(exponent) == 3 && exponent > "308" { + return false + } + } + i = end - 1 + } + } + return true +} + +func numberCharacter(b byte) bool { + return b >= '0' && b <= '9' || b == '+' || b == '-' || b == '.' || b == 'e' || b == 'E' +} + +func candidateJSON(data []byte) (any, string) { + if !measureCandidate(data, MaxDocumentBytes, MaxDepth) { + return nil, "input-over-bound" + } + value, failure := carrier.Decode(data, limits()) + if failure != nil { + if failure.Resource { + return nil, "input-over-bound" + } + return nil, "invalid-json" + } + return value, "" +} + +func CanonicalizeFormat(command string, data []byte, format string) (Report, int) { + r, _, code := parseFormat(command, data, format) + return r, code +} +func DigestFormat(command string, data []byte, format string) (Report, int) { + r, code := CanonicalizeFormat(command, data, format) + r.Document = "" + return r, code +} + +func candidateIssue(code string) *issue { + return &issue{code: "JPS-POLICY-CANDIDATE-" + strings.ToUpper(code), message: "Proposed-draft candidate check refused: " + code + ".", candidateCode: code} +} + +func candidateCode(err *issue, exit int) string { + if err.candidateCode != "" { + return err.candidateCode + } + if err.code == "JPS-POLICY-CANONICAL-DOMAIN" { + return "unsupported-canonical-identity" + } + if exit == result.ExitUnsupported { + return "input-over-bound" + } + switch err.code { + case "JPS-POLICY-MATERIAL-MISSING": + return "missing-material" + case "JPS-POLICY-NARRATIVE-MEDIA", "JPS-POLICY-ARTIFACT-MEDIA": + return "invalid-document" + case "JPS-POLICY-NARRATIVE-UTF8", "JPS-POLICY-ANCHOR-RANGE", "JPS-POLICY-ANCHOR-UTF8", "JPS-POLICY-ANCHOR-DIGEST", "JPS-POLICY-SOURCE-REFERENCE": + return "invalid-anchor" + case "JPS-POLICY-ELEMENT-REFERENCE", "JPS-POLICY-COVERAGE-SCOPE", "JPS-POLICY-COVERAGE-MISSING", "JPS-POLICY-DUPLICATE-POLICY", "JPS-POLICY-DUPLICATE-COVERAGE", "JPS-POLICY-DUPLICATE-ELEMENT", "JPS-POLICY-SCOPE-REFERENCE": + return "invalid-coverage" + case "JPS-POLICY-CONSUMER-STRUCTURE", "JPS-POLICY-FALLBACK-REFERENCE", "JPS-POLICY-EXCEPTION-REFERENCE": + return "invalid-consumer" + } + return "reference-mismatch" +} + +func finishCandidateCheck(r Report, code int) (Report, int) { + if r.FormatVersion == "" { + return r, code + } + if code == 0 { + r.CandidateResult = &CandidateResult{Status: "valid", FormatVersion: CandidateVersion, Maturity: "proposed-draft"} + } else if r.refusalCode != "" { + r.CandidateResult = &CandidateResult{Status: "refused", Code: r.refusalCode} + } + return r, code +} + +func artifactLimit(candidateMode bool) int { + if candidateMode { + return MaxDocumentBytes + } + return MaxMaterialBytes +} +func candidateExit(code string) int { + if code == "input-over-bound" || code == "unsupported-format" || code == "unsupported-canonical-identity" { + return result.ExitUnsupported + } + return result.ExitInvalid +} diff --git a/internal/policy/materials.go b/internal/policy/materials.go index e2074e8f..d673395c 100644 --- a/internal/policy/materials.go +++ b/internal/policy/materials.go @@ -19,63 +19,97 @@ type retained struct { type materialSet map[string]*retained func decodeMaterials(data []byte) (materialSet, *issue, int) { + return decodeMaterialsFormat(data, false) +} + +func decodeMaterialsFormat(data []byte, candidateMode bool) (materialSet, *issue, int) { if len(data) > MaxMaterialsWireBytes { return nil, problem("JPS-POLICY-MATERIALS-BOUND", "/materials", "The private Runtime materials JSON exceeds its transport byte support bound."), result.ExitUnsupported } + if candidateMode && !measureCandidate(data, MaxMaterialsWireBytes, MaxDepth) { + return nil, candidateIssue("input-over-bound"), result.ExitUnsupported + } value, failure := carrier.Decode(data, carrier.Limits{MaxDepth: 8, MaxNodes: 1024, MaxStringBytes: base64.StdEncoding.EncodedLen(MaxOriginalBytes)}) if failure != nil { code := result.ExitInvalid if failure.Resource { code = result.ExitUnsupported } + if candidateMode { + if failure.Resource { + return nil, candidateIssue("input-over-bound"), code + } + return nil, candidateIssue("invalid-carrier"), code + } return nil, problem(failure.Diagnostic.Code, "/materials", "Retained-material JSON is malformed or exceeds its support bounds."), code } root := object(value) entries := array(root["materials"]) + if candidateMode { + if root == nil || len(root) != 1 { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + if _, ok := root["materials"].([]any); !ok { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + for _, item := range entries { + entry := object(item) + if len(entry) != 2 || object(entry["content"]) == nil { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + if _, ok := entry["dataBase64"].(string); !ok { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + } + } if len(entries) > MaxMaterials { return nil, problem("JPS-POLICY-MATERIAL-COUNT", "/materials", "The private Runtime carrier supports at most 16 material registrations."), result.ExitUnsupported } // The schema library converts number tokens to arbitrary-precision values. // Refuse unsupported literals throughout this closed carrier first, including // numbers in unknown or wrong-typed members that schema validation will reject. - if failure, code := preflightMaterialNumbers(value, nil); failure != nil { - return nil, failure, code - } - compiled, err := loadSchemas() - if err != nil { - return nil, problem("JPS-POLICY-ARTIFACT", "", "Pinned prototype schemas could not be compiled."), result.ExitIO - } - if err := compiled["materials"].Validate(value); err != nil { - if schemaBound(err) { - return nil, problem("JPS-POLICY-MATERIALS-BOUND", "/materials", "Retained material exceeds the private Runtime carrier support bounds."), result.ExitUnsupported + if !candidateMode { + if failure, code := preflightMaterialNumbers(value, nil); failure != nil { + return nil, failure, code + } + compiled, err := loadSchemas() + if err != nil { + return nil, problem("JPS-POLICY-ARTIFACT", "", "Pinned prototype schemas could not be compiled."), result.ExitIO + } + if err := compiled["materials"].Validate(value); err != nil { + if schemaBound(err) { + return nil, problem("JPS-POLICY-MATERIALS-BOUND", "/materials", "Retained material exceeds the private Runtime carrier support bounds."), result.ExitUnsupported + } + return nil, problem("JPS-POLICY-MATERIALS-SCHEMA", "/materials", "Provide only materials entries containing a retained content reference and a standard padded dataBase64 string."), result.ExitInvalid } - return nil, problem("JPS-POLICY-MATERIALS-SCHEMA", "/materials", "Provide only materials entries containing a retained content reference and a standard padded dataBase64 string."), result.ExitInvalid } // Complete shape, type and encoded-length checks precede any base64 decoding. distinct := map[string]bool{} total := 0 - for i, item := range entries { - entry := object(item) - content := object(entry["content"]) - encoded := text(entry["dataBase64"]) - path := indexPath("/materials", i) + "/dataBase64" - declared := number(content["byteLength"]) - n, valid := base64Length(encoded) - if !valid { - return nil, problem("JPS-POLICY-BASE64", path, "Retained material must use strict standard padded base64 without whitespace."), result.ExitInvalid - } - if n > MaxOriginalBytes { - return nil, problem("JPS-POLICY-ORIGINAL-BOUND", path, "Retained material exceeds the original-source byte support bound."), result.ExitUnsupported - } - if n != declared { - return nil, problem("JPS-POLICY-BYTE-LENGTH", path, "Decoded retained bytes do not match their declared byte length."), result.ExitInvalid - } - key := text(content["bytesDigest"]) - if !distinct[key] { - distinct[key] = true - total += n - if total > MaxTotalMaterialBytes { - return nil, problem("JPS-POLICY-AGGREGATE-BOUND", "/materials", "Distinct retained material exceeds the aggregate byte support bound."), result.ExitUnsupported + if !candidateMode { + for i, item := range entries { + entry := object(item) + content := object(entry["content"]) + encoded := text(entry["dataBase64"]) + path := indexPath("/materials", i) + "/dataBase64" + declared := number(content["byteLength"]) + n, valid := base64Length(encoded) + if !valid { + return nil, problem("JPS-POLICY-BASE64", path, "Retained material must use strict standard padded base64 without whitespace."), result.ExitInvalid + } + if n > MaxOriginalBytes { + return nil, problem("JPS-POLICY-ORIGINAL-BOUND", path, "Retained material exceeds the original-source byte support bound."), result.ExitUnsupported + } + if n != declared { + return nil, problem("JPS-POLICY-BYTE-LENGTH", path, "Decoded retained bytes do not match their declared byte length."), result.ExitInvalid + } + key := text(content["bytesDigest"]) + if !distinct[key] { + distinct[key] = true + total += n + if total > MaxTotalMaterialBytes { + return nil, problem("JPS-POLICY-AGGREGATE-BOUND", "/materials", "Distinct retained material exceeds the aggregate byte support bound."), result.ExitUnsupported + } } } } @@ -83,10 +117,35 @@ func decodeMaterials(data []byte) (materialSet, *issue, int) { for i, item := range entries { entry := object(item) content := object(entry["content"]) + if candidateMode { + if err, c := candidateSchema("common", content); err != nil { + return nil, err, c + } + encoded := text(entry["dataBase64"]) + n, ok := base64Length(encoded) + if !ok { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + if n > MaxOriginalBytes { + return nil, candidateIssue("input-over-bound"), result.ExitUnsupported + } + if n != number(content["byteLength"]) { + return nil, candidateIssue("reference-mismatch"), result.ExitInvalid + } + } raw, err := base64.StdEncoding.Strict().DecodeString(text(entry["dataBase64"])) if err != nil { + if candidateMode { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } return nil, problem("JPS-POLICY-BASE64", indexPath("/materials", i)+"/dataBase64", "Retained material is not strict standard padded base64."), result.ExitInvalid } + if candidateMode { + if err, code := registerCandidateMaterial(content, raw, material); err != nil { + return nil, err, code + } + continue + } key := text(content["bytesDigest"]) if digest(raw) != key { return nil, problem("JPS-POLICY-BYTES-DIGEST", indexPath("/materials", i)+"/content/bytesDigest", "Retained bytes do not match their exact SHA-256 reference."), result.ExitInvalid @@ -197,5 +256,37 @@ func prefixed(err *issue, prefix string) *issue { if err == nil { return nil } - return &issue{code: err.code, path: prefix + err.path, message: err.message} + return &issue{code: err.code, path: prefix + err.path, message: err.message, candidateCode: err.candidateCode} +} + +// registerCandidateMaterial is shared by the private wire carrier and the +// portable-vector harness. Checks happen in registration order before mutation. +func registerCandidateMaterial(reference map[string]any, raw []byte, material materialSet) (*issue, int) { + if err, code := candidateSchema("common", reference); err != nil { + return err, code + } + if len(raw) > MaxOriginalBytes { + return candidateIssue("input-over-bound"), result.ExitUnsupported + } + key := text(reference["bytesDigest"]) + existing := material[key] + if existing != nil && !bytes.Equal(existing.raw, raw) || len(raw) != number(reference["byteLength"]) || digest(raw) != key { + return candidateIssue("reference-mismatch"), result.ExitInvalid + } + total := 0 + for _, retained := range material { + total += len(retained.raw) + } + if existing == nil { + total += len(raw) + } + if total > MaxTotalMaterialBytes { + return candidateIssue("input-over-bound"), result.ExitUnsupported + } + if existing == nil { + existing = &retained{raw: raw, mediaTypes: map[string]bool{}} + material[key] = existing + } + existing.mediaTypes[text(reference["mediaType"])] = true + return nil, 0 } diff --git a/internal/policy/references.go b/internal/policy/references.go index 9212ae23..190204c3 100644 --- a/internal/policy/references.go +++ b/internal/policy/references.go @@ -6,7 +6,7 @@ import ( "strconv" ) -type issue struct{ code, path, message string } +type issue struct{ code, path, message, candidateCode string } func problem(code, path, message string) *issue { return &issue{code: code, path: path, message: message} diff --git a/internal/policy/schema.go b/internal/policy/schema.go index 710d92d8..e0a15a2d 100644 --- a/internal/policy/schema.go +++ b/internal/policy/schema.go @@ -59,14 +59,18 @@ func validURI(id string) bool { // resources. Vendored source schemas and their provenance hashes stay unchanged. func Schema(command, kindName, version string) (Report, int) { r := report(command) + if version == CandidateVersion { + r = candidateReport(command) + } if code, path, message := selector(kindName, version); code != 0 { return refused(r, "JPS-POLICY-SELECTOR", path, message, code) } - raw, err := prototype.ReadFile("prototype/" + kindName + ".schema.json") + source, directory, commonURI, revision := schemaSource(version) + raw, err := source.ReadFile(directory + "/" + kindName + ".schema.json") if err != nil { return refused(r, "JPS-POLICY-ARTIFACT", "", "The pinned prototype schema is unavailable.", result.ExitIO) } - common, _ := prototype.ReadFile("prototype/common.schema.json") + common, _ := source.ReadFile(directory + "/common.schema.json") var doc, shared map[string]any if json.Unmarshal(raw, &doc) != nil || json.Unmarshal(common, &shared) != nil { return refused(r, "JPS-POLICY-ARTIFACT", "", "The pinned prototype schema is invalid.", result.ExitIO) @@ -75,16 +79,19 @@ func Schema(command, kindName, version string) (Report, int) { delete(shared, "$schema") delete(shared, "$ref") rewriteRefs(shared, "#/$defs/", "#/$defs/common/$defs/") - rewriteRefs(shared, commonID+"#", "#/$defs/common") - rewriteRefs(doc, commonID+"#", "#/$defs/common") + rewriteRefs(shared, commonURI+"#", "#/$defs/common") + rewriteRefs(doc, commonURI+"#", "#/$defs/common") defs, _ := doc["$defs"].(map[string]any) if defs == nil { defs = map[string]any{} doc["$defs"] = defs } defs["common"] = shared - doc["$id"] = "urn:judgmentpack:runtime:experimental-policy:" + ProfileVersion + ":" + kindName + ":authoring-schema:1" - doc["$comment"] = "Runtime self-contained editing copy of non-normative RFC 0023 prototype at Spec commit " + SpecRevision + ". Use experimental policy validate/check; schema acceptance grants no approval, execution authority or conformance." + doc["$id"] = "urn:judgmentpack:runtime:experimental-policy:" + version + ":" + kindName + ":authoring-schema:1" + doc["$comment"] = "Runtime self-contained editing copy of non-normative RFC 0023 prototype at Spec commit " + revision + ". Use experimental policy validate/check; schema acceptance grants no approval, execution authority or conformance." + if version == CandidateVersion { + doc["$comment"] = "Runtime self-contained editing copy of proposed-draft, unadopted Policy contract candidate at Spec commit " + revision + ". Schema acceptance establishes no authority or conformance." + } text, err := json.MarshalIndent(doc, "", " ") if err != nil { return refused(r, "JPS-POLICY-ARTIFACT", "", "The editing schema could not be assembled.", result.ExitIO) @@ -114,10 +121,29 @@ func rewriteRefs(value any, from, to string) { } func validateDocument(command string, data []byte) (Report, map[string]any, int) { - r, doc, code := parse(command, data) + return validateDocumentFormat(command, data, "") +} +func validateDocumentFormat(command string, data []byte, format string) (Report, map[string]any, int) { + r, doc, code := parseFormat(command, data, format) if code != 0 { return r, nil, code } + if r.FormatVersion == CandidateVersion { + if failure, c := candidateSchema(r.Kind, doc); failure != nil { + if c == result.ExitIO { + rr, code := refused(r, failure.code, failure.path, failure.message, c) + return rr, nil, code + } + rr, code := candidateRefused(r, candidateCode(failure, c)) + return rr, nil, code + } + if failure := localReferences(doc); failure != nil { + rr, code := candidateRefused(r, candidateLocalCode(doc, failure)) + return rr, nil, code + } + r.Status, r.ValidationScope, r.Document = "document-valid", r.Capabilities.ValidationScope, "" + return r, doc, 0 + } if failure := referenceSelectors(doc); failure != nil { r, code := refused(r, failure.code, failure.path, failure.message, result.ExitUnsupported) return r, nil, code @@ -151,6 +177,11 @@ func Validate(command string, data []byte) (Report, int) { return r, code } +func ValidateFormat(command string, data []byte, format string) (Report, int) { + r, _, code := validateDocumentFormat(command, data, format) + return r, code +} + func referenceSelectors(doc map[string]any) *issue { if doc["kind"] != "governing-adoption" { return nil From 6dd003e29cccf7808227b98157e55cebce4b231b Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:42:09 -0400 Subject: [PATCH 2/6] Fix candidate URI assertions and material phase ordering Use an explicit candidate-only RFC 3986 URI assertion for every URI field, including editing-schema compilation and init. Keep Core and prototype URI validation unchanged. Check material count before entry shape and validate private-wire entries in registration order, preserving earlier refusals. Add 62 URI probes, candidate schema/init/reference parity, Core/prototype compatibility checks and native private-wire ordering regressions. These implement the two accepted same-vendor review findings on 558df435bbc5. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- internal/policy/candidate_review_test.go | 111 ++++++++ internal/policy/candidate_schema.go | 6 +- internal/policy/candidate_uri.go | 135 ++++++++++ internal/policy/materials.go | 16 +- .../policy/testdata/candidate-uri-cases.json | 250 ++++++++++++++++++ internal/validation/validator.go | 10 + 6 files changed, 518 insertions(+), 10 deletions(-) create mode 100644 internal/policy/candidate_review_test.go create mode 100644 internal/policy/candidate_uri.go create mode 100644 internal/policy/testdata/candidate-uri-cases.json diff --git a/internal/policy/candidate_review_test.go b/internal/policy/candidate_review_test.go new file mode 100644 index 00000000..a617eff6 --- /dev/null +++ b/internal/policy/candidate_review_test.go @@ -0,0 +1,111 @@ +package policy + +import ( + "encoding/json" + "os" + "strings" + "testing" + + "github.com/Judgment-Pack/judgment-pack-runtime/internal/result" + "github.com/Judgment-Pack/judgment-pack-runtime/internal/validation" +) + +func TestCandidateURIFormatAgreementAndInitSchemaParity(t *testing.T) { + raw, err := os.ReadFile("testdata/candidate-uri-cases.json") + if err != nil { + t.Fatal(err) + } + var cases []struct { + URI string `json:"uri"` + Valid bool `json:"valid"` + } + if err := json.Unmarshal(raw, &cases); err != nil { + t.Fatal(err) + } + schema, exit := Schema("schema", "policy", CandidateVersion) + if exit != 0 { + t.Fatal(schema, exit) + } + compiled, err := compileCandidateSchemas(map[string][]byte{"urn:test:candidate-editing-schema": []byte(schema.Resource.Text)}, "urn:test:candidate-editing-schema") + if err != nil { + t.Fatal(err) + } + f := candidateFixture(t, "refunds") + for _, tc := range cases { + t.Run(tc.URI, func(t *testing.T) { + f.policy["id"] = tc.URI + r, exit := Check("check", mustJSON(t, f.policy), f.wire(t), engine(t)) + if (exit == 0) != tc.Valid || !tc.Valid && r.CandidateResult.Code != "invalid-document" { + t.Fatalf("URI result %+v exit %d expected valid %v", r.CandidateResult, exit, tc.Valid) + } + if (compiled.Validate(f.policy) == nil) != tc.Valid { + t.Fatal("editing schema URI assertion differs") + } + if init, exit := Init("init", "policy", CandidateVersion, tc.URI, "7.3.42"); (exit == 0) != tc.Valid { + t.Fatalf("init URI assertion differs %+v exit %d", init, exit) + } + }) + } + // Candidate compilation must not replace the historical URI assertion used + // by Core/prototype consumers, even within the same process. + if !validURI("urn:test:[x]") { + t.Fatal("prototype URI behavior changed") + } + legacy := loadFixture(t, "refunds") + legacy.policy["id"] = "urn:test:[x]" + if report, exit := Validate("legacy", mustJSON(t, legacy.policy)); exit != 0 { + t.Fatalf("prototype schema URI behavior changed %+v %d", report, exit) + } + consumer := mustMap(t, legacy.raw["consumer-pack.json"]) + consumer["id"] = "urn:test:[x]" + if report, failure := engine(t).Validate(mustJSON(t, consumer), validation.Options{Through: "structural", Limits: limits()}); failure != nil || report.Status != "valid" { + t.Fatalf("Core URI behavior changed %+v %v", report, failure) + } +} + +func TestCandidateURIAssertionsCoverArtifactReferences(t *testing.T) { + for _, member := range []string{"id", "consumer", "policy"} { + f := candidateFixture(t, "refunds") + switch member { + case "id": + f.adoption["id"] = "urn:test:[x]" + case "consumer": + object(f.adoption["consumer"])["id"] = "urn:test:[x]" + case "policy": + object(object(array(f.adoption["governingPolicies"])[0])["policy"])["id"] = "urn:test:[x]" + } + r, exit := Validate("validate", mustJSON(t, f.adoption)) + if exit != result.ExitInvalid || r.refusalCode != "invalid-document" { + t.Fatalf("URI member %s bypassed assertion %+v exit %d", member, r, exit) + } + } +} + +func TestCandidatePrivateWireRegistrationPhaseOrdering(t *testing.T) { + f := candidateFixture(t, "refunds") + validEntry := f.entries[0] + sixteen := make([]wireEntry, 16) + for i := range sixteen { + sixteen[i] = validEntry + } + badDigest := wireEntry{Content: map[string]any{"bytesDigest": "sha256:" + strings.Repeat("0", 64), "byteLength": 1, "mediaType": "text/plain"}, DataBase64: encodeMaterial([]byte("x"))} + for _, tc := range []struct { + name string + entries []wireEntry + code string + exit int + }{ + {"count-before-entry-shape", append(sixteen, wireEntry{Content: nil, DataBase64: nil}), "input-over-bound", result.ExitUnsupported}, + {"earlier-digest-before-later-content-shape", []wireEntry{badDigest, {Content: nil, DataBase64: encodeMaterial([]byte("x"))}}, "reference-mismatch", result.ExitInvalid}, + {"earlier-digest-before-later-base64-type", []wireEntry{badDigest, {Content: validEntry.Content, DataBase64: nil}}, "reference-mismatch", result.ExitInvalid}, + {"reached-invalid-content", []wireEntry{validEntry, {Content: nil, DataBase64: encodeMaterial([]byte("x"))}}, "invalid-carrier", result.ExitInvalid}, + {"reached-invalid-base64-type", []wireEntry{validEntry, {Content: validEntry.Content, DataBase64: nil}}, "invalid-carrier", result.ExitInvalid}, + } { + t.Run(tc.name, func(t *testing.T) { + r, exit := Check("check", f.raw["policy.json"], mustJSON(t, map[string]any{"materials": tc.entries}), engine(t)) + if exit != tc.exit || r.CandidateResult == nil || r.CandidateResult.Code != tc.code { + t.Fatalf("native wire phase result %+v exit %d", r.CandidateResult, exit) + } + }) + } +} diff --git a/internal/policy/candidate_schema.go b/internal/policy/candidate_schema.go index 11e6f131..7a418da8 100644 --- a/internal/policy/candidate_schema.go +++ b/internal/policy/candidate_schema.go @@ -38,7 +38,7 @@ func loadCandidateSchemas() (map[string]*jsonschema.Schema, error) { } candidateSchemas = map[string]*jsonschema.Schema{} for name, id := range map[string]string{"common": candidateCommonID, "uri": candidateCommonID + "#/$defs/uri", "policy": "urn:jps:proposal:policy-companion:1.0.0:policy", "governing-adoption": "urn:jps:proposal:policy-companion:1.0.0:governing-adoption"} { - s, err := validation.CompileSchemas(resources, id) + s, err := compileCandidateSchemas(resources, id) if err != nil { candidateSchemasError = err return @@ -49,6 +49,10 @@ func loadCandidateSchemas() (map[string]*jsonschema.Schema, error) { return candidateSchemas, candidateSchemasError } +func compileCandidateSchemas(resources map[string][]byte, id string) (*jsonschema.Schema, error) { + return validation.CompileSchemasWithFormats(resources, id, &jsonschema.Format{Name: "uri", Validate: validateCandidateURI}) +} + func validURIFormat(id, version string) bool { if version == ProfileVersion { return validURI(id) diff --git a/internal/policy/candidate_uri.go b/internal/policy/candidate_uri.go new file mode 100644 index 00000000..4552cf0f --- /dev/null +++ b/internal/policy/candidate_uri.go @@ -0,0 +1,135 @@ +package policy + +import ( + "errors" + "net/netip" + "strings" +) + +// Candidate URI assertions follow the components in RFC 3986 Appendix A, +// https://www.rfc-editor.org/rfc/rfc3986#appendix-A. This is generic URI syntax, +// with no scheme-specific network, DNS, port-range or publication semantics. +// Core/prototype schemas retain their existing URI predicate. +func validateCandidateURI(value any) error { + uri, ok := value.(string) + if !ok { + return nil + } + if !candidateURI(uri) { + return errors.New("URI does not satisfy the candidate URI format assertion") + } + return nil +} + +func candidateURI(uri string) bool { + scheme, rest, found := strings.Cut(uri, ":") + if !found || scheme == "" || !uriAlpha(scheme[0]) { + return false + } + for i := 1; i < len(scheme); i++ { + if !uriAlpha(scheme[i]) && !uriDigit(scheme[i]) && !strings.ContainsRune("+.-", rune(scheme[i])) { + return false + } + } + // Query and fragment allow pchar, slash and question mark. A second raw + // fragment delimiter is consequently refused by the component grammar. + if body, fragment, found := strings.Cut(rest, "#"); found { + if !uriComponent(fragment, ":@/?", true) { + return false + } + rest = body + } + if body, query, found := strings.Cut(rest, "?"); found { + if !uriComponent(query, ":@/?", true) { + return false + } + rest = body + } + if strings.HasPrefix(rest, "//") { + authority, path, found := strings.Cut(rest[2:], "/") + if !uriAuthority(authority) { + return false + } + if !found { + return true + } + return uriComponent(path, ":@/", true) + } + // Without an authority, a leading double slash is unavailable. The three + // remaining path alternatives are absolute, rootless and empty; each uses + // the same pchar/segment grammar once authority selection is settled. + return uriComponent(rest, ":@/", true) +} + +func uriAuthority(authority string) bool { + if userinfo, host, found := strings.Cut(authority, "@"); found { + if !uriComponent(userinfo, ":", true) { + return false + } + authority = host + } + if strings.HasPrefix(authority, "[") { + literal, suffix, found := strings.Cut(authority[1:], "]") + if !found || !uriIPLiteral(literal) { + return false + } + return suffix == "" || strings.HasPrefix(suffix, ":") && uriPort(suffix[1:]) + } + host, port, found := strings.Cut(authority, ":") + // reg-name includes the textual IPv4 alternative and permits percent + // escapes in host names. It is not restricted to DNS label syntax. + if !uriComponent(host, "", true) { + return false + } + return !found || uriPort(port) +} + +func uriPort(port string) bool { + for i := range port { + if !uriDigit(port[i]) { + return false + } + } + return true +} + +func uriIPLiteral(literal string) bool { + if strings.HasPrefix(literal, "v") || strings.HasPrefix(literal, "V") { + version, address, found := strings.Cut(literal[1:], ".") + if !found || version == "" || address == "" { + return false + } + for i := range version { + if !uriHex(version[i]) { + return false + } + } + return uriComponent(address, ":", false) + } + // Scoped addresses are a later extension, outside the candidate's exact + // RFC 3986 assertion; a plain IPv4 address cannot occupy IP-literal. + address, err := netip.ParseAddr(literal) + return err == nil && address.Is6() && address.Zone() == "" +} + +func uriComponent(value, extra string, escapes bool) bool { + allowed := "-._~!$&'()*+,;=" + extra + for i := 0; i < len(value); i++ { + c := value[i] + if escapes && c == '%' { + if i+2 >= len(value) || !uriHex(value[i+1]) || !uriHex(value[i+2]) { + return false + } + i += 2 + continue + } + if !uriAlpha(c) && !uriDigit(c) && !strings.ContainsRune(allowed, rune(c)) { + return false + } + } + return true +} + +func uriAlpha(c byte) bool { return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' } +func uriDigit(c byte) bool { return c >= '0' && c <= '9' } +func uriHex(c byte) bool { return uriDigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f' } diff --git a/internal/policy/materials.go b/internal/policy/materials.go index d673395c..00c14906 100644 --- a/internal/policy/materials.go +++ b/internal/policy/materials.go @@ -52,15 +52,6 @@ func decodeMaterialsFormat(data []byte, candidateMode bool) (materialSet, *issue if _, ok := root["materials"].([]any); !ok { return nil, candidateIssue("invalid-carrier"), result.ExitInvalid } - for _, item := range entries { - entry := object(item) - if len(entry) != 2 || object(entry["content"]) == nil { - return nil, candidateIssue("invalid-carrier"), result.ExitInvalid - } - if _, ok := entry["dataBase64"].(string); !ok { - return nil, candidateIssue("invalid-carrier"), result.ExitInvalid - } - } } if len(entries) > MaxMaterials { return nil, problem("JPS-POLICY-MATERIAL-COUNT", "/materials", "The private Runtime carrier supports at most 16 material registrations."), result.ExitUnsupported @@ -118,6 +109,13 @@ func decodeMaterialsFormat(data []byte, candidateMode bool) (materialSet, *issue entry := object(item) content := object(entry["content"]) if candidateMode { + if len(entry) != 2 || object(entry["content"]) == nil { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + if _, ok := entry["dataBase64"].(string); !ok { + return nil, candidateIssue("invalid-carrier"), result.ExitInvalid + } + if err, c := candidateSchema("common", content); err != nil { return nil, err, c } diff --git a/internal/policy/testdata/candidate-uri-cases.json b/internal/policy/testdata/candidate-uri-cases.json new file mode 100644 index 00000000..78e55b0a --- /dev/null +++ b/internal/policy/testdata/candidate-uri-cases.json @@ -0,0 +1,250 @@ +[ + { + "uri": "urn:test:plain", + "valid": true + }, + { + "uri": "https://example.invalid/a", + "valid": true + }, + { + "uri": "https://%65xample.invalid/a", + "valid": true + }, + { + "uri": "foo://[v1.a]/", + "valid": true + }, + { + "uri": "https://[2001:db8::1]/a", + "valid": true + }, + { + "uri": "https://[::1]:443/a", + "valid": true + }, + { + "uri": "https://[::ffff:192.0.2.128]/", + "valid": true + }, + { + "uri": "https://[vF.a:b!$&'()*+,;=]/", + "valid": true + }, + { + "uri": "HTTPS://EXAMPLE.INVALID/a", + "valid": true + }, + { + "uri": "https://user:pass@example.invalid/a", + "valid": true + }, + { + "uri": "https://u%40ser:p%3Ass@example.invalid/a", + "valid": true + }, + { + "uri": "https://example.invalid/a%5Bb%5D", + "valid": true + }, + { + "uri": "urn:test:%5Bx%5D", + "valid": true + }, + { + "uri": "urn:test:%C3%A9", + "valid": true + }, + { + "uri": "https://example.invalid/a?b=%5Bc%5D", + "valid": true + }, + { + "uri": "https://example.invalid/#a%5Bb%5D", + "valid": true + }, + { + "uri": "https://exa!mple.invalid:99999/a", + "valid": true + }, + { + "uri": "https://example.invalid:/", + "valid": true + }, + { + "uri": "file:///tmp/example", + "valid": true + }, + { + "uri": "foo://", + "valid": true + }, + { + "uri": "foo:", + "valid": true + }, + { + "uri": "foo:/", + "valid": true + }, + { + "uri": "foo:a/b:c@d", + "valid": true + }, + { + "uri": "foo://@/", + "valid": true + }, + { + "uri": "https://example.invalid/a?x=/a?b#c/d?e", + "valid": true + }, + { + "uri": "https://example.invalid/..?a=1&b=2#part", + "valid": true + }, + { + "uri": "foo://256.999.0.1/", + "valid": true + }, + { + "uri": "urn:test:[x]", + "valid": false + }, + { + "uri": "https://example.invalid/[x]", + "valid": false + }, + { + "uri": "https://example.invalid/a?b=[c]", + "valid": false + }, + { + "uri": "https://example.invalid/#a[b]", + "valid": false + }, + { + "uri": "urn:test:\u00e9", + "valid": false + }, + { + "uri": "urn:test:foo bar", + "valid": false + }, + { + "uri": "urn:test:%", + "valid": false + }, + { + "uri": "urn:test:%GG", + "valid": false + }, + { + "uri": "https://%6xample.invalid/a", + "valid": false + }, + { + "uri": "/relative/path", + "valid": false + }, + { + "uri": "//example.invalid/path", + "valid": false + }, + { + "uri": "1foo:bar", + "valid": false + }, + { + "uri": "foo_:bar", + "valid": false + }, + { + "uri": "https://[x]/", + "valid": false + }, + { + "uri": "https://[]/", + "valid": false + }, + { + "uri": "https://[::1", + "valid": false + }, + { + "uri": "https://[::1]junk/", + "valid": false + }, + { + "uri": "https://[::1]:port/", + "valid": false + }, + { + "uri": "https://[::1%25eth0]/", + "valid": false + }, + { + "uri": "https://[2001:db8:::1]/", + "valid": false + }, + { + "uri": "https://[1:2:3:4:5:6:7:8:9]/", + "valid": false + }, + { + "uri": "https://[127.0.0.1]/", + "valid": false + }, + { + "uri": "https://[v1.]/", + "valid": false + }, + { + "uri": "https://[vG.a]/", + "valid": false + }, + { + "uri": "https://[v1.a%20b]/", + "valid": false + }, + { + "uri": "https://[VF.x:y]/", + "valid": true + }, + { + "uri": "https://foo@@example.invalid/", + "valid": false + }, + { + "uri": "https://[::1]@example.invalid/", + "valid": false + }, + { + "uri": "https://example.invalid:abc/", + "valid": false + }, + { + "uri": "https://example.invalid:1:2/", + "valid": false + }, + { + "uri": "https://example.invalid/#a#b", + "valid": false + }, + { + "uri": "https://example.invalid/\\path", + "valid": false + }, + { + "uri": "urn:test:foo\r\n", + "valid": false + }, + { + "uri": "urn:test:foo\n", + "valid": false + }, + { + "uri": "https://[::ffff:192.168.001.001]/", + "valid": false + } +] diff --git a/internal/validation/validator.go b/internal/validation/validator.go index 58db97ed..c7caba9c 100644 --- a/internal/validation/validator.go +++ b/internal/validation/validator.go @@ -70,9 +70,19 @@ func CompileSchema(schemaBytes []byte, resourceID string) (*jsonschema.Schema, e // CompileSchemas resolves only explicitly supplied schema resources, using the // same URI assertions and ECMAScript expressions as bundled Core validation. func CompileSchemas(resources map[string][]byte, resourceID string) (*jsonschema.Schema, error) { + return CompileSchemasWithFormats(resources, resourceID) +} + +// CompileSchemasWithFormats keeps the offline compiler's existing defaults and +// permits an explicit companion contract to override a named format assertion. +// Overrides never affect other compiled schemas or the bundled Core engine. +func CompileSchemasWithFormats(resources map[string][]byte, resourceID string, formats ...*jsonschema.Format) (*jsonschema.Schema, error) { compiler := jsonschema.NewCompiler() compiler.AssertFormat() compiler.RegisterFormat(&jsonschema.Format{Name: "uri", Validate: validateRFC3986URI}) + for _, format := range formats { + compiler.RegisterFormat(format) + } compiler.UseLoader(offlineSchemaLoader{}) compiler.UseRegexpEngine(ecmaRegexpCompile) for id, data := range resources { From 2e158c5105046594749139c955839a041331a106 Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:44:59 -0400 Subject: [PATCH 3/6] Apply candidate URI assertions to retained Pack validation Select candidate URI format assertions explicitly for Core structural checks inside candidate adoption. Validate original Pack bytes against the same bundled schema while leaving default Core and prototype engine behavior unchanged. Extend the accepted URI review correction with 62 full-adoption URI probes, raw numeric-literal identity checks and default-engine isolation coverage. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- internal/policy/candidate_review_test.go | 41 ++++++++++++++++++++++++ internal/policy/candidate_schema.go | 6 +++- internal/policy/check.go | 7 +++- internal/validation/validator.go | 16 ++++++++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/internal/policy/candidate_review_test.go b/internal/policy/candidate_review_test.go index a617eff6..1a5fd684 100644 --- a/internal/policy/candidate_review_test.go +++ b/internal/policy/candidate_review_test.go @@ -1,6 +1,7 @@ package policy import ( + "bytes" "encoding/json" "os" "strings" @@ -81,6 +82,46 @@ func TestCandidateURIAssertionsCoverArtifactReferences(t *testing.T) { } } +func TestCandidateConsumerURIUsesSameAssertionAndPreservesRawBytes(t *testing.T) { + raw, err := os.ReadFile("testdata/candidate-uri-cases.json") + if err != nil { + t.Fatal(err) + } + var cases []struct { + URI string `json:"uri"` + Valid bool `json:"valid"` + } + if err := json.Unmarshal(raw, &cases); err != nil { + t.Fatal(err) + } + for _, tc := range cases { + t.Run(tc.URI, func(t *testing.T) { + f := candidateFixture(t, "refunds") + reference := object(f.adoption["consumer"]) + pack := bytes.Replace(f.raw["consumer-pack.json"], mustJSON(t, reference["id"]), mustJSON(t, tc.URI), 1) + // An optional Core number outside jps-canon proves that checking the + // candidate URI neither reserializes the Pack nor narrows its numbers. + pack = bytes.Replace(pack, []byte(`"specVersion":`), []byte(`"extensions":{"com.example.uri":1.0},"specVersion":`), 1) + reference["id"] = tc.URI + f.retainConsumer(t, pack) + r, exit := Check("check", mustJSON(t, f.adoption), f.wire(t), engine(t)) + if (exit == 0) != tc.Valid || !tc.Valid && r.CandidateResult.Code != "invalid-document" { + t.Fatalf("consumer URI result %+v exit %d expected valid %v", r.CandidateResult, exit, tc.Valid) + } + if !bytes.Equal(f.raw["consumer-pack.json"], pack) || text(object(reference["content"])["bytesDigest"]) != digest(pack) { + t.Fatal("consumer raw identity changed") + } + }) + } + // Overrides belong to one candidate check, not the caller's shared engine. + f := candidateFixture(t, "refunds") + reference := object(f.adoption["consumer"]) + pack := bytes.Replace(f.raw["consumer-pack.json"], mustJSON(t, reference["id"]), mustJSON(t, "https://%65xample.invalid/a"), 1) + if report, failure := engine(t).Validate(pack, validation.Options{Through: "structural", Limits: limits()}); failure != nil || report.Status != "invalid" { + t.Fatalf("default Core URI behavior changed %+v %v", report, failure) + } +} + func TestCandidatePrivateWireRegistrationPhaseOrdering(t *testing.T) { f := candidateFixture(t, "refunds") validEntry := f.entries[0] diff --git a/internal/policy/candidate_schema.go b/internal/policy/candidate_schema.go index 7a418da8..1927d4ae 100644 --- a/internal/policy/candidate_schema.go +++ b/internal/policy/candidate_schema.go @@ -50,7 +50,11 @@ func loadCandidateSchemas() (map[string]*jsonschema.Schema, error) { } func compileCandidateSchemas(resources map[string][]byte, id string) (*jsonschema.Schema, error) { - return validation.CompileSchemasWithFormats(resources, id, &jsonschema.Format{Name: "uri", Validate: validateCandidateURI}) + return validation.CompileSchemasWithFormats(resources, id, candidateURIFormat()) +} + +func candidateURIFormat() *jsonschema.Format { + return &jsonschema.Format{Name: "uri", Validate: validateCandidateURI} } func validURIFormat(id, version string) bool { diff --git a/internal/policy/check.go b/internal/policy/check.go index 47268655..bd99612e 100644 --- a/internal/policy/check.go +++ b/internal/policy/check.go @@ -11,6 +11,7 @@ import ( "github.com/Judgment-Pack/judgment-pack-runtime/internal/jpscanon" "github.com/Judgment-Pack/judgment-pack-runtime/internal/result" "github.com/Judgment-Pack/judgment-pack-runtime/internal/validation" + "github.com/santhosh-tekuri/jsonschema/v6" ) // Check operates only on supplied bytes. The private carrier accepts no paths, @@ -253,7 +254,11 @@ func checkAdoption(doc map[string]any, materials materialSet, engine *validation if engine == nil { return problem("JPS-POLICY-ENGINE", "/consumer", "A bundled Core structural validation engine is required."), result.ExitIO } - checked, failure := engine.Validate(raw, validation.Options{Through: "structural", Limits: limits()}) + options := validation.Options{Through: "structural", Limits: limits()} + if candidateMode { + options.FormatOverrides = []*jsonschema.Format{candidateURIFormat()} + } + checked, failure := engine.Validate(raw, options) if failure != nil { return problem("JPS-POLICY-CONSUMER-BOUND", "/consumer", "Core structural validation could not complete within supported input bounds."), failure.ExitCode } diff --git a/internal/validation/validator.go b/internal/validation/validator.go index c7caba9c..a4580934 100644 --- a/internal/validation/validator.go +++ b/internal/validation/validator.go @@ -25,6 +25,9 @@ type Options struct { ExpectedSpecVersion string SupportedExtensions []string Limits carrier.Limits + // FormatOverrides is explicit companion-scoped structural validation. The + // same bundled schema and input bytes are used; cached defaults are untouched. + FormatOverrides []*jsonschema.Format } type OperationalFailure struct { @@ -233,7 +236,18 @@ func (e *Engine) Validate(data []byte, options Options) (result.Validation, *Ope Provenance: lock.Source.Kind, } - schemaErr := e.schemas[selectedVersion].Validate(value) + schema := e.schemas[selectedVersion] + if len(options.FormatOverrides) != 0 { + rawSchema, err := set.Schema() + if err == nil { + id := "urn:judgmentpack:jps:" + selectedVersion + ":schema" + schema, err = CompileSchemasWithFormats(map[string][]byte{id: rawSchema}, id, options.FormatOverrides...) + } + if err != nil { + return output, &OperationalFailure{Code: "JPS-SCHEMA-FORMAT-OVERRIDE", Message: "The bundled structural schema could not be compiled with explicit format assertions.", ExitCode: result.ExitIO} + } + } + schemaErr := schema.Validate(value) structuralCollector := newDiagnosticCollector() if schemaErr != nil { var validationError *jsonschema.ValidationError From 38b06043283d2ae294653ca8f25c8c5db415dd9e Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:47:20 -0400 Subject: [PATCH 4/6] Preserve candidate artifact bytes on Windows checkout Apply the existing immutable-artifact -text policy to the separately vendored Policy candidate tree. This prevents autocrlf checkout conversion from changing provenance, schemas, examples and portable vector inputs. Verified core.autocrlf=true checkout with all143 current upstream file digests, lengths and the independent provenance pin unchanged; a control file converted to CRLF. Runtime inputs and identity checks are unchanged. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index ca23e9ce..383dad5e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -17,5 +17,8 @@ internal/dialect/testdata/** -text # Pinned policy prototype files have exact upstream checksums. internal/policy/prototype/** -text +# Candidate schemas, provenance, examples and vectors also retain exact bytes. +internal/policy/candidate/** -text + # The served authoring schema has a byte digest on every platform. internal/dialect/version2.schema.json -text From 65ff571ec5380049b38a52aa55c6795c9e6b2a53 Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:49:17 -0400 Subject: [PATCH 5/6] Record reviewed Policy candidate corrections and exact source Pin the URI-corrected proposed-draft candidate at Spec 0852c5fa7726, preserving all 170 vendored source files with exact provenance and byte checks. Expand portable agreement to 124 vectors and record the accepted same-vendor review findings, their corrections and the temporary maintainer-authorized waiver. Accept ADR 0060 as the authorized merge-ready procedural transition without adopting a normative Policy format. Keep Core/prototype URI behavior and all release/Desk state unchanged. Verify companion URI bounds do not leak into Core structural assertions, and validate autocrlf checkout byte preservation. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- README.md | 4 +- .../0060-explicit-policy-candidate-format.md | 49 +- docs/adr/README.md | 2 +- docs/architecture.md | 4 +- docs/mcp-clients.md | 2 +- .../policy/candidate/0023-policy-companion.md | 14 + internal/policy/candidate/README.md | 26 +- internal/policy/candidate/common.schema.json | 3 +- internal/policy/candidate/provenance.json | 184 ++- internal/policy/candidate/vectors/README.md | 16 +- .../vectors/documents/uri-final-lf-pack.json | 62 + .../vectors/documents/uri-final-lf.json | 75 + .../documents/uri-fragment-raw-brackets.json | 76 + .../documents/uri-ipv6-compressed.json | 76 + .../uri-ipv6-double-compression.json | 76 + .../vectors/documents/uri-ipv6-ipv4-tail.json | 76 + .../uri-ipv6-leading-zero-ipv4-tail-pack.json | 62 + .../uri-ipv6-leading-zero-ipv4-tail.json | 75 + .../uri-ipvfuture-invalid-version.json | 76 + .../uri-ipvfuture-lowercase-pack.json | 62 + .../documents/uri-ipvfuture-lowercase.json | 75 + .../uri-ipvfuture-uppercase-pack.json | 62 + .../documents/uri-ipvfuture-uppercase.json | 75 + .../uri-numeric-regname-leading-zeros.json | 76 + .../documents/uri-path-raw-brackets-pack.json | 62 + .../documents/uri-path-raw-brackets.json | 75 + .../documents/uri-percent-brackets.json | 76 + .../documents/uri-percent-incomplete.json | 76 + .../vectors/documents/uri-percent-nonhex.json | 76 + .../documents/uri-percent-regname-pack.json | 62 + .../documents/uri-percent-regname.json | 75 + .../documents/uri-percent-unicode.json | 76 + .../documents/uri-query-raw-brackets.json | 76 + .../vectors/documents/uri-raw-unicode.json | 76 + .../uri-rootless-raw-brackets-pack.json | 62 + .../documents/uri-rootless-raw-brackets.json | 75 + .../uri-userinfo-percent-brackets.json | 76 + .../policy/candidate/vectors/manifest.json | 1249 +++++++++++++++++ internal/policy/candidate_review_test.go | 16 + internal/policy/candidate_test.go | 4 +- internal/policy/format.go | 2 +- 41 files changed, 3489 insertions(+), 33 deletions(-) create mode 100644 internal/policy/candidate/vectors/documents/uri-final-lf-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-final-lf.json create mode 100644 internal/policy/candidate/vectors/documents/uri-fragment-raw-brackets.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipv6-compressed.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipv6-double-compression.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipv6-ipv4-tail.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipvfuture-invalid-version.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase.json create mode 100644 internal/policy/candidate/vectors/documents/uri-numeric-regname-leading-zeros.json create mode 100644 internal/policy/candidate/vectors/documents/uri-path-raw-brackets-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-path-raw-brackets.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-brackets.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-incomplete.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-nonhex.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-regname-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-regname.json create mode 100644 internal/policy/candidate/vectors/documents/uri-percent-unicode.json create mode 100644 internal/policy/candidate/vectors/documents/uri-query-raw-brackets.json create mode 100644 internal/policy/candidate/vectors/documents/uri-raw-unicode.json create mode 100644 internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets-pack.json create mode 100644 internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets.json create mode 100644 internal/policy/candidate/vectors/documents/uri-userinfo-percent-brackets.json diff --git a/README.md b/README.md index d9f76720..c8598bd0 100644 --- a/README.md +++ b/README.md @@ -1144,7 +1144,7 @@ proposed-draft** candidate `formatVersion: "1.0.0"` ([ADR-0060](docs/adr/0060-explicit-policy-candidate-format.md)). It is a review candidate for RFC 0023, not a stable format, adopted standard or conformance class. Its artifacts are pinned separately to Spec commit -`4406cec9714ab9bc8e8971237cc79d58682cc904` in +`0852c5fa7726e51b36e574a5b110e7f5e012e03d` in [the candidate provenance manifest](internal/policy/candidate/provenance.json). Default `contract` output and all prototype reports keep their existing shape @@ -1187,7 +1187,7 @@ Canonicalize/digest establish encoding and identity only; validate checks closed document forms and local references, with retained materials unchecked. Their reports omit `candidateResult`. -The Go harness compares all 104 exact portable result objects, acquiring vector +The Go harness compares all 124 exact portable result objects, acquiring vector sources lazily and preserving raw Pack numbers and every retained-byte identity. It uses the shared registration/checking engine directly: valid distinct-byte bundles can exceed the private 24 MiB JSON/base64 carrier or MCP's 16 MiB request diff --git a/docs/adr/0060-explicit-policy-candidate-format.md b/docs/adr/0060-explicit-policy-candidate-format.md index 0f6d129c..2e4a1820 100644 --- a/docs/adr/0060-explicit-policy-candidate-format.md +++ b/docs/adr/0060-explicit-policy-candidate-format.md @@ -1,5 +1,5 @@ --- -status: proposed +status: accepted date: 2026-10-18 deciders: maintainer --- @@ -31,7 +31,7 @@ would break their discovery and authoring flows. Chosen option: explicit format dispatch around the shared engine. Candidate artifacts are separately vendored from immutable Spec commit -`4406cec9714ab9bc8e8971237cc79d58682cc904`, with a complete per-file provenance +`0852c5fa7726e51b36e574a5b110e7f5e012e03d`, with a complete per-file provenance manifest and independent manifest digest test. Prototype files and ADR-0059 remain unchanged. This record adopts no normative Policy format. @@ -61,13 +61,23 @@ identity, and Core structural validation receives the original Pack bytes. Source and narrative bytes, registrations under distinct media types, consuming role bounds and typed Pack references remain shared checks. +Candidate URI assertions use the RFC 3986 `URI` production: a scheme is required +and a fragment is permitted. Component grammar distinguishes authority, IP +literals, user information, paths, queries and fragments; percent-encoded host +characters and IPvFuture literals are valid without network interpretation. +Generic ports remain digit strings without a network port-range restriction. +Only candidate schemas/init and candidate-consuming Pack structural checks opt +into this assertion. The structural engine validates the same raw Pack bytes and +bundled schema with a per-call URI format override; default Core and prototype +URI behavior and their cached schemas remain unchanged. + The private Runtime base64 material transport remains separate from portable raw vector inputs. Its 24 MiB material JSON ceiling and MCP's 16 MiB request-line ceiling remain unchanged. Repeated registrations of identical large bytes can fit the candidate's distinct-byte budget while exceeding an encoded transport ceiling. The portable harness therefore uses the same shared post-parse checks and raw registration function, acquires sources lazily in declaration order and -stops on the first failure. Passing all 104 vectors promises no larger wire +stops on the first failure. Passing all 124 vectors promises no larger wire envelope, authority, conformance or independent implementation agreement. ### Consequences @@ -85,12 +95,33 @@ results extend a public surface; vendored candidate artifacts add a dependency boundary; ordered bounded input handling concerns the security posture. The maintainer authorized a temporary different-vendor review waiver for this -current Policy work. OpenAI/Codex implementation and any OpenAI/Codex adversarial -review are same-vendor work under that waiver, never different-vendor review or -independently authored interoperability evidence. Review records must identify -the reviewed commit and maintainer dispositions. The waiver changes no standing -repository requirement. This record remains proposed pending that procedural -disposition. +current Policy work. The recorded clean-room review of Runtime commit +`558df435bbc50fc872b14aceecae1d482b45898d`, performed by OpenAI/Codex +`gpt-6.1-sol` at `xhigh`, found two P2 issues and no P1 issue. The maintainer +accepted both findings: candidate URI assertions and private-carrier registration +phase ordering. The [review and dispositions on PR 296](https://github.com/Judgment-Pack/judgment-pack-runtime/pull/296#issuecomment-6254960095) +identify that reviewed commit and the bounded review's actual evidence. + +Commits `6dd003e29cccf7808227b98157e55cebce4b231b` and +`2e158c5105046594749139c955839a041331a106` implement those accepted findings, +including candidate-consuming Pack URI checks over unchanged bytes and schema. +The coordinator reports that the reviewer closed both findings at `2e158c5`. +Commit `38b06043283d2ae294653ca8f25c8c5db415dd9e` additionally preserves the +vendored candidate's exact bytes under Windows checkout conversion. Focused +verification covers the 124 portable vectors, 62 standalone and 62 consuming +Pack URI probes, ordered private-wire refusals, schema/init parity and unchanged +Core/prototype URI behavior. Checkout verification with `core.autocrlf=true` +checks every vendored source digest/length and the independent provenance pin. + +The URI source correction is pinned to the exact candidate commit above and is +tracked in [Spec PR 217](https://github.com/Judgment-Pack/judgment-pack-spec/pull/217). +The maintainer requires that source review and repository CI before Runtime merge. This +accepted status records the maintainer-authorized merge-ready procedural +transition; it does not adopt a normative Policy format or change the RFC's +Review status. All implementation, review and agreement evidence described here +is same-vendor work under the temporary waiver, never different-vendor review +or independently authored interoperability evidence. The waiver changes no +standing repository requirement. ## More information diff --git a/docs/adr/README.md b/docs/adr/README.md index 79e9be7e..bb15b928 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -155,4 +155,4 @@ authority, and following it confers no conformance status on anything. | [0056](0056-version-3-dialect-authoring.md) | Check supported version-3 Dialect declarations through shared authoring tools | accepted | | [0057](0057-named-dialect-artifact-identity.md) | Share offline tools for named Dialect artifacts | accepted | | [0059](0059-experimental-offline-policy-tools.md) | Prototype Policy document and retained-reference checks offline | accepted | -| [0060](0060-explicit-policy-candidate-format.md) | Add an explicit Policy contract candidate without changing prototype clients | proposed | +| [0060](0060-explicit-policy-candidate-format.md) | Add an explicit Policy contract candidate without changing prototype clients | accepted | diff --git a/docs/architecture.md b/docs/architecture.md index ee653d1a..3ed6758a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -50,8 +50,8 @@ so JSON/base64 overhead reduces the maximum retained material a call can carry. The proposed-draft, unadopted Policy contract candidate `1.0.0` is an additional explicit format ([ADR-0060](adr/0060-explicit-policy-candidate-format.md)). Its -schemas, prose, examples and 104 portable vectors are pinned separately to Spec -commit `4406cec9714ab9bc8e8971237cc79d58682cc904`. Format selection, schema and +schemas, prose, examples and 124 portable vectors are pinned separately to Spec +commit `0852c5fa7726e51b36e574a5b110e7f5e012e03d`. Format selection, schema and provenance differ; material identity, UTF-8 anchors and typed Pack coverage use the same engine. Candidate adoption cannot consume prototype Policy bytes. No-argument contract discovery and prototype reports retain their exact prior diff --git a/docs/mcp-clients.md b/docs/mcp-clients.md index cf853616..4095a581 100644 --- a/docs/mcp-clients.md +++ b/docs/mcp-clients.md @@ -504,7 +504,7 @@ encoded request; CLI named-file input supports the larger material JSON envelope The seven existing tools also serve the unadopted Policy contract candidate `1.0.0`, at `proposed-draft` maturity, pinned to Spec commit -`4406cec9714ab9bc8e8971237cc79d58682cc904` +`0852c5fa7726e51b36e574a5b110e7f5e012e03d` ([ADR-0060](adr/0060-explicit-policy-candidate-format.md)). Calling contract without arguments or with `{}` returns the exact existing prototype report. `{allFormats:true}` explicitly requests the separate registry version 1; diff --git a/internal/policy/candidate/0023-policy-companion.md b/internal/policy/candidate/0023-policy-companion.md index 7806a417..13bf6c05 100644 --- a/internal/policy/candidate/0023-policy-companion.md +++ b/internal/policy/candidate/0023-policy-companion.md @@ -110,6 +110,20 @@ A Policy contains: - retained original source references with provider/account/resource identity, nullable opaque source revision and original content identity. +The unreleased candidate's URI assertion is corrected after commit +`30b0b30a1b0c851c41bdb271d6ef9534c91bcdec` to the complete scheme-bearing `URI` +production of [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#appendix-A), with +optional fragments, not the narrower `absolute-URI` production. Final LF and +leading-zero IPv4 tails in IPv6 literals now refuse; uppercase `V` in IPvFuture +now validates under [RFC 5234 §2.3](https://www.rfc-editor.org/rfc/rfc5234#section-2.3). +Twenty portable URI vectors also cover percent encodings, Unicode and brackets by +component, including seven full adoptions with exact consuming-Pack IDs/references. +The candidate's consuming-Pack structural checks assert the same corrected URI +grammar; shared Core validators and the prototype remain unchanged. +This repairs candidate-only validation rather than adopting dependency +or URL-parser quirks. Core/prototype checks and exact retained-byte semantics remain +unchanged; proposed format `1.0.0` is still unreleased and not adopted. + The narrative can be authored directly or derived from original documents. Original PDF/page/file bytes remain separate. An anchor in the narrative is not an original-source offset, and a new extraction does not silently rewrite either. diff --git a/internal/policy/candidate/README.md b/internal/policy/candidate/README.md index dbb2c720..b5a13b6e 100644 --- a/internal/policy/candidate/README.md +++ b/internal/policy/candidate/README.md @@ -42,11 +42,33 @@ or historical uniqueness is inferred. In particular, artifact `7.3.42` still use format `1.0.0`. Pack artifact references follow the same bounded version grammar; the retained Pack keeps its own Core `specVersion` unchanged. -An `id` is an opaque absolute URI, at most 2,048 Unicode characters. Identity is -not permission to fetch it. Local IDs match `[a-z][a-z0-9]*(?:-[a-z0-9]+)*`, at most +An `id` is an opaque, scheme-bearing identifier matching the complete `URI` +production of [RFC 3986, Appendix A](https://www.rfc-editor.org/rfc/rfc3986#appendix-A), +at most 2,048 characters. Optional query and fragment are allowed; a relative +reference is refused. This means `URI`, not the narrower `absolute-URI` production +that excludes fragments. Raw Unicode, controls, whitespace (including a final LF) +and malformed percent triplets refuse. Percent-encoded Unicode and registered +names remain valid; percent decoding, trimming and identity normalization never +occur. Raw brackets belong only around an authority's IP literal, so brackets in +path, query, fragment or rootless content must be percent-encoded. IPv6 dotted +tails must satisfy the IPv4 decimal-octet grammar without leading zeros. IPvFuture +accepts both `v` and `V`, under [RFC 5234 §2.3](https://www.rfc-editor.org/rfc/rfc5234#section-2.3). +An unbracketed numeric host that fails IPv4 can still be a valid registered name. +Identity is not permission to fetch it. Local IDs match `[a-z][a-z0-9]*(?:-[a-z0-9]+)*`, at most 128 characters. Required readable text is nonempty and at most 4,096 characters. Every defined object is closed: unknown members at any level are refused. +The unreleased candidate URI correction after commit +`30b0b30a1b0c851c41bdb271d6ef9534c91bcdec` changes three dependency-derived answers: +final-LF identifiers and IPv6 literals with leading-zero IPv4 tails now refuse; +uppercase-`V` IPvFuture identifiers now validate. The checker applies a local +candidate format override, including its consuming-Pack structural checks. Shared +Core validators elsewhere and the frozen prototype are unchanged. The candidate's +2,048-character ID bound belongs to its schemas; other Core URI fields retain +their existing schema bounds. +The 20 URI vectors also distinguish generic URI grammar from URL-parser behavior. +Format `1.0.0` remains proposed and unreleased; this correction confers no adoption. + ## 2. Exact retained content and optional canonical identity A content reference is exactly `{bytesDigest, byteLength, mediaType}`. The digest diff --git a/internal/policy/candidate/common.schema.json b/internal/policy/candidate/common.schema.json index e7c544e8..581bb42a 100644 --- a/internal/policy/candidate/common.schema.json +++ b/internal/policy/candidate/common.schema.json @@ -25,7 +25,8 @@ "type": "string", "format": "uri", "minLength": 1, - "maxLength": 2048 + "maxLength": 2048, + "description": "Scheme-bearing RFC 3986 URI production, including optional fragment. Assert the entire ASCII string; no trimming, Unicode/percent decoding, or identity normalization. See candidate prose for IPv6 and case-insensitive IPvFuture checks." }, "content": { "type": "object", diff --git a/internal/policy/candidate/provenance.json b/internal/policy/candidate/provenance.json index 109088f4..d6bedab8 100644 --- a/internal/policy/candidate/provenance.json +++ b/internal/policy/candidate/provenance.json @@ -1,6 +1,6 @@ { "sourceRepository": "https://github.com/Judgment-Pack/judgment-pack-spec", - "sourceRevision": "4406cec9714ab9bc8e8971237cc79d58682cc904", + "sourceRevision": "0852c5fa7726e51b36e574a5b110e7f5e012e03d", "formatVersion": "1.0.0", "maturity": "proposed-draft", "license": "Apache-2.0", @@ -14,8 +14,8 @@ { "sourcePath": "rfcs/policy-companion-contract/README.md", "path": "README.md", - "sha256": "fa67bf571088ea7c9a0ce9936558207a0053342e30f7f9dbc7088723c1b8a8e0", - "byteLength": 20590 + "sha256": "21364149bbd76cc7bc2b917b898d0fa79739bd454f94d4af3510e0e1a6ea88f7", + "byteLength": 22250 }, { "sourcePath": "rfcs/policy-companion-contract/capabilities.json", @@ -26,8 +26,8 @@ { "sourcePath": "rfcs/policy-companion-contract/common.schema.json", "path": "common.schema.json", - "sha256": "1fd3ad3ae5d76f99c82247f8202b6a821e1ab942350f9e0684a83a3b0bdea8c7", - "byteLength": 5003 + "sha256": "a26362280ac4cf0ba7a15a6c382ee8c61df97c78be4ef291f1107db24f28dd06", + "byteLength": 5262 }, { "sourcePath": "rfcs/policy-companion-contract/examples/data-access/adoption.json", @@ -188,8 +188,8 @@ { "sourcePath": "rfcs/policy-companion-contract/vectors/README.md", "path": "vectors/README.md", - "sha256": "23afb102f1a3407eb8b53e9859af50339392ecd8af453f64c78647673de1a624", - "byteLength": 5303 + "sha256": "d27b79c1932261d3bf64abb07d5c95ccab0a9016e83412c40a129747fdb8eaec", + "byteLength": 6372 }, { "sourcePath": "rfcs/policy-companion-contract/vectors/documents/aggregate-max.json", @@ -833,17 +833,179 @@ "sha256": "356114c27d81685231f3e6b7aa32305ae890319cf392e652e69d8ce908f5ca90", "byteLength": 2201 }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-final-lf-pack.json", + "path": "vectors/documents/uri-final-lf-pack.json", + "sha256": "c418f413e2b19f32dcc2f46664717ff2eb81e940fca57315275d39e63037f495", + "byteLength": 1503 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-final-lf.json", + "path": "vectors/documents/uri-final-lf.json", + "sha256": "2f801fd7b06bf34f5c3a42973249a71bf84c421755a1ef372b1bbd4ccd3710c4", + "byteLength": 2297 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-fragment-raw-brackets.json", + "path": "vectors/documents/uri-fragment-raw-brackets.json", + "sha256": "0ef6ed9f582d15475ec9b5358be05194b372f1fbc1935cc3a175e31e6c526736", + "byteLength": 1980 + }, { "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-invalid.json", "path": "vectors/documents/uri-invalid.json", "sha256": "2c8f6c238143c7dfa4381ab81b78365bfd43902a7eea09b872f1ee37ca0789ba", "byteLength": 1964 }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipv6-compressed.json", + "path": "vectors/documents/uri-ipv6-compressed.json", + "sha256": "6c59778a6d517c252840226d8a3056280777b04e76bf6759c731343f7d01080b", + "byteLength": 1978 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipv6-double-compression.json", + "path": "vectors/documents/uri-ipv6-double-compression.json", + "sha256": "b1be77321cd95c07b4ecf8baaba8751028b831e2787ba8ab6ee2a9c5e884193e", + "byteLength": 1973 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipv6-ipv4-tail.json", + "path": "vectors/documents/uri-ipv6-ipv4-tail.json", + "sha256": "2c26026d56fe5564dad671c20ad55b0237d5137a291edf56c455bd217f6340c2", + "byteLength": 1979 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json", + "path": "vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json", + "sha256": "0ea4f86f542fcfe5a183050daac17f5d43796995965096773ba7481c5ad93e4e", + "byteLength": 1523 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json", + "path": "vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json", + "sha256": "88efbe036d7386812662a46c154cf1521caf9864a9e676d35036038af754a81f", + "byteLength": 2317 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipvfuture-invalid-version.json", + "path": "vectors/documents/uri-ipvfuture-invalid-version.json", + "sha256": "399ba24e5ffb43360654f3c641fc002f61d8cb2f920eed0480808912bbccc2ed", + "byteLength": 1964 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipvfuture-lowercase-pack.json", + "path": "vectors/documents/uri-ipvfuture-lowercase-pack.json", + "sha256": "ebd7ca932ab1557442af46b391d5e1b980c9398a7213d4682a3308732be4cf5a", + "byteLength": 1504 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipvfuture-lowercase.json", + "path": "vectors/documents/uri-ipvfuture-lowercase.json", + "sha256": "13c1a9fff73cddc63b779e619a622cc05e6ffeb4d5eb2d544a43acfe80973bbd", + "byteLength": 2298 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipvfuture-uppercase-pack.json", + "path": "vectors/documents/uri-ipvfuture-uppercase-pack.json", + "sha256": "6992d4add7edc8a3dec0679b28dd58a4838d2cf5f218b4f702081583e9cb8c6b", + "byteLength": 1504 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-ipvfuture-uppercase.json", + "path": "vectors/documents/uri-ipvfuture-uppercase.json", + "sha256": "0ce1badc441db3a4290400dab23f2d8e5afee8fc0bf799abdb7cb01140e9ff10", + "byteLength": 2298 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-numeric-regname-leading-zeros.json", + "path": "vectors/documents/uri-numeric-regname-leading-zeros.json", + "sha256": "2ab9c70bc4c613fabe5bcbacd27ca79b73b08803e918f1755b3735ebcd96ca6f", + "byteLength": 1974 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-path-raw-brackets-pack.json", + "path": "vectors/documents/uri-path-raw-brackets-pack.json", + "sha256": "c0e3ef08c4644024d87d26ed4d77a5c14b1b7f46c8ca0a4b0ce7d8157ade7208", + "byteLength": 1518 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-path-raw-brackets.json", + "path": "vectors/documents/uri-path-raw-brackets.json", + "sha256": "b70d9a76a3b38f58a0f2b075c9ecfe6803b6e0a404c2b526000f85a86b244f67", + "byteLength": 2312 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-brackets.json", + "path": "vectors/documents/uri-percent-brackets.json", + "sha256": "52ed06084ad97c026b15ece99674e6d638d26509506b62ce3d5195da7acd5a63", + "byteLength": 1997 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-incomplete.json", + "path": "vectors/documents/uri-percent-incomplete.json", + "sha256": "f8db4efe5972393c15cd0c8ad8cbe88262ac02845d8863781cad83f970fa212b", + "byteLength": 1978 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-nonhex.json", + "path": "vectors/documents/uri-percent-nonhex.json", + "sha256": "4a239d1009d314a9a0e285848fb1eba211a5574e17907253936aa6820f98534b", + "byteLength": 1979 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-regname-pack.json", + "path": "vectors/documents/uri-percent-regname-pack.json", + "sha256": "50e9179933d3bab136e4872f25874e556cc9b1508410dd945ad564a2a3e90daa", + "byteLength": 1518 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-regname.json", + "path": "vectors/documents/uri-percent-regname.json", + "sha256": "86ea9309a59ba683a85c73442c2638d56aa21f2e9e4f020d3954b043ab7c5f06", + "byteLength": 2312 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-percent-unicode.json", + "path": "vectors/documents/uri-percent-unicode.json", + "sha256": "5f062c610d9c546cba55951e3f9921b0de142ac382dac7d4a00e69ba65cf890f", + "byteLength": 1981 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-query-raw-brackets.json", + "path": "vectors/documents/uri-query-raw-brackets.json", + "sha256": "8d24bd52b12805ba9c602f113ca47c0a1dd141fc35577c09e0581c033ee46e24", + "byteLength": 1981 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-raw-unicode.json", + "path": "vectors/documents/uri-raw-unicode.json", + "sha256": "15bf301598d90e8a1e001973df95a1cb04021e1cb7a4385bf3ca0ef8eecebf7a", + "byteLength": 1977 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-rootless-raw-brackets-pack.json", + "path": "vectors/documents/uri-rootless-raw-brackets-pack.json", + "sha256": "a2b8f1d350ac991ebfd9f94ce6e53e40d19485e1f8ec7baaeb91f2ba279418ca", + "byteLength": 1503 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-rootless-raw-brackets.json", + "path": "vectors/documents/uri-rootless-raw-brackets.json", + "sha256": "4143f4d8d6e9df42e8a8ab8e011b9404b719f4e400dcb25d360d2ac80ff2b39d", + "byteLength": 2297 + }, + { + "sourcePath": "rfcs/policy-companion-contract/vectors/documents/uri-userinfo-percent-brackets.json", + "path": "vectors/documents/uri-userinfo-percent-brackets.json", + "sha256": "85c63cc716e50e0020cd419f636caf824afbe22826df6abc135cc7433cf4253f", + "byteLength": 1992 + }, { "sourcePath": "rfcs/policy-companion-contract/vectors/manifest.json", "path": "vectors/manifest.json", - "sha256": "7681dfd18be6cb8a251095b67f69d6868693c34b3f68a6ee5e94ac06fdbfae30", - "byteLength": 185434 + "sha256": "953177df0e844ad78ebe145d21c9f1e760336eda4ed20247331493c44be8eedd", + "byteLength": 223417 }, { "sourcePath": "LICENSE", @@ -860,8 +1022,8 @@ { "sourcePath": "rfcs/0023-policy-companion.md", "path": "0023-policy-companion.md", - "sha256": "626e0422f29aaf69db6d3cb47ee3c3232acccf0f7b658d4fbe042c42d3be49ca", - "byteLength": 22215 + "sha256": "9ae28641c548fc541c3379179a6000b05619099382220abc7849ad503f37bb76", + "byteLength": 23233 } ] } diff --git a/internal/policy/candidate/vectors/README.md b/internal/policy/candidate/vectors/README.md index 92530bb0..cc2b7d40 100644 --- a/internal/policy/candidate/vectors/README.md +++ b/internal/policy/candidate/vectors/README.md @@ -73,6 +73,20 @@ spend the aggregate budget only once. Every role independently applies its size limit. Raw Core numeric extensions include fractional, exponent and unsafe integer literals; expected results distinguish optional canonical identity from raw pins. +The 20 additional URI vectors assert the candidate's scheme-bearing RFC 3986 `URI` +grammar in Policy IDs and consuming-Pack references. They cover complete-string assertion, percent-encoding, +IPv6/IPvFuture, registered names, Unicode and component-specific brackets. Their +expected results describe URI syntax, not URL fetching or a dependency's quirks; +valid query/fragment content remains supported. Original retained materials are +unchanged. The earlier 104 vectors retain their exact inputs and expectations. +Seven cases are complete adoptions whose consuming Pack ID and exact consumer +reference agree. Their retained Pack files change only the ID string token; +every other original Pack byte, including number literals and whitespace, remains +unchanged. Raw digest/length and optional canonical identity are refreshed for +those synthetic candidate bytes. Valid percent-encoded hosts and IPvFuture `v`/`V` +must pass the candidate's consuming-Pack structural checker as well as its +reference grammar; invalid brackets, final LF and leading-zero IPv4 tails refuse. + Run the reference harness with the repository's pinned dependencies: ```sh @@ -80,7 +94,7 @@ python rfcs/policy-companion-contract/check_vectors.py ``` Successful harness output is exactly -`{"status":"matched","cases":104,"maturity":"proposed-draft"}`; this is harness +`{"status":"matched","cases":124,"maturity":"proposed-draft"}`; this is harness agreement, not the result for an individual document or a conformance claim. Each refusal vector's exact output is retained in the manifest. The harness and schema are optional conveniences: another language can read these same bytes and the diff --git a/internal/policy/candidate/vectors/documents/uri-final-lf-pack.json b/internal/policy/candidate/vectors/documents/uri-final-lf-pack.json new file mode 100644 index 00000000..a588c5fb --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-final-lf-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "urn:test:x\n", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-final-lf.json b/internal/policy/candidate/vectors/documents/uri-final-lf.json new file mode 100644 index 00000000..ccc861b7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-final-lf.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "urn:test:x\n", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c418f413e2b19f32dcc2f46664717ff2eb81e940fca57315275d39e63037f495", + "byteLength": 1503, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:47f2a4f8ac55a8731d5599090cda8396f35520a21414f9af1f91777b3ebaf12f" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-fragment-raw-brackets.json b/internal/policy/candidate/vectors/documents/uri-fragment-raw-brackets.json new file mode 100644 index 00000000..57b42460 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-fragment-raw-brackets.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/#a[b]", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipv6-compressed.json b/internal/policy/candidate/vectors/documents/uri-ipv6-compressed.json new file mode 100644 index 00000000..68e5dc78 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipv6-compressed.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "http://[2001:db8::1]:8080/a", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipv6-double-compression.json b/internal/policy/candidate/vectors/documents/uri-ipv6-double-compression.json new file mode 100644 index 00000000..610c293d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipv6-double-compression.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "http://[2001::db8::1]/", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipv6-ipv4-tail.json b/internal/policy/candidate/vectors/documents/uri-ipv6-ipv4-tail.json new file mode 100644 index 00000000..6ed1cc25 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipv6-ipv4-tail.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "http://[::ffff:192.168.1.1]/", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json b/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json new file mode 100644 index 00000000..b725cf36 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "http://[::ffff:192.168.001.001]/", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json b/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json new file mode 100644 index 00000000..81c56210 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "http://[::ffff:192.168.001.001]/", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:0ea4f86f542fcfe5a183050daac17f5d43796995965096773ba7481c5ad93e4e", + "byteLength": 1523, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:9128ab46ba265f6e5dff041a4a7f423f803e0c6959879cc570e793609aae1996" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipvfuture-invalid-version.json b/internal/policy/candidate/vectors/documents/uri-ipvfuture-invalid-version.json new file mode 100644 index 00000000..6ae88b8d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipvfuture-invalid-version.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "foo://[vG.a]/", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase-pack.json b/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase-pack.json new file mode 100644 index 00000000..480c266c --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "foo://[v1.a]/", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase.json b/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase.json new file mode 100644 index 00000000..aa46e52f --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipvfuture-lowercase.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "foo://[v1.a]/", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:ebd7ca932ab1557442af46b391d5e1b980c9398a7213d4682a3308732be4cf5a", + "byteLength": 1504, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:a0cf145d4d18c2e0259968b41186fb6c241be660e07c7fde7dabf7db304fa140" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase-pack.json b/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase-pack.json new file mode 100644 index 00000000..2f10f621 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "foo://[V1.a]/", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase.json b/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase.json new file mode 100644 index 00000000..fafba2b7 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-ipvfuture-uppercase.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "foo://[V1.a]/", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6992d4add7edc8a3dec0679b28dd58a4838d2cf5f218b4f702081583e9cb8c6b", + "byteLength": 1504, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:c794e18a50ee3b6cc076841ba1f03bbbcbfa7d91f3428aaef9a5b9004967bf21" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-numeric-regname-leading-zeros.json b/internal/policy/candidate/vectors/documents/uri-numeric-regname-leading-zeros.json new file mode 100644 index 00000000..63428d67 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-numeric-regname-leading-zeros.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "http://192.168.001.001/", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-path-raw-brackets-pack.json b/internal/policy/candidate/vectors/documents/uri-path-raw-brackets-pack.json new file mode 100644 index 00000000..23f8928d --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-path-raw-brackets-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://example.invalid/[x]", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-path-raw-brackets.json b/internal/policy/candidate/vectors/documents/uri-path-raw-brackets.json new file mode 100644 index 00000000..92153d8f --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-path-raw-brackets.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://example.invalid/[x]", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:c0e3ef08c4644024d87d26ed4d77a5c14b1b7f46c8ca0a4b0ce7d8157ade7208", + "byteLength": 1518, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:10c3750e1583b45caa9a57baa8ffaa4dc2c091651aa1f725fc6618f47bc6425f" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-brackets.json b/internal/policy/candidate/vectors/documents/uri-percent-brackets.json new file mode 100644 index 00000000..718dff40 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-brackets.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "foo://%5Bname%5D/%5Bpath%5D?b=%5Bc%5D#a%5Bb%5D", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-incomplete.json b/internal/policy/candidate/vectors/documents/uri-percent-incomplete.json new file mode 100644 index 00000000..5df792a4 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-incomplete.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/a%2", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-nonhex.json b/internal/policy/candidate/vectors/documents/uri-percent-nonhex.json new file mode 100644 index 00000000..b2d545d3 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-nonhex.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/a%GG", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-regname-pack.json b/internal/policy/candidate/vectors/documents/uri-percent-regname-pack.json new file mode 100644 index 00000000..7f592366 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-regname-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "https://%65xample.invalid/a", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-regname.json b/internal/policy/candidate/vectors/documents/uri-percent-regname.json new file mode 100644 index 00000000..a0bca651 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-regname.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "https://%65xample.invalid/a", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:50e9179933d3bab136e4872f25874e556cc9b1508410dd945ad564a2a3e90daa", + "byteLength": 1518, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:a638315c0dde2052fb78f3b2282e74f970c1e292221213339817856caadde3ed" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-percent-unicode.json b/internal/policy/candidate/vectors/documents/uri-percent-unicode.json new file mode 100644 index 00000000..20d60f6c --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-percent-unicode.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/%C3%A9", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-query-raw-brackets.json b/internal/policy/candidate/vectors/documents/uri-query-raw-brackets.json new file mode 100644 index 00000000..ac7c5b63 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-query-raw-brackets.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/?b=[c]", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-raw-unicode.json b/internal/policy/candidate/vectors/documents/uri-raw-unicode.json new file mode 100644 index 00000000..9d4e50da --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-raw-unicode.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "https://example.invalid/é", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets-pack.json b/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets-pack.json new file mode 100644 index 00000000..a228f764 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets-pack.json @@ -0,0 +1,62 @@ +{ + "specVersion": "0.2.0-draft", + "id": "urn:test:[x]", + "version": "1.0.0", + "title": "Data access — synthetic interpretation", + "description": "Synthetic RFC material only. No operational authorization or external action.", + "decision": { + "intent": "Apply the retained automated eligibility clause.", + "question": "Is this request eligible for the automated path?" + }, + "outcomes": [ + { + "id": "eligible", + "label": "Eligible for review" + }, + { + "id": "ineligible", + "label": "Ineligible" + }, + { + "id": "review", + "label": "Human review needed" + } + ], + "rules": [ + { + "id": "eligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": true + }, + "outcome": "eligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + }, + { + "id": "ineligible", + "when": { + "op": "fact", + "path": "/dataset/deidentified", + "operator": "equals", + "value": false + }, + "outcome": "ineligible", + "onUnknown": "escalate", + "description": "Synthetic interpretation of the retained automated eligibility clause." + } + ], + "fallbackOutcome": "review", + "escalation": { + "triggers": [ + "unknown", + "no-match" + ], + "target": { + "kind": "human-role", + "name": "Synthetic reviewer" + } + } +} diff --git a/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets.json b/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets.json new file mode 100644 index 00000000..683f091f --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-rootless-raw-brackets.json @@ -0,0 +1,75 @@ +{ + "formatVersion": "1.0.0", + "kind": "governing-adoption", + "id": "https://example.invalid/policy-companion-contract/data-access/adoption", + "version": "1.0.0", + "consumer": { + "kind": "pack", + "id": "urn:test:[x]", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:a2b8f1d350ac991ebfd9f94ce6e53e40d19485e1f8ec7baaeb91f2ba279418ca", + "byteLength": 1503, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:3b4c17543d6b4fd14d6e28b206387dc989cc3a849626cd9bd84c17dabc1dda65" + } + }, + "governingPolicies": [ + { + "policy": { + "kind": "policy", + "id": "https://example.invalid/policy-companion-contract/data-access/policy", + "version": "1.0.0", + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + }, + "canonicalIdentity": { + "profile": "jps-canon", + "canonicalDigest": "sha256:8e9de4d2824a3186354e4ab410f4b0c744afa452796ce089bc0461adee63bce5" + } + }, + "scope": { + "kind": "whole-policy" + }, + "coverage": [ + { + "sectionId": "eligibility", + "status": "implemented", + "consumerElements": [ + { + "kind": "rule", + "id": "eligible" + }, + { + "kind": "rule", + "id": "ineligible" + }, + { + "kind": "fallback" + } + ], + "reviewBasis": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "sectionId": "exception-review", + "status": "manual", + "handoff": "Fictional specialist uses the documented manual review queue; this statement grants no role or access." + }, + { + "sectionId": "audit-review", + "status": "awaiting-implementation", + "explanation": "Synthetic open work item: develop and review a separate implementation." + } + ] + } + ] +} diff --git a/internal/policy/candidate/vectors/documents/uri-userinfo-percent-brackets.json b/internal/policy/candidate/vectors/documents/uri-userinfo-percent-brackets.json new file mode 100644 index 00000000..33f41f31 --- /dev/null +++ b/internal/policy/candidate/vectors/documents/uri-userinfo-percent-brackets.json @@ -0,0 +1,76 @@ +{ + "formatVersion": "1.0.0", + "kind": "policy", + "id": "foo://u%5Bser%5D:p%40ss@example.invalid/a", + "version": "1.0.0", + "title": "Data access — synthetic policy content", + "managementMode": "workspace-managed", + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + }, + "sections": [ + { + "id": "eligibility", + "title": "Automated release", + "anchor": { + "startByte": 41, + "endByte": 215, + "bytesDigest": "sha256:95eac1de35b93fdd947821f9336f8441a4ae4ffd69473e4ee332951b150c3896" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 1" + } + ] + }, + { + "id": "exception-review", + "title": "Restricted requests", + "anchor": { + "startByte": 215, + "endByte": 351, + "bytesDigest": "sha256:d2f664a5c4e515f11a5e05c0a2be36d4de7600b0b2d4f33f81dfafed55b441e8" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 2" + } + ] + }, + { + "id": "audit-review", + "title": "Quarterly audit", + "anchor": { + "startByte": 351, + "endByte": 449, + "bytesDigest": "sha256:7f4e8c2f9f2a9ad8f3276c6610f9e9a140833edfd9b46dbf825a1638ab8b6a6e" + }, + "sourceRefs": [ + { + "sourceId": "retained-original", + "location": "Clause 3" + } + ] + } + ], + "sourceProvenance": [ + { + "id": "retained-original", + "source": { + "provider": "synthetic-fixture", + "accountId": "fictional-organization", + "resourceId": "data-access-original" + }, + "sourceRevision": null, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + } + ] +} diff --git a/internal/policy/candidate/vectors/manifest.json b/internal/policy/candidate/vectors/manifest.json index db8047fc..a802df4f 100644 --- a/internal/policy/candidate/vectors/manifest.json +++ b/internal/policy/candidate/vectors/manifest.json @@ -6192,6 +6192,1255 @@ "status": "refused", "code": "invalid-carrier" } + }, + { + "id": "uri-final-lf", + "document": { + "path": "vectors/documents/uri-final-lf.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-final-lf-pack.json" + }, + "content": { + "bytesDigest": "sha256:c418f413e2b19f32dcc2f46664717ff2eb81e940fca57315275d39e63037f495", + "byteLength": 1503, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-ipv6-leading-zero-ipv4-tail", + "document": { + "path": "vectors/documents/uri-ipv6-leading-zero-ipv4-tail.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-ipv6-leading-zero-ipv4-tail-pack.json" + }, + "content": { + "bytesDigest": "sha256:0ea4f86f542fcfe5a183050daac17f5d43796995965096773ba7481c5ad93e4e", + "byteLength": 1523, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-raw-unicode", + "document": { + "path": "vectors/documents/uri-raw-unicode.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-percent-unicode", + "document": { + "path": "vectors/documents/uri-percent-unicode.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-percent-incomplete", + "document": { + "path": "vectors/documents/uri-percent-incomplete.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-percent-nonhex", + "document": { + "path": "vectors/documents/uri-percent-nonhex.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-ipv6-compressed", + "document": { + "path": "vectors/documents/uri-ipv6-compressed.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-ipv6-ipv4-tail", + "document": { + "path": "vectors/documents/uri-ipv6-ipv4-tail.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-ipv6-double-compression", + "document": { + "path": "vectors/documents/uri-ipv6-double-compression.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-ipvfuture-lowercase", + "document": { + "path": "vectors/documents/uri-ipvfuture-lowercase.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-ipvfuture-lowercase-pack.json" + }, + "content": { + "bytesDigest": "sha256:ebd7ca932ab1557442af46b391d5e1b980c9398a7213d4682a3308732be4cf5a", + "byteLength": 1504, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-ipvfuture-uppercase", + "document": { + "path": "vectors/documents/uri-ipvfuture-uppercase.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-ipvfuture-uppercase-pack.json" + }, + "content": { + "bytesDigest": "sha256:6992d4add7edc8a3dec0679b28dd58a4838d2cf5f218b4f702081583e9cb8c6b", + "byteLength": 1504, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-ipvfuture-invalid-version", + "document": { + "path": "vectors/documents/uri-ipvfuture-invalid-version.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-percent-regname", + "document": { + "path": "vectors/documents/uri-percent-regname.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-percent-regname-pack.json" + }, + "content": { + "bytesDigest": "sha256:50e9179933d3bab136e4872f25874e556cc9b1508410dd945ad564a2a3e90daa", + "byteLength": 1518, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-userinfo-percent-brackets", + "document": { + "path": "vectors/documents/uri-userinfo-percent-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-percent-brackets", + "document": { + "path": "vectors/documents/uri-percent-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } + }, + { + "id": "uri-rootless-raw-brackets", + "document": { + "path": "vectors/documents/uri-rootless-raw-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-rootless-raw-brackets-pack.json" + }, + "content": { + "bytesDigest": "sha256:a2b8f1d350ac991ebfd9f94ce6e53e40d19485e1f8ec7baaeb91f2ba279418ca", + "byteLength": 1503, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-path-raw-brackets", + "document": { + "path": "vectors/documents/uri-path-raw-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "vectors/documents/uri-path-raw-brackets-pack.json" + }, + "content": { + "bytesDigest": "sha256:c0e3ef08c4644024d87d26ed4d77a5c14b1b7f46c8ca0a4b0ce7d8157ade7208", + "byteLength": 1518, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-query-raw-brackets", + "document": { + "path": "vectors/documents/uri-query-raw-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-fragment-raw-brackets", + "document": { + "path": "vectors/documents/uri-fragment-raw-brackets.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "refused", + "code": "invalid-document" + } + }, + { + "id": "uri-numeric-regname-leading-zeros", + "document": { + "path": "vectors/documents/uri-numeric-regname-leading-zeros.json" + }, + "materials": [ + { + "source": { + "path": "examples/data-access/narrative.txt" + }, + "content": { + "bytesDigest": "sha256:801a0d0969c0ffe5b95d12bbdc593c823a995ea28ccdb894b0beb7de370ba172", + "byteLength": 449, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/source.txt" + }, + "content": { + "bytesDigest": "sha256:9a4f335306e2a8e4fbcf73f5a5bad14f45369fa22985756181eeb8ea1ee217dd", + "byteLength": 433, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/interpretation.txt" + }, + "content": { + "bytesDigest": "sha256:7c649cafae58eb11498332c03a107be64fb7d72fcbedebe2c5da32aa801d55f8", + "byteLength": 262, + "mediaType": "text/plain" + } + }, + { + "source": { + "path": "examples/data-access/consumer-pack.json" + }, + "content": { + "bytesDigest": "sha256:c4912216ef58c754473bdda95be7322126ab2970bd75bea9306f342927d974e4", + "byteLength": 1558, + "mediaType": "application/json" + } + }, + { + "source": { + "path": "examples/data-access/policy.json" + }, + "content": { + "bytesDigest": "sha256:6abbd1b965ff006e210b8a98c4a8db6eb0bb795c1f8a995d3be343aa1a984f51", + "byteLength": 2019, + "mediaType": "application/json" + } + } + ], + "expected": { + "status": "valid", + "formatVersion": "1.0.0", + "maturity": "proposed-draft" + } } ] } diff --git a/internal/policy/candidate_review_test.go b/internal/policy/candidate_review_test.go index 1a5fd684..6d191cbd 100644 --- a/internal/policy/candidate_review_test.go +++ b/internal/policy/candidate_review_test.go @@ -9,6 +9,7 @@ import ( "github.com/Judgment-Pack/judgment-pack-runtime/internal/result" "github.com/Judgment-Pack/judgment-pack-runtime/internal/validation" + "github.com/santhosh-tekuri/jsonschema/v6" ) func TestCandidateURIFormatAgreementAndInitSchemaParity(t *testing.T) { @@ -150,3 +151,18 @@ func TestCandidatePrivateWireRegistrationPhaseOrdering(t *testing.T) { }) } } + +func TestCandidateURIAssertionDoesNotAddCoreLengthBounds(t *testing.T) { + f := candidateFixture(t, "refunds") + id := "urn:test:" + strings.Repeat("a", 3000) + pack := bytes.Replace(f.raw["consumer-pack.json"], mustJSON(t, object(f.adoption["consumer"])["id"]), mustJSON(t, id), 1) + options := validation.Options{Through: "structural", Limits: limits(), FormatOverrides: []*jsonschema.Format{candidateURIFormat()}} + if report, failure := engine(t).Validate(pack, options); failure != nil || report.Status != "valid" { + t.Fatalf("URI assertion imposed a companion bound on Core %+v %v", report, failure) + } + // The companion schema remains the owner of its separate URI character cap. + f.policy["id"] = id + if report, exit := Validate("validate", mustJSON(t, f.policy)); exit != result.ExitUnsupported || report.refusalCode != "input-over-bound" { + t.Fatalf("companion URI bound missing %+v %d", report, exit) + } +} diff --git a/internal/policy/candidate_test.go b/internal/policy/candidate_test.go index f0fa0514..0bfdca38 100644 --- a/internal/policy/candidate_test.go +++ b/internal/policy/candidate_test.go @@ -63,7 +63,7 @@ func TestCandidatePortableVectors(t *testing.T) { } manifest := object(value) cases := array(manifest["cases"]) - if len(cases) != 104 { + if len(cases) != 124 { t.Fatalf("unexpected vector count %d", len(cases)) } for _, value := range cases { @@ -111,7 +111,7 @@ func TestCandidatePortableVectors(t *testing.T) { func TestCandidateProvenance(t *testing.T) { raw := candidateRead(t, "provenance.json") - if digest(raw) != "sha256:eb2644703944bd550f954dac3d51124d611867b54465ed1b0f6541018bdfba21" { + if digest(raw) != "sha256:f21466b49e2eb95c33f6e97bef74203a2e2255737476be27e72e3c43fc01f971" { t.Fatal("candidate manifest pin changed") } manifest := mustMap(t, raw) diff --git a/internal/policy/format.go b/internal/policy/format.go index ab6470a1..bdb3fa11 100644 --- a/internal/policy/format.go +++ b/internal/policy/format.go @@ -11,7 +11,7 @@ import ( ) const CandidateVersion = "1.0.0" -const CandidateRevision = "4406cec9714ab9bc8e8971237cc79d58682cc904" +const CandidateRevision = "0852c5fa7726e51b36e574a5b110e7f5e012e03d" const CandidateURL = "https://github.com/Judgment-Pack/judgment-pack-spec/blob/" + CandidateRevision + "/rfcs/policy-companion-contract/README.md" type formatDescriptor struct { From 55a23b884f0ce67fe6a9141b04e081a518fd5d61 Mon Sep 17 00:00:00 2001 From: kikashy Date: Sun, 18 Oct 2026 16:50:25 -0400 Subject: [PATCH 6/6] Record final Policy candidate review closure links Record the three resolved Runtime P2 findings and the completed review of the exact URI-corrected Spec source. The source remains pinned to reviewed 0852c5f, with RFC Review status and no normative adoption or independent-vendor claim. This documentation-only follow-up preserves the production and vendored bytes of 65ff571 for the already-started CI and final delta review. Co-authored-by: Codex (gpt-6.1-sol) Signed-off-by: kikashy --- docs/adr/0060-explicit-policy-candidate-format.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/adr/0060-explicit-policy-candidate-format.md b/docs/adr/0060-explicit-policy-candidate-format.md index 2e4a1820..af0bc560 100644 --- a/docs/adr/0060-explicit-policy-candidate-format.md +++ b/docs/adr/0060-explicit-policy-candidate-format.md @@ -107,15 +107,20 @@ Commits `6dd003e29cccf7808227b98157e55cebce4b231b` and including candidate-consuming Pack URI checks over unchanged bytes and schema. The coordinator reports that the reviewer closed both findings at `2e158c5`. Commit `38b06043283d2ae294653ca8f25c8c5db415dd9e` additionally preserves the -vendored candidate's exact bytes under Windows checkout conversion. Focused +vendored candidate's exact bytes under Windows checkout conversion, addressing +the third P2 finding. The [final Runtime correction review](https://github.com/Judgment-Pack/judgment-pack-runtime/pull/296#issuecomment-6254971185) +closes all three findings through that commit. Focused verification covers the 124 portable vectors, 62 standalone and 62 consuming Pack URI probes, ordered private-wire refusals, schema/init parity and unchanged Core/prototype URI behavior. Checkout verification with `core.autocrlf=true` checks every vendored source digest/length and the independent provenance pin. The URI source correction is pinned to the exact candidate commit above and is -tracked in [Spec PR 217](https://github.com/Judgment-Pack/judgment-pack-spec/pull/217). -The maintainer requires that source review and repository CI before Runtime merge. This +recorded in [Spec PR 217's clean-room review](https://github.com/Judgment-Pack/judgment-pack-spec/pull/217#issuecomment-6254970472). +That exact `0852c5f` source passed review without P1/P2 findings, 13 focused +tests, 124 portable vectors and 99 additional URI probes, and merged as +`a74a440cfc31d0e135cdc8035f3474b17f27f320` after repository CI passed. Runtime +retains the immutable reviewed source pin; its merge also requires repository CI. This accepted status records the maintainer-authorized merge-ready procedural transition; it does not adopt a normative Policy format or change the RFC's Review status. All implementation, review and agreement evidence described here