From 20fd91195f9ad1a758ed04c63f14ad141a56ea1e Mon Sep 17 00:00:00 2001 From: snapsynapse <57973674+snapsynapse@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:08:36 -0600 Subject: [PATCH 1/4] Add opt-in corrected content profile with frozen compatibility replays --- .github/workflows/test.yml | 8 +- CHANGELOG.md | 11 + INTENT.md | 10 + Makefile | 12 +- api/verify.py | 8 +- assistant-guide-manifest.txt | 11 + docs/corrected-content-policy-2026-09-07.md | 239 ++++ ...corrected-content-validation-2026-09-07.md | 85 ++ docs/verify/verify.js | 11 +- finding-ids.md | 1 + .../compatibility/strict-1.0.0-baseline.json | 706 ++++++++++ .../anchors/dns-txt.txt | 1 + .../corrected-affirmative-crlf/expected.json | 11 + .../corrected-affirmative-crlf/guide.txt | 92 ++ .../corrected-affirmative-crlf/manifest.txt | 9 + .../anchors/dns-txt.txt | 1 + .../expected.json | 10 + .../guide.txt | 92 ++ .../manifest.txt | 9 + .../anchors/dns-txt.txt | 1 + .../corrected-bound-unpinned/expected.json | 9 + .../2.0.0/corrected-bound-unpinned/guide.txt | 90 ++ .../corrected-bound-unpinned/manifest.txt | 9 + .../anchors/dns-txt.txt | 1 + .../corrected-safe-negation/expected.json | 7 + .../2.0.0/corrected-safe-negation/guide.txt | 92 ++ .../corrected-safe-negation/manifest.txt | 9 + .../anchors/dns-txt.txt | 1 + .../corrected-unresolved-exec/expected.json | 10 + .../2.0.0/corrected-unresolved-exec/guide.txt | 90 ++ .../corrected-unresolved-exec/manifest.txt | 9 + .../2.0.0/dns-only/anchors/dns-txt.txt | 1 + .../profiles/2.0.0/dns-only/expected.json | 7 + fixtures/profiles/2.0.0/dns-only/guide.txt | 90 ++ fixtures/profiles/2.0.0/dns-only/manifest.txt | 9 + .../local-consistency/anchors/dns-txt.txt | 1 + .../anchors/repository-file.txt | 90 ++ .../2.0.0/local-consistency/expected.json | 11 + .../2.0.0/local-consistency/guide.txt | 90 ++ .../2.0.0/local-consistency/manifest.txt | 9 + .../anchors/dns-txt.txt | 1 + .../manifest-profile-mismatch/expected.json | 9 + .../2.0.0/manifest-profile-mismatch/guide.txt | 90 ++ .../manifest-profile-mismatch/manifest.txt | 9 + .../repository-and-dns/anchors/dns-txt.txt | 1 + .../anchors/repository-file.txt | 90 ++ .../2.0.0/repository-and-dns/expected.json | 9 + .../2.0.0/repository-and-dns/guide.txt | 90 ++ .../2.0.0/repository-and-dns/manifest.txt | 9 + .../repository-conflict/anchors/dns-txt.txt | 1 + .../anchors/repository-file.txt | 90 ++ .../2.0.0/repository-conflict/expected.json | 11 + .../2.0.0/repository-conflict/guide.txt | 90 ++ .../2.0.0/repository-conflict/manifest.txt | 9 + .../anchors/repository-file.txt | 90 ++ .../2.0.0/repository-only/expected.json | 11 + .../profiles/2.0.0/repository-only/guide.txt | 90 ++ .../2.0.0/repository-only/manifest.txt | 9 + profiles/2.0.0/example-report.json | 101 ++ profiles/2.0.0/spec.md | 1154 +++++++++++++++++ profiles/2.0.0/verifier-conformance.md | 805 ++++++++++++ pyproject.toml | 1 + roadmap.md | 11 +- schemas/2.0.0/fixture-expected.schema.json | 15 + schemas/2.0.0/manifest.schema.json | 73 ++ schemas/2.0.0/verifier-output.schema.json | 421 ++++++ scripts/build_public_contracts.py | 4 +- scripts/check_version_sync.py | 8 +- scripts/guidecheck_constants.py | 1 + scripts/guidecheck_corrected.py | 648 +++++++++ scripts/guidecheck_profiles.py | 15 +- scripts/guidecheck_verify.py | 16 +- scripts/test_corrected_content.py | 213 +++ scripts/test_package_consumer.py | 74 ++ scripts/test_profile_dispatch.py | 99 +- scripts/test_strict_compatibility.py | 70 + scripts/test_verify_ui.mjs | 15 +- scripts/validate_contracts.py | 3 + 78 files changed, 6382 insertions(+), 37 deletions(-) create mode 100644 assistant-guide-manifest.txt create mode 100644 docs/corrected-content-policy-2026-09-07.md create mode 100644 docs/corrected-content-validation-2026-09-07.md create mode 100644 fixtures/compatibility/strict-1.0.0-baseline.json create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-crlf/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-crlf/expected.json create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-crlf/guide.txt create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-crlf/manifest.txt create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-prohibited/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-prohibited/expected.json create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-prohibited/guide.txt create mode 100644 fixtures/profiles/2.0.0/corrected-affirmative-prohibited/manifest.txt create mode 100644 fixtures/profiles/2.0.0/corrected-bound-unpinned/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/corrected-bound-unpinned/expected.json create mode 100644 fixtures/profiles/2.0.0/corrected-bound-unpinned/guide.txt create mode 100644 fixtures/profiles/2.0.0/corrected-bound-unpinned/manifest.txt create mode 100644 fixtures/profiles/2.0.0/corrected-safe-negation/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/corrected-safe-negation/expected.json create mode 100644 fixtures/profiles/2.0.0/corrected-safe-negation/guide.txt create mode 100644 fixtures/profiles/2.0.0/corrected-safe-negation/manifest.txt create mode 100644 fixtures/profiles/2.0.0/corrected-unresolved-exec/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/corrected-unresolved-exec/expected.json create mode 100644 fixtures/profiles/2.0.0/corrected-unresolved-exec/guide.txt create mode 100644 fixtures/profiles/2.0.0/corrected-unresolved-exec/manifest.txt create mode 100644 fixtures/profiles/2.0.0/dns-only/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/dns-only/expected.json create mode 100644 fixtures/profiles/2.0.0/dns-only/guide.txt create mode 100644 fixtures/profiles/2.0.0/dns-only/manifest.txt create mode 100644 fixtures/profiles/2.0.0/local-consistency/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/local-consistency/anchors/repository-file.txt create mode 100644 fixtures/profiles/2.0.0/local-consistency/expected.json create mode 100644 fixtures/profiles/2.0.0/local-consistency/guide.txt create mode 100644 fixtures/profiles/2.0.0/local-consistency/manifest.txt create mode 100644 fixtures/profiles/2.0.0/manifest-profile-mismatch/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/manifest-profile-mismatch/expected.json create mode 100644 fixtures/profiles/2.0.0/manifest-profile-mismatch/guide.txt create mode 100644 fixtures/profiles/2.0.0/manifest-profile-mismatch/manifest.txt create mode 100644 fixtures/profiles/2.0.0/repository-and-dns/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/repository-and-dns/anchors/repository-file.txt create mode 100644 fixtures/profiles/2.0.0/repository-and-dns/expected.json create mode 100644 fixtures/profiles/2.0.0/repository-and-dns/guide.txt create mode 100644 fixtures/profiles/2.0.0/repository-and-dns/manifest.txt create mode 100644 fixtures/profiles/2.0.0/repository-conflict/anchors/dns-txt.txt create mode 100644 fixtures/profiles/2.0.0/repository-conflict/anchors/repository-file.txt create mode 100644 fixtures/profiles/2.0.0/repository-conflict/expected.json create mode 100644 fixtures/profiles/2.0.0/repository-conflict/guide.txt create mode 100644 fixtures/profiles/2.0.0/repository-conflict/manifest.txt create mode 100644 fixtures/profiles/2.0.0/repository-only/anchors/repository-file.txt create mode 100644 fixtures/profiles/2.0.0/repository-only/expected.json create mode 100644 fixtures/profiles/2.0.0/repository-only/guide.txt create mode 100644 fixtures/profiles/2.0.0/repository-only/manifest.txt create mode 100644 profiles/2.0.0/example-report.json create mode 100644 profiles/2.0.0/spec.md create mode 100644 profiles/2.0.0/verifier-conformance.md create mode 100644 schemas/2.0.0/fixture-expected.schema.json create mode 100644 schemas/2.0.0/manifest.schema.json create mode 100644 schemas/2.0.0/verifier-output.schema.json create mode 100644 scripts/guidecheck_corrected.py create mode 100644 scripts/test_corrected_content.py create mode 100644 scripts/test_package_consumer.py create mode 100644 scripts/test_strict_compatibility.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f0ff7bc..8e3cfc1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,10 @@ permissions: jobs: test: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: ["3.10", "3.12"] steps: - name: Check out repository uses: actions/checkout@v4 @@ -19,9 +23,11 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: ${{ matrix.python }} - name: Run local verification suite run: | make test test-verify-ui python3 scripts/build_public_contracts.py + - name: Verify installed wheel outside the checkout + run: python3 scripts/test_package_consumer.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 8644c76..b9e7ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to GuideCheck's Human-Verifiable Assistant Guide profile and ## [Unreleased] +- Include the corrected evaluator in the installable wheel and exercise legacy, + strict, corrected, and scanner dispatch from an isolated installed consumer in CI. + +- Add the root assistant-guide manifest and enforce byte equality with the + served copy, preserving published self-guide and manifest bytes. +- Add a local, unreleased 2.0.0 profile candidate selected only by guide bytes. + It corrects bounded negation and independent occurrence matching, blocks + unresolved execution targets, recognizes syntax-proven repository dispatch, + and inherits the released 1.0.0 strict anchor policy without changing legacy + or 1.0.0 reports. + ## [1.0.0] - 2026-09-05 ### Added diff --git a/INTENT.md b/INTENT.md index fe6e098..38fda60 100644 --- a/INTENT.md +++ b/INTENT.md @@ -79,6 +79,14 @@ GuideCheck is a PAICE Foundation standard. It sits alongside the other open-spec The current profile is declared in `profiles/1.0.0/spec.md` and tracked in `CHANGELOG.md`. The current version is 1.0.0, released. Root normative documents preserve the legacy contract; the self-guide remains pinned to 0.7.1. The version is asserted by `scripts/check_version_sync.py` against `scripts/guidecheck_constants.py` against independently pinned release, engine, and self-guide identities, so the status here and the released tag cannot silently disagree. `spec.md` and `verifier-conformance.md` are normative. `design-rationale.md` and `threat-register.md` are explanatory and must stay consistent with the normative documents. `archive/` is historical and is not edited. +## Corrected content checks + +Decided by Sam on 2026-09-07: preserve frozen legacy reports and add an explicitly selected corrected evaluation path. The September 7 detector review reproduced negation false positives, affirmative-instruction false negatives, and unpinned script-dispatch gaps. These are maintenance of existing content-check obligations, not authority to silently alter a published evaluation contract. + +Existing supported profile behavior, findings, levels, report identity, and exit semantics remain frozen. The corrected path must have an explicit selection and distinguishable policy identity; its precise selector, version, normative changes, and migration design remain to be proposed under the admission criteria above. This decision does not automatically revise the released strict 1.0.0 policy, which reuses legacy content checks. Implementation, release, and hosted acceptance are not completed by this decision. + +Sam also decided on 2026-09-07 that an unresolved execution target blocks Level 3 acceptance on the corrected path. The guide must establish the effective target and satisfy the applicable pinning contract. A declared hash alone cannot resolve an unidentified target. This requirement does not change any released legacy or 1.0.0 evaluation. + ## Maintenance and demand gate The June 9 disposition parked new product investment while maintaining existing @@ -90,6 +98,8 @@ standard scope or authorize a cross-standard certification product. The Septembe ## Changelog +- 2026-09-07: Sam selected blocking unresolved execution targets for Level 3 on the opt-in corrected path; released evaluations remain frozen. +- 2026-09-07: Sam selected preservation of frozen legacy reports with opt-in corrected content checks. Recorded the decision and remaining selector/version design scope; evaluator and published profiles remain unchanged. - 2026-09-05: Sam approved the version-aware anchor proposal with legacy compatibility required. The local 1.0.0 candidate excludes repository-file evidence from independent qualification, while the dispatcher preserves supported legacy evaluations and published self-guide bytes. Release and deployment remain separate. See `docs/anchor-policy-compatibility.md` and `docs/anchor-dispatch-validation.md`. - 2026-07-31: Opened the canonical approval receipt as a live open question, prompted by an external question about binding approval to the exact executing action. Detail in `roadmap.md`; the identity fork (field in the record versus signer over it) is the first thing to resolve, gated behind Level 5 fixture-suite design. diff --git a/Makefile b/Makefile index 00998c6..e67b9d5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,11 @@ -.PHONY: test-verify-ui test-legacy-anchor-compatibility test-bounded-execution eval verify-fixtures validate-contracts test-contract-schema-validation test-parser-edge-cases check-guide-artifacts check-version-sync test-fetch-safety test-hosted-anchors test-hosted-api test-fetch-replay test-cli-contract test-scanner test release-archive conformance-kit +.PHONY: test-verify-ui test-legacy-anchor-compatibility test-bounded-execution test-corrected-content eval verify-fixtures validate-contracts test-contract-schema-validation test-parser-edge-cases check-guide-artifacts check-version-sync test-fetch-safety test-hosted-anchors test-hosted-api test-fetch-replay test-cli-contract test-scanner test release-archive conformance-kit VERSION := $(shell python3 -c "import sys; sys.path.insert(0, 'scripts'); from guidecheck_constants import GUIDECHECK_VERSION; print(GUIDECHECK_VERSION)") +.PHONY: test-package-consumer +test-package-consumer: + python3 scripts/test_package_consumer.py + eval: python3 scripts/eval_guidecheck.py @@ -44,16 +48,20 @@ test-scanner: test-bounded-execution: python3 scripts/test_bounded_execution.py +test-corrected-content: + python3 scripts/test_corrected_content.py + test-legacy-anchor-compatibility: python3 scripts/test_legacy_anchor_compatibility.py python3 scripts/test_dispatch_compatibility.py + python3 scripts/test_strict_compatibility.py python3 scripts/test_profile_dispatch.py # Keep the established Python-only test entry point usable without Node. test-verify-ui: node scripts/test_verify_ui.mjs -test: test-legacy-anchor-compatibility test-bounded-execution eval verify-fixtures validate-contracts test-contract-schema-validation test-parser-edge-cases check-guide-artifacts check-version-sync test-fetch-safety test-hosted-anchors test-hosted-api test-fetch-replay test-cli-contract test-scanner +test: test-legacy-anchor-compatibility test-bounded-execution test-corrected-content eval verify-fixtures validate-contracts test-contract-schema-validation test-parser-edge-cases check-guide-artifacts check-version-sync test-fetch-safety test-hosted-anchors test-hosted-api test-fetch-replay test-cli-contract test-scanner # Full source archive for a GitHub release, matching prior build/ layout. release-archive: diff --git a/api/verify.py b/api/verify.py index ac77e2e..48a26c2 100644 --- a/api/verify.py +++ b/api/verify.py @@ -43,6 +43,7 @@ import guidecheck_verify as gv # noqa: E402 from guidecheck_profiles import ProfileError, select_profile # noqa: E402 from guidecheck_strict import decorate_report # noqa: E402 +from guidecheck_corrected import decorate_report as decorate_corrected_report # noqa: E402 from guidecheck_constants import GUIDECHECK_VERSION, HOSTED_VERIFIER_NAME, LEGACY_ENGINE_VERSION # noqa: E402 from guidecheck_fetch import FetchError, safe_fetch, variation_request_profile # noqa: E402 from guidecheck_hosted_anchors import ( # noqa: E402 @@ -738,10 +739,13 @@ def build_evaluated( if note: result["location_note"] = note result["compact_report"] = _compact_report(result) - if selection is not None and selection.strict: + if selection is not None and selection.modern: for anchor in result.get("cross_channel_anchors", []): anchor.update((anchor_sources or {}).get(anchor["channel"] + " anchor", {})) - decorate_report(result, selection) + if selection.corrected: + decorate_corrected_report(result, selection) + else: + decorate_report(result, selection) return result diff --git a/assistant-guide-manifest.txt b/assistant-guide-manifest.txt new file mode 100644 index 0000000..b72efd4 --- /dev/null +++ b/assistant-guide-manifest.txt @@ -0,0 +1,11 @@ +guide-path: /.well-known/assistant-guide.txt +guide-version: 0.7.1 +guide-sha256: 4b30202c809a3db037290371da8fed6a9681255199e0e19cfe1a0a7fc1d5df9e +guide-bytes: 8065 +immutable-release-url: https://github.com/snapsynapse/guidecheck/releases/tag/v0.7.1 +profile: human-verifiable-assistant-guide +profile-version: 0.7.1 +canonical-url: https://guidecheck.org/.well-known/assistant-guide.txt +repository-url: https://github.com/snapsynapse/guidecheck +released-at: 2026-07-21T00:00:00Z +changelog-url: https://github.com/snapsynapse/guidecheck/blob/v0.7.1/CHANGELOG.md diff --git a/docs/corrected-content-policy-2026-09-07.md b/docs/corrected-content-policy-2026-09-07.md new file mode 100644 index 0000000..bd4dbd6 --- /dev/null +++ b/docs/corrected-content-policy-2026-09-07.md @@ -0,0 +1,239 @@ +# Corrected content policy contract + +Status: implemented local candidate contract, 2026-09-07. The profile documents, +schemas, fixtures, selectors, and callers named below agree; profile 2.0.0 remains +unreleased and undeployed. + +## Decision + +Add the corrected checks as profile `2.0.0`. A guide selects them only by +declaring exactly one `profile: human-verifiable-assistant-guide` and exactly +one `profile-version: 2.0.0` in its metadata block. Build metadata MAY identify +an equivalent build, such as `2.0.0+build.1`, and MUST resolve to policy +`2.0.0` as existing selectors do. + +This is the smallest honest selector. The corrected checks tighten some cases +and relax false-positive cases, so the repository's SemVer rule requires a +major profile version. A CLI flag, hosted request field, manifest assertion, +or caller-supplied `ProfileSelection` MUST NOT reinterpret guide bytes as +`2.0.0`. `--require-profile-version 2.0.0` and the hosted equivalent remain +assertions that fail when the guide does not declare the required profile. + +Profile `2.0.0` has these policy identities: + +- content policy: `corrected-content-1` +- anchor policy: `1.0.0-strict` +- evaluated policy: `2.0.0` + +Supported legacy declarations through `0.7.1` continue to select the frozen +legacy engine. A `1.0.0` declaration continues to select the released strict +anchor policy with frozen content checks. Neither path gains corrected checks, +new findings, changed levels, changed report fields, or changed exit behavior. + +## Anchor composition + +Profile `2.0.0` inherits the complete `1.0.0-strict` anchor contract: + +- repository-file evidence is corroboration and never establishes independent + provenance or qualifies for Level 4 +- a fetched matching non-repository qualifying channel is required for Level 4 +- matching local evidence cannot establish independence and local-file mode is + capped at Level 3 +- manifest `profile` and `profile-version` must match the selected guide profile + exactly, so a `2.0.0` guide requires a `2.0.0` manifest +- mismatches, unsupported channels, qualification reasons, and Level 5 + readiness retain the released strict semantics + +Content and anchor policy are composed after one request-local selection from +the guide bytes. Content findings may limit the achieved level, but they do not +change which anchor channels qualify. Anchor evidence does not suppress or +reinterpret content findings. The implementation MUST NOT mutate global +policy state, monkey-patch the legacy evaluator, or modify +`scripts/guidecheck_legacy.py`. + +## Corrected content behavior + +The new content engine segments prose before matching. Sentence punctuation, +semicolons, blank lines, action markers, metadata and structured fields, list +items, and headings terminate negation scope. One ordinary LF or CRLF prose +wrap does not terminate a directly governing phrase. + +Each prohibited instruction occurrence is matched independently using token +boundaries and bounded, non-greedy spans. A later affirmative instruction is +reported even when an earlier occurrence in the same prose unit is prohibited. +A direct negation may suppress its governed phrase across one prose wrap. A +comma-coordinated prohibition is recognized only for a narrow verb-phrase list +with an explicit conjunction. An intervening subject, contrast, temporal or +conditional term, sentence, structured boundary, or unrelated reassurance +ends governance. Ambiguous grammar does not suppress a finding. + +The 29 cases in the September 7 reproducer define the initial direct detector +contract. In particular: + +| Case | Corrected result | +|---|---| +| `Do not` plus one wrapped encoded-execution phrase | no encoded-execution finding | +| coordinated `Do not broaden ..., disable ..., or persist ...` | no skip-approval finding | +| affirmative encoded-execution phrase across one wrap | `prohibited.encoded-execution` error | +| negated occurrence followed by an affirmative occurrence | `prohibited.encoded-execution` error | +| sentence, paragraph, field, list, heading, action, contrast, subject, or temporal boundary | affirmative occurrence remains an error | + +No new prohibited-instruction finding ID is required for these cases. Existing +IDs retain their meanings and severities on the corrected path. + +## Bounded execution behavior + +The corrected path distinguishes syntax-proven repository dispatch from cases +whose ownership cannot be decided from the command. It MUST emit the new +`action.exec-target-unresolved` finding for an unresolved code-executing +target. `ambiguous` is an explicit review result, not a clean result. + +Sam decided on 2026-09-07 that `action.exec-target-unresolved` is an error. It +blocks Level 3 because the verifier cannot establish which bytes the action +executes. A declared hash cannot clear the finding by itself: until the target +is identified, the verifier cannot establish what those declared hash bytes +would bind. + +| Command shape | Classification | Reason or counterexample | +|---|---|---| +| `npm run